001: //
002: // This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v1.0.4-b18-fcs
003: // See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a>
004: // Any modifications to this file will be lost upon recompilation of the source schema.
005: // Generated on: 2005.03.04 at 10:20:40 PST
006: //
007:
008: package com.nabhinc.portal.config.impl.runtime;
009:
010: import javax.xml.bind.ValidationEvent;
011:
012: import org.relaxng.datatype.Datatype;
013: import org.xml.sax.SAXException;
014: import org.xml.sax.helpers.AttributesImpl;
015:
016: import com.sun.msv.grammar.IDContextProvider2;
017: import com.sun.msv.util.LightStack;
018: import com.sun.msv.util.StartTagInfo;
019: import com.sun.msv.util.StringRef;
020: import com.sun.msv.verifier.Acceptor;
021: import com.sun.msv.verifier.regexp.StringToken;
022: import com.sun.xml.bind.JAXBAssertionError;
023: import com.sun.xml.bind.JAXBObject;
024: import com.sun.xml.bind.RIElement;
025: import com.sun.xml.bind.marshaller.IdentifiableObject;
026: import com.sun.xml.bind.serializer.AbortSerializationException;
027: import com.sun.xml.bind.serializer.Util;
028: import com.sun.xml.bind.validator.Messages;
029:
030: /**
031: * XMLSerializer that calls the native interface of MSV and performs validation.
032: * Used in a pair with a ValidationContext.
033: *
034: * @author Kohsuke Kawaguchi
035: */
036: public class MSVValidator implements XMLSerializer, IDContextProvider2 {
037: /** Current acceptor in use. */
038: private Acceptor acceptor;
039:
040: /** Context object that coordinates the entire validation effort. */
041: private final ValidationContext context;
042:
043: /** The object which we are validating. */
044: private final ValidatableObject target;
045:
046: final DefaultJAXBContextImpl jaxbContext;
047:
048: /**
049: * Acceptor stack. Whenever an element is found, the current acceptor is
050: * pushed to the stack and new one is created.
051: *
052: * LightStack is a light-weight stack implementation
053: */
054: private final LightStack stack = new LightStack();
055:
056: public NamespaceContext2 getNamespaceContext() {
057: return context.getNamespaceContext();
058: }
059:
060: /**
061: * To use this class, call the static validate method.
062: */
063: private MSVValidator(DefaultJAXBContextImpl _jaxbCtx,
064: ValidationContext _ctxt, ValidatableObject vo) {
065: jaxbContext = _jaxbCtx;
066: acceptor = vo.createRawValidator().createAcceptor();
067: context = _ctxt;
068: target = vo;
069: }
070:
071: /**
072: * Validates the specified object and reports any error to the context.
073: */
074: public static void validate(DefaultJAXBContextImpl jaxbCtx,
075: ValidationContext context, ValidatableObject vo)
076: throws SAXException {
077: try {
078: new MSVValidator(jaxbCtx, context, vo)._validate();
079: } catch (RuntimeException e) {
080: // sometimes when a conversion between Java object and
081: // lexical value fails, it may throw an exception like
082: // NullPointerException or NumberFormatException.
083: //
084: // catch them and report them as an error.
085: context.reportEvent(vo, e);
086: }
087: }
088:
089: /** performs the validation to the object specified in the constructor. */
090: private void _validate() throws SAXException {
091: context.getNamespaceContext().startElement();
092:
093: // validate attributes
094: target.serializeURIs(this );
095:
096: endNamespaceDecls();
097:
098: target.serializeAttributes(this );
099:
100: endAttributes();
101:
102: // validate content model
103: target.serializeBody(this );
104: writePendingText();
105:
106: context.getNamespaceContext().endElement();
107:
108: if (!acceptor.isAcceptState(null)) {
109: // some elements are missing
110: // report error
111: StringRef ref = new StringRef();
112: acceptor.isAcceptState(ref);
113: context.reportEvent(target, ref.str);
114: }
115: }
116:
117: public void endNamespaceDecls() throws SAXException {
118: context.getNamespaceContext().endNamespaceDecls();
119: }
120:
121: public void endAttributes() throws SAXException {
122: if (!acceptor.onEndAttributes(null, null)) {
123: // some required attributes are missing.
124: // report a validation error
125: // Note that we don't know which property of this object
126: // causes this error.
127: StringRef ref = new StringRef();
128: StartTagInfo sti = new StartTagInfo(currentElementUri,
129: currentElementLocalName, currentElementLocalName,
130: emptyAttributes, this );
131: acceptor.onEndAttributes(sti, ref);
132: context.reportEvent(target, ref.str);
133: }
134: }
135:
136: /** stores text reported by the text method. */
137: private StringBuffer buf = new StringBuffer();
138:
139: public final void text(String text, String fieldName)
140: throws SAXException {
141: if (text == null) {
142: reportMissingObjectError(fieldName);
143: return;
144: }
145:
146: if (buf.length() != 0)
147: buf.append(' ');
148: buf.append(text);
149: }
150:
151: public void reportMissingObjectError(String fieldName)
152: throws SAXException {
153: reportError(Util.createMissingObjectError(target, fieldName));
154: }
155:
156: // used to keep attribute names until the endAttribute method is called.
157: private String attNamespaceUri;
158: private String attLocalName;
159: private boolean insideAttribute;
160:
161: public void startAttribute(String uri, String local) {
162: // we will do the processing at the end element
163: this .attNamespaceUri = uri;
164: this .attLocalName = local;
165: insideAttribute = true;
166: }
167:
168: public void endAttribute() throws SAXException {
169: insideAttribute = false;
170: if (!acceptor
171: .onAttribute2(
172: attNamespaceUri,
173: attLocalName,
174: attLocalName /* we don't have QName, so just use the local name */,
175: buf.toString(), this , null, null)) {
176:
177: // either the name was incorrect (which is quite unlikely),
178: // or the value was wrong.
179: // report an error
180: StringRef ref = new StringRef();
181: acceptor.onAttribute2(attNamespaceUri, attLocalName,
182: attLocalName, buf.toString(), this , ref, null);
183:
184: context.reportEvent(target, ref.str);
185: }
186:
187: buf = new StringBuffer();
188: }
189:
190: private void writePendingText() throws SAXException {
191: // assert(textBuf!=null);
192: if (!acceptor.onText2(buf.toString(), this , null, null)) {
193: // this text is invalid.
194: // report an error
195: StringRef ref = new StringRef();
196: acceptor.onText2(buf.toString(), this , ref, null);
197: context.reportEvent(target, ref.str);
198: }
199:
200: if (buf.length() > 1024)
201: buf = new StringBuffer();
202: else
203: buf.setLength(0);
204: }
205:
206: private String currentElementUri;
207: private String currentElementLocalName;
208:
209: public void startElement(String uri, String local)
210: throws SAXException {
211: writePendingText();
212:
213: context.getNamespaceContext().startElement();
214:
215: stack.push(acceptor);
216:
217: StartTagInfo sti = new StartTagInfo(uri, local, local,
218: emptyAttributes, this );
219:
220: // we pass in an empty attributes, as there is just no way for us to
221: // properly re-construct attributes. Fortunately, I know MSV is not using
222: // attribute values, so this would work, but nevertheless this code is
223: // ugly. This is one of the problems of the "middle" approach.
224: Acceptor child = acceptor.createChildAcceptor(sti, null);
225: if (child == null) {
226: // this element is invalid. probably, so this object is invalid
227: // report an error
228: StringRef ref = new StringRef();
229: child = acceptor.createChildAcceptor(sti, ref);
230: context.reportEvent(target, ref.str);
231: }
232:
233: this .currentElementUri = uri;
234: this .currentElementLocalName = local;
235:
236: acceptor = child;
237: }
238:
239: public void endElement() throws SAXException {
240: writePendingText();
241:
242: if (!acceptor.isAcceptState(null)) {
243: // some required elements are missing
244: // report error
245: StringRef ref = new StringRef();
246: acceptor.isAcceptState(ref);
247: context.reportEvent(target, ref.str);
248: }
249:
250: // pop the acceptor
251: Acceptor child = acceptor;
252: acceptor = (Acceptor) stack.pop();
253: if (!acceptor.stepForward(child, null)) {
254: // some required elements are missing.
255: // report an error
256: StringRef ref = new StringRef();
257: acceptor.stepForward(child, ref); // force recovery and obtain an error message.
258:
259: context.reportEvent(target, ref.str);
260: }
261:
262: context.getNamespaceContext().endElement();
263: }
264:
265: public void childAsAttributes(JAXBObject o, String fieldName)
266: throws SAXException {
267: // do nothing
268:
269: // either the onMarshallableObjectInElement method
270: // or the onMarshallableObjectInAttributeBody method will be
271: // called for every content tree objects.
272: //
273: // so we don't need to validate an object within this method.
274: }
275:
276: public void childAsURIs(JAXBObject o, String fieldName)
277: throws SAXException {
278: // ditto.
279: }
280:
281: /** An empty <code>Attributes</code> object. */
282: private static final AttributesImpl emptyAttributes = new AttributesImpl();
283:
284: /** namespace URI of dummy elements. TODO: allocate one namespace URI for this. */
285: public static final String DUMMY_ELEMENT_NS = "http://java.sun.com/jaxb/xjc/dummy-elements";
286:
287: public void childAsBody(JAXBObject o, String fieldName)
288: throws SAXException {
289: //final ValidatableObject vo = Util.toValidatableObject(o);
290: final ValidatableObject vo = jaxbContext.getGrammarInfo()
291: .castToValidatableObject(o);
292:
293: if (vo == null) {
294: reportMissingObjectError(fieldName);
295: return;
296: }
297:
298: if (insideAttribute)
299: childAsAttributeBody(vo, fieldName);
300: else
301: childAsElementBody(o, vo);
302: }
303:
304: private void childAsElementBody(Object o, ValidatableObject vo)
305: throws SAXException {
306: String intfName = vo.getPrimaryInterface().getName();
307: intfName = intfName.replace('$', '.');
308:
309: // if the object implements the RIElement interface,
310: // add a marker attribute to the dummy element.
311: //
312: // For example, if the object is org.acme.impl.FooImpl,
313: // the dummy element will look like
314: // <{DUMMY_ELEMENT_NS}org.acme.Foo
315: // {<URI of this element>}:<local name of this element>="" />
316: //
317: // This extra attribute is used to validate wildcards.
318: // AttributesImpl atts;
319: // if(o instanceof RIElement) {
320: // RIElement rie = (RIElement)o;
321: // atts = new AttributesImpl();
322: // atts.addAttribute(
323: // rie.____jaxb_ri____getNamespaceURI(),
324: // rie.____jaxb_ri____getLocalName(),
325: // rie.____jaxb_ri____getLocalName(), // use local name as qname
326: // "CDATA",
327: // ""); // we don't care about the attribute value
328: // } else
329: // atts = emptyAttributes;
330:
331: // feed a dummy element to the acceptor.
332: StartTagInfo sti = new StartTagInfo(DUMMY_ELEMENT_NS, intfName,
333: intfName/*just pass the local name as QName.*/,
334: emptyAttributes, this );
335:
336: Acceptor child = acceptor.createChildAcceptor(sti, null);
337: if (child == null) {
338: // some required elements were missing. report errors
339: StringRef ref = new StringRef();
340: child = acceptor.createChildAcceptor(sti, ref);
341: context.reportEvent(target, ref.str);
342: }
343:
344: if (o instanceof RIElement) {
345: RIElement rie = (RIElement) o;
346: if (!child.onAttribute2(rie
347: .____jaxb_ri____getNamespaceURI(), rie
348: .____jaxb_ri____getLocalName(), rie
349: .____jaxb_ri____getLocalName(), "", null, null,
350: null))
351:
352: // this object is not a valid member of the wildcard
353: context.reportEvent(target, Messages.format(
354: Messages.INCORRECT_CHILD_FOR_WILDCARD, rie
355: .____jaxb_ri____getNamespaceURI(), rie
356: .____jaxb_ri____getLocalName()));
357: }
358:
359: child.onEndAttributes(sti, null);
360:
361: if (!acceptor.stepForward(child, null)) {
362: // this can't be possible, as the dummy element was
363: // generated by XJC.
364: throw new JAXBAssertionError();
365: }
366:
367: // we need a separate validator instance to validate a child object
368: context.validate(vo);
369:
370: }
371:
372: private void childAsAttributeBody(ValidatableObject vo,
373: String fieldName) throws SAXException {
374: /*
375: Dirty quick hack. When we split a schema into fragments, basically
376: every chlid object needs a place holder in the fragment
377: (so that the parent schema fragment can correctly validate that the
378: child objects are at their supposed places.)
379:
380: For example, cconsider the following schema:
381:
382: imagine:
383: <class>
384: <attribute>
385: <list>
386: <oneOrMore>
387: <ref name="bar"/>
388: </oneOrMore>
389: </list>
390: </attribute>
391: </class>
392:
393: In our algorithm, the corresponding schema fragment will be:
394:
395: <class>
396: <attribute>
397: <list>
398: <oneOrMore>
399: <value>\u0000full.class.name.of.BarImpl</value>
400: </oneOrMore>
401: </list>
402: </attribute>
403: </class>
404:
405: If we find a child object inside an attribute
406: (that's why we are in this method BTW),
407: we generate a class name (with a special marker \u0000).
408: */
409:
410: // put a class name with a special marker \u0000. This char is an invalid
411: // XML char, so sensible datatypes should reject this (although many
412: // datatype implementations will accept it in actuality)
413: text("\u0000" + vo.getPrimaryInterface().getName(), fieldName);
414:
415: // validate a child object
416: context.validate(vo);
417: }
418:
419: public void reportError(ValidationEvent e)
420: throws AbortSerializationException {
421: context.reportEvent(target, e);
422: }
423:
424: //
425: //
426: // ID/IDREF validation
427: //
428: //
429: public String onID(IdentifiableObject owner, String value)
430: throws SAXException {
431: return context.onID(target, value);
432: }
433:
434: public String onIDREF(IdentifiableObject value) throws SAXException {
435: return context.onIDREF(target, value.____jaxb____getId());
436: }
437:
438: //
439: //
440: // ValidationContext implementation. Used by MSV to obtain
441: // contextual information related to validation.
442: //
443: //
444: public String getBaseUri() {
445: return null;
446: }
447:
448: public boolean isUnparsedEntity(String entityName) {
449: // abandon the validation of ENTITY type.
450: return true;
451: }
452:
453: public boolean isNotation(String notation) {
454: // abandon the validation of NOTATION type.
455: return true;
456: }
457:
458: public void onID(Datatype dt, StringToken s) {
459: // ID/IDREF validation will be done by ourselves.
460: // so we will not rely on the validator to perform this check.
461: // because we will use multiple instances of validators, so
462: // they cannot check global consistency.
463:
464: // see onID/onIDREF of the ValidationContext.
465: }
466:
467: public String resolveNamespacePrefix(String prefix) {
468: return context.getNamespaceContext().getNamespaceURI(prefix);
469: }
470:
471: }
|