blob: abd031ec33b1fe66e0f09833d5cd098bb96cc524 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2006, 2010 VMware Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
* is available at http://www.opensource.org/licenses/apache2.0.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* VMware Inc.
*****************************************************************************/
package org.eclipse.gemini.blueprint.blueprint.container;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.gemini.blueprint.blueprint.container.support.BlueprintEditorRegistrar;
import org.eclipse.gemini.blueprint.context.support.internal.security.SecurityUtils;
import org.osgi.service.blueprint.container.Converter;
import org.osgi.service.blueprint.container.ReifiedType;
import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.convert.ConversionException;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.TypeDescriptor;
/**
* OSGi 4.2 Blueprint converter adapter as an Spring 4.0 ConverterService.
*
* @author Costin Leau
*/
public class SpringBlueprintConverterService implements ConversionService {
private static final class BlueprintConverterException extends ConversionException {
public BlueprintConverterException(String message, Throwable cause) {
super(message, cause);
}
public BlueprintConverterException(String message) {
super(message);
}
}
/** fallback delegate */
private final ConversionService delegate;
private final List<Converter> converters = new ArrayList<Converter>();
private final SimpleTypeConverter typeConverter;
// used for grabbing the security context
private final ConfigurableBeanFactory cbf;
private volatile boolean converterInitialized = false;
public SpringBlueprintConverterService(ConversionService delegate, ConfigurableBeanFactory cbf) {
this.delegate = delegate;
this.cbf = cbf;
this.typeConverter = new SimpleTypeConverter();
}
public void add(Converter blueprintConverter) {
synchronized (converters) {
converters.add(blueprintConverter);
}
}
public void add(Collection<Converter> blueprintConverters) {
synchronized (converters) {
converters.addAll(blueprintConverters);
}
}
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
return true;
}
public boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType) {
return true;
}
@SuppressWarnings("unchecked")
public <T> T convert(Object source, Class<T> targetType) {
return (T) convert(source, TypeDescriptor.forObject(source), TypeDescriptor.valueOf(targetType));
}
public Object convert(final Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
if (targetType == null)
return source;
final ReifiedType type = TypeFactory.getType(targetType);
boolean hasSecurity = (System.getSecurityManager() != null);
AccessControlContext acc = (hasSecurity ? SecurityUtils.getAccFrom(cbf) : null);
Object result;
if (hasSecurity) {
result = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return doConvert(source, type);
}
}, acc);
} else {
result = doConvert(source, type);
}
if (result != null) {
return result;
}
if (!targetType.isCollection() && !targetType.isArray() && !targetType.isMap()) {
if (type.size() > 0) {
for (int i = 0; i < type.size(); i++) {
ReifiedType arg = type.getActualTypeArgument(i);
if (!Object.class.equals(arg.getRawClass())) {
throw new BlueprintConverterException(
"No conversion found for generic argument(s) for reified type " + arg.getRawClass()
+ "source type " + sourceType + "| targetType =" + targetType.getType(), null);
}
}
}
}
if (delegate != null) {
delegate.convert(source, sourceType, targetType);
}
lazyInitConverter();
return typeConverter.convertIfNecessary(source, targetType.getType());
}
private void lazyInitConverter() {
if (!converterInitialized) {
synchronized (typeConverter) {
if (!converterInitialized) {
converterInitialized = true;
if (cbf != null) {
cbf.copyRegisteredEditorsTo(typeConverter);
new BlueprintEditorRegistrar().registerCustomEditors(typeConverter);
}
}
}
}
}
private Object doConvert(Object source, ReifiedType type) {
synchronized (converters) {
for (Converter converter : converters) {
try {
if (converter.canConvert(source, type)) {
return converter.convert(source, type);
}
} catch (Exception ex) {
throw new BlueprintConverterException("Conversion between source " + source + " and reified type "
+ type + " failed", ex);
}
}
}
return null;
}
}