summaryrefslogtreecommitdiffstats
path: root/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src
diff options
context:
space:
mode:
Diffstat (limited to 'sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src')
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/AnyTypeXmlAdapter.java39
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DOMElementXmlAdapter.java57
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DataConverter.java378
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DefaultXMLAdapterExtensionPoint.java60
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2Node.java85
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2SAX.java77
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2String.java82
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java561
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java492
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBDataBinding.java148
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBPropertyDescriptor.java302
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBTypeHelper.java244
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperException.java56
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHandler.java151
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHelper.java166
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/Node2JAXB.java75
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/Reader2JAXB.java79
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/String2JAXB.java86
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLAdapterExtensionPoint.java52
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLRootElementUtil.java299
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLStreamReader2JAXB.java80
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/package.html29
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.DataBinding20
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.PullTransformer33
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.jaxb.XMLAdapterExtensionPoint17
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/com/example/stock/StockQuoteOffer.java45
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCacheTestCase.java122
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBDataBindingTestCase.java131
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBReflectionTestCase.java39
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBTestCase.java148
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHandlerTestCase.java90
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyBean.java162
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyInterface.java29
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyInterfaceImpl.java67
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyJaxbBean.java64
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MySubBean.java35
-rw-r--r--sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/POJOTestCase.java238
-rwxr-xr-xsandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/resources/ipo.xsd144
38 files changed, 4982 insertions, 0 deletions
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/AnyTypeXmlAdapter.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/AnyTypeXmlAdapter.java
new file mode 100644
index 0000000000..57922e1c89
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/AnyTypeXmlAdapter.java
@@ -0,0 +1,39 @@
+/*
+ * 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.jaxb;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+/**
+ * This special XmlAdapter can be used by JAXB classes to annotate the references to java interfaces
+ */
+public class AnyTypeXmlAdapter extends XmlAdapter<Object, Object> {
+
+ @Override
+ public Object marshal(Object v) throws Exception {
+ return v;
+ }
+
+ @Override
+ public Object unmarshal(Object v) throws Exception {
+ return v;
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DOMElementXmlAdapter.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DOMElementXmlAdapter.java
new file mode 100644
index 0000000000..91cb39b0f2
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DOMElementXmlAdapter.java
@@ -0,0 +1,57 @@
+/*
+ * 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.jaxb;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.databinding.xml.DOMDataBinding;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.w3c.dom.Element;
+
+/**
+ * A generic XmlAdapter for JAXB to marshal/unmarshal between the java objects and DOM elements
+ */
+public class DOMElementXmlAdapter extends XmlAdapter<Element, Object> {
+ private Mediator mediator;
+ private DataType dataType;
+ private DataType domType;
+
+ public DOMElementXmlAdapter(Mediator mediator, DataType dataType) {
+ this.mediator = mediator;
+ this.dataType = dataType;
+ this.domType = new DataTypeImpl(DOMDataBinding.NAME, Element.class, dataType.getLogical());
+ }
+
+ @Override
+ public Element marshal(Object value) throws Exception {
+ return (Element) mediator.mediate(value, dataType, domType, null);
+ }
+
+ @Override
+ public Object unmarshal(Element element) throws Exception {
+ return mediator.mediate(element, domType, dataType, null);
+ }
+
+ public void setMediator(Mediator mediator) {
+ this.mediator = mediator;
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DataConverter.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DataConverter.java
new file mode 100644
index 0000000000..35adffe23b
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DataConverter.java
@@ -0,0 +1,378 @@
+/*
+ * 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.jaxb;
+
+import java.awt.Image;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.activation.DataHandler;
+import javax.imageio.ImageIO;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.oasisopen.sca.ServiceRuntimeException;
+
+/**
+ * Provides utilities to convert an object into a different kind of Object. For example, convert a
+ * String[] into a List<String>
+ */
+public class DataConverter {
+
+ /**
+ * This method should return true if the convert method will succeed.
+ * <p/>
+ * Note that any changes to isConvertable() must also be accompanied by similar changes to
+ * convert()
+ *
+ * @param obj source object or class
+ * @param dest destination class
+ * @return boolean true if convert(..) can convert obj to the destination class
+ */
+ public static boolean isConvertable(Object obj, Class dest) {
+ Class src = null;
+
+ if (obj != null) {
+ if (obj instanceof Class) {
+ src = (Class)obj;
+ } else {
+ src = obj.getClass();
+ }
+ }
+
+ if (dest == null) {
+ return false;
+ }
+
+ if (src == null) {
+ return true;
+ }
+
+ // If we're directly assignable, we're good.
+ if (dest.isAssignableFrom(src)) {
+ return true;
+ }
+
+ // If it's a wrapping conversion, we're good.
+ if (getWrapperClass(src) == dest) {
+ return true;
+ }
+ if (getWrapperClass(dest) == src) {
+ return true;
+ }
+
+ // If it's List -> Array or vice versa, we're good.
+ if ((Collection.class.isAssignableFrom(src) || src.isArray()) && (Collection.class.isAssignableFrom(dest) || dest
+ .isArray())) {
+
+ // TODO this should consider the component types instead of returning true.
+ return true;
+ }
+
+ // Allow mapping of HashMaps to Hashtables
+ if (src == HashMap.class && dest == Hashtable.class)
+ return true;
+
+ // Allow mapping of Calendar to Date
+ if (Calendar.class.isAssignableFrom(src) && dest == Date.class) {
+ return true;
+ }
+
+ if (src.isPrimitive()) {
+ return isConvertable(getWrapperClass(src), dest);
+ }
+
+ if (InputStream.class.isAssignableFrom(src) && dest == byte[].class) {
+ return true;
+ }
+
+ if (Source.class.isAssignableFrom(src) && dest == byte[].class) {
+ return true;
+ }
+
+ if (DataHandler.class.isAssignableFrom(src) && isConvertable(byte[].class, dest)) {
+ return true;
+ }
+
+ if (DataHandler.class.isAssignableFrom(src) && dest == Image.class) {
+ return true;
+ }
+
+ if (DataHandler.class.isAssignableFrom(src) && dest == Source.class) {
+ return true;
+ }
+
+ if (byte[].class.isAssignableFrom(src) && dest == String.class) {
+ return true;
+ }
+
+ // If it's a MIME type mapping and we want a DataHandler,
+ // then we're good.
+ // REVIEW Do we want to support this
+ /*
+ if (dest.getName().equals("javax.activation.DataHandler")) {
+ String name = src.getName();
+ if (src == String.class
+ || src == java.awt.Image.class
+ || name.equals("javax.mail.internet.MimeMultipart")
+ || name.equals("javax.xml.transform.Source"))
+ return true;
+ }
+ */
+
+ return false;
+ }
+
+ /**
+ * Utility function to convert an Object to some desired Class.
+ * <p/>
+ * Normally this is used for T[] to List<T> processing. Other conversions are also done (i.e.
+ * HashMap <->Hashtable, etc.)
+ * <p/>
+ * Use the isConvertable() method to determine if conversion is possible. Note that any changes
+ * to convert() must also be accompanied by similar changes to isConvertable()
+ *
+ * @param arg the array to convert
+ * @param destClass the actual class we want
+ * @return object of destClass if conversion possible, otherwise returns arg
+ */
+ public static Object convert(Object arg, Class<?> destClass) {
+ if (destClass == null) {
+ return arg;
+ }
+
+ if (arg != null && destClass.isAssignableFrom(arg.getClass())) {
+ return arg;
+ }
+
+ // Convert between Calendar and Date
+ if (arg instanceof Calendar && destClass == Date.class) {
+ return ((Calendar)arg).getTime();
+ }
+
+ // Convert between HashMap and Hashtable
+ if (arg instanceof HashMap && destClass == Hashtable.class) {
+ return new Hashtable((HashMap)arg);
+ }
+
+ if (arg instanceof InputStream && destClass == byte[].class) {
+
+ try {
+ InputStream is = (InputStream)arg;
+ return getBytesFromStream(is);
+ } catch (IOException e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ if (arg instanceof Source && destClass == byte[].class) {
+ try {
+ if (arg instanceof StreamSource) {
+ InputStream is = ((StreamSource)arg).getInputStream();
+ if (is != null) {
+ return getBytesFromStream(is);
+ }
+ }
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ Result result = new StreamResult(out);
+ Transformer transformer = TransformerFactory.newInstance().newTransformer();
+ transformer.transform((Source)arg, result);
+ byte[] bytes = out.toByteArray();
+ return bytes;
+
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ if (arg instanceof DataHandler) {
+ try {
+ InputStream is = ((DataHandler)arg).getInputStream();
+ if (destClass == Image.class) {
+ return ImageIO.read(is);
+ } else if (destClass == Source.class) {
+ return new StreamSource(is);
+ }
+ byte[] bytes = getBytesFromStream(is);
+ return convert(bytes, destClass);
+ } catch (Exception e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ if (arg instanceof byte[] && destClass == String.class) {
+ return new String((byte[])arg);
+ }
+
+ // If the destination is an array and the source
+ // is a suitable component, return an array with
+ // the single item.
+ /* REVIEW do we need to support atomic to array conversion ?
+ if (arg != null &&
+ destClass.isArray() &&
+ !destClass.getComponentType().equals(Object.class) &&
+ destClass.getComponentType().isAssignableFrom(arg.getClass())) {
+ Object array =
+ Array.newInstance(destClass.getComponentType(), 1);
+ Array.set(array, 0, arg);
+ return array;
+ }
+ */
+
+ // Return if no conversion is available
+ if (!(arg instanceof Collection || (arg != null && arg.getClass().isArray()))) {
+ return arg;
+ }
+
+ if (arg == null) {
+ return null;
+ }
+
+ // The arg may be an array or List
+ Object destValue = null;
+ int length = 0;
+ if (arg.getClass().isArray()) {
+ length = Array.getLength(arg);
+ } else {
+ length = ((Collection)arg).size();
+ }
+
+ try {
+ if (destClass.isArray()) {
+ if (destClass.getComponentType().isPrimitive()) {
+
+ Object array = Array.newInstance(destClass.getComponentType(), length);
+ // Assign array elements
+ if (arg.getClass().isArray()) {
+ for (int i = 0; i < length; i++) {
+ Array.set(array, i, Array.get(arg, i));
+ }
+ } else {
+ int idx = 0;
+ for (Iterator i = ((Collection)arg).iterator(); i.hasNext();) {
+ Array.set(array, idx++, i.next());
+ }
+ }
+ destValue = array;
+
+ } else {
+ Object[] array;
+ try {
+ array = (Object[])Array.newInstance(destClass.getComponentType(), length);
+ } catch (Exception e) {
+ return arg;
+ }
+
+ // Use convert to assign array elements.
+ if (arg.getClass().isArray()) {
+ for (int i = 0; i < length; i++) {
+ array[i] = convert(Array.get(arg, i), destClass.getComponentType());
+ }
+ } else {
+ int idx = 0;
+ for (Iterator i = ((Collection)arg).iterator(); i.hasNext();) {
+ array[idx++] = convert(i.next(), destClass.getComponentType());
+ }
+ }
+ destValue = array;
+ }
+ } else if (Collection.class.isAssignableFrom(destClass)) {
+ Collection newList = null;
+ try {
+ // if we are trying to create an interface, build something
+ // that implements the interface
+ if (destClass == Collection.class || destClass == List.class) {
+ newList = new ArrayList();
+ } else if (destClass == Set.class) {
+ newList = new HashSet();
+ } else {
+ newList = (Collection)destClass.newInstance();
+ }
+ } catch (Exception e) {
+ // No FFDC code needed
+ // Couldn't build one for some reason... so forget it.
+ return arg;
+ }
+
+ if (arg.getClass().isArray()) {
+ for (int j = 0; j < length; j++) {
+ newList.add(Array.get(arg, j));
+ }
+ } else {
+ for (Iterator j = ((Collection)arg).iterator(); j.hasNext();) {
+ newList.add(j.next());
+ }
+ }
+ destValue = newList;
+ } else {
+ destValue = arg;
+ }
+ } catch (Throwable t) {
+ throw new ServiceRuntimeException(t);
+ }
+
+ return destValue;
+ }
+
+ private static byte[] getBytesFromStream(InputStream is) throws IOException {
+ // TODO This code assumes that available is the length of the stream.
+ byte[] bytes = new byte[is.available()];
+ is.read(bytes);
+ return bytes;
+ }
+
+ public static Class getWrapperClass(Class primitive) {
+ if (primitive == int.class) {
+ return java.lang.Integer.class;
+ } else if (primitive == short.class) {
+ return java.lang.Short.class;
+ } else if (primitive == boolean.class) {
+ return java.lang.Boolean.class;
+ } else if (primitive == byte.class) {
+ return java.lang.Byte.class;
+ } else if (primitive == long.class) {
+ return java.lang.Long.class;
+ } else if (primitive == double.class) {
+ return java.lang.Double.class;
+ } else if (primitive == float.class) {
+ return java.lang.Float.class;
+ } else if (primitive == char.class) {
+ return java.lang.Character.class;
+ }
+
+ return null;
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DefaultXMLAdapterExtensionPoint.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DefaultXMLAdapterExtensionPoint.java
new file mode 100644
index 0000000000..062da48206
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/DefaultXMLAdapterExtensionPoint.java
@@ -0,0 +1,60 @@
+/*
+ * 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.jaxb;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class DefaultXMLAdapterExtensionPoint implements XMLAdapterExtensionPoint {
+ private Map<Class<?>, Class<? extends XmlAdapter>> adapters =
+ new ConcurrentHashMap<Class<?>, Class<? extends XmlAdapter>>();
+
+ public void addAdapter(Class<?> boundType, Class<? extends XmlAdapter> adapter) {
+ adapters.put(boundType, adapter);
+ }
+
+ public Class<? extends XmlAdapter> getAdapter(Class<?> boundType) {
+ Class<? extends XmlAdapter> cls = adapters.get(boundType);
+ if (cls != null) {
+ return cls;
+ }
+ for (Map.Entry<Class<?>, Class<? extends XmlAdapter>> e : adapters.entrySet()) {
+ if (e.getKey().isAssignableFrom(boundType)) {
+ return e.getValue();
+ }
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Class<? extends XmlAdapter> removeAdapter(Class<?> boundType) {
+ return adapters.remove(boundType);
+ }
+
+ public Map<Class<?>, Class<? extends XmlAdapter>> getAdapters() {
+ return adapters;
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2Node.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2Node.java
new file mode 100644
index 0000000000..3d25af5b25
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2Node.java
@@ -0,0 +1,85 @@
+/*
+ * 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.jaxb;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+
+import org.apache.tuscany.sca.common.xml.dom.DOMHelper;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.PullTransformer;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.databinding.TransformationException;
+import org.apache.tuscany.sca.databinding.BaseTransformer;
+import org.apache.tuscany.sca.databinding.xml.DOMDataBinding;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class JAXB2Node extends BaseTransformer<Object, Node> implements PullTransformer<Object, Node> {
+ private DOMHelper helper;
+ private JAXBContextHelper contextHelper;
+
+ public JAXB2Node(ExtensionPointRegistry registry) {
+ super();
+ helper = DOMHelper.getInstance(registry);
+ contextHelper = JAXBContextHelper.getInstance(registry);
+ }
+
+ public Node transform(Object source, TransformationContext tContext) {
+// if (source == null) {
+// return null;
+// }
+ try {
+ JAXBContext context = contextHelper.createJAXBContext(tContext, true);
+ Marshaller marshaller = context.createMarshaller();
+ // FIXME: The default Marshaller doesn't support
+ // marshaller.getNode()
+ Document document = helper.newDocument();
+ Object jaxbElement = JAXBContextHelper.createJAXBElement(context, tContext.getSourceDataType(), source);
+ marshaller.marshal(jaxbElement, document);
+ return DOMDataBinding.adjustElementName(tContext, document.getDocumentElement());
+ } catch (Exception e) {
+ throw new TransformationException(e);
+ }
+ }
+
+ @Override
+ protected Class<Object> getSourceType() {
+ return Object.class;
+ }
+
+ @Override
+ protected Class<Node> getTargetType() {
+ return Node.class;
+ }
+
+ @Override
+ public int getWeight() {
+ return 30;
+ }
+
+ @Override
+ public String getSourceDataBinding() {
+ return JAXBDataBinding.NAME;
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2SAX.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2SAX.java
new file mode 100644
index 0000000000..a0b6ff8237
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2SAX.java
@@ -0,0 +1,77 @@
+/*
+ * 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.jaxb;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.PushTransformer;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.databinding.TransformationException;
+import org.apache.tuscany.sca.databinding.BaseTransformer;
+import org.xml.sax.ContentHandler;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class JAXB2SAX extends BaseTransformer<Object, ContentHandler> implements
+ PushTransformer<Object, ContentHandler> {
+
+ private JAXBContextHelper contextHelper;
+
+ public JAXB2SAX(ExtensionPointRegistry registry) {
+ contextHelper = JAXBContextHelper.getInstance(registry);
+ }
+
+ @Override
+ protected Class<Object> getSourceType() {
+ return Object.class;
+ }
+
+ @Override
+ protected Class<ContentHandler> getTargetType() {
+ return ContentHandler.class;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.databinding.PushTransformer#transform(java.lang.Object, java.lang.Object, org.apache.tuscany.sca.databinding.TransformationContext)
+ */
+ public void transform(Object source, ContentHandler target, TransformationContext tContext) {
+ try {
+ JAXBContext context = contextHelper.createJAXBContext(tContext, true);
+ Marshaller marshaller = context.createMarshaller();
+ Object jaxbElement = JAXBContextHelper.createJAXBElement(context, tContext.getSourceDataType(), source);
+ marshaller.marshal(jaxbElement, target);
+ } catch (Exception e) {
+ throw new TransformationException(e);
+ }
+ }
+
+ @Override
+ public int getWeight() {
+ return 20;
+ }
+
+ @Override
+ public String getSourceDataBinding() {
+ return JAXBDataBinding.NAME;
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2String.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2String.java
new file mode 100644
index 0000000000..7ecca3a042
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXB2String.java
@@ -0,0 +1,82 @@
+/*
+ * 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.jaxb;
+
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.PullTransformer;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.databinding.TransformationException;
+import org.apache.tuscany.sca.databinding.BaseTransformer;
+import org.apache.tuscany.sca.databinding.xml.XMLStringDataBinding;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class JAXB2String extends BaseTransformer<Object, String> implements PullTransformer<Object, String> {
+ private JAXBContextHelper contextHelper;
+
+ public JAXB2String(ExtensionPointRegistry registry) {
+ contextHelper = JAXBContextHelper.getInstance(registry);
+ }
+ public String transform(Object source, TransformationContext tContext) {
+ try {
+ JAXBContext context = contextHelper.createJAXBContext(tContext, true);
+ Marshaller marshaller = context.createMarshaller();
+ StringWriter writer = new StringWriter();
+ StreamResult result = new StreamResult(writer);
+ Object jaxbElement = JAXBContextHelper.createJAXBElement(context, tContext.getSourceDataType(), source);
+ marshaller.marshal(jaxbElement, result);
+ return writer.toString();
+ } catch (Exception e) {
+ throw new TransformationException(e);
+ }
+ }
+
+ @Override
+ protected Class<Object> getSourceType() {
+ return Object.class;
+ }
+
+ @Override
+ protected Class<String> getTargetType() {
+ return String.class;
+ }
+
+ @Override
+ public int getWeight() {
+ return 30;
+ }
+
+ @Override
+ public String getSourceDataBinding() {
+ return JAXBDataBinding.NAME;
+ }
+
+ @Override
+ public String getTargetDataBinding() {
+ return XMLStringDataBinding.NAME;
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java
new file mode 100644
index 0000000000..025b4f7c73
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCache.java
@@ -0,0 +1,561 @@
+/*
+ * 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.jaxb;
+
+import java.awt.Image;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.lang.ref.SoftReference;
+import java.net.URI;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.activation.DataHandler;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlTransient;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.transform.Source;
+
+import org.apache.tuscany.sca.common.java.collection.LRUCache;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.extensibility.ClassLoaderContext;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class JAXBContextCache {
+ private static final int CACHE_SIZE = 128;
+
+ private static HashMap<String, Class<?>> loadClassMap = new HashMap<String, Class<?>>();
+
+ static {
+ loadClassMap.put("byte", byte.class);
+ loadClassMap.put("int", int.class);
+ loadClassMap.put("short", short.class);
+ loadClassMap.put("long", long.class);
+ loadClassMap.put("float", float.class);
+ loadClassMap.put("double", double.class);
+ loadClassMap.put("boolean", boolean.class);
+ loadClassMap.put("char", char.class);
+ loadClassMap.put("void", void.class);
+ }
+
+ protected static Class<?>[] JAXB_BUILTIN_CLASSES =
+ {byte[].class, boolean.class, byte.class, char.class, double.class, float.class, int.class, long.class,
+ short.class, void.class, java.awt.Image.class, java.io.File.class, java.lang.Boolean.class,
+ java.lang.Byte.class, java.lang.Character.class, java.lang.Class.class, java.lang.Double.class,
+ java.lang.Float.class, java.lang.Integer.class, java.lang.Long.class, java.lang.Object.class,
+ java.lang.Short.class, java.lang.String.class, java.lang.Void.class, java.math.BigDecimal.class,
+ java.math.BigInteger.class, java.net.URI.class, java.net.URL.class, java.util.Calendar.class,
+ java.util.Date.class, java.util.GregorianCalendar.class, java.util.UUID.class,
+ javax.activation.DataHandler.class, javax.xml.bind.JAXBElement.class, javax.xml.datatype.Duration.class,
+ javax.xml.datatype.XMLGregorianCalendar.class, javax.xml.namespace.QName.class,
+ javax.xml.transform.Source.class};
+
+ protected static final Set<Class<?>> BUILTIN_CLASSES_SET = new HashSet<Class<?>>(Arrays.asList(JAXB_BUILTIN_CLASSES));
+
+ /*
+ protected static Class<?>[] COMMON_ARRAY_CLASSES =
+ new Class[] {char[].class, short[].class, int[].class, long[].class, float[].class, double[].class,
+ String[].class
+ };
+
+ protected static final Set<Class<?>> COMMON_CLASSES_SET = new HashSet<Class<?>>(Arrays.asList(COMMON_ARRAY_CLASSES));
+ */
+
+ protected LRUCache<Object, JAXBContext> cache;
+ protected Pool<JAXBContext, Marshaller> mpool;
+ protected Pool<JAXBContext, Unmarshaller> upool;
+
+ // protected JAXBContext commonContext;
+ protected JAXBContext defaultContext;
+ private ExtensionPointRegistry registry;
+
+ public JAXBContextCache(ExtensionPointRegistry registry) {
+ this(CACHE_SIZE, CACHE_SIZE, CACHE_SIZE, registry);
+ }
+
+ public JAXBContextCache(int contextSize, int marshallerSize, int unmarshallerSize, ExtensionPointRegistry registry) {
+ this.registry = registry;
+ cache = new LRUCache<Object, JAXBContext>(contextSize);
+ mpool = new Pool<JAXBContext, Marshaller>();
+ upool = new Pool<JAXBContext, Unmarshaller>();
+ defaultContext = getDefaultJAXBContext();
+ }
+
+ private JAXBContext newJAXBContext(final Class<?>... classesToBeBound) throws JAXBException {
+ try {
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<JAXBContext>() {
+ public JAXBContext run() throws JAXBException {
+ // Try to set up TCCL so that JAXBContext service discovery works in OSGi
+ ClassLoader tccl =
+ ClassLoaderContext.setContextClassLoader(JAXBContextCache.class.getClassLoader(),
+ registry.getServiceDiscovery(),
+ // The service provider of JAXBContext doesn't extend JAXBContext
+ // We should use the service name instead of the class
+ JAXBContext.class.getName(),
+ DatatypeFactory.class.getName());
+ try {
+ JAXBContext context = JAXBContext.newInstance(classesToBeBound);
+ return context;
+ } finally {
+ if (tccl != null) {
+ Thread.currentThread().setContextClassLoader(tccl);
+ }
+ }
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw (JAXBException)e.getException();
+ }
+ }
+
+
+ public JAXBContext getDefaultJAXBContext() {
+ try {
+ return newJAXBContext();
+ } catch (JAXBException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * @param name of primitive type
+ * @return primitive Class or null
+ */
+ public static Class<?> getPrimitiveClass(String text) {
+ return loadClassMap.get(text);
+ }
+
+ /**
+ * Return the class for this name
+ *
+ * @return Class
+ */
+ private static Class<?> forName(final String className, final boolean initialize, final ClassLoader classloader)
+ throws ClassNotFoundException {
+ // NOTE: This method must remain private because it uses AccessController
+ Class<?> cl = null;
+ try {
+ cl = AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
+ public Class<?> run() throws ClassNotFoundException {
+ // Class.forName does not support primitives
+ Class<?> cls = getPrimitiveClass(className);
+ if (cls == null) {
+ cls = Class.forName(className, initialize, classloader);
+ }
+ return cls;
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw (ClassNotFoundException)e.getException();
+ }
+
+ return cl;
+ }
+
+ public Marshaller getMarshaller(JAXBContext context) throws JAXBException {
+ Marshaller marshaller = mpool.get(context);
+ if (marshaller == null) {
+ marshaller = context.createMarshaller();
+ }
+ marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
+ return marshaller;
+ }
+
+ public void releaseJAXBMarshaller(JAXBContext context, Marshaller marshaller) {
+ if (marshaller != null) {
+ marshaller.setAttachmentMarshaller(null);
+ mpool.put(context, marshaller);
+ // No point unsetting marshaller's JAXB_FRAGMENT property, since we'll just reset it when
+ // doing the next get.
+ }
+ }
+
+ public Unmarshaller getUnmarshaller(JAXBContext context) throws JAXBException {
+ Unmarshaller unmarshaller = upool.get(context);
+ if (unmarshaller == null) {
+ unmarshaller = context.createUnmarshaller();
+ }
+ return unmarshaller;
+ }
+
+ public void releaseJAXBUnmarshaller(JAXBContext context, Unmarshaller unmarshaller) {
+ if (unmarshaller != null) {
+ unmarshaller.setAttachmentUnmarshaller(null);
+ upool.put(context, unmarshaller);
+ }
+ }
+
+ public LRUCache<Object, JAXBContext> getCache() {
+ return cache;
+ }
+
+ public JAXBContext getJAXBContext(Class<?> cls) throws JAXBException {
+ if (BUILTIN_CLASSES_SET.contains(cls)) {
+ return defaultContext;
+ }
+ return getJAXBContext(new Class<?>[] {cls});
+ }
+
+ public JAXBContext getJAXBContext(Class<?>[] classes) throws JAXBException {
+ Set<Class<?>> classSet = new HashSet<Class<?>>(Arrays.asList(classes));
+ return getJAXBContext(classSet);
+ }
+
+ public JAXBContext getJAXBContext(Set<Class<?>> classes) throws JAXBException {
+ // Remove the JAXB built-in types to maximize the cache hit
+ Set<Class<?>> classSet = new HashSet<Class<?>>(classes);
+ classSet.removeAll(BUILTIN_CLASSES_SET);
+
+ // FIXME: [rfeng] Remove java classes that are mapped to the same XSD type to avoid
+ // conflicts
+ if (classSet.contains(Date[].class)) {
+ classSet.remove(Calendar[].class);
+ }
+
+ if (classSet.contains(URI[].class)) {
+ classSet.remove(UUID[].class);
+ }
+
+ if (classSet.contains(Source[].class)) {
+ classSet.remove(Image[].class);
+ classSet.remove(DataHandler[].class);
+ }
+
+ classSet = getJAXBClasses(classSet);
+
+ if(classSet.isEmpty()) {
+ return defaultContext;
+ }
+
+ synchronized (cache) {
+ JAXBContext context = cache.get(classSet);
+ if (context != null) {
+ return context;
+ }
+ context = newJAXBContext(classSet.toArray(new Class<?>[classSet.size()]));
+ cache.put(classSet, context);
+ return context;
+ }
+ }
+
+ public void clear() {
+ synchronized (cache) {
+ cache.clear();
+ }
+ /*
+ synchronized (upool) {
+ upool.clear();
+ }
+ synchronized (upool) {
+ upool.clear();
+ }
+ */
+ }
+
+ //
+ // This inner class is copied in its entirety from the Axis2 utility class,
+ // org.apache.axis2.jaxws.message.databinding.JAXBUtils. We could look into extending but it's such a basic data structure
+ // without other dependencies so we might be better off copying it and avoiding a new
+ // Axis2 dependency here.
+ //
+
+ /**
+ * Pool a list of items for a specific key
+ *
+ * @param <K> Key
+ * @param <V> Pooled object
+ */
+ private static class Pool<K,V> {
+ private SoftReference<Map<K,List<V>>> softMap =
+ new SoftReference<Map<K,List<V>>>(
+ new ConcurrentHashMap<K, List<V>>());
+
+ // The maps are freed up when a LOAD FACTOR is hit
+ private static final int MAX_LIST_FACTOR = 50;
+ private static final int MAX_LOAD_FACTOR = 32; // Maximum number of JAXBContext to store
+
+ /**
+ * @param key
+ * @return removed item from pool or null.
+ */
+ public V get(K key) {
+ List<V> values = getValues(key);
+ synchronized (values) {
+ if (values.size()>0) {
+ V v = values.remove(values.size()-1);
+ return v;
+
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Add item back to pool
+ * @param key
+ * @param value
+ */
+ public void put(K key, V value) {
+ adjustSize();
+ List<V> values = getValues(key);
+ synchronized (values) {
+ if (values.size() < MAX_LIST_FACTOR) {
+ values.add(value);
+ }
+ }
+ }
+
+ /**
+ * Get or create a list of the values for the key
+ * @param key
+ * @return list of values.
+ */
+ private List<V> getValues(K key) {
+ Map<K,List<V>> map = softMap.get();
+ List<V> values = null;
+ if (map != null) {
+ values = map.get(key);
+ if(values !=null) {
+ return values;
+ }
+ }
+ synchronized (this) {
+ if (map != null) {
+ values = map.get(key);
+ }
+ if (values == null) {
+ if (map == null) {
+ map = new ConcurrentHashMap<K, List<V>>();
+ softMap =
+ new SoftReference<Map<K,List<V>>>(map);
+ }
+ values = new ArrayList<V>();
+ map.put(key, values);
+
+ }
+ return values;
+ }
+ }
+
+ /**
+ * AdjustSize
+ * When the number of keys exceeds the maximum load, half
+ * of the entries are deleted.
+ *
+ * The assumption is that the JAXBContexts, UnMarshallers, Marshallers, etc. require
+ * a large footprint.
+ */
+ private void adjustSize() {
+ Map<K,List<V>> map = softMap.get();
+ if (map != null && map.size() > MAX_LOAD_FACTOR) {
+ // Remove every other Entry in the map.
+ Iterator it = map.entrySet().iterator();
+ boolean removeIt = false;
+ while (it.hasNext()) {
+ it.next();
+ if (removeIt) {
+ it.remove();
+ }
+ removeIt = !removeIt;
+ }
+ }
+ }
+ }
+
+ /**
+ * Find the JAXB classes (looking into packages) to be bound
+ * @param classes A collection of classes
+ * @return A set of classes that include the ObjectFactory and indexed JAXB classes
+ * @throws JAXBException
+ */
+ private static Set<Class<?>> getJAXBClasses(Collection<Class<?>> classes) throws JAXBException {
+ Set<Class<?>> classSet = new HashSet<Class<?>>();
+ // Index the packages
+ Map<Package, ClassLoader> pkgs = getPackages(classes);
+ Set<Package> nonJAXBPackages = new HashSet<Package>();
+ for (Map.Entry<Package, ClassLoader> p : pkgs.entrySet()) {
+ Package pkg = p.getKey();
+ if (pkg == null) {
+ continue;
+ }
+ Set<Class<?>> set = getJAXBClasses(pkg.getName(), p.getValue());
+ if (set.isEmpty()) {
+ // No JAXB package
+ nonJAXBPackages.add(pkg);
+ } else {
+ // Add JAXB ObjectFactory and indexed classes
+ classSet.addAll(set);
+ }
+ }
+ // Adding classes that are not part of JAXB packages
+ for (Class<?> cls : classes) {
+
+ Package pkg = getPackage(cls);
+ if (pkg == null || nonJAXBPackages.contains(pkg)) {
+ classSet.add(cls);
+ } else {
+ // TUSCANY-3162: Test if a class is generated by JAXB
+ // There might be the case that non-JAXB classes are in the same package as the JAXB classes
+ if (!cls.isAnnotationPresent(XmlType.class)
+ && !cls.isAnnotationPresent(XmlEnum.class)
+ && !cls.isAnnotationPresent(XmlSeeAlso.class)
+ && !cls.isAnnotationPresent(XmlRootElement.class)
+ && !cls.isAnnotationPresent(XmlTransient.class)) {
+ classSet.add(cls);
+ }
+ }
+ }
+ return classSet;
+ }
+
+ /**
+ * Get the package for a class, taking array into account
+ * @param cls
+ * @return
+ */
+ private static Package getPackage(Class<?> cls) {
+ Class<?> type = cls;
+ while (type.isArray()) {
+ type = type.getComponentType();
+ }
+ return type.getPackage();
+ }
+
+ /**
+ * Get a map of packages
+ * @param classes
+ * @return
+ */
+ private static Map<Package, ClassLoader> getPackages(Collection<Class<?>> classes) {
+ Map<Package, ClassLoader> pkgs = new HashMap<Package, ClassLoader>();
+ for (Class<?> cls : classes) {
+ Package pkg = getPackage(cls);
+ if (pkg != null) {
+ pkgs.put(pkg, cls.getClassLoader());
+ }
+ }
+ return pkgs;
+ }
+
+ /**
+ * Find ObjectFactory and indexed JAXB classes for the package
+ * @param pkg
+ * @param classLoader
+ * @return
+ * @throws JAXBException
+ */
+ private static Set<Class<?>> getJAXBClasses(String pkg, ClassLoader classLoader) throws JAXBException {
+ Set<Class<?>> classes = new HashSet<Class<?>>();
+ List<Class<?>> indexedClasses;
+
+ // look for ObjectFactory and load it
+ final Class<?> o;
+ try {
+ o = forName(pkg + ".ObjectFactory", false, classLoader);
+ classes.add(o);
+ } catch (ClassNotFoundException e) {
+ // not necessarily an error
+ }
+
+ // look for jaxb.index and load the list of classes
+ try {
+ indexedClasses = loadIndexedClasses(pkg, classLoader);
+ } catch (IOException e) {
+ throw new JAXBException(e);
+ }
+ if (indexedClasses != null) {
+ classes.addAll(indexedClasses);
+ }
+
+ return classes;
+ }
+
+ /**
+ * Look for jaxb.index file in the specified package and load it's contents
+ *
+ * @param pkg package name to search in
+ * @param classLoader ClassLoader to search in
+ * @return a List of Class objects to load, null if there weren't any
+ * @throws IOException if there is an error reading the index file
+ * @throws JAXBException if there are any errors in the index file
+ */
+ private static List<Class<?>> loadIndexedClasses(String pkg, ClassLoader classLoader) throws IOException,
+ JAXBException {
+ if (classLoader == null) {
+ return null;
+ }
+ final String resource = pkg.replace('.', '/') + "/jaxb.index";
+ final InputStream resourceAsStream = classLoader.getResourceAsStream(resource);
+
+ if (resourceAsStream == null) {
+ return null;
+ }
+
+ BufferedReader in = new BufferedReader(new InputStreamReader(resourceAsStream, "UTF-8"));
+ try {
+ List<Class<?>> classes = new ArrayList<Class<?>>();
+ String className = in.readLine();
+ while (className != null) {
+ className = className.trim();
+ if (className.startsWith("#") || (className.length() == 0)) {
+ className = in.readLine();
+ continue;
+ }
+
+ try {
+ classes.add(forName(pkg + '.' + className, false, classLoader));
+ } catch (ClassNotFoundException e) {
+ throw new JAXBException(e);
+ }
+
+ className = in.readLine();
+ }
+ return classes;
+ } finally {
+ in.close();
+ }
+ }
+
+}
+
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java
new file mode 100644
index 0000000000..50fc346270
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextHelper.java
@@ -0,0 +1,492 @@
+/*
+ * 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.jaxb;
+
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.JAXBIntrospector;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlEnum;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchema;
+import javax.xml.bind.annotation.XmlSeeAlso;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.common.java.collection.LRUCache;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.databinding.SimpleTypeMapper;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.databinding.TransformationException;
+import org.apache.tuscany.sca.databinding.impl.SimpleTypeMapperImpl;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.apache.tuscany.sca.interfacedef.java.JavaInterface;
+import org.apache.tuscany.sca.interfacedef.util.WrapperInfo;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+// FIXME: [rfeng] We probably should turn this into a pluggable system service
+public final class JAXBContextHelper {
+ private final JAXBContextCache cache;
+ private final static SimpleTypeMapper SIMPLE_TYPE_MAPPER = new SimpleTypeMapperImpl();
+
+ public JAXBContextHelper(ExtensionPointRegistry registry) {
+ cache = new JAXBContextCache(registry);
+ }
+
+ public static JAXBContextHelper getInstance(ExtensionPointRegistry registry) {
+ UtilityExtensionPoint utilityExtensionPoint = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ return utilityExtensionPoint.getUtility(JAXBContextHelper.class);
+ }
+
+ /**
+ * Create a JAXBContext for a given class
+ * @param cls
+ * @return
+ * @throws JAXBException
+ */
+ public JAXBContext createJAXBContext(Class<?> cls) throws JAXBException {
+ return cache.getJAXBContext(cls);
+ }
+
+ public JAXBContext createJAXBContext(TransformationContext tContext, boolean source) throws JAXBException {
+ if (tContext == null)
+ throw new TransformationException("JAXB context is not set for the transformation.");
+
+ // TODO: [rfeng] Need to figure out what's the best granularity to create the JAXBContext
+ // per interface, operation or parameter
+ Operation op = source ? tContext.getSourceOperation() : tContext.getTargetOperation();
+ if (op != null) {
+ synchronized (op) {
+ JAXBContext context = op.getInputType().getMetaData(JAXBContext.class);
+ if (context == null) {
+ context = createJAXBContext(getDataTypes(op, true));
+ op.getInputType().setMetaData(JAXBContext.class, context);
+ }
+ return context;
+ }
+ }
+
+ // For property transformation, the operation can be null
+ DataType<?> dataType = source ? tContext.getSourceDataType() : tContext.getTargetDataType();
+ return createJAXBContext(dataType);
+
+ }
+
+ private static Class<?>[] getSeeAlso(Class<?> interfaze) {
+ if (interfaze == null) {
+ return null;
+ }
+ XmlSeeAlso seeAlso = interfaze.getAnnotation(XmlSeeAlso.class);
+ if (seeAlso == null) {
+ return null;
+ } else {
+ return seeAlso.value();
+ }
+ }
+
+ public JAXBContext createJAXBContext(DataType dataType) throws JAXBException {
+ return createJAXBContext(findClasses(dataType));
+ }
+
+ public Unmarshaller getUnmarshaller(JAXBContext context) throws JAXBException {
+ return cache.getUnmarshaller(context);
+ }
+
+ public void releaseJAXBUnmarshaller(JAXBContext context, Unmarshaller unmarshaller) {
+ cache.releaseJAXBUnmarshaller(context, unmarshaller);
+ }
+
+ public Marshaller getMarshaller(JAXBContext context) throws JAXBException {
+ return cache.getMarshaller(context);
+ }
+
+ public void releaseJAXBMarshaller(JAXBContext context, Marshaller marshaller) {
+ cache.releaseJAXBMarshaller(context, marshaller);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Object createJAXBElement(JAXBContext context, DataType dataType, Object value) {
+ Class<?> type = dataType == null ? value.getClass() : dataType.getPhysical();
+ QName name = JAXBDataBinding.ROOT_ELEMENT;
+ if (context != null) {
+ Object logical = dataType == null ? null : dataType.getLogical();
+ if (logical instanceof XMLType) {
+ XMLType xmlType = (XMLType)logical;
+ if (xmlType.isElement()) {
+ name = xmlType.getElementName();
+ } else {
+ /**
+ * Set the declared type to Object.class so that xsi:type
+ * will be produced
+ */
+ type = Object.class;
+ }
+ } else {
+ type = Object.class;
+ }
+ }
+
+ JAXBIntrospector introspector = context.createJAXBIntrospector();
+ Object element = null;
+ if (value != null && introspector.isElement(value)) {
+ // NOTE: [rfeng] We cannot wrap an element in a JAXBElement
+ element = value;
+ }
+ if (element == null) {
+ // For local elements, we still have to produce xsi:type
+ element = new JAXBElement(name, Object.class, value);
+ }
+ return element;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static Object createReturnValue(JAXBContext context, DataType dataType, Object value) {
+ Class<?> cls = getJavaType(dataType);
+ if (cls == JAXBElement.class) {
+ return createJAXBElement(context, dataType, value);
+ } else {
+ if (value instanceof JAXBElement) {
+ Object returnValue = ((JAXBElement)value).getValue();
+
+ if (returnValue == null){
+ // TUSCANY-3530
+ // something went wrong in the transformation that
+ // generated the JAXBElement. Have seen this when trying
+ // to convert a value to a simple type with an incompatible
+ // value.
+ throw new TransformationException("Null returned when trying to convert value to: " + cls.getName());
+ }
+ return returnValue;
+ } else {
+ return value;
+ }
+ }
+ }
+
+ /**
+ * Create a JAXContext for an array of classes
+ * @param classes
+ * @return
+ * @throws JAXBException
+ */
+ public JAXBContext createJAXBContext(Class<?>[] classes) throws JAXBException {
+ return cache.getJAXBContext(classes);
+ }
+
+ public JAXBContext createJAXBContext(Set<Class<?>> classes) throws JAXBException {
+ return cache.getJAXBContext(classes);
+ }
+
+ /**
+ * Create a JAXBContext for a given java interface
+ * @param intf
+ * @return
+ * @throws JAXBException
+ */
+ public JAXBContext createJAXBContext(Interface intf, boolean useWrapper) throws JAXBException {
+ synchronized (cache) {
+ LRUCache<Object, JAXBContext> map = cache.getCache();
+ Integer key = new Integer(System.identityHashCode(intf));
+ JAXBContext context = map.get(key);
+ if (context != null) {
+ return context;
+ }
+ List<DataType> dataTypes = getDataTypes(intf, useWrapper);
+ context = createJAXBContext(dataTypes);
+ map.put(key, context);
+ return context;
+ }
+ }
+
+ public JAXBContext createJAXBContext(List<DataType> dataTypes) throws JAXBException {
+ JAXBContext context;
+ Set<Class<?>> classes = new HashSet<Class<?>>();
+ Set<Type> visited = new HashSet<Type>();
+ for (DataType d : dataTypes) {
+ findClasses(d, classes, visited);
+ }
+
+ context = createJAXBContext(classes);
+ return context;
+ }
+
+ private static Set<Class<?>> findClasses(DataType d) {
+ Set<Class<?>> classes = new HashSet<Class<?>>();
+ Set<Type> visited = new HashSet<Type>();
+ findClasses(d, classes, visited);
+ return classes;
+ }
+
+ private static void findClasses(DataType d, Set<Class<?>> classes, Set<Type> visited) {
+ if (d == null) {
+ return;
+ }
+ String db = d.getDataBinding();
+ if (JAXBDataBinding.NAME.equals(db) || (db != null && db.startsWith("java:")) || db == null) {
+ if (!d.getPhysical().isInterface() && !JAXBElement.class.isAssignableFrom(d.getPhysical())) {
+ classes.add(d.getPhysical());
+ }
+ }
+ if (d.getPhysical() != d.getGenericType()) {
+ findClasses(d.getGenericType(), classes, visited);
+ }
+ }
+
+ /**
+ * Find referenced classes in the generic type
+ * @param type
+ * @param classSet
+ * @param visited
+ */
+ private static void findClasses(Type type, Set<Class<?>> classSet, Set<Type> visited) {
+ if (visited.contains(type) || type == null) {
+ return;
+ }
+ visited.add(type);
+ if (type instanceof Class) {
+ Class<?> cls = (Class<?>)type;
+ if (!cls.isInterface()) {
+ classSet.add(cls);
+ }
+ return;
+ } else if (type instanceof ParameterizedType) {
+ ParameterizedType pType = (ParameterizedType)type;
+ findClasses(pType.getRawType(), classSet, visited);
+ for (Type t : pType.getActualTypeArguments()) {
+ findClasses(t, classSet, visited);
+ }
+ } else if (type instanceof TypeVariable) {
+ TypeVariable<?> tv = (TypeVariable<?>)type;
+ for (Type t : tv.getBounds()) {
+ findClasses(t, classSet, visited);
+ }
+ } else if (type instanceof GenericArrayType) {
+ GenericArrayType gType = (GenericArrayType)type;
+ findClasses(gType.getGenericComponentType(), classSet, visited);
+ } else if (type instanceof WildcardType) {
+ WildcardType wType = (WildcardType)type;
+ for (Type t : wType.getLowerBounds()) {
+ findClasses(t, classSet, visited);
+ }
+ for (Type t : wType.getUpperBounds()) {
+ findClasses(t, classSet, visited);
+ }
+ }
+ }
+
+ public JAXBContext createJAXBContext(Interface intf) throws JAXBException {
+ return createJAXBContext(intf, true);
+ }
+
+ /**
+ * @param intf
+ * @param useWrapper Use wrapper classes?
+ * @return
+ */
+ private static List<DataType> getDataTypes(Interface intf, boolean useWrapper) {
+ List<DataType> dataTypes = new ArrayList<DataType>();
+ for (Operation op : intf.getOperations()) {
+ getDataTypes(dataTypes, op, useWrapper);
+ }
+ return dataTypes;
+ }
+
+ private static List<DataType> getDataTypes(Operation op, boolean useWrapper) {
+ List<DataType> dataTypes = new ArrayList<DataType>();
+ getDataTypes(dataTypes, op, useWrapper);
+ // Adding classes referenced by @XmlSeeAlso in the java interface
+ Interface interface1 = op.getInterface();
+ if (interface1 instanceof JavaInterface) {
+ JavaInterface javaInterface = (JavaInterface)interface1;
+ Class<?>[] seeAlso = getSeeAlso(javaInterface.getJavaClass());
+ if (seeAlso != null) {
+ for (Class<?> cls : seeAlso) {
+ dataTypes.add(new DataTypeImpl<XMLType>(JAXBDataBinding.NAME, cls, XMLType.UNKNOWN));
+ }
+ }
+ seeAlso = getSeeAlso(javaInterface.getCallbackClass());
+ if (seeAlso != null) {
+ for (Class<?> cls : seeAlso) {
+ dataTypes.add(new DataTypeImpl<XMLType>(JAXBDataBinding.NAME, cls, XMLType.UNKNOWN));
+ }
+ }
+ }
+ return dataTypes;
+ }
+
+ private static void getDataTypes(List<DataType> dataTypes, Operation op, boolean useWrapper) {
+ WrapperInfo wrapper = op.getWrapper();
+ if (useWrapper && wrapper != null) {
+ DataType dt1 = wrapper.getInputWrapperType();
+ if (dt1 != null) {
+ dataTypes.add(dt1);
+ }
+ DataType dt2 = wrapper.getOutputWrapperType();
+ if (dt2 != null) {
+ dataTypes.add(dt2);
+ }
+ }
+ // FIXME: [rfeng] We may need to find the referenced classes in the child types
+ // else
+ {
+ for (DataType dt1 : op.getInputType().getLogical()) {
+ dataTypes.add(dt1);
+ }
+ DataType dt2 = op.getOutputType();
+ if (dt2 != null) {
+ dataTypes.add(dt2);
+ }
+ }
+ for (DataType<DataType> dt3 : op.getFaultTypes()) {
+ DataType dt4 = dt3.getLogical();
+ if (dt4 != null) {
+ dataTypes.add(dt4);
+ }
+ }
+ }
+
+ public static Class<?> getJavaType(DataType<?> dataType) {
+ if (dataType == null) {
+ return null;
+ }
+ Class type = dataType.getPhysical();
+ if (JAXBElement.class.isAssignableFrom(type)) {
+ Type generic = dataType.getGenericType();
+ type = Object.class;
+ }
+ if (type == Object.class && dataType.getLogical() instanceof XMLType) {
+ XMLType xType = (XMLType)dataType.getLogical();
+ Class javaType = SIMPLE_TYPE_MAPPER.getJavaType(xType.getTypeName());
+ if (javaType != null) {
+ type = javaType;
+ }
+ }
+ return type;
+ }
+
+ public static XMLType getXmlTypeName(Class<?> javaType) {
+ if (javaType.isInterface()) {
+ // JAXB doesn't support interfaces
+ return null;
+ }
+ String namespace = null;
+ String name = null;
+ Package pkg = javaType.getPackage();
+ if (pkg != null) {
+ XmlSchema schema = pkg.getAnnotation(XmlSchema.class);
+ if (schema != null) {
+ namespace = schema.namespace();
+ }
+ }
+
+ QName elementQName = null;
+ QName typeQName = null;
+ XmlRootElement rootElement = javaType.getAnnotation(XmlRootElement.class);
+ if (rootElement != null) {
+ String elementName = rootElement.name();
+ String elementNamespace = rootElement.namespace();
+ if (elementNamespace.equals("##default")) {
+ elementNamespace = namespace;
+ }
+ if (elementName.equals("##default")) {
+ elementName = jaxbDecapitalize(javaType.getSimpleName());
+ }
+ elementQName = new QName(elementNamespace, elementName);
+ }
+ XmlType type = javaType.getAnnotation(XmlType.class);
+ if (type != null) {
+ String typeNamespace = type.namespace();
+ String typeName = type.name();
+
+ if (typeNamespace.equals("##default")) {
+ // namespace is from the package
+ typeNamespace = namespace;
+ }
+
+ if (typeName.equals("##default")) {
+ typeName = jaxbDecapitalize(javaType.getSimpleName());
+ }
+ typeQName = new QName(typeNamespace, typeName);
+ } else {
+ XmlEnum xmlEnum = javaType.getAnnotation(XmlEnum.class);
+ // POJO can have the @XmlSchema on the package-info too
+ if (xmlEnum != null || namespace != null) {
+ name = jaxbDecapitalize(javaType.getSimpleName());
+ typeQName = new QName(namespace, name);
+ }
+ }
+ if (elementQName == null && typeQName == null) {
+ return null;
+ }
+ return new XMLType(elementQName, typeQName);
+ }
+
+ /**
+ * The JAXB RI doesn't implement the decapitalization algorithm in the
+ * JAXB spec. See Sun bug 6505643 for details. This means that instead
+ * of calling java.beans.Introspector.decapitalize() as the JAXB spec says,
+ * Tuscany needs to mimic the incorrect JAXB RI algorithm.
+ */
+ public static String jaxbDecapitalize(String name) {
+ // find first lower case char in name
+ int lower = name.length();
+ for (int i = 0; i < name.length(); i++) {
+ if (Character.isLowerCase(name.charAt(i))) {
+ lower = i;
+ break;
+ }
+ }
+
+ int decap;
+ if (name.length() == 0) {
+ decap = 0; // empty string: nothing to do
+ } else if (lower == 0) {
+ decap = 0; // first char is lower case: nothing to do
+ } else if (lower == 1) {
+ decap = 1; // one upper followed by lower: decapitalize 1 char
+ } else if (lower < name.length()) {
+ decap = lower - 1; // n uppers followed by at least one lower: decapitalize n-1 chars
+ } else {
+ decap = name.length(); // all upper case: decapitalize all chars
+ }
+
+ return name.substring(0, decap).toLowerCase() + name.substring(decap);
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBDataBinding.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBDataBinding.java
new file mode 100644
index 0000000000..5d7527cfa7
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBDataBinding.java
@@ -0,0 +1,148 @@
+/*
+ * 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.jaxb;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.common.xml.dom.DOMHelper;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.BaseDataBinding;
+import org.apache.tuscany.sca.databinding.WrapperHandler;
+import org.apache.tuscany.sca.databinding.XMLTypeHelper;
+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;
+import org.w3c.dom.Document;
+
+/**
+ * JAXB DataBinding
+ *
+ * @version $Rev$ $Date$
+ */
+public class JAXBDataBinding extends BaseDataBinding {
+ public static final String NAME = JAXBElement.class.getName();
+
+ public static final String ROOT_NAMESPACE = "http://tuscany.apache.org/xmlns/sca/databinding/jaxb/1.0";
+ public static final QName ROOT_ELEMENT = new QName(ROOT_NAMESPACE, "root");
+
+ private JAXBWrapperHandler wrapperHandler;
+ private JAXBTypeHelper xmlTypeHelper;
+ private DOMHelper domHelper;
+ private JAXBContextHelper contextHelper;
+
+ public JAXBDataBinding(ExtensionPointRegistry registry) {
+ super(NAME, JAXBElement.class);
+ this.wrapperHandler = new JAXBWrapperHandler();
+ this.xmlTypeHelper = new JAXBTypeHelper(registry);
+ this.domHelper = DOMHelper.getInstance(registry);
+ contextHelper = JAXBContextHelper.getInstance(registry);
+ }
+
+ @Override
+ public boolean introspect(DataType dataType, Operation operation) {
+ Class javaType = dataType.getPhysical();
+ if (JAXBElement.class.isAssignableFrom(javaType)) {
+ Type type = javaType.getGenericSuperclass();
+ if (type instanceof ParameterizedType) {
+ ParameterizedType parameterizedType = ((ParameterizedType)type);
+ Type rawType = parameterizedType.getRawType();
+ if (rawType == JAXBElement.class) {
+ Type actualType = parameterizedType.getActualTypeArguments()[0];
+ if (actualType instanceof Class) {
+ XMLType xmlType = JAXBContextHelper.getXmlTypeName((Class)actualType);
+ dataType.setLogical(xmlType);
+ dataType.setDataBinding(NAME);
+ return true;
+ }
+ }
+ }
+ if (dataType.getLogical() == null) {
+ dataType.setLogical(XMLType.UNKNOWN);
+ }
+ dataType.setDataBinding(NAME);
+ return true;
+ }
+
+ XMLType xmlType = JAXBContextHelper.getXmlTypeName(javaType);
+ if (xmlType == null) {
+ return false;
+ }
+ dataType.setLogical(xmlType);
+ dataType.setDataBinding(NAME);
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object copy(Object arg,
+ DataType sourceDataType,
+ DataType targetDataType,
+ Operation sourceOperation,
+ Operation targetOperation) {
+ try {
+ boolean isElement = false;
+ if (sourceDataType == null) {
+ Class cls = arg.getClass();
+ if (arg instanceof JAXBElement) {
+ isElement = true;
+ cls = ((JAXBElement)arg).getDeclaredType();
+ }
+ sourceDataType = new DataTypeImpl<XMLType>(NAME, cls, XMLType.UNKNOWN);
+ }
+ JAXBContext context = contextHelper.createJAXBContext(sourceDataType);
+ arg = JAXBContextHelper.createJAXBElement(context, sourceDataType, arg);
+ Document doc = domHelper.newDocument();
+ context.createMarshaller().marshal(arg, doc);
+
+ Object value;
+ if (targetDataType != null && targetDataType.getPhysical() != sourceDataType.getPhysical()) {
+ JAXBContext targetContext = contextHelper.createJAXBContext(targetDataType);
+ value = targetContext.createUnmarshaller().unmarshal(doc, targetDataType.getPhysical());
+ } else {
+ value = context.createUnmarshaller().unmarshal(doc, sourceDataType.getPhysical());
+ }
+
+ if (isElement && value instanceof JAXBElement) {
+ return value;
+ }
+ return JAXBContextHelper.createReturnValue(context, sourceDataType, value);
+ } catch (Exception e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ @Override
+ public WrapperHandler getWrapperHandler() {
+ return wrapperHandler;
+ }
+
+ @Override
+ public XMLTypeHelper getXMLTypeHelper() {
+ // return new JAXBTypeHelper();
+ return xmlTypeHelper;
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBPropertyDescriptor.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBPropertyDescriptor.java
new file mode 100644
index 0000000000..217345caba
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBPropertyDescriptor.java
@@ -0,0 +1,302 @@
+/*
+ * 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.jaxb;
+
+import java.beans.IndexedPropertyDescriptor;
+import java.beans.PropertyDescriptor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Collection;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.namespace.QName;
+
+import org.oasisopen.sca.ServiceRuntimeException;
+
+/**
+ * A PropertyDescriptor provides access to a bean property. Values can be queried/changed using the
+ * read and writer methods of the PropertyDescriptor.
+ * <p/>
+ * A PropertyDescriptorPlus object wraps a PropertyDescriptor and supplies enhanced set/get methods
+ * that match JAXB semantics.
+ * <p/>
+ * For example, the set(..) method is smart enough to add lists, arrays and atomic values on JAXB
+ * beans.
+ * <p/>
+ * The PropertyDescriptorPlus object also stores the xmlName of the property.
+ *
+ * @See XMLRootElementUtil.createPropertyDescriptorMap , which creates the PropertyDescriptorPlus
+ * objects
+ */
+public class JAXBPropertyDescriptor implements Comparable<JAXBPropertyDescriptor> {
+ PropertyDescriptor descriptor;
+ QName xmlName = null;
+ int index;
+
+ /**
+ * Package protected constructor. Only created by XMLRootElementUtil.createPropertyDescriptorMap
+ * @param descriptor
+ * @param index TODO
+ * @param propertyName
+ *
+ * @see XMLRootElementUtil.createPropertyDescriptorMap
+ */
+ JAXBPropertyDescriptor(PropertyDescriptor descriptor, QName xmlName, int index) {
+ super();
+ this.descriptor = descriptor;
+ this.xmlName = xmlName;
+ }
+
+ /**
+ * Package protected constructor. Only created by XMLRootElementUtil.createPropertyDescriptorMap
+ * @param descriptor
+ * @param index TODO
+ * @param propertyName
+ *
+ * @see XMLRootElementUtil.createPropertyDescriptorMap
+ */
+ JAXBPropertyDescriptor(PropertyDescriptor descriptor, String xmlName, int index) {
+ super();
+ this.descriptor = descriptor;
+ this.xmlName = new QName("", xmlName);
+ }
+
+ public int compareTo(JAXBPropertyDescriptor o) {
+ return index - o.index;
+ }
+
+ /** @return xmlname */
+ public String getXmlName() {
+ return xmlName.getLocalPart();
+ }
+
+ public QName getXmlQName() {
+ return xmlName;
+ }
+
+ /** @return property type */
+ public Class<?> getPropertyType() {
+ return descriptor.getPropertyType();
+ }
+
+ /** @return property name */
+ public String getPropertyName() {
+ return descriptor.getName();
+ }
+
+ /**
+ * Get the object
+ *
+ * @param targetBean
+ * @return Object for this property or null
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ */
+ public Object get(Object targetBean) throws InvocationTargetException, IllegalAccessException {
+ Method method = descriptor.getReadMethod();
+ if (method == null && descriptor.getPropertyType() == Boolean.class) {
+ String propertyName = descriptor.getName();
+ if (propertyName != null) {
+ String methodName = "is";
+ methodName =
+ methodName + ((propertyName.length() > 0) ? propertyName.substring(0, 1).toUpperCase() : "");
+ methodName = methodName + ((propertyName.length() > 1) ? propertyName.substring(1) : "");
+ try {
+ method = targetBean.getClass().getMethod(methodName);
+ } catch (NoSuchMethodException e) {
+ }
+ }
+ }
+ if (method == null) {
+ throw new ServiceRuntimeException("No getter is found");
+ }
+ Object ret = method.invoke(targetBean);
+ if (method.getReturnType() == JAXBElement.class) {
+ ret = ((JAXBElement<?>)ret).getValue();
+ }
+ return ret;
+ }
+
+ /**
+ * Set the object
+ *
+ * @param targetBean
+ * @param propValue
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ * @throws JAXBWrapperException
+ */
+ public void set(Object targetBean, Object propValue) throws InvocationTargetException, IllegalAccessException,
+ JAXBWrapperException {
+
+ Method writeMethod = null;
+ try {
+ // No set occurs if the value is null
+ if (propValue == null) {
+ return;
+ }
+
+ // There are 3 different types of setters that can occur.
+ // 1) Normal Attomic Setter : setFoo(type)
+ // 2) Indexed Array Setter : setFoo(type[])
+ // 3) No Setter case if the property is a List<T>.
+
+ writeMethod = descriptor.getWriteMethod();
+ if (descriptor instanceof IndexedPropertyDescriptor) {
+ // Set for indexed T[]
+ setIndexedArray(targetBean, propValue, writeMethod);
+ } else if (writeMethod == null) {
+ // Set for List<T>
+ setList(targetBean, propValue);
+ } else if (descriptor.getPropertyType() == JAXBElement.class) {
+ if (propValue != null) {
+ Class<?> clazz = propValue.getClass();
+ JAXBElement<?> element = new JAXBElement(xmlName, clazz, propValue);
+ setAtomic(targetBean, element, writeMethod);
+ }
+ } else {
+ // Normal case
+ setAtomic(targetBean, propValue, writeMethod);
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ }
+ }
+
+ /**
+ * Set the property value onto targetBean using the writeMethod
+ *
+ * @param targetBean
+ * @param propValue
+ * @param writeMethod (set(T))
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ * @throws JAXBWrapperException
+ */
+ private void setAtomic(Object targetBean, Object propValue, Method writeMethod) throws InvocationTargetException,
+ IllegalAccessException, JAXBWrapperException {
+ // JAXB provides setters for atomic value.
+
+ if (propValue != null) {
+ // Normal case
+ Object[] SINGLE_PARAM = new Object[1];
+ SINGLE_PARAM[0] = propValue;
+ writeMethod.invoke(targetBean, SINGLE_PARAM);
+ } else {
+ Class<?>[] paramTypes = writeMethod.getParameterTypes();
+
+ if (paramTypes != null && paramTypes.length == 1) {
+ Class<?> paramType = paramTypes[0];
+ if (paramType.isPrimitive() && propValue == null) {
+ //Ignoring null value for primitive type, this could potentially be the way of a customer indicating to set
+ //default values defined in JAXBObject/xmlSchema.
+ return;
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Set the property value using the indexed array setter
+ *
+ * @param targetBean
+ * @param propValue
+ * @param writeMethod set(T[])
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ * @throws JAXBWrapperException
+ */
+ private void setIndexedArray(Object targetBean, Object propValue, Method writeMethod)
+ throws InvocationTargetException, IllegalAccessException, JAXBWrapperException {
+
+ Class<?> paramType = writeMethod.getParameterTypes()[0];
+ Object value = asArray(propValue, paramType);
+ // JAXB provides setters for atomic value.
+ Object[] SINGLE_PARAM = new Object[1];
+ SINGLE_PARAM[0] = value;
+
+ writeMethod.invoke(targetBean, SINGLE_PARAM);
+ }
+
+ /**
+ * Set the property value for the collection case.
+ *
+ * @param targetBean
+ * @param propValue
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ * @throws JAXBWrapperException
+ */
+ private void setList(Object targetBean, Object propValue) throws InvocationTargetException, IllegalAccessException,
+ JAXBWrapperException {
+ // For the List<T> case, there is no setter.
+ // You are supposed to use the getter to obtain access to the collection and then add the collection
+
+ Collection value = asCollection(propValue, descriptor.getPropertyType());
+ Collection collection = (Collection)get(targetBean);
+
+ // Now add our our object to the collection
+ collection.clear();
+ if (propValue != null) {
+ collection.addAll(value);
+ }
+ }
+
+ /**
+ * @param propValue
+ * @param destType
+ * @return propValue as a Collection
+ */
+ private static Collection asCollection(Object propValue, Class<?> destType) {
+ // TODO Missing function
+ // Convert the object into an equivalent object that is a collection
+ if (DataConverter.isConvertable(propValue, destType)) {
+ return (Collection)DataConverter.convert(propValue, destType);
+ } else {
+ String objectClass = (propValue == null) ? "null" : propValue.getClass().getName();
+ throw new ServiceRuntimeException("Cannot convert " + objectClass);
+ }
+ }
+
+ /**
+ * @param propValue
+ * @param destType T[]
+ * @return array of component type
+ */
+ private static Object asArray(Object propValue, Class<?> destType) {
+ if (DataConverter.isConvertable(propValue, destType)) {
+ return DataConverter.convert(propValue, destType);
+ } else {
+ String objectClass = (propValue == null) ? "null" : propValue.getClass().getName();
+ throw new ServiceRuntimeException("Cannot convert " + objectClass);
+
+ }
+ }
+
+ @Override
+ public String toString() {
+ String value = "PropertyDescriptorPlus[";
+ value += " name=" + this.getPropertyName();
+ value += " type=" + this.getPropertyType().getName();
+ value += " propertyDecriptor=" + this.descriptor;
+ return value + "]";
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBTypeHelper.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBTypeHelper.java
new file mode 100644
index 0000000000..84529752de
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBTypeHelper.java
@@ -0,0 +1,244 @@
+/*
+ * 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.jaxb;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.SchemaOutputResolver;
+import javax.xml.namespace.QName;
+import javax.xml.transform.Result;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.stream.StreamResult;
+
+import org.apache.tuscany.sca.contribution.resolver.ModelResolver;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.XMLTypeHelper;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Interface;
+import org.apache.tuscany.sca.interfacedef.util.JavaXMLMapper;
+import org.apache.tuscany.sca.interfacedef.util.TypeInfo;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.apache.tuscany.sca.xsd.XSDFactory;
+import org.apache.tuscany.sca.xsd.XSDefinition;
+import org.oasisopen.sca.ServiceRuntimeException;
+import org.w3c.dom.Document;
+
+public class JAXBTypeHelper implements XMLTypeHelper {
+ private static final String SCHEMA_NS = "http://www.w3.org/2001/XMLSchema";
+ private static final String ANYTYPE_NAME = "anyType";
+ private static final QName ANYTYPE_QNAME = new QName(SCHEMA_NS, ANYTYPE_NAME);
+
+ private JAXBContextHelper contextHelper;
+
+ public JAXBTypeHelper(ExtensionPointRegistry registry) {
+ super();
+ contextHelper = JAXBContextHelper.getInstance(registry);
+ }
+
+ public TypeInfo getTypeInfo(Class javaType, Object logical) {
+ QName xmlType = JavaXMLMapper.getXMLType(javaType);
+ if (xmlType != null) {
+ return new TypeInfo(xmlType, true, null);
+ } else if (javaType.isInterface()) {
+ return new TypeInfo(ANYTYPE_QNAME, true, null);
+ } else {
+ // types.add(javaType);
+ if (logical instanceof XMLType) {
+ xmlType = ((XMLType)logical).getTypeName();
+ }
+ if (xmlType == null) {
+ xmlType = new QName(JAXBContextHelper.jaxbDecapitalize(javaType.getSimpleName()));
+ }
+ return new TypeInfo(xmlType, false, null);
+ }
+ }
+
+ /*
+ public List<XSDefinition> getSchemaDefinitions(XSDFactory factory, ModelResolver resolver) {
+ List<XSDefinition> definitions = new ArrayList<XSDefinition>();
+ generateJAXBSchemas(definitions, factory);
+ return definitions;
+ }
+ */
+
+ public static Map<String, String> generateSchema(JAXBContext context) throws IOException {
+ StringResolverImpl resolver = new StringResolverImpl();
+ context.generateSchema(resolver);
+ Map<String, String> xsds = new HashMap<String, String>();
+ for (Map.Entry<String, StreamResult> xsd : resolver.getResults().entrySet()) {
+ xsds.put(xsd.getKey(), xsd.getValue().getWriter().toString());
+ }
+ return xsds;
+ }
+
+// private static class XSDResolver implements URIResolver {
+// private Map<String, String> xsds;
+//
+// public XSDResolver(Map<String, String> xsds) {
+// super();
+// this.xsds = xsds;
+// }
+//
+// public InputSource resolveEntity(java.lang.String namespace,
+// java.lang.String schemaLocation,
+// java.lang.String baseUri) {
+// String xsd = xsds.get(schemaLocation);
+// if (xsd == null) {
+// return null;
+// }
+// return new InputSource(new StringReader(xsd));
+// }
+//
+// }
+
+ /*
+ private void generateJAXBSchemas1(List<XSDefinition> definitions, XSDFactory factory) {
+ if (types.size() > 0) {
+ try {
+ XmlSchemaCollection collection = new XmlSchemaCollection();
+ Class[] typesArray = new Class[types.size()];
+ typesArray = types.toArray(typesArray);
+ JAXBContext context = JAXBContextHelper.createJAXBContext(typesArray);
+ Map<String, String> results = generateSchema(context);
+ collection.setSchemaResolver(new XSDResolver(results));
+
+ for (Map.Entry<String, String> entry : results.entrySet()) {
+ XSDefinition definition = factory.createXSDefinition();
+ int index = entry.getKey().lastIndexOf('#');
+ String ns = entry.getKey().substring(0, index);
+ String file = entry.getKey().substring(index + 1);
+ definition.setUnresolved(true);
+ definition.setNamespace(ns);
+ definition.setSchema(collection.read(new StringReader(entry.getValue()), null));
+ definition.setSchemaCollection(collection);
+ definition.setUnresolved(false);
+ definitions.add(definition);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ */
+
+ private static class DOMResolverImpl extends SchemaOutputResolver {
+ private Map<String, DOMResult> results = new HashMap<String, DOMResult>();
+
+ @Override
+ public Result createOutput(String ns, String file) throws IOException {
+ DOMResult result = new DOMResult();
+ // TUSCANY-2498: Set the system id to "" so that the xsd:import doesn't produce
+ // an illegal schemaLocation attr
+ result.setSystemId("");
+ results.put(ns, result);
+ return result;
+ }
+
+ public Map<String, DOMResult> getResults() {
+ return results;
+ }
+ }
+
+ /*
+ private void generateJAXBSchemas(List<XSDefinition> definitions, XSDFactory factory) {
+ if (types.size() > 0) {
+ try {
+ Class<?>[] typesArray = new Class<?>[types.size()];
+ typesArray = types.toArray(typesArray);
+ JAXBContext context = JAXBContext.newInstance(typesArray);
+ generateSchemas(definitions, factory, context);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ */
+
+ private void generateSchemas(List<XSDefinition> definitions, XSDFactory factory, JAXBContext context)
+ throws IOException {
+ DOMResolverImpl resolver = new DOMResolverImpl();
+ context.generateSchema(resolver);
+ Map<String, DOMResult> results = resolver.getResults();
+ for (Map.Entry<String, DOMResult> entry : results.entrySet()) {
+ XSDefinition definition = factory.createXSDefinition();
+ definition.setUnresolved(true);
+ definition.setDocument((Document)entry.getValue().getNode());
+ definition.setNamespace(entry.getKey());
+ URI location = null;
+ try {
+ location = new URI(entry.getValue().getSystemId());
+ } catch (URISyntaxException e) {
+ // ignore: use null value
+ }
+ definition.setLocation(location);
+ definitions.add(definition);
+ }
+ }
+
+ private static class StringResolverImpl extends SchemaOutputResolver {
+ private Map<String, StreamResult> results = new HashMap<String, StreamResult>();
+
+ @Override
+ public Result createOutput(String ns, String file) throws IOException {
+ StringWriter sw = new StringWriter();
+ StreamResult result = new StreamResult(sw);
+ String sysId = ns + '#' + file;
+ result.setSystemId(sysId);
+ results.put(sysId, result);
+ return result;
+ }
+
+ public Map<String, StreamResult> getResults() {
+ return results;
+ }
+ }
+
+ public List<XSDefinition> getSchemaDefinitions(XSDFactory factory, ModelResolver resolver, Interface intf) {
+ try {
+ JAXBContext context = contextHelper.createJAXBContext(intf, false);
+ List<XSDefinition> definitions = new ArrayList<XSDefinition>();
+ generateSchemas(definitions, factory, context);
+ return definitions;
+ } catch (Throwable e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+ public List<XSDefinition> getSchemaDefinitions(XSDFactory factory, ModelResolver resolver, List<DataType> dataTypes) {
+ try {
+
+ JAXBContext context = contextHelper.createJAXBContext(dataTypes);
+ List<XSDefinition> definitions = new ArrayList<XSDefinition>();
+ generateSchemas(definitions, factory, context);
+ return definitions;
+ } catch (Throwable e) {
+ throw new ServiceRuntimeException(e);
+ }
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperException.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperException.java
new file mode 100644
index 0000000000..7473a8e56e
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperException.java
@@ -0,0 +1,56 @@
+/*
+ * 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.jaxb;
+
+import org.oasisopen.sca.ServiceRuntimeException;
+
+public class JAXBWrapperException extends ServiceRuntimeException {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ */
+ public JAXBWrapperException() {
+ super();
+
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public JAXBWrapperException(String message, Throwable cause) {
+ super(message, cause);
+
+ }
+
+ /** @param message */
+ public JAXBWrapperException(String message) {
+ super(message);
+
+ }
+
+ /** @param cause */
+ public JAXBWrapperException(Throwable cause) {
+ super(cause);
+
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHandler.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHandler.java
new file mode 100644
index 0000000000..a1f4c12c8f
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHandler.java
@@ -0,0 +1,151 @@
+/*
+ * 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.jaxb;
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.tuscany.sca.databinding.TransformationException;
+import org.apache.tuscany.sca.databinding.WrapperHandler;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.util.ElementInfo;
+import org.apache.tuscany.sca.interfacedef.util.WrapperInfo;
+
+/**
+ * JAXB WrapperHandler implementation
+ *
+ * @version $Rev$ $Date$
+ */
+public class JAXBWrapperHandler implements WrapperHandler<Object> {
+ private JAXBWrapperHelper helper = new JAXBWrapperHelper();
+
+ public Object create(Operation operation, boolean input) {
+ WrapperInfo wrapperInfo = operation.getWrapper();
+ ElementInfo element = input ? wrapperInfo.getInputWrapperElement() : wrapperInfo.getOutputWrapperElement();
+ final Class<?> wrapperClass = input ? wrapperInfo.getInputWrapperClass() : wrapperInfo.getOutputWrapperClass();
+ try {
+ if (wrapperClass == null) {
+ return null;
+ }
+ return AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws Exception {
+ return wrapperClass.newInstance();
+ }
+ });
+ } catch (PrivilegedActionException e) {
+ throw new TransformationException(e);
+ }
+ }
+
+ public void setChildren(Object wrapper, Object[] childObjects, Operation operation, boolean input) {
+ List<ElementInfo> childElements =
+ input ? operation.getWrapper().getInputChildElements() : operation.getWrapper().getOutputChildElements();
+ List<String> childNames = new ArrayList<String>();
+ Map<String, Object> values = new HashMap<String, Object>();
+ for (int i = 0; i < childElements.size(); i++) {
+ ElementInfo e = childElements.get(i);
+ String name = e.getQName().getLocalPart();
+ childNames.add(name);
+ values.put(name, childObjects[i]);
+ }
+ // Get the property descriptor map
+ Map<String, JAXBPropertyDescriptor> pdMap = null;
+ try {
+ pdMap = XMLRootElementUtil.createPropertyDescriptorMap(wrapper.getClass());
+ } catch (Throwable t) {
+ throw new JAXBWrapperException(t);
+ }
+ helper.wrap(wrapper, childNames, values, pdMap);
+ }
+
+ public void setChild(Object wrapper, int i, ElementInfo childElement, Object value) {
+ Object wrapperValue = wrapper;
+ Class<?> wrapperClass = wrapperValue.getClass();
+
+ // FIXME: We probably should use the jaxb-reflection to handle the properties
+ try {
+ String prop = childElement.getQName().getLocalPart();
+ boolean collection = (value instanceof Collection);
+ Method getter = null;
+ for (Method m : wrapperClass.getMethods()) {
+ Class<?>[] paramTypes = m.getParameterTypes();
+ if (paramTypes.length == 1 && m.getName().equals("set" + capitalize(prop))) {
+ m.invoke(wrapperValue, new Object[] {value});
+ return;
+ }
+ if (collection && paramTypes.length == 0 && m.getName().equals("get" + capitalize(prop))) {
+ getter = m;
+ }
+ }
+ if (getter != null && Collection.class.isAssignableFrom(getter.getReturnType())) {
+ ((Collection)getter.invoke(wrapperValue)).addAll((Collection)value);
+ }
+
+ } catch (Throwable e) {
+ throw new TransformationException(e);
+ }
+ }
+
+ private static String capitalize(String name) {
+ char first = Character.toUpperCase(name.charAt(0));
+ return first + name.substring(1);
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.databinding.WrapperHandler#getChildren(java.lang.Object, Operation, boolean)
+ */
+ public List getChildren(Object wrapper, Operation operation, boolean input) {
+ List<ElementInfo> childElements = input? operation.getWrapper().getInputChildElements():
+ operation.getWrapper().getOutputChildElements();
+
+ List<String> childNames = new ArrayList<String>();
+ for (ElementInfo e : childElements) {
+ childNames.add(e.getQName().getLocalPart());
+ }
+ return Arrays.asList(helper.unwrap(wrapper, childNames));
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.databinding.WrapperHandler#getWrapperType(Operation, boolean)
+ */
+ public DataType getWrapperType(Operation operation, boolean input) {
+ WrapperInfo wrapper = operation.getWrapper();
+ DataType dt = input ? wrapper.getInputWrapperType() : wrapper.getOutputWrapperType();
+ return dt;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.databinding.WrapperHandler#isInstance(java.lang.Object, Operation, boolean)
+ */
+ public boolean isInstance(Object wrapper, Operation operation, boolean input) {
+ Class<?> wrapperClass =
+ input ? operation.getWrapper().getInputWrapperClass() : operation.getWrapper().getOutputWrapperClass();
+ return wrapperClass == null ? false : wrapperClass.isInstance(wrapper);
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHelper.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHelper.java
new file mode 100644
index 0000000000..5f90aa4d7a
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHelper.java
@@ -0,0 +1,166 @@
+/*
+ * 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.jaxb;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The JAXBWrapper tool is used to create a JAXB Object from a series of child objects (wrap) or get
+ * the child objects from a JAXB Object (unwrap)
+ */
+public class JAXBWrapperHelper {
+
+ /**
+ * unwrap Returns the list of child objects of the jaxb object
+ *
+ * @param jaxbObject that represents the type
+ * @param childNames list of xml child names as String
+ * @param pdMap PropertyDescriptor map for this jaxbObject
+ * @return list of Objects in the same order as the element names.
+ */
+ public Object[] unwrap(Object jaxbObject, List<String> childNames, Map<String, JAXBPropertyDescriptor> pdMap)
+ throws JAXBWrapperException {
+
+ // Get the object that will have the property descriptors (i.e. the object representing the complexType)
+ Object jaxbComplexTypeObj = jaxbObject;
+
+ // Get the PropertyDescriptorPlus map.
+ // The method makes sure that each child name has a matching jaxb property
+ // checkPropertyDescriptorMap(jaxbComplexTypeObj.getClass(), childNames, pdMap);
+
+ // Get the corresponsing objects from the jaxb bean
+ ArrayList<Object> objList = new ArrayList<Object>();
+ int index = 0;
+ for (String childName : childNames) {
+ JAXBPropertyDescriptor propInfo = getPropertyDescriptor(pdMap, childName, index);
+
+ Object object = null;
+ try {
+ object = propInfo.get(jaxbComplexTypeObj);
+ } catch (Throwable e) {
+ throw new JAXBWrapperException(e);
+ }
+
+ objList.add(object);
+ index++;
+ }
+ Object[] jaxbObjects = objList.toArray();
+ objList = null;
+ return jaxbObjects;
+
+ }
+
+ private JAXBPropertyDescriptor getPropertyDescriptor(Map<String, JAXBPropertyDescriptor> pdMap,
+ String childName,
+ int index) {
+ JAXBPropertyDescriptor propInfo = pdMap.get(childName);
+ if (propInfo == null) {
+ // FIXME: [rfeng] Sometimes the child element names don't match. Get chilld by location?
+ List<JAXBPropertyDescriptor> props = new ArrayList<JAXBPropertyDescriptor>(pdMap.values());
+ // Sort the properties by index. We might need to take propOrder into consideration
+ Collections.sort(props);
+ propInfo = props.get(index);
+ }
+ return propInfo;
+ }
+
+ /**
+ * wrap Creates a jaxb object that is initialized with the child objects.
+ * <p/>
+ * Note that the jaxbClass must be the class the represents the complexType. (It should never be
+ * JAXBElement)
+ *
+ * @param jaxbClass
+ * @param childNames list of xml child names as String
+ * @param childObjects, component type objects
+ * @param pdMap PropertyDescriptor map for this jaxbObject
+ */
+ public Object wrap(Class<?> jaxbClass,
+ List<String> childNames,
+ Map<String, Object> childObjects,
+ Map<String, JAXBPropertyDescriptor> pdMap) throws JAXBWrapperException {
+
+ // Just like unWrap, get the property info map
+ // checkPropertyDescriptorMap(jaxbClass, childNames, pdMap);
+
+ // The jaxb object always has a default constructor. Create the object
+ Object jaxbObject = null;
+ try {
+ jaxbObject = jaxbClass.newInstance();
+ } catch (Throwable t) {
+ throw new JAXBWrapperException(t);
+ }
+
+ wrap(jaxbObject, childNames, childObjects, pdMap);
+
+ // Return the jaxb object
+ return jaxbObject;
+ }
+
+ public void wrap(Object jaxbObject,
+ List<String> childNames,
+ Map<String, Object> childObjects,
+ Map<String, JAXBPropertyDescriptor> pdMap) {
+ // Now set each object onto the jaxb object
+ int index = 0;
+ for (String childName : childNames) {
+ JAXBPropertyDescriptor propInfo = getPropertyDescriptor(pdMap, childName, index);
+ Object value = childObjects.get(childName);
+ try {
+ propInfo.set(jaxbObject, value);
+ } catch (Throwable t) {
+ throw new JAXBWrapperException(t);
+ }
+ index++;
+ }
+ }
+
+ public Object[] unwrap(Object jaxbObject, List<String> childNames) throws JAXBWrapperException {
+ // Get the property descriptor map for this JAXBClass
+ Class<?> jaxbClass = jaxbObject.getClass();
+ Map<String, JAXBPropertyDescriptor> pdMap = null;
+ try {
+ pdMap = XMLRootElementUtil.createPropertyDescriptorMap(jaxbClass);
+ } catch (Throwable t) {
+ throw new JAXBWrapperException(t);
+ }
+
+ // Delegate
+ return unwrap(jaxbObject, childNames, pdMap);
+ }
+
+ public Object wrap(Class<?> jaxbClass, List<String> childNames, Map<String, Object> childObjects)
+ throws JAXBWrapperException {
+ // Get the property descriptor map
+ Map<String, JAXBPropertyDescriptor> pdMap = null;
+ try {
+ pdMap = XMLRootElementUtil.createPropertyDescriptorMap(jaxbClass);
+ } catch (Throwable t) {
+ throw new JAXBWrapperException(t);
+ }
+
+ // Delegate
+ return wrap(jaxbClass, childNames, childObjects, pdMap);
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/Node2JAXB.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/Node2JAXB.java
new file mode 100644
index 0000000000..e6fc1b4405
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/Node2JAXB.java
@@ -0,0 +1,75 @@
+/*
+ * 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.jaxb;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.PullTransformer;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.databinding.TransformationException;
+import org.apache.tuscany.sca.databinding.BaseTransformer;
+import org.w3c.dom.Node;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class Node2JAXB extends BaseTransformer<Node, Object> implements PullTransformer<Node, Object> {
+ private JAXBContextHelper contextHelper;
+
+ public Node2JAXB(ExtensionPointRegistry registry) {
+ contextHelper = JAXBContextHelper.getInstance(registry);
+ }
+
+ public Object transform(Node source, TransformationContext context) {
+ if (source == null)
+ return null;
+ try {
+ JAXBContext jaxbContext = contextHelper.createJAXBContext(context, false);
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ Object result = unmarshaller.unmarshal(source, JAXBContextHelper.getJavaType(context.getTargetDataType()));
+ return JAXBContextHelper.createReturnValue(jaxbContext, context.getTargetDataType(), result);
+ } catch (Exception e) {
+ throw new TransformationException(e);
+ }
+ }
+
+ @Override
+ protected Class<Node> getSourceType() {
+ return Node.class;
+ }
+
+ @Override
+ protected Class<Object> getTargetType() {
+ return Object.class;
+ }
+
+ @Override
+ public int getWeight() {
+ return 30;
+ }
+
+ @Override
+ public String getTargetDataBinding() {
+ return JAXBDataBinding.NAME;
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/Reader2JAXB.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/Reader2JAXB.java
new file mode 100644
index 0000000000..b063d9524f
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/Reader2JAXB.java
@@ -0,0 +1,79 @@
+/*
+ * 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.jaxb;
+
+import java.io.Reader;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.PullTransformer;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.databinding.TransformationException;
+import org.apache.tuscany.sca.databinding.BaseTransformer;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class Reader2JAXB extends BaseTransformer<Reader, Object> implements
+ PullTransformer<Reader, Object> {
+ private JAXBContextHelper contextHelper;
+
+ public Reader2JAXB(ExtensionPointRegistry registry) {
+ contextHelper = JAXBContextHelper.getInstance(registry);
+ }
+ public Object transform(final Reader source, final TransformationContext context) {
+ if (source == null) {
+ return null;
+ }
+ try {
+ JAXBContext jaxbContext = contextHelper.createJAXBContext(context, false);
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ StreamSource streamSource = new StreamSource(source);
+ Object result = unmarshaller.unmarshal(streamSource, JAXBContextHelper.getJavaType(context.getTargetDataType()));
+ return JAXBContextHelper.createReturnValue(jaxbContext, context.getTargetDataType(), result);
+ } catch (Exception e) {
+ throw new TransformationException(e);
+ }
+ }
+
+ @Override
+ protected Class<Reader> getSourceType() {
+ return Reader.class;
+ }
+
+ @Override
+ protected Class<Object> getTargetType() {
+ return Object.class;
+ }
+
+ @Override
+ public int getWeight() {
+ return 30;
+ }
+
+ @Override
+ public String getTargetDataBinding() {
+ return JAXBDataBinding.NAME;
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/String2JAXB.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/String2JAXB.java
new file mode 100644
index 0000000000..9d0accefcc
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/String2JAXB.java
@@ -0,0 +1,86 @@
+/*
+ * 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.jaxb;
+
+import java.io.StringReader;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.PullTransformer;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.databinding.TransformationException;
+import org.apache.tuscany.sca.databinding.BaseTransformer;
+import org.apache.tuscany.sca.databinding.xml.XMLStringDataBinding;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class String2JAXB extends BaseTransformer<String, Object> implements
+ PullTransformer<String, Object> {
+ private JAXBContextHelper contextHelper;
+
+ public String2JAXB(ExtensionPointRegistry registry) {
+ contextHelper = JAXBContextHelper.getInstance(registry);
+ }
+
+ public Object transform(final String source, final TransformationContext context) {
+ if (source == null) {
+ return null;
+ }
+ try {
+ JAXBContext jaxbContext = contextHelper.createJAXBContext(context, false);
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ StreamSource streamSource = new StreamSource(new StringReader(source));
+ Object result = unmarshaller.unmarshal(streamSource, JAXBContextHelper.getJavaType(context.getTargetDataType()));
+ return JAXBContextHelper.createReturnValue(jaxbContext, context.getTargetDataType(), result);
+ } catch (Exception e) {
+ throw new TransformationException(e);
+ }
+ }
+
+ @Override
+ protected Class<String> getSourceType() {
+ return String.class;
+ }
+
+ @Override
+ protected Class<Object> getTargetType() {
+ return Object.class;
+ }
+
+ @Override
+ public int getWeight() {
+ return 30;
+ }
+
+ @Override
+ public String getSourceDataBinding() {
+ return XMLStringDataBinding.NAME;
+ }
+
+ @Override
+ public String getTargetDataBinding() {
+ return JAXBDataBinding.NAME;
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLAdapterExtensionPoint.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLAdapterExtensionPoint.java
new file mode 100644
index 0000000000..5fa98b5ed1
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLAdapterExtensionPoint.java
@@ -0,0 +1,52 @@
+/*
+ * 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.jaxb;
+
+import java.util.Map;
+
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface XMLAdapterExtensionPoint {
+ /**
+ * @param boundType
+ * @param adapter
+ */
+ void addAdapter(Class<?> boundType, Class<? extends XmlAdapter> adapter);
+
+ /**
+ * @param boundType
+ * @return
+ */
+ Class<? extends XmlAdapter> getAdapter(Class<?> boundType);
+
+ /**
+ * @param boundType
+ * @return
+ */
+ Class<? extends XmlAdapter> removeAdapter(Class<?> boundType);
+
+ /**
+ * @return
+ */
+ Map<Class<?>, Class<? extends XmlAdapter>> getAdapters();
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLRootElementUtil.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLRootElementUtil.java
new file mode 100644
index 0000000000..d177d53eda
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLRootElementUtil.java
@@ -0,0 +1,299 @@
+/*
+ * 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.jaxb;
+
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.WeakHashMap;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElementRef;
+import javax.xml.bind.annotation.XmlEnumValue;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlSchema;
+import javax.xml.namespace.QName;
+
+/**
+ *
+ */
+public class XMLRootElementUtil {
+
+ /**
+ * TUSCANY-3167
+ * Cache for property descriptors
+ */
+ private static Map<Class<?>, Map<String, JAXBPropertyDescriptor>> PROPERTY_MAP =
+ new WeakHashMap<Class<?>, Map<String, JAXBPropertyDescriptor>>();
+
+ /** Constructor is intentionally private. This class only provides static utility methods */
+ private XMLRootElementUtil() {
+
+ }
+
+ /**
+ * @param clazz
+ * @return namespace of root element qname or null if this is not object does not represent a
+ * root element
+ */
+ public static QName getXmlRootElementQNameFromObject(Object obj) {
+
+ // A JAXBElement stores its name
+ if (obj instanceof JAXBElement) {
+ return ((JAXBElement<?>)obj).getName();
+ }
+
+ Class<?> clazz = (obj instanceof java.lang.Class) ? (Class<?>)obj : obj.getClass();
+ return getXmlRootElementQName(clazz);
+ }
+
+ /**
+ * @param clazz
+ * @return namespace of root element qname or null if this is not object does not represent a
+ * root element
+ */
+ public static QName getXmlRootElementQName(Class<?> clazz) {
+
+ // See if the object represents a root element
+ XmlRootElement root = (XmlRootElement)getAnnotation(clazz, XmlRootElement.class);
+ if (root == null) {
+ return null;
+ }
+
+ String name = root.name();
+ String namespace = root.namespace();
+
+ // The name may need to be defaulted
+ if (name == null || name.length() == 0 || name.equals("##default")) {
+ name = getSimpleName(clazz.getCanonicalName());
+ }
+
+ // The namespace may need to be defaulted
+ if (namespace == null || namespace.length() == 0 || namespace.equals("##default")) {
+ Package pkg = clazz.getPackage();
+ XmlSchema schema = (XmlSchema)getAnnotation(pkg, XmlSchema.class);
+ if (schema != null) {
+ namespace = schema.namespace();
+ } else {
+ namespace = "";
+ }
+ }
+
+ return new QName(namespace, name);
+ }
+
+ /**
+ * @param clazz
+ * @return namespace of root element qname or null if this is not object does not represent a root element
+ */
+ public static String getEnumValue(Enum<?> myEnum) {
+ Field f;
+ String value;
+ try {
+ f = myEnum.getClass().getField(myEnum.name());
+
+ f.setAccessible(true);
+
+ XmlEnumValue xev = (XmlEnumValue)getAnnotation(f, XmlEnumValue.class);
+ if (xev == null) {
+ value = f.getName();
+ } else {
+ value = xev.value();
+ }
+ } catch (SecurityException e) {
+ value = null;
+ } catch (NoSuchFieldException e) {
+ value = null;
+ }
+
+ return value;
+ }
+
+ /**
+ * utility method to get the last token in a "."-delimited package+classname string
+ *
+ * @return
+ */
+ private static String getSimpleName(String in) {
+ if (in == null || in.length() == 0) {
+ return in;
+ }
+ String out = null;
+ StringTokenizer tokenizer = new StringTokenizer(in, ".");
+ if (tokenizer.countTokens() == 0)
+ out = in;
+ else {
+ while (tokenizer.hasMoreTokens()) {
+ out = tokenizer.nextToken();
+ }
+ }
+ return out;
+ }
+
+ /**
+ * The JAXBClass has a set of bean properties each represented by a PropertyDescriptor Each of
+ * the fields of the class has an associated xml name. The method returns a map where the key is
+ * the xml name and value is the PropertyDescriptor
+ *
+ * @param jaxbClass
+ * @return map
+ */
+ public synchronized static Map<String, JAXBPropertyDescriptor> createPropertyDescriptorMap(Class<?> jaxbClass)
+ throws NoSuchFieldException, IntrospectionException {
+
+ Map<String, JAXBPropertyDescriptor> map = PROPERTY_MAP.get(jaxbClass);
+ if (map != null) {
+ return map;
+ }
+
+ map = new HashMap<String, JAXBPropertyDescriptor>();
+ PropertyDescriptor[] pds = Introspector.getBeanInfo(jaxbClass).getPropertyDescriptors();
+
+ // Unfortunately the element names are stored on the fields.
+ // Get all of the fields in the class and super classes
+
+ List<Field> fields = getFields(jaxbClass);
+
+ // Now match up the fields with the property descriptors...Sigh why didn't JAXB put the @XMLElement annotations on the
+ // property methods!
+ for (PropertyDescriptor pd : pds) {
+
+ // Skip over the class property..it is never represented as an xml element
+ if (pd.getName().equals("class")) {
+ continue;
+ }
+
+ // For the current property, find a matching field...so that we can get the xml name
+ boolean found = false;
+
+ int index = 0;
+ for (Field field : fields) {
+ String fieldName = field.getName();
+
+ // Use the name of the field and property to find the match
+ if (fieldName.equalsIgnoreCase(pd.getDisplayName()) || fieldName.equalsIgnoreCase(pd.getName())) {
+ // Get the xmlElement name for this field
+ QName xmlName = getXmlElementRefOrElementQName(field.getDeclaringClass(), field);
+ found = true;
+ map.put(xmlName.getLocalPart(), new JAXBPropertyDescriptor(pd, xmlName, index));
+ index++;
+ break;
+ }
+
+ // Unfortunately, sometimes the field name is preceeded by an underscore
+ if (fieldName.startsWith("_")) {
+ fieldName = fieldName.substring(1);
+ if (fieldName.equalsIgnoreCase(pd.getDisplayName()) || fieldName.equalsIgnoreCase(pd.getName())) {
+ // Get the xmlElement name for this field
+ QName xmlName = getXmlElementRefOrElementQName(field.getDeclaringClass(), field);
+ found = true;
+
+ map.put(xmlName.getLocalPart(), new JAXBPropertyDescriptor(pd, xmlName, index));
+ index++;
+ break;
+ }
+ }
+ }
+
+ // We didn't find a field. Default the xmlname to the property name
+ if (!found) {
+ String xmlName = pd.getName();
+
+ map.put(xmlName, new JAXBPropertyDescriptor(pd, xmlName, index));
+ index++;
+ }
+ }
+ PROPERTY_MAP.put(jaxbClass, map);
+ return map;
+ }
+
+ /**
+ * Gets all of the fields in this class and the super classes
+ *
+ * @param beanClass
+ * @return
+ */
+ static private List<Field> getFields(final Class<?> beanClass) {
+ // This class must remain private due to Java 2 Security concerns
+ List<Field> fields = AccessController.doPrivileged(new PrivilegedAction<List<Field>>() {
+ public List<Field> run() {
+ List<Field> fields = new ArrayList<Field>();
+ Class<?> cls = beanClass;
+ while (cls != null) {
+ Field[] fieldArray = cls.getDeclaredFields();
+ for (Field field : fieldArray) {
+ fields.add(field);
+ }
+ cls = cls.getSuperclass();
+ }
+ return fields;
+ }
+ });
+
+ return fields;
+ }
+
+ /**
+ * Get the name of the field by looking at the XmlElement annotation.
+ *
+ * @param jaxbClass
+ * @param fieldName
+ * @return
+ * @throws NoSuchFieldException
+ */
+ private static QName getXmlElementRefOrElementQName(Class<?> jaxbClass, Field field) throws NoSuchFieldException {
+ XmlElementRef xmlElementRef = (XmlElementRef)getAnnotation(field, XmlElementRef.class);
+ if (xmlElementRef != null) {
+ return new QName(xmlElementRef.namespace(), xmlElementRef.name());
+ }
+ XmlElement xmlElement = (XmlElement)getAnnotation(field, XmlElement.class);
+
+ // If XmlElement does not exist, default to using the field name
+ if (xmlElement == null || xmlElement.name().equals("##default")) {
+ return new QName("", field.getName());
+ }
+ return new QName(xmlElement.namespace(), xmlElement.name());
+ }
+
+ /**
+ * Get an annotation. This is wrappered to avoid a Java2Security violation.
+ * @param cls Class that contains annotation
+ * @param annotation Class of requrested Annotation
+ * @return annotation or null
+ */
+ private static <T extends Annotation> T getAnnotation(final AnnotatedElement element, final Class<T> annotation) {
+ return AccessController.doPrivileged(new PrivilegedAction<T>() {
+ public T run() {
+ return element.getAnnotation(annotation);
+ }
+ });
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLStreamReader2JAXB.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLStreamReader2JAXB.java
new file mode 100644
index 0000000000..9c3760b119
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/XMLStreamReader2JAXB.java
@@ -0,0 +1,80 @@
+/*
+ * 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.jaxb;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.stream.XMLStreamReader;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.PullTransformer;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.databinding.TransformationException;
+import org.apache.tuscany.sca.databinding.BaseTransformer;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class XMLStreamReader2JAXB extends BaseTransformer<XMLStreamReader, Object> implements
+ PullTransformer<XMLStreamReader, Object> {
+
+ private JAXBContextHelper contextHelper;
+
+ public XMLStreamReader2JAXB(ExtensionPointRegistry registry) {
+ contextHelper = JAXBContextHelper.getInstance(registry);
+ }
+
+ public Object transform(XMLStreamReader source, TransformationContext context) {
+ if (source == null) {
+ return null;
+ }
+ try {
+ JAXBContext jaxbContext = contextHelper.createJAXBContext(context, false);
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ // FIXME: [rfeng] If the java type is Object.class, the unmarshalled result will be
+ // a DOM Node
+ Object result = unmarshaller.unmarshal(source, JAXBContextHelper.getJavaType(context.getTargetDataType()));
+ source.close();
+ return JAXBContextHelper.createReturnValue(jaxbContext, context.getTargetDataType(), result);
+ } catch (Exception e) {
+ throw new TransformationException(e);
+ }
+ }
+
+ @Override
+ public Class<XMLStreamReader> getSourceType() {
+ return XMLStreamReader.class;
+ }
+
+ @Override
+ public Class<Object> getTargetType() {
+ return Object.class;
+ }
+
+ @Override
+ public int getWeight() {
+ return 10;
+ }
+
+ @Override
+ public String getTargetDataBinding() {
+ return JAXBDataBinding.NAME;
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/package.html b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/package.html
new file mode 100644
index 0000000000..3dd869384a
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/java/org/apache/tuscany/sca/databinding/jaxb/package.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!--
+ * 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.
+-->
+<html>
+<head>
+</head>
+<body>
+Base Package for the JAXB databinding extension.
+
+Whilst this package and its subpackages are not currently deemed to represent extension developers SPI, this extension has a special relationship with binding-atom-runtime. binding-atom-runtime can be viewed as a specialization of binding.http.
+
+</body>
+</html>
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.DataBinding b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.DataBinding
new file mode 100644
index 0000000000..1447ed4e7f
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.DataBinding
@@ -0,0 +1,20 @@
+# 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.
+
+# implementation classes for the databindings
+org.apache.tuscany.sca.databinding.jaxb.JAXBDataBinding;name=javax.xml.bind.JAXBElement
+
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.PullTransformer b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.PullTransformer
new file mode 100644
index 0000000000..673e75d50c
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.PullTransformer
@@ -0,0 +1,33 @@
+# 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.
+
+# Implementation classes for the transformers
+org.apache.tuscany.sca.databinding.jaxb.JAXB2Node;source=javax.xml.bind.JAXBElement,target=org.w3c.dom.Node,weight=500
+org.apache.tuscany.sca.databinding.jaxb.Node2JAXB;source=org.w3c.dom.Node,target=javax.xml.bind.JAXBElement,weight=500
+org.apache.tuscany.sca.databinding.jaxb.Reader2JAXB;source=java.io.Reader,target=javax.xml.bind.JAXBElement,weight=510
+org.apache.tuscany.sca.databinding.jaxb.XMLStreamReader2JAXB;source=javax.xml.stream.XMLStreamReader,target=javax.xml.bind.JAXBElement,weight=490
+
+org.apache.tuscany.sca.databinding.jaxb.JAXB2Node;source=java:complexType,target=org.w3c.dom.Node,weight=90000
+org.apache.tuscany.sca.databinding.jaxb.Node2JAXB;source=org.w3c.dom.Node,target=java:complexType,weight=90000
+
+org.apache.tuscany.sca.databinding.jaxb.Node2JAXB;source=org.w3c.dom.Node,target=java:simpleType,weight=90000
+org.apache.tuscany.sca.databinding.jaxb.JAXB2Node;source=java:simpleType,target=org.w3c.dom.Node,weight=90000
+
+org.apache.tuscany.sca.databinding.jaxb.XMLStreamReader2JAXB;source=javax.xml.stream.XMLStreamReader,target=java:complexType,weight=90000
+org.apache.tuscany.sca.databinding.jaxb.XMLStreamReader2JAXB;source=javax.xml.stream.XMLStreamReader,target=java:simpleType,weight=90000
+
+
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.jaxb.XMLAdapterExtensionPoint b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.jaxb.XMLAdapterExtensionPoint
new file mode 100644
index 0000000000..b8d185b468
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/main/resources/META-INF/services/org.apache.tuscany.sca.databinding.jaxb.XMLAdapterExtensionPoint
@@ -0,0 +1,17 @@
+# 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.
+org.apache.tuscany.sca.databinding.jaxb.DefaultXMLAdapterExtensionPoint
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/com/example/stock/StockQuoteOffer.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/com/example/stock/StockQuoteOffer.java
new file mode 100644
index 0000000000..5c5c892f33
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/com/example/stock/StockQuoteOffer.java
@@ -0,0 +1,45 @@
+/*
+ * 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 com.example.stock;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+/**
+ * <p>Java class for anonymous complex type.
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {"input"})
+@XmlRootElement(name = "stockQuoteOffer")
+public class StockQuoteOffer {
+
+ protected String input;
+
+ public String getInput() {
+ return this.input;
+ }
+
+ public void setInput(String input) {
+ this.input = input;
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCacheTestCase.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCacheTestCase.java
new file mode 100644
index 0000000000..9dd5892f7c
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBContextCacheTestCase.java
@@ -0,0 +1,122 @@
+/*
+ * 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.jaxb;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.namespace.QName;
+import javax.xml.transform.Source;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.tuscany.sca.common.java.collection.LRUCache;
+import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.example.ipo.jaxb.Address;
+import com.example.ipo.jaxb.PurchaseOrderType;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class JAXBContextCacheTestCase {
+ @Test
+ public void testCache() throws JAXBException {
+ JAXBContextCache cache = new JAXBContextCache(new DefaultExtensionPointRegistry());
+ JAXBContext context1 = cache.getJAXBContext(String.class);
+ JAXBContext context2 = cache.getJAXBContext(int.class);
+ JAXBContext context3 = cache.getJAXBContext(String[].class);
+ JAXBContext context4 = cache.getJAXBContext(Source.class);
+ Assert.assertSame(context1, context2);
+ Assert.assertNotSame(context2, context3);
+ Assert.assertSame(context1, context4);
+
+ QName name = new QName("http://example.com/ns1", "e1");
+ JAXBElement<String> element = new JAXBElement<String>(name, String.class, "123");
+ StringWriter sw = new StringWriter();
+ context4.createMarshaller().marshal(element, sw);
+ StreamSource source = new StreamSource(new StringReader(sw.toString()), null);
+ context4.createUnmarshaller().unmarshal(source, String.class);
+
+ JAXBContext context5 = cache.getJAXBContext(Address.class);
+ JAXBContext context6 = cache.getJAXBContext(PurchaseOrderType.class);
+ Assert.assertSame(context5, context6);
+ }
+
+ @Test
+ public void testLRUCache() {
+ LRUCache<String, String> cache = new LRUCache<String, String>(3);
+ cache.put("1", "A");
+ Assert.assertEquals(1, cache.size());
+ cache.put("2", "B");
+ Assert.assertEquals(2, cache.size());
+ cache.put("3", "C");
+ Assert.assertEquals(3, cache.size());
+ cache.put("4", "D");
+ Assert.assertEquals(3, cache.size());
+ String data = cache.get("1");
+ Assert.assertNull(data);
+ data = cache.get("2");
+ Assert.assertEquals("B", data);
+ cache.put("5", "E");
+ data = cache.get("2");
+ Assert.assertEquals("B", data);
+ }
+
+ @Test
+ public void testPerf() throws JAXBException {
+ JAXBContextCache cache = new JAXBContextCache(new DefaultExtensionPointRegistry());
+
+ // Test JAXBContext for simple java classes
+ long start = System.currentTimeMillis();
+ for (int i = 0; i < 100; i++) {
+ JAXBContext context = JAXBContext.newInstance(String.class);
+ }
+ long end = System.currentTimeMillis();
+ long d1 = end - start;
+ start = System.currentTimeMillis();
+ for (int i = 0; i < 100; i++) {
+ JAXBContext context = cache.getJAXBContext(String.class);
+ }
+ end = System.currentTimeMillis();
+ long d2 = end - start;
+ System.out.println(d1 + "ms vs. " + d2 + "ms");
+
+ // Test JAXBContext for generated JAXB classes
+ start = System.currentTimeMillis();
+ for (int i = 0; i < 20; i++) {
+ JAXBContext context = JAXBContext.newInstance(PurchaseOrderType.class);
+ }
+ end = System.currentTimeMillis();
+ d1 = end - start;
+ start = System.currentTimeMillis();
+ for (int i = 0; i < 20; i++) {
+ JAXBContext context = cache.getJAXBContext(PurchaseOrderType.class);
+ }
+ end = System.currentTimeMillis();
+ d2 = end - start;
+ System.out.println(d1 + "ms vs. " + d2 + "ms");
+
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBDataBindingTestCase.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBDataBindingTestCase.java
new file mode 100644
index 0000000000..ec414641c6
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBDataBindingTestCase.java
@@ -0,0 +1,131 @@
+/*
+ * 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.jaxb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry;
+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;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.example.ipo.jaxb.ObjectFactory;
+import com.example.ipo.jaxb.PurchaseOrderType;
+import com.example.ipo.jaxb.USAddress;
+import com.example.ipo.jaxb.USState;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class JAXBDataBindingTestCase {
+ private JAXBDataBinding binding;
+
+ @Before
+ public void setUp() throws Exception {
+ binding = new JAXBDataBinding(new DefaultExtensionPointRegistry());
+ }
+
+ /**
+ * Test method for
+ * {@link org.apache.tuscany.sca.databinding.jaxb.JAXBDataBinding#introspect(java.lang.Class, Operation)}.
+ */
+ @Test
+ public final void testIntrospect() {
+ DataType dataType = new DataTypeImpl<Class>(JAXBElement.class, null);
+ Operation op = null;
+ boolean yes = binding.introspect(dataType, op);
+ assertTrue(yes);
+ assertTrue(dataType.getDataBinding().equals(binding.getName()));
+ assertTrue(dataType.getPhysical() == JAXBElement.class && dataType.getLogical() == XMLType.UNKNOWN);
+ dataType = new DataTypeImpl<Class>(MockJAXBElement.class, null);
+ yes = binding.introspect(dataType, op);
+ assertTrue(yes);
+ assertEquals(MockJAXBElement.class, dataType.getPhysical());
+ assertEquals(new QName("http://www.example.com/IPO", "PurchaseOrderType"), ((XMLType)dataType.getLogical())
+ .getTypeName());
+ dataType = new DataTypeImpl<Class>(USAddress.class, null);
+ yes = binding.introspect(dataType, op);
+ assertTrue(yes);
+ assertEquals(USAddress.class, dataType.getPhysical());
+ assertEquals(new QName("http://www.example.com/IPO", "USAddress"), ((XMLType)dataType.getLogical())
+ .getTypeName());
+ dataType = new DataTypeImpl<Class>(USState.class, null);
+ yes = binding.introspect(dataType, op);
+ assertTrue(yes);
+ assertTrue(dataType.getDataBinding().equals(binding.getName()));
+ assertEquals(USState.class, dataType.getPhysical());
+ assertEquals(new QName("http://www.example.com/IPO", "USState"), ((XMLType)dataType.getLogical()).getTypeName());
+
+ }
+
+ private static class MockJAXBElement extends JAXBElement<PurchaseOrderType> {
+
+ private static final long serialVersionUID = -2767569071002707973L;
+
+ /**
+ * @param elementName
+ * @param type
+ * @param value
+ */
+ public MockJAXBElement(QName elementName, Class<PurchaseOrderType> type, PurchaseOrderType value) {
+ super(elementName, type, value);
+ }
+
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testCopy() {
+ ObjectFactory factory = new ObjectFactory();
+ PurchaseOrderType poType = factory.createPurchaseOrderType();
+ JAXBElement<PurchaseOrderType> po = factory.createPurchaseOrder(poType);
+ JAXBElement<PurchaseOrderType> copy = (JAXBElement<PurchaseOrderType>)binding.copy(po, null, null, null, null);
+ assertEquals(new QName("http://www.example.com/IPO", "purchaseOrder"), copy.getName());
+ }
+
+ @Test
+ public void testCopyNonElement() {
+ ObjectFactory factory = new ObjectFactory();
+ PurchaseOrderType poType = factory.createPurchaseOrderType();
+ poType.setComment("Comment");
+ PurchaseOrderType copy = (PurchaseOrderType)binding.copy(poType, null, null, null, null);
+ assertTrue(copy instanceof PurchaseOrderType);
+ assertEquals("Comment", (copy).getComment());
+ }
+
+ @Test
+ public void testCopyNonRoot() {
+ ObjectFactory factory = new ObjectFactory();
+ USAddress address = factory.createUSAddress();
+ address.setCity("San Jose");
+ USAddress copy = (USAddress)binding.copy(address, null, null, null, null);
+ assertTrue(copy instanceof USAddress);
+ assertEquals("San Jose", (copy).getCity());
+
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBReflectionTestCase.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBReflectionTestCase.java
new file mode 100644
index 0000000000..f5cff68969
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBReflectionTestCase.java
@@ -0,0 +1,39 @@
+/*
+ * 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.jaxb;
+
+import java.util.Map;
+
+import javax.xml.bind.JAXBContext;
+
+import org.junit.Test;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class JAXBReflectionTestCase {
+
+ @Test
+ public void testGenerateSchema() throws Exception {
+ JAXBContext context = JAXBContext.newInstance("com.example.ipo.jaxb");
+ Map<String, String> schemas = JAXBTypeHelper.generateSchema(context);
+ System.out.println(schemas);
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBTestCase.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBTestCase.java
new file mode 100644
index 0000000000..6e2a540ada
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBTestCase.java
@@ -0,0 +1,148 @@
+/*
+ * 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.jaxb;
+
+import java.io.StringReader;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.core.DefaultExtensionPointRegistry;
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.databinding.impl.TransformationContextImpl;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.junit.Assert;
+import org.junit.Test;
+import org.w3c.dom.Node;
+
+import com.example.ipo.jaxb.ObjectFactory;
+import com.example.ipo.jaxb.PurchaseOrderType;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class JAXBTestCase {
+ private static final String IPO_XML =
+ "<?xml version=\"1.0\"?>" + "<ipo:purchaseOrder"
+ + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
+ + " xmlns:ipo=\"http://www.example.com/IPO\""
+ + " xsi:schemaLocation=\"http://www.example.com/IPO ipo.xsd\""
+ + " orderDate=\"1999-12-01\">"
+ + " <shipTo exportCode=\"1\" xsi:type=\"ipo:UKAddress\">"
+ + " <name>Helen Zoe</name>"
+ + " <street>47 Eden Street</street>"
+ + " <city>Cambridge</city>"
+ + " <postcode>CB1 1JR</postcode>"
+ + " </shipTo>"
+ + " <billTo xsi:type=\"ipo:USAddress\">"
+ + " <name>Robert Smith</name>"
+ + " <street>8 Oak Avenue</street>"
+ + " <city>Old Town</city>"
+ + " <state>PA</state>"
+ + " <zip>95819</zip>"
+ + " </billTo>"
+ + " <items>"
+ + " <item partNum=\"833-AA\">"
+ + " <productName>Lapis necklace</productName>"
+ + " <quantity>1</quantity>"
+ + " <USPrice>99.95</USPrice>"
+ + " <ipo:comment>Want this for the holidays</ipo:comment>"
+ + " <shipDate>1999-12-05</shipDate>"
+ + " </item>"
+ + " </items>"
+ + "</ipo:purchaseOrder>";
+
+ private static ExtensionPointRegistry registry = new DefaultExtensionPointRegistry();
+
+ @Test
+ public void testTransform() throws Exception {
+ Reader2JAXB t0 = new Reader2JAXB(registry);
+
+ DataType targetDataType = new DataTypeImpl<Class>(PurchaseOrderType.class, null);
+
+ TransformationContext tContext = new TransformationContextImpl();
+ tContext.setTargetDataType(targetDataType);
+
+ Object object1 = t0.transform(new StringReader(IPO_XML), tContext);
+
+ DataType sourceDataType = new DataTypeImpl<Class>(PurchaseOrderType.class, null);
+
+ TransformationContext tContext1 = new TransformationContextImpl();
+ tContext1.setSourceDataType(sourceDataType);
+
+ JAXB2Node t1 = new JAXB2Node(registry);
+ Node node = t1.transform(object1, tContext1);
+
+ Assert.assertNotNull(node);
+
+ Node2JAXB t2 = new Node2JAXB(registry);
+ Object object2 = t2.transform(node, tContext);
+ Assert.assertNotNull(object2);
+
+ }
+
+ @Test
+ public void testTransform2() throws Exception {
+ Reader2JAXB t0 = new Reader2JAXB(registry);
+
+ QName root = new QName("http://www.example.com/IPO", "purchaseOrder");
+ DataType targetDataType = new DataTypeImpl<XMLType>(PurchaseOrderType.class, new XMLType(root, null));
+ // targetDataType.setMetadata(JAXBContextHelper.JAXB_CONTEXT_PATH, contextPath);
+
+ TransformationContext tContext = new TransformationContextImpl();
+ tContext.setTargetDataType(targetDataType);
+ Object object1 = t0.transform(new StringReader(IPO_XML), tContext);
+
+ DataType sourceDataType = new DataTypeImpl<XMLType>(PurchaseOrderType.class, new XMLType(root, null));
+ // sourceDataType.setMetadata(JAXBContextHelper.JAXB_CONTEXT_PATH, contextPath);
+
+ TransformationContext tContext1 = new TransformationContextImpl();
+ tContext1.setSourceDataType(sourceDataType);
+
+ JAXB2Node t1 = new JAXB2Node(registry);
+ Node node = t1.transform(object1, tContext1);
+
+ Assert.assertNotNull(node);
+
+ Node2JAXB t2 = new Node2JAXB(registry);
+ Object object2 = t2.transform(node, tContext);
+ Assert.assertNotNull(object2);
+
+ }
+
+ @Test
+ public void testTransform3() throws Exception {
+
+ DataType sourceDataType = new DataTypeImpl<Class>(PurchaseOrderType.class, null);
+
+ TransformationContext tContext1 = new TransformationContextImpl();
+ tContext1.setSourceDataType(sourceDataType);
+
+
+ JAXB2Node t1 = new JAXB2Node(registry);
+ PurchaseOrderType po = new ObjectFactory().createPurchaseOrderType();
+ Node node = t1.transform(po, tContext1);
+
+ Assert.assertNotNull(node);
+
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHandlerTestCase.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHandlerTestCase.java
new file mode 100644
index 0000000000..6037212e5a
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/JAXBWrapperHandlerTestCase.java
@@ -0,0 +1,90 @@
+/*
+ * 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.jaxb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.apache.tuscany.sca.interfacedef.impl.OperationImpl;
+import org.apache.tuscany.sca.interfacedef.util.ElementInfo;
+import org.apache.tuscany.sca.interfacedef.util.WrapperInfo;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.example.stock.StockQuoteOffer;
+
+/**
+ * Test case for JAXBExceptionHandler
+ *
+ * @version $Rev$ $Date$
+ */
+public class JAXBWrapperHandlerTestCase {
+ private static final QName ELEMENT = new QName("http://www.example.com/stock", "stockQuoteOffer");
+ private static final QName INPUT = new QName("", "input");
+ private JAXBWrapperHandler handler;
+
+ @Before
+ public void setUp() throws Exception {
+ this.handler = new JAXBWrapperHandler();
+ }
+
+ @Test
+ public void testCreate() {
+ ElementInfo element = new ElementInfo(ELEMENT, null);
+ Operation op = new OperationImpl();
+ WrapperInfo wrapperInfo = new WrapperInfo(JAXBDataBinding.NAME, element, null, null, null);
+ wrapperInfo.setInputWrapperType(new DataTypeImpl<XMLType>(JAXBDataBinding.NAME, StockQuoteOffer.class,
+ XMLType.UNKNOWN));
+ op.setWrapper(wrapperInfo);
+ Object offer = handler.create(op, true);
+ Assert.assertTrue(offer instanceof StockQuoteOffer);
+ }
+
+ @Test
+ public void testSetChild() {
+ StockQuoteOffer wrapper = new StockQuoteOffer();
+ handler.setChild(wrapper, 0, new ElementInfo(INPUT, null), "IBM");
+ Assert.assertEquals("IBM", wrapper.getInput());
+ }
+
+ @Test
+ public void testGetChildren() {
+ StockQuoteOffer wrapper = new StockQuoteOffer();
+ wrapper.setInput("IBM");
+ List<ElementInfo> elements = new ArrayList<ElementInfo>();
+ elements.add(new ElementInfo(INPUT, null));
+ WrapperInfo wrapperInfo = new WrapperInfo(JAXBDataBinding.NAME, null, null, elements, null);
+ Operation op = new OperationImpl();
+ op.setWrapper(wrapperInfo);
+ List children = handler.getChildren(wrapper, op, true);
+ assertNotNull(children);
+ assertEquals(1, children.size());
+ assertEquals("IBM", children.get(0));
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyBean.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyBean.java
new file mode 100644
index 0000000000..9bdfb108fe
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyBean.java
@@ -0,0 +1,162 @@
+/*
+ * 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.jaxb;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class MyBean {
+ private int age;
+ private String name;
+ private float[] rates = new float[] {1.0f, 2.0f};
+ private List<String> notes = new ArrayList<String>();
+ private Map<String, Integer> map = new HashMap<String, Integer>();
+ private Object service;
+ private Object otherService;
+ private boolean good;
+
+ public int getAge() {
+ return age;
+ }
+
+ public void setAge(int age) {
+ this.age = age;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List<String> getNotes() {
+ return notes;
+ }
+
+ public void setNotes(List<String> notes) {
+ this.notes = notes;
+ }
+
+ public float[] getRates() {
+ return rates;
+ }
+
+ public void setRates(float[] rates) {
+ this.rates = rates;
+ }
+
+ public Map<String, Integer> getMap() {
+ return map;
+ }
+
+ public void setMap(Map<String, Integer> map) {
+ this.map = map;
+ }
+
+ public Object getService() {
+ return service;
+ }
+
+ public void setService(Object service) {
+ this.service = service;
+ }
+
+ public Object getOtherService() {
+ return otherService;
+ }
+
+ public void setOtherService(Object otherService) {
+ this.otherService = otherService;
+ }
+
+ public boolean isGood() {
+ return good;
+ }
+
+ public void setGood(boolean good) {
+ this.good = good;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + age;
+ result = prime * result + (good ? 1231 : 1237);
+ result = prime * result + ((map == null) ? 0 : map.hashCode());
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((notes == null) ? 0 : notes.hashCode());
+ result = prime * result + ((otherService == null) ? 0 : otherService.hashCode());
+ result = prime * result + Arrays.hashCode(rates);
+ result = prime * result + ((service == null) ? 0 : service.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final MyBean other = (MyBean)obj;
+ if (age != other.age)
+ return false;
+ if (good != other.good)
+ return false;
+ if (map == null) {
+ if (other.map != null)
+ return false;
+ } else if (!map.equals(other.map))
+ return false;
+ if (name == null) {
+ if (other.name != null)
+ return false;
+ } else if (!name.equals(other.name))
+ return false;
+ if (notes == null) {
+ if (other.notes != null)
+ return false;
+ } else if (!notes.equals(other.notes))
+ return false;
+ if (otherService == null) {
+ if (other.otherService != null)
+ return false;
+ } else if (!otherService.equals(other.otherService))
+ return false;
+ if (!Arrays.equals(rates, other.rates))
+ return false;
+ if (service == null) {
+ if (other.service != null)
+ return false;
+ } else if (!service.equals(other.service))
+ return false;
+ return true;
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyInterface.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyInterface.java
new file mode 100644
index 0000000000..b8e9ee7f7d
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyInterface.java
@@ -0,0 +1,29 @@
+/*
+ * 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.jaxb;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public interface MyInterface {
+ void setId(String id);
+
+ String getId();
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyInterfaceImpl.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyInterfaceImpl.java
new file mode 100644
index 0000000000..5c511e6ccb
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyInterfaceImpl.java
@@ -0,0 +1,67 @@
+/*
+ * 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.jaxb;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class MyInterfaceImpl implements MyInterface {
+ private String id;
+
+ /**
+ * @see org.apache.tuscany.databinding.jaxb.MyInterface#getId()
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * @see org.apache.tuscany.databinding.jaxb.MyInterface#setId(java.lang.String)
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((id == null) ? 0 : id.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final MyInterfaceImpl other = (MyInterfaceImpl)obj;
+ if (id == null) {
+ if (other.id != null)
+ return false;
+ } else if (!id.equals(other.id))
+ return false;
+ return true;
+ }
+
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyJaxbBean.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyJaxbBean.java
new file mode 100644
index 0000000000..3c3992524a
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MyJaxbBean.java
@@ -0,0 +1,64 @@
+/*
+ * 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.jaxb;
+
+import javax.xml.bind.annotation.XmlAnyElement;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+import org.w3c.dom.Element;
+
+/**
+ *
+ */
+@XmlRootElement(name = "myBean", namespace = "http://ns1")
+public class MyJaxbBean {
+ public MyBean myBean;
+
+ @XmlJavaTypeAdapter(AnyTypeXmlAdapter.class)
+ public MyInterface myInterface;
+
+ @XmlElement(type = MyInterfaceImpl.class)
+ public MyInterface myInterface1;
+
+ @XmlJavaTypeAdapter(MyInterfaceAdapter.class)
+ public MyInterface myInterface2;
+
+ public Object myObject;
+
+ @XmlAnyElement
+ public Element anyElement;
+
+ public static class MyInterfaceAdapter extends XmlAdapter<MyInterfaceImpl, MyInterface> {
+
+ @Override
+ public MyInterfaceImpl marshal(MyInterface v) throws Exception {
+ return (MyInterfaceImpl) v;
+ }
+
+ @Override
+ public MyInterface unmarshal(MyInterfaceImpl v) throws Exception {
+ return (MyInterface) v;
+ }
+
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MySubBean.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MySubBean.java
new file mode 100644
index 0000000000..62dfa6f73c
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/MySubBean.java
@@ -0,0 +1,35 @@
+/*
+ * 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.jaxb;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class MySubBean extends MyBean {
+ private String addtional;
+
+ public String getAddtional() {
+ return addtional;
+ }
+
+ public void setAddtional(String addtional) {
+ this.addtional = addtional;
+ }
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/POJOTestCase.java b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/POJOTestCase.java
new file mode 100644
index 0000000000..98aefed546
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/java/org/apache/tuscany/sca/databinding/jaxb/POJOTestCase.java
@@ -0,0 +1,238 @@
+/*
+ * 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.jaxb;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Map;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.namespace.QName;
+import javax.xml.transform.stream.StreamSource;
+
+import org.junit.Test;
+
+
+/**
+ *
+ * @version $Rev$ $Date$
+ */
+public class POJOTestCase {
+
+ @Test
+ public void testAdapter() throws Exception {
+ JAXBContext context = JAXBContext.newInstance(MyJaxbBean.class, MyInterfaceImpl.class);
+ StringWriter writer = new StringWriter();
+ MyJaxbBean bean = new MyJaxbBean();
+ bean.myBean = new MySubBean();
+ bean.myBean.setName("Ray");
+ bean.myInterface = new MyInterfaceImpl();
+ bean.myInterface.setId("001");
+ bean.myObject = new MyBean();
+ ((MyBean) bean.myObject).setName("Y");
+ context.createMarshaller().marshal(bean, writer);
+ System.out.println(writer.toString());
+ Object result = context.createUnmarshaller().unmarshal(new StringReader(writer.toString()));
+ assertTrue(result instanceof MyJaxbBean);
+ Map<String, String> schemas = JAXBTypeHelper.generateSchema(context);
+ System.out.println(schemas);
+ }
+
+ @Test
+ public void testPOJO() throws Exception {
+ JAXBContext context = JAXBContext.newInstance(MyBean.class, MyInterfaceImpl.class);
+ StringWriter writer = new StringWriter();
+ MyBean bean = new MyBean();
+ bean.setName("Test");
+ bean.setAge(20);
+ bean.getNotes().add("1");
+ bean.getNotes().add("2");
+ bean.getMap().put("1", 1);
+ MyInterface service = new MyInterfaceImpl();
+ service.setId("ID001");
+ bean.setService(service);
+ bean.setOtherService(service);
+ JAXBElement<Object> element = new JAXBElement<Object>(new QName("http://ns1", "bean"), Object.class, bean);
+ context.createMarshaller().marshal(element, writer);
+ // System.out.println(writer.toString());
+
+ Object result = context.createUnmarshaller().unmarshal(new StringReader(writer.toString()));
+ assertTrue(result instanceof JAXBElement);
+ JAXBElement e2 = (JAXBElement)result;
+ assertTrue(e2.getValue() instanceof MyBean);
+ MyBean newBean = (MyBean)e2.getValue();
+ assertEquals(bean, newBean);
+ }
+
+ @Test
+ public void testPOJOArray() throws Exception {
+ JAXBContext context = JAXBContext.newInstance(MyBean[].class, MySubBean.class);
+ StringWriter writer = new StringWriter();
+ MySubBean bean = new MySubBean();
+ bean.setAddtional("SUB");
+ bean.setName("Test");
+ bean.setAge(20);
+ bean.getNotes().add("1");
+ bean.getNotes().add("2");
+ bean.getMap().put("1", 1);
+
+ JAXBElement<Object> element =
+ new JAXBElement<Object>(new QName("http://ns1", "beans"), Object.class, new MyBean[] {bean});
+ context.createMarshaller().marshal(element, writer);
+ System.out.println(writer.toString());
+
+ Object result =
+ context.createUnmarshaller().unmarshal(new StreamSource(new StringReader(writer.toString())),
+ MyBean[].class);
+ assertTrue(result instanceof JAXBElement);
+ JAXBElement e2 = (JAXBElement)result;
+ assertTrue(e2.getValue() instanceof MyBean[]);
+ MyBean newBean = ((MyBean[])e2.getValue())[0];
+ assertTrue(newBean instanceof MySubBean);
+ }
+
+ /*
+ public void testXMLStreamReader() throws Exception {
+ JAXBContext context = JAXBContext.newInstance(MyBean.class, MyInterfaceImpl.class);
+
+ MyBean bean = new MyBean();
+ bean.setName("Test");
+ bean.setAge(20);
+ bean.getNotes().add("1");
+ bean.getNotes().add("2");
+ bean.getMap().put("1", 1);
+ MyInterface service = new MyInterfaceImpl();
+ service.setId("ID001");
+ bean.setService(service);
+ bean.setOtherService(service);
+ QName name = new QName("http://ns1", "bean");
+ JAXBElement<Object> element = new JAXBElement<Object>(name, Object.class, bean);
+ TransformationContext tContext = new TransformationContextImpl();
+ XMLStreamReader reader = new JAXB2XMLStreamReader().transform(element, tContext);
+
+// XMLStreamReader2String t2 = new XMLStreamReader2String();
+// String xml = t2.transform(reader, null);
+ // System.out.println(xml);
+ Object result = context.createUnmarshaller().unmarshal(reader, MyBean.class);
+ assertTrue(result instanceof JAXBElement);
+ JAXBElement e2 = (JAXBElement)result;
+ assertTrue(e2.getValue() instanceof MyBean);
+ MyBean newBean = (MyBean)e2.getValue();
+ // FIXME :To be implemented
+ // assertEquals(bean, newBean);
+ }
+ */
+
+ @Test
+ public void testString() throws Exception {
+ JAXBContext context = JAXBContext.newInstance(String.class);
+ StringWriter writer = new StringWriter();
+ JAXBElement<Object> element = new JAXBElement<Object>(new QName("http://ns1", "bean"), Object.class, "ABC");
+ context.createMarshaller().marshal(element, writer);
+ // System.out.println(writer.toString());
+
+ Object result = context.createUnmarshaller().unmarshal(new StringReader(writer.toString()));
+ assertTrue(result instanceof JAXBElement);
+ JAXBElement e2 = (JAXBElement)result;
+ assertEquals("ABC", e2.getValue());
+ }
+
+ @Test
+ public void testNull() throws Exception {
+ JAXBContext context = JAXBContext.newInstance(String.class);
+ StringWriter writer = new StringWriter();
+ JAXBElement<Object> element = new JAXBElement<Object>(new QName("http://ns1", "bean"), Object.class, null);
+ element.setNil(true);
+ context.createMarshaller().marshal(element, writer);
+ // System.out.println(writer.toString());
+ StreamSource source = new StreamSource(new StringReader(writer.toString()));
+ Object result = context.createUnmarshaller().unmarshal(source, String.class);
+ assertTrue(result instanceof JAXBElement);
+ JAXBElement e2 = (JAXBElement)result;
+ assertNull(e2.getValue());
+ }
+
+ @Test
+ public void testArray() throws Exception {
+ JAXBContext context = JAXBContext.newInstance(String[].class);
+ StringWriter writer = new StringWriter();
+ JAXBElement<Object> element =
+ new JAXBElement<Object>(new QName("http://ns1", "bean"), Object.class, new String[] {"ABC", "123"});
+ context.createMarshaller().marshal(element, writer);
+ // System.out.println(writer.toString());
+
+ Object result = context.createUnmarshaller().unmarshal(new StringReader(writer.toString()));
+ assertTrue(result instanceof JAXBElement);
+ JAXBElement e2 = (JAXBElement)result;
+ assertTrue(e2.getValue() instanceof String[]);
+ }
+
+ @Test
+ public void testByteArray() throws Exception {
+ JAXBContext context = JAXBContext.newInstance(byte[].class);
+ StringWriter writer = new StringWriter();
+ JAXBElement<Object> element =
+ new JAXBElement<Object>(new QName("http://ns1", "bean"), Object.class, "ABC".getBytes());
+ context.createMarshaller().marshal(element, writer);
+ String xml = writer.toString();
+ assertTrue(xml.contains("QUJD"));
+ assertTrue(xml.contains("base64Binary"));
+
+ Object result = context.createUnmarshaller().unmarshal(new StringReader(xml));
+ assertTrue(result instanceof JAXBElement);
+ JAXBElement e2 = (JAXBElement)result;
+ assertTrue(e2.getValue() instanceof byte[]);
+ }
+
+ @Test
+ public void testPrimitive() throws Exception {
+ JAXBContext context = JAXBContext.newInstance(int.class);
+ StringWriter writer = new StringWriter();
+ JAXBElement<Integer> element = new JAXBElement<Integer>(new QName("http://ns1", "bean"), Integer.class, 1);
+ context.createMarshaller().marshal(element, writer);
+ // System.out.println(writer.toString());
+
+ StreamSource source = new StreamSource(new StringReader(writer.toString()));
+ Object result = context.createUnmarshaller().unmarshal(source, int.class);
+ assertTrue(result instanceof JAXBElement);
+ JAXBElement e2 = (JAXBElement)result;
+ assertEquals(1, e2.getValue());
+ }
+
+ /*
+ public void testException() throws Exception {
+ JAXBContext context = JAXBContext.newInstance(IllegalArgumentException.class);
+ StringWriter writer = new StringWriter();
+ Exception e = new IllegalArgumentException("123");
+ JAXBElement<Object> element = new JAXBElement<Object>(new QName("http://ns1", "bean"), Object.class, e);
+ context.createMarshaller().marshal(element, writer);
+ System.out.println(writer.toString());
+
+ Object result = context.createUnmarshaller().unmarshal(new StringReader(writer.toString()));
+ assertTrue(result instanceof JAXBElement);
+ JAXBElement e2 = (JAXBElement)result;
+ assertTrue(e2.getValue() instanceof Exception);
+ }
+ */
+}
diff --git a/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/resources/ipo.xsd b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/resources/ipo.xsd
new file mode 100755
index 0000000000..04e8cb44f3
--- /dev/null
+++ b/sandbox/sebastien/java/dynamic/modules/databinding-jaxb/src/test/resources/ipo.xsd
@@ -0,0 +1,144 @@
+<!--
+ * 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.
+-->
+<schema targetNamespace="http://www.example.com/IPO"
+ xmlns="http://www.w3.org/2001/XMLSchema"
+ xmlns:ipo="http://www.example.com/IPO">
+
+ <annotation>
+ <documentation xml:lang="en">
+ International Purchase order schema for Example.com
+ Copyright 2000 Example.com. All rights reserved.
+ </documentation>
+ </annotation>
+
+
+ <element name="purchaseOrder" type="ipo:PurchaseOrderType" />
+
+ <element name="comment" type="string" />
+
+ <complexType name="PurchaseOrderType">
+ <sequence>
+ <element name="shipTo" type="ipo:Address" />
+ <element name="billTo" type="ipo:Address" />
+ <element ref="ipo:comment" minOccurs="0" />
+ <element name="items" type="ipo:Items" />
+ </sequence>
+ <attribute name="orderDate" type="date" />
+ </complexType>
+
+ <complexType name="Items">
+ <sequence>
+ <element name="item" minOccurs="0" maxOccurs="unbounded">
+ <complexType>
+ <sequence>
+ <element name="productName" type="string" />
+ <element name="quantity">
+ <simpleType>
+ <restriction base="positiveInteger">
+ <maxExclusive value="100" />
+ </restriction>
+ </simpleType>
+ </element>
+ <element name="USPrice" type="decimal" />
+ <element ref="ipo:comment" minOccurs="0" />
+ <element name="shipDate" type="date"
+ minOccurs="0" />
+ </sequence>
+ <attribute name="partNum" type="ipo:SKU"
+ use="required" />
+ </complexType>
+ </element>
+ </sequence>
+ </complexType>
+
+ <simpleType name="SKU">
+ <restriction base="string">
+ <pattern value="\d{3}-[A-Z]{2}" />
+ </restriction>
+ </simpleType>
+
+ <complexType name="Address">
+ <sequence>
+ <element name="name" type="string" />
+ <element name="street" type="string" />
+ <element name="city" type="string" />
+ </sequence>
+ </complexType>
+
+ <complexType name="USAddress">
+ <complexContent>
+ <extension base="ipo:Address">
+ <sequence>
+ <element name="state" type="ipo:USState" />
+ <element name="zip" type="positiveInteger" />
+ </sequence>
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <complexType name="UKAddress">
+ <complexContent>
+ <extension base="ipo:Address">
+ <sequence>
+ <element name="postcode" type="ipo:UKPostcode" />
+ </sequence>
+ <attribute name="exportCode" type="positiveInteger"
+ fixed="1" />
+ </extension>
+ </complexContent>
+ </complexType>
+
+ <!-- other Address derivations for more countries -->
+
+ <simpleType name="USState">
+ <restriction base="string">
+ <enumeration value="AK" />
+ <enumeration value="AL" />
+ <enumeration value="AR" />
+ <enumeration value="CA" />
+ <enumeration value="PA" />
+ <!-- and so on ... -->
+ </restriction>
+ </simpleType>
+
+ <simpleType name="Postcode">
+ <restriction base="string">
+ <length value="7" fixed="true" />
+ </restriction>
+ </simpleType>
+
+
+ <simpleType name="UKPostcode">
+ <restriction base="ipo:Postcode">
+ <pattern value="[A-Z]{2}\d\s\d[A-Z]{2}" />
+ </restriction>
+ </simpleType>
+
+ <element name="note" type="ipo:Note" />
+ <complexType name="Note" mixed="true">
+ <sequence>
+ <any namespace="##any" processContents="lax" minOccurs="0"/>
+ </sequence>
+ <anyAttribute/>
+ </complexType>
+
+
+
+</schema>
+