/**
* 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.client;
import edu.isi.pegasus.planner.parser.dax.DAXParser2;
import edu.isi.pegasus.planner.parser.dax.Callback;
import edu.isi.pegasus.planner.parser.dax.DAX2Graph;
import edu.isi.pegasus.planner.parser.dax.DAX2LabelGraph;
import edu.isi.pegasus.planner.parser.DAXParserFactory;
import edu.isi.pegasus.planner.partitioner.WriterCallback;
import edu.isi.pegasus.planner.partitioner.Partitioner;
import edu.isi.pegasus.planner.partitioner.PartitionerFactory;
import edu.isi.pegasus.planner.partitioner.graph.GraphNode;
import edu.isi.pegasus.common.logging.LogManager;
import edu.isi.pegasus.planner.common.PegasusProperties;
import edu.isi.pegasus.planner.classes.PegasusBag;
import edu.isi.pegasus.common.util.FactoryException;
import edu.isi.pegasus.planner.parser.Parser;
import edu.isi.pegasus.planner.parser.dax.DAXParser;
import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;
import java.io.File;
import java.util.Date;
import java.util.Map;
/**
* The class ends up partitioning the dax into smaller daxes according to the
* various algorithms/criteria, to be used for deferred planning.
*
*
* @author Karan Vahi
* @version $Revision$
*/
public class PartitionDAX extends Executable {
/**
* The name of the default partitioner that is loaded, if none is specified
* by the user.
*/
public static final String DEFAULT_PARTITIONER_TYPE =
PartitionerFactory.DEFAULT_PARTITIONING_CLASS;
/**
* The path to the dax file that is to be partitioned.
*/
private String mDAXFile;
/**
* The directory in which the partition daxes are generated.
*/
private String mDirectory;
/**
* The type of the partitioner to be used. Is the same as the name of the
* implementing class.
*/
private String mType;
/**
* The default constructor.
*/
public PartitionDAX() {
}
/**
* Initialize the PartitionDax object
* @param opts the command line argument passed to the PartitionDax
*/
public void initalize(String[] opts){
super.initialize(opts);
mDAXFile = null;
mDirectory = ".";
mType = DEFAULT_PARTITIONER_TYPE;
}
/**
* The main function of the class, that is invoked by the jvm. It calls
* the executeCommand function.
*
* @param args array of arguments.
*/
public static void main(String[] args){
PartitionDAX pdax = new PartitionDAX();
pdax.initalize(args);
pdax.executeCommand();
}
/**
* Executes the partition dax on the basis of the options given by the
* user.
*
* @param args the arguments array populated by the user options.
*/
public void executeCommand() {
int option = 0;
LongOpt[] longOptions = generateValidOptions();
Getopt g = new Getopt("PartitionDAX", getCommandLineOptions(), "vhVD:d:t:c:", longOptions, false);
boolean help = false;
boolean version = false;
int status = 0;
//log the starting time
double starttime = new Date().getTime();
int level = 0;
while ( (option = g.getopt()) != -1) {
//System.out.println("Option tag " + option);
switch (option) {
case 'd': //dax
mDAXFile = g.getOptarg();
break;
case 'D': //dir
mDirectory = g.getOptarg();
break;
case 't': //type
mType = g.getOptarg();
break;
case 'c': // conf
//do nothing
break;
case 'v': //verbose
//set the verbose level in the logger
level++;
break;
case 'V': //version
version = true;
break;
case 'h': //help
help = true;
break;
default: //same as help
mLogger.log("Incorrect option or option usage " +
(char)g.getOptopt(),
LogManager.FATAL_MESSAGE_LEVEL);
printShortVersion();
System.exit(1);
break;
}
}
if ( level > 0 ) {
//set the logging level only if -v was specified
//else bank upon the the default logging level
mLogger.setLevel( level );
}else{
// default level is warning
mLogger.setLevel(LogManager.WARNING_MESSAGE_LEVEL);
}
if ( ( help && version ) || help ) {
printLongVersion();
System.exit( status );
}
else if ( version ) {
//print the version message
mLogger.log( getGVDSVersion(), LogManager.INFO_MESSAGE_LEVEL );
System.exit( status );
}
try{
String pdax = partitionDAX( mProps, mDAXFile, mDirectory, mType );
mLogger.log( "Partitioned DAX written out " + pdax,
LogManager.CONSOLE_MESSAGE_LEVEL );
}
catch( Exception e ){
mLogger.log( "", e, LogManager.FATAL_MESSAGE_LEVEL );
status = 1;
}
//log the end time and time execute
double endtime = new Date().getTime();
double execTime = (endtime - starttime)/1000;
mLogger.log("Time taken to execute is " + execTime + " seconds",
LogManager.INFO_MESSAGE_LEVEL);
System.exit( status );
}
/**
* @param properties the PegasusProperties
* @param daxFile String
* @param directory the directory where paritioned daxes reside
* @param type the type of partitioning to use.
*
* @return the path to the pdax file.
*/
public String partitionDAX( PegasusProperties properties ,
String daxFile,
String directory,
String type ){
int status = 0;
//sanity check for the dax file
if ( daxFile == null || daxFile.length() == 0 ) {
mLogger.log( "The dax file that is to be partitioned not " +
"specified", LogManager.FATAL_MESSAGE_LEVEL );
printShortVersion();
status = 1;
throw new RuntimeException( "Unable to partition" );
}
//always try to make the directory
//referred to by the directory
File dir = new File( directory );
dir.mkdirs();
//build up the partition graph
//String callbackClass = ( type.equalsIgnoreCase("label") ) ?
// "DAX2LabelGraph": //graph with labels populated
// "DAX2Graph";
//load the appropriate partitioner
Callback callback = null;
Partitioner partitioner = null;
String daxName = null;
int state = 0;
try{
PegasusBag bag = new PegasusBag();
bag.add( PegasusBag.PEGASUS_PROPERTIES, properties );
bag.add( PegasusBag.PEGASUS_LOGMANAGER, mLogger );
callback = DAXParserFactory.loadDAXParserCallback( type,
bag,
daxFile );
//set the appropriate key that is to be used for picking up the labels
if( callback instanceof DAX2LabelGraph ){
((DAX2LabelGraph)callback).setLabelKey( properties.getPartitionerLabelKey() );
}
state = 1;
Parser p = (Parser)DAXParserFactory.loadDAXParser( bag, callback, daxFile );
p.startParser( daxFile );
state = 2;
//get the graph map
Map graphMap = (Map) callback.getConstructedObject();
//get the fake dummy root node
GraphNode root = (GraphNode) graphMap.get( DAX2Graph.DUMMY_NODE_ID );
daxName = ( (DAX2Graph) callback).getNameOfDAX();
state = 3;
partitioner = PartitionerFactory.loadInstance( properties,
root,
graphMap,
type );
}
catch ( FactoryException fe){
mLogger.log( fe.convertException() , LogManager.FATAL_MESSAGE_LEVEL);
System.exit( 2 );
}
catch( Exception e ){
int errorStatus = 1;
switch(state){
case 0:
mLogger.log( "Unable to load the DAXCallback", e,
LogManager.FATAL_MESSAGE_LEVEL );
errorStatus = 2;
break;
case 1:
mLogger.log( "Error while parsing the DAX file", e ,
LogManager.FATAL_MESSAGE_LEVEL );
errorStatus = 1;
break;
case 2:
mLogger.log( "Error while determining the root of the parsed DAX",
e, LogManager.FATAL_MESSAGE_LEVEL );
errorStatus = 1;
break;
case 3:
mLogger.log( "Unable to load the partitioner", e,
LogManager.FATAL_MESSAGE_LEVEL );
errorStatus = 2;
break;
default:
mLogger.log( "Unknown Error", e,
LogManager.FATAL_MESSAGE_LEVEL );
errorStatus = 1;
break;
}
status = errorStatus;
}
if( status > 0 ){
throw new RuntimeException( "Unable to partition" );
}
//load the writer callback that writes out
//the partitioned daxes and PDAX
WriterCallback cb = new WriterCallback();
cb.initialize( properties, daxFile, daxName, directory );
//start the partitioning of the graph
partitioner.determinePartitions( cb );
return cb.getPDAX();
}
/**
* Generates the short version of the help on the stdout.
*/
public void printShortVersion() {
String text =
"\n $Id$ " +
"\n" + getGVDSVersion() +
"\n Usage :partitiondax -d <dax file> [-D <dir for partitioned daxes>] " +
" -t <type of partitioning to be used> [-c <path to property file>] [-v] [-V] [-h]";
mLogger.log(text,LogManager.ERROR_MESSAGE_LEVEL);
}
/**
* Generated the long version of the help on the stdout.
*/
public void printLongVersion() {
String text =
"\n " + getGVDSVersion() +
"\n CPlanner/partitiondax - The tool that is used to partition the dax " +
"\n into smaller daxes for use in deferred planning." +
"\n " +
"\n Usage :partitiondax --dax <dax file> [--dir <dir for partitioned daxes>] " +
"\n --type <type of partitioning to be used> [--conf <path to property file>] [--verbose] [--version] " +
"\n [--help]" +
"\n" +
"\n Mandatory Options " +
"\n -d|--dax fn the dax file that has to be partitioned into smaller daxes." +
"\n Other Options " +
"\n -t|--type type the partitioning technique that is to be used for partitioning." +
"\n -D|--dir dir the directory in which the partitioned daxes reside (defaults to " +
"\n current directory)"+
"\n -c|--conf path to property file" +
"\n -v|--verbose increases the verbosity of messages about what is going on." +
"\n -V|--version displays the version number of the Griphyn Virtual Data System." +
"\n -h|--help generates this help";
System.out.println(text);
}
/**
* Tt generates the LongOpt which contain the valid options that the command
* will accept.
*
* @return array of <code>LongOpt</code> objects , corresponding to the valid
* options
*/
public LongOpt[] generateValidOptions() {
LongOpt[] longopts = new LongOpt[7];
longopts[0] = new LongOpt("dir",LongOpt.REQUIRED_ARGUMENT,null,'D');
longopts[1] = new LongOpt("dax",LongOpt.REQUIRED_ARGUMENT,null,'d');
longopts[2] = new LongOpt("type",LongOpt.REQUIRED_ARGUMENT,null,'t');
longopts[3] = new LongOpt("verbose",LongOpt.NO_ARGUMENT,null,'v');
longopts[4] = new LongOpt("version",LongOpt.NO_ARGUMENT,null,'V');
longopts[5] = new LongOpt("help",LongOpt.NO_ARGUMENT,null,'h');
longopts[6] = new LongOpt( "conf", LongOpt.REQUIRED_ARGUMENT, null, 'c' );
return longopts;
}
/**
* Loads all the properties that are needed by this class.
*/
public void loadProperties(){
}
}