KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > thaiopensource > validate > mns > SchemaImpl


1 package com.thaiopensource.validate.mns;
2
3 import com.thaiopensource.util.Localizer;
4 import com.thaiopensource.util.PropertyMap;
5 import com.thaiopensource.util.Uri;
6 import com.thaiopensource.util.PropertyMapBuilder;
7 import com.thaiopensource.validate.IncorrectSchemaException;
8 import com.thaiopensource.validate.Schema;
9 import com.thaiopensource.validate.ValidateProperty;
10 import com.thaiopensource.validate.Validator;
11 import com.thaiopensource.validate.AbstractSchema;
12 import com.thaiopensource.validate.auto.SchemaFuture;
13 import com.thaiopensource.xml.sax.XmlBaseHandler;
14 import com.thaiopensource.xml.sax.DelegatingContentHandler;
15 import com.thaiopensource.xml.sax.CountingErrorHandler;
16 import com.thaiopensource.xml.util.Name;
17 import com.thaiopensource.xml.util.StringSplitter;
18 import com.thaiopensource.xml.util.WellKnownNamespaces;
19 import org.xml.sax.Attributes;
20 import org.xml.sax.ErrorHandler;
21 import org.xml.sax.InputSource;
22 import org.xml.sax.Locator;
23 import org.xml.sax.SAXException;
24 import org.xml.sax.SAXParseException;
25 import org.xml.sax.XMLReader;
26 import org.xml.sax.helpers.LocatorImpl;
27
28 import java.io.IOException;
29 import java.util.Enumeration;
30 import java.util.Hashtable;
31 import java.util.Stack;
32
33 class SchemaImpl extends AbstractSchema {
34   static final String MNS_URI = "http://www.thaiopensource.com/ns/mns";
35   private final Hashtable modeMap = new Hashtable();
36   private Mode startMode;
37   private static final String DEFAULT_MODE_NAME = "#default";
38   private final boolean attributesSchema;
39
40   static private final class WrappedIOException extends RuntimeException {
41     private final IOException exception;
42
43     private WrappedIOException(IOException exception) {
44       this.exception = exception;
45     }
46
47     private IOException getException() {
48       return exception;
49     }
50   }
51
52   static class ElementAction {
53     private final Schema schema;
54     private final Mode mode;
55     private final ContextMap contextMap;
56     private final ElementsOrAttributes prune;
57     private final Hashset covered = new Hashset();
58
59     ElementAction(String ns, Schema schema, Mode mode, ContextMap contextMap, ElementsOrAttributes prune) {
60       this.schema = schema;
61       this.mode = mode;
62       this.contextMap = contextMap;
63       this.prune = prune;
64       covered.add(ns);
65     }
66
67     Mode getMode() {
68       return mode;
69     }
70
71     ContextMap getContextMap() {
72       return contextMap;
73     }
74
75     Schema getSchema() {
76       return schema;
77     }
78
79     ElementsOrAttributes getPrune() {
80       return prune;
81     }
82
83     Hashset getCoveredNamespaces() {
84       return covered;
85     }
86   }
87
88   static class Mode {
89     private Locator whereDefined;
90     private boolean defined = false;
91     private ElementsOrAttributes lax;
92     private boolean strictDefined = false;
93     private final Hashtable elementMap = new Hashtable();
94     private final Hashtable attributesMap = new Hashtable();
95
96     Mode(ElementsOrAttributes lax) {
97       this.lax = lax;
98     }
99
100     ElementsOrAttributes getLax() {
101       return lax;
102     }
103
104     Schema getAttributesSchema(String ns) {
105       return (Schema)attributesMap.get(ns);
106     }
107
108     ElementAction getElementAction(String ns) {
109       return (ElementAction)elementMap.get(ns);
110     }
111   }
112
113   private class Handler extends DelegatingContentHandler implements SchemaFuture {
114     private final SchemaReceiverImpl sr;
115     private ElementAction currentElementAction;
116     private boolean hadError = false;
117     private final ErrorHandler eh;
118     private final CountingErrorHandler ceh;
119     private final Localizer localizer = new Localizer(SchemaImpl.class);
120     private Locator locator;
121     private final XmlBaseHandler xmlBaseHandler = new XmlBaseHandler();
122     private int foreignDepth = 0;
123     private String contextNs;
124     private Mode contextMode;
125     private String elementNs;
126     private String defaultSchemaType;
127     private final Stack nameStack = new Stack();
128     private boolean isRoot;
129     private int pathDepth = 0;
130     private Validator validator;
131
132
133     Handler(SchemaReceiverImpl sr) {
134       this.sr = sr;
135       this.eh = ValidateProperty.ERROR_HANDLER.get(sr.getProperties());
136       this.ceh = new CountingErrorHandler(eh);
137     }
138
139     public void setDocumentLocator(Locator locator) {
140       xmlBaseHandler.setLocator(locator);
141       this.locator = locator;
142     }
143
144     public void startDocument() throws SAXException {
145       try {
146         PropertyMapBuilder builder = new PropertyMapBuilder(sr.getProperties());
147         ValidateProperty.ERROR_HANDLER.put(builder, ceh);
148         validator = sr.getMnsSchema().createValidator(builder.toPropertyMap());
149       }
150       catch (IOException e) {
151         throw new WrappedIOException(e);
152       }
153       catch (IncorrectSchemaException e) {
154         throw new RuntimeException("internal error in RNG schema for MNS");
155       }
156       setDelegate(validator.getContentHandler());
157       if (locator != null)
158         super.setDocumentLocator(locator);
159       super.startDocument();
160     }
161
162     public Schema getSchema() throws IncorrectSchemaException, SAXException {
163       if (validator == null || ceh.getHadErrorOrFatalError())
164         throw new IncorrectSchemaException();
165       for (Enumeration enum = modeMap.keys(); enum.hasMoreElements();) {
166         String modeName = (String)enum.nextElement();
167         Mode mode = (Mode)modeMap.get(modeName);
168         if (!mode.defined && !modeName.equals(DEFAULT_MODE_NAME))
169           error("undefined_mode", modeName, mode.whereDefined);
170       }
171       if (hadError)
172         throw new IncorrectSchemaException();
173       return SchemaImpl.this;
174     }
175
176     public RuntimeException unwrapException(RuntimeException e) throws SAXException, IOException, IncorrectSchemaException {
177       if (e instanceof WrappedIOException)
178         throw ((WrappedIOException)e).getException();
179       return e;
180     }
181
182     public void startElement(String uri, String localName,
183                              String qName, Attributes attributes)
184             throws SAXException {
185       super.startElement(uri, localName, qName, attributes);
186       xmlBaseHandler.startElement();
187       String xmlBase = attributes.getValue(WellKnownNamespaces.XML, "base");
188       if (xmlBase != null)
189         xmlBaseHandler.xmlBaseAttribute(xmlBase);
190       if (!MNS_URI.equals(uri) || foreignDepth > 0) {
191         foreignDepth++;
192         return;
193       }
194       if (ceh.getHadErrorOrFatalError())
195         return;
196       if (localName.equals("rules"))
197         parseRules(attributes);
198       else if (localName.equals("cover"))
199         parseCover(attributes);
200       else if (localName.equals("context"))
201         parseContext(attributes);
202       else if (localName.equals("root"))
203         parseRoot(attributes);
204       else if (localName.equals("element"))
205         parseElement(attributes);
206       else if (localName.equals("lax"))
207         parseLax(attributes);
208       else
209         parseValidate(localName.equals("validateAttributes"), attributes);
210     }
211
212     public void endElement(String namespaceURI, String localName,
213                            String qName)
214             throws SAXException {
215       super.endElement(namespaceURI, localName, qName);
216       xmlBaseHandler.endElement();
217       if (foreignDepth > 0) {
218         foreignDepth--;
219         return;
220       }
221      if (pathDepth > 0) {
222         pathDepth--;
223         if (pathDepth == 0)
224           endPath();
225       }
226     }
227
228
229     private void parseRules(Attributes attributes) {
230       String modeName = attributes.getValue("", "startMode");
231       if (modeName == null)
232         modeName = DEFAULT_MODE_NAME;
233       defaultSchemaType = getSchemaType(attributes);
234       startMode = lookupCreateMode(modeName);
235     }
236
237     private void parseCover(Attributes attributes) throws SAXException {
238       String ns = getNs(attributes, false);
239       currentElementAction.covered.add(ns);
240     }
241
242     private void parseLax(Attributes attributes) throws SAXException {
243       String[] modeNames = getInModes(attributes);
244       Mode[] modes = getModes(modeNames);
245       ElementsOrAttributes lax = toElementsOrAttributes(attributes.getValue("", "allow"),
246                                                         ElementsOrAttributes.BOTH);
247       for (int i = 0; i < modes.length; i++) {
248         if (modes[i].strictDefined)
249           error("lax_multiply_defined", modeNames[i]);
250         else {
251           modes[i].lax = lax;
252           modes[i].strictDefined = true;
253         }
254       }
255     }
256
257     private void parseValidate(boolean isAttribute, Attributes attributes) throws SAXException {
258       String[] modeNames = getInModes(attributes);
259       Mode[] modes = getModes(modeNames);
260       String ns = getNs(attributes, isAttribute);
261       String schemaUri = getSchema(attributes);
262       String schemaType = getSchemaType(attributes);
263       if (schemaType == null)
264         schemaType = defaultSchemaType;
265       try {
266         if (isAttribute) {
267           Schema schema = sr.createChildSchema(new InputSource(schemaUri), schemaType, true);
268           for (int i = 0; i < modes.length; i++) {
269             if (modes[i].attributesMap.get(ns) != null)
270               error("validate_attributes_multiply_defined", modeNames[i], ns);
271             else
272               modes[i].attributesMap.put(ns, schema);
273           }
274         }
275         else {
276           Schema schema = sr.createChildSchema(new InputSource(schemaUri), schemaType, false);
277           currentElementAction = new ElementAction(ns,
278                                                    schema,
279                                                    getUseMode(attributes),
280                                                    new ContextMap(),
281                                                    getPrune(attributes));
282           contextNs = ns;
283           for (int i = 0; i < modes.length; i++) {
284             if (modes[i].elementMap.get(ns) != null)
285               error("validate_element_multiply_defined", modeNames[i], ns);
286             else
287               modes[i].elementMap.put(ns, currentElementAction);
288           }
289         }
290       }
291       catch (IncorrectSchemaException e) {
292         hadError = true;
293       }
294       catch (IOException e) {
295         throw new WrappedIOException(e);
296       }
297     }
298
299     private void parseContext(Attributes attributes) throws SAXException {
300       String ns = getNs(attributes, false);
301       if (ns != null)
302         contextNs = ns;
303       elementNs = contextNs;
304       contextMode = getUseMode(attributes);
305     }
306
307     private void parseRoot(Attributes attributes) throws SAXException {
308       String ns = getNs(attributes, false);
309       if (ns != null)
310         elementNs = ns;
311       isRoot = true;
312       pathDepth++;
313     }
314
315     private void parseElement(Attributes attributes) throws SAXException {
316       String ns = getNs(attributes, false);
317       if (ns != null)
318         elementNs = ns;
319       if (!currentElementAction.covered.contains(elementNs))
320         error("context_ns_not_covered", elementNs);
321       nameStack.push(new Name(elementNs, attributes.getValue("", "name").trim()));
322       pathDepth++;
323     }
324
325     private void endPath() throws SAXException {
326       if (!currentElementAction.contextMap.put(isRoot, nameStack, contextMode))
327         error("path_multiply_defined", displayPath(isRoot, nameStack));
328       elementNs = contextNs;
329       isRoot = false;
330       nameStack.setSize(0);
331     }
332
333     private String displayPath(boolean isRoot, Stack nameStack) {
334       StringBuffer buf = new StringBuffer();
335       for (int i = 0, len = nameStack.size(); i < len; i++) {
336         if (i > 0 || isRoot)
337           buf.append('/');
338         Name name = (Name)nameStack.elementAt(i);
339         if (name.getNamespaceUri().length() > 0) {
340           buf.append('{');
341           buf.append(name.getNamespaceUri());
342           buf.append('}');
343         }
344         buf.append(name.getLocalName());
345       }
346       return buf.toString();
347     }
348
349     private String getSchema(Attributes attributes) throws SAXException {
350       String schemaUri = attributes.getValue("", "schema");
351       if (Uri.hasFragmentId(schemaUri))
352         error("schema_fragment_id");
353       return Uri.resolve(xmlBaseHandler.getBaseUri(),
354                          Uri.escapeDisallowedChars(schemaUri));
355     }
356
357     private String getSchemaType(Attributes attributes) {
358       return attributes.getValue("", "schemaType");
359     }
360
361     private ElementsOrAttributes getPrune(Attributes attributes) {
362       return toElementsOrAttributes(attributes.getValue("", "prune"),
363                                     ElementsOrAttributes.NEITHER);
364     }
365
366     private ElementsOrAttributes toElementsOrAttributes(String value, ElementsOrAttributes defaultValue) {
367       if (value == null)
368         return defaultValue;
369       ElementsOrAttributes eoa = ElementsOrAttributes.NEITHER;
370       if (value.indexOf("elements") >= 0)
371         eoa = eoa.addElements();
372       if (value.indexOf("attributes") >= 0)
373         eoa = eoa.addAttributes();
374       return eoa;
375     }
376
377     private Mode getUseMode(Attributes attributes) {
378       String modeName = attributes.getValue("", "useMode");
379       if (modeName == null)
380         modeName = DEFAULT_MODE_NAME;
381       Mode mode = lookupCreateMode(modeName);
382       if (mode.whereDefined == null && locator != null)
383         mode.whereDefined = new LocatorImpl(locator);
384       return mode;
385     }
386
387     private String getNs(Attributes attributes, boolean forbidEmpty) throws SAXException {
388       String ns = attributes.getValue("", "ns");
389       if (ns != null && !Uri.isAbsolute(ns) && (forbidEmpty || !ns.equals("")))
390         error("ns_absolute");
391       return ns;
392     }
393
394     private Mode[] getModes(String[] modeNames) {
395       Mode[] modes = new Mode[modeNames.length];
396       for (int i = 0; i < modes.length; i++) {
397         modes[i] = lookupCreateMode(modeNames[i]);
398         modes[i].defined = true;
399       }
400       return modes;
401     }
402
403     private String[] getInModes(Attributes attributes) {
404       String inModes = attributes.getValue("", "inModes");
405       if (inModes == null)
406         return new String[] { DEFAULT_MODE_NAME };
407       return StringSplitter.split(inModes);
408     }
409
410
411     void error(String key) throws SAXException {
412       hadError = true;
413       if (eh == null)
414         return;
415       eh.error(new SAXParseException(localizer.message(key), locator));
416     }
417
418     void error(String key, String arg) throws SAXException {
419       hadError = true;
420       if (eh == null)
421         return;
422       eh.error(new SAXParseException(localizer.message(key, arg), locator));
423     }
424
425     void error(String key, String arg, Locator locator) throws SAXException {
426       hadError = true;
427       if (eh == null)
428         return;
429       eh.error(new SAXParseException(localizer.message(key, arg), locator));
430     }
431
432     void error(String key, String arg1, String arg2) throws SAXException {
433       hadError = true;
434       if (eh == null)
435         return;
436       eh.error(new SAXParseException(localizer.message(key, arg1, arg2), locator));
437     }
438
439   }
440
441   SchemaImpl(boolean attributesSchema) {
442     this.attributesSchema = attributesSchema;
443   }
444
445   SchemaFuture installHandlers(XMLReader in, SchemaReceiverImpl sr) {
446     Handler h = new Handler(sr);
447     in.setContentHandler(h);
448     return h;
449   }
450
451   public Validator createValidator(PropertyMap properties) {
452     return new ValidatorImpl(startMode, properties);
453   }
454
455   private Mode lookupCreateMode(String name) {
456     Mode mode = (Mode)modeMap.get(name);
457     if (mode == null) {
458       mode = new Mode(attributesSchema ? ElementsOrAttributes.ELEMENTS : ElementsOrAttributes.NEITHER);
459       modeMap.put(name, mode);
460     }
461     return mode;
462   }
463
464 }
465
Popular Tags