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