View Javadoc

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