summaryrefslogtreecommitdiffstats
path: root/sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire')
-rw-r--r--sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataBindingRuntimeWireProcessor.java220
-rw-r--r--sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataTransformationInterceptor.java257
-rw-r--r--sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/PassByValueInterceptor.java188
3 files changed, 665 insertions, 0 deletions
diff --git a/sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataBindingRuntimeWireProcessor.java b/sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataBindingRuntimeWireProcessor.java
new file mode 100644
index 0000000000..d0a2dbc003
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataBindingRuntimeWireProcessor.java
@@ -0,0 +1,220 @@
+/*
+ * 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.core.databinding.wire;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import org.apache.tuscany.sca.assembly.Implementation;
+import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.InterfaceContract;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.invocation.Interceptor;
+import org.apache.tuscany.sca.invocation.InvocationChain;
+import org.apache.tuscany.sca.runtime.RuntimeComponent;
+import org.apache.tuscany.sca.runtime.RuntimeWire;
+import org.apache.tuscany.sca.runtime.RuntimeWireProcessor;
+
+/**
+ * This processor is responsible to add an interceptor to invocation chain if
+ * the source and target operations have different databinding requirements
+ *
+ * @version $Rev$ $Date$
+ */
+public class DataBindingRuntimeWireProcessor implements RuntimeWireProcessor {
+ private Mediator mediator;
+ private DataBindingExtensionPoint dataBindings;
+
+ public DataBindingRuntimeWireProcessor(Mediator mediator, DataBindingExtensionPoint dataBindings) {
+ super();
+ this.mediator = mediator;
+ this.dataBindings = dataBindings;
+ }
+
+ public boolean isTransformationRequired(DataType source, DataType target) {
+ if (source == null || target == null) { // void return type
+ return false;
+ }
+ if (source == target) {
+ return false;
+ }
+
+ // Output type can be null
+ if (source == null && target == null) {
+ return false;
+ } else if (source == null || target == null) {
+ return true;
+ }
+ String sourceDataBinding = source.getDataBinding();
+ String targetDataBinding = target.getDataBinding();
+ if (sourceDataBinding == targetDataBinding) {
+ return false;
+ }
+ if (sourceDataBinding == null || targetDataBinding == null) {
+ // TODO: If any of the databinding is null, then no transformation
+ return false;
+ }
+ return !sourceDataBinding.equals(targetDataBinding);
+ }
+
+ public boolean isTransformationRequired(Operation source, Operation target) {
+ if (source == target) {
+ return false;
+ }
+
+ if (source.isWrapperStyle() != target.isWrapperStyle()) {
+ return true;
+ }
+
+ // Check output type
+ DataType sourceOutputType = source.getOutputType();
+ DataType targetOutputType = target.getOutputType();
+
+ // Note the target output type is now the source for checking
+ // compatibility
+ if (isTransformationRequired(targetOutputType, sourceOutputType)) {
+ return true;
+ }
+
+ List<DataType> sourceInputType = source.getInputType().getLogical();
+ List<DataType> targetInputType = target.getInputType().getLogical();
+
+ int size = sourceInputType.size();
+ if (size != targetInputType.size()) {
+ // TUSCANY-1682: The wrapper style may have different arguments
+ return true;
+ }
+ for (int i = 0; i < size; i++) {
+ if (isTransformationRequired(sourceInputType.get(i), targetInputType.get(i))) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private boolean isTransformationRequired(InterfaceContract sourceContract,
+ Operation sourceOperation,
+ InterfaceContract targetContract,
+ Operation targetOperation) {
+ if (targetContract == null) {
+ targetContract = sourceContract;
+ }
+ if (sourceContract == targetContract) {
+ return false;
+ }
+ return isTransformationRequired(sourceOperation, targetOperation);
+ }
+
+ public void process(RuntimeWire wire) {
+ InterfaceContract sourceContract = wire.getSource().getInterfaceContract();
+ InterfaceContract targetContract = wire.getTarget().getInterfaceContract();
+ if (targetContract == null) {
+ targetContract = sourceContract;
+ }
+
+ if (!sourceContract.getInterface().isRemotable()) {
+ return;
+ }
+ List<InvocationChain> chains = wire.getInvocationChains();
+ for (InvocationChain chain : chains) {
+ Operation sourceOperation = chain.getSourceOperation();
+ Operation targetOperation = chain.getTargetOperation();
+
+ Interceptor interceptor = null;
+ if (isTransformationRequired(sourceContract, sourceOperation, targetContract, targetOperation)) {
+ // Add the interceptor to the source side because multiple
+ // references can be wired to the same service
+ interceptor = new DataTransformationInterceptor(wire, sourceOperation, targetOperation, mediator);
+ } else {
+ // assume pass-by-values copies are required if interfaces are remotable and there is no data binding
+ // transformation, i.e. a transformation will result in a copy so another pass-by-value copy is unnecessary
+ if (requiresCopy(wire, sourceOperation, targetOperation)) {
+ interceptor = new PassByValueInterceptor(dataBindings, targetOperation);
+ }
+ }
+ if (interceptor != null) {
+ chain.addInterceptor(0, interceptor);
+ }
+ }
+
+ }
+
+ /**
+ * Pass-by-value copies are required if the interfaces are remotable unless the
+ * implementation uses the @AllowsPassByReference annotation.
+ */
+ protected boolean requiresCopy(RuntimeWire wire, Operation sourceOperation, Operation targetOperation) {
+ if (!sourceOperation.getInterface().isRemotable()) {
+ return false;
+ }
+ if (!targetOperation.getInterface().isRemotable()) {
+ return false;
+ }
+
+ if (allowsPassByReference(wire.getSource().getComponent(), sourceOperation)) {
+ return false;
+ }
+
+ if (allowsPassByReference(wire.getTarget().getComponent(), sourceOperation)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Does the implementation use the @AllowsPassByReference annotation for the operation.
+ * Uses reflection to avoid a dependency on JavaImplementation because the isAllowsPassByReference
+ * and getAllowsPassByReference methods are not on the Implementation interface.
+ * TODO: move isAllowsPassByReference/getAllowsPassByReference to Implementation interface
+ */
+ protected boolean allowsPassByReference(RuntimeComponent component, Operation operation) {
+ if (component == null || component.getImplementation() == null) {
+ return true; // err on the side of no copies
+ }
+ Implementation impl = component.getImplementation();
+ try {
+
+ Method m = impl.getClass().getMethod("isAllowsPassByReference", new Class[] {});
+ if ((Boolean)m.invoke(impl, new Object[]{})) {
+ return true;
+ }
+
+ m = impl.getClass().getMethod("getAllowsPassByReferenceMethods", new Class[] {});
+ List<Method> ms = (List<Method>)m.invoke(impl, new Object[]{});
+ if (ms != null) {
+ for (Method m2 : ms) {
+ // simple name matching is ok as its a remote operation so no overloading
+ if (operation.getName().equals(m2.getName()))
+ return true;
+ }
+ }
+
+ } catch (Exception e) {
+ // ignore, assume the impl has no isAllowsPassByReference method
+ }
+
+ return false;
+ }
+
+}
diff --git a/sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataTransformationInterceptor.java b/sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataTransformationInterceptor.java
new file mode 100644
index 0000000000..461e281a82
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/DataTransformationInterceptor.java
@@ -0,0 +1,257 @@
+/*
+ * 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.core.databinding.wire;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.databinding.DataBinding;
+import org.apache.tuscany.sca.databinding.ExceptionHandler;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.databinding.TransformationException;
+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.FaultException;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.apache.tuscany.sca.invocation.Interceptor;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.Message;
+import org.apache.tuscany.sca.runtime.RuntimeWire;
+
+/**
+ * An interceptor to transform data accross databindings on the wire
+ *
+ * @version $Rev$ $Date$
+ */
+public class DataTransformationInterceptor implements Interceptor {
+ private Invoker next;
+
+ private Operation sourceOperation;
+
+ private Operation targetOperation;
+ private RuntimeWire wire;
+ private Mediator mediator;
+
+ public DataTransformationInterceptor(RuntimeWire wire,
+ Operation sourceOperation,
+ Operation targetOperation,
+ Mediator mediator) {
+ super();
+ this.sourceOperation = sourceOperation;
+ this.targetOperation = targetOperation;
+ this.mediator = mediator;
+ this.wire = wire;
+ }
+
+ public Invoker getNext() {
+ return next;
+ }
+
+ public Message invoke(Message msg) {
+ Object input = transform(msg.getBody(), sourceOperation.getInputType(), targetOperation.getInputType(), false);
+ msg.setBody(input);
+ Message resultMsg = next.invoke(msg);
+ Object result = resultMsg.getBody();
+ if (sourceOperation.isNonBlocking()) {
+ // Not to reset the message body
+ return resultMsg;
+ }
+
+ // FIXME: Should we fix the Operation model so that getOutputType
+ // returns DataType<DataType<T>>?
+ DataType<DataType> targetType =
+ new DataTypeImpl<DataType>(DataBinding.IDL_OUTPUT, Object.class, targetOperation.getOutputType());
+
+ DataType<DataType> sourceType =
+ new DataTypeImpl<DataType>(DataBinding.IDL_OUTPUT, Object.class, sourceOperation.getOutputType());
+
+ if (resultMsg.isFault()) {
+
+ // FIXME: We need to figure out what fault type it is and then
+ // transform it
+ // back the source fault type
+ // throw new InvocationRuntimeException((Throwable) result);
+
+ if ((result instanceof Exception) && !(result instanceof RuntimeException)) {
+ // FIXME: How to match fault data to a fault type for the
+ // operation?
+
+ // If the result is from an InvocationTargetException look at
+ // the actual cause.
+ if (result instanceof InvocationTargetException) {
+ result = ((InvocationTargetException)result).getCause();
+ }
+ DataType targetDataType = null;
+ for (DataType exType : targetOperation.getFaultTypes()) {
+ if (((Class)exType.getPhysical()).isInstance(result)) {
+ if (result instanceof FaultException) {
+ if (((FaultException)result).isMatchingType(exType.getLogical())) {
+ targetDataType = exType;
+ break;
+ }
+ } else {
+ targetDataType = exType;
+ break;
+ }
+ }
+ }
+
+ if (targetDataType == null) {
+ // Not a business exception
+ return resultMsg;
+ }
+
+ DataType targetFaultType = getFaultType(targetDataType);
+ if (targetFaultType == null) {
+ throw new TransformationException("Target fault type cannot be resolved: " + targetDataType);
+ }
+
+ // FIXME: How to match a source fault type to a target fault
+ // type?
+ DataType sourceDataType = null;
+ DataType sourceFaultType = null;
+ for (DataType exType : sourceOperation.getFaultTypes()) {
+ DataType faultType = getFaultType(exType);
+ // Match by the QName (XSD element) of the fault type
+ if (faultType != null && typesMatch(targetFaultType.getLogical(), faultType.getLogical())) {
+ sourceDataType = exType;
+ sourceFaultType = faultType;
+ break;
+ }
+ }
+
+ if (sourceFaultType == null) {
+ throw new TransformationException("No matching source fault type is found: " + targetFaultType);
+ }
+
+ Object newResult =
+ transformException(result, targetDataType, sourceDataType, targetFaultType, sourceFaultType);
+ if (newResult != result) {
+ resultMsg.setFaultBody(newResult);
+ }
+ }
+
+ } else {
+ assert !(result instanceof Throwable) : "Expected messages that are not throwable " + result;
+
+ Object newResult = transform(result, targetType, sourceType, true);
+ if (newResult != result) {
+ resultMsg.setBody(newResult);
+ }
+ }
+
+ return resultMsg;
+ }
+
+ private Object transform(Object source, DataType sourceType, DataType targetType, boolean isResponse) {
+ if (sourceType == targetType || (sourceType != null && sourceType.equals(targetType))) {
+ return source;
+ }
+ Map<String, Object> metadata = new HashMap<String, Object>();
+ metadata.put("source.operation", isResponse ? targetOperation : sourceOperation);
+ metadata.put("target.operation", isResponse ? sourceOperation : targetOperation);
+ metadata.put("wire", wire);
+ return mediator.mediate(source, sourceType, targetType, metadata);
+ }
+
+ private DataType getFaultType(DataType exceptionType) {
+ // FIXME: We cannot assume the exception will have a databinding set
+ DataBinding targetDataBinding = mediator.getDataBindings().getDataBinding(exceptionType.getDataBinding());
+ if (targetDataBinding == null) {
+ return null;
+ }
+ ExceptionHandler targetHandler = targetDataBinding.getExceptionHandler();
+ if (targetHandler == null) {
+ return null;
+ }
+ return targetHandler.getFaultType(exceptionType);
+ }
+
+ private boolean typesMatch(Object first, Object second) {
+ if (first.equals(second)) {
+ return true;
+ }
+ if (first instanceof XMLType && second instanceof XMLType) {
+ XMLType t1 = (XMLType)first;
+ XMLType t2 = (XMLType)second;
+ return matches(t1.getElementName(), t2.getElementName()) && matches(t1.getTypeName(), t2.getTypeName());
+ }
+ return false;
+ }
+
+ /**
+ * @param qn1
+ * @param qn2
+ */
+ private boolean matches(QName qn1, QName qn2) {
+ if (qn1 == qn2) {
+ return true;
+ }
+ if (qn1 == null || qn2 == null) {
+ return false;
+ }
+ String ns1 = qn1.getNamespaceURI();
+ String ns2 = qn2.getNamespaceURI();
+ String e1 = qn1.getLocalPart();
+ String e2 = qn2.getLocalPart();
+ if (e1.equals(e2) && (ns1.equals(ns2) || ns1.equals(ns2 + "/") || ns2.equals(ns1 + "/"))) {
+ // Tolerating the trailing / which is required by JAX-WS java package --> xml ns mapping
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param source The source exception
+ * @param sourceExType The data type for the source exception
+ * @param targetExType The data type for the target exception
+ * @param sourceType The fault type for the source
+ * @param targetType The fault type for the target
+ * @return
+ */
+ private Object transformException(Object source,
+ DataType sourceExType,
+ DataType targetExType,
+ DataType sourceType,
+ DataType targetType) {
+ if (sourceType == targetType || (sourceType != null && sourceType.equals(targetType))) {
+ return source;
+ }
+ Map<String, Object> metadata = new HashMap<String, Object>();
+ metadata.put("source.operation", targetOperation);
+ metadata.put("target.operation", sourceOperation);
+ metadata.put("wire", wire);
+ DataType<DataType> eSourceDataType =
+ new DataTypeImpl<DataType>("idl:fault", sourceExType.getPhysical(), sourceType);
+ DataType<DataType> eTargetDataType =
+ new DataTypeImpl<DataType>("idl:fault", targetExType.getPhysical(), targetType);
+
+ return mediator.mediate(source, eSourceDataType, eTargetDataType, metadata);
+ }
+
+ public void setNext(Invoker next) {
+ this.next = next;
+ }
+
+}
diff --git a/sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/PassByValueInterceptor.java b/sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/PassByValueInterceptor.java
new file mode 100644
index 0000000000..0e3f3947ec
--- /dev/null
+++ b/sca-java-1.x/branches/sca-java-1.1/modules/core-databinding/src/main/java/org/apache/tuscany/sca/core/databinding/wire/PassByValueInterceptor.java
@@ -0,0 +1,188 @@
+/*
+ * 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.core.databinding.wire;
+
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tuscany.sca.databinding.DataBinding;
+import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint;
+import org.apache.tuscany.sca.databinding.javabeans.JavaBeansDataBinding;
+import org.apache.tuscany.sca.databinding.jaxb.JAXBDataBinding;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.invocation.Interceptor;
+import org.apache.tuscany.sca.invocation.Invoker;
+import org.apache.tuscany.sca.invocation.Message;
+
+/**
+ * Implementation of an interceptor that enforces pass-by-value semantics
+ * on operation invocations by copying the operation input and output data.
+ *
+ * @version $Rev$ $Date$
+ */
+public class PassByValueInterceptor implements Interceptor {
+
+ private DataBindingExtensionPoint dataBindings;
+ private DataBinding[] inputDataBindings;
+ private DataBinding outputDataBinding;
+ private DataBinding javaBeanDataBinding;
+ private DataBinding jaxbDataBinding;
+ private Operation operation;
+ private Invoker nextInvoker;
+
+ /**
+ * Constructs a new PassByValueInterceptor.
+ * @param dataBindings databinding extension point
+ * @param operation the intercepted operation
+ */
+ public PassByValueInterceptor(DataBindingExtensionPoint dataBindings, Operation operation) {
+ this.operation = operation;
+
+ // Cache data bindings to use
+ this.dataBindings = dataBindings;
+ jaxbDataBinding = dataBindings.getDataBinding(JAXBDataBinding.NAME);
+ javaBeanDataBinding = dataBindings.getDataBinding(JavaBeansDataBinding.NAME);
+
+ // Determine the input databindings
+ if (operation.getInputType() != null) {
+ List<DataType> inputTypes = operation.getInputType().getLogical();
+ inputDataBindings = new DataBinding[inputTypes.size()];
+ int i = 0;
+ for (DataType inputType: inputTypes) {
+ String id = inputType.getDataBinding();
+ inputDataBindings[i++] = dataBindings.getDataBinding(id);
+ }
+ }
+
+ // Determine the output databinding
+ if (operation.getOutputType() != null) {
+ String id = operation.getOutputType().getDataBinding();
+ outputDataBinding = dataBindings.getDataBinding(id);
+ }
+ }
+
+ public Message invoke(Message msg) {
+ msg.setBody(copy((Object[])msg.getBody(), inputDataBindings));
+
+ Message resultMsg = nextInvoker.invoke(msg);
+
+ if (!msg.isFault() && operation.getOutputType() != null) {
+ resultMsg.setBody(copy(resultMsg.getBody(), outputDataBinding));
+ }
+ return resultMsg;
+ }
+
+ /**
+ * Copy an array of data objects passed to an operation
+ * @param data array of objects to copy
+ * @return the copy
+ */
+ private Object[] copy(Object[] data, DataBinding[] dataBindings) {
+ if (data == null) {
+ return null;
+ }
+ Object[] copy = new Object[data.length];
+ Map<Object, Object> map = new IdentityHashMap<Object, Object>();
+ for (int i = 0; i < data.length; i++) {
+ Object arg = data[i];
+ if (arg == null) {
+ copy[i] = null;
+ } else {
+ Object copiedArg = map.get(arg);
+ if (copiedArg != null) {
+ copy[i] = copiedArg;
+ } else {
+ copiedArg = copy(arg, dataBindings[i]);
+ map.put(arg, copiedArg);
+ copy[i] = copiedArg;
+ }
+ }
+ }
+ return copy;
+ }
+
+ /**
+ * Copy data using the specified databinding.
+ * @param data input data
+ * @param dataBinding databinding to use
+ * @return a copy of the data
+ */
+ private Object copy(Object data, DataBinding dataBinding) {
+ if (data == null) {
+ return null;
+ }
+
+ // If no databinding was specified, introspect the given arg to
+ // determine its databinding
+ if (dataBinding == null) {
+ DataType<?> dataType = dataBindings.introspectType(data);
+ if (dataType != null) {
+ String db = dataType.getDataBinding();
+ dataBinding = dataBindings.getDataBinding(db);
+ if (dataBinding == null && db != null) {
+ return data;
+ }
+ }
+ if (dataBinding == null) {
+
+ // Default to the JavaBean databinding
+ dataBinding = javaBeanDataBinding;
+ }
+ }
+
+ // Use the JAXB databinding to copy non-Serializable data
+ if (dataBinding == javaBeanDataBinding) {
+
+ // If the input data is an array containing non serializable elements
+ // use JAXB
+ Class<?> clazz = data.getClass();
+ if (clazz.isArray()) {
+ if (Array.getLength(data) != 0) {
+ Object element = Array.get(data, 0);
+ if (element != null && !(element instanceof Serializable)) {
+ dataBinding = jaxbDataBinding;
+ }
+ }
+ } else {
+
+ // If the input data is not serializable use JAXB
+ if (!(data instanceof Serializable)) {
+ dataBinding = jaxbDataBinding;
+ }
+ }
+ }
+
+ Object copy = dataBinding.copy(data);
+ return copy;
+ }
+
+ public Invoker getNext() {
+ return nextInvoker;
+ }
+
+ public void setNext(Invoker next) {
+ this.nextInvoker = next;
+ }
+
+}