KickJava   Java API By Example, From Geeks To Geeks.

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


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 com.wutka.dtd.DTD;
25 import com.wutka.dtd.DTDAttribute;
26 import com.wutka.dtd.DTDContainer;
27 import com.wutka.dtd.DTDElement;
28 import com.wutka.dtd.DTDEmpty;
29 import com.wutka.dtd.DTDItem;
30 import com.wutka.dtd.DTDMixed;
31 import com.wutka.dtd.DTDName;
32 import com.wutka.dtd.DTDPCData;
33 import com.wutka.dtd.DTDParser;
34 import com.wutka.dtd.DTDCardinal;
35 import org.jboss.logging.Logger;
36 import org.xml.sax.Attributes JavaDoc;
37 import org.xml.sax.SAXException JavaDoc;
38
39 import java.io.IOException JavaDoc;
40 import java.io.Reader JavaDoc;
41 import java.io.Writer JavaDoc;
42 import java.io.InputStream JavaDoc;
43 import java.io.InputStreamReader JavaDoc;
44 import java.util.Collection JavaDoc;
45 import java.util.Collections JavaDoc;
46 import java.util.Enumeration JavaDoc;
47 import java.util.Hashtable JavaDoc;
48 import java.util.Iterator JavaDoc;
49 import java.util.Map JavaDoc;
50 import java.util.HashMap JavaDoc;
51 import java.util.List JavaDoc;
52 import java.util.ArrayList JavaDoc;
53 import java.net.URL JavaDoc;
54 import java.net.MalformedURLException JavaDoc;
55 import javax.xml.parsers.ParserConfigurationException JavaDoc;
56
57
58 /**
59  * A DTD based org.jboss.xb.binding.Marshaller implementation.
60  *
61  * @author <a HREF="mailto:alex@jboss.org">Alexey Loubyansky</a>
62  * @version <tt>$Revision: 2009 $</tt>
63  */

64 public class DtdMarshaller
65    extends AbstractMarshaller
66 {
67    private static final Logger log = Logger.getLogger(DtdMarshaller.class);
68
69    private String JavaDoc publicId;
70    private String JavaDoc systemId;
71
72    private final Stack stack = new StackImpl();
73    private DTD dtd;
74    private GenericObjectModelProvider provider;
75    private Content content = new Content();
76
77    private final List JavaDoc elementStack = new ArrayList JavaDoc();
78
79    private final Map JavaDoc simpleTypeBindings = new HashMap JavaDoc();
80
81    public void addBinding(String JavaDoc elementName, TypeBinding binding)
82    {
83       simpleTypeBindings.put(elementName, binding);
84    }
85
86    public void mapPublicIdToSystemId(String JavaDoc publicId, String JavaDoc systemId)
87    {
88       this.publicId = publicId;
89       this.systemId = systemId;
90    }
91
92    public void declareNamespace(String JavaDoc prefix, String JavaDoc uri)
93    {
94       throw new UnsupportedOperationException JavaDoc("declareNamespace is not implemented.");
95    }
96
97    public void addAttribute(String JavaDoc prefix, String JavaDoc localName, String JavaDoc type, String JavaDoc value)
98    {
99       throw new UnsupportedOperationException JavaDoc("addAttribute is not implemented.");
100    }
101
102    public void marshal(String JavaDoc schemaUri, ObjectModelProvider provider, Object JavaDoc root, Writer JavaDoc writer) throws IOException JavaDoc,
103          ParserConfigurationException JavaDoc,
104       SAXException JavaDoc
105    {
106       URL JavaDoc url;
107       try
108       {
109          url = new URL JavaDoc(schemaUri);
110       }
111       catch(MalformedURLException JavaDoc e)
112       {
113          throw new IllegalArgumentException JavaDoc("Malformed schema URI " + schemaUri + ": " + e.getMessage());
114       }
115
116       InputStream JavaDoc is;
117       try
118       {
119          is = url.openStream();
120       }
121       catch(IOException JavaDoc e)
122       {
123          throw new IllegalStateException JavaDoc("Failed to open input stream for schema " + schemaUri + ": " + e.getMessage());
124       }
125
126       try
127       {
128          InputStreamReader JavaDoc reader = new InputStreamReader JavaDoc(is);
129          marshal(reader, provider, root, writer);
130       }
131       finally
132       {
133          is.close();
134       }
135    }
136
137    public void marshal(Reader JavaDoc dtdReader, ObjectModelProvider provider, Object JavaDoc document, Writer JavaDoc writer)
138       throws IOException JavaDoc, SAXException JavaDoc
139    {
140       DTDParser parser = new DTDParser(dtdReader);
141       dtd = parser.parse(true);
142
143       this.provider = provider instanceof GenericObjectModelProvider ?
144          (GenericObjectModelProvider)provider : new DelegatingObjectModelProvider(provider);
145       //stack.push(document);
146

147       DTDElement[] roots = null;
148       if(dtd.rootElement != null)
149       {
150          handleRootElement(document, dtd.rootElement);
151       }
152       else
153       {
154          roots = getRootList(dtd);
155          for(int i = 0; i < roots.length; ++i)
156          {
157             handleRootElement(document, roots[i]);
158          }
159       }
160
161       //stack.pop();
162

163       // version & encoding
164
writeXmlVersion(writer);
165
166       // DOCTYPE
167
writer.write("<!DOCTYPE ");
168
169       if(dtd.rootElement != null)
170       {
171          writer.write(dtd.rootElement.getName());
172       }
173       else
174       {
175          for(int i = 0; i < roots.length; ++i)
176          {
177             writer.write(", ");
178             writer.write(roots[i].getName());
179          }
180       }
181
182       writer.write(" PUBLIC \"");
183       writer.write(publicId);
184       writer.write("\" \"");
185       writer.write(systemId);
186       writer.write("\">\n");
187
188       ContentWriter contentWriter = new ContentWriter(writer, propertyIsTrueOrNotSet(Marshaller.PROP_OUTPUT_INDENTATION));
189       content.handleContent(contentWriter);
190    }
191
192    private void handleRootElement(Object JavaDoc o, final DTDElement dtdRoot)
193    {
194       Element el = new Element(dtdRoot, true);
195       elementStack.add(el);
196       content.startDocument();
197
198       Object JavaDoc root = provider.getRoot(o, null, systemId, dtdRoot.getName());
199       if(root == null)
200       {
201          return;
202       }
203       stack.push(root);
204
205       Attributes JavaDoc attrs = provideAttributes(dtdRoot, root);
206       content.startElement("", dtdRoot.getName(), dtdRoot.getName(), attrs);
207       handleElement(dtd, dtdRoot, attrs);
208       content.endElement("", dtdRoot.getName(), dtdRoot.getName());
209
210       stack.pop();
211       content.endDocument();
212       elementStack.remove(elementStack.size() - 1);
213    }
214
215    private final void handleElement(DTD dtd, DTDElement element, Attributes JavaDoc attrs)
216    {
217       DTDItem item = element.content;
218       if(item instanceof DTDMixed)
219       {
220          handleMixedElement(element, attrs);
221       }
222       else if(item instanceof DTDEmpty)
223       {
224          final Object JavaDoc value = provider.getElementValue(stack.peek(), null, systemId, element.getName());
225          if(Boolean.TRUE.equals(value))
226          {
227             writeSkippedElements();
228             content.startElement("", element.getName(), element.getName(), attrs);
229             content.endElement("", element.getName(), element.getName());
230          }
231       }
232       else if(item instanceof DTDContainer)
233       {
234          processContainer(dtd, (DTDContainer)item);
235       }
236       else
237       {
238          throw new IllegalStateException JavaDoc("Unexpected element: " + element.getName());
239       }
240    }
241
242    private final void handleMixedElement(DTDElement element, Attributes JavaDoc attrs)
243    {
244       boolean startElement = false;
245       if(!elementStack.isEmpty())
246       {
247          Element e = (Element) elementStack.get(elementStack.size() - 1);
248          startElement = element != e.element;
249       }
250       
251       DTDMixed mixed = (DTDMixed) element.content;
252       String JavaDoc elementName = element.getName();
253       Object JavaDoc parent = stack.peek();
254       DTDItem[] items = mixed.getItems();
255       for(int i = 0; i < items.length; ++i)
256       {
257          DTDItem item = items[i];
258          if(item instanceof DTDPCData)
259          {
260             Object JavaDoc value = provider.getElementValue(parent, null, systemId, elementName);
261             if(value != null)
262             {
263                writeSkippedElements();
264
265                String JavaDoc marshalled;
266                TypeBinding binding = (TypeBinding)simpleTypeBindings.get(elementName);
267                if(binding != null)
268                {
269                   marshalled = binding.marshal(value);
270                }
271                else
272                {
273                   marshalled = value.toString();
274                }
275
276                char[] ch = marshalled.toCharArray();
277                if(startElement)
278                {
279                   content.startElement("", elementName, elementName, attrs);
280                }
281                
282                content.characters(ch, 0, ch.length);
283
284                if(startElement)
285                {
286                   content.endElement("", elementName, elementName);
287                }
288             }
289          }
290       }
291    }
292
293    private final void handleChildren(DTD dtd, DTDElement element, DTDCardinal elementCardinal)
294    {
295       Object JavaDoc parent = stack.peek();
296       Object JavaDoc children = provider.getChildren(parent, null, systemId, element.getName());
297
298       if(children != null)
299       {
300          Iterator JavaDoc iter;
301          if(children instanceof Iterator JavaDoc)
302          {
303             iter = (Iterator JavaDoc)children;
304          }
305          else if(children instanceof Collection JavaDoc)
306          {
307             iter = ((Collection JavaDoc)children).iterator();
308          }
309          else
310          {
311             iter = Collections.singletonList(children).iterator();
312          }
313
314          writeSkippedElements();
315
316          Element el = new Element(element, true);
317          elementStack.add(el);
318
319          final boolean singleValued = elementCardinal == DTDCardinal.NONE || elementCardinal == DTDCardinal.OPTIONAL;
320          if(singleValued)
321          {
322             // todo attributes!
323
content.startElement("", element.getName(), element.getName(), null);
324          }
325
326          while(iter.hasNext())
327          {
328             Object JavaDoc child = iter.next();
329             stack.push(child);
330
331             AttributesImpl attrs = (element.attributes.isEmpty() ? null : provideAttributes(element, child));
332             if(!singleValued)
333             {
334                content.startElement("", element.getName(), element.getName(), attrs);
335             }
336
337             handleElement(dtd, element, attrs);
338
339             if(!singleValued)
340             {
341                content.endElement(systemId, element.getName(), element.getName());
342             }
343
344             stack.pop();
345          }
346
347          if(singleValued)
348          {
349             content.endElement(systemId, element.getName(), element.getName());
350          }
351
352          elementStack.remove(elementStack.size() - 1);
353       }
354       else
355       {
356          boolean removeLast = false;
357          if(!(element.getContent() instanceof DTDMixed || element.getContent() instanceof DTDEmpty))
358          {
359             Element el = new Element(element);
360             elementStack.add(el);
361             removeLast = true;
362          }
363
364          AttributesImpl attrs = (element.attributes.isEmpty() ? null : provideAttributes(element, parent));
365          handleElement(dtd, element, attrs);
366
367          if(removeLast)
368          {
369             Element el = (Element)elementStack.remove(elementStack.size() - 1);
370             if(el.started)
371             {
372                DTDElement started = el.element;
373                content.endElement("", started.getName(), started.getName());
374             }
375          }
376       }
377    }
378
379    private final void processContainer(DTD dtd, DTDContainer container)
380    {
381       DTDItem[] items = container.getItems();
382       for(int i = 0; i < items.length; ++i)
383       {
384          DTDItem item = items[i];
385          if(item instanceof DTDContainer)
386          {
387             processContainer(dtd, (DTDContainer)item);
388          }
389          else if(item instanceof DTDName)
390          {
391             DTDName name = (DTDName)item;
392             DTDElement element = (DTDElement)dtd.elements.get(name.value);
393             handleChildren(dtd, element, name.getCardinal());
394          }
395       }
396    }
397
398    private void writeSkippedElements()
399    {
400       Element el = (Element)elementStack.get(elementStack.size() - 1);
401       if(!el.started)
402       {
403          int firstNotStarted = elementStack.size() - 1;
404          do
405          {
406             el = (Element)elementStack.get(--firstNotStarted);
407          }
408          while(!el.started);
409
410          ++firstNotStarted;
411
412          while(firstNotStarted < elementStack.size())
413          {
414             el = (Element)elementStack.get(firstNotStarted++);
415             DTDElement notStarted = el.element;
416
417             if(log.isTraceEnabled())
418             {
419                log.trace("starting skipped> " + notStarted.getName());
420             }
421
422             content.startElement("", notStarted.getName(), notStarted.getName(), null);
423             el.started = true;
424          }
425       }
426    }
427
428    private AttributesImpl provideAttributes(DTDElement element, Object JavaDoc container)
429    {
430       final Hashtable JavaDoc attributes = element.attributes;
431       AttributesImpl attrs = new AttributesImpl(attributes.size());
432
433       for(Iterator JavaDoc attrIter = attributes.values().iterator(); attrIter.hasNext();)
434       {
435          DTDAttribute attr = (DTDAttribute)attrIter.next();
436          final Object JavaDoc attrValue = provider.getAttributeValue(container, null, systemId, attr.getName());
437
438          if(attrValue != null)
439          {
440             attrs.add(systemId,
441                attr.getName(),
442                attr.getName(),
443                attr.getType().toString(),
444                attrValue.toString()
445             );
446          }
447       }
448
449       return attrs;
450    }
451
452    /**
453     * @param dtd the DTD object model
454     * @return root element names
455     */

456    protected static DTDElement[] getRootList(DTD dtd)
457    {
458       Hashtable JavaDoc roots = new Hashtable JavaDoc();
459       Enumeration JavaDoc e = dtd.elements.elements();
460       while(e.hasMoreElements())
461       {
462          DTDElement element = (DTDElement)e.nextElement();
463          roots.put(element.name, element);
464       }
465
466       e = dtd.elements.elements();
467       while(e.hasMoreElements())
468       {
469          DTDElement element = (DTDElement)e.nextElement();
470          if(!(element.content instanceof DTDContainer))
471          {
472             continue;
473          }
474
475          Enumeration JavaDoc items = ((DTDContainer)element.content).getItemsVec().elements();
476          while(items.hasMoreElements())
477          {
478             removeElements(roots, dtd, (DTDItem)items.nextElement());
479          }
480       }
481
482       final Collection JavaDoc rootCol = roots.values();
483       return (DTDElement[])rootCol.toArray(new DTDElement[rootCol.size()]);
484    }
485
486    protected static void removeElements(Hashtable JavaDoc h, DTD dtd, DTDItem item)
487    {
488       if(item instanceof DTDName)
489       {
490          h.remove(((DTDName)item).value);
491       }
492       else if(item instanceof DTDContainer)
493       {
494          Enumeration JavaDoc e = ((DTDContainer)item).getItemsVec().elements();
495          while(e.hasMoreElements())
496          {
497             removeElements(h, dtd, (DTDItem)e.nextElement());
498          }
499       }
500    }
501
502    // Inner
503

504    private static final class Element
505    {
506       public final DTDElement element;
507       public boolean started;
508
509       public Element(DTDElement element, boolean started)
510       {
511          this.element = element;
512          this.started = started;
513       }
514
515       public Element(DTDElement element)
516       {
517          this.element = element;
518       }
519
520       public String JavaDoc toString()
521       {
522          return "[element=" + element.getName() + ", started=" + started + "]";
523       }
524    }
525 }
526
Popular Tags