KickJava   Java API By Example, From Geeks To Geeks.

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


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.Iterator JavaDoc;
23 import java.util.LinkedList JavaDoc;
24 import java.util.List JavaDoc;
25
26 // Zeus imports
27
import org.enhydra.zeus.Binder;
28 import org.enhydra.zeus.Binding;
29 import org.enhydra.zeus.Source;
30 import org.enhydra.zeus.ZeusDefaults;
31 import org.enhydra.zeus.binding.AtomicProperty;
32 import org.enhydra.zeus.binding.ContainerProperty;
33 import org.enhydra.zeus.util.NamingUtils;
34 import org.enhydra.zeus.util.SchemaUtils;
35
36 // JDOM imports
37
import org.jdom.Attribute;
38 import org.jdom.Document;
39 import org.jdom.Element;
40 import org.jdom.Namespace;
41
42 /**
43  * <p>
44  * <code>SchemaBinder</code> implements the <code>{@link Binder}</code>
45  * interface and allows generation of Zeus
46  * <code>{@link Binding}</code>s from an XML Schema.
47  * </p>
48  *
49  * @author Brett McLaughlin
50  * @version 1.0
51  */

52 public class SchemaBinder extends BaseBinder {
53
54     /** The JDOM <code>Namespace</code> object for the schema namespace */
55     private Namespace schemaNamespace;
56
57     /**
58      * <p>
59      * This constructor takes in a <code>{@link Source}</code>
60      * to read an XML Schema from and allow generation of the
61      * <code>{@link Binding}</code>s from it.
62      * </p>
63      *
64      * @param source <code>Source</code> to read input from.
65      */

66     public SchemaBinder(Source source) {
67         super(source);
68
69         // Set up default XML Schema namespace
70
schemaNamespace =
71             Namespace.getNamespace(ZeusDefaults.SCHEMA_NAMESPACE_URI);
72     }
73
74     /**
75      * <p>
76      * This returns the current namespace URI being used for XML Schema.
77      * </p>
78      *
79      * @return <code>String</code> - XML Schema namespace URI being used.
80      */

81     public String JavaDoc getSchemaNamespaceURI() {
82         return schemaNamespace.getURI();
83     }
84
85     /**
86      * <p>
87      * This will set the URI to use for XML Schema. This is useful for
88      * documents that have an older schema namespace URI. Note that this does
89      * <i>not</i> imply that the <code>SchemaBinder</code> can deal with
90      * older schema features and syntax; this is purely for incorrect or old
91      * namespace URIs.
92      * </p>
93      *
94      * @param schemaNamespaceURI the URI to use for XML Schema
95      */

96     public void setSchemaNamespaceURI(String JavaDoc schemaNamespaceURI) {
97         schemaNamespace = Namespace.getNamespace(schemaNamespaceURI);
98     }
99
100     /**
101      * <p>
102      * This is integral portion of the <code>Binder</code>. It
103      * is responsible for returning a Zeus representation of
104      * the set of constraints that this binding represents,
105      * resulting from the supplied XML Schema.
106      * </p>
107      *
108      * @return <code>List</code> - the resultant
109      * <code>Bindings</code> from conversion of
110      * constraints.
111      * @throws <code>IOException</code> when errors in reading
112      * input occur.
113      */

114     public List JavaDoc getBindings() throws IOException JavaDoc {
115         Document schema = source.getDocument();
116         Element root = schema.getRootElement();
117     
118         return convertToBindings(root);
119     }
120     
121     /**
122      * <p>
123      * This takes a single <code>Element</code> (in JDOM form), and
124      * converts it to a <code>Binding</code>.
125      * </p>
126      *
127      * @param element <code>Element</code> to convert to a Zeus
128      * <code>Binding</code>.
129      * @return <code>List</code> - the <code>Binding</code>s from
130      * the supplied <code>Element</code>.
131      */

132     private List JavaDoc convertToBindings(Element element) {
133
134         // Create the list to work with
135
List JavaDoc bindings = new LinkedList JavaDoc();
136
137         // Get all the elements named "element"
138
List JavaDoc elements = element.getChildren("element", schemaNamespace);
139         for (Iterator JavaDoc i = elements.iterator(); i.hasNext(); ) {
140             Element nextElement = (Element)i.next();
141             Attribute elementName = nextElement.getAttribute("name");
142             if (elementName == null) {
143                 // All root-level elements should be named types
144
throw new IllegalArgumentException JavaDoc("All root-level elements " +
145                     "should be named types (with a 'name' attribute).");
146             }
147
148             // Deal with the element definition
149
bindings.add(convertDefinitionToBinding(nextElement));
150         }
151
152         /**
153          * Currently, anything other than root-level elements are ignored.
154          * Eventually, complexTypes defined here should be handled at this
155          * point.
156          */

157         
158         // Deal with the element itself
159

160         return bindings;
161     }
162
163     /**
164      * <p>
165      * This will take an element that defines a structure (already determined
166      * by the time that this method is invoked) and convert the definition
167      * to a <code>{@link Binding}</code>.
168      * </p>
169      *
170      * @param element the element to convert
171      * @return <code>Binding</code> - the converted Zeus <code>Binding</code>.
172      */

173     private Binding convertDefinitionToBinding(Element element) {
174
175         // Create base container
176
String JavaDoc xmlName = element.getAttribute("name").getValue();
177         String JavaDoc xmlType = xmlName;
178
179         ContainerProperty container =
180             new ContainerProperty(xmlName, xmlType);
181
182         // See if this is a simple type or complex type
183
Attribute type = element.getAttribute("type");
184         if (type != null) {
185             // Simple type: deal with allowed values
186
String JavaDoc schemaType = type.getValue();
187             // XXX: I am sure I broke this! (Sean)
188
AtomicProperty property =
189                 new AtomicProperty("value", schemaType);
190             container.addProperty(property);
191         } else {
192             // This should be a complex type
193
Element complexType =
194                 element.getChild("complexType", schemaNamespace);
195             if (complexType == null) {
196                 // XXX: This should be a Zeus-specific exception
197
throw new IllegalArgumentException JavaDoc("Illegal schema: " +
198                     "No complexType defined for this element.");
199             }
200
201             // Determine if this extends a base type
202
Attribute baseType = complexType.getAttribute("baseType");
203             if (baseType != null) {
204                 // Set up the base type as a property
205
String JavaDoc schemaType = baseType.getValue();
206
207                 // XXX: I am sure I broke this! (Sean)
208
AtomicProperty property =
209                     new AtomicProperty("value", schemaType);
210                 container.addProperty(property);
211             }
212
213             // If there is a "sequence" element, it doesn't affect anything
214
Element parent = complexType.getChild("sequence", schemaNamespace);
215             if (parent == null) {
216                 parent = complexType;
217             }
218
219             // Deal with the attributes
220
List JavaDoc attributes = parent.getChildren("attribute", schemaNamespace);
221             for (Iterator JavaDoc i = attributes.iterator(); i.hasNext(); ) {
222                 Element theAttribute = (Element)i.next();
223                 Attribute propertyName = theAttribute.getAttribute("name");
224                 if (propertyName == null) {
225                     // XXX: This should be a Zeus-specific exception
226
throw new IllegalArgumentException JavaDoc("Attributes must have " +
227                         "a name (specified by the 'name' attribute).");
228                 }
229
230                 Attribute schemaType = theAttribute.getAttribute("type");
231                 if (schemaType == null) {
232                     // XXX: This should be a Zeus-specific exception
233
throw new IllegalArgumentException JavaDoc("Attributes must have " +
234                         "a type (specified by the 'type' attribute).");
235                 }
236
237                 // XXX: I am sure I broke this! (Sean)
238
AtomicProperty property =
239                     new AtomicProperty(propertyName.getValue(),
240                                        "",
241                                        "string",
242                                        ZeusDefaults.SCHEMA_NAMESPACE_URI);
243                 container.addProperty(property);
244             }
245
246             // Deal with the elements
247
List JavaDoc elements = parent.getChildren("element", schemaNamespace);
248             for (Iterator JavaDoc i = elements.iterator(); i.hasNext(); ) {
249                 Element theElement = (Element)i.next();
250
251                 // If an element ref, add as a property; otherwise recurse
252
Attribute ref = theElement.getAttribute("ref");
253                 if (ref == null) {
254                 } else {
255                     // Since this is a reference, add the property
256
String JavaDoc propertyName = ref.getValue();
257                     String JavaDoc propertyType =
258                         NamingUtils.getJavaClassName(propertyName);
259
260                     // XXX: I am sure I broke this! (Sean)
261
AtomicProperty property
262                         = new AtomicProperty(propertyName,
263                                              propertyType);
264
265                     // Determine if a list is needed
266
Attribute maxOccurs = theElement.getAttribute("maxOccurs");
267                     if (maxOccurs != null) {
268                         String JavaDoc value = maxOccurs.getValue();
269
270                         // The value should be either 'unbounded' or an int
271
if (value.equals("unbounded")) {
272                             property.setIsCollection(true);
273                         } else {
274                             try {
275                                 int maxOccursInt = Integer.parseInt(value);
276                                 if (maxOccursInt > 1) {
277                                     property.setIsCollection(true);
278                                 }
279                             } catch (NumberFormatException JavaDoc ignored) {
280                                 // Not a collection, so don't worry about it
281
}
282                         }
283                     }
284
285                     container.addProperty(property);
286                 }
287             }
288         }
289
290         return container;
291     }
292 }
293
Popular Tags