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