KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > xml > binding > XercesXsMarshaller


1 /*
2  * JBoss, the OpenSource J2EE webOS
3  *
4  * Distributable under LGPL license.
5  * See terms of license at gnu.org.
6  */

7 package org.jboss.xml.binding;
8
9 import org.apache.xerces.dom3.bootstrap.DOMImplementationRegistry;
10 import org.apache.xerces.xs.XSAttributeDeclaration;
11 import org.apache.xerces.xs.XSAttributeUse;
12 import org.apache.xerces.xs.XSComplexTypeDefinition;
13 import org.apache.xerces.xs.XSConstants;
14 import org.apache.xerces.xs.XSElementDeclaration;
15 import org.apache.xerces.xs.XSImplementation;
16 import org.apache.xerces.xs.XSLoader;
17 import org.apache.xerces.xs.XSModel;
18 import org.apache.xerces.xs.XSModelGroup;
19 import org.apache.xerces.xs.XSNamedMap;
20 import org.apache.xerces.xs.XSObject;
21 import org.apache.xerces.xs.XSObjectList;
22 import org.apache.xerces.xs.XSParticle;
23 import org.apache.xerces.xs.XSTerm;
24 import org.apache.xerces.xs.XSTypeDefinition;
25 import org.apache.xerces.xs.XSWildcard;
26 import org.jboss.logging.Logger;
27 import org.xml.sax.SAXException JavaDoc;
28
29 import javax.xml.parsers.ParserConfigurationException JavaDoc;
30 import javax.xml.namespace.QName JavaDoc;
31 import java.io.IOException JavaDoc;
32 import java.io.Reader JavaDoc;
33 import java.io.Writer JavaDoc;
34 import java.util.Collection JavaDoc;
35 import java.util.HashMap JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.Map JavaDoc;
38
39 /**
40  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
41  * @version <tt>$Revision: 1.7.2.5 $</tt>
42  */

43 public class XercesXsMarshaller
44    extends AbstractMarshaller
45 {
46    private static final Logger log = Logger.getLogger(XercesXsMarshaller.class);
47
48    private Stack stack = new StackImpl();
49
50    /**
51     * ObjectModelProvider for this marshaller
52     */

53    private GenericObjectModelProvider provider;
54    /**
55     * Content the result is written to
56     */

57    private Content content = new Content();
58
59    private final Map prefixByUri = new HashMap JavaDoc();
60
61    private Object JavaDoc root;
62
63    /**
64     * Defines a namespace. The namespace declaration will appear in the root element.
65     * <p>If <code>name</code> argument is <code>null</code> or is an empty string then
66     * the passed in URI will be used for the default namespace, i.e. <code>xmlns</code>.
67     * Otherwise, the declaration will follow the format <code>xmlns:name=uri</code>.
68     * <p>If the namespace with the given name was already declared, its value is overwritten.
69     *
70     * @param name the name of the namespace to declare (can be null or empty string)
71     * @param uri the URI of the namespace.
72     */

73    public void declareNamespace(String JavaDoc name, String JavaDoc uri)
74    {
75       prefixByUri.put(uri, name);
76    }
77
78    /**
79     * Adds an attribute to the top most elements.
80     * First, we check whether there is a namespace associated with the passed in prefix.
81     * If the prefix was not declared, an exception is thrown.
82     *
83     * @param prefix the prefix of the attribute to be declared
84     * @param localName local name of the attribute
85     * @param type the type of the attribute
86     * @param value the value of the attribute
87     */

88    public void addAttribute(String JavaDoc prefix, String JavaDoc localName, String JavaDoc type, String JavaDoc value)
89    {
90       // todo addAttribute(String prefix, String localName, String type, String value)
91
}
92
93    // AbstractMarshaller implementation
94

95    public void marshal(Reader JavaDoc xsdReader, ObjectModelProvider provider, Object JavaDoc root, Writer JavaDoc writer)
96       throws IOException JavaDoc, SAXException JavaDoc, ParserConfigurationException JavaDoc
97    {
98       XSModel model = loadSchema(xsdReader);
99       marshallInternal(provider, root, model, writer);
100    }
101
102    public void marshal(String JavaDoc xsdURL, ObjectModelProvider provider, Object JavaDoc root, Writer JavaDoc writer) throws IOException JavaDoc,
103       SAXException JavaDoc
104    {
105       XSModel model = loadSchema(xsdURL);
106       marshallInternal(provider, root, model, writer);
107    }
108
109    private void marshallInternal(ObjectModelProvider provider, Object JavaDoc root, XSModel model, Writer JavaDoc writer)
110       throws IOException JavaDoc, SAXException JavaDoc
111    {
112       this.provider = provider instanceof GenericObjectModelProvider ?
113          (GenericObjectModelProvider)provider : new DelegatingObjectModelProvider(provider);
114
115       this.root = root;
116
117       content.startDocument();
118
119       if (rootQNames.isEmpty())
120       {
121          XSNamedMap components = model.getComponents(XSConstants.ELEMENT_DECLARATION);
122          for (int i = 0; i < components.getLength(); ++i)
123          {
124             XSElementDeclaration element = (XSElementDeclaration)components.item(i);
125             marshalElement(element, 1, 1);// todo fix min/max
126
}
127       }
128       else
129       {
130          for (int i = 0; i < rootQNames.size(); ++i)
131          {
132             QName JavaDoc qName = (QName JavaDoc)rootQNames.get(i);
133             XSElementDeclaration element = model.getElementDeclaration(qName.getLocalPart(), qName.getNamespaceURI());
134             if (element == null)
135             {
136                XSNamedMap components = model.getComponents(XSConstants.ELEMENT_DECLARATION);
137                String JavaDoc roots = "";
138                for (int j = 0; j < components.getLength(); ++j)
139                {
140                   XSObject xsObject = components.item(j);
141                   if (j > 0)
142                   {
143                      roots += ", ";
144                   }
145                   roots += xsObject.getNamespace() + ":" + xsObject.getName();
146                }
147                throw new IllegalStateException JavaDoc("Root element not found: " + qName + " among " + roots);
148             }
149
150             marshalElement(element, 1, 1);// todo fix min/max
151
}
152       }
153
154       content.endDocument();
155
156       // version & encoding
157
writeXmlVersion(writer);
158
159       ContentWriter contentWriter = new ContentWriter(writer, propertyIsTrueOrNotSet(Marshaller.PROP_OUTPUT_INDENTATION));
160       content.handleContent(contentWriter);
161    }
162
163    private boolean marshalElement(XSElementDeclaration element, int minOccurs, int maxOccurs)
164    {
165       Object JavaDoc value;
166       if (stack.isEmpty())
167       {
168          value = provider.getRoot(root, element.getNamespace(), element.getName());
169          if (value == null)
170          {
171             return false;
172          }
173       }
174       else
175       {
176          if (stack.peek() instanceof Collection JavaDoc)
177          {
178             // collection is the provider
179
value = (Collection JavaDoc)stack.peek();
180          }
181          else
182          {
183             value = provider.getChildren(stack.peek(), element.getNamespace(), element.getName());
184             if (value == null)
185             {
186                value = provider.getElementValue(stack.peek(), element.getNamespace(), element.getName());
187             }
188          }
189       }
190
191       if (value != null)
192       {
193          stack.push(value);
194
195          if (maxOccurs != 1 && value instanceof Collection JavaDoc)
196          {
197             for (Iterator JavaDoc iter = ((Collection JavaDoc)value).iterator(); iter.hasNext();)
198             {
199                Object JavaDoc item = iter.next();
200                stack.push(item);
201                marshalElementType(element);
202                stack.pop();
203             }
204          }
205          else
206          {
207             marshalElementType(element);
208          }
209
210          stack.pop();
211       }
212
213       return minOccurs == 0 || value != null;
214    }
215
216    private void marshalElementType(XSElementDeclaration element)
217    {
218       XSTypeDefinition type = element.getTypeDefinition();
219       switch (type.getTypeCategory())
220       {
221          case XSTypeDefinition.SIMPLE_TYPE:
222             marshalSimpleType(element);
223             break;
224          case XSTypeDefinition.COMPLEX_TYPE:
225             marshalComplexType(element);
226             break;
227          default:
228             throw new IllegalStateException JavaDoc("Unexpected type category: " + type.getTypeCategory());
229       }
230    }
231
232    private void marshalSimpleType(XSElementDeclaration element)
233    {
234       Object JavaDoc value = stack.peek();
235       String JavaDoc valueStr = value.toString();
236
237       String JavaDoc prefix = (String JavaDoc)prefixByUri.get(element.getNamespace());
238       String JavaDoc qName = prefix == null ? element.getName() : prefix + ':' + element.getName();
239
240       content.startElement(element.getNamespace(), element.getName(), qName, null);
241       content.characters(valueStr.toCharArray(), 0, valueStr.length());
242       content.endElement(element.getNamespace(), element.getName(), qName);
243    }
244
245    private void marshalComplexType(XSElementDeclaration element)
246    {
247       XSComplexTypeDefinition type = (XSComplexTypeDefinition)element.getTypeDefinition();
248       XSParticle particle = type.getParticle();
249
250       XSObjectList attributeUses = type.getAttributeUses();
251       AttributesImpl attrs = attributeUses.getLength() > 0 ? new AttributesImpl(attributeUses.getLength()) : null;
252       for (int i = 0; i < attributeUses.getLength(); ++i)
253       {
254          XSAttributeUse attrUse = (XSAttributeUse)attributeUses.item(i);
255          XSAttributeDeclaration attrDec = attrUse.getAttrDeclaration();
256          Object JavaDoc attrValue = provider.getAttributeValue(stack.peek(), attrDec.getNamespace(), attrDec.getName());
257          if (attrValue != null)
258          {
259             attrs.add(attrDec.getNamespace(),
260                attrDec.getName(),
261                attrDec.getName(),
262                attrDec.getTypeDefinition().getName(),
263                attrValue.toString());
264          }
265       }
266
267       String JavaDoc prefix = (String JavaDoc)prefixByUri.get(element.getNamespace());
268       String JavaDoc qName = prefix == null ? element.getName() : prefix + ':' + element.getName();
269       content.startElement(element.getNamespace(), element.getName(), qName, attrs);
270
271       if (particle != null)
272       {
273          marshalParticle(particle);
274       }
275
276       content.endElement(element.getNamespace(), element.getName(), qName);
277    }
278
279    private boolean marshalParticle(XSParticle particle)
280    {
281       boolean marshalled;
282       XSTerm term = particle.getTerm();
283       switch (term.getType())
284       {
285          case XSConstants.MODEL_GROUP:
286             marshalled = marshalModelGroup((XSModelGroup)term);
287             break;
288          case XSConstants.WILDCARD:
289             marshalled = marshalWildcard((XSWildcard)term);
290             break;
291          case XSConstants.ELEMENT_DECLARATION:
292             marshalled = marshalElement((XSElementDeclaration)term, particle.getMinOccurs(), particle.getMaxOccurs());
293             break;
294          default:
295             throw new IllegalStateException JavaDoc("Unexpected term type: " + term.getType());
296       }
297       return marshalled;
298    }
299
300    private boolean marshalWildcard(XSWildcard wildcard)
301    {
302       // todo class resolution
303
ClassMapping mapping = getClassMapping(stack.peek().getClass());
304       if (mapping == null)
305       {
306          throw new IllegalStateException JavaDoc("Failed to marshal wildcard. Class mapping not found for " + stack.peek());
307       }
308
309       GenericObjectModelProvider parentProvider = this.provider;
310       Object JavaDoc parentRoot = this.root;
311       Stack parentStack = this.stack;
312
313       this.root = stack.peek();
314       this.provider = mapping.provider;
315       this.stack = new StackImpl();
316
317       boolean marshalled = false;
318       XSModel model = loadSchema(mapping.schemaUrl);
319       XSNamedMap components = model.getComponents(XSConstants.ELEMENT_DECLARATION);
320       for (int i = 0; i < components.getLength(); ++i)
321       {
322          XSElementDeclaration element = (XSElementDeclaration)components.item(i);
323          marshalled = marshalElement(element, 1, 1);// todo fix min/max
324
}
325
326       this.root = parentRoot;
327       this.provider = parentProvider;
328       this.stack = parentStack;
329
330       return marshalled;
331    }
332
333    private boolean marshalModelGroup(XSModelGroup modelGroup)
334    {
335       boolean marshalled;
336       switch (modelGroup.getCompositor())
337       {
338          case XSModelGroup.COMPOSITOR_ALL:
339             marshalled = marshalModelGroupAll(modelGroup.getParticles());
340             break;
341          case XSModelGroup.COMPOSITOR_CHOICE:
342             marshalled = marshalModelGroupChoice(modelGroup.getParticles());
343             break;
344          case XSModelGroup.COMPOSITOR_SEQUENCE:
345             marshalled = marshalModelGroupSequence(modelGroup.getParticles());
346             break;
347          default:
348             throw new IllegalStateException JavaDoc("Unexpected compsitor: " + modelGroup.getCompositor());
349       }
350       return marshalled;
351    }
352
353    private boolean marshalModelGroupAll(XSObjectList particles)
354    {
355       boolean marshalled = false;
356       for (int i = 0; i < particles.getLength(); ++i)
357       {
358          XSParticle particle = (XSParticle)particles.item(i);
359          marshalled |= marshalParticle(particle);
360       }
361       return marshalled;
362    }
363
364    private boolean marshalModelGroupChoice(XSObjectList particles)
365    {
366       boolean marshalled = false;
367       Content mainContent = this.content;
368       for (int i = 0; i < particles.getLength() && !marshalled; ++i)
369       {
370          XSParticle particle = (XSParticle)particles.item(i);
371          this.content = new Content();
372          marshalled = marshalParticle(particle);
373       }
374
375       if (marshalled)
376       {
377          mainContent.append(this.content);
378       }
379       this.content = mainContent;
380
381       return marshalled;
382    }
383
384    private boolean marshalModelGroupSequence(XSObjectList particles)
385    {
386       boolean marshalled = true;
387       for (int i = 0; i < particles.getLength(); ++i)
388       {
389          XSParticle particle = (XSParticle)particles.item(i);
390          marshalled &= marshalParticle(particle);
391       }
392       return marshalled;
393    }
394
395    private XSModel loadSchema(String JavaDoc xsdURL)
396    {
397       XSImplementation impl = getXSImplementation();
398       XSLoader schemaLoader = impl.createXSLoader(null);
399       XSModel model = schemaLoader.loadURI(xsdURL);
400       if (model == null)
401       {
402          throw new IllegalArgumentException JavaDoc("Invalid URI for schema: " + xsdURL);
403       }
404
405       return model;
406    }
407
408    private XSModel loadSchema(Reader JavaDoc xsdReader)
409    {
410       XSImplementation impl = getXSImplementation();
411       XSLoader schemaLoader = impl.createXSLoader(null);
412       // [TODO] load from reader
413
XSModel model = schemaLoader.load(null);
414       if (model == null)
415       {
416          throw new IllegalArgumentException JavaDoc("Cannot load schema");
417       }
418
419       return model;
420    }
421
422    private XSImplementation getXSImplementation()
423    {
424       // Get DOM Implementation using DOM Registry
425
System.setProperty(DOMImplementationRegistry.PROPERTY, "org.apache.xerces.dom.DOMXSImplementationSourceImpl");
426
427       XSImplementation impl;
428       try
429       {
430          DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
431          impl = (XSImplementation)registry.getDOMImplementation("XS-Loader");
432       }
433       catch (Exception JavaDoc e)
434       {
435          log.error("Failed to create schema loader.", e);
436          throw new IllegalStateException JavaDoc("Failed to create schema loader: " + e.getMessage());
437       }
438       return impl;
439    }
440 }
441
Popular Tags