/** * Copyright (C) 2010 BonitaSoft S.A. * BonitaSoft, 31 rue Gustave Eiffel - 38000 Grenoble * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2.0 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.bonitasoft.simulation.reporting; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.LineNumberReader; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import net.sf.csv4j.CSVFileProcessor; import net.sf.csv4j.CSVLineProcessor; import net.sf.csv4j.CSVWriter; import org.bonitasoft.simulation.engine.DefinitionPool; import org.bonitasoft.simulation.model.instance.SimActivityInstance; import org.bonitasoft.simulation.model.instance.SimDataInstance; import org.bonitasoft.simulation.model.instance.SimProcessInstance; import org.bonitasoft.simulation.model.process.SimActivity; import org.bonitasoft.simulation.model.process.SimBooleanData; import org.bonitasoft.simulation.model.process.SimData; import org.bonitasoft.simulation.model.process.SimLiteralsData; import org.bonitasoft.simulation.model.process.SimNumberData; import org.bonitasoft.simulation.model.process.SimProcess; /** * @author Romain Bioteau * */ public class CSVSimReportStorage implements ISimulationStore { private static final String PROCESS_INSTANCE = "BonitaSimulation_ProcessInstances_"; //$NON-NLS-1$ private static final String FINISHED_PROCESS_INSTANCE = "BonitaSimulation_FinishedProcessInstances_"; //$NON-NLS-1$ private SimpleDateFormat timeStamp; private String timeStampString; private Map<String,SimActivityInstance> instances; // private CSVWriter processCsvWriter; // private FileWriter processFileWriter; // private FileWriter finishedProcessFileWriter; // private CSVWriter finishProcessCsvWriter; private String processInstancesTmpFile; private String finishedProcessInstancesTmpFile; private boolean flushStore; public CSVSimReportStorage(String workingDirectory,String processName, boolean flushStore) throws IOException{ this.timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss") ; //$NON-NLS-1$ this.timeStampString = timeStamp.format(System.currentTimeMillis()) ; this.processInstancesTmpFile = workingDirectory+File.separatorChar+PROCESS_INSTANCE+processName+timeStampString+".csv" ; //$NON-NLS-1$ this.finishedProcessInstancesTmpFile = workingDirectory+File.separatorChar+FINISHED_PROCESS_INSTANCE+processName+"_"+timeStampString+".csv" ; //$NON-NLS-1$ //$NON-NLS-2$ // this.processFileWriter = new FileWriter(processInstancesTmpFile) ; // this.finishedProcessFileWriter = new FileWriter(finishedProcessInstancesTmpFile) ; // this.processCsvWriter = new CSVWriter(processFileWriter); // this.finishProcessCsvWriter = new CSVWriter(finishedProcessFileWriter); this.flushStore = flushStore ; } public String getStoredInstanceFilename(){ return processInstancesTmpFile ; } public String getFinishedStoredInstanceFilename(){ return finishedProcessInstancesTmpFile ; } public List<SimProcessInstance> getStoredProcessInstances(final int count) throws Exception { if(!flushStore && count > 0){ copyFile(processInstancesTmpFile); } final List<SimProcessInstance> processInstances = new ArrayList<SimProcessInstance>(); instances = new HashMap<String, SimActivityInstance>(); CSVFileProcessor csvProcessor = new CSVFileProcessor(); csvProcessor.setHasHeader(false); csvProcessor.processFile(processInstancesTmpFile, new CSVLineProcessor() { private int currentLine = -1; public void processHeaderLine(int arg0, List<String> arg1) { //NO HEADER } public void processDataLine(int lineNumber, List<String> values) { if(count < 0){ processInstances.add(createProcessInstanceFromString(values)) ; }else{ if(lineNumber <= count){ processInstances.add(createProcessInstanceFromString(values)) ; } } currentLine = lineNumber ; } public boolean continueProcessing() { return count > 0 ? currentLine <= count: true; } }) ; removeLines(processInstancesTmpFile,count); return processInstances; } private void copyFile(String filename) throws Exception { File outputFile = new File(filename+"copy.csv"); //$NON-NLS-1$ if(!outputFile.exists()){ //$NON-NLS-1$ File inputFile = new File(filename); FileReader in = new FileReader(inputFile); FileWriter out = new FileWriter(outputFile); int c; while ((c = in.read()) != -1) out.write(c); in.close(); out.close(); } } private void removeLines(String filePath, int lineNumber) throws Exception { File inputFile = new File(filePath); File newFile = new File(filePath+"tmp") ; FileReader fr = new FileReader(inputFile) ; BufferedReader in = new BufferedReader(fr); FileWriter fw = new FileWriter(newFile); BufferedWriter out = new BufferedWriter(fw); String temp; int i = 1 ; while ((temp = in.readLine()) != null) { if(i >= lineNumber){ out.write(temp); out.newLine(); } i++ ; } out.flush(); fr.close(); fw.close(); in.close(); out.close(); if(!inputFile.delete()){ throw new Exception("Fails to delete temporary buffer file"); } if(!newFile.renameTo(inputFile)){ throw new Exception("Fails to rename temporary buffer file"); } } public List<SimProcessInstance> getStoredFinishedProcessInstances(final int count) throws Exception { if(!flushStore && count > 0){ copyFile(finishedProcessInstancesTmpFile); } final List<SimProcessInstance> processInstances = new ArrayList<SimProcessInstance>(); instances = new HashMap<String, SimActivityInstance>(); CSVFileProcessor csvProcessor = new CSVFileProcessor(); csvProcessor.setHasHeader(false); csvProcessor.processFile(finishedProcessInstancesTmpFile, new CSVLineProcessor() { private int currentLine = -1; public void processHeaderLine(int arg0, List<String> arg1) { //NO HEADER } public void processDataLine(int lineNumber, List<String> values) { if(count < 0){ processInstances.add(createProcessInstanceFromString(values)) ; }else{ if(lineNumber <= count){ processInstances.add(createProcessInstanceFromString(values)) ; } } currentLine = lineNumber ; } public boolean continueProcessing() { return count > 0 ? currentLine <= count: true; } }) ; removeLines(finishedProcessInstancesTmpFile,count); return processInstances; } private SimProcessInstance createProcessInstanceFromString(List<String> values) { String defName = values.get(0) ; String uuid = values.get(1); long startDate = Long.parseLong(values.get(2)); long endDate = Long.parseLong(values.get(3)); SimProcess procDef = DefinitionPool.getInstance().getProcessDefinition(defName); SimProcessInstance simProcInstance = new SimProcessInstance(procDef, uuid,startDate) ; simProcInstance.setEndDate(endDate) ; List<SimDataInstance> data = createDataInstancesFromString(simProcInstance, values.get(4)) ; for(SimDataInstance d : data){ simProcInstance.addDataInstance(d); } if(values.size() > 5){ for(int i = 5 ; i < values.size() ; i++){ SimActivityInstance instance = createActivityInstanceFromString(simProcInstance,values.get(i)) ; instances.put(instance.getInstanceUUID(), instance) ; if(((SimActivity) instance.getDefinition()).isStartElement()){ simProcInstance.addStartElement(instance); } } for(int i = 5 ; i < values.size() ; i++){ buildProcessInstance(simProcInstance,values.get(i)) ; } } return simProcInstance; } private void buildProcessInstance(SimProcessInstance simProcInstance,String value) { String activityProp = value.substring(value.indexOf('(')+1,value.indexOf(')')); String[] values = activityProp.split(","); //$NON-NLS-1$ String uuid = values[0] ; if(instances.get(uuid) != null){ SimActivityInstance instance = instances.get(uuid) ; String[] nextValues = value.split(":") ; //$NON-NLS-1$ if(nextValues.length == 2){ StringTokenizer nextValue = new StringTokenizer(nextValues[1], ","); //$NON-NLS-1$ while (nextValue.hasMoreTokens()) { String nextActivityUUID = nextValue.nextToken(); if(instances.get(nextActivityUUID) != null){ instance.addNext(instances.get(nextActivityUUID)); } } } } } private SimActivityInstance createActivityInstanceFromString(SimProcessInstance parentProcessInstance,String value) { String activityName = value.substring(0, value.indexOf('(')) ; String activityProp = value.substring(value.indexOf('('),value.indexOf(')')); String[] values = activityProp.split(","); //$NON-NLS-1$ String uuid = values[0].substring(1) ; long startDate = Long.parseLong(values[1]) ; long executionDate = Long.parseLong(values[2]) ; long finishDate = Long.parseLong(values[3]) ; int skipped = Integer.parseInt(values[4]) ; SimActivity def = DefinitionPool.getInstance().getActivityDefinition(parentProcessInstance.getDefinition().getName(),activityName); SimActivityInstance instance = new SimActivityInstance(def, uuid, parentProcessInstance); instance.setStartDate(startDate) ; instance.setExecutionDate(executionDate); instance.setFinishDate(finishDate); instance.setSkip(skipped); return instance; } private List<SimDataInstance> createDataInstancesFromString(SimProcessInstance process,String value) { List<SimDataInstance> data = new ArrayList<SimDataInstance>(); StringTokenizer stToken = new StringTokenizer(value, ";") ; //$NON-NLS-1$ while(stToken.hasMoreTokens()){ String d = stToken.nextToken() ; String[] dataValues = d.split(",") ; //$NON-NLS-1$ SimData simDataDefinition = DefinitionPool.getInstance().getDataDefinition(process.getDefinition().getName(), dataValues[0]); SimDataInstance dataInstance = null ; if(simDataDefinition instanceof SimBooleanData){ dataInstance = new SimDataInstance(simDataDefinition, process.getInstanceUUID(), Boolean.valueOf(dataValues[1])); }else if(simDataDefinition instanceof SimNumberData){ dataInstance = new SimDataInstance(simDataDefinition, process.getInstanceUUID(), Double.valueOf(dataValues[1])); }else if(simDataDefinition instanceof SimLiteralsData){ dataInstance = new SimDataInstance(simDataDefinition, process.getInstanceUUID(), dataValues[1]); } data.add(dataInstance) ; } return data; } public void storeProcessInstances(List<SimProcessInstance> instances) throws Exception { FileWriter processFileWriter = new FileWriter(processInstancesTmpFile) ; CSVWriter processCsvWriter = new CSVWriter(processFileWriter); for(SimProcessInstance instance : instances){ processCsvWriter.writeLine(createStringFromProcessInstance(instance,false)); } processFileWriter.flush() ; processFileWriter.close(); } private List<String> createStringFromProcessInstance(SimProcessInstance instance,boolean finished) { DefinitionPool.getInstance().addProcessDefinition((SimProcess) instance.getDefinition()); List<String> result = new ArrayList<String>(); result.add(instance.getDefinition().getName()); result.add(instance.getInstanceUUID()); result.add(((Long)instance.getStartDate()).toString()); result.add(((Long)instance.getEndDate()).toString()); StringBuilder dataValuesBuilder = new StringBuilder(); for(SimDataInstance di : instance.getDataInstance()){ dataValuesBuilder.append(di.getDefinition().getName()).append(",").append(di.getValue().toString()).append(";");//$NON-NLS-1$ //$NON-NLS-2$ } String dataValues = dataValuesBuilder.toString(); if(dataValues.length() > 0){ dataValues = dataValues.substring(0, dataValues.length()-1); } result.add(dataValues) ; if(finished){ Set<SimActivityInstance> parsed = new HashSet<SimActivityInstance>() ; parseFinishedProcessInstance(instance.getStartElemInstances() ,result,parsed) ; }else{ parseProcessInstance(instance.getStartElemInstances() ,result) ; } return result; } private void parseProcessInstance(Set<SimActivityInstance> activityInstances, List<String> result) { for(SimActivityInstance a : activityInstances){ DefinitionPool.getInstance().addActivityDefinition(((SimActivity)a.getDefinition()).getParentProcessName(),(SimActivity) a.getDefinition()) ; result.add(a.toString()); if(a.hasNext()){ parseProcessInstance(a.getNext(),result) ; } } } private void parseFinishedProcessInstance(Set<SimActivityInstance> activityInstances, List<String> result,Set<SimActivityInstance> parsed) { for(SimActivityInstance a : activityInstances){ DefinitionPool.getInstance().addActivityDefinition(((SimActivity)a.getDefinition()).getParentProcessName(),(SimActivity) a.getDefinition()) ; if(a.getExecutionDate() != 0 ){ result.add(a.toString()); parsed.add(a); if(a.hasNext()){ for(SimActivityInstance nextInstance : a.getNext()){ if(!parsed.contains(nextInstance)){ parseFinishedProcessInstance(a.getNext(),result,parsed) ; } } } } } } public void storeProcessInstance(SimProcessInstance instance) throws Exception { FileWriter processFileWriter = new FileWriter(processInstancesTmpFile,true) ; CSVWriter processCsvWriter = new CSVWriter(processFileWriter); processCsvWriter.writeLine(createStringFromProcessInstance(instance,false)); processFileWriter.flush() ; processFileWriter.close(); } public void closeStore() throws Exception{ new File(processInstancesTmpFile).delete() ; new File(finishedProcessInstancesTmpFile).delete() ; } public void storeFinishedProcessInstance(SimProcessInstance instance)throws Exception { FileWriter finishedProcessFileWriter = new FileWriter(finishedProcessInstancesTmpFile,true) ; CSVWriter finishProcessCsvWriter = new CSVWriter(finishedProcessFileWriter); finishProcessCsvWriter.writeLine(createStringFromProcessInstance(instance,true)); finishedProcessFileWriter.flush() ; finishedProcessFileWriter.close(); } public void storeFinishedProcessInstance(List<SimProcessInstance> instances) throws Exception { FileWriter finishedProcessFileWriter = new FileWriter(finishedProcessInstancesTmpFile) ; CSVWriter finishProcessCsvWriter = new CSVWriter(finishedProcessFileWriter); for(SimProcessInstance instance : instances){ finishProcessCsvWriter.writeLine(createStringFromProcessInstance(instance,true)); } finishedProcessFileWriter.flush() ; finishedProcessFileWriter.close(); } public int size() throws FileNotFoundException { FileReader reader = new FileReader(finishedProcessInstancesTmpFile) ; LineNumberReader lnr = new LineNumberReader(reader) ; int result = 0 ; try { while(lnr.readLine() != null){ result++; } } catch (IOException e) { e.printStackTrace(); } finally { try { if(reader != null){ reader.close(); } } catch (IOException e) { e.printStackTrace(); } try { if(lnr != null){ lnr.close(); } } catch (IOException e) { e.printStackTrace(); } } return result ; } }