/**
* Copyright 2007-2008 University Of Southern California
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package edu.isi.pegasus.planner.parser;
import edu.isi.pegasus.common.logging.LogManager;
import edu.isi.pegasus.common.util.CondorVersion;
import edu.isi.pegasus.planner.common.PegasusProperties;
import edu.isi.pegasus.common.util.DynamicLoader;
import edu.isi.pegasus.planner.classes.PegasusBag;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* A factory class to load the appropriate Site Catalog Parser implementations
* based on version in the site catalog element of the XML document
*
* @author Karan Vahi
* @version $Revision$
*/
public class SiteCatalogXMLParserFactory {
/**
* Package to prefix "just" class names with.
*/
public static final String DEFAULT_PARSER_PACKAGE_NAME =
"edu.isi.pegasus.planner.parser";
/*
* Predefined Constant for Site Catalog Version 2.0
*/
private static final long SC_VERSION_2_0_0 = CondorVersion.numericValue( "2.0.0" );
/*
* Predefined Constant for Site Catalog Version 3.0
*/
public static final long SC_VERSION_3_0_0 = CondorVersion.numericValue( "3.0.0" );
/*
* Predefined Constant for Site Catalog Version 4.0
*/
public static final long SC_VERSION_4_0_0 = CondorVersion.numericValue( "4.0.0" );
/**
* The default Site Catalog Parser
*/
public static final String DEFAULT_SC_PARSER_CLASS = "SiteCatalogXMLParser4";
/**
* The SC Parser classname
*/
public static final String SC_PARSER3_CLASS = "SiteCatalogXMLParser3";
/**
* Loads the appropriate DAXParser looking at the dax schema that is specified by
* the user.
*
* @param bag bag of Pegasus intialization objects
* @param file the site catalog file
* @param sites the list of sites that need to be parsed. * means all
*
* @return the SiteCatalogXMLParser class that is loaded.
*
* @exception SiteCatalogXMLParserFactoryException that nests any error that
* might occur during the instantiation
*
* @see #DEFAULT_CALLBACK_PACKAGE_NAME
*/
public static SiteCatalogXMLParser loadSiteCatalogXMLParser( PegasusBag bag, String file , List<String> sites ) throws SiteCatalogXMLParserFactoryException{
String scClass = SiteCatalogXMLParserFactory.DEFAULT_SC_PARSER_CLASS;
LogManager logger = bag.getLogger();
PegasusProperties properties = bag.getPegasusProperties();
//sanity check
if( properties == null){
throw new RuntimeException("Invalid properties passed");
}
if( logger == null){
throw new RuntimeException("Invalid logger passed");
}
//try to figure out the schema version by parsing the dax file
String schemaVersion = null;
try{
Map m = getMetadata( bag, file );
if( m.containsKey( "version" ) && (schemaVersion = (String)m.get( "version" )) != null ){
logger.log( "Site Catalog Schema Version as determined from catalog file " + schemaVersion,
LogManager.DEBUG_MESSAGE_LEVEL );
//append .0 to the version number
//to be able to convert to numberic value
schemaVersion = schemaVersion + ".0";
}
//try to figure out the schema from the schemaLocation
//attribute in the root element
String schemaLocation = (String) m.get( "schemaLocation");
if( schemaVersion == null && schemaLocation != null ){
logger.log( "Guessing schema version from schema location " + schemaLocation,
LogManager.DEBUG_MESSAGE_LEVEL );
//split on whitespace
String constitutents[] = schemaLocation.split(file);
schemaLocation = constitutents[ constitutents.length -1 ];
//get the basename
String schema = new File( schemaLocation ).getName();
if( schema.startsWith( "sc-" ) && schema.endsWith( ".xsd" ) ){
schemaVersion = schema.substring( schema.indexOf( "sc-" ) + 3,
schema.lastIndexOf(".xsd") );
logger.log( "Site Catalog XML Version as determined from schema location " + schemaVersion,
LogManager.DEBUG_MESSAGE_LEVEL );
//append .0 to the version number
//to be able to convert to numberic value
schemaVersion = schemaVersion + ".0";
}
}
}
catch( Exception e ){
logger.log( "Problem while determining the version of dax" , e,
LogManager.ERROR_MESSAGE_LEVEL );
}
if( schemaVersion != null ){
long numericValue = CondorVersion.numericValue(schemaVersion);
if( numericValue < SiteCatalogXMLParserFactory.SC_VERSION_2_0_0 ){
//log error
throw new SiteCatalogXMLParserFactoryException( "Site Catalog Schema Version2 is no longer supported" );
}
else if( numericValue == SiteCatalogXMLParserFactory.SC_VERSION_3_0_0 ){
scClass = SiteCatalogXMLParserFactory.SC_PARSER3_CLASS;
}
else{
scClass = SiteCatalogXMLParserFactory.DEFAULT_SC_PARSER_CLASS;
}
}
logger.log( "Site Catalog Parser Class to be loaded is " + scClass,
LogManager.CONFIG_MESSAGE_LEVEL );
return loadSiteCatalogParser( scClass, bag, sites );
}
/**
* Loads the appropriate Site Catalog Parser looking at the dax schema that is specified by
* the user.
*
* @param classname the classname of the parser class that needs to be loaded
* @param bag bag of Pegasus intialization objects
* @param sites the list of sites that need to be parsed. * means all
*
* @return the DAXParser loaded.
*
* @exception SiteCatalogXMLParserFactoryException that nests any error that
* might occur during the instantiation
*
* @see #DEFAULT_CALLBACK_PACKAGE_NAME
*/
private static final SiteCatalogXMLParser loadSiteCatalogParser( String classname, PegasusBag bag, List<String> sites ){
SiteCatalogXMLParser parser = null;
try{
//load the DAX Parser class
//prepend the package name
String daxClass = ( classname.indexOf('.') == -1)?
//pick up from the default package
DEFAULT_PARSER_PACKAGE_NAME + "." + classname:
//load directly
classname;
DynamicLoader dl = new DynamicLoader( daxClass );
Object argList[] = new Object[2];
Class classList[] = new Class[2];
classList[0] = bag.getClass();
classList[1] = Class.forName("java.util.List");
argList[0] = bag;
argList[1] = sites;
parser = (SiteCatalogXMLParser)dl.instantiate( classList, argList);
}
catch(Exception e){
throw new SiteCatalogXMLParserFactoryException( "Unable to instantiate SiteCatalogXMLParser class ",
classname, e);
}
return parser;
}
/**
* Returns the metadata stored in the root adag element in the DAX
*
* @param bag the bag of initialization objects
* @param file the site catalog file.
*
* @return Map containing the metadata, else an empty map
*/
public static Map getMetadata( PegasusBag bag, String file ){
LogManager logger = bag.getLogger();
if( logger != null ){
logger.log( "Retrieving Metadata from the file " + file ,
LogManager.DEBUG_MESSAGE_LEVEL );
}
SiteCatalogXMLMetadataParser p = new SiteCatalogXMLMetadataParser( bag, "sitecatalog");
p.startParser( file );
return p.getMetadata();
}
}
/**
* A lightweight XML Parser class to just retrieve the meta data in first instance
* of an element in a XML Document. It used to get the metadata in the root element.
*
* @author Karan Vahi
*/
class SiteCatalogXMLMetadataParser extends Parser{
/**
* The root element name to look for.
*/
private String mElement;
/**
* The Metadata object that has to be returned.
*/
private Map<String,String> mMetadata;
/**
* A boolean indicating that parsing is done.
*/
protected boolean mParsingDone;
/**
* The overloaded constructor
*
* @param bag the bag of intiialization documents
* @param element the root element
*/
public SiteCatalogXMLMetadataParser( PegasusBag bag, String element ){
super( bag );
mElement = element;
mMetadata = new HashMap();
mParsingDone = false;
}
/**
* Returns the metadata/attributes assoicated with the element that
* was parsed for.
*
* @return
*/
public Map<String,String> getMetadata(){
if( mParsingDone ){
return mMetadata;
}
throw new RuntimeException( "Method called before parsing was started" );
}
/**
* Start Element.
*
* @param uri
* @param local
* @param raw
* @param attrs
*
* @throws SAXException
*/
public void startElement(String uri, String local, String raw, Attributes attrs) throws SAXException {
//check
if ( local == null || !local.equalsIgnoreCase( mElement) ) {
return;
}
//usually the element we want to search for is the first one
for ( int i=0; i < attrs.getLength(); ++i ) {
String name = attrs.getLocalName(i) ;
String value = attrs.getValue(i) ;
mMetadata.put( name, value );
}
//call to end document
this.endDocument();
//we need to throw an exception to stop the parser
//ugly
throw new StopParserException();
}
/***
* An empty implementation
*
* @param uri
* @param localName
* @param qName
* @throws SAXException
*/
public void endElement(String uri, String localName, String qName) throws SAXException {
}
/**
* Sets the boolean indicating parsing is done
*/
public void endDocument() {
mParsingDone = true;
}
/**
* The function that starts the parser
*
* @param file the file to be parsed
*/
public void startParser(String file) {
try{
this.testForFile( file );
}
catch( Exception e){
throw new RuntimeException( e );
}
//while determining the metadata we are just parsing adag element
//we want the parser validation to be turned off.
this.setParserFeature("http://xml.org/sax/features/validation", false);
this.setParserFeature("http://apache.org/xml/features/validation/schema", false);
try{
mParser.parse( file );
}
catch( StopParserException e ){
//ignore
}
catch (Exception e) {
//if a locator error then
String message = (mLocator == null) ?
"SiteCatalogXMLMetadataParser While parsing the file " + file:
"SiteCatalogXMLMetadataParser While parsing file " + mLocator.getSystemId() +
" at line " + mLocator.getLineNumber() +
" at column " + mLocator.getColumnNumber();
mLogger.logEventCompletion();
throw new RuntimeException(message, e);
}
}
/**
* Not implemented as yet
*
* @return
*/
public String getSchemaLocation() {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Not implemented as yet
*
* @return
*/
public String getSchemaNamespace() {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Private RuntimeException to stop the SAX Parser
*/
private static class StopParserException extends RuntimeException{
}
}