package ever.workflowRepresentation; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import javax.xml.stream.XMLOutputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; /** * This class is the root for workflow. It contains a Sequence which is the main sequence of the workflow. When an serialization to XML is * necessary, the exportToWfTree Method has to be called. * @author Pol Schumacher, Wirtschaftsinformatik, Institut fuer Informatik, Goethe Universitaet Frankfurt * */ public class Workflow implements Serializable { /** * */ private static final long serialVersionUID = 4; // To store the ThreadLocal information when the thread was destroyed // Stores a list of all products used in the workflow /** * It contains the list of the resources of the resource list in the original process description. * In a cooking domain this would be the ingredient list. *Conceptional this fields belong to the product. It is used e.g. to test if an extracted product is in the *resource list or not. Usually this would be done with a static field, which can not be used because of *multithreading. See ThreadLocal concept for more information. */ public ArrayList all; // // To store the ThreadLocal information when the thread was destroyed // // Stores which products names where used and how often. This makes it // // possible to have different HashValues for products with the same name // private HashMap usedNames; /** *Stores the last id which was used for a product. Necessary to generate the ids for the next product. *Usually this would be done with a static field, which can not be used because of *multithreading. See ThreadLocal concept for more information. */ private int lastId; public static final String base = "http://cake.wi2.uni-trier.de/rdf/cake"; /** * The root sequence of a workflow. */ Sequence topLevel; /** * Standard workflow constructor */ public Workflow() { topLevel = new Sequence(null,null); // usedNames=new HashMap(); all=new ArrayList(); lastId=-1; } /** * Sets a new root sequence. * @param seq The Sequence which is set as new root sequence */ public void setTopLevel(Sequence seq) { topLevel.addWfElement(seq); } // public void printWorkflow() // { // String current=""; // // while(current!=null) // { // current = topLevel.popNext().getName(); // System.out.println(current); // } // } /** * This method serializes the workflow to xml and writes out to a file. The Cake dataformat is used. * @param location path to output location */ public void exportWfToTree(String location) { XMLOutputFactory factory = XMLOutputFactory.newInstance(); try { XMLStreamWriter writer = factory .createXMLStreamWriter(new FileOutputStream(location)); writer.writeStartDocument(); writer.writeStartElement("cdop:ObjectPool"); writer.writeNamespace("rwfl", "http://cake.wi2.uni-trier.de/xml/rwfl"); writer.writeNamespace("nest", "http://cake.wi2.uni-trier.de/xml/nest"); writer.writeNamespace("cdol", "http://cake.wi2.uni-trier.de/xml/cdol"); writer.writeNamespace("cdop", "http://cake.wi2.uni-trier.de/xml/cdop"); writer.writeNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); writer.writeAttribute( "xsi:schemaLocation", "http://cake.wi2.uni-trier.de/xml/nest nest.xsd " + "http://cake.wi2.uni-trier.de/xml/cdop cdop.xsd http://cake.wi2.uni-trier.de/xml/rwfl " + "rwfl.xsd http://cake.wi2.uni-trier.de/xml/cdol cdol.xsd"); writer.writeStartElement("rwfl:Workflow"); writer.writeAttribute("status", "READY"); // DataObjects writer.writeStartElement("rwfl:DataObjects"); writer.writeCharacters("\n"); all.add(new SimpleProduct("TESTTEST", 0)); // HashSet all = // for (Product prod : all) { // try { // prod.exportProd2List(writer); // } catch (EmptyProductException e) { // // TODO Auto-generated catch block // System.err.println("Empty Product was in Datastructure."); // continue; // } // } writer.writeEndElement(); // Workflow output topLevel.exportWf2Xml(writer); writer.writeEndDocument(); writer.writeEndDocument(); writer.close(); // if(!ExportValidator.validate(location, "cdop.xsd")) // { // File f = new File(location); // if(f.exists()) // f.delete(); // } } catch (XMLStreamException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } /** * This method serializes the workflow to xml and returns it as String. The Cake dataformat is used. * @return The workflow in an xml string */ public String exportWfToTree() { XMLOutputFactory factory = XMLOutputFactory.newInstance(); ByteArrayOutputStream out = new ByteArrayOutputStream(); try { XMLStreamWriter writer = factory .createXMLStreamWriter(out); writer.writeStartDocument(); writer.writeStartElement("cdop:ObjectPool"); writer.writeNamespace("rwfl", "http://cake.wi2.uni-trier.de/xml/rwfl"); writer.writeNamespace("nest", "http://cake.wi2.uni-trier.de/xml/nest"); writer.writeNamespace("cdol", "http://cake.wi2.uni-trier.de/xml/cdol"); writer.writeNamespace("cdop", "http://cake.wi2.uni-trier.de/xml/cdop"); writer.writeNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); writer.writeAttribute( "xsi:schemaLocation", "http://cake.wi2.uni-trier.de/xml/nest nest.xsd " + "http://cake.wi2.uni-trier.de/xml/cdop cdop.xsd http://cake.wi2.uni-trier.de/xml/rwfl " + "rwfl.xsd http://cake.wi2.uni-trier.de/xml/cdol cdol.xsd"); writer.writeStartElement("rwfl:Workflow"); writer.writeAttribute("status", "READY"); // DataObjects writer.writeStartElement("rwfl:DataObjects"); writer.writeCharacters("\n"); all.add(new SimpleProduct("TESTTEST", 0)); // HashSet all = for (Product prod : all) { try { prod.exportProd2List(writer); } catch (EmptyProductException e) { // TODO Auto-generated catch block System.err.println("Empty Product was in Datastructure."); continue; } } writer.writeEndElement(); // Workflow output topLevel.exportWf2Xml(writer); writer.writeEndDocument(); writer.writeEndDocument(); writer.close(); return out.toString(); // if(!ExportValidator.validate(location, "cdop.xsd")) // { // File f = new File(location); // if(f.exists()) // f.delete(); // } } catch (XMLStreamException e) { e.printStackTrace(); return null; } catch (Exception e) { e.printStackTrace(); return null; } } // // Export fn for artificial workflow without complex Dataflow handling // public void exportWfToTreeArti(String location) { // XMLOutputFactory factory = XMLOutputFactory.newInstance(); // try { // XMLStreamWriter writer = factory // .createXMLStreamWriter(new FileOutputStream(location)); // writer.writeStartDocument(); // writer.writeStartElement("cdop:ObjectPool"); // // writer.writeNamespace("rwfl", // "http://cake.wi2.uni-trier.de/xml/rwfl"); // writer.writeNamespace("nest", // "http://cake.wi2.uni-trier.de/xml/nest"); // writer.writeNamespace("cdol", // "http://cake.wi2.uni-trier.de/xml/cdol"); // writer.writeNamespace("cdop", // "http://cake.wi2.uni-trier.de/xml/cdop"); // writer.writeNamespace("xsi", // "http://www.w3.org/2001/XMLSchema-instance"); // // writer.writeAttribute( // "xsi:schemaLocation", // "http://cake.wi2.uni-trier.de/xml/nest nest.xsd " // + "http://cake.wi2.uni-trier.de/xml/cdop cdop.xsd http://cake.wi2.uni-trier.de/xml/rwfl " // + "rwfl.xsd http://cake.wi2.uni-trier.de/xml/cdol cdol.xsd"); // writer.writeStartElement("rwfl:Workflow"); // // writer.writeAttribute("status", "READY"); // // DataObjects // writer.writeStartElement("rwfl:DataObjects"); // writer.writeCharacters("\n"); //// HashSet all = SimpleProduct.getAllProducts(); // for (Product prod : all) { // try { // prod.exportProd2List(writer); // } catch (EmptyProductException e) { // // TODO Auto-generated catch block // System.err.println("Empty Product was in Datastructure."); // continue; // } // } // writer.writeEndElement(); // // Workflow output // topLevel.exportWf2XmlArti(writer); // // writer.writeEndDocument(); // writer.writeEndDocument(); // writer.close(); // // if(!ExportValidator.validate(location, "cdop.xsd")) // // { // // File f = new File(location); // // if(f.exists()) // // f.delete(); // // } // // } catch (XMLStreamException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } catch (FileNotFoundException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } catch (Exception e) { // e.printStackTrace(); // } // // } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((topLevel == null) ? 0 : topLevel.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Workflow other = (Workflow) obj; if (topLevel == null) { if (other.topLevel != null) return false; } else if (!topLevel.equals(other.topLevel)) return false; return true; } // public WorkflowElement popLast() { // return topLevel.popLast(); // } // // public WorkflowElement getLast() { // return topLevel.getLast(); // } /** * Get the root sequence of a workflow. * @return root sequence */ public Sequence getTopSequence() { return topLevel; } /** * Sets the root sequence of the workflow. * @param seq */ public void setTopSequence(Sequence seq) { topLevel = seq; } /** * Is used to add an ingredient aka. a product which was listed in the ressource list of a process description. * @param p */ public void addProduct(Product p) { all.add(p); } //When a Thread is started or has finished we need to call these methods to change the store position /** * This method copies product data from the ThreadLocal to this workflow and resets the ThreadLocal Data. * The ThreadLocal concept allows a static-like behavior in a multithreaded environment. */ public void moveFromThreadLocalAllProducts() { all=SimpleProduct.getAllProductsThreadLocal(); SimpleProduct.setAllProductsThreadLocal(new ArrayList()); } /** * Takes the data which is in workflow scoope and copies it to the ThreadLocal element. * The ThreadLocal concept allows a static-like behavior in a multithreaded environment. */ public void moveToThreadLocalAllProducts() { SimpleProduct.setAllProductsThreadLocal(all); } // /** // * This method copies the used names data from the ThreadLocal to this workflow and resets the ThreadLocal Data. // * The ThreadLocal concept allows a static-like behavior in a multithreaded environment. // */ // public void moveFromThreadLocalUsedNames() // { // usedNames=SimpleProduct.getUsedThreadLocal(); // SimpleProduct.setUsedThreadLocal(new HashMap()); // } // /** // * Takes the data which is in workflow scoope and copies it to the ThreadLocal element. // * The ThreadLocal concept allows a static-like behavior in a multithreaded environment. // */ // public void moveToThreadLocalUsedNames() // { // SimpleProduct.setUsedThreadLocal(usedNames); // } /** * This method copies the last id used data from the ThreadLocal to this workflow and resets the ThreadLocal Data. * The ThreadLocal concept allows a static-like behavior in a multithreaded environment. */ public void moveFromThreadLocalLastId() { lastId=SimpleProduct.getLastIdThreadLocal(); SimpleProduct.setLastIdThreadLocal(-1); } /** * Takes the data which is in workflow scoope and copies it to the ThreadLocal element. * The ThreadLocal concept allows a static-like behavior in a multithreaded environment. */ public void moveToThreadLocalLastId() { SimpleProduct.setLastIdThreadLocal(lastId); } }