1 /* 2 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.xml.bind.helpers; 27 28 import org.xml.sax.InputSource; 29 import org.xml.sax.SAXException; 30 import org.xml.sax.XMLReader; 31 import org.w3c.dom.Node; 32 33 import javax.xml.bind.JAXBException; 34 import javax.xml.bind.PropertyException; 35 import javax.xml.bind.UnmarshalException; 36 import javax.xml.bind.Unmarshaller; 37 import javax.xml.bind.ValidationEventHandler; 38 import javax.xml.bind.JAXBElement; 39 import javax.xml.bind.annotation.adapters.XmlAdapter; 40 import javax.xml.bind.attachment.AttachmentUnmarshaller; 41 import javax.xml.parsers.ParserConfigurationException; 42 import javax.xml.parsers.SAXParserFactory; 43 import javax.xml.stream.XMLEventReader; 44 import javax.xml.stream.XMLStreamReader; 45 import javax.xml.transform.Source; 46 import javax.xml.transform.dom.DOMSource; 47 import javax.xml.transform.sax.SAXSource; 48 import javax.xml.transform.stream.StreamSource; 49 import javax.xml.validation.Schema; 50 import java.io.File; 51 import java.io.Reader; 52 import java.net.MalformedURLException; 53 import java.net.URL; 54 55 /** 56 * Partial default <tt>Unmarshaller</tt> implementation. 57 * 58 * <p> 59 * This class provides a partial default implementation for the 60 * {@link javax.xml.bind.Unmarshaller}interface. 61 * 62 * <p> 63 * A JAXB Provider has to implement five methods (getUnmarshallerHandler, 64 * unmarshal(Node), unmarshal(XMLReader,InputSource), 65 * unmarshal(XMLStreamReader), and unmarshal(XMLEventReader). 66 * 67 * @author <ul> 68 * <li>Kohsuke Kawaguchi, Sun Microsystems, Inc.</li> 69 * </ul> 70 * @see javax.xml.bind.Unmarshaller 71 * @since JAXB1.0 72 */ 73 public abstract class AbstractUnmarshallerImpl implements Unmarshaller 74 { 75 /** handler that will be used to process errors and warnings during unmarshal */ 76 private ValidationEventHandler eventHandler = 77 new DefaultValidationEventHandler(); 78 79 /** whether or not the unmarshaller will validate */ 80 protected boolean validating = false; 81 82 /** 83 * XMLReader that will be used to parse a document. 84 */ 85 private XMLReader reader = null; 86 87 /** 88 * Obtains a configured XMLReader. 89 * 90 * This method is used when the client-specified 91 * {@link SAXSource} object doesn't have XMLReader. 92 * 93 * {@link Unmarshaller} is not re-entrant, so we will 94 * only use one instance of XMLReader. 95 */ 96 protected XMLReader getXMLReader() throws JAXBException { 97 if(reader==null) { 98 try { 99 SAXParserFactory parserFactory; 100 parserFactory = SAXParserFactory.newInstance(); 101 parserFactory.setNamespaceAware(true); 102 // there is no point in asking a validation because 103 // there is no guarantee that the document will come with 104 // a proper schemaLocation. 105 parserFactory.setValidating(false); 106 reader = parserFactory.newSAXParser().getXMLReader(); 107 } catch( ParserConfigurationException e ) { 108 throw new JAXBException(e); 109 } catch( SAXException e ) { 110 throw new JAXBException(e); 111 } 112 } 113 return reader; 114 } 115 116 public Object unmarshal( Source source ) throws JAXBException { 117 if( source == null ) { 118 throw new IllegalArgumentException( 119 Messages.format( Messages.MUST_NOT_BE_NULL, "source" ) ); 120 } 121 122 if(source instanceof SAXSource) 123 return unmarshal( (SAXSource)source ); 124 if(source instanceof StreamSource) 125 return unmarshal( streamSourceToInputSource((StreamSource)source)); 126 if(source instanceof DOMSource) 127 return unmarshal( ((DOMSource)source).getNode() ); 128 129 // we don't handle other types of Source 130 throw new IllegalArgumentException(); 131 } 132 133 // use the client specified XMLReader contained in the SAXSource. 134 private Object unmarshal( SAXSource source ) throws JAXBException { 135 136 XMLReader r = source.getXMLReader(); 137 if( r == null ) 138 r = getXMLReader(); 139 140 return unmarshal( r, source.getInputSource() ); 141 } 142 143 /** 144 * Unmarshals an object by using the specified XMLReader and the InputSource. 145 * 146 * The callee should call the setErrorHandler method of the XMLReader 147 * so that errors are passed to the client-specified ValidationEventHandler. 148 */ 149 protected abstract Object unmarshal( XMLReader reader, InputSource source ) throws JAXBException; 150 151 public final Object unmarshal( InputSource source ) throws JAXBException { 152 if( source == null ) { 153 throw new IllegalArgumentException( 154 Messages.format( Messages.MUST_NOT_BE_NULL, "source" ) ); 155 } 156 157 return unmarshal( getXMLReader(), source ); 158 } 159 160 161 private Object unmarshal( String url ) throws JAXBException { 162 return unmarshal( new InputSource(url) ); 163 } 164 165 public final Object unmarshal( URL url ) throws JAXBException { 166 if( url == null ) { 167 throw new IllegalArgumentException( 168 Messages.format( Messages.MUST_NOT_BE_NULL, "url" ) ); 169 } 170 171 return unmarshal( url.toExternalForm() ); 172 } 173 174 public final Object unmarshal( File f ) throws JAXBException { 175 if( f == null ) { 176 throw new IllegalArgumentException( 177 Messages.format( Messages.MUST_NOT_BE_NULL, "file" ) ); 178 } 179 180 try { 181 // copied from JAXP 182 String path = f.getAbsolutePath(); 183 if (File.separatorChar != '/') 184 path = path.replace(File.separatorChar, '/'); 185 if (!path.startsWith("/")) 186 path = "/" + path; 187 if (!path.endsWith("/") && f.isDirectory()) 188 path = path + "/"; 189 return unmarshal(new URL("file", "", path)); 190 } catch( MalformedURLException e ) { 191 throw new IllegalArgumentException(e.getMessage()); 192 } 193 } 194 195 public final Object unmarshal( java.io.InputStream is ) 196 throws JAXBException { 197 198 if( is == null ) { 199 throw new IllegalArgumentException( 200 Messages.format( Messages.MUST_NOT_BE_NULL, "is" ) ); 201 } 202 203 InputSource isrc = new InputSource( is ); 204 return unmarshal( isrc ); 205 } 206 207 public final Object unmarshal( Reader reader ) throws JAXBException { 208 if( reader == null ) { 209 throw new IllegalArgumentException( 210 Messages.format( Messages.MUST_NOT_BE_NULL, "reader" ) ); 211 } 212 213 InputSource isrc = new InputSource( reader ); 214 return unmarshal( isrc ); 215 } 216 217 218 private static InputSource streamSourceToInputSource( StreamSource ss ) { 219 InputSource is = new InputSource(); 220 is.setSystemId( ss.getSystemId() ); 221 is.setByteStream( ss.getInputStream() ); 222 is.setCharacterStream( ss.getReader() ); 223 224 return is; 225 } 226 227 228 /** 229 * Indicates whether or not the Unmarshaller is configured to validate 230 * during unmarshal operations. 231 * <p> 232 * <i><b>Note:</b> I named this method isValidating() to stay in-line 233 * with JAXP, as opposed to naming it getValidating(). </i> 234 * 235 * @return true if the Unmarshaller is configured to validate during 236 * unmarshal operations, false otherwise 237 * @throws JAXBException if an error occurs while retrieving the validating 238 * flag 239 */ 240 public boolean isValidating() throws JAXBException { 241 return validating; 242 } 243 244 /** 245 * Allow an application to register a validation event handler. 246 * <p> 247 * The validation event handler will be called by the JAXB Provider if any 248 * validation errors are encountered during calls to any of the 249 * <tt>unmarshal</tt> methods. If the client application does not register 250 * a validation event handler before invoking the unmarshal methods, then 251 * all validation events will be silently ignored and may result in 252 * unexpected behaviour. 253 * 254 * @param handler the validation event handler 255 * @throws JAXBException if an error was encountered while setting the 256 * event handler 257 */ 258 public void setEventHandler(ValidationEventHandler handler) 259 throws JAXBException { 260 261 if( handler == null ) { 262 eventHandler = new DefaultValidationEventHandler(); 263 } else { 264 eventHandler = handler; 265 } 266 } 267 268 /** 269 * Specifies whether or not the Unmarshaller should validate during 270 * unmarshal operations. By default, the <tt>Unmarshaller</tt> does 271 * not validate. 272 * <p> 273 * This method may only be invoked before or after calling one of the 274 * unmarshal methods. 275 * 276 * @param validating true if the Unmarshaller should validate during 277 * unmarshal, false otherwise 278 * @throws JAXBException if an error occurred while enabling or disabling 279 * validation at unmarshal time 280 */ 281 public void setValidating(boolean validating) throws JAXBException { 282 this.validating = validating; 283 } 284 285 /** 286 * Return the current event handler or the default event handler if one 287 * hasn't been set. 288 * 289 * @return the current ValidationEventHandler or the default event handler 290 * if it hasn't been set 291 * @throws JAXBException if an error was encountered while getting the 292 * current event handler 293 */ 294 public ValidationEventHandler getEventHandler() throws JAXBException { 295 return eventHandler; 296 } 297 298 299 /** 300 * Creates an UnmarshalException from a SAXException. 301 * 302 * This is an utility method provided for the derived classes. 303 * 304 * <p> 305 * When a provider-implemented ContentHandler wants to throw a 306 * JAXBException, it needs to wrap the exception by a SAXException. 307 * If the unmarshaller implementation blindly wrap SAXException 308 * by JAXBException, such an exception will be a JAXBException 309 * wrapped by a SAXException wrapped by another JAXBException. 310 * This is silly. 311 * 312 * <p> 313 * This method checks the nested exception of SAXException 314 * and reduce those excessive wrapping. 315 * 316 * @return the resulting UnmarshalException 317 */ 318 protected UnmarshalException createUnmarshalException( SAXException e ) { 319 // check the nested exception to see if it's an UnmarshalException 320 Exception nested = e.getException(); 321 if(nested instanceof UnmarshalException) 322 return (UnmarshalException)nested; 323 324 if(nested instanceof RuntimeException) 325 // typically this is an unexpected exception, 326 // just throw it rather than wrap it, so that the full stack 327 // trace can be displayed. 328 throw (RuntimeException)nested; 329 330 331 // otherwise simply wrap it 332 if(nested!=null) 333 return new UnmarshalException(nested); 334 else 335 return new UnmarshalException(e); 336 } 337 338 /** 339 * Default implementation of the setProperty method always 340 * throws PropertyException since there are no required 341 * properties. If a provider needs to handle additional 342 * properties, it should override this method in a derived class. 343 */ 344 public void setProperty( String name, Object value ) 345 throws PropertyException { 346 347 if( name == null ) { 348 throw new IllegalArgumentException( 349 Messages.format( Messages.MUST_NOT_BE_NULL, "name" ) ); 350 } 351 352 throw new PropertyException(name, value); 353 } 354 355 /** 356 * Default implementation of the getProperty method always 357 * throws PropertyException since there are no required 358 * properties. If a provider needs to handle additional 359 * properties, it should override this method in a derived class. 360 */ 361 public Object getProperty( String name ) 362 throws PropertyException { 363 364 if( name == null ) { 365 throw new IllegalArgumentException( 366 Messages.format( Messages.MUST_NOT_BE_NULL, "name" ) ); 367 } 368 369 throw new PropertyException(name); 370 } 371 372 public Object unmarshal(XMLEventReader reader) throws JAXBException { 373 374 throw new UnsupportedOperationException(); 375 } 376 377 public Object unmarshal(XMLStreamReader reader) throws JAXBException { 378 379 throw new UnsupportedOperationException(); 380 } 381 382 public <T> JAXBElement<T> unmarshal(Node node, Class<T> expectedType) throws JAXBException { 383 throw new UnsupportedOperationException(); 384 } 385 386 public <T> JAXBElement<T> unmarshal(Source source, Class<T> expectedType) throws JAXBException { 387 throw new UnsupportedOperationException(); 388 } 389 390 public <T> JAXBElement<T> unmarshal(XMLStreamReader reader, Class<T> expectedType) throws JAXBException { 391 throw new UnsupportedOperationException(); 392 } 393 394 public <T> JAXBElement<T> unmarshal(XMLEventReader reader, Class<T> expectedType) throws JAXBException { 395 throw new UnsupportedOperationException(); 396 } 397 398 public void setSchema(Schema schema) { 399 throw new UnsupportedOperationException(); 400 } 401 402 public Schema getSchema() { 403 throw new UnsupportedOperationException(); 404 } 405 406 public void setAdapter(XmlAdapter adapter) { 407 if(adapter==null) 408 throw new IllegalArgumentException(); 409 setAdapter((Class)adapter.getClass(),adapter); 410 } 411 412 public <A extends XmlAdapter> void setAdapter(Class<A> type, A adapter) { 413 throw new UnsupportedOperationException(); 414 } 415 416 public <A extends XmlAdapter> A getAdapter(Class<A> type) { 417 throw new UnsupportedOperationException(); 418 } 419 420 public void setAttachmentUnmarshaller(AttachmentUnmarshaller au) { 421 throw new UnsupportedOperationException(); 422 } 423 424 public AttachmentUnmarshaller getAttachmentUnmarshaller() { 425 throw new UnsupportedOperationException(); 426 } 427 428 public void setListener(Listener listener) { 429 throw new UnsupportedOperationException(); 430 } 431 432 public Listener getListener() { 433 throw new UnsupportedOperationException(); 434 } 435 }