diff options
Diffstat (limited to 'sca-java-2.x/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl')
10 files changed, 3057 insertions, 0 deletions
diff --git a/sca-java-2.x/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/DirectedGraph.java b/sca-java-2.x/branches/2.0/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/branches/2.0/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/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/Group2GroupTransformer.java b/sca-java-2.x/branches/2.0/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/branches/2.0/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/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/GroupDataBinding.java b/sca-java-2.x/branches/2.0/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/branches/2.0/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/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/Java2SimpleTypeTransformer.java b/sca-java-2.x/branches/2.0/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/branches/2.0/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/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/MediatorImpl.java b/sca-java-2.x/branches/2.0/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/branches/2.0/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/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/PipedTransformer.java b/sca-java-2.x/branches/2.0/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/branches/2.0/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/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/SimpleType2JavaTransformer.java b/sca-java-2.x/branches/2.0/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/branches/2.0/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/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/SimpleTypeMapperImpl.java b/sca-java-2.x/branches/2.0/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/branches/2.0/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/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/TransformationContextImpl.java b/sca-java-2.x/branches/2.0/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/branches/2.0/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/branches/2.0/modules/databinding/src/main/java/org/apache/tuscany/sca/databinding/impl/XSDDataTypeConverter.java b/sca-java-2.x/branches/2.0/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/branches/2.0/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); + } +} |