/**
* 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.partitioner;
import edu.isi.pegasus.planner.classes.Data;
import edu.isi.pegasus.planner.partitioner.graph.GraphNode;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* This is an abstract container for a partition in the graph. This used for
* the generation of the partition element in the partition graph, and identifies
* the relations between the jobs in the partition if any.
*
*
* @author Karan Vahi
* @version $Revision$
*/
public class Partition extends Data {
/**
* The set of node id's in the partition.
*/
private Set<String> mNodeSet;
/**
* A map containing a node and it's parents ids in the partition.
* A node id's is the key and the corresponding value is the list of
* String id's of it's parents. The map only contain those nodes for
* which there is a parent.
*/
private Map <String,List<String>>mParentsMap;
/**
* The list of <code>GraphNode<code> objects corresponding to the nodes
* making the partiition.
*/
private List<GraphNode> mNodeList;
/**
* The partition id of the partition.
*/
private String mID;
/**
* The index associated with the partition. In most cases the ID of the
* partition is constructed using this index.
*/
private int mIndex;
/**
* The name of the partition.
*/
private String mName;
/**
* A pointer to the last added node to the partition.
*/
private GraphNode mLastAddedNode;
/**
* A boolean indicating whether a label was associated with the
* jobs in the partition or not.
*/
private boolean mHasAssociatedLabel;
/**
* The default constructor.
*/
public Partition(){
mID = null;
mName = "test";
mIndex = -1;
mNodeSet = new LinkedHashSet();
mParentsMap = new HashMap();
mNodeList = new java.util.LinkedList();
mLastAddedNode = null;
mHasAssociatedLabel = false;
}
/**
* The overloaded constructor.
*
* @param nodeList list of <code>GraphNode</code> objects.
* @param id the partition id of the partition.
*/
public Partition(List nodeList, String id) {
mNodeList = nodeList;
mID = id;
mParentsMap = new HashMap(nodeList.size());
mNodeSet = new LinkedHashSet(nodeList.size());
mIndex = -1;
//default to test
mName = "test";
mHasAssociatedLabel = false;
mLastAddedNode = null;
for( Iterator it = mNodeList.iterator(); it.hasNext(); ){
mNodeSet.add(((GraphNode)it.next()).getID());
}
}
/**
* Adds a node to the partition. It ends up adding it to the underneath
* node list.
*
* @param node the <code>GraphNode</code> object corresponding to the job
* that is to be added.
*/
public void addNode(GraphNode node){
mNodeList.add(node);
//also add it to the underlying job set
mNodeSet.add(node.getID());
mLastAddedNode = node;
}
/**
* Returns the last added node to the partition.
*
* @return the last added node, or null in case partition is empty
*/
public GraphNode lastAddedNode(){
return mLastAddedNode;
}
/**
* Returns a list of nodes making up the partition.
*
* @return List of <code>GraphNode</code> objects.
*/
public List<GraphNode> getNodes(){
return this.mNodeList;
}
/**
* Returns the root nodes in the partition. They can only be determined, after
* the constructPartition() has been called.
*
* @return List of <code>GraphNode</code> objects that are the root.
*/
public List getRootNodes(){
List l = new ArrayList(10);
Map m = this.getRelations();
for(Iterator it = getNodes().iterator();it.hasNext();){
GraphNode gn = (GraphNode)it.next();
if(!m.containsKey(gn.getID())){
l.add(gn);
}
}
return l;
}
/**
* It while looking at the node list constructs the relations between
* the jobs in the partition, that can be gotten through
* getRelationsInPartition().
*/
public void constructPartition(){
//traverse through all the nodes in the partition
for(Iterator it = mNodeList.iterator();it.hasNext();){
GraphNode node = (GraphNode)it.next();
Collection<GraphNode> parents = node.getParents();
if(parents == null){
continue;
}
//traverse through all the parents of the node, in
//the original DAX/Graph,that may or maynot be in
//this partition
List partitionParents = new java.util.LinkedList();
for(Iterator pIt = parents.iterator();pIt.hasNext();){
GraphNode parent = (GraphNode)pIt.next();
if(mNodeSet.contains(parent.getID())){
//relation between 2 nodes in the same partition.
partitionParents.add(parent.getID());
}
}
//only add if there are any parents
if(!partitionParents.isEmpty()){
mParentsMap.put(node.getID(), partitionParents);
}
}
}
/**
* It sets the partition name to the value passed.
*
* @param name the name to which the partition name needs to be set to.
*/
public void setName(String name){
mName = name;
}
/**
* It returns the name of the partition.
*/
public String getName(){
return mName;
}
/**
* Returns a boolean indicating if partition was associated with a label.
*
* @return boolean
*/
public boolean hasAssociatedLabel(){
return this.mHasAssociatedLabel;
}
/**
* Set a boolean indicating if partition was associated with a label.
*
* @param value boolean value
*/
public void doesHaveAssociatedLabel(boolean value ){
this.mHasAssociatedLabel = value;
}
/**
* Returns the number of nodes in the partition
*
* @return the size
*/
public int getSize(){
return this.mNodeList.size();
}
/**
* It sets the index associated with this partition to the value passed.
*
* @param index the index value.
*/
public void setIndex(int index){
mIndex = index;
}
/**
* It returns the index to number of the partition.
*/
public int getIndex(){
return mIndex;
}
/**
* It returns the unique id that is associated with the partition.
*/
public String getID(){
return mID;
}
/**
* It sets the id of the partition.
*
* @param id the id of the partition.
*/
public void setID(String id){
mID = id;
}
/**
* Returns the number of nodes in the partition.
*
* @return the number of nodes.
*/
public int size(){
return mNodeList.size();
}
/**
* Returns a list of id's of parents for a node in the partition.
* It lists parents that in the partition itself
*
* @param id the node for which parents are required
*
* @return List of parents else empty list
*/
public List<String> getParents( String id ){
List<String> parents = (List)mParentsMap.get(id);
return ( parents == null )? new LinkedList(): parents;
}
/**
* Returns a String version of the object.
*/
public String toString(){
StringBuffer sb = new StringBuffer();
sb.append("Partition ID ->").append(mID);
for( Iterator it = this.mNodeList.iterator(); it.hasNext(); ){
GraphNode gn = (GraphNode)it.next();
String id = (String)gn.getID();
sb.append( "\nJob ->").append(id);
sb.append( "\nBag ->" ).append( gn.getBag() );
List l = (List)mParentsMap.get(id);
if( l == null)
continue;
Iterator it1 = l.iterator();
sb.append(" Parents {");
while(it1.hasNext()){
sb.append(it1.next()).append(',');
}
sb.append("}");
}
return sb.toString();
}
/**
* Returns the xml description of the object. This is used for generating
* the partition graph. That is no longer done.
*
* @param writer is a Writer opened and ready for writing. This can also
* be a StringWriter for efficient output.
*
* @exception IOException if something fishy happens to the stream.
*/
public void toXML( Writer writer ) throws IOException {
String newLine = System.getProperty( "line.separator", "\r\n" );
String indent = "\t";
//write out the partition xml element
writer.write( indent );
writer.write( "<partition");
writeAttribute( writer, "name", mName );
writeAttribute( writer, "index", Integer.toString( mIndex ) );
writeAttribute( writer, "id", mID );
writer.write( ">" );
writer.write( newLine );
//write out all the jobs making up the partition
String newIndent = indent + "\t";
for ( Iterator it = mNodeList.iterator(); it.hasNext() ;){
GraphNode gn = (GraphNode)it.next();
writer.write( newIndent );
writer.write( "<job" );
writeAttribute( writer, "name", gn.getName() );
writeAttribute( writer, "id", gn.getID() );
writer.write( "/>" );
writer.write( newLine );
}
//write out all the dependencies amongst the jobs.
String id;
for ( Iterator it = mNodeSet.iterator(); it.hasNext() ; ){
id = (String)it.next();
List l = (List)mParentsMap.get(id);
if( l == null || l.isEmpty())
continue;
//write out the child
writer.write( newIndent );
writer.write( "<child" );
writeAttribute( writer, "ref", id );
writer.write( ">");
writer.write( newLine );
//write out all the parents of the child
String parentIndent = newIndent + "\t";
for( Iterator it1 = l.iterator(); it1.hasNext(); ){
writer.write( parentIndent );
writer.write( "<parent" );
writeAttribute( writer, "ref", (String)it1.next() );
writer.write( "/>" );
writer.write( newLine );
}
writer.write( newIndent );
writer.write( "</child>" );
writer.write( newLine );
}
writer.write( indent );
writer.write( "</partition>" );
writer.write( newLine );
}
/**
* Returns the xml description of the object. This is used for generating
* the partition graph. That is no longer done.
*
* @return String containing the Partition object in XML.
*
* @exception IOException if something fishy happens to the stream.
*/
public String toXML() throws IOException{
Writer writer = new StringWriter(32);
toXML( writer );
return writer.toString();
}
/**
* Writes an attribute to the stream. Wraps the value in quotes as required
* by XML.
*
* @param writer
* @param key
* @param value
*
* @exception IOException if something fishy happens to the stream.
*/
private void writeAttribute( Writer writer, String key, String value ) throws IOException{
writer.write( " " );
writer.write( key );
writer.write( "=\"");
writer.write( value );
writer.write( "\"" );
}
/**
* It returns the set of the job ids making up the partition.
*/
public Set getNodeIDs(){
return mNodeSet;
}
/**
* Ends up assigning the parents to a particular node. It does assign
* the parents to the node, if the node is in the partition. It however
* does not check if the parents are in the partition or not.
*
* @param node the id of the node for which you want to add the parents.
* @param parents list of id's of the parents of the nodes.
*/
public void addParents(String node, List parents){
//check if node is in the node set
if(mNodeSet.contains(node)){
//add to the graph
mParentsMap.put(node,parents);
}
}
/**
* A function to return the child-parent relations for the jobs making up the
* partition. The child parent relations are only returned for the jobs
* that have parents in the partition.
*
* @return Map containing the job id's as the keys and the values as the
* list of the parent id's in the partition.
*/
public Map getRelations(){
return mParentsMap;
}
/**
* Returns a copy of the object
*/
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Clone method not implemented in Partition");
}
}