KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > zeus > binder > DTDBinder


1 /*
2  * Enhydra Java Application Server Project
3  *
4  * The contents of this file are subject to the Enhydra Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License on
7  * the Enhydra web site ( http://www.enhydra.org/ ).
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
11  * the License for the specific terms governing rights and limitations
12  * under the License.
13  *
14  * The Initial Developer of the Enhydra Application Server is Lutris
15  * Technologies, Inc. The Enhydra Application Server and portions created
16  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17  * All Rights Reserved.
18  */

19 package org.enhydra.zeus.binder;
20
21 import java.io.IOException JavaDoc;
22 import java.util.BitSet JavaDoc;
23 import java.util.Enumeration JavaDoc;
24 import java.util.Hashtable JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.LinkedList JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Vector JavaDoc;
29
30 // Zeus imports
31
import org.enhydra.zeus.Binder;
32 import org.enhydra.zeus.Binding;
33 import org.enhydra.zeus.ZeusDefaults;
34 import org.enhydra.zeus.binding.Property;
35 import org.enhydra.zeus.binding.AtomicProperty;
36 import org.enhydra.zeus.binding.Container;
37 import org.enhydra.zeus.binding.ContainerProperty;
38 import org.enhydra.zeus.source.DTDSource;
39 import org.enhydra.zeus.util.CapitalizationUtils;
40 import org.enhydra.zeus.util.DTDUtils;
41
42 // DTDParser imports
43
import com.wutka.dtd.DTD;
44 import com.wutka.dtd.DTDAny;
45 import com.wutka.dtd.DTDAttribute;
46 import com.wutka.dtd.DTDCardinal;
47 import com.wutka.dtd.DTDContainer;
48 import com.wutka.dtd.DTDDecl;
49 import com.wutka.dtd.DTDElement;
50 import com.wutka.dtd.DTDEmpty;
51 import com.wutka.dtd.DTDEnumeration;
52 import com.wutka.dtd.DTDItem;
53 import com.wutka.dtd.DTDMixed;
54 import com.wutka.dtd.DTDName;
55 import com.wutka.dtd.DTDPCData;
56
57 /**
58  * <p>
59  * <code>DTDBinder</code> implements the <code>{@link Binder}</code>
60  * interface and allows generation of Zeus
61  * <code>{@link Binding}</code>s from a DTD.
62  * </p>
63  *
64  * @author Brett McLaughlin
65  * @author Steve Witten
66  * @author Maciej Zawadzki
67  * @author Sean Ogle
68  */

69 public class DTDBinder extends BaseBinder {
70
71     /** The DTD being processed */
72     protected DTD dtd;
73     
74     /** The elements by name */
75     protected Hashtable JavaDoc elements;
76     
77     /** The root element of the DTD */
78     protected String JavaDoc rootElementName;
79
80     /**
81      * <p>
82      * This constructor takes in a <code>{@link DTDSource}</code>
83      * to read an XML Schema from and allow generation of the
84      * <code>{@link Binding}</code>s from it.
85      * </p>
86      *
87      * @param source <code>Source</code> to read input from.
88      * @param rootElementName the name of the DTD's root element
89      */

90     public DTDBinder(DTDSource source, String JavaDoc rootElementName) {
91         super(source);
92         this.rootElementName = rootElementName;
93         elements = new Hashtable JavaDoc();
94     }
95     
96     /**
97      * <p>
98      * This constructor takes in a <code>{@link DTDSource}</code>
99      * to read an XML Schema from and allow generation of the
100      * <code>{@link Binding}</code>s from it.
101      * </p>
102      *
103      * @param source <code>Source</code> to read input from.
104      */

105     public DTDBinder(DTDSource source) {
106         this(source, null);
107     }
108     
109     /**
110      * <p>
111      * This retrieves the name of the root element for this binder.
112      * </p>
113      *
114      * @param <code>String</code> - this binder DTD's root element name.
115      */

116     public String JavaDoc getRootElementName() {
117         return rootElementName;
118     }
119
120     /**
121      * <p>
122      * This is integral portion of the <code>Binder</code>. It
123      * is responsible for returning a Zeus representation of
124      * the set of constraints that this binding represents,
125      * resulting from the supplied DTD.
126      * </p>
127      *
128      * @return <code>List</code> - the resultant
129      * <code>Binding</code>s from conversion of
130      * constraints.
131      * @throws <code>IOException</code> when errors in reading
132      * input occur.
133      */

134     public List JavaDoc getBindings() throws IOException JavaDoc {
135         // Get the DTD
136
dtd = ((DTDSource)source).getDTD();
137         
138         // Create a list for the bindings
139
List JavaDoc bindings = new LinkedList JavaDoc();
140         
141         // Get all of the elements in the DTD
142
Vector JavaDoc dtdElements = dtd.getItemsByType(DTDElement.class);
143         
144         // First, process element names and types
145
for (Iterator JavaDoc i = dtdElements.iterator(); i.hasNext(); ) {
146             DTDElement dtdElement = (DTDElement)i.next();
147             buildNamesAndTypes(dtdElement);
148         }
149         
150         // Second pass covers bindings
151
for (Iterator JavaDoc i = dtdElements.iterator(); i.hasNext(); ) {
152             DTDElement dtdElement = (DTDElement)i.next();
153             Binding binding = convertToBinding(dtdElement);
154             if (rootElementName != null) {
155                 if (dtdElement.getName().equals(rootElementName)) {
156                     binding.setIsXMLRootElement(true);
157                 }
158             } else if (dtdElement == dtd.rootElement) {
159                 binding.setIsXMLRootElement(true);
160             }
161             bindings.add(binding);
162         }
163     
164         return bindings;
165     }
166     
167     /**
168      * <p>
169      * This will build up a listing of the element's name and type for
170      * use in type lookups later.
171      * </p>
172      *
173      * @param dtdElement <code>DTDElement</code> to build from.
174      */

175     private void buildNamesAndTypes(DTDElement dtdElement) {
176         // The xmlName is the same as in the DTD
177
String JavaDoc xmlName = dtdElement.getName();
178
179         String JavaDoc xmlType = xmlName;
180         
181         // if collapsing, type is a string for simple elements...
182
if ((isCollapsingSimpleElements) &&
183             (DTDUtils.isSimpleElement(dtdElement, isIgnoringIDAttributes))) {
184             
185             xmlType = "string";
186         }
187         
188         elements.put(xmlName, xmlType);
189     }
190     
191     /**
192      * <p>
193      * This will take a single DTD element (in the form of a
194      * <code>DTDElement</code>) and convert it to a Zeus
195      * <code>Binding</code> object.
196      * </p>
197      *
198      * @param dtdElement <code>DTDElement</code> to convert to
199      * Zeus <code>Binding</code>.
200      * @return <code>Binding</code> - the converted Zeus <code>Binding</code>.
201      */

202     private Binding convertToBinding(DTDElement dtdElement) {
203         // The xmlName is the same as in the DTD
204
String JavaDoc xmlName = dtdElement.getName();
205         String JavaDoc xmlType = (String JavaDoc)elements.get(xmlName);
206         
207         // This property is an element.
208
BitSet JavaDoc modifiers = new BitSet JavaDoc();
209         modifiers.set(Property.SOURCE_ELEMENT);
210
211         // Build a new container to hold the element's contents.
212
ContainerProperty container =
213             new ContainerProperty(xmlName, xmlType);
214         container.setModifier(modifiers);
215             
216         // Deal with the content of the DTDElement
217
handleContent(container, dtdElement.getContent());
218         
219         // Deal with the attributes of the DTDElement
220
handleAttributes(container, dtdElement);
221     
222         return container;
223     }
224     
225     /**
226      * <p>
227      * This will take an element from a DTD (in <code>DTDElement</code>
228      * form) and create Zeus <code>{@link AtomicProperty}</code> objects
229      * from its attributes, adding them to the supplied
230      * <code>{@link Container}</code>.
231      * </p>
232      *
233      * @param container <code>Container</code> to add properties to.
234      * @param dtdElement <code>DTDElement</code> to read attributes of.
235      */

236     private void handleAttributes(Container container, DTDElement dtdElement) {
237         Hashtable JavaDoc elementAttributes = dtdElement.attributes;
238         Enumeration JavaDoc e = elementAttributes.elements();
239         while (e.hasMoreElements()) {
240             DTDAttribute attribute = (DTDAttribute)e.nextElement();
241             /**
242              * Create the attribute; all DTD attributes are
243              * simply Java <code>String</code>s, since
244              * there is no typing in DTDs.
245              */

246             DTDDecl decl = attribute.getDecl();
247             
248             // This will have private access and is from an XML attribute.
249
BitSet JavaDoc modifiers = new BitSet JavaDoc();
250             modifiers.set(Property.ACCESS_PRIVATE);
251             modifiers.set(Property.SOURCE_ATTLIST);
252             
253             // should the decl be stored for future reference?
254
// maybe in the code generator?
255
// we need to handle #REQUIRED, #IMPLIED, and #VALUE too...
256
if ((decl != null) && (decl.equals(DTDDecl.FIXED))) {
257                 modifiers.set(Property.MUTABILITY_FINAL);
258                 modifiers.set(Property.STORAGE_STATIC);
259             }
260
261             /**
262              * Set up the XML name and type information for an attribute. The
263              * type is always an XML string, and the namespace is the same
264              * as that of the XML Schema namespace, for default type
265              * processing.
266              */

267             String JavaDoc xmlName = attribute.getName();
268             String JavaDoc xmlType = "string";
269
270             // Get any enumeration information from the DTD.
271
Vector JavaDoc enumeration =
272                 (attribute.getType() instanceof DTDEnumeration) ?
273                 ((DTDEnumeration)attribute.getType()).getItemsVec() :
274                 null;
275
276             AtomicProperty atomicProperty =
277                 new AtomicProperty(xmlName,
278                                    "",
279                                    xmlType,
280                                    ZeusDefaults.SCHEMA_NAMESPACE_URI,
281                                    modifiers,
282                                    enumeration,
283                                    attribute.getDefaultValue());
284
285             container.addProperty(atomicProperty);
286         }
287     }
288
289     /**
290      * <p>
291      * This will take an element's content (in <code>DTDItem</code>
292      * form) and create Zeus <code>{@link AtomicProperty}</code> objects
293      * from its attributes, adding them to the supplied
294      * <code>{@link Container}</code>.
295      * </p><p>
296      * This convenience version (called by default) supplies no transitive
297      * cardinality, meaning that each content is treated as isolated from
298      * any other content being processed elsewhere.
299      * </p>
300      *
301      * @param conainer <code>Container</code> to add properties to.
302      * @param content <code>DTDItem</code> with element's content.
303      */

304     private void handleContent(Container container, DTDItem content) {
305         handleContent(container, content, DTDCardinal.NONE);
306     }
307     
308     /**
309      * <p>
310      * This will take an element's content (in <code>DTDItem</code>
311      * form) and create Zeus <code>{@link AtomicProperty}</code> objects
312      * from its attributes, adding them to the supplied
313      * <code>{@link Container}</code>. The items used have the supplied
314      * cardinality applied to them.
315      * </p>
316      *
317      * @param conainer <code>Container</code> to add properties to.
318      * @param content <code>DTDItem</code> with element's content.
319      * @param transCardinality <code>DTDCardinality</code> with any transitive
320      * cardinality applied.
321      */

322     private void handleContent(Container container, DTDItem content,
323                                DTDCardinal transCardinality) {
324         // Cycle through the various types of content
325
if (content instanceof DTDEmpty) {
326             // We're done - this is an empty element
327
} else if (content instanceof DTDPCData) {
328             /**
329              * PCDATA elements have text content that we map to an attribute
330              * with a special XML name. The namespace is the same
331              * as that of the XML Schema namespace, for default type
332              * processing.
333              */

334             String JavaDoc xmlName = ZeusDefaults.PCDATA_XML_NAME;
335             String JavaDoc xmlType = "string";
336
337             AtomicProperty property =
338                 new AtomicProperty(xmlName, "",
339                                    xmlType, ZeusDefaults.SCHEMA_NAMESPACE_URI);
340
341             container.addProperty(property);
342         } else if (content instanceof DTDName) {
343             // Generate a single property
344
BitSet JavaDoc modifiers = new BitSet JavaDoc();
345             modifiers.set(Property.ACCESS_PRIVATE);
346             modifiers.set(Property.SOURCE_ELEMENT);
347
348             // The XML name is the same as in the DTD.
349
String JavaDoc xmlName = ((DTDName)content).getValue();
350
351             // The XML type is the same as the XML name for elements.
352
String JavaDoc xmlType = (String JavaDoc)elements.get(xmlName);
353
354             AtomicProperty property = new AtomicProperty(xmlName, xmlType);
355             property.setModifier(modifiers);
356
357             // Handle cardinality - either a list or a single property
358
DTDCardinal cardinality = ((DTDName)content).getCardinal();
359
360             if ((cardinality.equals(DTDCardinal.ZEROMANY)) ||
361                 (cardinality.equals(DTDCardinal.ONEMANY))) {
362                 property.setIsCollection(true);
363             } else if ((transCardinality.equals(DTDCardinal.ZEROMANY)) ||
364                        (transCardinality.equals(DTDCardinal.ONEMANY))) {
365                            
366                 property.setIsCollection(true);
367             }
368
369             container.addProperty(property);
370         } else if (content instanceof DTDAny) {
371             String JavaDoc xmlName = "";
372             String JavaDoc xmlType = "anyType";
373
374             AtomicProperty property =
375                 new AtomicProperty(xmlName, "",
376                                    xmlType, ZeusDefaults.SCHEMA_NAMESPACE_URI);
377
378             property.setIsCollection(true);
379
380             container.addProperty(property);
381         } else if (content instanceof DTDContainer) {
382             // Get each item and handle it
383
Vector JavaDoc items = ((DTDContainer)content).getItemsVec();
384             
385             // Deal with transitive nature of cardinality on containers
386
DTDCardinal cardinality = content.getCardinal();
387
388             for (Iterator JavaDoc i = items.iterator(); i.hasNext(); ) {
389                 DTDItem subContent = (DTDItem)i.next();
390
391                 handleContent(container, subContent, cardinality);
392             }
393         }
394     }
395 }
396
Popular Tags