001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.xml.impl;
017:
018: import java.util.ArrayList;
019: import java.util.HashSet;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Set;
023:
024: import org.eclipse.xsd.XSDComplexTypeDefinition;
025: import org.eclipse.xsd.XSDElementDeclaration;
026: import org.eclipse.xsd.XSDEnumerationFacet;
027: import org.eclipse.xsd.XSDFacet;
028: import org.eclipse.xsd.XSDFactory;
029: import org.eclipse.xsd.XSDLengthFacet;
030: import org.eclipse.xsd.XSDMaxLengthFacet;
031: import org.eclipse.xsd.XSDMinLengthFacet;
032: import org.eclipse.xsd.XSDNamedComponent;
033: import org.eclipse.xsd.XSDSimpleTypeDefinition;
034: import org.eclipse.xsd.XSDTypeDefinition;
035: import org.eclipse.xsd.XSDVariety;
036: import org.eclipse.xsd.XSDWhiteSpace;
037: import org.eclipse.xsd.XSDWhiteSpaceFacet;
038: import org.geotools.xml.Binding;
039: import org.geotools.xml.ComplexBinding;
040: import org.geotools.xml.ElementInstance;
041: import org.geotools.xml.InstanceComponent;
042: import org.geotools.xml.Node;
043: import org.geotools.xml.Schemas;
044: import org.geotools.xml.SimpleBinding;
045: import org.geotools.xml.impl.BindingWalker.Visitor;
046: import org.geotools.xs.facets.Whitespace;
047: import org.picocontainer.MutablePicoContainer;
048:
049: public class ParseExecutor implements Visitor {
050: private InstanceComponent instance;
051: private Node node;
052: private MutablePicoContainer context;
053: private ParserHandler parser;
054:
055: /**
056: * initial binding value
057: */
058: private Object value;
059: /**
060: * final parsed result
061: */
062: private Object result;
063:
064: public ParseExecutor(InstanceComponent instance, Node node,
065: MutablePicoContainer context, ParserHandler parser) {
066: this .instance = instance;
067: this .node = node;
068: this .context = context;
069: this .parser = parser;
070: }
071:
072: public void visit(Binding binding) {
073: //reload out of context, we do this so that the binding can pick up any new dependencies
074: // providedb by this particular context
075: Class bindingClass = binding.getClass();
076: binding = (Binding) context.getComponentInstanceOfType(binding
077: .getClass());
078: if (binding == null) {
079: binding = parser.getBindingLoader().loadBinding(
080: bindingClass, context);
081: }
082:
083: //execute the binding
084: try {
085: if (result == null) {
086: //no result has been produced yet, should we pass the facet
087: // parsed text in? only for simple types or complex types with
088: // mixed content
089: XSDTypeDefinition type = null;
090: if (Schemas.nameMatches(instance.getDeclaration(),
091: binding.getTarget())) {
092: //instance binding
093: type = instance.getTypeDefinition();
094: } else {
095: //type binding
096: type = Schemas.getBaseTypeDefinition(instance
097: .getTypeDefinition(), binding.getTarget());
098: }
099:
100: if (value == null) {
101: //have not preprocessed raw string yet
102: //value = parseFacets( instance );
103: value = preParse(instance);
104:
105: //if the type is simple or complex and mixed, use the
106: // text as is, other wise trim it, turning to null if the
107: // result is empty
108: if (type != null
109: && (type instanceof XSDSimpleTypeDefinition || ((XSDComplexTypeDefinition) type)
110: .isMixed())) {
111: result = value;
112: } else {
113: if (value != null && value instanceof String) {
114: value = ((String) value).trim();
115: if ("".equals(value)) {
116: result = null;
117: } else {
118: result = value;
119: }
120: }
121: }
122:
123: }
124:
125: }
126:
127: if (binding instanceof SimpleBinding) {
128: result = ((SimpleBinding) binding).parse(instance,
129: result);
130: } else {
131: result = ((ComplexBinding) binding).parse(
132: (ElementInstance) instance, node, result);
133: }
134:
135: //only pass the value along if it was non-null
136: if (result != null) {
137: value = result;
138: }
139: } catch (Throwable t) {
140: String msg = "Parsing failed for " + instance.getName()
141: + ": " + t.toString();
142: throw new RuntimeException(msg, t);
143: }
144: }
145:
146: public Object getValue() {
147: return value;
148: }
149:
150: /**
151: * Pre-parses the instance compontent checking the following:
152: * <p>
153: *
154: * </p>
155: * @param instance
156: */
157: protected Object preParse(InstanceComponent instance) {
158: // we only preparse text, so simple types
159: XSDSimpleTypeDefinition type = null;
160: if (instance.getTypeDefinition() instanceof XSDSimpleTypeDefinition) {
161: type = (XSDSimpleTypeDefinition) instance
162: .getTypeDefinition();
163: } else {
164: XSDComplexTypeDefinition complexType = (XSDComplexTypeDefinition) instance
165: .getTypeDefinition();
166: if (complexType.getContentType() instanceof XSDSimpleTypeDefinition) {
167: type = (XSDSimpleTypeDefinition) complexType
168: .getContentType();
169: }
170: }
171:
172: String text = instance.getText();
173: if (type != null) {
174:
175: //alright, lets preparse some text
176: //first base on variety
177: if (type.getVariety() == XSDVariety.LIST_LITERAL) {
178:
179: //list, whiteSpace is fixed to "COLLAPSE
180: text = Whitespace.COLLAPSE.preparse(text);
181:
182: //lists are seperated by spaces
183: String[] list = text.split(" +");
184:
185: //apply the facets
186: // 1. length
187: // 2. maxLength
188: // 3. minLength
189: // 4. enumeration
190: if (type.getLengthFacet() != null) {
191: XSDLengthFacet length = type.getLengthFacet();
192: if (list.length != length.getValue()) {
193: //validation exception
194: }
195: }
196: if (type.getMaxLengthFacet() != null) {
197: XSDMaxLengthFacet length = type.getMaxLengthFacet();
198: if (list.length > length.getValue()) {
199: //validation exception
200: }
201: }
202: if (type.getMinLengthFacet() != null) {
203: XSDMinLengthFacet length = type.getMinLengthFacet();
204: if (list.length < length.getValue()) {
205: //validation exception
206: }
207: }
208: if (!type.getEnumerationFacets().isEmpty()) {
209: //gather up all teh possible values
210: Set values = new HashSet();
211: for (Iterator e = type.getEnumerationFacets()
212: .iterator(); e.hasNext();) {
213: XSDEnumerationFacet enumeration = (XSDEnumerationFacet) e
214: .next();
215: for (Iterator v = enumeration.getValue()
216: .iterator(); v.hasNext();) {
217: values.add(v.next());
218: }
219: }
220:
221: for (int i = 0; i < list.length; i++) {
222: if (!values.contains(list[i])) {
223: //validation exception
224: }
225: }
226: }
227:
228: //now we must parse the items up
229: final XSDSimpleTypeDefinition itemType = type
230: .getItemTypeDefinition();
231: List parsed = new ArrayList();
232: for (int i = 0; i < list.length; i++) {
233: //create a pseudo declaration
234: final XSDElementDeclaration element = XSDFactory.eINSTANCE
235: .createXSDElementDeclaration();
236: element.setTypeDefinition(itemType);
237:
238: if (instance.getName() != null) {
239: element.setName(instance.getName());
240: }
241: if (instance.getNamespace() != null) {
242: element.setTargetNamespace(instance
243: .getNamespace());
244: }
245:
246: //create a new instance of the specified type
247: InstanceComponentImpl theInstance = new InstanceComponentImpl() {
248:
249: public XSDTypeDefinition getTypeDefinition() {
250: return itemType;
251: }
252:
253: public XSDNamedComponent getDeclaration() {
254: return element;
255: };
256:
257: };
258: theInstance.setText(list[i]);
259:
260: //perform the parse
261: ParseExecutor executor = new ParseExecutor(
262: theInstance, null, context, parser);
263: parser.getBindingWalker().walk(element, executor,
264: context);
265:
266: parsed.add(executor.getValue());
267: }
268:
269: return parsed;
270: } else if (type.getVariety() == XSDVariety.UNION_LITERAL) {
271: //union, "valueSpace" and "lexicalSpace" facets are the union of the contained
272: // datatypes
273: return text;
274: } else {
275: //atomic
276:
277: //walk through the facets and preparse as necessary
278: for (Iterator f = type.getFacets().iterator(); f
279: .hasNext();) {
280: XSDFacet facet = (XSDFacet) f.next();
281:
282: //white space
283: if (facet instanceof XSDWhiteSpaceFacet) {
284: XSDWhiteSpaceFacet whitespace = (XSDWhiteSpaceFacet) facet;
285: if (whitespace.getValue() == XSDWhiteSpace.REPLACE_LITERAL) {
286: text = Whitespace.REPLACE.preparse(text);
287: }
288: if (whitespace.getValue() == XSDWhiteSpace.COLLAPSE_LITERAL) {
289: text = Whitespace.COLLAPSE.preparse(text);
290: }
291: if (whitespace.getValue() == XSDWhiteSpace.PRESERVE_LITERAL) {
292: //do nothing
293: }
294:
295: }
296: }
297:
298: return text;
299: }
300:
301: } else {
302: //type is not simple, or complex with simple content, do a check
303: // for mixed
304: if (instance.getTypeDefinition() instanceof XSDComplexTypeDefinition
305: && ((XSDComplexTypeDefinition) instance
306: .getTypeDefinition()).isMixed()) {
307: //collape the text
308: text = Whitespace.COLLAPSE.preparse(text);
309: }
310: }
311:
312: return text;
313: }
314:
315: protected Object parseFacets(InstanceComponent instance) {
316: XSDTypeDefinition type = instance.getTypeDefinition();
317:
318: String value = instance.getText();
319:
320: while (type != null) {
321: if (type instanceof XSDSimpleTypeDefinition) {
322: XSDSimpleTypeDefinition simpleType = (XSDSimpleTypeDefinition) type;
323: List facets = simpleType.getFacets();
324:
325: for (Iterator itr = facets.iterator(); itr.hasNext();) {
326: XSDFacet facet = (XSDFacet) itr.next();
327:
328: if ("whiteSpace".equals(facet.getFacetName())) {
329: Whitespace whitespace = Whitespace
330: .valueOf(facet.getLexicalValue());
331:
332: if (whitespace != null) {
333: value = whitespace.preparse(value);
334: }
335:
336: //else TODO: check for validation, throw exception?
337: }
338:
339: //TODO: other facets
340: }
341: }
342:
343: if (type.equals(type.getBaseType())) {
344: break;
345: }
346:
347: type = type.getBaseType();
348: }
349:
350: return value;
351: }
352: }
|