001 /* 002 * @(#)$Id: JAXBSource.java,v 1.9 2003/03/05 23:22:53 kk122374 Exp $ 003 * 004 * Copyright 2002 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.util; 011 012 import java.io.IOException; 013 import javax.xml.bind.JAXBContext; 014 import javax.xml.bind.JAXBException; 015 import javax.xml.bind.Marshaller; 016 import javax.xml.transform.sax.SAXSource; 017 018 import org.xml.sax.ContentHandler; 019 import org.xml.sax.DTDHandler; 020 import org.xml.sax.EntityResolver; 021 import org.xml.sax.ErrorHandler; 022 import org.xml.sax.InputSource; 023 import org.xml.sax.SAXException; 024 import org.xml.sax.SAXNotRecognizedException; 025 import org.xml.sax.SAXParseException; 026 import org.xml.sax.XMLReader; 027 import org.xml.sax.ext.LexicalHandler; 028 import org.xml.sax.helpers.XMLFilterImpl; 029 030 /** 031 * JAXP {@link javax.xml.transform.Source} implementation 032 * that marshals a JAXB-generated object. 033 * 034 * <p> 035 * This utility class is useful to combine JAXB with 036 * other Java/XML technologies. 037 * 038 * <p> 039 * The following example shows how to use JAXB to marshal a document 040 * for transformation by XSLT. 041 * 042 * <blockquote> 043 * <pre> 044 * MyObject o = // get JAXB content tree 045 * 046 * // jaxbContext is a JAXBContext object from which 'o' is created. 047 * JAXBSource source = new JAXBSource( jaxbContext, o ); 048 * 049 * // set up XSLT transformation 050 * TransformerFactory tf = TransformerFactory.newInstance(); 051 * Transformer t = tf.newTransformer(new StreamSource("test.xsl")); 052 * 053 * // run transformation 054 * t.transform(source,new StreamResult(System.out)); 055 * </pre> 056 * </blockquote> 057 * 058 * @author 059 * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com) 060 */ 061 public class JAXBSource extends SAXSource { 062 063 /** 064 * Creates a new {@link javax.xml.transform.Source} for the given content object. 065 * 066 * @param context 067 * JAXBContext that was used to create 068 * <code>contentObject</code>. This context is used 069 * to create a new instance of marshaller and must not be null. 070 * @param contentObject 071 * An instance of a JAXB-generated class, which will be 072 * used as a {@link javax.xml.transform.Source} (by marshalling it into XML). It must 073 * not be null. 074 * @throws JAXBException if an error is encountered while creating the 075 * JAXBSource or if either of the parameters are null. 076 */ 077 public JAXBSource( JAXBContext context, Object contentObject ) 078 throws JAXBException { 079 080 this( 081 ( context == null ) ? 082 assertionFailed( Messages.format( Messages.SOURCE_NULL_CONTEXT ) ) : 083 context.createMarshaller(), 084 085 ( contentObject == null ) ? 086 assertionFailed( Messages.format( Messages.SOURCE_NULL_CONTENT ) ) : 087 contentObject); 088 } 089 090 /** 091 * Creates a new {@link javax.xml.transform.Source} for the given content object. 092 * 093 * @param marshaller 094 * A marshaller instance that will be used to marshal 095 * <code>contentObject</code> into XML. This must be 096 * created from a JAXBContext that was used to build 097 * <code>contentObject</code> and must not be null. 098 * @param contentObject 099 * An instance of a JAXB-generated class, which will be 100 * used as a {@link javax.xml.transform.Source} (by marshalling it into XML). It must 101 * not be null. 102 * @throws JAXBException if an error is encountered while creating the 103 * JAXBSource or if either of the parameters are null. 104 */ 105 public JAXBSource( Marshaller marshaller, Object contentObject ) 106 throws JAXBException { 107 108 if( marshaller == null ) 109 throw new JAXBException( 110 Messages.format( Messages.SOURCE_NULL_MARSHALLER ) ); 111 112 if( contentObject == null ) 113 throw new JAXBException( 114 Messages.format( Messages.SOURCE_NULL_CONTENT ) ); 115 116 this.marshaller = marshaller; 117 this.contentObject = contentObject; 118 119 super.setXMLReader(pseudoParser); 120 // pass a dummy InputSource. We don't care 121 super.setInputSource(new InputSource()); 122 } 123 124 private final Marshaller marshaller; 125 private final Object contentObject; 126 127 // this object will pretend as an XMLReader. 128 // no matter what parameter is specified to the parse method, 129 // it just parse the contentObject. 130 private final XMLReader pseudoParser = new XMLReader() { 131 public boolean getFeature(String name) throws SAXNotRecognizedException { 132 throw new SAXNotRecognizedException(name); 133 } 134 135 public void setFeature(String name, boolean value) throws SAXNotRecognizedException { 136 throw new SAXNotRecognizedException(name); 137 } 138 139 public Object getProperty(String name) throws SAXNotRecognizedException { 140 if( "http://xml.org/sax/properties/lexical-handler".equals(name) ) { 141 return lexicalHandler; 142 } 143 throw new SAXNotRecognizedException(name); 144 } 145 146 public void setProperty(String name, Object value) throws SAXNotRecognizedException { 147 if( "http://xml.org/sax/properties/lexical-handler".equals(name) ) { 148 this.lexicalHandler = (LexicalHandler)value; 149 return; 150 } 151 throw new SAXNotRecognizedException(name); 152 } 153 154 private LexicalHandler lexicalHandler; 155 156 // we will store this value but never use it by ourselves. 157 private EntityResolver entityResolver; 158 public void setEntityResolver(EntityResolver resolver) { 159 this.entityResolver = resolver; 160 } 161 public EntityResolver getEntityResolver() { 162 return entityResolver; 163 } 164 165 private DTDHandler dtdHandler; 166 public void setDTDHandler(DTDHandler handler) { 167 this.dtdHandler = handler; 168 } 169 public DTDHandler getDTDHandler() { 170 return dtdHandler; 171 } 172 173 // SAX allows ContentHandler to be changed during the parsing, 174 // but JAXB doesn't. So this repeater will sit between those 175 // two components. 176 private XMLFilterImpl repeater = new XMLFilterImpl(); 177 178 public void setContentHandler(ContentHandler handler) { 179 repeater.setContentHandler(handler); 180 } 181 public ContentHandler getContentHandler() { 182 return repeater.getContentHandler(); 183 } 184 185 private ErrorHandler errorHandler; 186 public void setErrorHandler(ErrorHandler handler) { 187 this.errorHandler = handler; 188 } 189 public ErrorHandler getErrorHandler() { 190 return errorHandler; 191 } 192 193 public void parse(InputSource input) throws IOException, SAXException { 194 parse(); 195 } 196 197 public void parse(String systemId) throws IOException, SAXException { 198 parse(); 199 } 200 201 public void parse() throws SAXException { 202 // parses a content object by using the given marshaller 203 // SAX events will be sent to the repeater, and the repeater 204 // will further forward it to an appropriate component. 205 try { 206 marshaller.marshal( contentObject, repeater ); 207 } catch( JAXBException e ) { 208 // wrap it to a SAXException 209 SAXParseException se = 210 new SAXParseException( e.getMessage(), 211 null, null, -1, -1, e ); 212 213 // if the consumer sets an error handler, it is our responsibility 214 // to notify it. 215 if(errorHandler!=null) 216 errorHandler.fatalError(se); 217 218 // this is a fatal error. Even if the error handler 219 // returns, we will abort anyway. 220 throw se; 221 } 222 } 223 }; 224 225 /** 226 * Hook to throw exception from the middle of a contructor chained call 227 * to this 228 */ 229 private static Marshaller assertionFailed( String message ) 230 throws JAXBException { 231 232 throw new JAXBException( message ); 233 } 234 }