KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > api > xml > parsers > SAXEntityParser


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.api.xml.parsers;
21
22 import java.io.*;
23 import java.net.MalformedURLException JavaDoc;
24 import java.net.URL JavaDoc;
25 import org.openide.ErrorManager;
26
27 import org.xml.sax.*;
28
29 /**
30  * SAX parser wrapper allowing to parse parsed XML entities (including DTDs) for
31  * wellformedness.
32  * <p>
33  * Default implementation cannot be used for parsing of XML document entities!
34  * It wraps client's parser that it actually used for performing the parsing task.
35  * <p>
36  * <b>Primary use case (parse general entity):</b>
37  * <pre>
38  * XMLReader entityParser = new SAXEntityParser(xmlReader);
39  * entityParser.setErrorHandler(errorHandler);
40  * entityParser.parse(inputSource);
41  * </pre>
42  * <b>Secondary use case (delegating parser):</b> It requires subclassing and
43  * allow subclass entirely define internal wrapping logic.
44  *
45  * <b>Warning:</b> Implementation gurantees only proper ErrorHandler callbacks.
46  *
47  * @author Petr Kuzel
48  */

49 public class SAXEntityParser implements XMLReader {
50     
51     //??? we are not fully bullet proof
52
private static final long RANDOM = System.currentTimeMillis();
53     
54     private static final String JavaDoc FAKE_SYSTEM_ID =
55         "NetBeans:Fake-System-ID-" + RANDOM; // NOI18N
56

57     private static final String JavaDoc FAKE_PUBLIC_ID =
58         "-//NetBeans//Fake Public ID " + RANDOM + "//EN"; // NOI18N
59

60     // we delegate almost everything on it
61
private final XMLReader peer;
62
63     // defines wrapping logic
64
private final boolean generalEntity;
65
66     // was client parser already used
67
private boolean used = false;
68     
69     /**
70      * Creates a new instance of general entity parser.
71      * @param peer parser that will be used for parsing. Wrapped parser is
72      * exclusively owned by this class no other clients can share it.
73      */

74     public SAXEntityParser(XMLReader peer) {
75         this( peer, true);
76     }
77     
78     /**
79      * Creates a new instance of SAXEntityParser.
80      * @param peer parser that will be used for parsing
81      * @param generalEntity if <code>false</code> treat entity as parameter
82      * entity (i.e. DTD entities).
83      */

84     public SAXEntityParser(XMLReader peer, boolean generalEntity) {
85         if (peer == null) throw new NullPointerException JavaDoc();
86         this.peer = peer;
87         this.generalEntity = generalEntity;
88     }
89
90     /**
91      * Start entity parsing using peer parser. Staring from this moment
92      * all other methods calls are not supported.
93      * @param entity entity input source
94      */

95     public void parse( InputSource entity) throws IOException, SAXException {
96         
97         if (entity == null) throw new NullPointerException JavaDoc();
98         
99         synchronized (this) {
100             checkUsed();
101             used = true;
102         }
103
104         // log warning for common errors
105

106         String JavaDoc originalSID = entity.getSystemId();
107         if (originalSID == null) {
108             ErrorManager err = Util.THIS.getErrorManager();
109             if (err.isLoggable(err.WARNING)) {
110                 StringWriter writer = new StringWriter();
111                 PrintWriter out = new PrintWriter(writer);
112                 new IllegalArgumentException JavaDoc("WARNING: Missing system ID may cause serious errors while resolving relative references!").printStackTrace(out); // NOI18N
113
out.flush();
114                 err.log(err.WARNING, writer.getBuffer().toString());
115             }
116         }
117         
118         // provide fake entity resolver and input source
119

120         EntityResolver resolver = peer.getEntityResolver();
121         peer.setEntityResolver(new ER(resolver, entity));
122                 
123         ErrorHandler errorHandler = peer.getErrorHandler();
124         if (errorHandler != null) {
125             peer.setErrorHandler( new EH( errorHandler));
126         }
127         
128         InputSource fakeInput = wrapInputSource(entity);
129         if (fakeInput.getSystemId() == null) {
130             fakeInput.setSystemId(originalSID);
131         }
132         if (fakeInput.getPublicId() == null) {
133             fakeInput.setPublicId(FAKE_PUBLIC_ID);
134         }
135         peer.parse(fakeInput);
136         
137     }
138
139     /**
140      * Create wrapper input source. Default implementation utilizes fact that
141      * default <code>EntityResolver</code> redirects the first query to wrapped
142      * <code>InputSource</code>.
143      * @param input InputSource to be wrapped.
144      * @return InputSource that hosts of client's one
145      * @since 0.6
146      */

147     protected InputSource wrapInputSource(InputSource input) {
148         String JavaDoc sid = input.getSystemId();
149         InputSource fakeInput = new InputSource(FAKE_SYSTEM_ID);
150         String JavaDoc fakeDocument;
151         if (generalEntity) {
152             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
153             buffer.append("<!DOCTYPE fakeDocument" + RANDOM + " [\n"); // NOI18N
154
String JavaDoc entityRef = " PUBLIC '" + FAKE_PUBLIC_ID + "' '" + sid + "'";// NOI18N
155
buffer.append("<!ENTITY fakeEntity" + RANDOM + entityRef + ">\n"); // NOI18N
156
buffer.append("]>\n"); // NOI18N
157
buffer.append("<fakeDocument" + RANDOM + ">\n"); // NOI18N
158
buffer.append("&fakeEntity" + RANDOM + ";\n"); // NOI18N
159
buffer.append("</fakeDocument" + RANDOM + ">\n"); // NOI18N
160
fakeDocument = buffer.toString();
161         } else {
162             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
163             String JavaDoc extRef = " PUBLIC '" + FAKE_PUBLIC_ID + "' '" + sid + "'"; // NOI18N
164
buffer.append("<!DOCTYPE fakeDocument" + RANDOM + extRef + ">\n"); // NOI18N
165
buffer.append("<fakeDocument" + RANDOM + "/>\n"); // NOI18N
166
fakeDocument = buffer.toString();
167         }
168         fakeInput.setCharacterStream(new StringReader(fakeDocument));
169         return fakeInput;
170     }
171     
172     /**
173      * Examine if the exception should be propagated into client's <code>ErrorHandler</code>.
174      * @param ex examined exception
175      * @return <code>true</code> if the exception originates from client's
176      * <code>InputSource</code> and should be propagated.
177      */

178     protected boolean propagateException(SAXParseException ex) {
179         if (ex == null) return false;
180         return (FAKE_SYSTEM_ID.equals(ex.getSystemId()) == false);
181     }
182     
183     public org.xml.sax.ContentHandler JavaDoc getContentHandler() {
184         return peer.getContentHandler();
185     }
186     
187     public org.xml.sax.DTDHandler JavaDoc getDTDHandler() {
188         return peer.getDTDHandler();
189     }
190     
191     public org.xml.sax.EntityResolver JavaDoc getEntityResolver() {
192         return peer.getEntityResolver();
193     }
194     
195     public org.xml.sax.ErrorHandler JavaDoc getErrorHandler() {
196         return peer.getErrorHandler();
197     }
198     
199     public boolean getFeature(String JavaDoc name) throws org.xml.sax.SAXNotRecognizedException JavaDoc, org.xml.sax.SAXNotSupportedException JavaDoc {
200         return peer.getFeature(name);
201     }
202     
203     public Object JavaDoc getProperty(String JavaDoc name) throws org.xml.sax.SAXNotRecognizedException JavaDoc, org.xml.sax.SAXNotSupportedException JavaDoc {
204         return peer.getProperty(name);
205     }
206     
207     public void parse(String JavaDoc sid) throws java.io.IOException JavaDoc, org.xml.sax.SAXException JavaDoc {
208         this.parse(new InputSource(sid));
209     }
210     
211     public void setContentHandler(org.xml.sax.ContentHandler JavaDoc contentHandler) {
212         peer.setContentHandler(contentHandler);
213     }
214     
215     public void setDTDHandler(org.xml.sax.DTDHandler JavaDoc dTDHandler) {
216         peer.setDTDHandler(dTDHandler);
217     }
218     
219     public void setEntityResolver(org.xml.sax.EntityResolver JavaDoc entityResolver) {
220         peer.setEntityResolver(entityResolver);
221     }
222     
223     public void setErrorHandler(org.xml.sax.ErrorHandler JavaDoc errorHandler) {
224         peer.setErrorHandler(errorHandler);
225     }
226     
227     public void setFeature(String JavaDoc name, boolean val) throws org.xml.sax.SAXNotRecognizedException JavaDoc, org.xml.sax.SAXNotSupportedException JavaDoc {
228         peer.setFeature(name, val);
229     }
230     
231     public void setProperty(String JavaDoc name, Object JavaDoc val) throws org.xml.sax.SAXNotRecognizedException JavaDoc, org.xml.sax.SAXNotSupportedException JavaDoc {
232         peer.setProperty(name, val);
233     }
234
235     private synchronized void checkUsed() {
236         if (used == true) throw new IllegalStateException JavaDoc();
237     }
238     
239     /**
240      * Redirect to entity input source, it is always the first request.
241      * Pure FAKE_SYSTEM_ID approach have problems with some parser implementations.
242      */

243     private class ER implements EntityResolver {
244
245         private boolean entityResolved;
246         private final EntityResolver peer;
247         private final InputSource entity;
248         
249         public ER(EntityResolver peer, InputSource entity) {
250             this.peer = peer;
251             this.entity = entity;
252         }
253         
254         public InputSource resolveEntity(String JavaDoc pid, String JavaDoc sid) throws SAXException, IOException {
255             
256             Util.THIS.debug("SAXEntityParser:resolving PID: " + pid + " SID: " + sid);
257                 
258             if (isFirstRequest()) {
259
260                 // normalize passed entity InputSource using parent entity resolver
261
Util.THIS.debug("SAXEntityParser:redirecting to " + entity + " SID: " + entity.getSystemId());
262                 
263                 if (peer != null && entity.getByteStream() == null && entity.getCharacterStream() == null) {
264                     return peer.resolveEntity(entity.getPublicId(), entity.getSystemId());
265                 } else {
266                     return entity;
267                 }
268             } else {
269                 if (peer == null) {
270                     return null;
271                 } else {
272                     return peer.resolveEntity(pid, sid);
273                 }
274             }
275         }
276                 
277         private synchronized boolean isFirstRequest() {
278             if (entityResolved == false) {
279                 entityResolved = true;
280                 return true;
281             } else {
282                 return false;
283             }
284         }
285     }
286
287     /**
288      * Filter out errors in our fake document
289      */

290     private class EH implements ErrorHandler {
291         
292         private final ErrorHandler peer;
293         
294         public EH( ErrorHandler peer) {
295             this.peer = peer;
296         }
297         
298         public void error(SAXParseException ex) throws SAXException {
299             if (propagateException(ex)) {
300                 peer.error(ex);
301             } else {
302                 Util.THIS.debug("SAXEntityParser: filtering out:", ex);
303             }
304         }
305         
306         public void fatalError(SAXParseException ex) throws SAXException {
307             if (propagateException(ex)) {
308                 peer.fatalError(ex);
309             } else {
310                 Util.THIS.debug("SAXEntityParser: filtering out:", ex);
311             }
312         }
313         
314         public void warning(SAXParseException ex) throws SAXException {
315             if (propagateException(ex)) {
316                 peer.warning(ex);
317             } else {
318                 Util.THIS.debug("SAXEntityParser: filtering out:", ex);
319             }
320         }
321     }
322     
323 }
324
Popular Tags