View Javadoc

1   //
2   // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v1.0.3-b18-fcs 
3   // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
4   // Any modifications to this file will be lost upon recompilation of the source schema. 
5   // Generated on: 2004.12.16 at 07:09:44 EST 
6   //
7   
8   package net.sf.jour.rt.view.config.impl.runtime;
9   
10  import java.util.HashSet;
11  import java.util.Iterator;
12  import java.util.Set;
13  
14  import javax.xml.bind.JAXBException;
15  import javax.xml.bind.ValidationEvent;
16  import javax.xml.bind.ValidationEventHandler;
17  import javax.xml.bind.helpers.NotIdentifiableEventImpl;
18  import javax.xml.bind.helpers.ValidationEventLocatorImpl;
19  
20  import org.xml.sax.ContentHandler;
21  import org.xml.sax.SAXException;
22  import org.xml.sax.helpers.AttributesImpl;
23  
24  import com.sun.xml.bind.JAXBAssertionError;
25  import com.sun.xml.bind.JAXBObject;
26  import com.sun.xml.bind.marshaller.IdentifiableObject;
27  import com.sun.xml.bind.marshaller.Messages;
28  import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
29  import com.sun.xml.bind.serializer.AbortSerializationException;
30  import com.sun.xml.bind.serializer.Util;
31  
32  /***
33   * XMLSerializer that produces SAX2 events.
34   * 
35   * To marshal an object, create an instance of SAXMarshaller
36   * and call the serializeElements method of the XMLSerializable
37   * object that you want to marshal.
38   * 
39   * @author  Kohsuke Kawaguchi
40   */
41  public class SAXMarshaller implements XMLSerializer
42  {
43      /***
44       * "Attributes" object that is passed to the startElement event.
45       * One object is reused throughout the marshalling.
46       */
47      private final AttributesImpl attributes = new AttributesImpl();
48   
49      /*** This object receives SAX2 events generated from the marshaller. */
50      private final ContentHandler writer;
51      
52      /*** Marshaller object to which this object belongs. */
53      private final MarshallerImpl owner;
54      
55      /*** Objects referenced through IDREF. */
56      private final Set idReferencedObjects = new HashSet();
57      
58      /*** Objects with ID. */
59      private final Set objectsWithId = new HashSet();
60      
61      /*** Object currently marshalling itself. */
62      private JAXBObject currentTarget;
63      
64      /***
65       * Creates a marshalling context by designating the ContentHandler
66       * that receives generated SAX2 events.
67       */
68      public SAXMarshaller( ContentHandler _writer, NamespacePrefixMapper prefixMapper, MarshallerImpl _owner ) {
69          this.writer = _writer;
70          this.owner = _owner;
71          this.nsContext = new NamespaceContextImpl(
72              prefixMapper!=null?prefixMapper:defaultNamespacePrefixMapper);
73      }
74      
75      /*** namespace context. */
76      private final NamespaceContextImpl nsContext;
77      
78      public NamespaceContext2 getNamespaceContext() { return nsContext; }
79      
80      //
81      //
82      // name stack
83      //
84      //
85      
86      /*** Element name stack implemented as an array of (uri,local) pairs. */
87      private String[] elementStack = new String[16];;
88      private int elementLen=0;
89      
90      
91      
92      private void pushElement( String uri, String local ) {
93          if(elementStack.length==elementLen) {
94              // reallocate buffer
95              String[] buf = new String[elementStack.length*2];
96              System.arraycopy( elementStack, 0, buf, 0, elementStack.length );
97              elementStack = buf;
98          }
99          elementStack[elementLen++] = uri;
100         elementStack[elementLen++] = local;
101     }
102     
103     private void popElement() { elementLen-=2;  }
104     
105     private String getCurrentElementUri()   { return elementStack[elementLen-2]; }
106     private String getCurrentElementLocal() { return elementStack[elementLen-1]; }
107     
108     
109     
110     
111     
112     /***
113      * Starts marshalling of an element.
114      * Calling this method will push the internal state into the
115      * internal stack.
116      */
117     public void startElement( String uri, String local ) throws SAXException {
118         boolean isRoot = false;
119         String suggestion = null;
120         if( elementLen==0 ) {
121             isRoot = true;
122             // this is the root element. suggest this as the default namespace
123             suggestion = "";
124         }
125         
126         writePendingText();
127         nsContext.startElement();
128         pushElement(uri,local); // memorize element name
129                 
130         // declare this uri
131         nsContext.declareNamespace(uri,suggestion,false);
132         
133         // if this is the root element, declare user-specified namespace URIs.
134         if( isRoot ) {
135             // work defensively. we are calling an user-defined method.
136             String[] uris = nsContext.getNamespacePrefixMapper().getPreDeclaredNamespaceUris();
137             if( uris!=null ) {
138                 for( int i=0; i<uris.length; i++ ) {
139                     if( uris[i]!=null )
140                         nsContext.declareNamespace(uris[i],null,false);
141                 }
142             }
143         }
144     }
145     
146     
147     private final PrefixCallback startPrefixCallback = new PrefixCallback() {
148         public void onPrefixMapping( String prefix, String nsUri ) throws SAXException {
149             writer.startPrefixMapping(prefix,nsUri);
150         }
151     };
152     private final PrefixCallback endPrefixCallback = new PrefixCallback() {
153         public void onPrefixMapping( String prefix, String nsUri ) throws SAXException {
154             writer.endPrefixMapping(prefix);
155         }
156     };
157     
158     public void endNamespaceDecls() throws SAXException {
159         nsContext.endNamespaceDecls();
160     }
161     
162     /***
163      * Switches to the "marshal child texts/elements" mode.
164      * This method has to be called after the 1st pass is completed.
165      */
166     public void endAttributes() throws SAXException {
167         // calculate QName of the element
168         String uri = getCurrentElementUri();
169         String local = getCurrentElementLocal();
170         
171         String prefix = nsContext.getPrefix(uri);
172         _assert(prefix!=null);  // since we've declared it, it should be available
173         
174         String qname;
175         if(prefix.length()!=0 ) 
176             qname = prefix+':'+local;
177         else
178             qname = local;
179 
180         // fire startPrefixMapping events
181         nsContext.iterateDeclaredPrefixes(startPrefixCallback);
182         
183         // fire the startElement event
184         writer.startElement( uri, local, qname, attributes );
185         
186         
187         // reset attributes
188         attributes.clear();
189         
190         // prepare to collect texts
191         textBuf.setLength(0);
192     }
193     
194     /***
195      * Ends marshalling of an element.
196      * Pops the internal stack.
197      */
198     public void endElement() throws SAXException {
199         writePendingText();
200         
201         String uri = getCurrentElementUri();
202         String local = getCurrentElementLocal();
203         
204         String prefix = nsContext.getPrefix(uri);
205         _assert(prefix!=null);      // we've declared it earlier.
206         
207         String qname;
208         if(prefix.length()!=0)
209             qname = prefix+':'+local;
210         else
211             qname = local;
212         
213         writer.endElement( uri, local, qname );
214 
215         // pop namespace bindings and
216         // fire endPrefixMapping events
217         nsContext.iterateDeclaredPrefixes(endPrefixCallback);
218         
219         popElement();
220         
221         // prepare to collect texts
222         textBuf.setLength(0);
223         
224         nsContext.endElement();
225     }
226     
227     
228     /*** Buffer for collecting characters. */
229     private final StringBuffer textBuf = new StringBuffer();
230     
231     /***
232      * Marshalls text.
233      * 
234      * <p>
235      * This method can be called (i) after the startAttribute method
236      * and (ii) before the endAttribute method, to marshal attribute values.
237      * If the method is called more than once, those texts are considered
238      * as separated by whitespaces. For example,
239      * 
240      * <pre>
241      * c.startAttribute();
242      * c.text("abc");
243      * c.text("def");
244      * c.endAttribute("","foo");
245      * </pre>
246      * 
247      * will generate foo="abc def".
248      * 
249      * <p>
250      * Similarly, this method can be called after the endAttributes
251      * method to marshal texts inside elements. The same rule about
252      * multiple invokations apply to this case, too. For example,
253      * 
254      * <pre>
255      * c.startElement("","foo");
256      * c.endAttributes();
257      * c.text("abc");
258      * c.text("def");
259      *   c.startElement("","bar");
260      *   c.endAttributes();
261      *   c.endElement();
262      * c.text("ghi");
263      * c.endElement();
264      * </pre>
265      * 
266      * will generate <code>&lt;foo>abc def&lt;bar/>ghi&lt;/foo></code>.
267      */
268     public void text( String text, String fieldName ) throws SAXException {
269         // If the assertion fails, it must be a bug of xjc.
270         // right now, we are not expecting the text method to be called.
271         if(text==null) {
272             reportError(Util.createMissingObjectError(currentTarget,fieldName));
273             return;
274         }
275     
276         if(textBuf.length()!=0)
277             textBuf.append(' ');
278         textBuf.append(text);
279     }
280     
281     /***
282      * Writes pending text (characters inside elements) to the writer.
283      * This method is called from startElement and endElement.
284      */
285     private void writePendingText() throws SAXException {
286         // assert(textBuf!=null);
287         int len = textBuf.length();
288         
289         if(len!=0)
290             writer.characters( textBuf.toString().toCharArray(), 0, len );
291     }
292     
293     /***
294      * Starts marshalling of an attribute.
295      * 
296      * The marshalling of an attribute will be done by
297      * <ol>
298      *  <li>call the startAttribute method
299      *  <li>call the text method (several times if necessary)
300      *  <li>call the endAttribute method
301      * </ol>
302      * 
303      * No two attributes can be marshalled at the same time.
304      * Note that the whole attribute marshalling must be happened
305      * after the startElement method and before the endAttributes method.
306      */
307     public void startAttribute( String uri, String local ) {
308         // initialize the buffer to collect attribute value
309         textBuf.setLength(0);
310         
311         // remember the attribute name. We'll use this value later.
312         this.attNamespaceUri = uri;
313         this.attLocalName = local;
314     }
315     
316     // used to keep attribute names until the endAttribute method is called.
317     private String attNamespaceUri;
318     private String attLocalName;
319 
320     public void endAttribute() {
321         // use CDATA as the attribute type. This preserves
322         // successive processors to collapse whitespaces.
323         // (we cannot prevent characters like #xD to be replaced to
324         // #x20, though).
325         //
326         // strictly speaking, attribute value normalization should be
327         // provessed by XML parser, so it's unclear whether XML writer
328         // uses this type value.
329         //
330         // in any way, CDATA type is the safest choice here.
331         
332         String qname;
333         if(attNamespaceUri.length()==0) {
334             // default namespace. don't need prefix
335             qname = attLocalName;
336         } else {
337             qname = nsContext.declareNamespace(attNamespaceUri,null,true)+':'+attLocalName;
338         }
339 
340         attributes.addAttribute(attNamespaceUri,attLocalName,qname,"CDATA",textBuf.toString());
341     }
342     
343     public String onID( IdentifiableObject owner, String value ) throws SAXException {
344         objectsWithId.add(owner);
345         return value;
346     }
347     public String onIDREF( IdentifiableObject obj ) throws SAXException {
348         idReferencedObjects.add(obj);
349         String id = obj.____jaxb____getId();
350         if(id==null) {
351             reportError( new NotIdentifiableEventImpl(
352                 ValidationEvent.ERROR,
353                 Messages.format(Messages.ERR_NOT_IDENTIFIABLE),
354                 new ValidationEventLocatorImpl(obj) ) );
355         }
356         return id;
357     }
358     
359     void reconcileID() throws AbortSerializationException {
360         // find objects that were not a part of the object graph 
361         idReferencedObjects.removeAll(objectsWithId);
362         
363         for( Iterator itr=idReferencedObjects.iterator(); itr.hasNext(); ) {
364             IdentifiableObject o = (IdentifiableObject)itr.next();
365             reportError( new NotIdentifiableEventImpl(
366                 ValidationEvent.ERROR,
367                 Messages.format(Messages.ERR_DANGLING_IDREF,o.____jaxb____getId()),
368                 new ValidationEventLocatorImpl(o) ) );
369         }
370         
371         // clear the garbage
372         idReferencedObjects.clear();
373         objectsWithId.clear();
374     }
375 
376 
377 
378     public void childAsBody( JAXBObject o, String fieldName ) throws SAXException {
379         if(o==null) {
380             // if null is passed, it usually means that the content tree object
381             // doesn't have some of its required property.
382             reportMissingObjectError(fieldName);
383             // as a marshaller, we should be generous, so we'll continue to marshal
384             // this document by skipping this missing object.
385             return;
386         }
387         
388         JAXBObject oldTarget = currentTarget;
389         currentTarget = o;
390         
391         owner.context.getGrammarInfo().castToXMLSerializable(o).serializeBody(this);
392         
393         currentTarget = oldTarget;
394     }
395     
396     public void childAsAttributes( JAXBObject o, String fieldName ) throws SAXException {
397         if(o==null) {
398             reportMissingObjectError(fieldName);
399             return;
400         }
401 
402         JAXBObject oldTarget = currentTarget;
403         currentTarget = o;
404         
405         owner.context.getGrammarInfo().castToXMLSerializable(o).serializeAttributes(this);
406         
407         currentTarget = oldTarget;
408     }
409     
410     public void childAsURIs( JAXBObject o, String fieldName ) throws SAXException {
411         if(o==null) {
412             reportMissingObjectError(fieldName);
413             return;
414         }
415         
416         JAXBObject oldTarget = currentTarget;
417         currentTarget = o;
418         
419         owner.context.getGrammarInfo().castToXMLSerializable(o).serializeURIs(this);
420         
421         currentTarget = oldTarget;
422     }
423     
424 
425     public void reportError( ValidationEvent ve ) throws AbortSerializationException {
426         ValidationEventHandler handler;
427         
428         try {
429             handler = owner.getEventHandler();
430         } catch( JAXBException e ) {
431             throw new AbortSerializationException(e);
432         }
433         
434         if(!handler.handleEvent(ve)) {
435             if(ve.getLinkedException() instanceof Exception)
436                 throw new AbortSerializationException((Exception)ve.getLinkedException());
437             else
438                 throw new AbortSerializationException(ve.getMessage());
439         }
440     }
441     
442     
443     public void reportMissingObjectError(String fieldName) throws SAXException {
444         reportError(Util.createMissingObjectError(currentTarget,fieldName));
445     }
446     
447     
448     private static void _assert( boolean b ) {
449         if(!b)
450             throw new JAXBAssertionError();
451     }
452     
453     /***
454      * Default {@link NamespacePrefixMapper} implementation used when
455      * it is not specified by the user.
456      */
457     private static NamespacePrefixMapper defaultNamespacePrefixMapper = new NamespacePrefixMapper() {
458         public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
459             if( namespaceUri.equals("http://www.w3.org/2001/XMLSchema-instance") )
460                 return "xsi";
461             return suggestion;
462         }
463     };
464 }