KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > xb > binding > sunday > unmarshalling > SundayContentHandler


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.xb.binding.sunday.unmarshalling;
23
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.ListIterator JavaDoc;
28 import javax.xml.namespace.QName JavaDoc;
29 import org.apache.xerces.xs.XSTypeDefinition;
30 import org.jboss.logging.Logger;
31 import org.jboss.util.StringPropertyReplacer;
32 import org.jboss.xb.binding.Constants;
33 import org.jboss.xb.binding.GenericValueContainer;
34 import org.jboss.xb.binding.JBossXBRuntimeException;
35 import org.jboss.xb.binding.NamespaceRegistry;
36 import org.jboss.xb.binding.Util;
37 import org.jboss.xb.binding.group.ValueList;
38 import org.jboss.xb.binding.group.ValueListHandler;
39 import org.jboss.xb.binding.group.ValueListInitializer;
40 import org.jboss.xb.binding.introspection.FieldInfo;
41 import org.jboss.xb.binding.metadata.CharactersMetaData;
42 import org.jboss.xb.binding.metadata.PropertyMetaData;
43 import org.jboss.xb.binding.metadata.ValueMetaData;
44 import org.jboss.xb.binding.parser.JBossXBParser;
45 import org.jboss.xb.binding.sunday.xop.XOPIncludeHandler;
46 import org.xml.sax.Attributes JavaDoc;
47
48 /**
49  * ContentHandler that is used as a sandbox for JBXB-76
50  *
51  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
52  * @version <tt>$Revision: 2141 $</tt>
53  */

54 public class SundayContentHandler
55    implements JBossXBParser.ContentHandler
56 {
57    private final static Logger log = Logger.getLogger(SundayContentHandler.class);
58
59    private final static Object JavaDoc NIL = new Object JavaDoc();
60
61    private final SchemaBinding schema;
62    private final SchemaBindingResolver schemaResolver;
63
64    private final StackImpl stack = new StackImpl();
65
66    private Object JavaDoc root;
67    private NamespaceRegistry nsRegistry = new NamespaceRegistry();
68
69    private ParticleHandler defParticleHandler = DefaultHandlers.ELEMENT_HANDLER;
70
71    private UnmarshallingContextImpl ctx = new UnmarshallingContextImpl();
72
73    private final boolean trace = log.isTraceEnabled();
74
75    public SundayContentHandler(SchemaBinding schema)
76    {
77       this.schema = schema;
78       this.schemaResolver = null;
79    }
80
81    public SundayContentHandler(SchemaBindingResolver schemaResolver)
82    {
83       this.schemaResolver = schemaResolver;
84       this.schema = null;
85    }
86
87    public void characters(char[] ch, int start, int length)
88    {
89       StackItem stackItem = stack.peek();
90       if(stackItem.cursor == null)
91       {
92          if(stackItem.textContent == null)
93          {
94             stackItem.textContent = new StringBuffer JavaDoc();
95          }
96          stackItem.textContent.append(ch, start, length);
97       }
98    }
99
100    public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName)
101    {
102       ElementBinding elementBinding = null;
103       QName JavaDoc endName = localName.length() == 0 ? new QName JavaDoc(qName) : new QName JavaDoc(namespaceURI, localName);
104       StackItem item;
105       while(true)
106       {
107          item = stack.peek();
108          if(item.cursor == null)
109          {
110             if(item.ended)
111             {
112                pop();
113                if(item.particle.isRepeatable())
114                {
115                   endRepeatableParticle(item.particle);
116                }
117             }
118             else
119             {
120                elementBinding = (ElementBinding)item.particle.getTerm();
121                item.ended = true;
122                break;
123             }
124          }
125          else
126          {
127             if(!item.ended) // could be ended if it's a choice
128
{
129                endParticle(item, endName, 1);
130             }
131
132             ParticleBinding currentParticle = item.cursor.getCurrentParticle();
133             TermBinding term = currentParticle.getTerm();
134             if(term.isWildcard() && currentParticle.isRepeatable())
135             {
136                endRepeatableParticle(currentParticle);
137             }
138
139             pop();
140             if(item.particle.isRepeatable())
141             {
142                endRepeatableParticle(item.particle);
143             }
144          }
145       }
146
147       if(elementBinding == null)
148       {
149          throw new JBossXBRuntimeException("Failed to endElement " + qName + ": binding not found");
150       }
151
152       if(!elementBinding.getQName().equals(endName))
153       {
154          throw new JBossXBRuntimeException("Failed to end element " +
155             new QName JavaDoc(namespaceURI, localName) +
156             ": element on the stack is " + elementBinding.getQName()
157          );
158       }
159
160       endElement();
161    }
162
163    public void startElement(String JavaDoc namespaceURI,
164                             String JavaDoc localName,
165                             String JavaDoc qName,
166                             Attributes JavaDoc atts,
167                             XSTypeDefinition xercesType)
168    {
169       QName JavaDoc startName = localName.length() == 0 ? new QName JavaDoc(qName) : new QName JavaDoc(namespaceURI, localName);
170       ParticleBinding particle = null;
171       ParticleHandler handler = null;
172       boolean repeated = false;
173       boolean repeatedParticle = false;
174       StackItem item = null;
175       ModelGroupBinding.Cursor cursor = null; // used only when particle is a wildcard
176
SchemaBinding schemaBinding = schema;
177
178       if(stack.isEmpty())
179       {
180          if(schemaBinding != null)
181          {
182             particle = schemaBinding.getElementParticle(startName);
183          }
184          else if(schemaResolver != null)
185          {
186             String JavaDoc schemaLocation = atts == null ? null : Util.getSchemaLocation(atts, namespaceURI);
187             schemaBinding = schemaResolver.resolve(namespaceURI, null, schemaLocation);
188             if(schemaBinding != null)
189             {
190                particle = schemaBinding.getElementParticle(startName);
191             }
192             else
193             {
194                throw new JBossXBRuntimeException("Failed to resolve schema nsURI=" + namespaceURI + " location=" + schemaLocation);
195             }
196          }
197          else
198          {
199             throw new JBossXBRuntimeException("Neither schema binding nor schema binding resolver is available!");
200          }
201       }
202       else
203       {
204          while(!stack.isEmpty())
205          {
206             item = stack.peek();
207             if(item.cursor == null)
208             {
209                TermBinding term = item.particle.getTerm();
210                ElementBinding element = (ElementBinding)term;
211                if(item.ended)
212                {
213                   if(element.getQName().equals(startName))
214                   {
215                      particle = item.particle;
216                      repeated = true;
217                      item.reset();
218
219                      if(!particle.isRepeatable())
220                      {
221                         endRepeatableParent(startName);
222                      }
223                   }
224                   else
225                   {
226                      pop();
227                      if(item.particle.isRepeatable())
228                      {
229                         endRepeatableParticle(item.particle);
230                      }
231                      continue;
232                   }
233                }
234                else
235                {
236                   ParticleBinding typeParticle = element.getType().getParticle();
237                   ModelGroupBinding modelGroup = typeParticle == null ?
238                      null :
239                      (ModelGroupBinding)typeParticle.getTerm();
240                   if(modelGroup == null)
241                   {
242                      if(startName.equals(Constants.QNAME_XOP_INCLUDE))
243                      {
244                         TypeBinding anyUriType = schema.getType(Constants.QNAME_ANYURI);
245                         if(anyUriType == null)
246                         {
247                            log.warn("Type " + Constants.QNAME_ANYURI + " not bound.");
248                         }
249
250                         TypeBinding xopIncludeType = new TypeBinding(new QName JavaDoc(Constants.NS_XOP_INCLUDE, "Include"));
251                         xopIncludeType.setSchemaBinding(schema);
252                         xopIncludeType.addAttribute(new QName JavaDoc("href"), anyUriType, DefaultHandlers.ATTRIBUTE_HANDLER);
253                         xopIncludeType.setHandler(new XOPIncludeHandler(element.getType(), schema.getXopUnmarshaller()));
254
255                         ElementBinding xopInclude = new ElementBinding(schema, Constants.QNAME_XOP_INCLUDE, xopIncludeType);
256
257                         particle = new ParticleBinding(xopInclude);
258
259                         ElementBinding parentElement = (ElementBinding) item.particle.getTerm();
260                         parentElement.setXopUnmarshaller(schema.getXopUnmarshaller());
261
262                         item.handler = DefaultHandlers.XOP_HANDLER;
263                         item.ignoreCharacters = true;
264                         item.o = item.handler.startParticle(stack.peek().o, startName, stack.peek().particle, null, nsRegistry);
265                         break;
266                      }
267
268                      QName JavaDoc typeName = element.getType().getQName();
269                      throw new JBossXBRuntimeException((typeName == null ? "Anonymous" : typeName.toString()) +
270                         " type of element " +
271                         element.getQName() +
272                         " should be complex and contain " + startName + " as a child element."
273                      );
274                   }
275
276                   cursor = modelGroup.newCursor(typeParticle);
277                   List JavaDoc newCursors = cursor.startElement(startName, atts);
278                   if(newCursors.isEmpty())
279                   {
280                      throw new JBossXBRuntimeException(startName +
281                         " not found as a child of " +
282                         ((ElementBinding)term).getQName()
283                      );
284                   }
285                   else
286                   {
287                      Object JavaDoc o = item.o;
288                      // push all except the last one
289
for(int i = newCursors.size() - 1; i >= 0; --i)
290                      {
291                         cursor = (ModelGroupBinding.Cursor)newCursors.get(i);
292
293                         ParticleBinding modelGroupParticle = cursor.getParticle();
294                         if(modelGroupParticle.isRepeatable())
295                         {
296                            startRepeatableParticle(startName, modelGroupParticle);
297                         }
298
299                         handler = getHandler(modelGroupParticle);
300                         o = handler.startParticle(o, startName, modelGroupParticle, atts, nsRegistry);
301                         push(cursor, o, handler);
302                      }
303                      particle = cursor.getCurrentParticle();
304                   }
305                }
306                break;
307             }
308             else
309             {
310                cursor = item.cursor;
311                if(cursor == null)
312                {
313                   throw new JBossXBRuntimeException("No cursor for " + startName);
314                }
315
316                // todo review
317
if(!item.ended && cursor.isPositioned() && cursor.getParticle().getTerm() instanceof ChoiceBinding)
318                {
319                   endParticle(item, startName, 1);
320                   if(!item.particle.isRepeatable()) // this is for repeatable choices that should stay on the stack
321
{
322                      pop();
323                   }
324                   continue;
325                }
326
327                //int prevOccurence = cursor.getOccurence();
328
ParticleBinding prevParticle = cursor.isPositioned() ? cursor.getCurrentParticle() : null;
329                List JavaDoc newCursors = cursor.startElement(startName, atts);
330                if(newCursors.isEmpty())
331                {
332                   if(!item.ended) // this is for choices
333
{
334                      endParticle(item, startName, 1);
335                   }
336                   pop();
337                }
338                else
339                {
340                   if(item.ended) // for repeatable choices
341
{
342                      if(!item.particle.isRepeatable())
343                      {
344                         throw new JBossXBRuntimeException("The particle expected to be repeatable but it's not: " + item.particle.getTerm());
345                      }
346                      item.reset();
347                      
348                      handler = getHandler(item.particle);
349                      item.o = handler.startParticle(stack.peek(1).o, startName, item.particle, atts, nsRegistry);
350                   }
351                   
352                   ParticleBinding curParticle = cursor.getCurrentParticle();
353                   if(curParticle != prevParticle)
354                   {
355                      if(prevParticle != null && prevParticle.isRepeatable() && prevParticle.getTerm().isModelGroup())
356                      {
357                         endRepeatableParticle(prevParticle);
358                      }
359
360                      if(newCursors.size() > 1 && curParticle.isRepeatable())
361                      {
362                         startRepeatableParticle(startName, curParticle);
363                      }
364                   }
365                   else
366                   {
367                      repeatedParticle = true;
368                   }
369
370                   // push all except the last one
371
Object JavaDoc o = item.o;
372                   for(int i = newCursors.size() - 2; i >= 0; --i)
373                   {
374                      cursor = (ModelGroupBinding.Cursor)newCursors.get(i);
375
376                      ParticleBinding modelGroupParticle = cursor.getParticle();
377                      handler = getHandler(modelGroupParticle);
378                      o = handler.startParticle(o, startName, modelGroupParticle, atts, nsRegistry);
379                      push(cursor, o, handler);
380                   }
381                   cursor = (ModelGroupBinding.Cursor)newCursors.get(0);
382                   particle = cursor.getCurrentParticle();
383                   break;
384                }
385             }
386          }
387       }
388
389       Object JavaDoc o = null;
390       if(particle != null)
391       {
392          Object JavaDoc parent = stack.isEmpty() ? null :
393             (repeated ? stack.peek(1).o : stack.peek().o);
394          if(particle.getTerm() instanceof WildcardBinding)
395          {
396             /*
397             WildcardBinding wildcard = (WildcardBinding)particle.getTerm();
398             ElementBinding element = wildcard.getElement(startName, atts);
399             */

400             ElementBinding element = cursor.getElement();
401             if(element == null)
402             {
403                throw new JBossXBRuntimeException("Failed to resolve element " +
404                   startName + " for wildcard."
405                );
406             }
407
408             if(!repeatedParticle && particle.isRepeatable())
409             {
410                startRepeatableParticle(startName, particle);
411             }
412             particle = new ParticleBinding(element/*, particle.getMinOccurs(), particle.getMaxOccurs(), particle.getMaxOccursUnbounded()*/);
413          }
414
415          ElementBinding element = (ElementBinding)particle.getTerm();
416
417          // todo xsi:type support should be implemented in a better way
418
String JavaDoc xsiType = atts.getValue("xsi:type");
419          if(xsiType != null)
420          {
421             if(trace)
422             {
423                log.trace(element.getQName() + " uses xsi:type " + xsiType);
424             }
425
426             String JavaDoc xsiTypePrefix;
427             String JavaDoc xsiTypeLocal;
428             int colon = xsiType.indexOf(':');
429             if(colon == -1)
430             {
431                xsiTypePrefix = "";
432                xsiTypeLocal = xsiType;
433             }
434             else
435             {
436                xsiTypePrefix = xsiType.substring(0, colon);
437                xsiTypeLocal = xsiType.substring(colon + 1);
438             }
439
440             String JavaDoc xsiTypeNs = nsRegistry.getNamespaceURI(xsiTypePrefix);
441             QName JavaDoc xsiTypeQName = new QName JavaDoc(xsiTypeNs, xsiTypeLocal);
442
443             TypeBinding xsiTypeBinding = schemaBinding.getType(xsiTypeQName);
444             if(xsiTypeBinding == null)
445             {
446                throw new JBossXBRuntimeException("Type binding not found for type " +
447                   xsiTypeQName +
448                   " specified with xsi:type for element " + startName
449                );
450             }
451
452             element = new ElementBinding(schemaBinding, startName, xsiTypeBinding);
453             particle =
454                new ParticleBinding(element,
455                   particle.getMinOccurs(),
456                   particle.getMaxOccurs(),
457                   particle.getMaxOccursUnbounded()
458                );
459          }
460
461          if(!repeated && particle.isRepeatable())
462          {
463             startRepeatableParticle(startName, particle);
464          }
465
466          TypeBinding type = element.getType();
467          if(type == null)
468          {
469             throw new JBossXBRuntimeException("No type for element " + element);
470          }
471
472          handler = type.getHandler();
473          if(handler == null)
474          {
475             handler = defParticleHandler;
476          }
477
478          List JavaDoc interceptors = element.getInterceptors();
479          if(!interceptors.isEmpty())
480          {
481             if (repeated)
482             {
483                pop();
484             }
485
486             for (int i = 0; i < interceptors.size(); ++i)
487             {
488                ElementInterceptor interceptor = (ElementInterceptor) interceptors.get(i);
489                parent = interceptor.startElement(parent, startName, type);
490                push(startName, particle, parent, handler);
491                interceptor.attributes(parent, startName, type, atts, nsRegistry);
492             }
493
494             if (repeated)
495             {
496                // to have correct endRepeatableParticle calls
497
stack.push(item);
498             }
499          }
500
501          String JavaDoc nil = atts.getValue("xsi:nil");
502          if(nil == null || !("1".equals(nil) || "true".equals(nil)))
503          {
504             o = handler.startParticle(parent, startName, particle, atts, nsRegistry);
505          }
506          else
507          {
508             o = NIL;
509          }
510       }
511       else
512       {
513          ElementBinding parentBinding = null;
514          if(!stack.isEmpty())
515          {
516             ParticleBinding stackParticle = repeated ? stack.peek(1).particle : stack.peek().particle;
517             if(stackParticle != null)
518             {
519                parentBinding = (ElementBinding)stackParticle.getTerm();
520             }
521          }
522
523          if(parentBinding != null && parentBinding.getSchema() != null)
524          {
525             schemaBinding = parentBinding.getSchema();
526          }
527
528          String JavaDoc msg = "Element " +
529             startName +
530             " is not bound " +
531             (parentBinding == null ? "as a global element." : "in type " + parentBinding.getType().getQName());
532          if(schemaBinding != null && schemaBinding.isStrictSchema())
533          {
534             throw new JBossXBRuntimeException(msg);
535          }
536          else if(trace)
537          {
538             log.trace(msg);
539          }
540       }
541
542       if(repeated)
543       {
544          item.o = o;
545       }
546       else
547       {
548          push(startName, particle, o, handler);
549       }
550    }
551
552    private ParticleHandler getHandler(ParticleBinding modelGroupParticle)
553    {
554       ParticleHandler handler = ((ModelGroupBinding)modelGroupParticle.getTerm()).getHandler();
555       return handler == null ? defParticleHandler : handler;
556    }
557
558    private void endRepeatableParent(QName JavaDoc startName)
559    {
560       int parentPos = 1;
561       StackItem parentItem;
562       ParticleBinding parentParticle = null;
563       while(true)
564       {
565          parentItem = stack.peek(parentPos);
566          if(parentItem.cursor == null)
567          {
568             throw new JBossXBRuntimeException(
569                "Failed to start " + startName +
570                ": the element is not repeatable, repeatable parent expected to be a model group but got element " +
571                ((ElementBinding)parentItem.particle.getTerm()).getQName()
572             );
573          }
574
575          parentParticle = parentItem.particle;
576          if(parentParticle.isRepeatable())
577          {
578             break;
579          }
580
581          endParticle(parentItem, startName, ++parentPos);
582       }
583
584       if(!parentParticle.isRepeatable())
585       {
586          StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
587
588          StackItem item = stack.peek();
589          ParticleBinding currentParticle = item.particle;
590          msg.append("Failed to start ").append(startName).append(": ")
591             .append(currentParticle.getTerm())
592             .append(" is not repeatable.")
593             .append(" Its parent ")
594             .append(parentParticle.getTerm())
595             .append(" expected to be repeatable!")
596             .append("\ncurrent stack: ");
597
598          for(int i = stack.size() - 1; i >= 0; --i)
599          {
600             item = stack.peek(i);
601             ParticleBinding particle = item.particle;
602             TermBinding term = particle.getTerm();
603             if(term.isModelGroup())
604             {
605                if(term instanceof SequenceBinding)
606                {
607                   msg.append("sequence");
608                }
609                else if(term instanceof ChoiceBinding)
610                {
611                   msg.append("choice");
612                }
613                else
614                {
615                   msg.append("all");
616                }
617             }
618             else if(term.isWildcard())
619             {
620                msg.append("wildcard");
621             }
622             else
623             {
624                msg.append(((ElementBinding)term).getQName());
625             }
626             msg.append("\\");
627          }
628
629          throw new JBossXBRuntimeException(msg.toString());
630       }
631
632       // todo startName is wrong here
633
endParticle(parentItem, startName, parentPos + 1);
634
635       parentItem = stack.peek(parentPos + 1);
636       while(parentPos > 0)
637       {
638          StackItem item = stack.peek(parentPos--);
639          ParticleHandler handler = getHandler(item.particle);
640          item.reset();
641          item.o = handler.startParticle(parentItem.o, startName, item.particle, null, nsRegistry);
642          parentItem = item;
643       }
644    }
645
646    private void startRepeatableParticle(QName JavaDoc startName, ParticleBinding particle)
647    {
648       //System.out.println(" start repeatable (" + stack.size() + "): " + particle.getTerm());
649

650       TermBinding term = particle.getTerm();
651       if(term.isSkip())
652       {
653          return;
654       }
655       
656       StackItem item = stack.peek();
657       if(item.o != null &&
658             !(item.o instanceof GenericValueContainer) &&
659             term.getAddMethodMetaData() == null &&
660             term.getMapEntryMetaData() == null &&
661             term.getPutMethodMetaData() == null)
662       {
663          ValueListHandler handler = ValueListHandler.FACTORY.lazy(item.o);
664          Class JavaDoc cls = item.o.getClass();
665          item.repeatableParticleValue = new ValueListInitializer().newValueList(handler, cls);
666       }
667    }
668
669    private void endRepeatableParticle(ParticleBinding particle)
670    {
671       //System.out.println(" end repeatable (" + stack.size() + "): " + particle.getTerm());
672

673       StackItem item = stack.peek();
674       ValueList valueList = item.repeatableParticleValue;
675       if(valueList != null)
676       {
677          item.repeatableParticleValue = null;
678          if(valueList.size() == 0)
679          {
680             return;
681          }
682             
683          if(particle.getTerm().isWildcard())
684          {
685             ParticleHandler handler = ((WildcardBinding)particle.getTerm()).getWildcardHandler();
686             if(handler == null)
687             {
688                handler = defParticleHandler;
689             }
690
691             // that's not good. some elements can be handled as "unresolved" and some as "resolved"
692
QName JavaDoc qName = valueList.getValue(0).qName;
693             Collection JavaDoc col = new ArrayList JavaDoc();
694             for(int i = 0; i < valueList.size(); ++i)
695             {
696                col.add(valueList.getValue(i).value);
697             }
698             StackItem parentItem = stack.peek(1);
699             handler.setParent(parentItem.o, col, qName, particle, parentItem.particle);
700          }
701          else
702          {
703             valueList.getHandler().newInstance(particle, valueList);
704          }
705       }
706    }
707
708    private void endParticle(StackItem item, QName JavaDoc qName, int parentStackPos)
709    {
710       if(item.ended)
711       {
712          throw new JBossXBRuntimeException(item.particle.getTerm() + " has already been ended.");
713       }
714
715       ParticleBinding modelGroupParticle = item.particle;
716       ParticleHandler handler = item.handler;//getHandler(modelGroupParticle);
717

718       Object JavaDoc o;
719       if(item.o instanceof ValueList && !modelGroupParticle.getTerm().isSkip())
720       {
721          if(trace)
722          {
723             log.trace("endParticle " + modelGroupParticle.getTerm() + " valueList");
724          }
725          ValueList valueList = (ValueList)item.o;
726          o = valueList.getHandler().newInstance(modelGroupParticle, valueList);
727       }
728       else
729       {
730          o = handler.endParticle(item.o, qName, modelGroupParticle);
731       }
732
733       item.ended = true;
734
735       // model group should always have parent particle
736
item = (StackItem)stack.peek(parentStackPos);
737       if(item.o != null)
738       {
739          ParticleBinding parentParticle = getParentParticle();//item.particle;
740
if(parentParticle == null)
741          {
742             parentParticle = item.particle;
743          }
744          setParent(handler,
745                item.repeatableParticleValue == null ? item.o : item.repeatableParticleValue,
746                o, qName, modelGroupParticle, parentParticle);
747       }
748    }
749
750    public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
751    {
752       nsRegistry.addPrefixMapping(prefix, uri);
753    }
754
755    public void endPrefixMapping(String JavaDoc prefix)
756    {
757       nsRegistry.removePrefixMapping(prefix);
758    }
759
760    public void processingInstruction(String JavaDoc target, String JavaDoc data)
761    {
762    }
763
764    public Object JavaDoc getRoot()
765    {
766       return root;
767    }
768
769    // Private
770

771    private ParticleBinding getParentParticle()
772    {
773       ListIterator JavaDoc iter = stack.prevIterator();
774       while(iter.hasPrevious())
775       {
776          StackItem prev = (StackItem)iter.previous();
777          ParticleBinding peeked = prev.particle;
778
779          TermBinding term = peeked.getTerm();
780          if(!term.isSkip())
781          {
782             return peeked;
783          }
784       }
785       return null;
786    }
787
788    private void endElement()
789    {
790       StackItem item = stack.peek();
791       Object JavaDoc o = item.o;
792       ParticleBinding particle = item.particle;
793       
794       ElementBinding element = (ElementBinding)particle.getTerm();
795       QName JavaDoc endName = element.getQName();
796       TypeBinding type = element.getType();
797       List JavaDoc interceptors = element.getInterceptors();
798       int interceptorsTotal = interceptors.size();
799
800       if(o != NIL)
801       {
802          //
803
// characters
804
//
805

806          TypeBinding charType = type.getSimpleType();
807          if(charType == null)
808          {
809             charType = type;
810          }
811
812          CharactersHandler charHandler = item.ignoreCharacters ? null : charType.getCharactersHandler();
813
814          /**
815           * If there is text content then unmarshal it and set.
816           * If there is no text content and the type is simple and
817           * its characters handler is not null then unmarshal and set.
818           * If the type is complex and there is no text data then the unmarshalled value
819           * of the empty text content is assumed to be null
820           * (in case of simple types that's not always true and depends on nillable attribute).
821           */

822          String JavaDoc textContent = item.textContent == null ? "" : item.textContent.toString();
823          if(textContent.length() > 0 || charHandler != null && type.isSimple())
824          {
825             String JavaDoc dataContent;
826             SchemaBinding schema = element.getSchema();
827             if(textContent.length() == 0)
828             {
829                dataContent = null;
830             }
831             else
832             {
833                dataContent = textContent.toString();
834                if(schema != null && schema.isReplacePropertyRefs())
835                {
836                   dataContent = StringPropertyReplacer.replaceProperties(dataContent);
837                }
838             }
839
840             Object JavaDoc unmarshalled;
841
842             if(charHandler == null)
843             {
844                if(!type.isSimple() &&
845                   schema != null &&
846                   schema.isStrictSchema()
847                   // todo this isSkip() doesn't look nice here
848
&& !element.isSkip())
849                {
850                   throw new JBossXBRuntimeException("Element " +
851                      endName +
852                      " with type binding " +
853                      type.getQName() +
854                      " does not include text content binding: " + dataContent
855                   );
856                }
857                unmarshalled = dataContent;
858             }
859             else
860             {
861                ValueMetaData valueMetaData = element.getValueMetaData();
862                if(valueMetaData == null)
863                {
864                   CharactersMetaData charactersMetaData = type.getCharactersMetaData();
865                   if(charactersMetaData != null)
866                   {
867                      valueMetaData = charactersMetaData.getValue();
868                   }
869                }
870
871                // todo valueMetaData is available from type
872
unmarshalled = dataContent == null ?
873                   charHandler.unmarshalEmpty(endName, charType, nsRegistry, valueMetaData) :
874                   charHandler.unmarshal(endName, charType, nsRegistry, valueMetaData, dataContent);
875             }
876
877             if(unmarshalled != null)
878             {
879                // if startElement returned null, we use characters as the object for this element
880
if(o == null)
881                {
882                   o = unmarshalled;
883                }
884                else if(charHandler != null)
885                {
886                   TermBeforeSetParentCallback beforeSetParent = charType.getBeforeSetParentCallback();
887                   if(beforeSetParent != null)
888                   {
889                      ctx.parent = o;
890                      ctx.particle = particle;
891                      ctx.parentParticle = getParentParticle();
892                      unmarshalled = beforeSetParent.beforeSetParent(unmarshalled, ctx);
893                      ctx.clear();
894                   }
895
896                   if(o instanceof ValueList)
897                   {
898                      ValueList valueList = (ValueList)o;
899                      if(type.isSimple())
900                      {
901                         valueList.getInitializer().addTermValue(endName,
902                            particle,
903                            charHandler,
904                            valueList,
905                            unmarshalled,
906                            null
907                         );
908                      }
909                      else
910                      {
911                         valueList.getInitializer().addTextValue(endName,
912                            particle,
913                            charHandler,
914                            valueList,
915                            unmarshalled
916                         );
917                      }
918                   }
919                   else
920                   {
921                      charHandler.setValue(endName, element, o, unmarshalled);
922                   }
923                }
924             }
925
926             for(int i = interceptorsTotal - 1; i >= 0; --i)
927             {
928                ElementInterceptor interceptor = (ElementInterceptor)interceptors.get(i);
929                interceptor.characters(((StackItem)stack.peek(interceptorsTotal - i)).o,
930                   endName, type, nsRegistry, dataContent
931                );
932             }
933          }
934       }
935       else
936       {
937          o = null;
938       }
939
940       //
941
// endElement
942
//
943

944       StackItem parentItem = stack.size() == 1 ? null : stack.peek(1);
945       Object JavaDoc parent = parentItem == null ? null : parentItem.o;
946       ParticleHandler handler = stack.peek().handler;
947       
948       if(o instanceof ValueList && !particle.getTerm().isSkip())
949       {
950          if(trace)
951          {
952             log.trace("endParticle " + endName + " valueList");
953          }
954          ValueList valueList = (ValueList)o;
955          o = valueList.getHandler().newInstance(particle, valueList);
956       }
957       else
958       {
959          o = handler.endParticle(o, endName, particle);
960       }
961
962       for(int i = interceptorsTotal - 1; i >= 0; --i)
963       {
964          ElementInterceptor interceptor = (ElementInterceptor)interceptors.get(i);
965          interceptor.endElement(((StackItem)stack.peek(interceptorsTotal - i)).o, endName, type);
966       }
967
968       //
969
// setParent
970
//
971

972       if(interceptorsTotal == 0)
973       {
974          ParticleBinding parentParticle = getParentParticle();
975          boolean hasWildcard = false;
976          ParticleHandler wildcardHandler = null;
977
978          if (parentParticle != null && parentParticle.getTerm().isElement())
979          {
980             WildcardBinding wildcard = ((ElementBinding) parentParticle.getTerm()).getType().getWildcard();
981             if (wildcard != null)
982             {
983                hasWildcard = true;
984                wildcardHandler = wildcard.getWildcardHandler();
985             }
986          }
987
988          if(parent != null)
989          {
990             /*if(o == null)
991             {
992                throw new JBossXBRuntimeException(endName + " is null!");
993             } */

994             if(wildcardHandler != null)
995             {
996                setParent(wildcardHandler,
997                      parentItem.repeatableParticleValue == null ? parent : parentItem.repeatableParticleValue,
998                      o, endName, particle, parentParticle);
999             }
1000            else
1001            {
1002               setParent(handler,
1003                     parentItem.repeatableParticleValue == null ? parent : parentItem.repeatableParticleValue,
1004                     o, endName, particle, parentParticle);
1005            }
1006         }
1007         else if(parentParticle != null && hasWildcard && stack.size() > 1)
1008         {
1009            // the parent has anyType, so it gets the value of its child
1010
ListIterator JavaDoc iter = stack.prevIterator();
1011            while(iter.hasPrevious())
1012            {
1013               StackItem peeked = (StackItem)iter.previous();
1014               peeked.o = o;
1015               if(peeked.cursor == null)
1016               {
1017                  break;
1018               }
1019            }
1020
1021            if(trace)
1022            {
1023               log.trace("Value of " + endName + " " + o + " is promoted as the value of its parent element.");
1024            }
1025         }
1026      }
1027      else
1028      {
1029         StackItem popped = pop();
1030         for(int i = interceptorsTotal - 1; i >= 0; --i)
1031         {
1032            ElementInterceptor interceptor = (ElementInterceptor)interceptors.get(i);
1033            parent = pop().o;
1034            interceptor.add(parent, o, endName);
1035            o = parent;
1036         }
1037         // need to have correst endRepeatableParticle events
1038
stack.push(popped);
1039      }
1040
1041      if(stack.size() == 1)
1042      {
1043         root = o;
1044         stack.clear();
1045      }
1046   }
1047
1048   private void setParent(ParticleHandler handler,
1049                          Object JavaDoc parent,
1050                          Object JavaDoc o,
1051                          QName JavaDoc endName,
1052                          ParticleBinding particle,
1053                          ParticleBinding parentParticle)
1054   {
1055      TermBeforeSetParentCallback beforeSetParent = particle.getTerm().getBeforeSetParentCallback();
1056      if(beforeSetParent != null)
1057      {
1058         ctx.parent = parent;
1059         ctx.particle = particle;
1060         ctx.parentParticle = parentParticle;
1061         o = beforeSetParent.beforeSetParent(o, ctx);
1062         ctx.clear();
1063      }
1064
1065      if(parent instanceof ValueList /*&& !particle.getTerm().isSkip()*/)
1066      {
1067         if(parent == o)
1068         {
1069            return;
1070         }
1071         ValueList valueList = (ValueList)parent;
1072         valueList.getInitializer().addTermValue(endName, particle, handler, valueList, o, parentParticle);
1073      }
1074      else
1075      {
1076         handler.setParent(parent, o, endName, particle, parentParticle);
1077      }
1078   }
1079
1080   private void push(QName JavaDoc qName, ParticleBinding particle, Object JavaDoc o, ParticleHandler handler)
1081   {
1082      StackItem item = new StackItem(particle, o, handler);
1083      stack.push(item);
1084      if(trace)
1085      {
1086         Object JavaDoc binding = null;
1087         if(particle != null)
1088         {
1089            binding = particle.getTerm();
1090         }
1091         log.trace("pushed " + qName + "=" + o + ", binding=" + binding);
1092      }
1093   }
1094
1095   private void push(ModelGroupBinding.Cursor cursor, Object JavaDoc o, ParticleHandler handler)
1096   {
1097      StackItem item = new StackItem(cursor, o, handler);
1098      stack.push(item);
1099      if(trace)
1100      {
1101         log.trace("pushed cursor " + cursor + ", o=" + o);
1102      }
1103   }
1104
1105   private StackItem pop()
1106   {
1107      StackItem item = stack.pop();
1108      if(trace)
1109      {
1110         if(item.cursor == null)
1111         {
1112            log.trace("poped " + ((ElementBinding)item.particle.getTerm()).getQName() + "=" + item.particle);
1113         }
1114         else
1115         {
1116            log.trace("poped " + item.cursor.getCurrentParticle().getTerm());
1117         }
1118      }
1119      return item;
1120   }
1121
1122   // Inner
1123

1124   private static class StackItem
1125   {
1126      final ModelGroupBinding.Cursor cursor;
1127      final ParticleBinding particle;
1128      ParticleHandler handler;
1129      boolean ignoreCharacters;
1130      Object JavaDoc o;
1131      ValueList repeatableParticleValue;
1132      StringBuffer JavaDoc textContent;
1133      boolean ended;
1134
1135      public StackItem(ModelGroupBinding.Cursor cursor, Object JavaDoc o, ParticleHandler handler)
1136      {
1137         if (cursor == null)
1138            throw new IllegalArgumentException JavaDoc("Null cursor");
1139         // this is modelgroup particle
1140
this.cursor = cursor;
1141         this.particle = cursor.getParticle();
1142         this.o = o;
1143         this.handler = handler;
1144      }
1145
1146      public StackItem(ParticleBinding particle, Object JavaDoc o, ParticleHandler handler)
1147      {
1148         if (particle == null)
1149            throw new IllegalArgumentException JavaDoc("Null particle");
1150         // this is element particle
1151
this.cursor = null;
1152         this.particle = particle;
1153         this.o = o;
1154         this.handler = handler;
1155      }
1156
1157      void reset()
1158      {
1159         if(!ended)
1160         {
1161            throw new JBossXBRuntimeException(
1162               "Attempt to reset a particle that has already been reset: " + particle.getTerm()
1163            );
1164         }
1165
1166         ended = false;
1167         o = null;
1168         if(textContent != null)
1169         {
1170            textContent.delete(0, textContent.length());
1171         }
1172      }
1173   }
1174
1175   static class StackImpl
1176   {
1177      private List JavaDoc list = new ArrayList JavaDoc();
1178
1179      public void clear()
1180      {
1181         list.clear();
1182      }
1183
1184      public void push(Object JavaDoc o)
1185      {
1186         list.add(o);
1187      }
1188
1189      public StackItem pop()
1190      {
1191         return (StackItem)list.remove(list.size() - 1);
1192      }
1193
1194      public ListIterator JavaDoc prevIterator()
1195      {
1196         return list.listIterator(list.size() - 1);
1197      }
1198
1199      public StackItem peek()
1200      {
1201         return (StackItem)list.get(list.size() - 1);
1202      }
1203
1204      public StackItem peek(int i)
1205      {
1206         return (StackItem)list.get(list.size() - 1 - i);
1207      }
1208
1209      public boolean isEmpty()
1210      {
1211         return list.isEmpty();
1212      }
1213
1214      public int size()
1215      {
1216         return list.size();
1217      }
1218   }
1219
1220   private class UnmarshallingContextImpl implements UnmarshallingContext
1221   {
1222      Object JavaDoc parent;
1223      ParticleBinding particle;
1224      ParticleBinding parentParticle;
1225      
1226      public Object JavaDoc getParentValue()
1227      {
1228         return parent;
1229      }
1230      
1231      public ParticleBinding getParticle()
1232      {
1233         return particle;
1234      }
1235      
1236      public ParticleBinding getParentParticle()
1237      {
1238         return parentParticle;
1239      }
1240      
1241      public String JavaDoc resolvePropertyName()
1242      {
1243         TermBinding term = particle.getTerm();
1244         PropertyMetaData propertyMetaData = term.getPropertyMetaData();
1245         String JavaDoc prop = propertyMetaData == null ? null : propertyMetaData.getName();
1246         
1247         if(prop != null)
1248         {
1249            return prop;
1250         }
1251         
1252         if(term.isElement())
1253         {
1254            QName JavaDoc name = ((ElementBinding)term).getQName();
1255            prop = Util.xmlNameToFieldName(name.getLocalPart(), term.getSchema().isIgnoreLowLine());
1256         }
1257         
1258         return prop;
1259      }
1260
1261      public Class JavaDoc resolvePropertyType()
1262      {
1263         if(parent == null)
1264         {
1265            return null;
1266         }
1267         
1268         String JavaDoc prop = resolvePropertyName();
1269         if(prop != null)
1270         {
1271            FieldInfo fieldInfo = FieldInfo.getFieldInfo(parent.getClass(), prop, false);
1272            if (fieldInfo != null)
1273            {
1274               return fieldInfo.getType();
1275            }
1276         }
1277         return null;
1278      }
1279      
1280      // private
1281

1282      void clear()
1283      {
1284         ctx.parent = null;
1285         ctx.particle = null;
1286         ctx.parentParticle = null;
1287      }
1288   }
1289}
1290
Popular Tags