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