package sushi.application.pages.input.bpmn;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
import org.apache.wicket.ajax.form.OnChangeAjaxBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.ajax.markup.html.form.AjaxButton;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.DefaultDataTable;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.form.upload.FileUpload;
import org.apache.wicket.markup.html.form.upload.FileUploadField;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;
import sushi.application.components.form.ExternalPage;
import sushi.application.components.form.WarnOnExitForm;
import sushi.application.pages.AbstractSushiPage;
import sushi.application.pages.input.bpmn.model.ProcessModelProvider;
import sushi.application.pages.process.modal.ProcessEditorModal;
import sushi.application.pages.simulator.BPMNSimulationPanel;
import sushi.application.pages.simulator.SimulationPanel;
import sushi.bpmn.element.AbstractBPMNElement;
import sushi.bpmn.element.BPMNProcess;
import sushi.process.SushiProcess;
import sushi.xml.importer.BPM2XMLToSignavioXMLConverter;
import sushi.xml.importer.BPMNParser;
/**
* This panel allows the upload and visualisation of a BPMN process model from a BPMN2.0-XML file.
* Furthermore it is possible to simulate this process with the {@link SimulationPanel}.
* @author micha
* @author benni
*/
public class BPMNProcessUploadPanel extends Panel{
private static final long serialVersionUID = 1L;
private FileUploadField fileUpload;
private ProcessEditorModal processEditorModal;
private ArrayList<String> processNameList;
private BPMNProcess processModel;
private DropDownChoice<String> processSelect;
private WarnOnExitForm uploadForm;
private Button uploadButton;
private AjaxButton saveModelButton;
private AjaxButton deleteModelButton;
private SushiProcess process;
private AjaxButton cancelButton;
private AjaxButton saveChangesButton;
private TextField<String> bpmnProcessNameInput;
private String fileNameWithoutExtension;
private String bpmnProcessNameInputValue;
private AbstractSushiPage abstractSushiPage;
private ArrayList<IColumn<AbstractBPMNElement, String>> columns;
private DefaultDataTable<AbstractBPMNElement, String> processModelTable;
private ProcessModelProvider processModelProvider;
private BPMNProcessUploadPanel bpmnProcessUploadPanel;
private ExternalPage externalPage;
private BPMNSimulationPanel simulationPanel;
private final String pathToCoreComponents = "http://localhost:8080/signaviocore/p/editor?id=c%3A%3Btemp%3B";
private final String signavioCoreWorkspace = "~/signaviocore-workspace";
private List<Component> targets;
/**
* This is the constructor for a panel, which allows the upload and visualisation of a BPMN process model from a BPMN2.0-XML file.
* Furthermore it is possible to simulate this process with the {@link SimulationPanel}.
* @param id
* @param abstractSushiPage
*/
@SuppressWarnings("unchecked")
public BPMNProcessUploadPanel(String id, final AbstractSushiPage abstractSushiPage) {
super(id);
this.abstractSushiPage = abstractSushiPage;
this.bpmnProcessUploadPanel = this;
this.processModelProvider = new ProcessModelProvider();
Form<Void> layoutForm = new Form<Void>("layoutForm");
add(layoutForm);
addProcessSelect(layoutForm);
addUploadForm();
createProcessEditModalWindow(layoutForm);
addResultForm();
//TODO:
externalPage = new ExternalPage("iframe", "http://localhost:8181/signaviocore/p/explorer");
externalPage.setOutputMarkupId(true);
add(externalPage);
createTargetList(abstractSushiPage);
}
private void createTargetList(final AbstractSushiPage abstractSushiPage) {
targets = new ArrayList<Component>();
targets.add(deleteModelButton);
targets.add(saveChangesButton);
targets.add(saveModelButton);
targets.add(cancelButton);
targets.add(abstractSushiPage.getFeedbackPanel());
targets.add(processModelTable);
targets.add(bpmnProcessNameInput);
targets.add(uploadButton);
targets.add(fileUpload);
}
private void addResultForm() {
Form<Void> resultForm = new Form<Void>("resultForm");
add(resultForm);
resultForm.add(addProcessModelTable());
saveModelButton = (new AjaxButton("saveModel"){
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form){
if(process.getBpmnProcess() != null){
process.getBpmnProcess().remove();
}
if(bpmnProcessNameInputValue == null || bpmnProcessNameInputValue.isEmpty()){
bpmnProcessNameInputValue = fileNameWithoutExtension;
}
if(!containsOtherProcessSameBPMNProcessName(process, bpmnProcessNameInputValue)){
processModel.setName(bpmnProcessNameInputValue);
process.setBpmnProcess(processModel);
processModel.save();
process.save();
saveModelButton.setVisible(false);
cancelButton.setVisible(false);
saveChangesButton.setVisible(true);
deleteModelButton.setVisible(true);
abstractSushiPage.getFeedbackPanel().success("Saved process!");
} else {
abstractSushiPage.getFeedbackPanel().error("Another process has the same BPMN process name!");
}
addTargets(target);
}
});
saveModelButton.setVisible(false);
resultForm.add(saveModelButton);
saveModelButton.setOutputMarkupId(true);
saveModelButton.setOutputMarkupPlaceholderTag(true);
cancelButton = (new AjaxButton("cancel"){
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form) {
processModel = process.getBpmnProcess();
processModelProvider.setProcessModel(processModel);
if (processModel != null){
deleteModelButton.setVisible(true);
saveChangesButton.setVisible(true);
}
else{
deleteModelButton.setVisible(false);
saveChangesButton.setVisible(false);
}
cancelButton.setVisible(false);
saveModelButton.setVisible(false);
addTargets(target);
}
});
cancelButton.setVisible(false);
resultForm.add(cancelButton);
cancelButton.setOutputMarkupId(true);
cancelButton.setOutputMarkupPlaceholderTag(true);
saveChangesButton = (new AjaxButton("saveChanges"){
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form){
if(bpmnProcessNameInputValue == null || bpmnProcessNameInputValue.isEmpty()){
bpmnProcessNameInputValue = fileNameWithoutExtension;
}
processModel.setName(bpmnProcessNameInputValue);
//TODO: geƤndertes Modell einlesen
processModel.save();
process.save();
}
});
saveChangesButton.setVisible(false);
saveChangesButton.setEnabled(false);
resultForm.add(saveChangesButton);
saveChangesButton.setOutputMarkupId(true);
saveChangesButton.setOutputMarkupPlaceholderTag(true);
deleteModelButton = (new AjaxButton("deleteModel"){
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit(AjaxRequestTarget target, Form<?> form){
if(process.getBpmnProcess() != null){
process.getBpmnProcess().remove();
}
abstractSushiPage.getFeedbackPanel().error("No process model exists!");
processModelProvider.setProcessModel(null);
deleteModelButton.setVisible(false);
saveChangesButton.setVisible(false);
addTargets(target);
}
});
deleteModelButton.setVisible(false);
resultForm.add(deleteModelButton);
deleteModelButton.setOutputMarkupId(true);
deleteModelButton.setOutputMarkupPlaceholderTag(true);
}
private void addUploadForm() {
uploadForm = new WarnOnExitForm("uploadForm"){
private static final long serialVersionUID = 1L;
@Override
protected void onSubmit() {
final FileUpload uploadedFile = fileUpload.getFileUpload();
if (uploadedFile != null) {
String uploadFolder;
if (System.getProperty("os.name").contains("Windows")) {
uploadFolder = "C:\\temp\\";
}
else {
File _uploadFolder = new File(signavioCoreWorkspace);
_uploadFolder.mkdirs();
try {
uploadFolder = _uploadFolder.getCanonicalPath();
} catch (IOException e) {
uploadFolder = "/tmp/";
e.printStackTrace();
}
}
String fileName = uploadedFile.getClientFileName();
File newFile = new File(uploadFolder + fileName);
if (newFile.exists()) {
newFile.delete();
}
try {
newFile.createNewFile();
uploadedFile.writeTo(newFile);
// info("Saved file: " + fileName);
} catch (IOException e) {
throw new IllegalStateException("Error: File could not be saved.");
}
int index = fileName.lastIndexOf('.');
fileNameWithoutExtension = fileName.substring(0,index);
String fileExtension = fileName.substring(index + 1, fileName.length());
if(fileExtension.toLowerCase().contains("xml") || fileExtension.toLowerCase().contains("bpmn")){
processModel = BPMNParser.generateProcessFromXML(newFile.getAbsolutePath());
BPM2XMLToSignavioXMLConverter signavioConverter = new BPM2XMLToSignavioXMLConverter(newFile.getAbsolutePath());
// String newFileName = signavioConverter.generateSignavioXMLFromBPM2XML();
processModelProvider.setProcessModel(processModel);
cancelButton.setVisible(true);
saveModelButton.setVisible(true);
deleteModelButton.setVisible(false);
saveChangesButton.setVisible(false);
// externalPage.setURL(pathToCoreComponents + newFileName);
} else {
System.out.println("no xml");
}
uploadButton.setEnabled(false);
} else {
error("File not found");
}
if(simulationPanel != null){
simulationPanel.updateMonitoringPoints(null);
}
}
};
uploadForm.add(fileUpload = new FileUploadField("fileUpload"));
uploadForm.setMultiPart(true);
fileUpload.setOutputMarkupId(true);
fileUpload.setEnabled(false);
add(uploadForm);
uploadButton = new Button("upload");
uploadButton.setEnabled(false);
uploadButton.setOutputMarkupId(true);
uploadForm.add(uploadButton);
bpmnProcessNameInput = new TextField<String>("bpmnProcessNameInput", new PropertyModel(this,"bpmnProcessNameInputValue"));
bpmnProcessNameInput.setOutputMarkupId(true);
bpmnProcessNameInput.add(new OnChangeAjaxBehavior(){
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(final AjaxRequestTarget target){
bpmnProcessNameInputValue = ((TextField<String>) getComponent()).getModelObject();
}
});
uploadForm.add(bpmnProcessNameInput);
}
private void addProcessSelect(Form<Void> layoutForm) {
processNameList = new ArrayList<String>();
for (SushiProcess process : SushiProcess.findAll()) {
processNameList.add(process.getName());
}
processSelect = new DropDownChoice<String>("processSelect", new Model<String>(), processNameList);
processSelect.setOutputMarkupId(true);
processSelect.add(new AjaxFormComponentUpdatingBehavior("onchange") {
private static final long serialVersionUID = 1L;
@Override
protected void onUpdate(AjaxRequestTarget target) {
fileUpload.setEnabled(true);
uploadButton.setEnabled(true);
process = SushiProcess.findByName(processSelect.getChoices().get(Integer.parseInt(processSelect.getValue()))).get(0);
processModel = process.getBpmnProcess();
processModelProvider.setProcessModel(processModel);
if (processModel != null){
deleteModelButton.setVisible(true);
saveChangesButton.setVisible(true);
bpmnProcessNameInputValue = processModel.getName();
if(simulationPanel != null){
simulationPanel.updateMonitoringPoints(target);
}
}
addTargets(target);
}
});
layoutForm.add(processSelect);
}
@SuppressWarnings("unchecked")
private Component addProcessModelTable() {
columns = new ArrayList<IColumn<AbstractBPMNElement, String>>();
columns.add(new AbstractColumn<AbstractBPMNElement, String>(new Model("Element")) {
@Override
public void populateItem(Item cellItem, String componentId, IModel rowModel) {
String elementName = ((AbstractBPMNElement) rowModel.getObject()).toString();
cellItem.add(new Label(componentId, elementName));
}
});
columns.add(new PropertyColumn<AbstractBPMNElement, String>(Model.of("Predecessors"), "predecessors"));
columns.add(new PropertyColumn<AbstractBPMNElement, String>(Model.of("Successors"), "successors"));
columns.add(new PropertyColumn<AbstractBPMNElement, String>(Model.of("Monitoring Points"), "monitoringPoints"));
processModelTable = new DefaultDataTable<AbstractBPMNElement, String>("processModelElements", columns, processModelProvider, 40);
processModelTable.setOutputMarkupId(true);
processModelTable.setOutputMarkupPlaceholderTag(true);
return processModelTable;
}
private void createProcessEditModalWindow(Form<Void> layoutForm){
processEditorModal = new ProcessEditorModal("processEditorModal", processSelect);
add(processEditorModal);
layoutForm.add(new AjaxLink<Void>("showProcessEditModal"){
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target){
processEditorModal.show(target);
}
});
}
public String getSelectedProcessName() {
return processSelect.getModelObject();
}
public SushiProcess getProcess() {
return process;
}
public BPMNProcess getProcessModel() {
return processModel;
}
public void setSimulationPanel(BPMNSimulationPanel simulationPanel){
this.simulationPanel = simulationPanel;
targets.add(simulationPanel.getMonitoringPointTable());
}
private void addTargets(AjaxRequestTarget target) {
for(Component targetComponent : targets){
target.add(targetComponent);
}
}
/**
* Searches for BPMN processes with the same, but a different containing process.
* @param process
* @param bpmnProcessName
* @return
*/
private boolean containsOtherProcessSameBPMNProcessName(SushiProcess process, String bpmnProcessName) {
List<BPMNProcess> bpmnProcesses = BPMNProcess.findByName(bpmnProcessName);
for(BPMNProcess bpmnProcess : bpmnProcesses){
if(!SushiProcess.findByBPMNProcess(bpmnProcess).equals(process)){
return true;
}
}
return false;
}
}