001// 002// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v1.0.6-01/24/2006 06:15 PM(kohsuke)-fcs 003// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 004// Any modifications to this file will be lost upon recompilation of the source schema. 005// Generated on: 2012.10.03 at 04:27:47 AM CEST 006// 007 008package org.jdtaus.mojo.resource.model.impl.runtime; 009 010import java.util.HashSet; 011import java.util.Iterator; 012import java.util.Set; 013 014import javax.xml.bind.JAXBException; 015import javax.xml.bind.ValidationEvent; 016import javax.xml.bind.ValidationEventHandler; 017import javax.xml.bind.helpers.NotIdentifiableEventImpl; 018import javax.xml.bind.helpers.ValidationEventLocatorImpl; 019 020import org.xml.sax.ContentHandler; 021import org.xml.sax.SAXException; 022import org.xml.sax.helpers.AttributesImpl; 023 024import com.sun.xml.bind.JAXBAssertionError; 025import com.sun.xml.bind.JAXBObject; 026import com.sun.xml.bind.marshaller.IdentifiableObject; 027import com.sun.xml.bind.marshaller.Messages; 028import com.sun.xml.bind.marshaller.NamespacePrefixMapper; 029import com.sun.xml.bind.serializer.AbortSerializationException; 030import com.sun.xml.bind.serializer.Util; 031 032/** 033 * XMLSerializer that produces SAX2 events. 034 * 035 * To marshal an object, create an instance of SAXMarshaller 036 * and call the serializeElements method of the XMLSerializable 037 * object that you want to marshal. 038 * 039 * @author Kohsuke Kawaguchi 040 */ 041public class SAXMarshaller implements XMLSerializer 042{ 043 /** 044 * "Attributes" object that is passed to the startElement event. 045 * One object is reused throughout the marshalling. 046 */ 047 private final AttributesImpl attributes = new AttributesImpl(); 048 049 /** This object receives SAX2 events generated from the marshaller. */ 050 private final ContentHandler writer; 051 052 /** Marshaller object to which this object belongs. */ 053 private final MarshallerImpl owner; 054 055 /** Objects referenced through IDREF. */ 056 private final Set idReferencedObjects = new HashSet(); 057 058 /** Objects with ID. */ 059 private final Set objectsWithId = new HashSet(); 060 061 /** Object currently marshalling itself. */ 062 private JAXBObject currentTarget; 063 064 /** 065 * Creates a marshalling context by designating the ContentHandler 066 * that receives generated SAX2 events. 067 */ 068 public SAXMarshaller( ContentHandler _writer, NamespacePrefixMapper prefixMapper, MarshallerImpl _owner ) { 069 this.writer = _writer; 070 this.owner = _owner; 071 this.nsContext = new NamespaceContextImpl( 072 prefixMapper!=null?prefixMapper:defaultNamespacePrefixMapper); 073 } 074 075 /** namespace context. */ 076 private final NamespaceContextImpl nsContext; 077 078 public NamespaceContext2 getNamespaceContext() { return nsContext; } 079 080 // 081 // 082 // name stack 083 // 084 // 085 086 /** Element name stack implemented as an array of (uri,local) pairs. */ 087 private String[] elementStack = new String[16];; 088 private int elementLen=0; 089 090 091 092 private void pushElement( String uri, String local ) { 093 if(elementStack.length==elementLen) { 094 // reallocate buffer 095 String[] buf = new String[elementStack.length*2]; 096 System.arraycopy( elementStack, 0, buf, 0, elementStack.length ); 097 elementStack = buf; 098 } 099 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><foo>abc def<bar/>ghi</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}