001: //
002: // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v1.0.5-b16-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.12.17 at 09:43:27 AM GMT+07:00
006: //
007:
008: package com.mvnforum.jaxb.db.impl.runtime;
009:
010: import java.util.ArrayList;
011: import java.util.Collections;
012: import java.util.Hashtable;
013: import java.util.Iterator;
014: import java.util.List;
015:
016: import javax.xml.XMLConstants;
017: import javax.xml.bind.JAXBException;
018: import javax.xml.bind.UnmarshalException;
019: import javax.xml.bind.ValidationEvent;
020: import javax.xml.bind.ValidationEventHandler;
021:
022: import org.xml.sax.Attributes;
023: import org.xml.sax.Locator;
024: import org.xml.sax.SAXException;
025: import org.xml.sax.SAXParseException;
026: import org.xml.sax.helpers.LocatorImpl;
027:
028: import com.sun.xml.bind.JAXBAssertionError;
029: import com.sun.xml.bind.unmarshaller.Messages;
030: import com.sun.xml.bind.unmarshaller.Tracer;
031: import com.sun.xml.bind.util.AttributesImpl;
032:
033: /**
034: * Implementation of {@link UnmarshallerHandler}.
035: *
036: * This object converts SAX events into unmarshaller events and
037: * cooridnates the entire unmarshalling process.
038: *
039: * @author
040: * <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI</a>
041: */
042: public class SAXUnmarshallerHandlerImpl implements
043: SAXUnmarshallerHandler, UnmarshallingContext {
044: /**
045: * This flag is set to true at the startDocument event
046: * and false at the endDocument event.
047: *
048: * Until the first document is unmarshalled, we don't
049: * want to return an object. So this variable is initialized
050: * to true.
051: */
052: private boolean isUnmarshalInProgress = true;
053:
054: public SAXUnmarshallerHandlerImpl(UnmarshallerImpl _parent,
055: GrammarInfo _gi) {
056: this .parent = _parent;
057: grammarInfo = _gi;
058: startPrefixMapping("", ""); // by default, the default ns is bound to "".
059: }
060:
061: private final GrammarInfo grammarInfo;
062:
063: public GrammarInfo getGrammarInfo() {
064: return grammarInfo;
065: }
066:
067: /**
068: * Returns true if we should be collecting characters in the current element.
069: */
070: private final boolean shouldCollectText() {
071: return collectText[stackTop];
072: }
073:
074: public void startDocument() throws SAXException {
075: // reset the object
076: result = null;
077: handlerLen = 0;
078: patchers = null;
079: patchersLen = 0;
080: aborted = false;
081: isUnmarshalInProgress = true;
082:
083: stackTop = 0;
084: elementDepth = 1;
085: }
086:
087: public void endDocument() throws SAXException {
088: runPatchers();
089: isUnmarshalInProgress = false;
090: }
091:
092: public void startElement(String uri, String local, String qname,
093: Attributes atts) throws SAXException {
094:
095: // work gracefully with misconfigured parsers that don't support namespaces
096: if (uri == null)
097: uri = "";
098: if (local == null || local.length() == 0)
099: local = qname;
100: if (qname == null || qname.length() == 0)
101: qname = local;
102:
103: if (result == null) {
104: // this is the root element.
105: // create a root object and start unmarshalling
106: UnmarshallingEventHandler unmarshaller = grammarInfo
107: .createUnmarshaller(uri, local, this );
108: if (unmarshaller == null) {
109: // the registry doesn't know about this element.
110: //
111: // the no.1 cause of this problem is that your application is configuring
112: // an XML parser by your self and you forgot to call
113: // the SAXParserFactory.setNamespaceAware(true). When this happens, you see
114: // the namespace URI is reported as empty whereas you expect something else.
115: throw new SAXParseException(Messages.format(
116: Messages.UNEXPECTED_ROOT_ELEMENT2, uri, local,
117: computeExpectedRootElements()), getLocator());
118: }
119: result = unmarshaller.owner();
120:
121: pushContentHandler(unmarshaller, 0);
122: }
123:
124: processText(true);
125:
126: getCurrentHandler().enterElement(uri, local, qname, atts);
127: }
128:
129: public final void endElement(String uri, String local, String qname)
130: throws SAXException {
131:
132: // work gracefully with misconfigured parsers that don't support namespaces
133: if (uri == null)
134: uri = "";
135: if (local == null || local.length() == 0)
136: local = qname;
137: if (qname == null || qname.length() == 0)
138: qname = local;
139:
140: processText(false);
141: getCurrentHandler().leaveElement(uri, local, qname);
142: }
143:
144: /** Root object that is being unmarshalled. */
145: private Object result;
146:
147: public Object getResult() throws UnmarshalException {
148: if (isUnmarshalInProgress)
149: throw new IllegalStateException();
150:
151: if (!aborted)
152: return result;
153:
154: // there was an error.
155: throw new UnmarshalException((String) null);
156: }
157:
158: //
159: //
160: // handler stack maintainance
161: //
162: //
163: private UnmarshallingEventHandler[] handlers = new UnmarshallingEventHandler[16];
164: private int[] mementos = new int[16];
165: private int handlerLen = 0;
166:
167: public void pushContentHandler(UnmarshallingEventHandler handler,
168: int memento) {
169: if (handlerLen == handlers.length) {
170: // expand buffer
171: UnmarshallingEventHandler[] h = new UnmarshallingEventHandler[handlerLen * 2];
172: int[] m = new int[handlerLen * 2];
173: System.arraycopy(handlers, 0, h, 0, handlerLen);
174: System.arraycopy(mementos, 0, m, 0, handlerLen);
175: handlers = h;
176: mementos = m;
177: }
178: handlers[handlerLen] = handler;
179: mementos[handlerLen] = memento;
180: handlerLen++;
181: }
182:
183: public void popContentHandler() throws SAXException {
184: handlerLen--;
185: handlers[handlerLen] = null; // this handler is removed
186: getCurrentHandler().leaveChild(mementos[handlerLen]);
187: }
188:
189: public UnmarshallingEventHandler getCurrentHandler() {
190: return handlers[handlerLen - 1];
191: }
192:
193: //
194: //
195: // text handling
196: //
197: //
198: private StringBuffer buffer = new StringBuffer();
199:
200: protected void consumeText(String str, boolean ignorable)
201: throws SAXException {
202: if (ignorable && str.trim().length() == 0)
203: // if we are allowed to ignore text and
204: // the text is ignorable, ignore.
205: return;
206:
207: // otherwise perform a transition by this token.
208: getCurrentHandler().text(str);
209: }
210:
211: private void processText(boolean ignorable) throws SAXException {
212: if (shouldCollectText())
213: consumeText(buffer.toString(), ignorable);
214:
215: // avoid excessive object allocation, but also avoid
216: // keeping a huge array inside StringBuffer.
217: if (buffer.length() < 1024)
218: buffer.setLength(0);
219: else
220: buffer = new StringBuffer();
221: }
222:
223: public final void characters(char[] buf, int start, int len) {
224: if (shouldCollectText())
225: buffer.append(buf, start, len);
226: }
227:
228: public final void ignorableWhitespace(char[] buf, int start, int len) {
229: characters(buf, start, len);
230: }
231:
232: //
233: //
234: // namespace binding maintainance
235: //
236: //
237: private String[] nsBind = new String[16];
238: private int nsLen = 0;
239:
240: // in the current scope, nsBind[0] - nsBind[idxStack[idxStackTop]-1]
241: // are active.
242: // use {@link #elementDepth} and {@link stackTop} to access.
243: private int[] idxStack = new int[16];
244:
245: public void startPrefixMapping(String prefix, String uri) {
246: if (nsBind.length == nsLen) {
247: // expand the buffer
248: String[] n = new String[nsLen * 2];
249: System.arraycopy(nsBind, 0, n, 0, nsLen);
250: nsBind = n;
251: }
252: nsBind[nsLen++] = prefix;
253: nsBind[nsLen++] = uri;
254: }
255:
256: public void endPrefixMapping(String prefix) {
257: nsLen -= 2;
258: }
259:
260: public String resolveNamespacePrefix(String prefix) {
261: if (prefix.equals("xml"))
262: return "http://www.w3.org/XML/1998/namespace";
263:
264: for (int i = idxStack[stackTop] - 2; i >= 0; i -= 2) {
265: if (prefix.equals(nsBind[i]))
266: return nsBind[i + 1];
267: }
268: return null;
269: }
270:
271: public String[] getNewlyDeclaredPrefixes() {
272: return getPrefixList(idxStack[stackTop - 1]);
273: }
274:
275: public String[] getAllDeclaredPrefixes() {
276: return getPrefixList(2); // skip the default ""->"" mapping
277: }
278:
279: private String[] getPrefixList(int startIndex) {
280: int size = (idxStack[stackTop] - startIndex) / 2;
281: String[] r = new String[size];
282: for (int i = 0; i < r.length; i++)
283: r[i] = nsBind[startIndex + i * 2];
284: return r;
285: }
286:
287: //
288: // NamespaceContext2 implementation
289: //
290: public Iterator getPrefixes(String uri) {
291: // wrap it into unmodifiable list so that the remove method
292: // will throw UnsupportedOperationException.
293: return Collections.unmodifiableList(getAllPrefixesInList(uri))
294: .iterator();
295: }
296:
297: private List getAllPrefixesInList(String uri) {
298: List a = new ArrayList();
299:
300: if (uri.equals(XMLConstants.XML_NS_URI)) {
301: a.add(XMLConstants.XML_NS_PREFIX);
302: return a;
303: }
304: if (uri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
305: a.add(XMLConstants.XMLNS_ATTRIBUTE);
306: return a;
307: }
308: if (uri == null)
309: throw new IllegalArgumentException();
310:
311: for (int i = nsLen - 2; i >= 0; i -= 2)
312: if (uri.equals(nsBind[i + 1]))
313: if (getNamespaceURI(nsBind[i]).equals(nsBind[i + 1]))
314: // make sure that this prefix is still effective.
315: a.add(nsBind[i]);
316:
317: return a;
318: }
319:
320: public String getPrefix(String uri) {
321: if (uri.equals(XMLConstants.XML_NS_URI))
322: return XMLConstants.XML_NS_PREFIX;
323: if (uri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI))
324: return XMLConstants.XMLNS_ATTRIBUTE;
325: if (uri == null)
326: throw new IllegalArgumentException();
327:
328: for (int i = idxStack[stackTop] - 2; i >= 0; i -= 2)
329: if (uri.equals(nsBind[i + 1]))
330: if (getNamespaceURI(nsBind[i]).equals(nsBind[i + 1]))
331: // make sure that this prefix is still effective.
332: return nsBind[i];
333:
334: return null;
335: }
336:
337: public String getNamespaceURI(String prefix) {
338: if (prefix == null)
339: throw new IllegalArgumentException();
340: if (prefix.equals(XMLConstants.XMLNS_ATTRIBUTE))
341: return XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
342:
343: return resolveNamespacePrefix(prefix);
344: }
345:
346: //
347: //
348: // Attribute handling
349: //
350: //
351: /**
352: * Attributes stack.
353: */
354: private AttributesImpl[] attStack = new AttributesImpl[16];
355: /**
356: * Element nesting level.
357: */
358: private int elementDepth;
359: /**
360: * Always {@link #elementDepth}-1.
361: */
362: private int stackTop;
363:
364: /**
365: * Stack of collectText flag.
366: * False means text can be ignored for this element.
367: *
368: * Use {@link #elementDepth} and {@link #stackTop} to access the array.
369: */
370: private boolean[] collectText = new boolean[16];
371:
372: public void pushAttributes(Attributes atts, boolean collectTextFlag) {
373:
374: if (attStack.length == elementDepth) {
375: // reallocate the buffer
376: AttributesImpl[] buf1 = new AttributesImpl[attStack.length * 2];
377: System.arraycopy(attStack, 0, buf1, 0, attStack.length);
378: attStack = buf1;
379:
380: int[] buf2 = new int[idxStack.length * 2];
381: System.arraycopy(idxStack, 0, buf2, 0, idxStack.length);
382: idxStack = buf2;
383:
384: boolean[] buf3 = new boolean[collectText.length * 2];
385: System.arraycopy(collectText, 0, buf3, 0,
386: collectText.length);
387: collectText = buf3;
388: }
389:
390: elementDepth++;
391: stackTop++;
392:
393: // push the stack
394: AttributesImpl a = attStack[stackTop];
395: if (a == null)
396: attStack[stackTop] = a = new AttributesImpl();
397: else
398: a.clear();
399:
400: // since Attributes object is mutable, it is criticall important
401: // to make a copy.
402: // also symbolize attribute names
403: for (int i = 0; i < atts.getLength(); i++) {
404: String auri = atts.getURI(i);
405: String alocal = atts.getLocalName(i);
406: String avalue = atts.getValue(i);
407: String aqname = atts.getQName(i);
408:
409: // work gracefully with misconfigured parsers that don't support namespaces
410: if (auri == null)
411: auri = "";
412: if (alocal == null || alocal.length() == 0)
413: alocal = aqname;
414: if (aqname == null || aqname.length() == 0)
415: aqname = alocal;
416:
417: // <foo xsi:nil="false">some value</foo> is a valid fragment, however
418: // we need a look ahead to correctly handle this case.
419: // (because when we process @xsi:nil, we don't know what the value is,
420: // and by the time we read "false", we can't cancel this attribute anymore.)
421: //
422: // as a quick workaround, we remove @xsi:nil if the value is false.
423: if (auri == "http://www.w3.org/2001/XMLSchema-instance"
424: && alocal == "nil") {
425: String v = avalue.trim();
426: if (v.equals("false") || v.equals("0"))
427: continue; // skip this attribute
428: }
429:
430: // otherwise just add it.
431: a.addAttribute(auri, alocal, aqname, atts.getType(i),
432: avalue);
433: }
434:
435: // start a new namespace scope
436: idxStack[stackTop] = nsLen;
437:
438: collectText[stackTop] = collectTextFlag;
439: }
440:
441: public void popAttributes() {
442: stackTop--;
443: elementDepth--;
444: }
445:
446: public Attributes getUnconsumedAttributes() {
447: return attStack[stackTop];
448: }
449:
450: /**
451: * @param uri,local
452: * has to be interned.
453: */
454: public int getAttribute(String uri, String local) {
455: return attStack[stackTop].getIndexFast(uri, local);
456: }
457:
458: public void consumeAttribute(int idx) throws SAXException {
459: AttributesImpl a = attStack[stackTop];
460:
461: String uri = a.getURI(idx);
462: String local = a.getLocalName(idx);
463: String qname = a.getQName(idx);
464: String value = a.getValue(idx);
465:
466: // mark the attribute as consumed
467: // we need to remove the attribute before we process it
468: // because the event handler might access attributes.
469: a.removeAttribute(idx);
470:
471: getCurrentHandler().enterAttribute(uri, local, qname);
472: consumeText(value, false);
473: getCurrentHandler().leaveAttribute(uri, local, qname);
474: }
475:
476: public String eatAttribute(int idx) throws SAXException {
477: AttributesImpl a = attStack[stackTop];
478:
479: String value = a.getValue(idx);
480:
481: // mark the attribute as consumed
482: a.removeAttribute(idx);
483:
484: return value;
485: }
486:
487: //
488: //
489: // ID/IDREF related code
490: //
491: //
492: /**
493: * Submitted patchers in the order they've submitted.
494: * Many XML vocabulary doesn't use ID/IDREF at all, so we
495: * initialize it with null.
496: */
497: private Runnable[] patchers = null;
498: private int patchersLen = 0;
499:
500: public void addPatcher(Runnable job) {
501: // re-allocate buffer if necessary
502: if (patchers == null)
503: patchers = new Runnable[32];
504: if (patchers.length == patchersLen) {
505: Runnable[] buf = new Runnable[patchersLen * 2];
506: System.arraycopy(patchers, 0, buf, 0, patchersLen);
507: patchers = buf;
508: }
509: patchers[patchersLen++] = job;
510: }
511:
512: /** Executes all the patchers. */
513: private void runPatchers() {
514: if (patchers != null) {
515: for (int i = 0; i < patchersLen; i++)
516: patchers[i].run();
517: }
518: }
519:
520: /** Records ID->Object map. */
521: private Hashtable idmap = null;
522:
523: public String addToIdTable(String id) {
524: if (idmap == null)
525: idmap = new Hashtable();
526: idmap.put(id, getCurrentHandler().owner());
527: return id;
528: }
529:
530: public Object getObjectFromId(String id) {
531: if (idmap == null)
532: return null;
533: return idmap.get(id);
534: }
535:
536: //
537: //
538: // Other SAX callbacks
539: //
540: //
541: public void skippedEntity(String name) {
542: }
543:
544: public void processingInstruction(String target, String data) {
545: // just ignore
546: }
547:
548: public void setDocumentLocator(Locator loc) {
549: locator = loc;
550: }
551:
552: public Locator getLocator() {
553: return locator;
554: }
555:
556: private Locator locator = DUMMY_LOCATOR;
557:
558: private static final Locator DUMMY_LOCATOR = new LocatorImpl();
559:
560: //
561: //
562: // error handling
563: //
564: //
565: private final UnmarshallerImpl parent;
566: private boolean aborted = false;
567:
568: public void handleEvent(ValidationEvent event, boolean canRecover)
569: throws SAXException {
570: ValidationEventHandler eventHandler;
571: try {
572: eventHandler = parent.getEventHandler();
573: } catch (JAXBException e) {
574: // impossible.
575: throw new JAXBAssertionError();
576: }
577:
578: boolean recover = eventHandler.handleEvent(event);
579:
580: // if the handler says "abort", we will not return the object
581: // from the unmarshaller.getResult()
582: if (!recover)
583: aborted = true;
584:
585: if (!canRecover || !recover)
586: throw new SAXException(new UnmarshalException(event
587: .getMessage(), event.getLinkedException()));
588: }
589:
590: //
591: //
592: // ValidationContext implementation
593: //
594: //
595: public String getBaseUri() {
596: return null;
597: }
598:
599: public boolean isUnparsedEntity(String s) {
600: return true;
601: }
602:
603: public boolean isNotation(String s) {
604: return true;
605: }
606:
607: //
608: //
609: // debug trace methods
610: //
611: //
612: private Tracer tracer;
613:
614: public void setTracer(Tracer t) {
615: this .tracer = t;
616: }
617:
618: public Tracer getTracer() {
619: if (tracer == null)
620: tracer = new Tracer.Standard();
621: return tracer;
622: }
623:
624: /**
625: * Computes the names of possible root elements for a better error diagnosis.
626: */
627: private String computeExpectedRootElements() {
628: String r = "";
629:
630: String[] probePoints = grammarInfo.getProbePoints();
631: for (int i = 0; i < probePoints.length; i += 2) {
632: if (grammarInfo.recognize(probePoints[i],
633: probePoints[i + 1])) {
634: if (r.length() != 0)
635: r += ',';
636: r += "<{" + probePoints[i] + "}" + probePoints[i + 1]
637: + ">";
638: }
639: }
640:
641: return r;
642: }
643: }
|