View Javadoc

1   /*
2    * Copyright 2000-2004 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.jetspeed.util;
18  
19  //standard java stuff
20  import java.io.InputStream;
21  import java.io.PrintWriter;
22  import java.io.Reader;
23  import java.io.UnsupportedEncodingException;
24  import java.util.Vector;
25  
26  // SAX classes
27  import org.xml.sax.AttributeList;
28  import org.xml.sax.HandlerBase;
29  import org.xml.sax.InputSource;
30  import org.xml.sax.Parser;
31  import org.xml.sax.SAXException;
32  import org.xml.sax.SAXParseException;
33  import org.xml.sax.helpers.ParserFactory;
34  
35  // Jetspeed classes
36  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
37  import org.apache.jetspeed.services.logging.JetspeedLogger;
38  
39  /***
40  This class is used to either strip and/or insert PIs in a XML document.
41  It uses SAX-1 API and outputs text to an
42  output stream.
43  WARNING: This behavior will be modified in the future.
44  
45  @author <A HREF="mailto:raphael@apache.org">Raphaël Luta</A>
46  @version $Id: SAXPIFilter.java,v 1.8 2004/02/23 03:23:42 jford Exp $
47  */
48  public class SAXPIFilter extends HandlerBase 
49  {
50      /***
51       * Static initialization of the logger for this class
52       */    
53      private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(SAXPIFilter.class.getName());
54      
55      private static final String DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser";
56  
57      protected PrintWriter out=new PrintWriter(System.out);
58  
59      private String pi;
60  
61      private boolean stripExistingPI;
62  
63      private Vector pis = new Vector();
64      
65      /***
66      Creates of simple parser which outputs its document to the PrintWriter passed
67      as arguments.
68      In this mode the parser may be used as a simple well-formedness checker.
69  
70      @param outPW the printWriter where to output parsed data
71      */
72      public SAXPIFilter(PrintWriter outPW) throws UnsupportedEncodingException {
73          this(outPW,false,null);
74      }
75  
76      /***
77      In this mode the parser may be used as a simple well-formedness checker or a PI
78      stripper.
79  
80      @param outPW the printWriter where to output parsed data
81      @param strip configure the parser to strip PIs if strip is true
82      */
83      public SAXPIFilter(PrintWriter outPW, boolean strip) throws UnsupportedEncodingException {
84          this( outPW, strip, null );
85      }
86  
87      /***
88      In this mode the parser can strip existing PIs and insert new ones just after
89      the document declaration
90  
91      @param outPW the printWriter where to output parsed data
92      @param strip configure the parser to strip PIs if strip is true
93      @param PI string reprensenting the PI to be output after the document declaration
94      */
95      public SAXPIFilter(PrintWriter outPW, boolean strip, String PI) throws UnsupportedEncodingException {
96          this.out=outPW;
97          this.stripExistingPI=strip;
98          this.pi=PI;
99      }
100 
101     /***
102     Get all permitted processing instructions
103     */
104     public String[] getProcessingInstructions() {
105         
106         String[] ins = new String[ pis.size() ];
107         pis.copyInto( ins );
108         return ins;
109         
110     }
111     
112     public void addProcessingInstruction(String pi) {
113         this.pis.addElement( pi );
114     }
115 
116 
117     /***
118     Parse and output the content of the URL given as parameter.
119 
120     @param uri URL where to fetch the document to be parsed
121     */
122     public void print(String uri) {
123 
124         try {
125             HandlerBase handler = this;
126 
127             Parser parser = ParserFactory.makeParser(DEFAULT_PARSER_NAME);
128             parser.setDocumentHandler(handler);
129             parser.setErrorHandler(handler);
130             parser.parse(uri);
131         }
132         catch (Exception e) {
133             logger.error("Exception",  e);
134         }
135 
136     }
137 
138     /***
139     Parse and output the content of the stream
140 
141     @param in a content InputStream
142     */
143     public void print(InputStream in) {
144 
145         try {
146             HandlerBase handler = this;
147 
148             Parser parser = ParserFactory.makeParser(DEFAULT_PARSER_NAME);
149             parser.setDocumentHandler(handler);
150             parser.setErrorHandler(handler);
151             parser.parse(new InputSource(in));
152         }
153         catch (Exception e) {
154             logger.error("Exception",  e);
155         }
156 
157     }
158 
159     /***
160     Parse and output the content of the reader
161 
162     @param in a content Reader
163     */
164     public void print(Reader in) {
165 
166         try {
167             HandlerBase handler = this;
168 
169             Parser parser = ParserFactory.makeParser(DEFAULT_PARSER_NAME);
170             parser.setDocumentHandler(handler);
171             parser.setErrorHandler(handler);
172             parser.parse(new InputSource(in));
173         }
174         catch (Exception e) {
175             logger.error("Exception",  e);
176         }
177 
178     }
179 
180     /***
181     SAX Handler implementation
182     */
183     public void processingInstruction(String target, String data) {
184 
185         
186         if ( ! stripExistingPI ) {
187             out.print( makeSAXPI( target, data ) );
188         } else {
189             //cocoon-process            
190             //if your original XML document has cocoon tags leave them in.
191 
192             //add exceptable processing instructions here.
193             if ( target.equals("cocoon-process") ) {
194                 
195                 this.addProcessingInstruction( makeSAXPI( target, data ) );
196 
197            }
198             
199         }
200 
201     }
202 
203     private String makeSAXPI( String target, String data ) {
204 
205         StringBuffer buffer = new StringBuffer();
206         buffer.append("<?");
207         buffer.append( target );
208         if (data != null && data.length() > 0) {
209             buffer.append(' ');
210             buffer.append(data);
211         }
212         buffer.append("?>");
213         
214         return buffer.toString();
215     }
216     
217    
218 
219     /***
220     SAX Handler implementation
221     */
222     public void startDocument() {
223 
224         if ( pi != null ) {
225             out.print( pi );
226         }
227 
228     }
229 
230     /***
231     SAX Handler implementation
232     */
233     public void startElement(String name, AttributeList attrs) {
234 
235         out.print('<');
236         out.print(name);
237         if (attrs != null) {
238             int len = attrs.getLength();
239             for (int i = 0; i < len; i++) {
240                 out.print(' ');
241                 out.print(attrs.getName(i));
242                 out.print("=\"");
243                 out.print(normalize(attrs.getValue(i)));
244                 out.print('"');
245             }
246         }
247         out.print('>');
248 
249     }
250 
251     /***
252     SAX Handler implementation
253     */
254     public void characters(char ch[], int start, int length) {
255 
256         out.print(normalize(new String(ch, start, length)));
257 
258     }
259 
260     /***
261     SAX Handler implementation
262     */
263     public void ignorableWhitespace(char ch[], int start, int length) {
264 
265         characters(ch, start, length);
266 
267     }
268 
269     /***
270     SAX Handler implementation
271     */
272     public void endElement(String name) {
273 
274         out.print("</");
275         out.print(name);
276         out.print('>');
277 
278     }
279 
280     /***
281     SAX Handler implementation
282     */
283     public void endDocument() {
284 
285         out.flush();
286 
287     }
288 
289     /***
290     SAX Handler implementation
291     */
292     public void warning(SAXParseException ex) {
293         System.err.println("[Warning] "+
294                            getLocationString(ex)+": "+
295                            ex.getMessage());
296     }
297 
298     /***
299     SAX Handler implementation
300     */
301     public void error(SAXParseException ex) {
302         System.err.println("[Error] "+
303                            getLocationString(ex)+": "+
304                            ex.getMessage());
305     }
306 
307     /***
308     SAX Handler implementation
309     */
310     public void fatalError(SAXParseException ex) throws SAXException {
311         System.err.println("[Fatal Error] "+
312                            getLocationString(ex)+": "+
313                            ex.getMessage());
314         throw ex;
315     }
316 
317     /***
318     Retrieves the error location in the input stream
319     */
320     private String getLocationString(SAXParseException ex) {
321         StringBuffer str = new StringBuffer();
322 
323         String systemId = ex.getSystemId();
324         if (systemId != null) {
325             int index = systemId.lastIndexOf('/');
326             if (index != -1)
327                 systemId = systemId.substring(index + 1);
328             str.append(systemId);
329         }
330         str.append(':');
331         str.append(ex.getLineNumber());
332         str.append(':');
333         str.append(ex.getColumnNumber());
334 
335         return str.toString();
336 
337     }
338 
339     /***
340     Escapes characters data
341     */
342     protected String normalize(String s) {
343         StringBuffer str = new StringBuffer();
344 
345         int len = (s != null) ? s.length() : 0;
346         for (int i = 0; i < len; i++) {
347             char ch = s.charAt(i);
348             switch (ch) {
349                 case '<': {
350                     str.append("&lt;");
351                     break;
352                 }
353                 case '>': {
354                     str.append("&gt;");
355                     break;
356                 }
357                 case '&': {
358                     str.append("&amp;");
359                     break;
360                 }
361                 case '"': {
362                     str.append("&quot;");
363                     break;
364                 }
365                 default: {
366                     str.append(ch);
367                 }
368             }
369         }
370 
371         return str.toString();
372 
373     }
374 
375 }