001: /*
002: * Copyright (C) 2007 Jared Alexander Spigner
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: * jspigner@openjx.org
019: *
020: * XMLParser.java
021: *
022: * Created on June 8, 2007, 1:17 AM
023: *
024: */
025:
026: package org.openjx.parser;
027:
028: import org.xml.sax.Attributes;
029: import org.xml.sax.ErrorHandler;
030: import org.xml.sax.InputSource;
031: import org.xml.sax.SAXException;
032: import org.xml.sax.SAXParseException;
033:
034: import org.xml.sax.helpers.DefaultHandler;
035:
036: import java.io.FileNotFoundException;
037: import java.io.IOException;
038:
039: import java.util.Vector;
040:
041: import javax.xml.parsers.ParserConfigurationException;
042: import javax.xml.parsers.SAXParser;
043: import javax.xml.parsers.SAXParserFactory;
044:
045: import javax.xml.validation.Schema;
046: import javax.xml.validation.SchemaFactory;
047: import javax.xml.validation.Validator;
048:
049: import javax.xml.XMLConstants;
050:
051: import javax.xml.transform.stream.StreamSource;
052:
053: import javax.swing.JOptionPane;
054:
055: import org.openjx.conf.JXGLOBAL;
056: import org.openjx.conf.Plugin;
057:
058: import org.openjx.display.JXMessageBox;
059:
060: import org.openjx.core.VirtualMachine;
061:
062: /**
063: * This is a SAX parser which handles interpreting the XML form language into
064: * the JXObject in an event driven manner.
065: *
066: * @author Jared Spigner
067: */
068: public class XMLParser extends DefaultHandler implements ErrorHandler {
069: /**
070: * A temporary variable used to store characters as they are read into the
071: * parser.
072: */
073: public String temp;
074:
075: /** Reference to the schema and schema factory. */
076: public Schema schema;
077: public SchemaFactory schemaFactory;
078:
079: public boolean validationError;
080: public SAXParseException saxParseException;
081:
082: /** Reference to SAX Parser object. */
083: public SAXParser saxParser;
084:
085: /** Reference to the SAX ParserFactor. */
086: public SAXParserFactory saxParserFactory;
087:
088: /** Reference to the Virtual Machine. */
089: public VirtualMachine virtualMachine;
090:
091: /**
092: * This is the constructor for the XMLParser class. It creates a new
093: * instance of XMLParser.
094: *
095: * @param vm points to an instance of the VirtualMachine class.
096: */
097: public XMLParser(VirtualMachine vm) {
098: super ();
099:
100: this .virtualMachine = vm;
101:
102: this .schema = null;
103: this .schemaFactory = null;
104:
105: this .validationError = false;
106: this .saxParseException = null;
107:
108: this .saxParser = null;
109: this .saxParserFactory = null;
110: }
111:
112: /**
113: * This method belongs to the DefaultHandler. It receives notification of
114: * character data inside an element. It throws SAXException.
115: *
116: * @param buf - The characters.
117: * @param offset - The start position in the character array.
118: * @param len - The number of characters to use from the character
119: * array.
120: */
121: public void characters(char buf[], int offset, int len)
122: throws SAXException {
123: String temp2;
124: temp2 = new String(buf, offset, len).trim();
125: if (!temp2.equals("")) {
126: this .temp = temp2;
127: }
128: }
129:
130: /**
131: * This method belongs to the DefaultHandler. It receives notification of
132: * the end of the document. It throws SAXException.
133: */
134: public void endDocument() throws SAXException {
135: // We need these lines of code to free up the lock on our XML jx file.
136: this .saxParser = null;
137: this .saxParserFactory = null;
138: System.gc();
139: if (JXGLOBAL.DEBUG_PARSER)
140: System.out.println("########## END DOCUMENT ##########");
141: }
142:
143: /**
144: * This method belongs to the DefaultHandler. It receives notification of
145: * the end of element. It throws SAXException.
146: *
147: * @param namespaceURI - The Namespace URI, or the empty string if the element has
148: * no Namespace URI or if Namespace processing is not being performed.
149: * @param localName - The local name (without prefix), or the empty string
150: * if Namespace processing is not being performed.
151: * @param qName - The qualified name (with prefix), or the empty string if
152: * qualified names are not available.
153: */
154: public void endElement(String namespaceURI, String localName,
155: String qName) throws SAXException {
156: if (JXGLOBAL.DEBUG_PARSER)
157: System.out.println("########## END ELEMENT LOCAL NAME:"
158: + localName + " QNAME:" + qName);
159:
160: this .virtualMachine.stackCall(localName, temp, null,
161: JXGLOBAL.JXSTACK_CALL.JXSTACK_UPDATE);
162:
163: this .virtualMachine.stackCall(localName, null, null,
164: JXGLOBAL.JXSTACK_CALL.JXSTACK_FINAL);
165: }
166:
167: /**
168: * This method initiates the parser on an XML file.
169: *
170: * @param systemId is the file name and path of the XML file we wish to
171: * parse.
172: *
173: * @return true if success, else false on the event of an exception.
174: */
175: public boolean parseXML(String systemId) {
176: if (!this .validateXML(systemId)) {
177: return false;
178: }
179:
180: try {
181: this .saxParserFactory = SAXParserFactory.newInstance();
182: this .saxParserFactory.setNamespaceAware(true);
183: this .schemaFactory = SchemaFactory
184: .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
185:
186: try {
187: Vector<Plugin> list = this .virtualMachine
188: .getPluginParser().getPluginListCTL(true);
189: StreamSource[] sources = new StreamSource[list.size() + 1];
190:
191: sources[0] = new StreamSource(getClass()
192: .getResourceAsStream("/org/openjx/OpenJX.xsd"));
193:
194: for (int i = 0; i < list.size(); i++) {
195: Plugin plugin = list.elementAt(i);
196: if (plugin.getPluginControl() == false)
197: continue;
198:
199: if (plugin.getPluginSchema() != null
200: || !plugin.getPluginSchema().equals(""))
201: sources[i + 1] = new StreamSource(getClass()
202: .getResourceAsStream(
203: "/" + plugin.getPluginSchema()));
204: else
205: sources[i + 1] = new StreamSource(getClass()
206: .getResourceAsStream("/"));
207: }
208:
209: if (sources != null && sources[0] != null)
210: this .schema = schemaFactory.newSchema(sources);
211: } catch (SAXException e) {
212: new JXMessageBox(JOptionPane.ERROR_MESSAGE,
213: "XML Parsing Failure", "" + e,
214: this .virtualMachine.getViewer());
215: return false;
216: }
217:
218: this .saxParserFactory.setSchema(this .schema);
219: this .saxParserFactory.setFeature(
220: "http://xml.org/sax/features/namespace-prefixes",
221: true);
222: this .saxParserFactory.setFeature(
223: "http://xml.org/sax/features/xmlns-uris", true);
224: this .saxParser = this .saxParserFactory.newSAXParser();
225: this .saxParser.parse(systemId, this );
226: } catch (Exception e) {
227: new JXMessageBox(JOptionPane.ERROR_MESSAGE,
228: "XML Parsing Failure", "" + e, this .virtualMachine
229: .getViewer());
230: return false;
231: }
232:
233: return true;
234: }
235:
236: /**
237: * This method belongs to the DefaultHandler. It receives notification of
238: * the start of the document. It throws SAXException.
239: */
240: public void startDocument() throws SAXException {
241: if (JXGLOBAL.DEBUG_PARSER)
242: System.out.println("########## START DOCUMENT ##########");
243: }
244:
245: /**
246: * This method belongs to the DefaultHandler. It receives notification of
247: * the start of an element. It throws SAXException.
248: * @param namespaceURI - The Namespace URI, or the empty string if the element has
249: * no Namespace URI or if Namespace processing is not being performed.
250: * @param localName - The local name (without prefix), or the empty string
251: * if Namespace processing is not being performed.
252: * @param qName - The qualified name (with prefix), or the empty string if
253: * qualified names are not available.
254: * @param attr - The attributes attached to the element. If there
255: * are no attributes, it shall be an empty Attributes object.
256: */
257: public void startElement(String namespaceURI, String localName,
258: String qName, Attributes attr) throws SAXException {
259: this .temp = "";
260:
261: if (JXGLOBAL.DEBUG_PARSER)
262: System.out.println("########## START ELEMENT LOCAL NAME:"
263: + localName);
264:
265: this .virtualMachine.stackCall(localName, null, attr,
266: JXGLOBAL.JXSTACK_CALL.JXSTACK_PUSH);
267: }
268:
269: public void error(SAXParseException exception) throws SAXException {
270: validationError = true;
271: saxParseException = exception;
272: }
273:
274: public void fatalError(SAXParseException exception)
275: throws SAXException {
276: validationError = true;
277: saxParseException = exception;
278: }
279:
280: public void warning(SAXParseException exception)
281: throws SAXException {
282: }
283:
284: /**
285: * This method validates an XML file.
286: * @param systemId is the file name and path of the XML file we wish to
287: * parse.
288: * @return true if success, else false on the event of an exception.
289: */
290: public boolean validateXML(String systemId) {
291: /** Instantiate a new SaxParserFactory object to parse the XML. */
292: this .saxParserFactory = SAXParserFactory.newInstance();
293: this .saxParserFactory.setNamespaceAware(true);
294:
295: try {
296: saxParser = saxParserFactory.newSAXParser();
297: } catch (ParserConfigurationException e) {
298: new JXMessageBox(JOptionPane.ERROR_MESSAGE,
299: "Validation Configuration Exception", "" + e,
300: this .virtualMachine.getViewer());
301: return false;
302: } catch (SAXException e) {
303: new JXMessageBox(JOptionPane.ERROR_MESSAGE,
304: "Validation SAX Exception", "" + e,
305: this .virtualMachine.getViewer());
306: return false;
307: }
308:
309: this .schemaFactory = SchemaFactory
310: .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
311:
312: try {
313: Vector<Plugin> list = this .virtualMachine.getPluginParser()
314: .getPluginListCTL(true);
315: StreamSource[] sources = new StreamSource[list.size() + 1];
316:
317: sources[0] = new StreamSource(getClass()
318: .getResourceAsStream("/org/openjx/OpenJX.xsd"));
319:
320: for (int i = 0; i < list.size(); i++) {
321: Plugin plugin = list.elementAt(i);
322: if (plugin.getPluginControl() == false)
323: continue;
324:
325: if (plugin.getPluginSchema() != null
326: || !plugin.getPluginSchema().equals(""))
327: sources[i + 1] = new StreamSource(getClass()
328: .getResourceAsStream(
329: "/" + plugin.getPluginSchema()));
330: else
331: sources[i + 1] = new StreamSource(getClass()
332: .getResourceAsStream("/"));
333: }
334:
335: if (sources != null && sources[0] != null)
336: this .schema = schemaFactory.newSchema(sources);
337: } catch (SAXException e) {
338: new JXMessageBox(JOptionPane.ERROR_MESSAGE,
339: "Validation: SAX Exception", "" + e,
340: this .virtualMachine.getViewer());
341: return false;
342: }
343:
344: Validator validator = schema.newValidator();
345:
346: validator.setErrorHandler(this );
347:
348: try {
349: validator.validate(new StreamSource(systemId));
350: } catch (FileNotFoundException e) {
351: new JXMessageBox(JOptionPane.ERROR_MESSAGE,
352: "Validation: File Not Found Exception", "" + e,
353: this .virtualMachine.getViewer());
354: return false;
355: } catch (SAXException e) {
356: new JXMessageBox(JOptionPane.ERROR_MESSAGE,
357: "Validation: SAX Exception", "" + e,
358: this .virtualMachine.getViewer());
359: return false;
360: } catch (IOException e) {
361: new JXMessageBox(JOptionPane.ERROR_MESSAGE,
362: "Validation: IO Exception", "" + e,
363: this .virtualMachine.getViewer());
364: return false;
365: }
366:
367: if (this .validationError == true) {
368: new JXMessageBox(JOptionPane.ERROR_MESSAGE,
369: "Validation: Invalid Form", "JX Form is invalid: "
370: + this .validationError + ", "
371: + this .saxParseException.getMessage(),
372: this .virtualMachine.getViewer());
373: return false;
374: } else {
375: return true;
376: }
377: }
378:
379: }
|