KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > xb > binding > ObjectModelBuilder


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;
23
24 import org.xml.sax.Attributes JavaDoc;
25 import org.jboss.logging.Logger;
26 import org.jboss.xb.binding.parser.JBossXBParser;
27 import org.apache.xerces.xs.XSTypeDefinition;
28
29 import javax.xml.namespace.QName JavaDoc;
30 import javax.xml.namespace.NamespaceContext JavaDoc;
31 import java.util.Map JavaDoc;
32 import java.util.HashMap JavaDoc;
33 import java.util.Collections JavaDoc;
34 import java.util.StringTokenizer JavaDoc;
35 import java.util.Iterator JavaDoc;
36 import java.util.List JavaDoc;
37 import java.util.ArrayList JavaDoc;
38 import java.lang.reflect.InvocationTargetException JavaDoc;
39 import java.lang.reflect.Method JavaDoc;
40
41 /**
42  * An instance of this class translates SAX events into org.jboss.xml.binding.GenericObjectModelFactory calls
43  * such as newChild, addChild and setValue.
44  * WARN: this implementation is not thread-safe!
45  *
46  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
47  * @version <tt>$Revision: 1958 $</tt>
48  */

49 public class ObjectModelBuilder
50    implements UnmarshallingContext, JBossXBParser.ContentHandler
51 {
52    /**
53     * logger
54     */

55    private static final Logger log = Logger.getLogger(ObjectModelBuilder.class);
56
57    /**
58     * The object that represents an ignored by the object model factory XML element, i.e. the factory returned null
59     * from its newChild method
60     */

61    private static final Object JavaDoc IGNORED = new Object JavaDoc();
62
63    /**
64     * The root of the unmarshalled object graph
65     */

66    private Object JavaDoc root;
67
68    /**
69     * the stack of all the objects including IGNORED
70     */

71    private Stack all = new StackImpl();
72
73    /**
74     * the stack of only accepted objects (all - IGNORED)
75     */

76    private Stack accepted = new StackImpl();
77
78    private GenericObjectModelFactory curFactory;
79    private String JavaDoc curNameSwitchingFactory;
80    private String JavaDoc curNsSwitchingFactory;
81    private Stack nameSwitchingFactory;
82    private Stack nsSwitchingFactory;
83
84    /**
85     * default object model factory
86     */

87    private GenericObjectModelFactory defaultFactory;
88
89    /**
90     * factories mapped to namespace URIs
91     */

92    private Map JavaDoc factoriesToNs = Collections.EMPTY_MAP;
93
94    /**
95     * NamespaceContext implementation
96     */

97    private final NamespaceRegistry nsRegistry = new NamespaceRegistry();
98
99    private XSTypeDefinition currentType;
100
101    private boolean trace = log.isTraceEnabled();
102
103    // Public
104

105    public void mapFactoryToNamespace(ObjectModelFactory factory, String JavaDoc namespaceUri)
106    {
107       if(factoriesToNs == Collections.EMPTY_MAP)
108       {
109          factoriesToNs = new HashMap JavaDoc();
110       }
111       factoriesToNs.put(namespaceUri, getGenericObjectModelFactory(factory));
112    }
113
114    public void init(ObjectModelFactory defaultFactory, Object JavaDoc root)
115    {
116       this.defaultFactory = getGenericObjectModelFactory(defaultFactory);
117       all.clear();
118       accepted.clear();
119       this.root = root;
120    }
121
122    public void pushFactory(String JavaDoc namespaceURI, String JavaDoc localName, GenericObjectModelFactory factory)
123    {
124       if(curNsSwitchingFactory != null)
125       {
126          if(nsSwitchingFactory == null)
127          {
128             nsSwitchingFactory = new StackImpl();
129             nameSwitchingFactory = new StackImpl();
130          }
131          nsSwitchingFactory.push(curNsSwitchingFactory);
132          nameSwitchingFactory.push(curNameSwitchingFactory);
133       }
134       curNsSwitchingFactory = namespaceURI;
135       curNameSwitchingFactory = localName;
136       curFactory = factory;
137    }
138
139    public void popFactory()
140    {
141       if(nsSwitchingFactory == null || nsSwitchingFactory.isEmpty())
142       {
143          curNameSwitchingFactory = null;
144          curNsSwitchingFactory = null;
145       }
146       else
147       {
148          curNameSwitchingFactory = (String JavaDoc)nameSwitchingFactory.pop();
149          curNsSwitchingFactory = (String JavaDoc)nsSwitchingFactory.pop();
150       }
151
152       curFactory = getFactory(curNsSwitchingFactory);
153    }
154
155    // UnmarshallingContext implementation
156

157    public Iterator JavaDoc getNamespaceURIs()
158    {
159       return nsRegistry.getRegisteredURIs();
160    }
161
162    public NamespaceContext JavaDoc getNamespaceContext()
163    {
164       return nsRegistry;
165    }
166
167    /**
168     * Construct a QName from a value
169     *
170     * @param value A value that is of the form [prefix:]localpart
171     */

172    public QName JavaDoc resolveQName(String JavaDoc value)
173    {
174       StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(value, ":");
175       if(st.countTokens() == 1)
176          return new QName JavaDoc(value);
177
178       if(st.countTokens() != 2)
179          throw new IllegalArgumentException JavaDoc("Illegal QName: " + value);
180
181       String JavaDoc prefix = st.nextToken();
182       String JavaDoc local = st.nextToken();
183       String JavaDoc nsURI = nsRegistry.getNamespaceURI(prefix);
184       if (nsURI == null)
185          throw new IllegalStateException JavaDoc("Cannot obtain namespace URI for prefix: " + prefix);
186
187       return new QName JavaDoc(nsURI, local, prefix);
188    }
189
190    public String JavaDoc getChildContent(String JavaDoc namespaceURI, String JavaDoc qName)
191    {
192       // todo reimplement later
193
throw new UnsupportedOperationException JavaDoc();
194       //return content.getChildContent(namespaceURI, qName);
195
}
196
197    public XSTypeDefinition getType()
198    {
199       return currentType;
200    }
201
202    // Public
203

204    public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
205    {
206       nsRegistry.addPrefixMapping(prefix, uri);
207    }
208
209    public void endPrefixMapping(String JavaDoc prefix)
210    {
211       nsRegistry.removePrefixMapping(prefix);
212    }
213
214    public void processingInstruction(String JavaDoc target, String JavaDoc data)
215    {
216       if(!"jbossxb".equals(target))
217       {
218          return;
219       }
220
221       int i = data.indexOf("factory=\"");
222       if(i != -1)
223       {
224          int end = data.indexOf('\"', i + 9);
225          if(end == -1)
226          {
227             throw new JBossXBRuntimeException(
228                "Property 'factory' is not terminated with '\"' in processing instruction: " + data
229             );
230          }
231
232          String JavaDoc factoryProp = data.substring(i + 9, end);
233          Class JavaDoc factoryCls;
234          try
235          {
236             factoryCls = Thread.currentThread().getContextClassLoader().loadClass(factoryProp);
237          }
238          catch(ClassNotFoundException JavaDoc e)
239          {
240             throw new JBossXBRuntimeException("Failed to load factory class : " + e.getMessage(), e);
241          }
242
243          ObjectModelFactory factory;
244          try
245          {
246             factory = (ObjectModelFactory)factoryCls.newInstance();
247          }
248          catch(Exception JavaDoc e)
249          {
250             throw new JBossXBRuntimeException("Failed to instantiate factory " + factoryProp + ": " + e.getMessage(),
251                e
252             );
253          }
254
255          i = data.indexOf("ns=\"");
256          if(i == -1)
257          {
258             throw new JBossXBRuntimeException(
259                "Property 'ns' not found in factory mapping processing instruction: " + data
260             );
261          }
262
263          end = data.indexOf("\"", i + 4);
264          if(end == -1)
265          {
266             throw new JBossXBRuntimeException(
267                "Property 'ns' is not terminated with '\"' in processing instruction: " + data
268             );
269          }
270
271          String JavaDoc nsProp = data.substring(i + 4, end);
272          mapFactoryToNamespace(factory, nsProp);
273       }
274       else
275       {
276          throw new JBossXBRuntimeException(
277             "Unexpected data in processing instruction: target=" + target + ", data=" + data
278          );
279       }
280    }
281
282    public Object JavaDoc getRoot()
283    {
284       if(!all.isEmpty())
285       {
286          popAll();
287          popAccepted();
288       }
289       return root;
290    }
291
292    public void startElement(String JavaDoc namespaceURI,
293                             String JavaDoc localName,
294                             String JavaDoc qName,
295                             Attributes JavaDoc atts,
296                             XSTypeDefinition type)
297    {
298       Object JavaDoc parent = accepted.isEmpty() ? root : peekAccepted();
299
300       // todo currentType assignment
301
currentType = type;
302
303       Object JavaDoc element;
304       if(!namespaceURI.equals(curNsSwitchingFactory))
305       {
306          GenericObjectModelFactory newFactory = getFactory(namespaceURI);
307          if(newFactory != curFactory)
308          {
309             element = newFactory.newRoot(parent, this, namespaceURI, localName, atts);
310          }
311          else
312          {
313             element = newFactory.newChild(parent, this, namespaceURI, localName, atts);
314          }
315
316          // still have to push since curNsSwitchingFactory needs to be updated to prevent
317
// newRoot calls for the children
318
pushFactory(namespaceURI, localName, newFactory);
319       }
320       else
321       {
322          element = curFactory.newChild(parent, this, namespaceURI, localName, atts);
323       }
324
325       if(element == null)
326       {
327          pushAll(IGNORED);
328
329          if(trace)
330          {
331             log.trace("ignored " + namespaceURI + ':' + qName);
332          }
333       }
334       else
335       {
336          pushAll(element);
337          pushAccepted(element);
338
339          if(trace)
340          {
341             log.trace("accepted " + namespaceURI + ':' + qName);
342          }
343       }
344    }
345
346    public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName)
347    {
348       AllElement element = popAll();
349
350       if(!accepted.isEmpty())
351       {
352          Object JavaDoc acceptedElement = peekAccepted();
353          if(element.characters != null && element.characters.length() > 0)
354          {
355             String JavaDoc characters = element.characters.toString().trim();
356             if(characters.length() > 0)
357             {
358                curFactory.setValue(acceptedElement, this, namespaceURI, localName, characters);
359             }
360          }
361       }
362
363       if(localName.equals(curNameSwitchingFactory) && namespaceURI.equals(curNsSwitchingFactory))
364       {
365          popFactory();
366       }
367
368       if(element.element != IGNORED)
369       {
370          popAccepted();
371          Object JavaDoc parent = (accepted.isEmpty() ? null : peekAccepted());
372
373          if(parent != null)
374          {
375             curFactory.addChild(parent, element.element, this, namespaceURI, localName);
376          }
377          else
378          {
379             root = curFactory.completeRoot(element.element, this, namespaceURI, localName);
380          }
381       }
382    }
383
384    public void characters(char[] ch, int start, int length)
385    {
386       if(!accepted.isEmpty())
387       {
388          String JavaDoc str = String.valueOf(ch, start, length);
389          AllElement allElement = peekAll();
390          if(allElement.characters == null)
391          {
392             allElement.characters = new StringBuffer JavaDoc(str);
393          }
394          else
395          {
396             allElement.characters.append(str);
397          }
398       }
399    }
400
401    // Private
402

403    private GenericObjectModelFactory getFactory(String JavaDoc namespaceUri)
404    {
405       GenericObjectModelFactory factory = (GenericObjectModelFactory)factoriesToNs.get(namespaceUri);
406       if(factory == null)
407       {
408          factory = defaultFactory;
409       }
410       return factory;
411    }
412
413    static Object JavaDoc invokeFactory(Object JavaDoc factory, Method JavaDoc method, Object JavaDoc[] args)
414    {
415       try
416       {
417          return method.invoke(factory, args);
418       }
419       catch(InvocationTargetException JavaDoc e)
420       {
421          Throwable JavaDoc te = e.getCause();
422          if(te instanceof RuntimeException JavaDoc)
423          {
424             throw (RuntimeException JavaDoc)te;
425          }
426
427          String JavaDoc msg = "Failed to invoke method " + method + ", factory=" + factory;
428          log.error(msg, e.getTargetException());
429
430          IllegalStateException JavaDoc ise = new IllegalStateException JavaDoc(msg);
431          ise.initCause(te);
432          throw ise;
433       }
434       catch(Exception JavaDoc e)
435       {
436          String JavaDoc msg = "Failed to invoke method " + method.getName() + ", factory=" + factory;
437          log.error(msg, e);
438          IllegalStateException JavaDoc ise = new IllegalStateException JavaDoc(msg);
439          ise.initCause(e);
440          throw ise;
441       }
442    }
443
444    static Method JavaDoc getMethodForElement(Object JavaDoc factory, String JavaDoc name, Class JavaDoc[] params)
445    {
446       Method JavaDoc method = null;
447       try
448       {
449          method = factory.getClass().getMethod(name, params);
450       }
451       catch(NoSuchMethodException JavaDoc e)
452       {
453       }
454       catch(SecurityException JavaDoc e)
455       {
456          throw e;
457       }
458
459       return method;
460    }
461
462    static final GenericObjectModelFactory getGenericObjectModelFactory(ObjectModelFactory factory)
463    {
464       if(!(factory instanceof GenericObjectModelFactory))
465       {
466          factory = new DelegatingObjectModelFactory(factory);
467       }
468       return factory instanceof GenericObjectModelFactory ?
469          (GenericObjectModelFactory)factory :
470          new DelegatingObjectModelFactory(factory);
471    }
472
473    private void pushAccepted(Object JavaDoc o)
474    {
475       accepted.push(o);
476    }
477
478    private Object JavaDoc popAccepted()
479    {
480       return accepted.pop();
481    }
482
483    private Object JavaDoc peekAccepted()
484    {
485       return accepted.peek();
486    }
487
488    private void pushAll(Object JavaDoc o)
489    {
490       all.push(new AllElement(o));
491    }
492
493    private AllElement popAll()
494    {
495       return (AllElement)all.pop();
496    }
497
498    private AllElement peekAll()
499    {
500       return (AllElement)all.peek();
501    }
502
503    private static final class AllElement
504    {
505       public final Object JavaDoc element;
506       public StringBuffer JavaDoc characters;
507
508       public AllElement(Object JavaDoc element)
509       {
510          this.element = element;
511       }
512    }
513
514    private static interface Stack
515    {
516       void clear();
517
518       void push(Object JavaDoc o);
519
520       Object JavaDoc pop();
521
522       Object JavaDoc peek();
523
524       boolean isEmpty();
525    }
526
527    private static class StackImpl
528       implements Stack
529    {
530       private List JavaDoc list = new ArrayList JavaDoc();
531
532       public void clear()
533       {
534          list.clear();
535       }
536
537       public void push(Object JavaDoc o)
538       {
539          list.add(o);
540       }
541
542       public Object JavaDoc pop()
543       {
544          return list.remove(list.size() - 1);
545       }
546
547       public Object JavaDoc peek()
548       {
549          return list.get(list.size() - 1);
550       }
551
552       public boolean isEmpty()
553       {
554          return list.isEmpty();
555       }
556    }
557 }
558
Popular Tags