001: /*
002: * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
003: * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
004: */
005: package javax.xml.bind.helpers;
006:
007: import org.xml.sax.InputSource;
008: import org.xml.sax.SAXException;
009: import org.xml.sax.XMLReader;
010: import org.w3c.dom.Node;
011:
012: import javax.xml.bind.JAXBException;
013: import javax.xml.bind.PropertyException;
014: import javax.xml.bind.UnmarshalException;
015: import javax.xml.bind.Unmarshaller;
016: import javax.xml.bind.ValidationEventHandler;
017: import javax.xml.bind.JAXBElement;
018: import javax.xml.bind.annotation.adapters.XmlAdapter;
019: import javax.xml.bind.attachment.AttachmentUnmarshaller;
020: import javax.xml.parsers.ParserConfigurationException;
021: import javax.xml.parsers.SAXParserFactory;
022: import javax.xml.stream.XMLEventReader;
023: import javax.xml.stream.XMLStreamReader;
024: import javax.xml.transform.Source;
025: import javax.xml.transform.dom.DOMSource;
026: import javax.xml.transform.sax.SAXSource;
027: import javax.xml.transform.stream.StreamSource;
028: import javax.xml.validation.Schema;
029: import java.io.File;
030: import java.io.Reader;
031: import java.net.MalformedURLException;
032: import java.net.URL;
033:
034: /**
035: * Partial default <tt>Unmarshaller</tt> implementation.
036: *
037: * <p>
038: * This class provides a partial default implementation for the
039: * {@link javax.xml.bind.Unmarshaller}interface.
040: *
041: * <p>
042: * A JAXB Provider has to implement five methods (getUnmarshallerHandler,
043: * unmarshal(Node), unmarshal(XMLReader,InputSource),
044: * unmarshal(XMLStreamReader), and unmarshal(XMLEventReader).
045: *
046: * @author <ul>
047: * <li>Kohsuke Kawaguchi, Sun Microsystems, Inc.</li>
048: * </ul>
049: * @version $Revision: 1.14 $ $Date: 2006/03/08 17:01:00 $
050: * @see javax.xml.bind.Unmarshaller
051: * @since JAXB1.0
052: */
053: public abstract class AbstractUnmarshallerImpl implements Unmarshaller {
054: /** handler that will be used to process errors and warnings during unmarshal */
055: private ValidationEventHandler eventHandler = new DefaultValidationEventHandler();
056:
057: /** whether or not the unmarshaller will validate */
058: protected boolean validating = false;
059:
060: /**
061: * XMLReader that will be used to parse a document.
062: */
063: private XMLReader reader = null;
064:
065: /**
066: * Obtains a configured XMLReader.
067: *
068: * This method is used when the client-specified
069: * {@link SAXSource} object doesn't have XMLReader.
070: *
071: * {@link Unmarshaller} is not re-entrant, so we will
072: * only use one instance of XMLReader.
073: */
074: protected XMLReader getXMLReader() throws JAXBException {
075: if (reader == null) {
076: try {
077: SAXParserFactory parserFactory;
078: parserFactory = SAXParserFactory.newInstance();
079: parserFactory.setNamespaceAware(true);
080: // there is no point in asking a validation because
081: // there is no guarantee that the document will come with
082: // a proper schemaLocation.
083: parserFactory.setValidating(false);
084: reader = parserFactory.newSAXParser().getXMLReader();
085: } catch (ParserConfigurationException e) {
086: throw new JAXBException(e);
087: } catch (SAXException e) {
088: throw new JAXBException(e);
089: }
090: }
091: return reader;
092: }
093:
094: public Object unmarshal(Source source) throws JAXBException {
095: if (source == null) {
096: throw new IllegalArgumentException(Messages.format(
097: Messages.MUST_NOT_BE_NULL, "source"));
098: }
099:
100: if (source instanceof SAXSource)
101: return unmarshal((SAXSource) source);
102: if (source instanceof StreamSource)
103: return unmarshal(streamSourceToInputSource((StreamSource) source));
104: if (source instanceof DOMSource)
105: return unmarshal(((DOMSource) source).getNode());
106:
107: // we don't handle other types of Source
108: throw new IllegalArgumentException();
109: }
110:
111: // use the client specified XMLReader contained in the SAXSource.
112: private Object unmarshal(SAXSource source) throws JAXBException {
113:
114: XMLReader reader = source.getXMLReader();
115: if (reader == null)
116: reader = getXMLReader();
117:
118: return unmarshal(reader, source.getInputSource());
119: }
120:
121: /**
122: * Unmarshals an object by using the specified XMLReader and the InputSource.
123: *
124: * The callee should call the setErrorHandler method of the XMLReader
125: * so that errors are passed to the client-specified ValidationEventHandler.
126: */
127: protected abstract Object unmarshal(XMLReader reader,
128: InputSource source) throws JAXBException;
129:
130: public final Object unmarshal(InputSource source)
131: throws JAXBException {
132: if (source == null) {
133: throw new IllegalArgumentException(Messages.format(
134: Messages.MUST_NOT_BE_NULL, "source"));
135: }
136:
137: return unmarshal(getXMLReader(), source);
138: }
139:
140: private Object unmarshal(String url) throws JAXBException {
141: return unmarshal(new InputSource(url));
142: }
143:
144: public final Object unmarshal(URL url) throws JAXBException {
145: if (url == null) {
146: throw new IllegalArgumentException(Messages.format(
147: Messages.MUST_NOT_BE_NULL, "url"));
148: }
149:
150: return unmarshal(url.toExternalForm());
151: }
152:
153: public final Object unmarshal(File f) throws JAXBException {
154: if (f == null) {
155: throw new IllegalArgumentException(Messages.format(
156: Messages.MUST_NOT_BE_NULL, "file"));
157: }
158:
159: try {
160: // copied from JAXP
161: String path = f.getAbsolutePath();
162: if (File.separatorChar != '/')
163: path = path.replace(File.separatorChar, '/');
164: if (!path.startsWith("/"))
165: path = "/" + path;
166: if (!path.endsWith("/") && f.isDirectory())
167: path = path + "/";
168: return unmarshal(new URL("file", "", path));
169: } catch (MalformedURLException e) {
170: throw new IllegalArgumentException(e.getMessage());
171: }
172: }
173:
174: public final Object unmarshal(java.io.InputStream is)
175: throws JAXBException {
176:
177: if (is == null) {
178: throw new IllegalArgumentException(Messages.format(
179: Messages.MUST_NOT_BE_NULL, "is"));
180: }
181:
182: InputSource isrc = new InputSource(is);
183: return unmarshal(isrc);
184: }
185:
186: public final Object unmarshal(Reader reader) throws JAXBException {
187: if (reader == null) {
188: throw new IllegalArgumentException(Messages.format(
189: Messages.MUST_NOT_BE_NULL, "reader"));
190: }
191:
192: InputSource isrc = new InputSource(reader);
193: return unmarshal(isrc);
194: }
195:
196: private static InputSource streamSourceToInputSource(StreamSource ss) {
197: InputSource is = new InputSource();
198: is.setSystemId(ss.getSystemId());
199: is.setByteStream(ss.getInputStream());
200: is.setCharacterStream(ss.getReader());
201:
202: return is;
203: }
204:
205: /**
206: * Indicates whether or not the Unmarshaller is configured to validate
207: * during unmarshal operations.
208: * <p>
209: * <i><b>Note:</b> I named this method isValidating() to stay in-line
210: * with JAXP, as opposed to naming it getValidating(). </i>
211: *
212: * @return true if the Unmarshaller is configured to validate during
213: * unmarshal operations, false otherwise
214: * @throws JAXBException if an error occurs while retrieving the validating
215: * flag
216: */
217: public boolean isValidating() throws JAXBException {
218: return validating;
219: }
220:
221: /**
222: * Allow an application to register a validation event handler.
223: * <p>
224: * The validation event handler will be called by the JAXB Provider if any
225: * validation errors are encountered during calls to any of the
226: * <tt>unmarshal</tt> methods. If the client application does not register
227: * a validation event handler before invoking the unmarshal methods, then
228: * all validation events will be silently ignored and may result in
229: * unexpected behaviour.
230: *
231: * @param handler the validation event handler
232: * @throws JAXBException if an error was encountered while setting the
233: * event handler
234: */
235: public void setEventHandler(ValidationEventHandler handler)
236: throws JAXBException {
237:
238: if (handler == null) {
239: eventHandler = new DefaultValidationEventHandler();
240: } else {
241: eventHandler = handler;
242: }
243: }
244:
245: /**
246: * Specifies whether or not the Unmarshaller should validate during
247: * unmarshal operations. By default, the <tt>Unmarshaller</tt> does
248: * not validate.
249: * <p>
250: * This method may only be invoked before or after calling one of the
251: * unmarshal methods.
252: *
253: * @param validating true if the Unmarshaller should validate during
254: * unmarshal, false otherwise
255: * @throws JAXBException if an error occurred while enabling or disabling
256: * validation at unmarshal time
257: */
258: public void setValidating(boolean validating) throws JAXBException {
259: this .validating = validating;
260: }
261:
262: /**
263: * Return the current event handler or the default event handler if one
264: * hasn't been set.
265: *
266: * @return the current ValidationEventHandler or the default event handler
267: * if it hasn't been set
268: * @throws JAXBException if an error was encountered while getting the
269: * current event handler
270: */
271: public ValidationEventHandler getEventHandler()
272: throws JAXBException {
273: return eventHandler;
274: }
275:
276: /**
277: * Creates an UnmarshalException from a SAXException.
278: *
279: * This is an utility method provided for the derived classes.
280: *
281: * <p>
282: * When a provider-implemented ContentHandler wants to throw a
283: * JAXBException, it needs to wrap the exception by a SAXException.
284: * If the unmarshaller implementation blindly wrap SAXException
285: * by JAXBException, such an exception will be a JAXBException
286: * wrapped by a SAXException wrapped by another JAXBException.
287: * This is silly.
288: *
289: * <p>
290: * This method checks the nested exception of SAXException
291: * and reduce those excessive wrapping.
292: *
293: * @return the resulting UnmarshalException
294: */
295: protected UnmarshalException createUnmarshalException(SAXException e) {
296: // check the nested exception to see if it's an UnmarshalException
297: Exception nested = e.getException();
298: if (nested instanceof UnmarshalException)
299: return (UnmarshalException) nested;
300:
301: if (nested instanceof RuntimeException)
302: // typically this is an unexpected exception,
303: // just throw it rather than wrap it, so that the full stack
304: // trace can be displayed.
305: throw (RuntimeException) nested;
306:
307: // otherwise simply wrap it
308: if (nested != null)
309: return new UnmarshalException(nested);
310: else
311: return new UnmarshalException(e);
312: }
313:
314: /**
315: * Default implementation of the setProperty method always
316: * throws PropertyException since there are no required
317: * properties. If a provider needs to handle additional
318: * properties, it should override this method in a derived class.
319: */
320: public void setProperty(String name, Object value)
321: throws PropertyException {
322:
323: if (name == null) {
324: throw new IllegalArgumentException(Messages.format(
325: Messages.MUST_NOT_BE_NULL, "name"));
326: }
327:
328: throw new PropertyException(name, value);
329: }
330:
331: /**
332: * Default implementation of the getProperty method always
333: * throws PropertyException since there are no required
334: * properties. If a provider needs to handle additional
335: * properties, it should override this method in a derived class.
336: */
337: public Object getProperty(String name) throws PropertyException {
338:
339: if (name == null) {
340: throw new IllegalArgumentException(Messages.format(
341: Messages.MUST_NOT_BE_NULL, "name"));
342: }
343:
344: throw new PropertyException(name);
345: }
346:
347: public Object unmarshal(XMLEventReader reader) throws JAXBException {
348:
349: throw new UnsupportedOperationException();
350: }
351:
352: public Object unmarshal(XMLStreamReader reader)
353: throws JAXBException {
354:
355: throw new UnsupportedOperationException();
356: }
357:
358: public <T> JAXBElement<T> unmarshal(Node node, Class<T> expectedType)
359: throws JAXBException {
360: throw new UnsupportedOperationException();
361: }
362:
363: public <T> JAXBElement<T> unmarshal(Source source,
364: Class<T> expectedType) throws JAXBException {
365: throw new UnsupportedOperationException();
366: }
367:
368: public <T> JAXBElement<T> unmarshal(XMLStreamReader reader,
369: Class<T> expectedType) throws JAXBException {
370: throw new UnsupportedOperationException();
371: }
372:
373: public <T> JAXBElement<T> unmarshal(XMLEventReader reader,
374: Class<T> expectedType) throws JAXBException {
375: throw new UnsupportedOperationException();
376: }
377:
378: public void setSchema(Schema schema) {
379: throw new UnsupportedOperationException();
380: }
381:
382: public Schema getSchema() {
383: throw new UnsupportedOperationException();
384: }
385:
386: public void setAdapter(XmlAdapter adapter) {
387: if (adapter == null)
388: throw new IllegalArgumentException();
389: setAdapter((Class) adapter.getClass(), adapter);
390: }
391:
392: public <A extends XmlAdapter> void setAdapter(Class<A> type,
393: A adapter) {
394: throw new UnsupportedOperationException();
395: }
396:
397: public <A extends XmlAdapter> A getAdapter(Class<A> type) {
398: throw new UnsupportedOperationException();
399: }
400:
401: public void setAttachmentUnmarshaller(AttachmentUnmarshaller au) {
402: throw new UnsupportedOperationException();
403: }
404:
405: public AttachmentUnmarshaller getAttachmentUnmarshaller() {
406: throw new UnsupportedOperationException();
407: }
408:
409: public void setListener(Listener listener) {
410: throw new UnsupportedOperationException();
411: }
412:
413: public Listener getListener() {
414: throw new UnsupportedOperationException();
415: }
416: }
|