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 org.griphyn.cPlanner.common.UserOptions;
019: import org.griphyn.cPlanner.common.LogManager;
020: import org.griphyn.cPlanner.common.PegasusProperties;
021:
022: import org.griphyn.cPlanner.parser.pdax.Callback;
023:
024: import org.griphyn.cPlanner.partitioner.Partition;
025:
026: import org.griphyn.cPlanner.partitioner.graph.GraphNode;
027:
028: import org.griphyn.common.util.FactoryException;
029:
030: import org.xml.sax.Attributes;
031: import org.xml.sax.SAXException;
032:
033: import java.io.File;
034:
035: import java.util.HashMap;
036: import java.util.List;
037:
038: /**
039: * This is a parser class for the parsing the pdax that contain the jobs in the
040: * various partitions and the relations between the partitions.
041: *
042: * @author Karan Vahi
043: * @version $Revision: 50 $
044: */
045: public class PDAXParser extends Parser {
046:
047: /**
048: * The "not-so-official" location URL of the DAX schema definition.
049: */
050: public static final String SCHEMA_LOCATION = "http://pegasus.isi.edu/schema/pdax-2.0.xsd";
051:
052: /**
053: * URI namespace
054: */
055: public static final String SCHEMA_NAMESPACE = "http://pegasus.isi.edu/schema/PDAX";
056:
057: /**
058: * The object holding the contents of one partition as indicated in the
059: * pdax.
060: */
061: private Partition mPartition;
062:
063: /**
064: * The current depth of parsing through the xml structure.
065: */
066: private int mCurrentDepth;
067:
068: /**
069: * The current child.
070: */
071: private String mChild;
072:
073: /**
074: * List of parents for a particular child.
075: */
076: private List mParents;
077:
078: /**
079: * The callback handler to which the callbacks are sent during designated
080: * points of parsing the pdax.
081: */
082: private Callback mCallback;
083:
084: /**
085: * The default constructor.
086: *
087: * @param properties the <code>PegasusProperties</code> to be used.
088: */
089: public PDAXParser(PegasusProperties properties) {
090: super (properties);
091: //intialize to null every member variable
092: mPartition = null;
093: mCurrentDepth = 0;
094: mCallback = null;
095: }
096:
097: /**
098: * The constructor initialises the parser, and turns on the validation feature
099: * in Xerces.
100: *
101: * @param fileName the file which one has to parse using the parser.
102: * @param properties the <code>PegasusProperties</code> to be used.
103: */
104: public PDAXParser(String fileName, PegasusProperties properties) {
105: super (properties);
106: mCurrentDepth = 0;
107:
108: try {
109: this .testForFile(fileName);
110: } catch (Exception e) {
111: throw new RuntimeException(e);
112: }
113: mCallback = null;
114:
115: //set the schema location against which
116: //to validate.
117: String schemaLoc = getSchemaLocation();
118: mLogger.log("Picking schema " + schemaLoc,
119: LogManager.CONFIG_MESSAGE_LEVEL);
120: String list = PDAXParser.SCHEMA_NAMESPACE + " " + schemaLoc;
121: setSchemaLocations(list);
122:
123: }
124:
125: /**
126: * Sets the callback handler for this parsing instance.
127: */
128: public void setCallback(Callback callback) {
129: mCallback = callback;
130: }
131:
132: /**
133: * Ends up starting the parsing of the file , by the underlying parser.
134: *
135: * @param file the path/url to the file that needs to be parsed.
136: */
137: public void startParser(String file) {
138: try {
139: mParser.parse(file);
140: } catch (FactoryException fe) {
141: //throw it as it is for time being
142: throw fe;
143: } catch (Exception e) {
144: String message;
145: //if a locator error then
146: if (mLocator != null) {
147: message = "Parsing Error in " + mLocator.getSystemId()
148: + " at line " + mLocator.getLineNumber()
149: + " at column " + mLocator.getColumnNumber()
150: + " : ";
151:
152: } else {
153: message = "Parsing the PDAX file ";
154: mLogger.log(message, LogManager.ERROR_MESSAGE_LEVEL);
155: }
156: throw new RuntimeException(message, e);
157: }
158:
159: }
160:
161: /**
162: * An empty implementation is provided by DefaultHandler of ContentHandler.
163: * This method receives the notification from the sacks parser when start
164: * tag of an element comes. Any parser class must implement this method.
165: */
166: public void startElement(String uri, String local, String raw,
167: Attributes attrs) throws SAXException {
168:
169: String key;
170: String value;
171: int i = 0;
172:
173: //new element increment the depth
174: mCurrentDepth++;
175:
176: if (local.equals("pdag")) {
177: HashMap mp = new HashMap();
178:
179: for (i = 0; i < attrs.getLength(); i++) {
180: key = attrs.getLocalName(i);
181: value = attrs.getValue(i);
182: //should probably check for valid attributes before setting
183: mp.put(key, value);
184: //System.out.println(key + " --> " + value);
185: }
186: //call the callback interface
187: mCallback.cbDocument(mp);
188:
189: return;
190: } else if (local.equals("partition")) {
191: mPartition = new Partition();
192: for (i = 0; i < attrs.getLength(); i++) {
193: key = attrs.getLocalName(i);
194: value = attrs.getValue(i);
195:
196: //check for valid attributes before setting
197: if (key.equals("name")) {
198: mPartition.setName(value);
199: } else if (key.equals("id")) {
200: mPartition.setID(value);
201: } else if (key.equals("index")) {
202: int index = -1;
203: //try convert the String to int
204: try {
205: index = Integer.parseInt(value);
206: } catch (Exception e) {
207: invalidValue(local, key, value);
208: }
209: mPartition.setIndex(index);
210: } else {
211: invalidAttribute(local, key, value);
212: }
213: //System.out.println(key + " --> " + value);
214: }
215: return;
216: } else if (local.equals("job")) {
217: String name = null;
218: String id = null;
219: GraphNode job;
220:
221: for (i = 0; i < attrs.getLength(); i++) {
222: key = attrs.getLocalName(i);
223: value = attrs.getValue(i);
224:
225: //check for valid attributes before setting
226: if (key.equals("name")) {
227: name = value;
228: } else if (key.equals("id")) {
229: id = value;
230: } else {
231: //complain about invalid key
232: invalidAttribute(local, key, value);
233: }
234: }
235: job = new GraphNode(id, name);
236: //add it to the partition
237: mPartition.addNode(job);
238: return;
239: } else if (local.equals("child")) {
240: //we do not know how many parents it has
241: mParents = new java.util.LinkedList();
242: for (i = 0; i < attrs.getLength(); i++) {
243: key = attrs.getLocalName(i);
244: value = attrs.getValue(i);
245: if (key.equals("ref")) {
246: mChild = value;
247: } else {
248: invalidAttribute(local, key, value);
249: }
250: }
251:
252: return;
253: } else if (local.equals("parent")) {
254: for (i = 0; i < attrs.getLength(); i++) {
255: key = attrs.getLocalName(i);
256: value = attrs.getValue(i);
257: if (key.equals("ref")) {
258: mParents.add(value);
259: } else {
260: invalidAttribute(local, key, value);
261: }
262: }
263:
264: return;
265:
266: } else {
267: mLogger.log("No implementation for element " + local,
268: LogManager.ERROR_MESSAGE_LEVEL);
269:
270: throw new RuntimeException("No implementation for element "
271: + local);
272: }
273: }
274:
275: /**
276: * An empty implementation is provided by DefaultHandler class. This method
277: * is called automatically by the Sax parser when the end tag of an element
278: * comes in the xml file. Any parser class should implement this method
279: */
280: public void endElement(String uri, String local, String qName) {
281: //decrement the depth of parsing
282: mCurrentDepth--;
283:
284: if (local.equals("pdag")) {
285: //call the callback interface
286: return;
287: } else if (local.equals("partition")) {
288: //call the callback interface
289: mCallback.cbPartition(mPartition);
290: //cleanup the object
291: mPartition = null;
292: } else if (local.equals("child")) {
293: //check if it was nested in partition element
294: //or the pdag element
295: if (mCurrentDepth == 2) {
296: //means the put the child and parents in partition
297: mPartition.addParents(mChild, mParents);
298: } else if (mCurrentDepth == 1) {
299: //need to call the callback interface
300: mCallback.cbParents(mChild, mParents);
301: } else {
302: throw new RuntimeException("Wrongly formed xml");
303: }
304: } else if (local.equals("parent") || local.equals("job")) {
305: //do nothing
306: return;
307: } else {
308: //end of invalid element.
309: //non reachable line???
310: mLogMsg = "End of invalid element reached " + local;
311: mLogMsg = (mLocator == null) ? mLogMsg :
312: //append the locator information
313: mLogMsg + " at line " + mLocator.getLineNumber()
314: + " at column "
315: + mLocator.getColumnNumber();
316:
317: throw new RuntimeException(mLogMsg);
318: }
319:
320: }
321:
322: /**
323: * This is called automatically when the end of the XML file is reached.
324: */
325: public void endDocument() {
326: //do a sanity check
327: if (mCurrentDepth != 0) {
328: mLogger.log("It seems that the xml was not well formed!!",
329: LogManager.ERROR_MESSAGE_LEVEL);
330: }
331: //call the callback interface
332: mCallback.cbDone();
333: }
334:
335: /**
336: * Helps the load database to locate the PDAX XML schema, if available.
337: * Please note that the schema location URL in the instance document
338: * is only a hint, and may be overriden by the findings of this method.
339: *
340: * @return a location pointing to a definition document of the XML
341: * schema that can read PDAX. Result may be null, if such a document
342: * is unknown or unspecified.
343: */
344: public String getSchemaLocation() {
345: String child = new File(this .SCHEMA_LOCATION).getName();
346: File pdax = // create a pointer to the default local position
347: new File(this .mProps.getSysConfDir(), child);
348:
349: //System.out.println("\nDefault Location of PDAX is " + pdax.getAbsolutePath());
350:
351: // Nota bene: vds.schema.dax may be a networked URI...
352: return this .mProps
353: .getPDAXSchemaLocation(pdax.getAbsolutePath());
354:
355: }
356:
357: /**
358: * Logs a message if an unknown key is come across, while parsing the
359: * xml document.
360: *
361: * @param element the xml element in which the invalid key was come across.
362: * @param key the key that is construed to be invalid.
363: * @param value the value associated with the key.
364: */
365: private void invalidAttribute(String element, String key,
366: String value) {
367: String message = "Invalid attribute " + key + "found in "
368: + element + " with value " + value;
369: message = (mLocator == null) ? message :
370: //append the locator information
371: message + " at line " + mLocator.getLineNumber()
372: + " at column " + mLocator.getColumnNumber();
373:
374: mLogger.log(message, LogManager.WARNING_MESSAGE_LEVEL);
375:
376: }
377:
378: /**
379: * Logs a message if an unknown value is come across, while parsing the
380: * xml document.
381: *
382: * @param element the xml element in which the invalid key was come across.
383: * @param key the key that is construed to be invalid.
384: * @param value the value associated with the key.
385: */
386: private void invalidValue(String element, String key, String value) {
387: String message = "Invalid value " + value + "found in "
388: + element + " for attribute " + value;
389: message = (mLocator == null) ? message :
390: //append the locator information
391: message + " at line " + mLocator.getLineNumber()
392: + " at column " + mLocator.getColumnNumber();
393:
394: mLogger.log(message, LogManager.WARNING_MESSAGE_LEVEL);
395:
396: }
397:
398: }
|