KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > jaxp > JAXPValidatorComponent


1 /*
2  * Copyright 2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.jaxp;
18
19 import java.io.IOException JavaDoc;
20
21 import javax.xml.validation.TypeInfoProvider JavaDoc;
22 import javax.xml.validation.ValidatorHandler JavaDoc;
23
24 import org.apache.xerces.dom.DOMInputImpl;
25 import org.apache.xerces.impl.Constants;
26 import org.apache.xerces.impl.XMLErrorReporter;
27 import org.apache.xerces.impl.xs.opti.DefaultXMLDocumentHandler;
28 import org.apache.xerces.util.AttributesProxy;
29 import org.apache.xerces.util.AugmentationsImpl;
30 import org.apache.xerces.util.ErrorHandlerProxy;
31 import org.apache.xerces.util.ErrorHandlerWrapper;
32 import org.apache.xerces.util.LocatorProxy;
33 import org.apache.xerces.util.SymbolTable;
34 import org.apache.xerces.util.XMLResourceIdentifierImpl;
35 import org.apache.xerces.xni.Augmentations;
36 import org.apache.xerces.xni.NamespaceContext;
37 import org.apache.xerces.xni.QName;
38 import org.apache.xerces.xni.XMLAttributes;
39 import org.apache.xerces.xni.XMLDocumentHandler;
40 import org.apache.xerces.xni.XMLLocator;
41 import org.apache.xerces.xni.XMLString;
42 import org.apache.xerces.xni.XNIException;
43 import org.apache.xerces.xni.parser.XMLComponent;
44 import org.apache.xerces.xni.parser.XMLComponentManager;
45 import org.apache.xerces.xni.parser.XMLConfigurationException;
46 import org.apache.xerces.xni.parser.XMLEntityResolver;
47 import org.apache.xerces.xni.parser.XMLErrorHandler;
48 import org.apache.xerces.xni.parser.XMLInputSource;
49 import org.w3c.dom.TypeInfo JavaDoc;
50 import org.w3c.dom.ls.LSInput JavaDoc;
51 import org.w3c.dom.ls.LSResourceResolver JavaDoc;
52 import org.xml.sax.Attributes JavaDoc;
53 import org.xml.sax.ContentHandler JavaDoc;
54 import org.xml.sax.ErrorHandler JavaDoc;
55 import org.xml.sax.SAXException JavaDoc;
56 import org.xml.sax.SAXParseException JavaDoc;
57 import org.xml.sax.helpers.DefaultHandler JavaDoc;
58
59 /**
60  * Runs events through a {@link javax.xml.validation.ValidatorHandler}
61  * and performs validation/infoset-augmentation by an external validator.
62  *
63  * <p>
64  * This component sets up the pipeline as follows:
65  *
66  * <!-- this picture may look teribble on your IDE but it is correct. -->
67  * <pre>
68  * __ __
69  * / |==> XNI2SAX --> Validator --> SAX2XNI ==>|
70  * / | |
71  * ==>| Tee| | next
72  * \ | | component
73  * \ |============other XNI events============>|
74  * ~~ ~~
75  * </pre>
76  * <p>
77  * only those events that need to go through Validator will go the 1st route,
78  * and other events go the 2nd direct route.
79  *
80  * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
81  * @version $Id: JAXPValidatorComponent.java,v 1.4 2005/06/22 02:03:40 mrglavas Exp $
82  */

83 final class JAXPValidatorComponent
84     extends TeeXMLDocumentFilterImpl implements XMLComponent {
85     
86     /** Property identifier: entity manager. */
87     private static final String JavaDoc ENTITY_MANAGER =
88         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
89     
90     /** Property identifier: error reporter. */
91     private static final String JavaDoc ERROR_REPORTER =
92         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
93     
94     /** Property identifier: symbol table. */
95     private static final String JavaDoc SYMBOL_TABLE =
96         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
97     
98     // pipeline parts
99
private final ValidatorHandler JavaDoc validator;
100     private final XNI2SAX xni2sax = new XNI2SAX();
101     private final SAX2XNI sax2xni = new SAX2XNI();
102     
103     // never be null
104
private final TypeInfoProvider JavaDoc typeInfoProvider;
105     
106     /**
107      * Used to store the {@link Augmentations} associated with the
108      * current event, so that we can pick it up again
109      * when the event is forwarded by the {@link ValidatorHandler}.
110      *
111      * UGLY HACK.
112      */

113     private Augmentations fCurrentAug;
114     
115     /**
116      * {@link XMLAttributes} version of {@link #fCurrentAug}.
117      */

118     private XMLAttributes fCurrentAttributes;
119     
120     // components obtained from a manager / property
121

122     private SymbolTable fSymbolTable;
123     private XMLErrorReporter fErrorReporter;
124     private XMLEntityResolver fEntityResolver;
125     
126     /**
127      * @param validatorHandler may not be null.
128      */

129     public JAXPValidatorComponent( ValidatorHandler JavaDoc validatorHandler ) {
130         this.validator = validatorHandler;
131         TypeInfoProvider JavaDoc tip = validatorHandler.getTypeInfoProvider();
132         if(tip==null) tip = noInfoProvider;
133         this.typeInfoProvider = tip;
134         
135         // configure wiring between internal components.
136
xni2sax.setContentHandler(validator);
137         validator.setContentHandler(sax2xni);
138         this.setSide(xni2sax);
139
140         // configure validator with proper EntityResolver/ErrorHandler.
141
validator.setErrorHandler(new ErrorHandlerProxy() {
142             protected XMLErrorHandler getErrorHandler() {
143                 XMLErrorHandler handler = fErrorReporter.getErrorHandler();
144                 if(handler!=null) return handler;
145                 return new ErrorHandlerWrapper(DraconianErrorHandler.getInstance());
146             }
147         });
148         validator.setResourceResolver(new LSResourceResolver JavaDoc() {
149             public LSInput JavaDoc resolveResource(String JavaDoc type,String JavaDoc ns, String JavaDoc publicId, String JavaDoc systemId, String JavaDoc baseUri) {
150                 if(fEntityResolver==null) return null;
151                 try {
152                     XMLInputSource is = fEntityResolver.resolveEntity(
153                         new XMLResourceIdentifierImpl(publicId,systemId,baseUri,null));
154                     if(is==null) return null;
155                         
156                     LSInput JavaDoc di = new DOMInputImpl();
157                     di.setBaseURI(is.getBaseSystemId());
158                     di.setByteStream(is.getByteStream());
159                     di.setCharacterStream(is.getCharacterStream());
160                     di.setEncoding(is.getEncoding());
161                     di.setPublicId(is.getPublicId());
162                     di.setSystemId(is.getSystemId());
163                         
164                     return di;
165                 } catch( IOException JavaDoc e ) {
166                     // erors thrown by the callback is not supposed to be
167
// reported to users.
168
throw new XNIException(e);
169                 }
170             }
171         });
172     }
173     
174
175     public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
176         fCurrentAttributes = attributes;
177         fCurrentAug = augs;
178         xni2sax.startElement(element,attributes,null);
179         fCurrentAttributes = null; // mostly to make it easy to find any bug.
180
}
181
182     public void endElement(QName element, Augmentations augs) throws XNIException {
183         fCurrentAug = augs;
184         xni2sax.endElement(element,null);
185     }
186
187     public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
188         startElement(element,attributes,augs);
189         endElement(element,augs);
190     }
191
192     
193     public void characters(XMLString text, Augmentations augs) throws XNIException {
194         // since a validator may change the contents,
195
// let this one go through a validator
196
fCurrentAug = augs;
197         xni2sax.characters(text,null);
198     }
199
200     public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
201         // since a validator may change the contents,
202
// let this one go through a validator
203
fCurrentAug = augs;
204         xni2sax.ignorableWhitespace(text,null);
205     }
206
207     public void reset(XMLComponentManager componentManager) throws XMLConfigurationException {
208         // obtain references from the manager
209
fSymbolTable = (SymbolTable)componentManager.getProperty(SYMBOL_TABLE);
210         fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER);
211         try {
212             fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
213         }
214         catch (XMLConfigurationException e) {
215             fEntityResolver = null;
216         }
217     }
218     
219     /**
220      *
221      * Uses {@link DefaultHandler} as a default implementation of
222      * {@link ContentHandler}.
223      *
224      * <p>
225      * We only forward certain events from a {@link ValidatorHandler}.
226      * Other events should go "the 2nd direct route".
227      */

228     private final class SAX2XNI extends DefaultHandler JavaDoc {
229         
230         /**
231          * {@link Augmentations} to send along with events.
232          * We reuse one object for efficiency.
233          */

234         private final Augmentations fAugmentations = new AugmentationsImpl();
235         
236         /**
237          * {@link QName} to send along events.
238          * we reuse one QName for efficiency.
239          */

240         private final QName fQName = new QName();
241         
242         public void characters(char[] ch, int start, int len) throws SAXException JavaDoc {
243             try {
244                 handler().characters(new XMLString(ch,start,len),aug());
245             } catch( XNIException e ) {
246                 throw toSAXException(e);
247             }
248         }
249
250         public void ignorableWhitespace(char[] ch, int start, int len) throws SAXException JavaDoc {
251             try {
252                 handler().ignorableWhitespace(new XMLString(ch,start,len),aug());
253             } catch( XNIException e ) {
254                 throw toSAXException(e);
255             }
256         }
257
258         public void startElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qname, Attributes atts) throws SAXException JavaDoc {
259             try {
260                 updateAttributes(atts);
261                 handler().startElement(toQName(uri,localName,qname), fCurrentAttributes, elementAug());
262             } catch( XNIException e ) {
263                 throw toSAXException(e);
264             }
265         }
266
267         public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qname) throws SAXException JavaDoc {
268             try {
269                 handler().endElement(toQName(uri,localName,qname),aug());
270             } catch( XNIException e ) {
271                 throw toSAXException(e);
272             }
273         }
274         
275         private Augmentations elementAug() {
276             Augmentations aug = aug();
277             /** aug.putItem(Constants.TYPEINFO,typeInfoProvider.getElementTypeInfo()); **/
278             return aug;
279         }
280
281         
282         /**
283          * Gets the {@link Augmentations} that should be associated with
284          * the current event.
285          */

286         private Augmentations aug() {
287             if( fCurrentAug!=null ) {
288                 Augmentations r = fCurrentAug;
289                 fCurrentAug = null; // we "consumed" this augmentation.
290
return r;
291             }
292             fAugmentations.removeAllItems();
293             return fAugmentations;
294         }
295         
296         /**
297          * Get the handler to which we should send events.
298          */

299         private XMLDocumentHandler handler() {
300             return JAXPValidatorComponent.this.getDocumentHandler();
301         }
302         
303         /**
304          * Converts the {@link XNIException} received from a downstream
305          * component to a {@link SAXException}.
306          */

307         private SAXException JavaDoc toSAXException( XNIException xe ) {
308             Exception JavaDoc e = xe.getException();
309             if( e==null ) e = xe;
310             if( e instanceof SAXException JavaDoc ) return (SAXException JavaDoc)e;
311             return new SAXException JavaDoc(e);
312         }
313         
314         /**
315          * Creates a proper {@link QName} object from 3 parts.
316          * <p>
317          * This method does the symbolization.
318          */

319         private QName toQName( String JavaDoc uri, String JavaDoc localName, String JavaDoc qname ) {
320             String JavaDoc prefix = null;
321             int idx = qname.indexOf(':');
322             if( idx>0 )
323                 prefix = symbolize(qname.substring(0,idx));
324             
325             localName = symbolize(localName);
326             qname = symbolize(qname);
327             uri = symbolize(uri);
328
329             // notify handlers
330
fQName.setValues(prefix, localName, qname, uri);
331             return fQName;
332         }
333     }
334     
335     /**
336      * Converts {@link XNI} events to {@link ContentHandler} events.
337      *
338      * <p>
339      * Deriving from {@link DefaultXMLDocumentHandler}
340      * to reuse its default {@link org.apache.xerces.xni.XMLDocumentHandler}
341      * implementation.
342      *
343      * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
344      */

345     private final class XNI2SAX extends DefaultXMLDocumentHandler {
346         
347         private ContentHandler JavaDoc fContentHandler;
348
349         private String JavaDoc fVersion;
350
351         /** Namespace context */
352         protected NamespaceContext fNamespaceContext;
353         
354         /**
355          * For efficiency, we reuse one instance.
356          */

357         private final AttributesProxy fAttributesProxy = new AttributesProxy(null);
358
359         public void setContentHandler( ContentHandler JavaDoc handler ) {
360             this.fContentHandler = handler;
361         }
362         
363         public ContentHandler JavaDoc getContentHandler() {
364             return fContentHandler;
365         }
366         
367
368         public void xmlDecl(String JavaDoc version, String JavaDoc encoding, String JavaDoc standalone, Augmentations augs) throws XNIException {
369             this.fVersion = version;
370         }
371
372         public void startDocument(XMLLocator locator, String JavaDoc encoding, NamespaceContext namespaceContext, Augmentations augs) throws XNIException {
373             fNamespaceContext = namespaceContext;
374             fContentHandler.setDocumentLocator(new LocatorProxy(locator));
375             try {
376                 fContentHandler.startDocument();
377             } catch (SAXException JavaDoc e) {
378                 throw new XNIException(e);
379             }
380         }
381
382         public void endDocument(Augmentations augs) throws XNIException {
383             try {
384                 fContentHandler.endDocument();
385             } catch (SAXException JavaDoc e) {
386                 throw new XNIException(e);
387             }
388         }
389
390         public void processingInstruction(String JavaDoc target, XMLString data, Augmentations augs) throws XNIException {
391             try {
392                 fContentHandler.processingInstruction(target,data.toString());
393             } catch (SAXException JavaDoc e) {
394                 throw new XNIException(e);
395             }
396         }
397
398         public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
399             try {
400                 // start namespace prefix mappings
401
int count = fNamespaceContext.getDeclaredPrefixCount();
402                 if (count > 0) {
403                     String JavaDoc prefix = null;
404                     String JavaDoc uri = null;
405                     for (int i = 0; i < count; i++) {
406                         prefix = fNamespaceContext.getDeclaredPrefixAt(i);
407                         uri = fNamespaceContext.getURI(prefix);
408                         fContentHandler.startPrefixMapping(prefix, (uri == null)?"":uri);
409                     }
410                 }
411                         
412                 String JavaDoc uri = element.uri != null ? element.uri : "";
413                 String JavaDoc localpart = element.localpart;
414                 fAttributesProxy.setAttributes(attributes);
415                 fContentHandler.startElement(uri, localpart, element.rawname, fAttributesProxy);
416             } catch( SAXException JavaDoc e ) {
417                 throw new XNIException(e);
418             }
419         }
420
421         public void endElement(QName element, Augmentations augs) throws XNIException {
422             try {
423                 String JavaDoc uri = element.uri != null ? element.uri : "";
424                 String JavaDoc localpart = element.localpart;
425                 fContentHandler.endElement(uri, localpart, element.rawname);
426                 
427                 // send endPrefixMapping events
428
int count = fNamespaceContext.getDeclaredPrefixCount();
429                 if (count > 0) {
430                     for (int i = 0; i < count; i++) {
431                         fContentHandler.endPrefixMapping(fNamespaceContext.getDeclaredPrefixAt(i));
432                     }
433                 }
434             } catch( SAXException JavaDoc e ) {
435                 throw new XNIException(e);
436             }
437         }
438
439         public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
440             startElement(element,attributes,augs);
441             endElement(element,augs);
442         }
443
444         public void characters(XMLString text, Augmentations augs) throws XNIException {
445             try {
446                 fContentHandler.characters(text.ch,text.offset,text.length);
447             } catch (SAXException JavaDoc e) {
448                 throw new XNIException(e);
449             }
450         }
451
452         public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
453             try {
454                 fContentHandler.ignorableWhitespace(text.ch,text.offset,text.length);
455             } catch (SAXException JavaDoc e) {
456                 throw new XNIException(e);
457             }
458         }
459     }
460     
461     private static final class DraconianErrorHandler implements ErrorHandler {
462
463         /**
464          * Singleton instance.
465          */

466         private static final DraconianErrorHandler ERROR_HANDLER_INSTANCE
467             = new DraconianErrorHandler();
468         
469         private DraconianErrorHandler() {}
470         
471         /** Returns the one and only instance of this error handler. */
472         public static DraconianErrorHandler getInstance() {
473             return ERROR_HANDLER_INSTANCE;
474         }
475         
476         /** Warning: Ignore. */
477         public void warning(SAXParseException JavaDoc e) throws SAXException JavaDoc {
478             // noop
479
}
480         
481         /** Error: Throws back SAXParseException. */
482         public void error(SAXParseException JavaDoc e) throws SAXException JavaDoc {
483             throw e;
484         }
485         
486         /** Fatal Error: Throws back SAXParseException. */
487         public void fatalError(SAXParseException JavaDoc e) throws SAXException JavaDoc {
488             throw e;
489         }
490         
491     } // DraconianErrorHandler
492

493     
494     /**
495      * Compares the given {@link Attributes} with {@link #fCurrentAttributes}
496      * and update the latter accordingly.
497      */

498     private void updateAttributes( Attributes atts ) {
499         int len = atts.getLength();
500         for( int i=0; i<len; i++ ) {
501             String JavaDoc aqn = atts.getQName(i);
502             int j = fCurrentAttributes.getIndex(aqn);
503             String JavaDoc av = atts.getValue(i);
504             if(j==-1) {
505                 // newly added attribute. add to the current attribute list.
506

507                 String JavaDoc prefix;
508                 int idx = aqn.indexOf(':');
509                 if( idx<0 ) {
510                     prefix = null;
511                 } else {
512                     prefix = symbolize(aqn.substring(0,idx));
513                 }
514                 
515                 j = fCurrentAttributes.addAttribute(
516                     new QName(
517                         prefix,
518                         symbolize(atts.getLocalName(i)),
519                         symbolize(aqn),
520                         symbolize(atts.getURI(i))),
521                     atts.getType(i),av);
522             } else {
523                 // the attribute is present.
524
if( !av.equals(fCurrentAttributes.getValue(j)) ) {
525                     // but the value was changed.
526
fCurrentAttributes.setValue(j,av);
527                 }
528             }
529             
530             /** Augmentations augs = fCurrentAttributes.getAugmentations(j);
531             augs.putItem( Constants.TYPEINFO,
532                 typeInfoProvider.getAttributeTypeInfo(i) );
533             augs.putItem( Constants.ID_ATTRIBUTE,
534                 typeInfoProvider.isIdAttribute(i)?Boolean.TRUE:Boolean.FALSE ); **/

535         }
536     }
537     
538     private String JavaDoc symbolize( String JavaDoc s ) {
539         return fSymbolTable.addSymbol(s);
540     }
541
542     
543     /**
544      * {@link TypeInfoProvider} that returns no info.
545      */

546     private static final TypeInfoProvider JavaDoc noInfoProvider = new TypeInfoProvider JavaDoc() {
547         public TypeInfo JavaDoc getElementTypeInfo() {
548             return null;
549         }
550         public TypeInfo JavaDoc getAttributeTypeInfo(int index) {
551             return null;
552         }
553         public TypeInfo JavaDoc getAttributeTypeInfo(String JavaDoc attributeQName) {
554             return null;
555         }
556         public TypeInfo JavaDoc getAttributeTypeInfo(String JavaDoc attributeUri, String JavaDoc attributeLocalName) {
557             return null;
558         }
559         public boolean isIdAttribute(int index) {
560             return false;
561         }
562         public boolean isSpecified(int index) {
563             return false;
564         }
565     };
566     
567     //
568
//
569
// XMLComponent implementation.
570
//
571
//
572

573     // no property/feature supported
574
public String JavaDoc[] getRecognizedFeatures() {
575         return null;
576     }
577
578     public void setFeature(String JavaDoc featureId, boolean state) throws XMLConfigurationException {
579     }
580
581     public String JavaDoc[] getRecognizedProperties() {
582         return new String JavaDoc[]{ENTITY_MANAGER, ERROR_REPORTER, SYMBOL_TABLE};
583     }
584
585     public void setProperty(String JavaDoc propertyId, Object JavaDoc value) throws XMLConfigurationException {
586     }
587     
588     public Boolean JavaDoc getFeatureDefault(String JavaDoc featureId) {
589         return null;
590     }
591
592     public Object JavaDoc getPropertyDefault(String JavaDoc propertyId) {
593         return null;
594     }
595
596 }
597
Popular Tags