1   /**
2    * Distribution License:
3    * JSword is free software; you can redistribute it and/or modify it under
4    * the terms of the GNU Lesser General Public License, version 2.1 or later
5    * as published by the Free Software Foundation. This program is distributed
6    * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
7    * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8    * See the GNU Lesser General Public License for more details.
9    *
10   * The License is available on the internet at:
11   *      http://www.gnu.org/copyleft/lgpl.html
12   * or by writing to:
13   *      Free Software Foundation, Inc.
14   *      59 Temple Place - Suite 330
15   *      Boston, MA 02111-1307, USA
16   *
17   * © CrossWire Bible Society, 2005 - 2016
18   *
19   */
20  package org.crosswire.common.xml;
21  
22  import java.io.IOException;
23  
24  import org.crosswire.common.util.ClassUtil;
25  import org.xml.sax.SAXException;
26  import org.xml.sax.XMLReader;
27  import org.xml.sax.helpers.XMLReaderFactory;
28  
29  /**
30   * Runs an xml parser on an xml file using an xml handler. The default behavior
31   * is to check that the xml file is well-formed.
32   * 
33   * @see gnu.lgpl.License The GNU Lesser General Public License for details.
34   * @author DM Smith
35   */
36  public class XMLProcess {
37  
38      public XMLProcess() {
39          features = new XMLFeatureSet();
40      }
41  
42      /**
43       * @return Returns the features.
44       */
45      public XMLFeatureSet getFeatures() {
46          return features;
47      }
48  
49      /**
50       * Process an xml file according to the arguments.
51       * 
52       * @param argv the command-line arguments
53       */
54      public static void main(String[] argv) {
55          XMLProcess checker = new XMLProcess();
56  
57          // is there anything to do?
58          if (argv.length == 0) {
59              checker.usage();
60              System.exit(1);
61          }
62  
63          // variables
64          String arg = null;
65  
66          // process arguments
67          for (int i = 0; i < argv.length; i++) {
68              arg = argv[i];
69              if (arg.charAt(0) == '-') {
70                  String option = arg.substring(1);
71                  if ("h".equals(option)) {
72                      checker.usage();
73                      System.exit(0);
74                  }
75              }
76          }
77  
78          checker.initialize(argv);
79          checker.parse(arg);
80  
81      }
82  
83      private void initialize(String[] argv) {
84          // process arguments
85          int i = 0;
86          for (i = 0; i < argv.length; i++) {
87              String arg = argv[i];
88              if (arg.charAt(0) == '-') {
89                  String option = arg.substring(1);
90                  if ("p".equals(option)) {
91                      // get parser name
92                      if (++i == argv.length) {
93                          System.err.println("error: Missing argument to -p option.");
94                      }
95                      parserName = argv[i];
96  
97                      createParser();
98                      continue;
99                  }
100                 if ("a".equals(option)) {
101                     // get parser name
102                     if (++i == argv.length) {
103                         System.err.println("error: Missing argument to -a option.");
104                     }
105                     adapterName = argv[i];
106 
107                     createAdapter();
108                     continue;
109                 }
110             }
111         }
112 
113         features.setFeatureStates(argv);
114     }
115 
116     private void bind() {
117         createParser();
118         createAdapter();
119 
120         // Now that we have a parser and a handler
121         // make the parser use them.
122         setHandlers();
123         features.setFeatures(parser);
124 
125     }
126 
127     private void createParser() {
128         if (parser != null) {
129             return;
130         }
131 
132         try {
133             parser = XMLReaderFactory.createXMLReader(parserName);
134         } catch (SAXException e) {
135             System.err.println("error: Unable to instantiate parser (" + parserName + ")");
136         }
137 
138     }
139 
140     private void createAdapter() {
141         if (adapter != null) {
142             return;
143         }
144 
145         try {
146             adapter = (XMLHandlerAdapter) ClassUtil.forName(adapterName).newInstance();
147         } catch (ClassNotFoundException e) {
148             System.err.println("error: Unable to instantiate XMLHandlerAdpater (" + adapterName + ")");
149         } catch (InstantiationException e) {
150             System.err.println("error: Unable to instantiate XMLHandlerAdpater (" + adapterName + ")");
151         } catch (IllegalAccessException e) {
152             System.err.println("error: Unable to instantiate XMLHandlerAdpater (" + adapterName + ")");
153         }
154 
155     }
156 
157     private void setHandlers() {
158         parser.setDTDHandler(adapter);
159         parser.setErrorHandler(adapter);
160         parser.setContentHandler(adapter);
161 
162         try {
163             parser.setProperty(DECLARATION_HANDLER_PROPERTY_ID, adapter);
164         } catch (SAXException e) {
165             e.printStackTrace(System.err);
166         }
167 
168         try {
169             parser.setProperty(LEXICAL_HANDLER_PROPERTY_ID, adapter);
170         } catch (SAXException e) {
171             e.printStackTrace(System.err);
172         }
173     }
174 
175     public void parse(String xmlFile) {
176         bind();
177         // parse file
178         try {
179             System.out.println("Parsing with the following:");
180             printActual();
181             parser.parse(xmlFile);
182             System.out.println("Done: no problems found.");
183         } catch (SAXException e) {
184             System.err.println("error: Parse error occurred - " + e.getMessage());
185             Exception nested = e.getException();
186             if (nested != null) {
187                 nested.printStackTrace(System.err);
188             } else {
189                 e.printStackTrace(System.err);
190             }
191         } catch (IOException e) {
192             e.printStackTrace(System.err);
193         }
194     }
195 
196     /** Prints the usage. */
197     private void usage() {
198         System.err.println("usage: java org.crosswire.common.xml.XMLProcess (options) uri");
199         System.err.println();
200 
201         System.err.println("options:");
202         printUsage();
203         System.err.println("  -h          This help screen.");
204         System.err.println();
205 
206         System.err.println("defaults:");
207         printDefaults();
208     }
209 
210     public void printUsage() {
211         System.err.println("  -p name     Select parser by name.");
212         System.err.println("  -a name     Select XMLHandlerAdapter by name.");
213         features.printUsage();
214     }
215 
216     public void printDefaults() {
217         System.err.println("Parser:     " + DEFAULT_PARSER_NAME);
218         System.err.println("Handler:    " + DEFAULT_HANDLER_NAME);
219         System.err.println(new XMLFeatureSet().toString());
220     }
221 
222     public void printActual() {
223         System.err.println("Parser:     " + parserName);
224         System.err.println("Handler:    " + adapterName);
225         System.err.println(new XMLFeatureSet().toString());
226     }
227 
228     // property ids
229 
230     /**
231      * Lexical handler property id
232      */
233     private static final String LEXICAL_HANDLER_PROPERTY_ID = "http://xml.org/sax/properties/lexical-handler";
234 
235     /**
236      * Declaration handler property id
237      */
238     private static final String DECLARATION_HANDLER_PROPERTY_ID = "http://xml.org/sax/properties/declaration-handler";
239 
240     // default settings
241 
242     /** Default parser name. */
243     private static final String DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser";
244     private static final String DEFAULT_HANDLER_NAME = "org.crosswire.common.xml.XMLHandlerAdapter";
245 
246     private String parserName = DEFAULT_PARSER_NAME;
247     private XMLReader parser;
248     private String adapterName = DEFAULT_HANDLER_NAME;
249     private XMLHandlerAdapter adapter;
250     private XMLFeatureSet features;
251 }
252