KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xerces > internal > jaxp > JAXPValidatorComponent


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57 package com.sun.org.apache.xerces.internal.jaxp;
58
59 import java.io.IOException JavaDoc;
60
61 import javax.xml.validation.TypeInfoProvider JavaDoc;
62 import javax.xml.validation.ValidatorHandler JavaDoc;
63
64 import com.sun.org.apache.xerces.internal.dom.DOMInputImpl;
65 import com.sun.org.apache.xerces.internal.impl.Constants;
66 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
67 import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
68 import com.sun.org.apache.xerces.internal.util.DraconianErrorHandler;
69 import com.sun.org.apache.xerces.internal.util.ErrorHandlerProxy;
70 import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper;
71 import com.sun.org.apache.xerces.internal.util.SymbolTable;
72 import com.sun.org.apache.xerces.internal.util.TeeXMLDocumentFilterImpl;
73 import com.sun.org.apache.xerces.internal.util.XMLResourceIdentifierImpl;
74 import com.sun.org.apache.xerces.internal.xni.Augmentations;
75 import com.sun.org.apache.xerces.internal.xni.QName;
76 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
77 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
78 import com.sun.org.apache.xerces.internal.xni.XMLString;
79 import com.sun.org.apache.xerces.internal.xni.XNIException;
80 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
81 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
82 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
83 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
84 import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
85 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
86 import org.w3c.dom.TypeInfo JavaDoc;
87 import org.w3c.dom.ls.LSInput JavaDoc;
88 import org.w3c.dom.ls.LSResourceResolver JavaDoc;
89 import org.xml.sax.Attributes JavaDoc;
90 import org.xml.sax.SAXException JavaDoc;
91 import org.xml.sax.helpers.DefaultHandler JavaDoc;
92
93 /**
94  * Runs events through a {@link javax.xml.validation.ValidatorHandler}
95  * and performs validation/infoset-augmentation by an external validator.
96  *
97  * <p>
98  * This component sets up the pipeline as follows:
99  *
100  * <!-- this picture may look teribble on your IDE but it is correct. -->
101  * <pre>
102  * __ __
103  * / |==> XNI2SAX --> Validator --> SAX2XNI ==>|
104  * / | |
105  * ==>| Tee| | next
106  * \ | | component
107  * \ |============other XNI events============>|
108  * ~~ ~~
109  * </pre>
110  * <p>
111  * only those events that need to go through Validator will go the 1st route,
112  * and other events go the 2nd direct route.
113  *
114  * @author
115  * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
116  */

117 public class JAXPValidatorComponent extends TeeXMLDocumentFilterImpl implements XMLComponent {
118     
119     // pipeline parts
120
private final ValidatorHandler JavaDoc validator;
121     private final XNI2SAX xni2sax = new XNI2SAX();
122     private final SAX2XNI sax2xni = new SAX2XNI();
123     
124     // never be null
125
private final TypeInfoProvider JavaDoc typeInfoProvider;
126     
127     /**
128      * Used to store the {@link Augmentations} associated with the
129      * current event, so that we can pick it up again
130      * when the event is forwarded by the {@link ValidatorHandler}.
131      *
132      * UGLY HACK.
133      */

134     private Augmentations fCurrentAug;
135     
136     /**
137      * {@link XMLAttributes} version of {@link #fCurrentAug}.
138      */

139     private XMLAttributes fCurrentAttributes;
140     
141     // components obtained from a manager / property
142

143     private SymbolTable fSymbolTable;
144     private XMLErrorReporter fErrorReporter;
145     private XMLEntityResolver fEntityResolver;
146     
147     /**
148      * @param validatorHandler
149      * may not be null.
150      */

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

249     private final class SAX2XNI extends DefaultHandler JavaDoc {
250         
251         /**
252          * {@link Augmentations} to send along with events.
253          * We reuse one object for efficiency.
254          */

255         private final Augmentations fAugmentations = new AugmentationsImpl();
256         
257         /**
258          * {@link QName} to send along events.
259          * we reuse one QName for efficiency.
260          */

261         private final QName fQName = new QName();
262         
263         public void characters(char[] ch, int start, int len) throws SAXException JavaDoc {
264             try {
265                 handler().characters(new XMLString(ch,start,len),aug());
266             } catch( XNIException e ) {
267                 throw toSAXException(e);
268             }
269         }
270
271         public void ignorableWhitespace(char[] ch, int start, int len) throws SAXException JavaDoc {
272             try {
273                 handler().ignorableWhitespace(new XMLString(ch,start,len),aug());
274             } catch( XNIException e ) {
275                 throw toSAXException(e);
276             }
277         }
278
279         public void startElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qname, Attributes atts) throws SAXException JavaDoc {
280             try {
281                 updateAttributes(atts);
282                 
283                 handler().startElement(toQName(uri,localName,qname), fCurrentAttributes, elementAug());
284             } catch( XNIException e ) {
285                 throw toSAXException(e);
286             }
287         }
288
289         public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qname) throws SAXException JavaDoc {
290             try {
291                 handler().endElement(toQName(uri,localName,qname),aug());
292             } catch( XNIException e ) {
293                 throw toSAXException(e);
294             }
295         }
296         
297         private Augmentations elementAug() {
298             Augmentations aug = aug();
299             aug.putItem(Constants.TYPEINFO,typeInfoProvider.getElementTypeInfo());
300             return aug;
301         }
302
303         
304         /**
305          * Gets the {@link Augmentations} that should be associated with
306          * the current event.
307          */

308         private Augmentations aug() {
309             if( fCurrentAug!=null ) {
310                 Augmentations r = fCurrentAug;
311                 fCurrentAug = null; // we "consumed" this augmentation.
312
return r;
313             }
314             fAugmentations.removeAllItems();
315             return fAugmentations;
316         }
317         
318         /**
319          * Get the handler to which we should send events.
320          */

321         private XMLDocumentHandler handler() {
322             return JAXPValidatorComponent.this.getDocumentHandler();
323         }
324         
325         /**
326          * Converts the {@link XNIException} received from a downstream
327          * component to a {@link SAXException}.
328          */

329         private SAXException JavaDoc toSAXException( XNIException xe ) {
330             Exception JavaDoc e = xe.getException();
331             if( e==null ) e = xe;
332             if( e instanceof SAXException JavaDoc ) return (SAXException JavaDoc)e;
333             return new SAXException JavaDoc(e);
334         }
335         
336         /**
337          * Creates a proper {@link QName} object from 3 parts.
338          * <p>
339          * This method does the symbolization.
340          */

341         private QName toQName( String JavaDoc uri, String JavaDoc localName, String JavaDoc qname ) {
342             String JavaDoc prefix = null;
343             int idx = qname.indexOf(':');
344             if( idx>0 )
345                 prefix = symbolize(qname.substring(0,idx));
346             
347             localName = symbolize(localName);
348             qname = symbolize(qname);
349             uri = symbolize(uri);
350
351             // notify handlers
352
fQName.setValues(prefix, localName, qname, uri);
353             return fQName;
354         }
355     }
356     
357     
358     /**
359      * Compares the given {@link Attributes} with {@link #fCurrentAttributes}
360      * and update the latter accordingly.
361      */

362     private void updateAttributes( Attributes atts ) {
363         int len = atts.getLength();
364         for( int i=0; i<len; i++ ) {
365             String JavaDoc aqn = atts.getQName(i);
366             int j = fCurrentAttributes.getIndex(aqn);
367             String JavaDoc av = atts.getValue(i);
368             if(j==-1) {
369                 // newly added attribute. add to the current attribute list.
370

371                 String JavaDoc prefix;
372                 int idx = aqn.indexOf(':');
373                 if( idx<0 ) {
374                     prefix = null;
375                 } else {
376                     prefix = symbolize(aqn.substring(0,idx));
377                 }
378                 
379                 j = fCurrentAttributes.addAttribute(
380                     new QName(
381                         prefix,
382                         symbolize(atts.getLocalName(i)),
383                         symbolize(aqn),
384                         symbolize(atts.getURI(i))),
385                     atts.getType(i),av);
386             } else {
387                 // the attribute is present.
388
if( !av.equals(fCurrentAttributes.getValue(j)) ) {
389                     // but the value was changed.
390
fCurrentAttributes.setValue(j,av);
391                 }
392             }
393             
394             Augmentations augs = fCurrentAttributes.getAugmentations(j);
395             augs.putItem( Constants.TYPEINFO,
396                 typeInfoProvider.getAttributeTypeInfo(i) );
397             augs.putItem( Constants.ID_ATTRIBUTE,
398                 typeInfoProvider.isIdAttribute(i)?Boolean.TRUE:Boolean.FALSE );
399         }
400         
401
402 // spec says attributes won't be removed.
403
//
404
// // we might remove attributes as we go through,
405
// // so iterate in the reverse order.
406
// for( int j=fCurrentAttributes.getLength()-1; j>=0; j-- ) {
407
// String aqn = fCurrentAttributes.getQName(j);
408
// int i = atts.getIndex(aqn);
409
// if(i==-1)
410
// // this attribute is removed.
411
// fCurrentAttributes.removeAttributeAt(j);
412
// }
413
}
414     
415     private String JavaDoc symbolize( String JavaDoc s ) {
416         return fSymbolTable.addSymbol(s);
417     }
418
419     
420     /**
421      * {@link TypeInfoProvider} that returns no info.
422      */

423     private static final TypeInfoProvider JavaDoc noInfoProvider = new TypeInfoProvider JavaDoc() {
424         public TypeInfo JavaDoc getElementTypeInfo() {
425             return null;
426         }
427         public TypeInfo JavaDoc getAttributeTypeInfo(int index) {
428             return null;
429         }
430         public TypeInfo JavaDoc getAttributeTypeInfo(String JavaDoc attributeQName) {
431             return null;
432         }
433         public TypeInfo JavaDoc getAttributeTypeInfo(String JavaDoc attributeUri, String JavaDoc attributeLocalName) {
434             return null;
435         }
436         public boolean isIdAttribute(int index) {
437             return false;
438         }
439         public boolean isSpecified(int index) {
440             return false;
441         }
442     };
443     
444 //
445
//
446
// XMLComponent implementation.
447
//
448
//
449

450 // no property/feature supported
451
public String JavaDoc[] getRecognizedFeatures() {
452         return null;
453     }
454
455     public void setFeature(String JavaDoc featureId, boolean state) throws XMLConfigurationException {
456     }
457
458     public String JavaDoc[] getRecognizedProperties() {
459         return new String JavaDoc[]{Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY};
460     }
461
462     public void setProperty(String JavaDoc propertyId, Object JavaDoc value) throws XMLConfigurationException {
463         if(propertyId.equals(Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY)) {
464             fEntityResolver = (XMLEntityResolver)value;
465         }
466     }
467     
468     public Boolean JavaDoc getFeatureDefault(String JavaDoc featureId) {
469         return null;
470     }
471
472     public Object JavaDoc getPropertyDefault(String JavaDoc propertyId) {
473         return null;
474     }
475
476 }
477
Popular Tags