From e5b7380c874745c989d1816b8f552504f038e1bc Mon Sep 17 00:00:00 2001 From: lresende Date: Thu, 26 Sep 2013 20:33:20 +0000 Subject: 2.0 branch for possible maintenance release git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@1526672 13f79535-47bb-0310-9956-ffa450edef68 --- .../DefaultDataBindingExtensionPoint.java | 261 +++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 sca-java-2.x/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/DefaultDataBindingExtensionPoint.java (limited to 'sca-java-2.x/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/DefaultDataBindingExtensionPoint.java') diff --git a/sca-java-2.x/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/DefaultDataBindingExtensionPoint.java b/sca-java-2.x/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/DefaultDataBindingExtensionPoint.java new file mode 100644 index 0000000000..22b6e8646e --- /dev/null +++ b/sca-java-2.x/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/DefaultDataBindingExtensionPoint.java @@ -0,0 +1,261 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.tuscany.sca.databinding; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.tuscany.sca.core.ExtensionPointRegistry; +import org.apache.tuscany.sca.databinding.javabeans.JavaBeansDataBinding; +import org.apache.tuscany.sca.databinding.javabeans.JavaExceptionDataBinding; +import org.apache.tuscany.sca.extensibility.ServiceDeclaration; +import org.apache.tuscany.sca.interfacedef.DataType; +import org.apache.tuscany.sca.interfacedef.Operation; +import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl; +import org.apache.tuscany.sca.interfacedef.util.XMLType; + +/** + * The default implementation of a data binding extension point. + * + * @version $Rev$ $Date$ + */ +public class DefaultDataBindingExtensionPoint implements DataBindingExtensionPoint { + private ExtensionPointRegistry registry; + private final Map bindings = new HashMap(); + private final List databindings = new ArrayList(); + private static final Logger logger = Logger.getLogger(DefaultDataBindingExtensionPoint.class.getName()); + private boolean loadedDataBindings; + +// public DefaultDataBindingExtensionPoint() { +// } + + public DefaultDataBindingExtensionPoint(ExtensionPointRegistry registry) { + this.registry = registry; + } + + public DataBinding getDataBinding(String id) { + if (id == null) { + return null; + } + loadDataBindings(); + DataBinding dataBinding = bindings.get(id.toLowerCase()); + if (dataBinding == null) { + loadDataBindings(); + dataBinding = bindings.get(id.toLowerCase()); + } + return dataBinding; + } + + public void addDataBinding(DataBinding dataBinding) { + if (logger.isLoggable(Level.FINE)) { + String className = dataBinding.getClass().getName(); + boolean lazy = false; + if (dataBinding instanceof LazyDataBinding) { + className = ((LazyDataBinding)dataBinding).dataBindingDeclaration.getClassName(); + lazy = true; + } + logger.fine("Adding databinding: " + className + ";name=" + dataBinding.getName() + ",lazy=" + lazy); + } + databindings.add(dataBinding); + bindings.put(dataBinding.getName().toLowerCase(), dataBinding); + + } + + public DataBinding removeDataBinding(String id) { + if (id == null) { + return null; + } + DataBinding dataBinding = bindings.remove(id.toLowerCase()); + if (dataBinding != null) { + databindings.remove(dataBinding); + } + return dataBinding; + } + + /** + * Dynamically load data bindings declared under META-INF/services + */ + private synchronized void loadDataBindings() { + if (loadedDataBindings) + return; + + // Get the databinding service declarations + Collection dataBindingDeclarations; + try { + dataBindingDeclarations = registry.getServiceDiscovery().getServiceDeclarations(DataBinding.class.getName()); + } catch (IOException e) { + throw new IllegalStateException(e); + } + + // Load data bindings + for (ServiceDeclaration dataBindingDeclaration : dataBindingDeclarations) { + Map attributes = dataBindingDeclaration.getAttributes(); + String name = attributes.get("name"); + + // Create a data binding wrapper and register it + DataBinding dataBinding = new LazyDataBinding(name, dataBindingDeclaration); + addDataBinding(dataBinding); + } + + loadedDataBindings = true; + } + + /** + * A data binding facade allowing data bindings to be lazily loaded and + * initialized. + */ + private class LazyDataBinding implements DataBinding { + + private String name; + private ServiceDeclaration dataBindingDeclaration; + private DataBinding dataBinding; + + private LazyDataBinding(String type, ServiceDeclaration dataBindingDeclaration) { + this.name = type; + this.dataBindingDeclaration = dataBindingDeclaration; + } + + /** + * Load and instantiate the data binding class. + * + * @return The data binding. + */ + @SuppressWarnings("unchecked") + private DataBinding getDataBinding() { + if (dataBinding == null) { + try { + Class dataBindingClass = (Class)dataBindingDeclaration.loadClass(); + try { + Constructor constructor = dataBindingClass.getConstructor(); + dataBinding = constructor.newInstance(); + } catch (NoSuchMethodException e) { + Constructor constructor = + dataBindingClass.getConstructor(ExtensionPointRegistry.class); + dataBinding = constructor.newInstance(DefaultDataBindingExtensionPoint.this.registry); + } + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + return dataBinding; + } + + public Object copy(Object object, DataType sourceDataType, DataType targetDataType, Operation sourceOperation, Operation targetOperation) { + return getDataBinding().copy(object, sourceDataType, targetDataType, sourceOperation, targetOperation); + } + + public String getName() { + return name; + } + + public XMLTypeHelper getXMLTypeHelper() { + return getDataBinding().getXMLTypeHelper(); + } + + public WrapperHandler getWrapperHandler() { + return getDataBinding().getWrapperHandler(); + } + + public boolean introspect(DataType dataType, Operation operation) { + return getDataBinding().introspect(dataType, operation); + } + + public DataType introspect(Object value, Operation operation) { + return getDataBinding().introspect(value, operation); + } + } + + //FIXME The following methods should not be on the extension point + // they should be on a separate class + public boolean introspectType(DataType dataType, Operation operation) { + loadDataBindings(); + for (DataBinding binding : databindings) { + // don't introspect for JavaBeansDatabinding as all javatypes will + // anyways match to its basetype + // which is java.lang.Object. Default to this only if no databinding + // results + if (!binding.getName().equals(JavaBeansDataBinding.NAME)) { + if (binding.introspect(dataType, operation)) { + return true; + } + } + } + // FIXME: Should we honor the databinding from operation/interface + // level? + Class physical = dataType.getPhysical(); + if (physical == Object.class) { + dataType.setDataBinding(JavaBeansDataBinding.NAME); + return false; + } + if (dataType.getPhysical().isArray()) { + introspectArray(dataType, operation); + return true; + } else if (Throwable.class.isAssignableFrom(physical)) { + dataType.setDataBinding(JavaExceptionDataBinding.NAME); + return true; + } else { + dataType.setDataBinding(JavaBeansDataBinding.NAME); + return false; + } + } + + private boolean introspectArray(DataType dataType, Operation operation) { + Class physical = dataType.getPhysical(); + if (!physical.isArray() || physical == byte[].class) { + return false; + } + Class componentType = physical.getComponentType(); + Type genericComponentType = componentType; + if(dataType.getGenericType() instanceof GenericArrayType) { + genericComponentType = ((GenericArrayType) dataType.getGenericType()).getGenericComponentType(); + } + DataType logical = new DataTypeImpl(dataType.getDataBinding(), componentType, genericComponentType, dataType.getLogical()); + introspectType(logical, operation); + dataType.setDataBinding("java:array"); + dataType.setLogical(logical); + return true; + } + + public DataType introspectType(Object value, Operation operation) { + loadDataBindings(); + DataType dataType = null; + for (DataBinding binding : databindings) { + // don't introspect for JavaBeansDatabinding as all javatypes will + // anyways match to its basetype + // which is java.lang.Object. Default to this only if no databinding + // results + if (!binding.getName().equals(JavaBeansDataBinding.NAME)) { + dataType = binding.introspect(value, operation); + } + if (dataType != null) { + return dataType; + } + } + return new DataTypeImpl(JavaBeansDataBinding.NAME, value.getClass(), XMLType.UNKNOWN); + } +} -- cgit v1.2.3