001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015:
016: package org.griphyn.cPlanner.parser;
017:
018: import java.io.File;
019: import java.io.FileNotFoundException;
020:
021: import org.griphyn.cPlanner.common.LogManager;
022: import org.griphyn.cPlanner.common.PegasusProperties;
023: import org.xml.sax.Attributes;
024: import org.xml.sax.Locator;
025: import org.xml.sax.SAXException;
026: import org.xml.sax.XMLReader;
027: import org.xml.sax.helpers.DefaultHandler;
028: import org.xml.sax.helpers.XMLReaderFactory;
029:
030: /**
031: * This is the base class which all the xml parsing classes extend.
032: * It initializes the xml parser namely Xerces, sets it's various features
033: * like turning on validation against schema etc, plus the namespace resolution.
034: *
035: * @author Karan Vahi
036: * @author Gaurang Mehta
037: *
038: * @version $Revision: 50 $
039: *
040: */
041:
042: public abstract class Parser extends DefaultHandler {
043:
044: /**
045: * Default parser name. Using Xerces at present.
046: */
047: protected final String DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser";
048:
049: /**
050: * Locator object to determine on which line in the xml has the error
051: * occured.
052: */
053: protected Locator mLocator;
054:
055: /**
056: * Holds the text in an element (text between start and final tags if any).
057: * Used in case of elements of mixed type.
058: */
059: protected StringBuffer mTextContent;
060:
061: /**
062: * The LogManager object which logs the Pegasus messages.
063: */
064: protected LogManager mLogger;
065:
066: /**
067: * The String which contains the messages to be logged.
068: */
069: protected String mLogMsg;
070:
071: /**
072: * The object which is used to parse the dax. This reads the XML document
073: * and sends it to the event handlers.
074: */
075: protected XMLReader mParser = null;
076:
077: /**
078: * The object holding all the properties pertaining to Pegasus.
079: */
080: protected PegasusProperties mProps;
081:
082: /**
083: * A String that holds the contents of data passed as text. The string
084: * should only be trimmed when the appropriate end tag of the element is
085: * invoked. At this point, a whitespace is added if there are whitespaces in
086: * at the ends.
087: */
088: protected String mTextString;
089:
090: /**
091: * Boolean flag to ensure that two adjacent filenames are separated by a
092: * whitespace.
093: */
094: protected boolean mAdjFName;
095:
096: /**
097: * Intialises the parser. Sets the various features. However the parsing is
098: * done in the implementing class, by call mParser.parse(filename).
099: *
100: * @param properties the <code>PegasusProperties</code> to be used.
101: */
102: public Parser(PegasusProperties properties) {
103: mTextContent = new StringBuffer();
104: mLogMsg = new String();
105: mLogger = LogManager.getInstance();
106: mProps = properties;
107: mTextString = new String();
108: mAdjFName = false;
109: mTextContent.setLength(0);
110: createParserInstance();
111: }
112:
113: /**
114: * An empty implementation is provided by DefaultHandler of ContentHandler.
115: * This method receives the notification from the sacks parser when start
116: * tag of an element comes. Any parser class must implement this method.
117: */
118: public abstract void startElement(String uri, String local,
119: String raw, Attributes attrs) throws SAXException;
120:
121: /**
122: * An empty implementation is provided by DefaultHandler class. This method
123: * is called automatically by the Sax parser when the end tag of an element
124: * comes in the xml file. Any parser class should implement this method
125: */
126: public abstract void endElement(String uri, String localName,
127: String qName);
128:
129: /**
130: * This is called automatically when the end of the XML file is reached.
131: */
132: public abstract void endDocument();
133:
134: /**
135: * Start the parser. This starts the parsing of the file by the parser.
136: *
137: * @param file the path to the XML file you want to parse.
138: */
139: public abstract void startParser(String file);
140:
141: /**
142: * Helps the load database to locate the VDLx XML schema, if available.
143: * Please note that the schema location URL in the instance document
144: * is only a hint, and may be overriden by the findings of this method.
145: *
146: * @return a location pointing to a definition document of the XML
147: * schema that can read VDLx. Result may be null, if such a document
148: * is unknown or unspecified.
149: */
150: public abstract String getSchemaLocation();
151:
152: /**
153: * Sets the list of external real locations where the XML schema may be found.
154: * Since this list can be determined at run-time through properties etc., we
155: * expect this function to be called between instantiating the parser, and
156: * using the parser
157: *
158: * @param list is a list of strings representing schema locations. The content
159: * exists in pairs, one of the namespace URI, one of the location URL.
160: *
161: *
162: */
163: public void setSchemaLocations(String list) {
164: /*
165: // default place to add
166: list += "http://www.griphyn.org/working_groups/VDS/vdl-1.19.xsd " +
167: "http://www.griphyn.org/working_groups/VDS/vdl-1.19.xsd";
168: */
169:
170: // schema location handling
171: try {
172: mParser
173: .setProperty(
174: "http://apache.org/xml/properties/schema/external-schemaLocation",
175: list);
176: } catch (SAXException se) {
177: mLogger.log("The SAXParser reported an error: "
178: + se.getMessage(), LogManager.ERROR_MESSAGE_LEVEL);
179: }
180: }
181:
182: /**
183: * This is used to store the character data that is in xml. An implementation
184: * of the interface for the Sacks parser.
185: */
186: public void characters(char[] chars, int start, int length) {
187:
188: //appending the buffer with chars. We use this way bec sacks parser can
189: //parse internally the data any way they like
190:
191: //Very IMPORTANT
192: String temp = new String(chars, start, length);
193:
194: /*if(temp.trim().length() > 0){
195: mTextContent.append(temp);
196: }*/
197: temp = this .ignoreWhitespace(temp);
198: mTextContent.append(temp);
199: //set the adjacent flag to false
200: mAdjFName = false;
201:
202: }
203:
204: /**
205: * Our own implementation for ignorable whitespace. A String that holds the
206: * contents of data passed as text by the underlying parser. The whitespaces
207: * at the end are replaced by one whitespace.
208: *
209: * @param str The string that contains whitespaces.
210: *
211: * @return String corresponding to the trimmed version.
212: *
213: */
214: public String ignoreWhitespace(String str) {
215: boolean st = false;
216: boolean end = false;
217: int length = str.length();
218: if (length > 0) {
219: //check for whitespace in the
220: //starting
221: if (str.charAt(0) == ' ' || str.charAt(0) == '\t'
222: || str.charAt(0) == '\n') {
223: st = true;
224: }
225: //check for whitespace in the end
226: if (str.length() > 1
227: && (str.charAt(length - 1) == ' '
228: || str.charAt(length - 1) == '\t' || str
229: .charAt(length - 1) == '\n')) {
230:
231: end = true;
232: }
233: //trim the string and add a single whitespace accordingly
234: str = str.trim();
235: str = st == true ? ' ' + str : str;
236: str = end == true ? str + ' ' : str;
237: }
238:
239: return str;
240: }
241:
242: /**
243: * Overrides the empty implementation provided by Default Handler and sets
244: * the locator variable for the locator.
245: *
246: * @param loc the Locator object which keeps the track as to the line
247: * numbers of the line being parsed.
248: */
249: public void setDocumentLocator(Locator loc) {
250: this .mLocator = loc;
251: }
252:
253: /**
254: * Tests whether the file exists or not.
255: */
256: public void testForFile(String file) throws FileNotFoundException {
257:
258: File f = new File(file);
259: if (!f.exists()) {
260: mLogMsg = "The file (" + file
261: + " ) specified does not exist";
262: throw new FileNotFoundException(mLogMsg);
263: }
264: }
265:
266: /**
267: * Creates an instance of the parser, and sets the various options to it.
268: */
269: private void createParserInstance() {
270: //creating a parser
271: try {
272: mParser = XMLReaderFactory
273: .createXMLReader(DEFAULT_PARSER_NAME);
274: } catch (Exception e) {
275: throw new RuntimeException("Unable to create XMLReader"
276: + e.getMessage(), e);
277: }
278:
279: //setting the handlers The class extend DefaultHandler which provides
280: //for a empty implemetnation of the four handlers
281: mParser.setContentHandler(this );
282: mParser.setErrorHandler(new XMLErrorHandler());
283:
284: try {
285: //setting the feature that xml should be validated against the
286: //xml schema specified in it
287:
288: setParserFeature("http://xml.org/sax/features/validation",
289: true);
290: setParserFeature(
291: "http://apache.org/xml/features/validation/schema",
292: true);
293:
294: //should be set only for debugging purposes
295: //setParserFeature("http://apache.org/xml/features/validation/schema-full-checking", true);
296:
297: setParserFeature(
298: "http://apache.org/xml/features/validation/dynamic",
299: true);
300: setParserFeature(
301: "http://apache.org/xml/features/validation/warn-on-duplicate-attdef",
302: true);
303:
304: //fails with the new xerces
305: //setParserFeature("http://apache.org/xml/features/validation/warn-on-undeclared-elemdef", true);
306:
307: setParserFeature(
308: "http://apache.org/xml/features/warn-on-duplicate-entitydef",
309: true);
310: setParserFeature(
311: "http://apache.org/xml/features/validation/schema/element-default",
312: true);
313:
314: } catch (Exception e) {
315: //if a locator error then
316: if (mLocator != null) {
317: String message = "Error in " + mLocator.getSystemId()
318: + " at line " + mLocator.getLineNumber()
319: + " at column " + mLocator.getColumnNumber()
320: + e.getMessage();
321: mLogger.log(message, LogManager.ERROR_MESSAGE_LEVEL);
322:
323: }
324: mLogger.log(e.getMessage(), LogManager.ERROR_MESSAGE_LEVEL);
325: }
326:
327: }
328:
329: /**
330: * Sets a parser feature, and fails here enabling us to set all the following
331: * features.
332: *
333: * @param uri is the feature's URI to modify
334: * @param flag is the new value to set.
335: * @return true if the feature could be set, else false for
336: * an exception.
337: */
338: public boolean setParserFeature(String uri, boolean flag) {
339: boolean result = false;
340: try {
341: this .mParser.setFeature(uri, flag);
342: result = true;
343: } catch (SAXException se) {
344: mLogger.log("Unable to set parser feature " + uri + " :"
345: + se.getMessage(), LogManager.ERROR_MESSAGE_LEVEL);
346: }
347: return result;
348: }
349:
350: }
|