001: /*--
002:
003: Copyright (C) 2002-2005 Adrian Price.
004: All rights reserved.
005:
006: Redistribution and use in source and binary forms, with or without
007: modification, are permitted provided that the following conditions
008: are met:
009:
010: 1. Redistributions of source code must retain the above copyright
011: notice, this list of conditions, and the following disclaimer.
012:
013: 2. Redistributions in binary form must reproduce the above copyright
014: notice, this list of conditions, and the disclaimer that follows
015: these conditions in the documentation and/or other materials
016: provided with the distribution.
017:
018: 3. The names "OBE" and "Open Business Engine" must not be used to
019: endorse or promote products derived from this software without prior
020: written permission. For written permission, please contact
021: adrianprice@sourceforge.net.
022:
023: 4. Products derived from this software may not be called "OBE" or
024: "Open Business Engine", nor may "OBE" or "Open Business Engine"
025: appear in their name, without prior written permission from
026: Adrian Price (adrianprice@users.sourceforge.net).
027:
028: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
029: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
030: OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
031: DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
032: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
033: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
034: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
035: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
036: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
037: IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
038: POSSIBILITY OF SUCH DAMAGE.
039:
040: For more information on OBE, please see
041: <http://obe.sourceforge.net/>.
042:
043: */
044:
045: package org.obe.xpdl.model.data;
046:
047: import org.jaxen.JaxenException;
048: import org.jaxen.SimpleVariableContext;
049: import org.jaxen.XPath;
050: import org.jaxen.dom.DOMXPath;
051: import org.obe.OBERuntimeException;
052: import org.obe.XMLException;
053: import org.obe.util.ClassUtils;
054: import org.obe.util.SchemaUtils;
055: import org.obe.util.W3CNames;
056: import org.obe.xpdl.XPDLNames;
057: import org.w3c.dom.Document;
058: import org.w3c.dom.Element;
059: import org.xml.sax.InputSource;
060: import org.xml.sax.SAXException;
061:
062: import javax.xml.namespace.QName;
063: import javax.xml.parsers.DocumentBuilderFactory;
064: import javax.xml.parsers.ParserConfigurationException;
065: import javax.xml.transform.Source;
066: import javax.xml.transform.TransformerException;
067: import javax.xml.transform.dom.DOMSource;
068: import javax.xml.transform.stream.StreamSource;
069: import java.io.IOException;
070: import java.io.InputStream;
071: import java.io.Reader;
072: import java.io.Serializable;
073:
074: /**
075: * Reference to an external entity as defined in XPDL 1.0b1.
076: *
077: * @author Adrian Price
078: */
079: public final class ExternalReference implements Type, Serializable {
080: private static final long serialVersionUID = -5052512021996360394L;
081: private static final String WSDL_SCHEMA_XPATH = "/wsdl:definitions/wsdl:types/xsd:schema[@targetNamespace=$namespace]";
082: private static final DocumentBuilderFactory _docBuilderFactory = DocumentBuilderFactory
083: .newInstance();
084:
085: private String _location;
086: private String _xref;
087: private String _namespace;
088: private transient QName _qname;
089: private transient Type _xpdlType;
090:
091: static {
092: _docBuilderFactory.setNamespaceAware(true);
093: _docBuilderFactory.setIgnoringComments(true);
094: _docBuilderFactory.setValidating(false);
095: }
096:
097: public ExternalReference() {
098: }
099:
100: /**
101: * Construct a new ExternalReference.
102: *
103: * @param location The location
104: */
105: public ExternalReference(String location) {
106: setLocation(location);
107: }
108:
109: /**
110: * Construct a new ExternalReference.
111: *
112: * @param location The location
113: * @param xref
114: * @param namespace
115: */
116: public ExternalReference(String location, String xref,
117: String namespace) {
118: _location = location;
119: _xref = xref;
120: _namespace = namespace;
121: }
122:
123: public int value() {
124: return EXTERNAL_REFERENCE_TYPE;
125: }
126:
127: /**
128: * Get the location URI.
129: *
130: * @return The location URI
131: */
132: public String getLocation() {
133: return _location;
134: }
135:
136: /**
137: * Set the location URI.
138: *
139: * @param location The new location URI
140: */
141: public void setLocation(String location) {
142: if (location == null)
143: throw new IllegalArgumentException(
144: "location cannot be null");
145: _location = location;
146: }
147:
148: /**
149: * Get the identity of the entity in the external reference. This value is
150: * optional and this method may return null.
151: *
152: * @return The entity identity
153: */
154: public String getXref() {
155: return _xref;
156: }
157:
158: /**
159: * Set the identity of the entity in the external reference. This value is
160: * optional and can be set to null.
161: *
162: * @param xref The entity identity
163: */
164: public void setXref(String xref) {
165: _xref = xref;
166: _qname = null;
167: }
168:
169: /**
170: * Get the namespace of the external reference. The value is optional and
171: * this method may return null.
172: *
173: * @return The namespace
174: */
175: public String getNamespace() {
176: return _namespace;
177: }
178:
179: /**
180: * Set the namespace of the external reference. This value is optional and
181: * can be set to null.
182: *
183: * @param namespace The namespace
184: */
185: public void setNamespace(String namespace) {
186: _namespace = namespace;
187: _qname = null;
188: }
189:
190: public QName getQName() {
191: if (_qname == null && _xref != null)
192: _qname = new QName(_namespace, _xref);
193: return _qname;
194: }
195:
196: public boolean equals(Object obj) {
197: if (this == obj)
198: return true;
199: if (!(obj instanceof ExternalReference))
200: return false;
201:
202: ExternalReference externalReference = (ExternalReference) obj;
203:
204: if (!_location.equals(externalReference._location))
205: return false;
206: if (_namespace != null ? !_namespace
207: .equals(externalReference._namespace)
208: : externalReference._namespace != null) {
209:
210: return false;
211: }
212: return !(_xref != null ? !_xref.equals(externalReference._xref)
213: : externalReference._xref != null);
214: }
215:
216: public int hashCode() {
217: int result;
218: result = _location.hashCode();
219: result = 29 * result + (_xref != null ? _xref.hashCode() : 0);
220: result = 29 * result
221: + (_namespace != null ? _namespace.hashCode() : 0);
222: return result;
223: }
224:
225: public Type getImpliedType() {
226: if (_xpdlType == null) {
227: try {
228: // TODO: eliminate case sensitivity.
229: if (_location.startsWith("java:")) {
230: resolveJavaReference();
231: } else if (_location.endsWith("?wsdl")
232: || _location.endsWith(".wsdl")) {
233:
234: resolveWSDLReference();
235: } else if (_location.endsWith(".xsd")) {
236: resolveSchemaReference();
237: } else {
238: _xpdlType = this ;
239: }
240: } catch (ClassNotFoundException e) {
241: throw new OBERuntimeException(e);
242: } catch (IOException e) {
243: throw new OBERuntimeException(e);
244: } catch (JaxenException e) {
245: throw new OBERuntimeException(e);
246: } catch (ParserConfigurationException e) {
247: throw new OBERuntimeException(e);
248: } catch (SAXException e) {
249: throw new OBERuntimeException(e);
250: } catch (TransformerException e) {
251: throw new OBERuntimeException(e);
252: } catch (XMLException e) {
253: throw new OBERuntimeException(e);
254: }
255: }
256: return _xpdlType;
257: }
258:
259: private void resolveJavaReference() throws ClassNotFoundException {
260: Class javaClass = ClassUtils.classForName(_location
261: .substring(5));
262: Type type = DataTypes.dataTypeForClass(javaClass).getType();
263: _xpdlType = type instanceof ExternalReference ? this : type;
264: }
265:
266: private void resolveSchemaReference() throws IOException,
267: XMLException, TransformerException {
268:
269: // Map the schema type to a Java class.
270: Source src = null;
271: Class javaType = null;
272: try {
273: QName typeName = getQName();
274: src = SchemaUtils.getURIResolver().resolve(_location, null);
275: if (src == null) {
276: throw new XMLException("Could not resolve reference '"
277: + _location + '\'');
278: }
279:
280: if (src instanceof DOMSource) {
281: DOMSource domSource = (DOMSource) src;
282: javaType = SchemaUtils.classForSchemaType(
283: (Element) domSource.getNode(), typeName);
284: } else if (src instanceof StreamSource) {
285: StreamSource ss = (StreamSource) src;
286: InputStream in = ss.getInputStream();
287: if (in != null) {
288: javaType = SchemaUtils.classForSchemaType(in,
289: typeName);
290: } else {
291: Reader rdr = ss.getReader();
292: if (rdr != null)
293: javaType = SchemaUtils.classForSchemaType(rdr,
294: typeName);
295: }
296: }
297: } finally {
298: SchemaUtils.close(src);
299: }
300:
301: // Map a non-XML Java class to an XPDL data type.
302: _xpdlType = DataTypes.dataTypeForClass(javaType).getType();
303: }
304:
305: private void resolveWSDLReference() throws SAXException,
306: IOException, ParserConfigurationException, JaxenException,
307: XMLException {
308:
309: // Retrieve the WSDL and parse it into a DOM document.
310: Document wsdlDoc;
311: InputSource in = null;
312: try {
313: in = SchemaUtils.getEntityResolver().resolveEntity(null,
314: _location);
315: wsdlDoc = _docBuilderFactory.newDocumentBuilder().parse(in);
316: } finally {
317: SchemaUtils.close(in);
318: }
319:
320: // Use XPath to select the appropriate schema element.
321: XPath xpath = new DOMXPath(WSDL_SCHEMA_XPATH);
322: xpath.addNamespace("wsdl", W3CNames.WSDL_NS_URI);
323: xpath.addNamespace("xsd", W3CNames.XSD_NS_URI);
324: SimpleVariableContext varCtx = new SimpleVariableContext();
325: varCtx.setVariableValue(XPDLNames.NAMESPACE, _namespace);
326: xpath.setVariableContext(varCtx);
327: Element elem = (Element) xpath.selectSingleNode(wsdlDoc);
328:
329: // Examine the schema to determine the Java class which matches the type
330: // referenced by this external reference.
331: if (elem == null) {
332: throw new XMLException(
333: "WSDL file '"
334: + _location
335: + "' does not provide a schema for the target namespace '"
336: + _namespace + '\'');
337: }
338:
339: // Map the XML Schema type to a Java class.
340: Class javaType = SchemaUtils.classForSchemaType(elem,
341: getQName());
342:
343: // Map a non-XML Java class to an XPDL data type.
344: _xpdlType = DataTypes.dataTypeForClass(javaType).getType();
345: }
346:
347: public boolean isAssignableFrom(Type fromType) {
348: return equals(fromType)
349: || DataTypes.classForType(getImpliedType())
350: .isAssignableFrom(
351: DataTypes.classForType(fromType));
352: }
353:
354: public String toString() {
355: // General form is: <location>[#[{<namespace>}]<xref>]
356: String s;
357: if (_namespace == null && _xref == null) {
358: s = _location;
359: } else {
360: StringBuffer sb = new StringBuffer(_location).append('#');
361: if (_namespace != null)
362: sb.append('{').append(_namespace).append('}');
363: if (_xref != null)
364: sb.append(_xref);
365: s = sb.toString();
366: }
367: return s;
368: }
369: }
|