summaryrefslogtreecommitdiffstats
path: root/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl
diff options
context:
space:
mode:
Diffstat (limited to 'sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl')
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/DirectedGraph.java469
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/Group2GroupTransformer.java91
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/GroupDataBinding.java104
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/Java2SimpleTypeTransformer.java72
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/MediatorImpl.java687
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/PipedTransformer.java70
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/SimpleType2JavaTransformer.java91
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/SimpleTypeMapperImpl.java402
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/TransformationContextImpl.java101
-rw-r--r--sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/XSDDataTypeConverter.java970
10 files changed, 3057 insertions, 0 deletions
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/DirectedGraph.java b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/DirectedGraph.java
new file mode 100644
index 0000000000..a551671452
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/DirectedGraph.java
@@ -0,0 +1,469 @@
+/*
+ * 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.impl;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Logger;
+
+/**
+ * Directed, weighted graph
+ *
+ * @param <V> The type of vertex object
+ * @param <E> The type of edge object
+ *
+ * @version $Rev$ $Date$
+ */
+public class DirectedGraph<V, E> implements Cloneable {
+ private final static Logger logger = Logger.getLogger(DirectedGraph.class.getName());
+ private final Map<V, Vertex> vertices = new HashMap<V, Vertex>();
+
+ /**
+ * Key for the shortest path cache
+ */
+ private final class VertexPair {
+ private Vertex source;
+
+ private Vertex target;
+
+ /**
+ * @param source
+ * @param target
+ */
+ private VertexPair(Vertex source, Vertex target) {
+ super();
+ this.source = source;
+ this.target = target;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (!VertexPair.class.isInstance(object)) {
+ return false;
+ }
+ VertexPair pair = (VertexPair)object;
+ return source == pair.source && target == pair.target;
+ }
+
+ @Override
+ public int hashCode() {
+ int x = source == null ? 0 : source.hashCode();
+ int y = target == null ? 0 : target.hashCode();
+ return x ^ y;
+ }
+
+ }
+
+ // Fix for TUSCANY-2069, making the map concurrent
+ private final Map<VertexPair, Path> paths = new ConcurrentHashMap<VertexPair, Path>();
+ private final Path NULL_PATH = new Path();
+
+ /**
+ * Vertex of a graph
+ */
+ public final class Vertex {
+ private V value;
+
+ // TODO: Do we want to support multiple edges for a vertex pair? If so,
+ // we should use a List instead of Map
+ private Map<Vertex, Edge> outEdges = new HashMap<Vertex, Edge>();
+ private Map<Vertex, Edge> inEdges = new HashMap<Vertex, Edge>();
+
+ private Vertex(V value) {
+ this.value = value;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + value + ")";
+ }
+
+ public V getValue() {
+ return value;
+ }
+
+ public Map<Vertex, Edge> getOutEdges() {
+ return outEdges;
+ }
+
+ public Map<Vertex, Edge> getInEdges() {
+ return inEdges;
+ }
+
+ }
+
+ /**
+ * An Edge connects two vertices in one direction
+ */
+ public final class Edge {
+ private Vertex sourceVertex;
+
+ private Vertex targetVertex;
+
+ private E value;
+
+ private int weight;
+
+ private boolean pub = true;
+
+ public Edge(Vertex source, Vertex target, E value, int weight, boolean pub) {
+ this.sourceVertex = source;
+ this.targetVertex = target;
+ this.value = value;
+ this.weight = weight;
+ this.pub = pub;
+ }
+
+ @Override
+ public String toString() {
+ return sourceVertex + "->" + targetVertex + "[" + value + "," + weight + "]";
+ }
+
+ public E getValue() {
+ return value;
+ }
+
+ public void setValue(E value) {
+ this.value = value;
+ }
+
+ public Vertex getTargetVertex() {
+ return targetVertex;
+ }
+
+ public void setTargetVertex(Vertex vertex) {
+ this.targetVertex = vertex;
+ }
+
+ public int getWeight() {
+ return weight;
+ }
+
+ public void setWeight(int weight) {
+ this.weight = weight;
+ }
+
+ public Vertex getSourceVertex() {
+ return sourceVertex;
+ }
+
+ public void setSourceVertex(Vertex sourceVertex) {
+ this.sourceVertex = sourceVertex;
+ }
+
+ public boolean isPublic() {
+ return pub;
+ }
+
+ public void setPublic(boolean pub) {
+ this.pub = pub;
+ }
+ }
+
+ private final class Node implements Comparable<Node> {
+
+ private long distance = Integer.MAX_VALUE;
+
+ private Node previous; // NOPMD by rfeng on 9/26/06 9:17 PM
+
+ private Vertex vertex; // NOPMD by rfeng on 9/26/06 9:17 PM
+
+ private Node(Vertex vertex) {
+ this.vertex = vertex;
+ }
+
+ public int compareTo(Node o) {
+ return (distance > o.distance) ? 1 : ((distance == o.distance) ? 0 : -1);
+ }
+ }
+
+ public void addEdge(V source, V target, E edgeValue, int weight, boolean publicEdge) {
+ // Fix for TUSCANY-3456
+ // First check if we already has an edge
+ Edge edge = getEdge(source, target);
+ if (edge != null) {
+ // An existing edge has higher weight, let's replace it
+ if (edge.weight > weight) {
+ logger.fine("An edge exists with higher weight: " + edge);
+ removeEdge(edge);
+ } else {
+ // Don't add this edge
+ logger.fine("An edge exists with lower weight: " + edge);
+ return;
+ }
+ }
+
+ Vertex s = getVertex(source);
+ if (s == null) {
+ s = new Vertex(source);
+ vertices.put(source, s);
+ }
+ Vertex t = getVertex(target);
+ if (t == null) {
+ t = new Vertex(target);
+ vertices.put(target, t);
+ }
+ edge = new Edge(s, t, edgeValue, weight, publicEdge);
+ s.outEdges.put(t, edge);
+ t.inEdges.put(s, edge);
+ }
+
+ public void addEdge(V soure, V target) {
+ addEdge(soure, target, null, 0, true);
+ }
+
+ public Vertex getVertex(V source) {
+ Vertex s = vertices.get(source);
+ return s;
+ }
+
+ public boolean removeEdge(V source, V target) {
+ Vertex s = getVertex(source);
+ if (s == null) {
+ return false;
+ }
+
+ Vertex t = getVertex(target);
+ if (t == null) {
+ return false;
+ }
+
+ return s.outEdges.remove(t) != null && t.inEdges.remove(s) != null;
+
+ }
+
+ public void removeEdge(Edge edge) {
+ edge.sourceVertex.outEdges.remove(edge.targetVertex);
+ edge.targetVertex.inEdges.remove(edge.sourceVertex);
+ }
+
+ public void removeVertex(Vertex vertex) {
+ vertices.remove(vertex.getValue());
+ for (Edge e : new ArrayList<Edge>(vertex.outEdges.values())) {
+ removeEdge(e);
+ }
+ for (Edge e : new ArrayList<Edge>(vertex.inEdges.values())) {
+ removeEdge(e);
+ }
+ }
+
+ public Edge getEdge(Vertex source, Vertex target) {
+ return source.outEdges.get(target);
+ }
+
+ public Edge getEdge(V source, V target) {
+ Vertex sv = getVertex(source);
+ if (sv == null) {
+ return null;
+ }
+ Vertex tv = getVertex(target);
+ if (tv == null) {
+ return null;
+ }
+ return getEdge(getVertex(source), getVertex(target));
+ }
+
+ /**
+ * Get the shortest path from the source vertex to the target vertex using
+ * Dijkstra's algorithm. If there's no path, null will be returned. If the
+ * source is the same as the target, it returns a path with empty edges with
+ * weight 0.
+ *
+ * @param sourceValue The value identifies the source
+ * @param targetValue The value identifies the target
+ * @return The shortest path
+ */
+ public Path getShortestPath(V sourceValue, V targetValue) {
+ Vertex source = getVertex(sourceValue);
+ if (source == null) {
+ return null;
+ }
+ Vertex target = getVertex(targetValue);
+ if (target == null) {
+ return null;
+ }
+
+ VertexPair pair = new VertexPair(source, target);
+ Path path = null;
+ if (paths.containsKey(pair)) {
+ path = paths.get(pair);
+ return path == NULL_PATH? null: path;
+ }
+
+ // Check if there is a direct link, if yes, use it instead
+ Edge direct = getEdge(source, target);
+ path = new Path();
+ if (direct != null) {
+ path.addEdge(direct);
+ paths.put(pair, path);
+ return path;
+ }
+
+ Map<Vertex, Node> nodes = new HashMap<Vertex, Node>();
+ for (Vertex v : vertices.values()) {
+ Node node = new Node(v);
+ if (v == source) {
+ node.distance = 0;
+ }
+ nodes.put(v, node);
+ }
+
+ Set<Node> otherNodes = new HashSet<Node>(nodes.values());
+ Set<Node> nodesOnPath = new HashSet<Node>();
+ Node nextNode = null;
+ while (!otherNodes.isEmpty()) {
+ nextNode = extractMin(otherNodes);
+ if (nextNode.vertex == target) {
+ path = getPath(nextNode);
+ paths.put(pair, path); // Cache it
+ return path == NULL_PATH? null: path;
+ }
+ nodesOnPath.add(nextNode);
+ for (Edge edge : nextNode.vertex.outEdges.values()) {
+ Node adjacentNode = nodes.get(edge.targetVertex);
+ // The private edge can only be used if the edge connects to the target directly
+ if (edge.isPublic() || edge.getTargetVertex() == target) {
+ if (nextNode.distance + edge.weight < adjacentNode.distance) {
+ adjacentNode.distance = nextNode.distance + edge.weight;
+ adjacentNode.previous = nextNode;
+ }
+ }
+ }
+ }
+ paths.put(pair, NULL_PATH); // Cache it
+ return null;
+ }
+
+ /**
+ * Searches for the vertex u in the vertex set Q that has the least d[u]
+ * value. That vertex is removed from the set Q and returned to the user.
+ *
+ * @param nodes
+ * @return
+ */
+ private Node extractMin(Set<Node> nodes) {
+ Node node = Collections.min(nodes);
+ nodes.remove(node);
+ return node;
+ }
+
+ /**
+ * The path between two vertices
+ */
+ public final class Path {
+ private List<Edge> edges = new LinkedList<Edge>();
+
+ private int weight;
+
+ public int getWeight() {
+ return weight;
+ }
+
+ public List<Edge> getEdges() {
+ return edges;
+ }
+
+ public void addEdge(Edge edge) {
+ edges.add(0, edge);
+ weight += edge.weight;
+ }
+
+ @Override
+ public String toString() {
+ return edges + ", " + weight;
+ }
+ }
+
+ private Path getPath(Node t) {
+ if (t.distance == Integer.MAX_VALUE) {
+ return NULL_PATH;
+ }
+ Path path = new Path();
+ Node u = t;
+ while (u.previous != null) {
+ Edge edge = getEdge(u.previous.vertex, u.vertex);
+ path.addEdge(edge);
+ u = u.previous;
+ }
+ return path;
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ for (Vertex v : vertices.values()) {
+ sb.append(v.outEdges.values()).append("\n");
+ }
+ return sb.toString();
+ }
+
+ public Map<V, Vertex> getVertices() {
+ return vertices;
+ }
+
+ public void addGraph(DirectedGraph<V, E> otherGraph) {
+ for (Vertex v : otherGraph.vertices.values()) {
+ for (Edge e : v.outEdges.values()) {
+ addEdge(e.sourceVertex.value, e.targetVertex.value, e.value, e.weight, true);
+ }
+ }
+ }
+
+ private Vertex getFirst() {
+ for (Vertex v : vertices.values()) {
+ if (v.inEdges.isEmpty()) {
+ return v;
+ }
+ }
+ if (!vertices.isEmpty()) {
+ throw new IllegalArgumentException("Circular ordering has been detected: " + toString());
+ } else {
+ return null;
+ }
+ }
+
+ public List<V> topologicalSort(boolean readOnly) {
+ DirectedGraph<V, E> graph = (!readOnly) ? this : (DirectedGraph<V, E>)clone();
+ List<V> list = new ArrayList<V>();
+ while (true) {
+ Vertex v = graph.getFirst();
+ if (v == null) {
+ break;
+ }
+ list.add(v.getValue());
+ graph.removeVertex(v);
+ }
+
+ return list;
+ }
+
+ @Override
+ public Object clone() {
+ DirectedGraph<V, E> copy = new DirectedGraph<V, E>();
+ copy.addGraph(this);
+ return copy;
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/Group2GroupTransformer.java b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/Group2GroupTransformer.java
new file mode 100644
index 0000000000..d4d0312bc0
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/Group2GroupTransformer.java
@@ -0,0 +1,91 @@
+/*
+ * 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.impl;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.databinding.BaseTransformer;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.databinding.PullTransformer;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.interfacedef.DataType;
+
+/**
+ * This is a special transformer to transform the output from one IDL to the
+ * other one
+ *
+ * @version $Rev$ $Date$
+ */
+public class Group2GroupTransformer extends BaseTransformer<Object, Object> implements
+ PullTransformer<Object, Object> {
+
+ protected Mediator mediator;
+
+ /**
+ * @param wrapperHandler
+ */
+ public Group2GroupTransformer(ExtensionPointRegistry registry) {
+ super();
+ this.mediator = registry.getExtensionPoint(UtilityExtensionPoint.class).getUtility(Mediator.class);
+ }
+
+ @Override
+ public String getSourceDataBinding() {
+ return GroupDataBinding.NAME;
+ }
+
+ @Override
+ public String getTargetDataBinding() {
+ return GroupDataBinding.NAME;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.databinding.BaseTransformer#getSourceType()
+ */
+ @Override
+ protected Class<Object> getSourceType() {
+ return Object.class;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.databinding.BaseTransformer#getTargetType()
+ */
+ @Override
+ protected Class<Object> getTargetType() {
+ return Object.class;
+ }
+
+ /**
+ * @see org.apache.tuscany.sca.databinding.Transformer#getWeight()
+ */
+ @Override
+ public int getWeight() {
+ return 10;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object transform(Object source, TransformationContext context) {
+ DataType<DataType> sourceType = context.getSourceDataType();
+ DataType<DataType> targetType = context.getTargetDataType();
+
+ return mediator.mediate(source, sourceType.getLogical(), targetType.getLogical(), context.getMetadata());
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/GroupDataBinding.java b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/GroupDataBinding.java
new file mode 100644
index 0000000000..1c7220fa67
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/GroupDataBinding.java
@@ -0,0 +1,104 @@
+/*
+ * 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.impl;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+import org.apache.tuscany.sca.databinding.BaseDataBinding;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+
+/**
+ * The base class for a special databinding which represents a group of other databindings
+ *
+ * @version $Rev$ $Date$
+ */
+public abstract class GroupDataBinding extends BaseDataBinding {
+ public static final String NAME = "databinding:group";
+
+ /**
+ * Marker type is a java class or interface representing the data format.
+ */
+ protected Class[] markerTypes;
+
+ public GroupDataBinding(Class[] types) {
+ super(NAME, GroupDataBinding.class);
+ this.markerTypes = types;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean introspect(DataType type, Operation operation) {
+ if (markerTypes == null) {
+ return false;
+ }
+ Type physical = type.getPhysical();
+ if (physical instanceof ParameterizedType) {
+ physical = ((ParameterizedType)physical).getRawType();
+ }
+ if (!(physical instanceof Class)) {
+ return false;
+ }
+ Class cls = (Class)physical;
+ for (Class<?> c : markerTypes) {
+ if (isTypeOf(c, cls)) {
+ type.setDataBinding(getDataBinding(c));
+ Object logical = getLogical(cls, null);
+ if (logical != null) {
+ type.setLogical(getLogical(cls, null));
+ } else {
+ type.setLogical(XMLType.UNKNOWN);
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Test if the given type is a subtype of the base type
+ * @param markerType
+ * @param type
+ * @return
+ */
+ protected boolean isTypeOf(Class<?> markerType, Class<?> type) {
+ return markerType.isAssignableFrom(type);
+ }
+
+ /**
+ * Derive the databinding name from a base class
+ * @param baseType
+ * @return
+ */
+ protected String getDataBinding(Class<?> baseType) {
+ return baseType.getName();
+ }
+
+ /**
+ * Get the logical type
+ * @param type The java type
+ * @param operation TODO
+ * @return
+ */
+ protected abstract Object getLogical(Class<?> type, Operation operation);
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/Java2SimpleTypeTransformer.java b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/Java2SimpleTypeTransformer.java
new file mode 100644
index 0000000000..f6e8e53459
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/Java2SimpleTypeTransformer.java
@@ -0,0 +1,72 @@
+/*
+ * 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.impl;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.databinding.BaseTransformer;
+import org.apache.tuscany.sca.databinding.PullTransformer;
+import org.apache.tuscany.sca.databinding.SimpleTypeMapper;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.databinding.javabeans.SimpleJavaDataBinding;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+
+/**
+ * Transformer to convert data from a simple java object to a databinding's representation
+ *
+ * @version $Rev$ $Date$
+ * @tuscany.spi.extension.inheritfrom
+ */
+public abstract class Java2SimpleTypeTransformer<T> extends BaseTransformer<Object, T> implements
+ PullTransformer<Object, T> {
+
+ protected SimpleTypeMapper mapper;
+
+ public Java2SimpleTypeTransformer() {
+ this.mapper = new SimpleTypeMapperImpl();
+ }
+
+ public Java2SimpleTypeTransformer(SimpleTypeMapper mapper) {
+ this.mapper = (mapper != null) ? mapper : new SimpleTypeMapperImpl();
+ }
+
+ public T transform(Object source, TransformationContext context) {
+ XMLType xmlType = (XMLType) context.getTargetDataType().getLogical();
+ String text = mapper.toXMLLiteral(xmlType.getTypeName(), source, context);
+ return createElement(xmlType.getElementName(), text, context);
+ }
+
+ @Override
+ public Class<Object> getSourceType() {
+ return Object.class;
+ }
+
+ @Override
+ public int getWeight() {
+ return 10000;
+ }
+
+ protected abstract T createElement(QName element, String literal, TransformationContext context);
+
+ @Override
+ public String getSourceDataBinding() {
+ return SimpleJavaDataBinding.NAME;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/MediatorImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/MediatorImpl.java
new file mode 100644
index 0000000000..20c6c2b9e2
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/MediatorImpl.java
@@ -0,0 +1,687 @@
+/*
+ * 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.impl;
+
+import static org.apache.tuscany.sca.interfacedef.Operation.IDL_FAULT;
+import static org.apache.tuscany.sca.interfacedef.Operation.IDL_OUTPUT;
+
+import java.io.Serializable;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.core.ExtensionPointRegistry;
+import org.apache.tuscany.sca.core.UtilityExtensionPoint;
+import org.apache.tuscany.sca.databinding.DataBinding;
+import org.apache.tuscany.sca.databinding.DataBindingExtensionPoint;
+import org.apache.tuscany.sca.databinding.DataPipe;
+import org.apache.tuscany.sca.databinding.DataPipeTransformer;
+import org.apache.tuscany.sca.databinding.Mediator;
+import org.apache.tuscany.sca.databinding.PullTransformer;
+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.Transformer;
+import org.apache.tuscany.sca.databinding.TransformerExtensionPoint;
+import org.apache.tuscany.sca.databinding.javabeans.JavaBeansDataBinding;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.FaultExceptionMapper;
+import org.apache.tuscany.sca.interfacedef.InterfaceContractMapper;
+import org.apache.tuscany.sca.interfacedef.Operation;
+import org.apache.tuscany.sca.interfacedef.ParameterMode;
+import org.apache.tuscany.sca.interfacedef.impl.DataTypeImpl;
+import org.apache.tuscany.sca.interfacedef.util.FaultException;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+import org.oasisopen.sca.ServiceRuntimeException;
+
+
+/**
+ * Default Mediator implementation
+ *
+ * @version $Rev$ $Date$
+ * @tuscany.spi.extension.asclient
+ */
+public class MediatorImpl implements Mediator {
+
+ private ExtensionPointRegistry registry;
+ private DataBindingExtensionPoint dataBindings;
+ private TransformerExtensionPoint transformers;
+ private InterfaceContractMapper interfaceContractMapper;
+ private FaultExceptionMapper faultExceptionMapper;
+
+ MediatorImpl(DataBindingExtensionPoint dataBindings, TransformerExtensionPoint transformers) {
+ this.dataBindings = dataBindings;
+ this.transformers = transformers;
+ }
+
+ public MediatorImpl(ExtensionPointRegistry registry) {
+ this.registry = registry;
+ this.dataBindings = registry.getExtensionPoint(DataBindingExtensionPoint.class);
+ this.transformers = registry.getExtensionPoint(TransformerExtensionPoint.class);
+ UtilityExtensionPoint utilities = registry.getExtensionPoint(UtilityExtensionPoint.class);
+ this.interfaceContractMapper = utilities.getUtility(InterfaceContractMapper.class);
+ this.faultExceptionMapper = utilities.getUtility(FaultExceptionMapper.class);
+
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object mediate(Object source, DataType sourceDataType, DataType targetDataType, Map<String, Object> metadata) {
+ if (sourceDataType == null || sourceDataType.getDataBinding() == null) {
+ if (source != null) {
+ Operation operation = (Operation)metadata.get(SOURCE_OPERATION);
+ sourceDataType = dataBindings.introspectType(source, operation);
+ }
+ }
+ if (sourceDataType == null || targetDataType == null) {
+ return source;
+ } else if (sourceDataType.equals(targetDataType)) {
+ return source;
+ }
+
+ List<Transformer> path = getTransformerChain(sourceDataType, targetDataType);
+
+ Object result = source;
+ int size = path.size();
+ int i = 0;
+ while (i < size) {
+ Transformer transformer = path.get(i);
+ TransformationContext context =
+ createTransformationContext(sourceDataType, targetDataType, size, i, transformer, metadata);
+ // the source and target type
+ if (transformer instanceof PullTransformer) {
+ // For intermediate node, set data type to null
+ result = ((PullTransformer)transformer).transform(result, context);
+ } else if (transformer instanceof PushTransformer) {
+ DataPipeTransformer dataPipeFactory = (i < size - 1) ? (DataPipeTransformer)path.get(++i) : null;
+ DataPipe dataPipe = dataPipeFactory == null ? null : dataPipeFactory.newInstance();
+ ((PushTransformer)transformer).transform(result, dataPipe.getSink(), context);
+ result = dataPipe.getResult();
+ }
+ i++;
+ }
+
+ return result;
+ }
+
+ private TransformationContext createTransformationContext(DataType sourceDataType,
+ DataType targetDataType,
+ int size,
+ int index,
+ Transformer transformer,
+ Map<String, Object> metadata) {
+ DataType sourceType =
+ (index == 0) ? sourceDataType : new DataTypeImpl<Object>(transformer.getSourceDataBinding(), Object.class,
+ sourceDataType.getLogical());
+ DataType targetType =
+ (index == size - 1) ? targetDataType : new DataTypeImpl<Object>(transformer.getTargetDataBinding(),
+ Object.class, targetDataType.getLogical());
+
+ Map<String, Object> copy = new HashMap<String, Object>();
+ if (metadata != null) {
+ copy.putAll(metadata);
+ }
+ copy.put(ExtensionPointRegistry.class.getName(), registry);
+
+ TransformationContext context = new TransformationContextImpl(sourceType, targetType, copy);
+ return context;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void mediate(Object source,
+ Object target,
+ DataType sourceDataType,
+ DataType targetDataType,
+ Map<String, Object> metadata) {
+ if (source == null) {
+ // Shortcut for null value
+ return;
+ }
+ if (sourceDataType == null || sourceDataType.getDataBinding() == null) {
+ Operation operation = (Operation)metadata.get(SOURCE_OPERATION);
+ sourceDataType = dataBindings.introspectType(source, operation);
+ }
+ if (sourceDataType == null) {
+ return;
+ } else if (sourceDataType.equals(targetDataType)) {
+ return;
+ }
+
+ List<Transformer> path = getTransformerChain(sourceDataType, targetDataType);
+ Object result = source;
+ int size = path.size();
+ for (int i = 0; i < size; i++) {
+ Transformer transformer = path.get(i);
+ TransformationContext context =
+ createTransformationContext(sourceDataType, targetDataType, size, i, transformer, metadata);
+
+ if (transformer instanceof PullTransformer) {
+ result = ((PullTransformer)transformer).transform(result, context);
+ } else if (transformer instanceof PushTransformer) {
+ DataPipeTransformer dataPipeFactory = (i < size - 1) ? (DataPipeTransformer)path.get(++i) : null;
+ DataPipe dataPipe = dataPipeFactory == null ? null : dataPipeFactory.newInstance();
+ Object sink = dataPipe != null ? dataPipe.getSink() : target;
+ ((PushTransformer)transformer).transform(result, sink, context);
+ result = (dataPipe != null) ? dataPipe.getResult() : null;
+ }
+ }
+ }
+
+ private List<Transformer> getTransformerChain(DataType sourceDataType, DataType targetDataType) {
+ String sourceId = sourceDataType.getDataBinding();
+ String targetId = targetDataType.getDataBinding();
+ List<Transformer> path = transformers.getTransformerChain(sourceId, targetId);
+ if (path == null) {
+ TransformationException ex =
+ new TransformationException("No path found for the transformation: " + sourceId + "->" + targetId);
+ ex.setSourceDataBinding(sourceId);
+ ex.setTargetDataBinding(targetId);
+ throw ex;
+ }
+ return path;
+ }
+
+ public DataBindingExtensionPoint getDataBindings() {
+ return dataBindings;
+ }
+
+ public TransformerExtensionPoint getTransformers() {
+ return transformers;
+ }
+
+ /**
+ * Find the fault data type behind the exception data type
+ * @param exceptionType The exception data type
+ * @return The fault data type
+ */
+ private DataType getFaultType(DataType exceptionType) {
+ return exceptionType == null ? null : (DataType)exceptionType.getLogical();
+ }
+
+ /**
+ * @param qn1
+ * @param qn2
+ */
+ private boolean matches(QName qn1, QName qn2) {
+ if (qn1 == qn2) {
+ return true;
+ }
+ if (qn1 == null || qn2 == null) {
+ return false;
+ }
+ String ns1 = qn1.getNamespaceURI();
+ String ns2 = qn2.getNamespaceURI();
+ String e1 = qn1.getLocalPart();
+ String e2 = qn2.getLocalPart();
+ if (e1.equals(e2) && (ns1.equals(ns2) || ns1.equals(ns2 + "/") || ns2.equals(ns1 + "/"))) {
+ // Tolerating the trailing / which is required by JAX-WS java package --> xml ns mapping
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param source The source exception
+ * @param sourceExType The data type for the source exception
+ * @param targetExType The data type for the target exception
+ * @param sourceType The fault type for the source
+ * @param targetType The fault type for the target
+ * @return
+ */
+ private Object transformException(Object source,
+ DataType sourceExType,
+ DataType targetExType,
+ DataType sourceType,
+ DataType targetType,
+ Map<String, Object> metadata) {
+
+ if (sourceType == targetType || (sourceType != null && sourceType.equals(targetType))) {
+ return source;
+ }
+
+ DataType<DataType> eSourceDataType =
+ new DataTypeImpl<DataType>(IDL_FAULT, sourceExType.getPhysical(), sourceType);
+ DataType<DataType> eTargetDataType =
+ new DataTypeImpl<DataType>(IDL_FAULT, targetExType.getPhysical(), targetType);
+
+ return mediate(source, eSourceDataType, eTargetDataType, metadata);
+ }
+
+ //
+ // Assumes we're going from target->source, knowing that we're throwing BACK an exception, rather than the more
+ // obvious source->target
+ //
+ public Object mediateFault(Object result,
+ Operation sourceOperation,
+ Operation targetOperation,
+ Map<String, Object> metadata) {
+
+ // FIXME: How to match fault data to a fault type for the
+ // operation?
+
+ // If the result is from an InvocationTargetException look at
+ // the actual cause.
+ if (result instanceof InvocationTargetException) {
+ result = ((InvocationTargetException)result).getCause();
+ }
+
+ DataType targetDataType = findFaultDataType(targetOperation, result);
+ DataType targetFaultType = getFaultType(targetDataType);
+
+
+ if (targetFaultType == null) {
+ // No matching fault type, it's a system exception
+ Throwable cause = (Throwable)result;
+ throw new ServiceRuntimeException(cause);
+ }
+
+ // FIXME: How to match a source fault type to a target fault
+ // type?
+ DataType sourceDataType = null;
+ DataType sourceFaultType = null;
+ for (DataType exType : sourceOperation.getFaultTypes()) {
+ DataType faultType = getFaultType(exType);
+ // Match by the QName (XSD element) of the fault type
+ if (faultType != null && typesMatch(targetFaultType.getLogical(), faultType.getLogical())) {
+ sourceDataType = exType;
+ sourceFaultType = faultType;
+ break;
+ }
+ }
+
+ if (sourceFaultType == null) {
+ // No matching fault type, it's a system exception
+ Throwable cause = (Throwable)result;
+ throw new ServiceRuntimeException(cause);
+ }
+
+ Map<String, Object> context = new HashMap<String, Object>();
+ if (metadata != null) {
+ context.putAll(metadata);
+ }
+ if (targetOperation != null) {
+ context.put(SOURCE_OPERATION, targetOperation);
+ }
+ if (sourceOperation != null) {
+ context.put(TARGET_OPERATION, sourceOperation);
+ }
+ if (context.get(BODY_TYPE) == null) {
+ context.put(BODY_TYPE, BODY_TYPE_FAULT);
+ }
+
+
+ Object newResult =
+ transformException(result, targetDataType, sourceDataType, targetFaultType, sourceFaultType, context);
+
+ return newResult;
+
+ }
+
+ /**
+ * Look up the fault data type that matches the fault or exception instance
+ * @param operation The operation
+ * @param faultOrException The fault or exception
+ * @return The matching fault data type
+ */
+ private DataType findFaultDataType(Operation operation, Object faultOrException) {
+ DataType targetDataType = null;
+ for (DataType exType : operation.getFaultTypes()) {
+ if (((Class)exType.getPhysical()).isInstance(faultOrException)) {
+ if (faultOrException instanceof FaultException) {
+ DataType faultType = (DataType)exType.getLogical();
+ if (((FaultException)faultOrException).isMatchingType(faultType.getLogical())) {
+ targetDataType = exType;
+ break;
+ }
+ } else {
+ targetDataType = exType;
+ break;
+ }
+ }
+ }
+ return targetDataType;
+ }
+
+ private boolean typesMatch(Object first, Object second) {
+ if (first.equals(second)) {
+ return true;
+ }
+ if (first instanceof XMLType && second instanceof XMLType) {
+ XMLType t1 = (XMLType)first;
+ XMLType t2 = (XMLType)second;
+ // TUSCANY-2113, we should compare element names only
+ return matches(t1.getElementName(), t2.getElementName());
+ }
+ return false;
+ }
+
+ /**
+ * Assumes we're going from target-to-source, knowing that we're sending BACK an output response, rather than the more
+ * obvious source-to-target.
+ *
+ * @param output
+ * @param sourceOperation
+ * @param targetOperation
+ * @return
+ */
+ public Object mediateOutput(Object output,
+ Operation sourceOperation,
+ Operation targetOperation,
+ Map<String, Object> metadata) {
+
+ DataType sourceType = sourceOperation.getOutputType();
+ DataType targetType = targetOperation.getOutputType();
+
+ if (sourceType == targetType || (sourceType != null && sourceType.equals(targetType))) {
+ return output;
+ }
+ Map<String, Object> context = new HashMap<String, Object>();
+ if (metadata != null) {
+ context.putAll(metadata);
+ }
+ if (targetOperation != null) {
+ context.put(SOURCE_OPERATION, targetOperation);
+ }
+ if (sourceOperation != null) {
+ context.put(TARGET_OPERATION, sourceOperation);
+ }
+ if (context.get(BODY_TYPE) == null) {
+ context.put(BODY_TYPE, BODY_TYPE_OUTPUT);
+ }
+
+ return mediate(output, targetType, sourceType, context);
+ }
+
+ public Object mediateInput(Object input,
+ Operation sourceOperation,
+ Operation targetOperation,
+ Map<String, Object> metadata) {
+ // Get the data type to represent the input passed in by the source operation
+ DataType sourceType = sourceOperation.getInputType();
+
+ // Get the data type to represent the input expected by the target operation
+ DataType targetType = targetOperation.getInputType();
+
+ if (sourceType == targetType || (sourceType != null && sourceType.equals(targetType))) {
+ return input;
+ }
+ Map<String, Object> context = new HashMap<String, Object>();
+ if (metadata != null) {
+ context.putAll(metadata);
+ }
+ if (sourceOperation != null) {
+ context.put(SOURCE_OPERATION, sourceOperation);
+ }
+ if (targetOperation != null) {
+ context.put(TARGET_OPERATION, targetOperation);
+ }
+ if (context.get(BODY_TYPE) == null) {
+ context.put(BODY_TYPE, BODY_TYPE_INPUT);
+ }
+
+ return mediate(input, sourceType, targetType, context);
+ }
+
+ public TransformationContext createTransformationContext() {
+ return new TransformationContextImpl();
+ }
+
+ public TransformationContext createTransformationContext(DataType sourceDataType,
+ DataType targetDataType,
+ Map<String, Object> metadata) {
+ return new TransformationContextImpl(sourceDataType, targetDataType, metadata);
+ }
+
+ public Object copy(Object data, DataType dataType) {
+ return copy(data, dataType, dataType, null, null);
+ }
+
+ public Object copy(Object data, DataType sourceDataType, DataType targetDataType) {
+ return copy(data, sourceDataType, targetDataType, null, null);
+ }
+
+ /**
+ * Copy data using the specified databinding.
+ * @param data input data
+ * @param sourceDataType
+ * @return a copy of the data
+ */
+ public Object copy(Object data,
+ DataType sourceDataType,
+ DataType targetDataType,
+ Operation sourceOperation,
+ Operation targetOperation) {
+ if (data == null) {
+ return null;
+ }
+ Class<?> clazz = data.getClass();
+ if (String.class == clazz || clazz.isPrimitive()
+ || Number.class.isAssignableFrom(clazz)
+ || Boolean.class.isAssignableFrom(clazz)
+ || Character.class.isAssignableFrom(clazz)
+ || Byte.class.isAssignableFrom(clazz)
+ || URI.class == clazz
+ || UUID.class == clazz
+ || QName.class == clazz) {
+ // Immutable classes
+ return data;
+ }
+
+ DataBinding javaBeansDataBinding = dataBindings.getDataBinding(JavaBeansDataBinding.NAME);
+ // FIXME: The JAXB databinding is hard-coded here
+ DataBinding jaxbDataBinding = dataBindings.getDataBinding("javax.xml.bind.JAXBElement");
+ DataBinding dataBinding = dataBindings.getDataBinding(sourceDataType.getDataBinding());
+ // If no databinding was specified, introspect the given arg to
+ // determine its databinding
+ if (dataBinding == null) {
+ if (!"java:array".equals(sourceDataType.getDataBinding())) {
+ sourceDataType = dataBindings.introspectType(data, sourceOperation);
+ if (sourceDataType != null) {
+ String db = sourceDataType.getDataBinding();
+ dataBinding = dataBindings.getDataBinding(db);
+ if (dataBinding == null && db != null) {
+ return data;
+ }
+ }
+ }
+ if (dataBinding == null) {
+
+ // Default to the JavaBean databinding
+ dataBinding = dataBindings.getDataBinding(JavaBeansDataBinding.NAME);
+ }
+ }
+
+ // Use the JAXB databinding to copy non-Serializable data
+ if (dataBinding == javaBeansDataBinding) {
+
+ // If the input data is an array containing non Serializable elements
+ // use JAXB
+ clazz = data.getClass();
+ if (clazz.isArray()) {
+ if (Array.getLength(data) != 0) {
+ Object element = Array.get(data, 0);
+ if (element != null && !(element instanceof Serializable)) {
+ dataBinding = jaxbDataBinding;
+ }
+ }
+ } else {
+
+ // If the input data is not Serializable use JAXB
+ if (!((data instanceof Serializable) || (data instanceof Cloneable))) {
+ dataBinding = jaxbDataBinding;
+ }
+ }
+ }
+
+ if (dataBinding == null) {
+ return data;
+ }
+
+ return dataBinding.copy(data, sourceDataType, targetDataType, sourceOperation, targetOperation);
+ }
+
+ /**
+ * Copy an array of data objects passed to an operation
+ * @param data array of objects to copy
+ * @return the copy
+ */
+ public Object copyInput(Object input, Operation operation) {
+ return copyInput(input, operation, operation);
+ }
+ public Object copyInput(Object input, Operation sourceOperation, Operation targetOperation) {
+ if (input == null) {
+ return null;
+ }
+ Object[] data = (input instanceof Object[]) ? (Object[])input : new Object[] {input};
+ List<DataType> inputTypes = sourceOperation.getInputType().getLogical();
+ List<DataType> inputTypesTarget = targetOperation == null ? null : targetOperation.getInputType().getLogical();
+ Object[] copy = new Object[data.length];
+ Map<Object, Object> map = new IdentityHashMap<Object, Object>();
+
+ // OUT-only parameters have already been filtered out of the inputTypes List.
+ for (int i = 0; i < inputTypes.size(); i++) {
+ Object arg = data[i];
+ if (arg == null) {
+ copy[i] = null;
+ } else {
+ Object copiedArg = map.get(arg);
+ if (copiedArg != null) {
+ copy[i] = copiedArg;
+ } else {
+ copiedArg =
+ copy(arg,
+ inputTypes.get(i),
+ inputTypesTarget == null ? null : inputTypesTarget.get(i),
+ sourceOperation,
+ targetOperation);
+ map.put(arg, copiedArg);
+ copy[i] = copiedArg;
+ }
+ }
+ }
+ return copy;
+ }
+
+ public Object copyOutput(Object data, Operation operation) {
+ return copyOutput(data, operation, operation);
+ }
+
+ public Object copyOutput(Object data, Operation sourceOperation, Operation targetOperation) {
+
+ // Rename the parameters so we can more easily remember which direction we're going in.
+ Operation fromOperation = targetOperation;
+ Operation toOperation = sourceOperation;
+
+ if ( data == null )
+ return null;
+ Object[] output = null;
+
+ if ( !fromOperation.hasArrayWrappedOutput() ) {
+ output = new Object[] {data};
+ } else {
+ output = (Object[])data;
+ }
+
+ List<DataType> outputTypes = fromOperation.getOutputType().getLogical();
+ List<DataType> outputTypesTarget = toOperation == null ? null : toOperation.getOutputType().getLogical();
+ Object[] copy = new Object[output.length];
+ Map<Object, Object> map = new IdentityHashMap<Object, Object>();
+ for (int i = 0, size = output.length; i < size; i++) {
+ Object arg = output[i];
+ if (arg == null) {
+ copy[i] = null;
+ } else {
+ Object copiedArg = map.get(arg);
+ if (copiedArg != null) {
+ copy[i] = copiedArg;
+ } else {
+ copiedArg =
+ copy(arg,
+ outputTypes.get(i),
+ outputTypesTarget == null ? null : outputTypesTarget.get(i),
+ fromOperation,
+ toOperation);
+ map.put(arg, copiedArg);
+ copy[i] = copiedArg;
+ }
+ }
+ }
+ if ( !toOperation.hasArrayWrappedOutput()) {
+ return copy[0];
+ } else {
+ return copy;
+ }
+ }
+
+ public Object copyFault(Object fault, Operation operation) {
+ return copyFault(fault, operation, operation);
+ }
+
+ public Object copyFault(Object fault, Operation sourceOperation, Operation targetOperation) {
+
+ // Rename the parameters so we can more easily remember which direction we're going in.
+ Operation fromOperation = targetOperation;
+ Operation toOperation = sourceOperation;
+
+ if (faultExceptionMapper == null) {
+ return fault;
+ }
+ List<DataType> fts = fromOperation.getFaultTypes();
+ for (int i = 0; i < fts.size(); i++) {
+ DataType et = fts.get(i);
+ if (et.getPhysical().isInstance(fault)) {
+ Throwable ex = (Throwable)fault;
+ DataType<DataType> exType = findFaultDataType(fromOperation, fault);
+ DataType faultType = getFaultType(exType);
+ Object faultInfo = faultExceptionMapper.getFaultInfo(ex, faultType.getPhysical(), fromOperation);
+ DataType targetExType = findSourceFaultDataType(toOperation, exType);
+ DataType targetFaultType = getFaultType(targetExType);
+ faultInfo = copy(faultInfo, faultType, targetFaultType, fromOperation, toOperation);
+ fault = faultExceptionMapper.wrapFaultInfo(targetExType, ex.getMessage(), faultInfo, ex.getCause(), toOperation);
+ return fault;
+ }
+ }
+ return fault;
+ }
+
+ /**
+ * Lookup a fault data type from the source operation which matches the target fault data type
+ * @param sourceOperation The source operation
+ * @param targetExceptionType The target fault data type
+ * @return The matching source target fault type
+ */
+ private DataType findSourceFaultDataType(Operation sourceOperation, DataType targetExceptionType) {
+ boolean remotable = sourceOperation.getInterface().isRemotable();
+ DataType targetFaultType = getFaultType(targetExceptionType);
+ for (DataType dt : sourceOperation.getFaultTypes()) {
+ DataType sourceFaultType = getFaultType(dt);
+ if (interfaceContractMapper.isCompatible(targetFaultType, sourceFaultType, remotable)) {
+ return dt;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/PipedTransformer.java b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/PipedTransformer.java
new file mode 100644
index 0000000000..a1a89005b3
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/PipedTransformer.java
@@ -0,0 +1,70 @@
+/*
+ * 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.impl;
+
+import org.apache.tuscany.sca.databinding.DataPipe;
+import org.apache.tuscany.sca.databinding.DataPipeTransformer;
+import org.apache.tuscany.sca.databinding.PullTransformer;
+import org.apache.tuscany.sca.databinding.PushTransformer;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+
+/**
+ * A utility class to connect PushTransformer and DataPipe to create a
+ * PullTransformer
+ *
+ * @param <S> Source type
+ * @param <I> Intermediate type
+ * @param <R> Result type
+ *
+ * @version $Rev$ $Date$
+ */
+public class PipedTransformer<S, I, R> implements PullTransformer<S, R> {
+ private PushTransformer<S, I> pusher;
+
+ private DataPipeTransformer<I, R> pipe;
+
+ /**
+ * @param pumper
+ * @param pipe
+ */
+ public PipedTransformer(PushTransformer<S, I> pumper, DataPipeTransformer<I, R> pipe) {
+ super();
+ this.pusher = pumper;
+ this.pipe = pipe;
+ }
+
+ public R transform(S source, TransformationContext context) {
+ DataPipe<I, R> dataPipe = pipe.newInstance();
+ pusher.transform(source, dataPipe.getSink(), context);
+ return dataPipe.getResult();
+ }
+
+ public String getSourceDataBinding() {
+ return pusher.getSourceDataBinding();
+ }
+
+ public String getTargetDataBinding() {
+ return pipe.getTargetDataBinding();
+ }
+
+ public int getWeight() {
+ return pusher.getWeight() + pipe.getWeight();
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/SimpleType2JavaTransformer.java b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/SimpleType2JavaTransformer.java
new file mode 100644
index 0000000000..a7849498b4
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/SimpleType2JavaTransformer.java
@@ -0,0 +1,91 @@
+/*
+ * 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.impl;
+
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.databinding.BaseTransformer;
+import org.apache.tuscany.sca.databinding.PullTransformer;
+import org.apache.tuscany.sca.databinding.SimpleTypeMapper;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.databinding.javabeans.SimpleJavaDataBinding;
+import org.apache.tuscany.sca.interfacedef.util.XMLType;
+
+/**
+ * Transformer to convert data from a databinding's representation of simple
+ * types to Java Objects
+ *
+ * @version $Rev$ $Date$
+ * @tuscany.spi.extension.inheritfrom
+ */
+public abstract class SimpleType2JavaTransformer<T> extends BaseTransformer<T, Object> implements
+ PullTransformer<T, Object> {
+
+ protected SimpleTypeMapper mapper;
+
+ public SimpleType2JavaTransformer() {
+ this.mapper = new SimpleTypeMapperImpl();
+ }
+
+ public SimpleType2JavaTransformer(SimpleTypeMapper mapper) {
+ this.mapper = (mapper != null) ? mapper : new SimpleTypeMapperImpl();
+ }
+
+ public Object transform(T source, TransformationContext context) {
+ XMLType xmlType = (XMLType)context.getSourceDataType().getLogical();
+ QName type = (xmlType != null) ? xmlType.getTypeName() : null;
+ if (type == null) {
+ xmlType = (XMLType)context.getTargetDataType().getLogical();
+ type = (xmlType != null) ? xmlType.getTypeName() : null;
+ }
+ Object result = mapper.toJavaObject(type, getText(source), context);
+ close(source);
+ return result;
+ }
+
+ @Override
+ protected Class<Object> getTargetType() {
+ return Object.class;
+ }
+
+ @Override
+ public int getWeight() {
+ // Cannot be used for intermediate
+ return 10000;
+ }
+
+ /**
+ * Get the string value from the source
+ * @param source
+ * @return A string
+ */
+ protected abstract String getText(T source);
+
+ /**
+ * To be overrided by the subclass
+ * @param source
+ */
+ protected void close(T source) {
+ }
+
+ @Override
+ public String getTargetDataBinding() {
+ return SimpleJavaDataBinding.NAME;
+ }
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/SimpleTypeMapperImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/SimpleTypeMapperImpl.java
new file mode 100644
index 0000000000..16eb4b42ed
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/SimpleTypeMapperImpl.java
@@ -0,0 +1,402 @@
+/*
+ * 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.impl;
+
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+
+import org.apache.tuscany.sca.databinding.SimpleTypeMapper;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.interfacedef.util.TypeInfo;
+
+/**
+ * Simple type mapper that maps from XSD types to Java Classes and Java Classes to XSD types.
+ *
+ * @version $Rev$ $Date$
+ * @tuscany.spi.extension.asclient
+ */
+public class SimpleTypeMapperImpl extends XSDDataTypeConverter implements SimpleTypeMapper {
+
+ public static final Map<Class, String> JAVA2XML = new HashMap<Class, String>();
+
+ public static final String URI_2001_SCHEMA_XSD = "http://www.w3.org/2001/XMLSchema";
+
+ public static final Map<String, Class> XML2JAVA = new HashMap<String, Class>();
+
+ public static final QName XSD_ANY = new QName(URI_2001_SCHEMA_XSD, "any");
+
+ public static final QName XSD_ANYSIMPLETYPE = new QName(URI_2001_SCHEMA_XSD, "anySimpleType");
+
+ public static final QName XSD_ANYTYPE = new QName(URI_2001_SCHEMA_XSD, "anyType");
+
+ public static final QName XSD_ANYURI = new QName(URI_2001_SCHEMA_XSD, "anyURI");
+
+ public static final QName XSD_BASE64 = new QName(URI_2001_SCHEMA_XSD, "base64Binary");
+
+ public static final QName XSD_BOOLEAN = new QName(URI_2001_SCHEMA_XSD, "boolean");
+
+ public static final QName XSD_BYTE = new QName(URI_2001_SCHEMA_XSD, "byte");
+
+ public static final QName XSD_DATE = new QName(URI_2001_SCHEMA_XSD, "date");
+
+ public static final QName XSD_DATETIME = new QName(URI_2001_SCHEMA_XSD, "dateTime");
+
+ public static final QName XSD_DAY = new QName(URI_2001_SCHEMA_XSD, "gDay");
+
+ public static final QName XSD_DECIMAL = new QName(URI_2001_SCHEMA_XSD, "decimal");
+
+ public static final QName XSD_DOUBLE = new QName(URI_2001_SCHEMA_XSD, "double");
+
+ public static final QName XSD_DURATION = new QName(URI_2001_SCHEMA_XSD, "duration");
+
+ public static final QName XSD_ENTITIES = new QName(URI_2001_SCHEMA_XSD, "ENTITIES");
+
+ public static final QName XSD_ENTITY = new QName(URI_2001_SCHEMA_XSD, "ENTITY");
+
+ public static final QName XSD_FLOAT = new QName(URI_2001_SCHEMA_XSD, "float");
+
+ public static final QName XSD_HEXBIN = new QName(URI_2001_SCHEMA_XSD, "hexBinary");
+
+ public static final QName XSD_IDREF = new QName(URI_2001_SCHEMA_XSD, "IDREF");
+
+ public static final QName XSD_IDREFS = new QName(URI_2001_SCHEMA_XSD, "IDREFS");
+
+ public static final QName XSD_INT = new QName(URI_2001_SCHEMA_XSD, "int");
+
+ public static final QName XSD_INTEGER = new QName(URI_2001_SCHEMA_XSD, "integer");
+
+ public static final QName XSD_LONG = new QName(URI_2001_SCHEMA_XSD, "long");
+
+ public static final QName XSD_MONTH = new QName(URI_2001_SCHEMA_XSD, "gMonth");
+
+ public static final QName XSD_MONTHDAY = new QName(URI_2001_SCHEMA_XSD, "gMonthDay");
+
+ public static final QName XSD_NAME = new QName(URI_2001_SCHEMA_XSD, "Name");
+
+ public static final QName XSD_NCNAME = new QName(URI_2001_SCHEMA_XSD, "NCName");
+
+ public static final QName XSD_NEGATIVEINTEGER = new QName(URI_2001_SCHEMA_XSD, "negativeInteger");
+
+ public static final QName XSD_NMTOKEN = new QName(URI_2001_SCHEMA_XSD, "NMTOKEN");
+
+ public static final QName XSD_NMTOKENS = new QName(URI_2001_SCHEMA_XSD, "NMTOKENS");
+
+ public static final QName XSD_NONNEGATIVEINTEGER = new QName(URI_2001_SCHEMA_XSD, "nonNegativeInteger");
+
+ public static final QName XSD_NONPOSITIVEINTEGER = new QName(URI_2001_SCHEMA_XSD, "nonPositiveInteger");
+
+ public static final QName XSD_NORMALIZEDSTRING = new QName(URI_2001_SCHEMA_XSD, "normalizedString");
+
+ public static final QName XSD_NOTATION = new QName(URI_2001_SCHEMA_XSD, "NOTATION");
+
+ public static final QName XSD_POSITIVEINTEGER = new QName(URI_2001_SCHEMA_XSD, "positiveInteger");
+
+ public static final QName XSD_QNAME = new QName(URI_2001_SCHEMA_XSD, "QName");
+
+ public static final QName XSD_SHORT = new QName(URI_2001_SCHEMA_XSD, "short");
+
+ public static final Map<String, TypeInfo> XSD_SIMPLE_TYPES = new HashMap<String, TypeInfo>();
+
+ public static final QName XSD_STRING = new QName(URI_2001_SCHEMA_XSD, "string");
+
+ public static final QName XSD_TIME = new QName(URI_2001_SCHEMA_XSD, "time");
+
+ public static final QName XSD_TOKEN = new QName(URI_2001_SCHEMA_XSD, "token");
+
+ public static final QName XSD_UNSIGNEDBYTE = new QName(URI_2001_SCHEMA_XSD, "unsignedByte");
+
+ public static final QName XSD_UNSIGNEDINT = new QName(URI_2001_SCHEMA_XSD, "unsignedInt");
+
+ public static final QName XSD_UNSIGNEDLONG = new QName(URI_2001_SCHEMA_XSD, "unsignedLong");
+
+ public static final QName XSD_UNSIGNEDSHORT = new QName(URI_2001_SCHEMA_XSD, "unsignedShort");
+
+ public static final QName XSD_YEAR = new QName(URI_2001_SCHEMA_XSD, "gYear");
+
+ public static final QName XSD_YEARMONTH = new QName(URI_2001_SCHEMA_XSD, "gYearMonth");
+
+ private static final String[] XSD_TYPE_NAMES =
+ {"string", "boolean", "double", "float", "int", "integer", "long", "short", "byte", "decimal", "base64Binary",
+ "hexBinary", "anySimpleType", "anyType", "any", "QName", "dateTime", "date", "time", "normalizedString",
+ "token", "unsignedLong", "unsignedInt", "unsignedShort", "unsignedByte", "positiveInteger", "negativeInteger",
+ "nonNegativeInteger", "nonPositiveInteger", "gYearMonth", "gMonthDay", "gYear", "gMonth", "gDay", "duration",
+ "Name", "NCName", "NMTOKEN", "NMTOKENS", "NOTATION", "ENTITY", "ENTITIES", "IDREF", "IDREFS", "anyURI",
+ "language", "ID"};
+
+ static {
+ for (String type : XSD_TYPE_NAMES) {
+ TypeInfo simpleType = new TypeInfo(new QName(URI_2001_SCHEMA_XSD, type), true, null);
+ XSD_SIMPLE_TYPES.put(type, simpleType);
+ }
+ }
+
+ static {
+ JAVA2XML.put(boolean.class, "boolean");
+ JAVA2XML.put(byte.class, "byte");
+ JAVA2XML.put(short.class, "short");
+ JAVA2XML.put(int.class, "int");
+ JAVA2XML.put(long.class, "long");
+ JAVA2XML.put(float.class, "float");
+ JAVA2XML.put(double.class, "double");
+ JAVA2XML.put(Boolean.class, "boolean");
+ JAVA2XML.put(Byte.class, "byte");
+ JAVA2XML.put(Short.class, "short");
+ JAVA2XML.put(Integer.class, "int");
+ JAVA2XML.put(Long.class, "long");
+ JAVA2XML.put(Float.class, "float");
+ JAVA2XML.put(Double.class, "double");
+ JAVA2XML.put(java.lang.String.class, "string");
+ JAVA2XML.put(java.math.BigInteger.class, "integer");
+ JAVA2XML.put(java.math.BigDecimal.class, "decimal");
+ JAVA2XML.put(java.util.Calendar.class, "dateTime");
+ JAVA2XML.put(java.util.Date.class, "dateTime");
+ JAVA2XML.put(javax.xml.namespace.QName.class, "QName");
+ JAVA2XML.put(java.net.URI.class, "string");
+ JAVA2XML.put(javax.xml.datatype.XMLGregorianCalendar.class, "anySimpleType");
+ JAVA2XML.put(javax.xml.datatype.Duration.class, "duration");
+ JAVA2XML.put(java.lang.Object.class, "anyType");
+ JAVA2XML.put(java.awt.Image.class, "base64Binary");
+ JAVA2XML.put(byte[].class, "base64Binary");
+ // java2XSD.put(javax.activation.DataHandler.class, "base64Binary");
+ JAVA2XML.put(javax.xml.transform.Source.class, "base64Binary");
+ JAVA2XML.put(java.util.UUID.class, "string");
+ }
+
+ static {
+ XML2JAVA.put("string", java.lang.String.class);
+ XML2JAVA.put("integer", java.math.BigInteger.class);
+ XML2JAVA.put("int", int.class);
+ XML2JAVA.put("long", long.class);
+ XML2JAVA.put("short", short.class);
+ XML2JAVA.put("decimal", java.math.BigDecimal.class);
+ XML2JAVA.put("float", float.class);
+ XML2JAVA.put("double", double.class);
+ XML2JAVA.put("boolean", boolean.class);
+ XML2JAVA.put("byte", byte.class);
+ XML2JAVA.put("QName", javax.xml.namespace.QName.class);
+ XML2JAVA.put("dateTime", javax.xml.datatype.XMLGregorianCalendar.class);
+ XML2JAVA.put("base64Binary", byte[].class);
+ XML2JAVA.put("hexBinary", byte[].class);
+ XML2JAVA.put("unsignedInt", long.class);
+ XML2JAVA.put("unsignedShort", int.class);
+ XML2JAVA.put("unsignedByte", short.class);
+ XML2JAVA.put("time", javax.xml.datatype.XMLGregorianCalendar.class);
+ XML2JAVA.put("date", javax.xml.datatype.XMLGregorianCalendar.class);
+ XML2JAVA.put("gDay", javax.xml.datatype.XMLGregorianCalendar.class);
+ XML2JAVA.put("gMonth", javax.xml.datatype.XMLGregorianCalendar.class);
+ XML2JAVA.put("gYear", javax.xml.datatype.XMLGregorianCalendar.class);
+ XML2JAVA.put("gYearMonth", javax.xml.datatype.XMLGregorianCalendar.class);
+ XML2JAVA.put("gMonthDay", javax.xml.datatype.XMLGregorianCalendar.class);
+ XML2JAVA.put("anySimpleType", java.lang.Object.class); // For elements
+ // XML2JAVA.put("anySimpleType", java.lang.String.class); // For
+ // attributes
+ XML2JAVA.put("duration", javax.xml.datatype.Duration.class);
+ XML2JAVA.put("NOTATION", javax.xml.namespace.QName.class);
+ }
+
+ private DatatypeFactory factory;
+
+ public SimpleTypeMapperImpl() {
+ super();
+ try {
+ this.factory = DatatypeFactory.newInstance();
+ } catch (DatatypeConfigurationException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public Class<?> getJavaType(QName xmlType) {
+ if (xmlType != null && URI_2001_SCHEMA_XSD.equals(xmlType.getNamespaceURI())) {
+ return XML2JAVA.get(xmlType.getLocalPart());
+ } else {
+ return null;
+ }
+ }
+
+ public TypeInfo getXMLType(Class javaType) {
+ return XSD_SIMPLE_TYPES.get(JAVA2XML.get(javaType));
+ }
+
+ public Object toJavaObject(QName simpleType, String literal, TransformationContext context) {
+ /**
+ * <ul>
+ * <li>xsd:string --- java.lang.String
+ * <li>xsd:integer --- java.math.BigInteger
+ * <li>xsd:int --- int
+ * <li>xsd:long --- long
+ * <li>xsd:short --- short
+ * <li>xsd:decimal --- java.math.BigDecimal
+ * <li>xsd:float --- float
+ * <li>xsd:double --- double
+ * <li>xsd:boolean --- boolean
+ * <li>xsd:byte --- byte
+ * <li>xsd:QName --- javax.xml.namespace.QName
+ * <li>xsd:dateTime --- javax.xml.datatype.XMLGregorianCalendar
+ * <li>xsd:base64Binary --- byte[]
+ * <li>xsd:hexBinary --- byte[]
+ * <li>xsd:unsignedInt --- long
+ * <li>xsd:unsignedShort --- int
+ * <li>xsd:unsignedByte --- short
+ * <li>xsd:time --- javax.xml.datatype.XMLGregorianCalendar
+ * <li>xsd:date --- javax.xml.datatype.XMLGregorianCalendar
+ * <li>xsd:g* --- javax.xml.datatype.XMLGregorianCalendar
+ * <li>xsd:anySimpleType (for xsd:element of this type)a
+ * java.lang.Object
+ * <li>xsd:anySimpleType (for xsd:attribute of this type)
+ * java.lang.String
+ * <li>xsd:duration javax.xml.datatype.Duration
+ * <li>xsd:NOTATION javax.xml.namespace.QName
+ * </ul>
+ */
+
+ if (literal == null) {
+ return null;
+ }
+ String value = literal.trim();
+
+ QName type = simpleType;
+ if (type.equals(XSD_STRING)) {
+ return parseString(value);
+ } else if (type.equals(XSD_INT)) {
+ return parseInt(value);
+ } else if (type.equals(XSD_INTEGER)) {
+ return parseInteger(value);
+ } else if (type.equals(XSD_INT)) {
+ return parseInt(value);
+ } else if (type.equals(XSD_FLOAT)) {
+ return parseFloat(value);
+ } else if (type.equals(XSD_DOUBLE)) {
+ return parseDouble(value);
+ } else if (type.equals(XSD_SHORT)) {
+ return parseShort(value);
+ } else if (type.equals(XSD_DECIMAL)) {
+ return parseDecimal(value);
+ } else if (type.equals(XSD_BOOLEAN)) {
+ return parseBoolean(value);
+ } else if (type.equals(XSD_BYTE)) {
+ return parseByte(value);
+ } else if (type.equals(XSD_LONG)) {
+ return parseLong(value);
+ } else if (type.equals(XSD_UNSIGNEDBYTE)) {
+ return parseUnsignedShort(value);
+ } else if (type.equals(XSD_UNSIGNEDSHORT)) {
+ return parseUnsignedShort(value);
+ } else if (type.equals(XSD_UNSIGNEDINT)) {
+ return parseUnsignedInt(value);
+ } else if (type.equals(XSD_UNSIGNEDLONG)) {
+ return parseUnsignedInt(value);
+ } else if (type.equals(XSD_DATETIME)) {
+ return parseDateTime(value);
+ } else if (type.equals(XSD_DATE)) {
+ return parseDate(value);
+ } else if (type.equals(XSD_TIME)) {
+ return parseTime(value);
+ } else if (type.equals(XSD_DURATION)) {
+ return parseDuration(value);
+ } else if (type.equals(XSD_HEXBIN)) {
+ return parseHexBinary(value);
+ } else if (type.equals(XSD_BASE64)) {
+ return parseBase64Binary(value);
+ } else if (type.equals(XSD_QNAME)) {
+ NamespaceContext namespaceContext =
+ (NamespaceContext)((context != null) ? context.getMetadata().get(NamespaceContext.class.getName()) : null);
+ return parseQName(value, namespaceContext);
+ } else if (type.equals(XSD_NOTATION)) {
+ NamespaceContext namespaceContext =
+ (NamespaceContext)((context != null) ? context.getMetadata().get(NamespaceContext.class.getName()) : null);
+ return parseQName(value, namespaceContext);
+ } else if (type.equals(XSD_YEAR)) {
+ return factory.newXMLGregorianCalendar(value);
+ } else if (type.equals(XSD_MONTH)) {
+ return factory.newXMLGregorianCalendar(value);
+ } else if (type.equals(XSD_DAY)) {
+ return factory.newXMLGregorianCalendar(value);
+ } else if (type.equals(XSD_YEARMONTH)) {
+ return factory.newXMLGregorianCalendar(value);
+ } else if (type.equals(XSD_MONTHDAY)) {
+ return factory.newXMLGregorianCalendar(value);
+ } else {
+ return value;
+ }
+ }
+
+ @SuppressWarnings("deprecation")
+ private XMLGregorianCalendar toXMLGregorianCalendar(Date date) {
+ GregorianCalendar c =
+ new GregorianCalendar(date.getYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(),
+ date.getSeconds());
+ return factory.newXMLGregorianCalendar(c);
+ }
+
+ private XMLGregorianCalendar toXMLGregorianCalendar(GregorianCalendar calendar) {
+ return factory.newXMLGregorianCalendar(calendar);
+ }
+
+ public String toXMLLiteral(QName simpleType, Object obj, TransformationContext context) {
+ if(obj == null) {
+ // It could be null if nilable=true
+ return null;
+ }
+ if (obj instanceof Float || obj instanceof Double) {
+ if (obj instanceof Float) {
+ return printDouble(((Float)obj).floatValue());
+ } else {
+ return printDouble(((Double)obj).doubleValue());
+ }
+ } else if (obj instanceof GregorianCalendar) {
+ GregorianCalendar calendar = (GregorianCalendar)obj;
+ return toXMLGregorianCalendar(calendar).toXMLFormat();
+ } else if (obj instanceof Date) {
+ return toXMLGregorianCalendar((Date)obj).toXMLFormat();
+ } else if (obj instanceof XMLGregorianCalendar) {
+ return ((XMLGregorianCalendar)obj).toXMLFormat();
+ } else if (obj instanceof byte[]) {
+ if (simpleType != null) {
+ if (simpleType.equals(XSD_BASE64)) {
+ return printBase64Binary((byte[])obj);
+ } else if (simpleType.equals(XSD_HEXBIN)) {
+ return printHexBinary((byte[])obj);
+ }
+ }
+ } else if (obj instanceof QName) {
+ NamespaceContext namespaceContext =
+ (NamespaceContext)((context != null) ? context.getMetadata().get(NamespaceContext.class.getName()) : null);
+ return printQName((QName)obj, namespaceContext);
+ }
+ return obj.toString();
+ }
+
+ public boolean isSimpleXSDType(QName typeName) {
+ if (typeName == null) {
+ return false;
+ }
+ return typeName.getNamespaceURI().equals(URI_2001_SCHEMA_XSD)
+ && XSD_SIMPLE_TYPES.get(typeName.getLocalPart()) != null;
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/TransformationContextImpl.java b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/TransformationContextImpl.java
new file mode 100644
index 0000000000..e8b1ac3c01
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/TransformationContextImpl.java
@@ -0,0 +1,101 @@
+/*
+ * 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.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.tuscany.sca.databinding.Mediator.SOURCE_OPERATION;
+import static org.apache.tuscany.sca.databinding.Mediator.TARGET_OPERATION;
+import org.apache.tuscany.sca.databinding.TransformationContext;
+import org.apache.tuscany.sca.interfacedef.DataType;
+import org.apache.tuscany.sca.interfacedef.Operation;
+
+public class TransformationContextImpl implements TransformationContext {
+
+ private DataType sourceDataType;
+
+ private DataType targetDataType;
+
+ private final Map<String, Object> metadata = new HashMap<String, Object>();
+
+ public TransformationContextImpl() {
+ super();
+ }
+
+ public TransformationContextImpl(DataType sourceDataType,
+ DataType targetDataType,
+ Map<String, Object> metadata) {
+ super();
+ this.sourceDataType = sourceDataType;
+ this.targetDataType = targetDataType;
+ if (metadata != null) {
+ this.metadata.putAll(metadata);
+ }
+ }
+
+ public DataType getSourceDataType() {
+ return sourceDataType;
+ }
+
+ public DataType getTargetDataType() {
+ return targetDataType;
+ }
+
+ public void setSourceDataType(DataType sourceDataType) {
+ this.sourceDataType = sourceDataType;
+ }
+
+ public void setTargetDataType(DataType targetDataType) {
+ this.targetDataType = targetDataType;
+ }
+
+ public Map<String, Object> getMetadata() {
+ return metadata;
+ }
+
+ /**
+ * @return the sourceOperation
+ */
+ public Operation getSourceOperation() {
+ return (Operation) metadata.get(SOURCE_OPERATION);
+ }
+
+ /**
+ * @param sourceOperation the sourceOperation to set
+ */
+ public void setSourceOperation(Operation sourceOperation) {
+ this.metadata.put(SOURCE_OPERATION, sourceOperation);
+ }
+
+ /**
+ * @return the targetOperation
+ */
+ public Operation getTargetOperation() {
+ return (Operation) metadata.get(TARGET_OPERATION);
+ }
+
+ /**
+ * @param targetOperation the targetOperation to set
+ */
+ public void setTargetOperation(Operation targetOperation) {
+ this.metadata.put(TARGET_OPERATION, targetOperation);
+ }
+
+}
diff --git a/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/XSDDataTypeConverter.java b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/XSDDataTypeConverter.java
new file mode 100644
index 0000000000..aeb63ce02f
--- /dev/null
+++ b/sca-java-2.x/tags/2.0.1-RC1/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/XSDDataTypeConverter.java
@@ -0,0 +1,970 @@
+/*
+ * 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.impl;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+import java.util.Calendar;
+import java.util.TimeZone;
+import java.util.logging.Logger;
+
+import javax.xml.XMLConstants;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.Duration;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+
+/**
+ * Utility class for XSD data type conversions
+ *
+ * @version $Rev$ $Date$
+ * @tuscany.spi.extension.asclient
+ */
+public class XSDDataTypeConverter {
+ private static final Logger logger = Logger.getLogger(XSDDataTypeConverter.class.getName(),
+ "org.apache.tuscany.sca.databinding.databinding-validation-messages");
+ /**
+ *
+ * @tuscany.spi.extension.asclient
+ *
+ */
+ public static final class Base64Binary {
+ private static final char[] S_BASE64CHAR =
+ {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
+ 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
+ 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
+ '5', '6', '7', '8', '9', '+', '/'};
+
+ private static final char S_BASE64PAD = '=';
+
+ private static final byte[] S_DECODETABLE = new byte[128];
+
+ static {
+ for (int i = 0; i < S_DECODETABLE.length; i++) {
+ S_DECODETABLE[i] = Byte.MAX_VALUE; // 127
+ }
+ for (int i = 0; i < S_BASE64CHAR.length; i++) {
+ // 0 to 63
+ S_DECODETABLE[S_BASE64CHAR[i]] = (byte) i;
+ }
+ }
+
+ private Base64Binary() {
+ }
+
+ /**
+ *
+ */
+ public static byte[] decode(char[] data, int off, int len) {
+ char[] ibuf = new char[4];
+ int ibufcount = 0;
+ byte[] obuf = new byte[len / 4 * 3 + 3];
+ int obufcount = 0;
+ for (int i = off; i < off + len; i++) {
+ char ch = data[i];
+ if (ch == S_BASE64PAD || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
+ ibuf[ibufcount++] = ch;
+ if (ibufcount == ibuf.length) {
+ ibufcount = 0;
+ obufcount += decode0(ibuf, obuf, obufcount);
+ }
+ }
+ }
+ if (obufcount == obuf.length) {
+ return obuf;
+ }
+ byte[] ret = new byte[obufcount];
+ System.arraycopy(obuf, 0, ret, 0, obufcount);
+ return ret;
+ }
+
+ /**
+ *
+ */
+ public static void decode(char[] data, int off, int len, OutputStream ostream) throws IOException {
+ char[] ibuf = new char[4];
+ int ibufcount = 0;
+ byte[] obuf = new byte[3];
+ for (int i = off; i < off + len; i++) {
+ char ch = data[i];
+ if (ch == S_BASE64PAD || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
+ ibuf[ibufcount++] = ch;
+ if (ibufcount == ibuf.length) {
+ ibufcount = 0;
+ int obufcount = decode0(ibuf, obuf, 0);
+ ostream.write(obuf, 0, obufcount);
+ }
+ }
+ }
+ }
+
+ /**
+ *
+ */
+ public static byte[] decode(String data) {
+ char[] ibuf = new char[4];
+ int ibufcount = 0;
+ byte[] obuf = new byte[data.length() / 4 * 3 + 3];
+ int obufcount = 0;
+ for (int i = 0; i < data.length(); i++) {
+ char ch = data.charAt(i);
+ if (ch == S_BASE64PAD || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
+ ibuf[ibufcount++] = ch;
+ if (ibufcount == ibuf.length) {
+ ibufcount = 0;
+ obufcount += decode0(ibuf, obuf, obufcount);
+ }
+ }
+ }
+ if (obufcount == obuf.length) {
+ return obuf;
+ }
+ byte[] ret = new byte[obufcount];
+ System.arraycopy(obuf, 0, ret, 0, obufcount);
+ return ret;
+ }
+
+ /**
+ *
+ */
+ public static void decode(String data, OutputStream ostream) throws IOException {
+ char[] ibuf = new char[4];
+ int ibufcount = 0;
+ byte[] obuf = new byte[3];
+ for (int i = 0; i < data.length(); i++) {
+ char ch = data.charAt(i);
+ if (ch == S_BASE64PAD || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
+ ibuf[ibufcount++] = ch;
+ if (ibufcount == ibuf.length) {
+ ibufcount = 0;
+ int obufcount = decode0(ibuf, obuf, 0);
+ ostream.write(obuf, 0, obufcount);
+ }
+ }
+ }
+ }
+
+ private static int decode0(char[] ibuf, byte[] obuf, int index) {
+ int wp = index;
+ int outlen = 3;
+ if (ibuf[3] == S_BASE64PAD) {
+ outlen = 2;
+ }
+ if (ibuf[2] == S_BASE64PAD) {
+ outlen = 1;
+ }
+ int b0 = S_DECODETABLE[ibuf[0]];
+ int b1 = S_DECODETABLE[ibuf[1]];
+ int b2 = S_DECODETABLE[ibuf[2]];
+ int b3 = S_DECODETABLE[ibuf[3]];
+ switch (outlen) {
+ case 1:
+ obuf[wp] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
+ return 1;
+ case 2:
+ obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
+ obuf[wp] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
+ return 2;
+ case 3:
+ obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
+ obuf[wp++] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
+ obuf[wp] = (byte) (b2 << 6 & 0xc0 | b3 & 0x3f);
+ return 3;
+ default:
+ throw new IllegalArgumentException(logger.getResourceBundle().getString("NotBase64Encoded"));
+ }
+ }
+
+ /**
+ * Returns base64 representation of specified byte array.
+ */
+ public static String encode(byte[] data) {
+ return encode(data, 0, data.length);
+ }
+
+ /**
+ * Returns base64 representation of specified byte array.
+ */
+ public static String encode(byte[] data, int off, int len) {
+ if (len <= 0) {
+ return "";
+ }
+ char[] out = new char[len / 3 * 4 + 4];
+ int rindex = off;
+ int windex = 0;
+ int rest = len - off;
+ while (rest >= 3) {
+ int i =
+ ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8)
+ + (data[rindex + 2] & 0xff);
+ out[windex++] = S_BASE64CHAR[i >> 18];
+ out[windex++] = S_BASE64CHAR[(i >> 12) & 0x3f];
+ out[windex++] = S_BASE64CHAR[(i >> 6) & 0x3f];
+ out[windex++] = S_BASE64CHAR[i & 0x3f];
+ rindex += 3;
+ rest -= 3;
+ }
+ if (rest == 1) {
+ int i = data[rindex] & 0xff;
+ out[windex++] = S_BASE64CHAR[i >> 2];
+ out[windex++] = S_BASE64CHAR[(i << 4) & 0x3f];
+ out[windex++] = S_BASE64PAD;
+ out[windex++] = S_BASE64PAD;
+ } else if (rest == 2) {
+ int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
+ out[windex++] = S_BASE64CHAR[i >> 10];
+ out[windex++] = S_BASE64CHAR[(i >> 4) & 0x3f];
+ out[windex++] = S_BASE64CHAR[(i << 2) & 0x3f];
+ out[windex++] = S_BASE64PAD;
+ }
+ return new String(out, 0, windex);
+ }
+
+ /**
+ * Outputs base64 representation of the specified byte array to a byte stream.
+ */
+ public static void encode(byte[] data, int off, int len, OutputStream ostream) throws IOException {
+ if (len <= 0) {
+ return;
+ }
+ byte[] out = new byte[4];
+ int rindex = off;
+ int rest = len - off;
+ while (rest >= 3) {
+ int i =
+ ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8)
+ + (data[rindex + 2] & 0xff);
+ out[0] = (byte) S_BASE64CHAR[i >> 18];
+ out[1] = (byte) S_BASE64CHAR[(i >> 12) & 0x3f];
+ out[2] = (byte) S_BASE64CHAR[(i >> 6) & 0x3f];
+ out[3] = (byte) S_BASE64CHAR[i & 0x3f];
+ ostream.write(out, 0, 4);
+ rindex += 3;
+ rest -= 3;
+ }
+ if (rest == 1) {
+ int i = data[rindex] & 0xff;
+ out[0] = (byte) S_BASE64CHAR[i >> 2];
+ out[1] = (byte) S_BASE64CHAR[(i << 4) & 0x3f];
+ out[2] = (byte) S_BASE64PAD;
+ out[3] = (byte) S_BASE64PAD;
+ ostream.write(out, 0, 4);
+ } else if (rest == 2) {
+ int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
+ out[0] = (byte) S_BASE64CHAR[i >> 10];
+ out[1] = (byte) S_BASE64CHAR[(i >> 4) & 0x3f];
+ out[2] = (byte) S_BASE64CHAR[(i << 2) & 0x3f];
+ out[3] = (byte) S_BASE64PAD;
+ ostream.write(out, 0, 4);
+ }
+ }
+
+ /**
+ * Outputs base64 representation of the specified byte array to a character stream.
+ */
+ public static void encode(byte[] data, int off, int len, Writer writer) throws IOException {
+ if (len <= 0) {
+ return;
+ }
+ char[] out = new char[4];
+ int rindex = off;
+ int rest = len - off;
+ int output = 0;
+ while (rest >= 3) {
+ int i =
+ ((data[rindex] & 0xff) << 16) + ((data[rindex + 1] & 0xff) << 8)
+ + (data[rindex + 2] & 0xff);
+ out[0] = S_BASE64CHAR[i >> 18];
+ out[1] = S_BASE64CHAR[(i >> 12) & 0x3f];
+ out[2] = S_BASE64CHAR[(i >> 6) & 0x3f];
+ out[3] = S_BASE64CHAR[i & 0x3f];
+ writer.write(out, 0, 4);
+ rindex += 3;
+ rest -= 3;
+ output += 4;
+ if (output % 76 == 0) {
+ writer.write("\n");
+ }
+ }
+ if (rest == 1) {
+ int i = data[rindex] & 0xff;
+ out[0] = S_BASE64CHAR[i >> 2];
+ out[1] = S_BASE64CHAR[(i << 4) & 0x3f];
+ out[2] = S_BASE64PAD;
+ out[3] = S_BASE64PAD;
+ writer.write(out, 0, 4);
+ } else if (rest == 2) {
+ int i = ((data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
+ out[0] = S_BASE64CHAR[i >> 10];
+ out[1] = S_BASE64CHAR[(i >> 4) & 0x3f];
+ out[2] = S_BASE64CHAR[(i << 2) & 0x3f];
+ out[3] = S_BASE64PAD;
+ writer.write(out, 0, 4);
+ }
+ }
+ }
+
+ /**
+ * <p/>
+ * Utility class for xs:hexbinary. </p>
+ */
+ public static final class HexBinary {
+ private HexBinary() {
+ }
+
+ /**
+ * Converts the string <code>pValue</code> into an array of hex bytes.
+ */
+ public static byte[] decode(String pValue) {
+ if ((pValue.length() % 2) != 0) {
+ throw new IllegalArgumentException(logger.getResourceBundle().getString("HexBinaryUnevenLength"));
+ }
+ byte[] result = new byte[pValue.length() / 2];
+ int j = 0;
+ int i = 0;
+ while (i < pValue.length()) {
+ byte b;
+ char c = pValue.charAt(i++);
+ char d = pValue.charAt(i++);
+ if (c >= '0' && c <= '9') {
+ b = (byte) ((c - '0') << 4);
+ } else if (c >= 'A' && c <= 'F') {
+ b = (byte) ((c - 'A' + 10) << 4);
+ } else if (c >= 'a' && c <= 'f') {
+ b = (byte) ((c - 'a' + 10) << 4);
+ } else {
+ throw new IllegalArgumentException(logger.getResourceBundle().getString("InvalidHexDigit") + " " + c);
+ }
+ if (d >= '0' && d <= '9') {
+ b += (byte) (d - '0');
+ } else if (d >= 'A' && d <= 'F') {
+ b += (byte) (d - 'A' + 10);
+ } else if (d >= 'a' && d <= 'f') {
+ b += (byte) (d - 'a' + 10);
+ } else {
+ throw new IllegalArgumentException(logger.getResourceBundle().getString("InvalidHexDigit") + " " + d);
+ }
+ result[j++] = b;
+ }
+ return result;
+ }
+
+ /**
+ * Converts the byte array <code>pHexBinary</code> into a string.
+ */
+ public static String encode(byte[] pHexBinary) {
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < pHexBinary.length; i++) {
+ byte b = pHexBinary[i];
+ byte c = (byte) ((b & 0xf0) >> 4);
+ if (c <= 9) {
+ result.append((char) ('0' + c));
+ } else {
+ result.append((char) ('A' + c - 10));
+ }
+ c = (byte) (b & 0x0f);
+ if (c <= 9) {
+ result.append((char) ('0' + c));
+ } else {
+ result.append((char) ('A' + c - 10));
+ }
+ }
+ return result.toString();
+ }
+
+ /**
+ * Creates a clone of the given byte array.
+ */
+ public static byte[] getClone(byte[] pHexBinary) {
+ byte[] result = new byte[pHexBinary.length];
+ System.arraycopy(pHexBinary, 0, result, 0, pHexBinary.length);
+ return result;
+ }
+ }
+
+ public class XSDDateFormat extends XSDDateTimeFormat {
+ private static final long serialVersionUID = -1629412916827246627L;
+
+ /**
+ * Creates a new instance.
+ */
+ public XSDDateFormat() {
+ super(true, false);
+ }
+ }
+
+ /**
+ * <p/>
+ * An instance of {@link java.text.Format}, which may be used to parse and format <code>xs:dateTime</code> values.
+ * </p>
+ */
+ public static class XSDDateTimeFormat extends Format {
+ private static final long serialVersionUID = -1148332471737068969L;
+
+ final boolean parseDate;
+
+ final boolean parseTime;
+
+ /**
+ * Creates a new instance.
+ */
+ public XSDDateTimeFormat() {
+ this(true, true);
+ }
+
+ XSDDateTimeFormat(boolean pParseDate, boolean pParseTime) {
+ parseDate = pParseDate;
+ parseTime = pParseTime;
+ }
+
+ private void append(StringBuffer pBuffer, int pNum, int pMinLen) {
+ String s = Integer.toString(pNum);
+ for (int i = s.length(); i < pMinLen; i++) {
+ pBuffer.append('0');
+ }
+ pBuffer.append(s);
+ }
+
+ @Override
+ public StringBuffer format(Object pCalendar, StringBuffer pBuffer, FieldPosition pPos) {
+ assert pCalendar != null : "The Calendar argument must not be null.";
+ assert pBuffer != null : "The StringBuffer argument must not be null.";
+ assert pPos != null : "The FieldPosition argument must not be null.";
+
+ Calendar cal = (Calendar) pCalendar;
+ if (parseDate) {
+ int year = cal.get(Calendar.YEAR);
+ if (year < 0) {
+ pBuffer.append('-');
+ year = -year;
+ }
+ append(pBuffer, year, 4);
+ pBuffer.append('-');
+ append(pBuffer, cal.get(Calendar.MONTH) + 1, 2);
+ pBuffer.append('-');
+ append(pBuffer, cal.get(Calendar.DAY_OF_MONTH), 2);
+ if (parseTime) {
+ pBuffer.append('T');
+ }
+ }
+ if (parseTime) {
+ append(pBuffer, cal.get(Calendar.HOUR_OF_DAY), 2);
+ pBuffer.append(':');
+ append(pBuffer, cal.get(Calendar.MINUTE), 2);
+ pBuffer.append(':');
+ append(pBuffer, cal.get(Calendar.SECOND), 2);
+ int millis = cal.get(Calendar.MILLISECOND);
+ if (millis > 0) {
+ pBuffer.append('.');
+ append(pBuffer, millis, 3);
+ }
+ }
+ TimeZone tz = cal.getTimeZone();
+ // JDK 1.4: int offset = tz.getOffset(cal.getTimeInMillis());
+ int offset = cal.get(Calendar.ZONE_OFFSET);
+ if (tz.inDaylightTime(cal.getTime())) {
+ offset += cal.get(Calendar.DST_OFFSET);
+ }
+ if (offset == 0) {
+ pBuffer.append('Z');
+ } else {
+ if (offset < 0) {
+ pBuffer.append('-');
+ offset = -offset;
+ } else {
+ pBuffer.append('+');
+ }
+ int minutes = offset / (60 * 1000);
+ int hours = minutes / 60;
+ minutes -= hours * 60;
+ append(pBuffer, hours, 2);
+ pBuffer.append(':');
+ append(pBuffer, minutes, 2);
+ }
+ return pBuffer;
+ }
+
+ private int parseInt(String pString, int offset, StringBuffer pDigits) {
+ int length = pString.length();
+ int pOffset = offset;
+ pDigits.setLength(0);
+ while (pOffset < length) {
+ char c = pString.charAt(pOffset);
+ if (Character.isDigit(c)) {
+ pDigits.append(c);
+ ++pOffset;
+ } else {
+ break;
+ }
+ }
+ return pOffset;
+ }
+
+ @Override
+ public Object parseObject(String pString, ParsePosition pParsePosition) {
+ assert pString != null : "The String argument must not be null.";
+ assert pParsePosition != null : "The ParsePosition argument must not be null.";
+ int offset = pParsePosition.getIndex();
+ int length = pString.length();
+
+ boolean isMinus = false;
+ StringBuffer digits = new StringBuffer();
+ int year = 0;
+ int month = 0;
+ int mday = 0;
+ if (parseDate) {
+ // Sign
+ if (offset < length) {
+ char c = pString.charAt(offset);
+ if (c == '+') {
+ ++offset;
+ } else if (c == '-') {
+ ++offset;
+ isMinus = true;
+ }
+ }
+
+ offset = parseInt(pString, offset, digits);
+ if (digits.length() < 4) {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+ year = Integer.parseInt(digits.toString());
+
+ if (offset < length && pString.charAt(offset) == '-') {
+ ++offset;
+ } else {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+
+ offset = parseInt(pString, offset, digits);
+ if (digits.length() != 2) {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+ month = Integer.parseInt(digits.toString());
+
+ if (offset < length && pString.charAt(offset) == '-') {
+ ++offset;
+ } else {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+
+ offset = parseInt(pString, offset, digits);
+ if (digits.length() != 2) {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+ mday = Integer.parseInt(digits.toString());
+
+ if (parseTime) {
+ if (offset < length && pString.charAt(offset) == 'T') {
+ ++offset;
+ } else {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+ }
+ } else {
+ year = month = mday = 0;
+ }
+
+ int hour = 0;
+ int minute = 0;
+ int second = 0;
+ int millis = 0;
+ if (parseTime) {
+ offset = parseInt(pString, offset, digits);
+ if (digits.length() != 2) {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+ hour = Integer.parseInt(digits.toString());
+
+ if (offset < length && pString.charAt(offset) == ':') {
+ ++offset;
+ } else {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+
+ offset = parseInt(pString, offset, digits);
+ if (digits.length() != 2) {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+ minute = Integer.parseInt(digits.toString());
+
+ if (offset < length && pString.charAt(offset) == ':') {
+ ++offset;
+ } else {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+
+ offset = parseInt(pString, offset, digits);
+ if (digits.length() != 2) {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+ second = Integer.parseInt(digits.toString());
+
+ if (offset < length && pString.charAt(offset) == '.') {
+ ++offset;
+ offset = parseInt(pString, offset, digits);
+ if (digits.length() > 0) {
+ millis = Integer.parseInt(digits.toString());
+ } else {
+ millis = 0;
+ }
+ } else {
+ millis = 0;
+ }
+ } else {
+ hour = minute = second = millis = 0;
+ }
+
+ digits.setLength(0);
+ digits.append("GMT");
+ if (offset < length) {
+ char c = pString.charAt(offset);
+ if (c == 'Z') {
+ // Ignore UTC, it is the default
+ ++offset;
+ } else if (c == '+' || c == '-') {
+ digits.append(c);
+ ++offset;
+ for (int i = 0; i < 5; i++) {
+ if (offset >= length) {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+ c = pString.charAt(offset);
+ if ((i != 2 && Character.isDigit(c)) || (i == 2 && c == ':')) {
+ digits.append(c);
+ } else {
+ pParsePosition.setErrorIndex(offset);
+ return null;
+ }
+ ++offset;
+ }
+ }
+ }
+
+ Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(digits.toString()));
+ cal.set(isMinus ? -year : year, parseDate ? month - 1 : month, mday, hour, minute, second);
+ cal.set(Calendar.MILLISECOND, millis);
+ pParsePosition.setIndex(offset);
+ return cal;
+ }
+ }
+
+ public static class XSDTimeFormat extends XSDDateTimeFormat {
+ private static final long serialVersionUID = 1346506860724640517L;
+
+ /**
+ * Creates a new instance.
+ */
+ public XSDTimeFormat() {
+ super(false, true);
+ }
+ }
+
+ private static final long MAX_UNSIGNED_INT = (((long) Integer.MAX_VALUE) * 2) + 1;
+
+ private static final int MAX_UNSIGNED_SHORT = Short.MAX_VALUE * 2 + 1;
+
+ public String parseAnySimpleType(String value) {
+ return value;
+ }
+
+ public byte[] parseBase64Binary(String value) {
+ return Base64Binary.decode(value);
+ }
+
+ public boolean parseBoolean(String value) {
+ return Boolean.valueOf(value).booleanValue();
+ }
+
+ public byte parseByte(String value) {
+ return Byte.parseByte(value);
+ }
+
+ public Calendar parseDate(String value) {
+ XSDDateFormat format = new XSDDateFormat();
+ ParsePosition pos = new ParsePosition(0);
+ Calendar cal = (Calendar) format.parseObject(value, pos);
+ if (cal == null) {
+ String message = logger.getResourceBundle().getString("BadDate");
+ message = message.replace("{0}", value);
+ message = message.replace("{1}", value.substring(pos.getErrorIndex()));
+ throw new IllegalArgumentException(message);
+ }
+ return cal;
+ }
+
+ public Calendar parseDateTime(String value) {
+ XSDDateTimeFormat format = new XSDDateTimeFormat();
+ ParsePosition pos = new ParsePosition(0);
+ Calendar cal = (Calendar) format.parseObject(value, pos);
+ if (cal == null) {
+ String message = logger.getResourceBundle().getString("BadDateTime");
+ message = message.replace("{0}", value);
+ message = message.replace("{1}", value.substring(pos.getErrorIndex()));
+ throw new IllegalArgumentException(message);
+ }
+ return cal;
+ }
+
+ public BigDecimal parseDecimal(String value) {
+ return new BigDecimal(value);
+ }
+
+ public double parseDouble(String value) {
+ if ("INF".equals(value)) {
+ return Double.POSITIVE_INFINITY;
+ } else if ("-INF".equals(value)) {
+ return Double.NEGATIVE_INFINITY;
+ } else if ("NaN".equals(value)) {
+ return Double.NaN;
+ } else {
+ return Double.parseDouble(value);
+ }
+ }
+
+ public Duration parseDuration(String pDuration) {
+ try {
+ return DatatypeFactory.newInstance().newDuration(pDuration);
+ } catch (DatatypeConfigurationException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ public float parseFloat(String value) {
+ if ("INF".equals(value)) {
+ return Float.POSITIVE_INFINITY;
+ } else if ("-INF".equals(value)) {
+ return Float.NEGATIVE_INFINITY;
+ } else if ("NaN".equals(value)) {
+ return Float.NaN;
+ } else {
+ return Float.parseFloat(value);
+ }
+ }
+
+ public byte[] parseHexBinary(String value) {
+ return HexBinary.decode(value);
+ }
+
+ public int parseInt(String value) {
+ return Integer.parseInt(value);
+ }
+
+ public BigInteger parseInteger(String value) {
+ return new BigInteger(value);
+ }
+
+ public long parseLong(String value) {
+ return Long.parseLong(value);
+ }
+
+ public QName parseQName(String value, NamespaceContext context) {
+ int offset = value.indexOf(':');
+ String uri;
+ String localName;
+ switch (offset) {
+ case -1:
+ localName = value;
+ uri = context.getNamespaceURI("");
+ if (uri == null) {
+ // Should not happen, indicates an error in the
+ // NamespaceContext
+ // implementation
+ throw new IllegalArgumentException(logger.getResourceBundle().getString("DefaultPrefixNotBound"));
+ }
+ break;
+ case 0:
+ throw new IllegalArgumentException(logger.getResourceBundle().getString("NoColonForPrefix") +
+ " " +
+ value);
+ default:
+ String prefix = value.substring(0, offset);
+ localName = value.substring(offset + 1);
+ uri = context.getNamespaceURI(prefix);
+ if (uri == null) {
+ String message = logger.getResourceBundle().getString("PrefixNotBound");
+ message = message.replace("{0}", prefix);
+ throw new IllegalArgumentException(message);
+ }
+ }
+ return new QName(uri, localName);
+ }
+
+ public short parseShort(String value) {
+ return Short.parseShort(value);
+ }
+
+ public String parseString(String value) {
+ return value;
+ }
+
+ public Calendar parseTime(String value) {
+ XSDTimeFormat format = new XSDTimeFormat();
+ ParsePosition pos = new ParsePosition(0);
+ Calendar cal = (Calendar) format.parseObject(value, pos);
+ if (cal == null) {
+ String message = logger.getResourceBundle().getString("BadTime");
+ message = message.replace("{0}", value);
+ message = message.replace("{1}", value.substring(pos.getErrorIndex()));
+ throw new IllegalArgumentException(message);
+ }
+ return cal;
+ }
+
+ public long parseUnsignedInt(String value) {
+ long l = Long.parseLong(value);
+ if (l < 0) {
+ String message = logger.getResourceBundle().getString("BadUnsignedIntNegative");
+ message = message.replace("{0}", value);
+ throw new IllegalArgumentException(message);
+ }
+ if (l > MAX_UNSIGNED_INT) {
+ String message = logger.getResourceBundle().getString("BadUnsignedIntMax");
+ message = message.replace("{0}", value);
+ message = message.replace("{1}", String.valueOf(MAX_UNSIGNED_INT));
+ throw new IllegalArgumentException(message);
+ }
+ return l;
+ }
+
+ public int parseUnsignedShort(String value) {
+ int i = Integer.parseInt(value);
+ if (i < 0) {
+ String message = logger.getResourceBundle().getString("BadUnsignedShortNegative");
+ message = message.replace("{0}", value);
+ throw new IllegalArgumentException(message);
+ }
+ if (i > MAX_UNSIGNED_SHORT) {
+ String message = logger.getResourceBundle().getString("BadUnsignedShortMax");
+ message = message.replace("{0}", value);
+ message = message.replace("{1}", String.valueOf(MAX_UNSIGNED_SHORT));
+ throw new IllegalArgumentException(message);
+ }
+ return i;
+ }
+
+ public String printAnySimpleType(String value) {
+ return value;
+ }
+
+ public String printBase64Binary(byte[] value) {
+ return Base64Binary.encode(value);
+ }
+
+ public String printBoolean(boolean value) {
+ return (value ? Boolean.TRUE : Boolean.FALSE).toString();
+ }
+
+ public String printByte(byte value) {
+ return Byte.toString(value);
+ }
+
+ public String printDate(Calendar value) {
+ return new XSDDateFormat().format(value);
+ }
+
+ public String printDateTime(Calendar value) {
+ return new XSDDateTimeFormat().format(value);
+ }
+
+ public String printDecimal(BigDecimal value) {
+ return value.toString();
+ }
+
+ public String printDouble(double value) {
+ return Double.toString(value);
+ }
+
+ public String printDuration(Duration pDuration) {
+ return pDuration.toString();
+ }
+
+ public String printFloat(float value) {
+ return Float.toString(value);
+ }
+
+ public String printHexBinary(byte[] value) {
+ return HexBinary.encode(value);
+ }
+
+ public String printInt(int value) {
+ return Integer.toString(value);
+ }
+
+ public String printInteger(BigInteger value) {
+ return value.toString();
+ }
+
+ public String printLong(long value) {
+ return Long.toString(value);
+ }
+
+ public String printQName(QName value, NamespaceContext context) {
+ String prefix = context.getPrefix(value.getNamespaceURI());
+ if (prefix == null) {
+ String message = logger.getResourceBundle().getString("NamespaceNotBound");
+ message = message.replace("{0}", value.getNamespaceURI());
+ throw new IllegalArgumentException(message);
+ } else if (XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) {
+ return value.getLocalPart();
+ } else {
+ return prefix + ":" + value.getLocalPart();
+ }
+ }
+
+ public String printShort(short value) {
+ return Short.toString(value);
+ }
+
+ public String printString(String value) {
+ return value;
+ }
+
+ public String printTime(Calendar value) {
+ return new XSDTimeFormat().format(value);
+ }
+
+ public String printUnsignedInt(long value) {
+ return Long.toString(value);
+ }
+
+ public String printUnsignedShort(int value) {
+ return Integer.toString(value);
+ }
+}