KickJava   Java API By Example, From Geeks To Geeks.

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


1 package com.thaiopensource.validate.nrl;
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.util.PropertyId;
8 import com.thaiopensource.validate.IncorrectSchemaException;
9 import com.thaiopensource.validate.Schema;
10 import com.thaiopensource.validate.ValidateProperty;
11 import com.thaiopensource.validate.Validator;
12 import com.thaiopensource.validate.Option;
13 import com.thaiopensource.validate.OptionArgumentException;
14 import com.thaiopensource.validate.OptionArgumentPresenceException;
15 import com.thaiopensource.validate.AbstractSchema;
16 import com.thaiopensource.validate.SchemaReader;
17 import com.thaiopensource.validate.auto.SchemaFuture;
18 import com.thaiopensource.xml.sax.XmlBaseHandler;
19 import com.thaiopensource.xml.sax.DelegatingContentHandler;
20 import com.thaiopensource.xml.sax.CountingErrorHandler;
21 import com.thaiopensource.xml.util.WellKnownNamespaces;
22 import org.xml.sax.Attributes;
23 import org.xml.sax.ErrorHandler;
24 import org.xml.sax.InputSource;
25 import org.xml.sax.Locator;
26 import org.xml.sax.SAXException;
27 import org.xml.sax.SAXParseException;
28 import org.xml.sax.XMLReader;
29 import org.xml.sax.helpers.LocatorImpl;
30
31 import java.io.IOException;
32 import java.util.Enumeration;
33 import java.util.Hashtable;
34 import java.util.Vector;
35
36 class SchemaImpl extends AbstractSchema {
37   static private final String IMPLICIT_MODE_NAME = "#implicit";
38   static private final String WRAPPER_MODE_NAME = "#wrapper";
39   static final String NRL_URI = SchemaReader.BASE_URI + "nrl";
40   private final Hashtable modeMap = new Hashtable();
41   private Mode startMode;
42   private final Mode defaultBaseMode;
43   private final boolean attributesSchema;
44
45   static private final class WrappedIOException extends RuntimeException {
46     private final IOException exception;
47
48     private WrappedIOException(IOException exception) {
49       this.exception = exception;
50     }
51
52     private IOException getException() {
53       return exception;
54     }
55   }
56
57   static private class MustSupportOption {
58     private final String name;
59     private final PropertyId pid;
60     private final Locator locator;
61
62     MustSupportOption(String name, PropertyId pid, Locator locator) {
63       this.name = name;
64       this.pid = pid;
65       this.locator = locator;
66     }
67   }
68
69   private class Handler extends DelegatingContentHandler implements SchemaFuture {
70     private final SchemaReceiverImpl sr;
71     private boolean hadError = false;
72     private final ErrorHandler eh;
73     private final CountingErrorHandler ceh;
74     private final Localizer localizer = new Localizer(SchemaImpl.class);
75     private Locator locator;
76     private final XmlBaseHandler xmlBaseHandler = new XmlBaseHandler();
77     private int foreignDepth = 0;
78     private Mode currentMode = null;
79     private String defaultSchemaType;
80     private Validator validator;
81     private ElementsOrAttributes match;
82     private ActionSet actions;
83     private AttributeActionSet attributeActions;
84     private String schemaUri;
85     private String schemaType;
86     private PropertyMapBuilder options;
87     private final Vector mustSupportOptions = new Vector();
88     private ModeUsage modeUsage;
89     private boolean anyNamespace;
90
91     Handler(SchemaReceiverImpl sr) {
92       this.sr = sr;
93       this.eh = ValidateProperty.ERROR_HANDLER.get(sr.getProperties());
94       this.ceh = new CountingErrorHandler(this.eh);
95     }
96
97     public void setDocumentLocator(Locator locator) {
98       xmlBaseHandler.setLocator(locator);
99       this.locator = locator;
100     }
101
102     public void startDocument() throws SAXException {
103       try {
104         PropertyMapBuilder builder = new PropertyMapBuilder(sr.getProperties());
105         ValidateProperty.ERROR_HANDLER.put(builder, ceh);
106         validator = sr.getNrlSchema().createValidator(builder.toPropertyMap());
107       }
108       catch (IOException e) {
109         throw new WrappedIOException(e);
110       }
111       catch (IncorrectSchemaException e) {
112         throw new RuntimeException("internal error in RNG schema for NRL");
113       }
114       setDelegate(validator.getContentHandler());
115       if (locator != null)
116         super.setDocumentLocator(locator);
117       super.startDocument();
118     }
119
120     public Schema getSchema() throws IncorrectSchemaException, SAXException {
121       if (validator == null || ceh.getHadErrorOrFatalError())
122         throw new IncorrectSchemaException();
123       Hashset openModes = new Hashset();
124       Hashset checkedModes = new Hashset();
125       for (Enumeration enum = modeMap.keys(); enum.hasMoreElements();) {
126         String modeName = (String)enum.nextElement();
127         Mode mode = (Mode)modeMap.get(modeName);
128         if (!mode.isDefined())
129           error("undefined_mode", modeName, mode.getWhereUsed());
130         for (Mode tem = mode; tem != null; tem = tem.getBaseMode()) {
131           if (checkedModes.contains(tem))
132             break;
133           if (openModes.contains(tem)) {
134             error("mode_cycle", tem.getName(), tem.getWhereDefined());
135             break;
136           }
137           openModes.add(tem);
138         }
139         checkedModes.addAll(openModes);
140         openModes.clear();
141       }
142       if (hadError)
143         throw new IncorrectSchemaException();
144       return SchemaImpl.this;
145     }
146
147     public RuntimeException unwrapException(RuntimeException e) throws SAXException, IOException, IncorrectSchemaException {
148       if (e instanceof WrappedIOException)
149         throw ((WrappedIOException)e).getException();
150       return e;
151     }
152
153     public void startElement(String uri, String localName,
154                              String qName, Attributes attributes)
155             throws SAXException {
156       super.startElement(uri, localName, qName, attributes);
157       xmlBaseHandler.startElement();
158       String xmlBase = attributes.getValue(WellKnownNamespaces.XML, "base");
159       if (xmlBase != null)
160         xmlBaseHandler.xmlBaseAttribute(xmlBase);
161       if (!NRL_URI.equals(uri) || foreignDepth > 0) {
162         foreignDepth++;
163         return;
164       }
165       if (ceh.getHadErrorOrFatalError())
166         return;
167       if (localName.equals("rules"))
168         parseRules(attributes);
169       else if (localName.equals("mode"))
170         parseMode(attributes);
171       else if (localName.equals("namespace"))
172         parseNamespace(attributes);
173       else if (localName.equals("anyNamespace"))
174         parseAnyNamespace(attributes);
175       else if (localName.equals("validate"))
176         parseValidate(attributes);
177       else if (localName.equals("reject"))
178         parseReject(attributes);
179       else if (localName.equals("attach"))
180         parseAttach(attributes);
181       else if (localName.equals("unwrap"))
182         parseUnwrap(attributes);
183       else if (localName.equals("allow"))
184         parseAllow(attributes);
185       else if (localName.equals("context"))
186         parseContext(attributes);
187       else if (localName.equals("option"))
188         parseOption(attributes);
189       else
190         throw new RuntimeException("unexpected element \"" + localName + "\"");
191     }
192
193     public void endElement(String namespaceURI, String localName,
194                            String qName)
195             throws SAXException {
196       super.endElement(namespaceURI, localName, qName);
197       xmlBaseHandler.endElement();
198       if (foreignDepth > 0) {
199         foreignDepth--;
200         return;
201       }
202       if (ceh.getHadErrorOrFatalError())
203         return;
204       if (localName.equals("validate"))
205         finishValidate();
206     }
207
208     private void parseRules(Attributes attributes) {
209       startMode = getModeAttribute(attributes, "startMode");
210       if (startMode == null) {
211         startMode = lookupCreateMode(IMPLICIT_MODE_NAME);
212         currentMode = startMode;
213         startMode.noteDefined(null);
214       }
215       startMode.noteUsed(locator);
216       if (attributesSchema) {
217         Mode wrapper = lookupCreateMode(WRAPPER_MODE_NAME);
218         ActionSet actions = new ActionSet();
219         actions.addNoResultAction(new AllowAction(new ModeUsage(startMode, startMode)));
220         wrapper.bindElement(Mode.ANY_NAMESPACE, actions);
221         wrapper.noteDefined(null);
222         startMode = wrapper;
223       }
224       defaultSchemaType = getSchemaType(attributes);
225     }
226
227     private void parseMode(Attributes attributes) throws SAXException {
228       currentMode = getModeAttribute(attributes, "name");
229       if (currentMode.isDefined()) {
230         error("duplicate_mode", currentMode.getName());
231         error("first_mode", currentMode.getName(), currentMode.getWhereDefined());
232       }
233       else {
234         Mode base = getModeAttribute(attributes, "extends");
235         if (base != null)
236           currentMode.setBaseMode(base);
237         currentMode.noteDefined(locator);
238       }
239     }
240
241     private void parseNamespace(Attributes attributes) throws SAXException {
242       anyNamespace = false;
243       parseRule(getNs(attributes), attributes);
244     }
245
246     private void parseAnyNamespace(Attributes attributes) throws SAXException {
247       anyNamespace = true;
248       parseRule(Mode.ANY_NAMESPACE, attributes);
249     }
250
251     private void parseRule(String ns, Attributes attributes) throws SAXException {
252       match = toElementsOrAttributes(attributes.getValue("", "match"),
253                                      ElementsOrAttributes.ELEMENTS);
254       if (match.containsAttributes()) {
255         attributeActions = new AttributeActionSet();
256         if (!currentMode.bindAttribute(ns, attributeActions)) {
257           if (ns.equals(Mode.ANY_NAMESPACE))
258             error("duplicate_attribute_action_any_namespace");
259           else
260             error("duplicate_attribute_action", ns);
261         }
262       }
263       if (match.containsElements()) {
264         actions = new ActionSet();
265         if (!currentMode.bindElement(ns, actions)) {
266           if (ns.equals(Mode.ANY_NAMESPACE))
267             error("duplicate_element_action_any_namespace");
268           else
269             error("duplicate_element_action", ns);
270         }
271       }
272       else
273         actions = null;
274     }
275
276     private void parseValidate(Attributes attributes) throws SAXException {
277       schemaUri = getSchema(attributes);
278       schemaType = getSchemaType(attributes);
279       if (schemaType == null)
280         schemaType = defaultSchemaType;
281       if (actions != null)
282         modeUsage = getModeUsage(attributes);
283       else
284         modeUsage = null;
285       options = new PropertyMapBuilder();
286       mustSupportOptions.clear();
287     }
288
289     private void finishValidate() throws SAXException {
290       try {
291         if (attributeActions != null) {
292           Schema schema = createSubSchema(true);
293           attributeActions.addSchema(schema);
294         }
295         if (actions != null) {
296           Schema schema = createSubSchema(false);
297           actions.addNoResultAction(new ValidateAction(modeUsage, schema));
298         }
299       }
300       catch (IncorrectSchemaException e) {
301         hadError = true;
302       }
303       catch (IOException e) {
304         throw new WrappedIOException(e);
305       }
306     }
307
308     private Schema createSubSchema(boolean isAttributesSchema) throws IOException, IncorrectSchemaException, SAXException {
309       PropertyMap requestedProperties = options.toPropertyMap();
310       Schema schema = sr.createChildSchema(new InputSource(schemaUri),
311                                            schemaType,
312                                            requestedProperties,
313                                            isAttributesSchema);
314       PropertyMap actualProperties = schema.getProperties();
315       for (Enumeration enum = mustSupportOptions.elements(); enum.hasMoreElements();) {
316         MustSupportOption mso = (MustSupportOption)enum.nextElement();
317         Object actualValue = actualProperties.get(mso.pid);
318         if (actualValue == null)
319           error("unsupported_option", mso.name, mso.locator);
320         else if (!actualValue.equals(requestedProperties.get(mso.pid)))
321           error("unsupported_option_arg", mso.name, mso.locator);
322       }
323       return schema;
324     }
325
326     private void parseOption(Attributes attributes) throws SAXException {
327       boolean mustSupport;
328       String mustSupportValue = attributes.getValue("", "mustSupport");
329       if (mustSupportValue != null) {
330         mustSupportValue = mustSupportValue.trim();
331         mustSupport = mustSupportValue.equals("1") || mustSupportValue.equals("true");
332       }
333       else
334         mustSupport = false;
335       String name = Uri.resolve(NRL_URI, attributes.getValue("", "name"));
336       Option option = sr.getOption(name);
337       if (option == null) {
338         if (mustSupport)
339           error("unknown_option", name);
340       }
341       else {
342         String arg = attributes.getValue("", "arg");
343         try {
344           PropertyId pid = option.getPropertyId();
345           Object value = option.valueOf(arg);
346           Object oldValue = options.get(pid);
347           if (oldValue != null) {
348             value = option.combine(new Object[]{oldValue, value});
349             if (value == null)
350               error("duplicate_option", name);
351             else
352               options.put(pid, value);
353           }
354           else {
355             options.put(pid, value);
356             mustSupportOptions.addElement(new MustSupportOption(name, pid,
357                                                                 locator == null
358                                                                 ? null
359                                                                 : new LocatorImpl(locator)));
360           }
361         }
362         catch (OptionArgumentPresenceException e) {
363           error(arg == null ? "option_requires_argument" : "option_unexpected_argument", name);
364         }
365         catch (OptionArgumentException e) {
366           if (arg == null)
367             error("option_requires_argument", name);
368           else
369             error("option_bad_argument", name, arg);
370         }
371       }
372     }
373
374     private void parseAttach(Attributes attributes) {
375       if (attributeActions != null)
376         attributeActions.setAttach(true);
377       if (actions != null) {
378         modeUsage = getModeUsage(attributes);
379         actions.setResultAction(new AttachAction(modeUsage));
380       }
381       else
382         modeUsage = null;
383     }
384
385     private void parseUnwrap(Attributes attributes) {
386       if (actions != null) {
387         modeUsage = getModeUsage(attributes);
388         actions.setResultAction(new UnwrapAction(modeUsage));
389       }
390       else
391         modeUsage = null;
392     }
393
394     private void parseAllow(Attributes attributes) {
395       if (actions != null) {
396         modeUsage = getModeUsage(attributes);
397         actions.addNoResultAction(new AllowAction(modeUsage));
398       }
399       else
400         modeUsage = null;
401     }
402
403     private void parseReject(Attributes attributes) {
404       if (actions != null) {
405         modeUsage = getModeUsage(attributes);
406         actions.addNoResultAction(new RejectAction(modeUsage));
407       }
408       else
409         modeUsage = null;
410       if (attributeActions != null)
411         attributeActions.setReject(true);
412     }
413
414     private void parseContext(Attributes attributes) throws SAXException {
415       if (anyNamespace) {
416         error("context_any_namespace");
417         return;
418       }
419       Mode mode = getUseMode(attributes);
420       try {
421         Vector paths = Path.parse(attributes.getValue("", "path"));
422         // XXX warning if modeUsage is null
423
if (modeUsage != null) {
424           for (int i = 0, len = paths.size(); i < len; i++) {
425             Path path = (Path)paths.elementAt(i);
426             if (!modeUsage.addContext(path.isRoot(), path.getNames(), mode))
427               error("duplicate_path", path.toString());
428           }
429         }
430       }
431       catch (Path.ParseException e) {
432         error(e.getMessageKey());
433       }
434     }
435
436     private String getSchema(Attributes attributes) throws SAXException {
437       String schemaUri = attributes.getValue("", "schema");
438       if (Uri.hasFragmentId(schemaUri))
439         error("schema_fragment_id");
440       return Uri.resolve(xmlBaseHandler.getBaseUri(),
441                          Uri.escapeDisallowedChars(schemaUri));
442     }
443
444     private String getSchemaType(Attributes attributes) {
445       return attributes.getValue("", "schemaType");
446     }
447
448     private ElementsOrAttributes toElementsOrAttributes(String value, ElementsOrAttributes defaultValue) {
449       if (value == null)
450         return defaultValue;
451       ElementsOrAttributes eoa = ElementsOrAttributes.NEITHER;
452       if (value.indexOf("elements") >= 0)
453         eoa = eoa.addElements();
454       if (value.indexOf("attributes") >= 0)
455         eoa = eoa.addAttributes();
456       return eoa;
457     }
458
459     private ModeUsage getModeUsage(Attributes attributes) {
460       return new ModeUsage(getUseMode(attributes), currentMode);
461     }
462
463     private Mode getUseMode(Attributes attributes) {
464       Mode mode = getModeAttribute(attributes, "useMode");
465       if (mode == null)
466         return Mode.CURRENT;
467       mode.noteUsed(locator);
468       return mode;
469     }
470
471     private String getNs(Attributes attributes) throws SAXException {
472       String ns = attributes.getValue("", "ns");
473       if (ns != null && !Uri.isAbsolute(ns) && !ns.equals(""))
474         error("ns_absolute");
475       return ns;
476     }
477
478     void error(String key) throws SAXException {
479       hadError = true;
480       if (eh == null)
481         return;
482       eh.error(new SAXParseException(localizer.message(key), locator));
483     }
484
485     void error(String key, String arg) throws SAXException {
486       hadError = true;
487       if (eh == null)
488         return;
489       eh.error(new SAXParseException(localizer.message(key, arg), locator));
490     }
491
492     void error(String key, String arg, Locator locator) throws SAXException {
493       hadError = true;
494       if (eh == null)
495         return;
496       eh.error(new SAXParseException(localizer.message(key, arg), locator));
497     }
498
499     void error(String key, String arg1, String arg2) throws SAXException {
500       hadError = true;
501       if (eh == null)
502         return;
503       eh.error(new SAXParseException(localizer.message(key, arg1, arg2), locator));
504     }
505
506   }
507
508   SchemaImpl(PropertyMap properties) {
509     super(properties);
510     this.attributesSchema = properties.contains(NrlProperty.ATTRIBUTES_SCHEMA);
511     makeBuiltinMode("#allow", AllowAction.class);
512     makeBuiltinMode("#attach", AttachAction.class);
513     makeBuiltinMode("#unwrap", UnwrapAction.class);
514     defaultBaseMode = makeBuiltinMode("#reject", RejectAction.class);
515   }
516
517   private Mode makeBuiltinMode(String name, Class cls) {
518     Mode mode = lookupCreateMode(name);
519     ActionSet actions = new ActionSet();
520     ModeUsage modeUsage = new ModeUsage(Mode.CURRENT, mode);
521     if (cls == AttachAction.class)
522       actions.setResultAction(new AttachAction(modeUsage));
523     else if (cls == AllowAction.class)
524       actions.addNoResultAction(new AllowAction(modeUsage));
525     else if (cls == UnwrapAction.class)
526       actions.setResultAction(new UnwrapAction(modeUsage));
527     else
528       actions.addNoResultAction(new RejectAction(modeUsage));
529     mode.bindElement(Mode.ANY_NAMESPACE, actions);
530     mode.noteDefined(null);
531     AttributeActionSet attributeActions = new AttributeActionSet();
532     if (attributesSchema)
533       attributeActions.setReject(true);
534     else
535       attributeActions.setAttach(true);
536     mode.bindAttribute(Mode.ANY_NAMESPACE, attributeActions);
537     return mode;
538   }
539
540   SchemaFuture installHandlers(XMLReader in, SchemaReceiverImpl sr) {
541     Handler h = new Handler(sr);
542     in.setContentHandler(h);
543     return h;
544   }
545
546   public Validator createValidator(PropertyMap properties) {
547     return new ValidatorImpl(startMode, properties);
548   }
549
550   private Mode getModeAttribute(Attributes attributes, String localName) {
551     return lookupCreateMode(attributes.getValue("", localName));
552   }
553
554   private Mode lookupCreateMode(String name) {
555     if (name == null)
556       return null;
557     name = name.trim();
558     Mode mode = (Mode)modeMap.get(name);
559     if (mode == null) {
560       mode = new Mode(name, defaultBaseMode);
561       modeMap.put(name, mode);
562     }
563     return mode;
564   }
565
566 }
567
Popular Tags