/****************************************************************************** | |
* 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; | |
} | |
} |