001: //
002: // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v1.0.4-b18-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: 2005.03.04 at 10:20:40 PST
006: //
007:
008: package com.nabhinc.portal.config.impl.runtime;
009:
010: import java.util.HashSet;
011: import java.util.Iterator;
012: import java.util.Set;
013:
014: import javax.xml.bind.JAXBException;
015: import javax.xml.bind.ValidationEvent;
016: import javax.xml.bind.ValidationEventHandler;
017: import javax.xml.bind.helpers.NotIdentifiableEventImpl;
018: import javax.xml.bind.helpers.ValidationEventLocatorImpl;
019:
020: import org.xml.sax.ContentHandler;
021: import org.xml.sax.SAXException;
022: import org.xml.sax.helpers.AttributesImpl;
023:
024: import com.sun.xml.bind.JAXBAssertionError;
025: import com.sun.xml.bind.JAXBObject;
026: import com.sun.xml.bind.marshaller.IdentifiableObject;
027: import com.sun.xml.bind.marshaller.Messages;
028: import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
029: import com.sun.xml.bind.serializer.AbortSerializationException;
030: import 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: */
041: public class SAXMarshaller implements XMLSerializer {
042: /**
043: * "Attributes" object that is passed to the startElement event.
044: * One object is reused throughout the marshalling.
045: */
046: private final AttributesImpl attributes = new AttributesImpl();
047:
048: /** This object receives SAX2 events generated from the marshaller. */
049: private final ContentHandler writer;
050:
051: /** Marshaller object to which this object belongs. */
052: private final MarshallerImpl owner;
053:
054: /** Objects referenced through IDREF. */
055: private final Set idReferencedObjects = new HashSet();
056:
057: /** Objects with ID. */
058: private final Set objectsWithId = new HashSet();
059:
060: /** Object currently marshalling itself. */
061: private JAXBObject currentTarget;
062:
063: /**
064: * Creates a marshalling context by designating the ContentHandler
065: * that receives generated SAX2 events.
066: */
067: public SAXMarshaller(ContentHandler _writer,
068: NamespacePrefixMapper prefixMapper, MarshallerImpl _owner) {
069: this .writer = _writer;
070: this .owner = _owner;
071: this .nsContext = new NamespaceContextImpl(
072: prefixMapper != null ? prefixMapper
073: : defaultNamespacePrefixMapper);
074: }
075:
076: /** namespace context. */
077: private final NamespaceContextImpl nsContext;
078:
079: public NamespaceContext2 getNamespaceContext() {
080: return nsContext;
081: }
082:
083: //
084: //
085: // name stack
086: //
087: //
088:
089: /** Element name stack implemented as an array of (uri,local) pairs. */
090: private String[] elementStack = new String[16];;
091: private int elementLen = 0;
092:
093: private void pushElement(String uri, String local) {
094: if (elementStack.length == elementLen) {
095: // reallocate buffer
096: String[] buf = new String[elementStack.length * 2];
097: System.arraycopy(elementStack, 0, buf, 0,
098: elementStack.length);
099: 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.
119: * Calling this method will push the internal state into the
120: * internal stack.
121: */
122: public void startElement(String uri, String local)
123: throws SAXException {
124: boolean isRoot = false;
125: String suggestion = null;
126: if (elementLen == 0) {
127: isRoot = true;
128: // this is the root element. suggest this as the default namespace
129: suggestion = "";
130: }
131:
132: writePendingText();
133: nsContext.startElement();
134: pushElement(uri, local); // memorize element name
135:
136: // declare this uri
137: nsContext.declareNamespace(uri, suggestion, false);
138:
139: // if this is the root element, declare user-specified namespace URIs.
140: if (isRoot) {
141: // work defensively. we are calling an user-defined method.
142: String[] uris = nsContext.getNamespacePrefixMapper()
143: .getPreDeclaredNamespaceUris();
144: if (uris != null) {
145: for (int i = 0; i < uris.length; i++) {
146: if (uris[i] != null)
147: nsContext
148: .declareNamespace(uris[i], null, false);
149: }
150: }
151: }
152: }
153:
154: private final PrefixCallback startPrefixCallback = new PrefixCallback() {
155: public void onPrefixMapping(String prefix, String nsUri)
156: throws SAXException {
157: writer.startPrefixMapping(prefix, nsUri);
158: }
159: };
160: private final PrefixCallback endPrefixCallback = new PrefixCallback() {
161: public void onPrefixMapping(String prefix, String nsUri)
162: throws SAXException {
163: writer.endPrefixMapping(prefix);
164: }
165: };
166:
167: public void endNamespaceDecls() throws SAXException {
168: nsContext.endNamespaceDecls();
169: }
170:
171: /**
172: * Switches to the "marshal child texts/elements" mode.
173: * This method has to be called after the 1st pass is completed.
174: */
175: public void endAttributes() throws SAXException {
176: // calculate QName of the element
177: String uri = getCurrentElementUri();
178: String local = getCurrentElementLocal();
179:
180: String prefix = nsContext.getPrefix(uri);
181: _assert(prefix != null); // since we've declared it, it should be available
182:
183: String qname;
184: if (prefix.length() != 0)
185: qname = prefix + ':' + local;
186: else
187: qname = local;
188:
189: // fire startPrefixMapping events
190: nsContext.iterateDeclaredPrefixes(startPrefixCallback);
191:
192: // fire the startElement event
193: writer.startElement(uri, local, qname, attributes);
194:
195: // reset attributes
196: attributes.clear();
197:
198: // prepare to collect texts
199: textBuf.setLength(0);
200: }
201:
202: /**
203: * Ends marshalling of an element.
204: * Pops the internal stack.
205: */
206: public void endElement() throws SAXException {
207: writePendingText();
208:
209: String uri = getCurrentElementUri();
210: String local = getCurrentElementLocal();
211:
212: String prefix = nsContext.getPrefix(uri);
213: _assert(prefix != null); // we've declared it earlier.
214:
215: String qname;
216: if (prefix.length() != 0)
217: qname = prefix + ':' + local;
218: else
219: qname = local;
220:
221: writer.endElement(uri, local, qname);
222:
223: // pop namespace bindings and
224: // fire endPrefixMapping events
225: nsContext.iterateDeclaredPrefixes(endPrefixCallback);
226:
227: popElement();
228:
229: // prepare to collect texts
230: textBuf.setLength(0);
231:
232: nsContext.endElement();
233: }
234:
235: /** Buffer for collecting characters. */
236: private final StringBuffer textBuf = new StringBuffer();
237:
238: /**
239: * Marshalls text.
240: *
241: * <p>
242: * This method can be called (i) after the startAttribute method
243: * and (ii) before the endAttribute method, to marshal attribute values.
244: * If the method is called more than once, those texts are considered
245: * as separated by whitespaces. For example,
246: *
247: * <pre>
248: * c.startAttribute();
249: * c.text("abc");
250: * c.text("def");
251: * c.endAttribute("","foo");
252: * </pre>
253: *
254: * will generate foo="abc def".
255: *
256: * <p>
257: * Similarly, this method can be called after the endAttributes
258: * method to marshal texts inside elements. The same rule about
259: * multiple invokations apply to this case, too. For example,
260: *
261: * <pre>
262: * c.startElement("","foo");
263: * c.endAttributes();
264: * c.text("abc");
265: * c.text("def");
266: * c.startElement("","bar");
267: * c.endAttributes();
268: * c.endElement();
269: * c.text("ghi");
270: * c.endElement();
271: * </pre>
272: *
273: * will generate <code><foo>abc def<bar/>ghi</foo></code>.
274: */
275: public void text(String text, String fieldName) throws SAXException {
276: // If the assertion fails, it must be a bug of xjc.
277: // right now, we are not expecting the text method to be called.
278: if (text == null) {
279: reportError(Util.createMissingObjectError(currentTarget,
280: fieldName));
281: return;
282: }
283:
284: if (textBuf.length() != 0)
285: textBuf.append(' ');
286: textBuf.append(text);
287: }
288:
289: /**
290: * Writes pending text (characters inside elements) to the writer.
291: * This method is called from startElement and endElement.
292: */
293: private void writePendingText() throws SAXException {
294: // assert(textBuf!=null);
295: int len = textBuf.length();
296:
297: if (len != 0)
298: writer.characters(textBuf.toString().toCharArray(), 0, len);
299: }
300:
301: /**
302: * Starts marshalling of an attribute.
303: *
304: * The marshalling of an attribute will be done by
305: * <ol>
306: * <li>call the startAttribute method
307: * <li>call the text method (several times if necessary)
308: * <li>call the endAttribute method
309: * </ol>
310: *
311: * No two attributes can be marshalled at the same time.
312: * Note that the whole attribute marshalling must be happened
313: * after the startElement method and before the endAttributes method.
314: */
315: public void startAttribute(String uri, String local) {
316: // initialize the buffer to collect attribute value
317: textBuf.setLength(0);
318:
319: // remember the attribute name. We'll use this value later.
320: this .attNamespaceUri = uri;
321: this .attLocalName = local;
322: }
323:
324: // used to keep attribute names until the endAttribute method is called.
325: private String attNamespaceUri;
326: private String attLocalName;
327:
328: public void endAttribute() {
329: // use CDATA as the attribute type. This preserves
330: // successive processors to collapse whitespaces.
331: // (we cannot prevent characters like #xD to be replaced to
332: // #x20, though).
333: //
334: // strictly speaking, attribute value normalization should be
335: // provessed by XML parser, so it's unclear whether XML writer
336: // uses this type value.
337: //
338: // in any way, CDATA type is the safest choice here.
339:
340: String qname;
341: if (attNamespaceUri.length() == 0) {
342: // default namespace. don't need prefix
343: qname = attLocalName;
344: } else {
345: qname = nsContext.declareNamespace(attNamespaceUri, null,
346: true)
347: + ':' + attLocalName;
348: }
349:
350: attributes.addAttribute(attNamespaceUri, attLocalName, qname,
351: "CDATA", textBuf.toString());
352: }
353:
354: public String onID(IdentifiableObject owner, String value)
355: throws SAXException {
356: objectsWithId.add(owner);
357: return value;
358: }
359:
360: public String onIDREF(IdentifiableObject obj) throws SAXException {
361: idReferencedObjects.add(obj);
362: String id = obj.____jaxb____getId();
363: if (id == null) {
364: reportError(new NotIdentifiableEventImpl(
365: ValidationEvent.ERROR, Messages
366: .format(Messages.ERR_NOT_IDENTIFIABLE),
367: new ValidationEventLocatorImpl(obj)));
368: }
369: return id;
370: }
371:
372: void reconcileID() throws AbortSerializationException {
373: // find objects that were not a part of the object graph
374: idReferencedObjects.removeAll(objectsWithId);
375:
376: for (Iterator itr = idReferencedObjects.iterator(); itr
377: .hasNext();) {
378: IdentifiableObject o = (IdentifiableObject) itr.next();
379: reportError(new NotIdentifiableEventImpl(
380: ValidationEvent.ERROR, Messages.format(
381: Messages.ERR_DANGLING_IDREF, o
382: .____jaxb____getId()),
383: new ValidationEventLocatorImpl(o)));
384: }
385:
386: // clear the garbage
387: idReferencedObjects.clear();
388: objectsWithId.clear();
389: }
390:
391: public void childAsBody(JAXBObject o, String fieldName)
392: throws SAXException {
393: if (o == null) {
394: // if null is passed, it usually means that the content tree object
395: // doesn't have some of its required property.
396: reportMissingObjectError(fieldName);
397: // as a marshaller, we should be generous, so we'll continue to marshal
398: // this document by skipping this missing object.
399: return;
400: }
401:
402: JAXBObject oldTarget = currentTarget;
403: currentTarget = o;
404:
405: owner.context.getGrammarInfo().castToXMLSerializable(o)
406: .serializeBody(this );
407:
408: currentTarget = oldTarget;
409: }
410:
411: public void childAsAttributes(JAXBObject o, String fieldName)
412: throws SAXException {
413: if (o == null) {
414: reportMissingObjectError(fieldName);
415: return;
416: }
417:
418: JAXBObject oldTarget = currentTarget;
419: currentTarget = o;
420:
421: owner.context.getGrammarInfo().castToXMLSerializable(o)
422: .serializeAttributes(this );
423:
424: currentTarget = oldTarget;
425: }
426:
427: public void childAsURIs(JAXBObject o, String fieldName)
428: throws SAXException {
429: if (o == null) {
430: reportMissingObjectError(fieldName);
431: return;
432: }
433:
434: JAXBObject oldTarget = currentTarget;
435: currentTarget = o;
436:
437: owner.context.getGrammarInfo().castToXMLSerializable(o)
438: .serializeURIs(this );
439:
440: currentTarget = oldTarget;
441: }
442:
443: public void reportError(ValidationEvent ve)
444: throws AbortSerializationException {
445: ValidationEventHandler handler;
446:
447: try {
448: handler = owner.getEventHandler();
449: } catch (JAXBException e) {
450: throw new AbortSerializationException(e);
451: }
452:
453: if (!handler.handleEvent(ve)) {
454: if (ve.getLinkedException() instanceof Exception)
455: throw new AbortSerializationException((Exception) ve
456: .getLinkedException());
457: else
458: throw new AbortSerializationException(ve.getMessage());
459: }
460: }
461:
462: public void reportMissingObjectError(String fieldName)
463: throws SAXException {
464: reportError(Util.createMissingObjectError(currentTarget,
465: fieldName));
466: }
467:
468: private static void _assert(boolean b) {
469: if (!b)
470: throw new JAXBAssertionError();
471: }
472:
473: /**
474: * Default {@link NamespacePrefixMapper} implementation used when
475: * it is not specified by the user.
476: */
477: private static NamespacePrefixMapper defaultNamespacePrefixMapper = new NamespacePrefixMapper() {
478: public String getPreferredPrefix(String namespaceUri,
479: String suggestion, boolean requirePrefix) {
480: if (namespaceUri
481: .equals("http://www.w3.org/2001/XMLSchema-instance"))
482: return "xsi";
483: return suggestion;
484: }
485: };
486: }
|