package sushi.application.pages.correlation;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.form.AjaxFormChoiceComponentUpdatingBehavior;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.extensions.markup.html.tabs.AbstractTab;
import org.apache.wicket.extensions.markup.html.tabs.ITab;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.RadioChoice;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
import sushi.application.components.form.BlockingAjaxButton;
import sushi.application.components.form.WarnOnExitForm;
import sushi.application.pages.AbstractSushiPage;
import sushi.application.pages.process.modal.ProcessEditorModal;
import sushi.correlation.AttributeCorrelator;
import sushi.correlation.CorrelationRule;
import sushi.correlation.RuleCorrelator;
import sushi.event.SushiEventType;
import sushi.event.attribute.SushiAttribute;
import sushi.process.SushiProcess;
import sushi.process.SushiProcessInstance;
import de.agilecoders.wicket.markup.html.bootstrap.tabs.Collapsible;
@SuppressWarnings("serial")
public class CorrelationPage extends AbstractSushiPage {
private SimpleCorrelationPanel simpleCorrelationPanel;
private SimpleCorrelationWithRulesPanel simpleCorrelationWithRulesPanel;
private boolean simpleCorrelationWithRules = false;
private AdvancedCorrelationPanel advancedCorrelationPanel;
private final DropDownChoice<String> processSelect;
private ProcessEditorModal processEditorModal;
private ArrayList<String> processNameList;
private ExistingCorrelationAlert existingCorrelationAlert;
private CorrelationPage correlationPage;
protected ArrayList<SushiAttribute> commonCorrelationAttributes = new ArrayList<SushiAttribute>();
private Form<Void> layoutForm;
public CorrelationPage() {
super();
this.correlationPage = this;
processNameList = new ArrayList<String>();
for (SushiProcess process : SushiProcess.findAll()) {
processNameList.add(process.getName());
}
layoutForm = new WarnOnExitForm("layoutForm");
add(layoutForm);
processSelect = new DropDownChoice<String>("processSelect", new Model<String>(), processNameList);
processSelect.setOutputMarkupId(true);
layoutForm.add(processSelect);
final RadioChoice<String> simpleCorrelationWithRulesRadioChoice = new RadioChoice<String>("simpleCorrelationWithRulesRadioChoice", new Model<String>(), Arrays.asList("same-name attributes", "correlation rules"));
simpleCorrelationWithRulesRadioChoice.add(new AjaxFormChoiceComponentUpdatingBehavior() {
@Override
protected void onUpdate(AjaxRequestTarget target) {
simpleCorrelationWithRules = simpleCorrelationWithRulesRadioChoice.getModelObject().equals("correlation rules");
updateSimpleCorrelationPanelComponents(target);
updateSimpleCorrelationWithRulesPanelComponents(target);
}
});
simpleCorrelationWithRulesRadioChoice.setModelObject("same-name attributes");
layoutForm.add(simpleCorrelationWithRulesRadioChoice);
addApplyButton(layoutForm);
addCorrelationTabs();
addProcessEditorModal();
existingCorrelationAlert = new ExistingCorrelationAlert("warning", "Correlation exists! Do you want to override it?", this);
existingCorrelationAlert.setVisible(false);
existingCorrelationAlert.setOutputMarkupId(true);
existingCorrelationAlert.setOutputMarkupPlaceholderTag(true);
add(existingCorrelationAlert);
}
private void addProcessEditorModal() {
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);
}
});
}
private void addApplyButton(Form<Void> layoutForm) {
BlockingAjaxButton applyButton = new BlockingAjaxButton("applyButton", layoutForm) {
private static final long serialVersionUID = 1L;
@Override
public void onSubmit(AjaxRequestTarget target, Form<?> form) {
super.onSubmit(target, form);
if ((simpleCorrelationWithRules && isSimpleCorrelationWithRulesPanelFilled()) || (!simpleCorrelationWithRules && isSimpleCorrelationPanelFilled())
&& isAdvancedCorrelationPanelFilled()) {
addEventTypesToProcessAndCorrelate(target);
}
target.add(correlationPage.getFeedbackPanel());
}
};
layoutForm.add(applyButton);
}
private boolean isSimpleCorrelationPanelFilled() {
if (processSelect.getValue().isEmpty()) {
correlationPage.getFeedbackPanel().error("No process selected!");
correlationPage.getFeedbackPanel().setVisible(true);
return false;
}
if (simpleCorrelationPanel.getCorrelationEventTypes().isEmpty()) {
correlationPage.getFeedbackPanel().error("No event types for correlation selected!");
correlationPage.getFeedbackPanel().setVisible(true);
return false;
}
if (simpleCorrelationPanel.getSelectedCorrelationAttributes().isEmpty()) {
correlationPage.getFeedbackPanel().error("No correlation attributes selected!");
correlationPage.getFeedbackPanel().setVisible(true);
return false;
}
return true;
}
private boolean isSimpleCorrelationWithRulesPanelFilled() {
if (processSelect.getValue().isEmpty()) {
correlationPage.getFeedbackPanel().error("No process selected!");
correlationPage.getFeedbackPanel().setVisible(true);
return false;
}
if (simpleCorrelationWithRulesPanel.getCorrelationRules().isEmpty()) {
correlationPage.getFeedbackPanel().error("No correlation rules provided!");
correlationPage.getFeedbackPanel().setVisible(true);
return false;
} else {
for (CorrelationRule correlationRule : simpleCorrelationWithRulesPanel.getCorrelationRules()) {
if (correlationRule.getFirstAttribute() == null || correlationRule.getSecondAttribute() == null) {
correlationPage.getFeedbackPanel().error("Some of the correlation rules are missing attributes!");
correlationPage.getFeedbackPanel().setVisible(true);
return false;
}
}
}
return true;
}
private boolean isAdvancedCorrelationPanelFilled() {
if (advancedCorrelationPanel.isTimeCorrelationSelected()) {
if (advancedCorrelationPanel.getTimeCondition().getSelectedEventType() == null) {
correlationPage.getFeedbackPanel().error("No event type for time correlation selected!");
correlationPage.getFeedbackPanel().setVisible(true);
return false;
}
if (advancedCorrelationPanel.getTimeCondition().getTimePeriod() == 0) {
correlationPage.getFeedbackPanel().error("No minutes for time correlation inserted!");
correlationPage.getFeedbackPanel().setVisible(true);
return false;
}
if (advancedCorrelationPanel.getTimeCondition().getConditionString().isEmpty()) {
correlationPage.getFeedbackPanel().error("No condition for time correlation inserted!");
correlationPage.getFeedbackPanel().setVisible(true);
return false;
}
if (advancedCorrelationPanel.getTimeCondition().getConditionString().startsWith("=") || advancedCorrelationPanel.getTimeCondition().getConditionString().endsWith("=")) {
correlationPage.getFeedbackPanel().error("Malformed condition for time correlation!");
correlationPage.getFeedbackPanel().setVisible(true);
return false;
}
}
return true;
}
public void clearAdvancedCorrelationPanelComponents() {
correlationPage.getAdvancedCorrelationPanel().getTimeCorrelationEventTypeSelect().setChoices(new ArrayList<SushiEventType>());
correlationPage.getAdvancedCorrelationPanel().getTimeCorrelationConditionAttributeSelect().setChoices(new ArrayList<String>());
correlationPage.getAdvancedCorrelationPanel().getTimeCorrelationConditionValueSelect().setChoices(new ArrayList<Serializable>());
}
public void updateAdvancedCorrelationPanelComponents(AjaxRequestTarget target) {
target.add(correlationPage.getAdvancedCorrelationPanel().getTimeCorrelationEventTypeSelect());
target.add(correlationPage.getAdvancedCorrelationPanel().getTimeCorrelationConditionAttributeSelect());
target.add(correlationPage.getAdvancedCorrelationPanel().getTimeCorrelationConditionValueSelect());
}
private void addCorrelationTabs() {
List<ITab> tabs = new ArrayList<ITab>();
tabs.add(new AbstractTab(new Model<String>("Simple correlation with same-name attributes")) {
public Panel getPanel(String panelId) {
simpleCorrelationPanel = new SimpleCorrelationPanel(panelId, correlationPage);
return simpleCorrelationPanel;
}
});
tabs.add(new AbstractTab(new Model<String>("Simple correlation with correlation rules")) {
public Panel getPanel(String panelId) {
simpleCorrelationWithRulesPanel = new SimpleCorrelationWithRulesPanel(panelId, correlationPage);
return simpleCorrelationWithRulesPanel;
}
});
tabs.add(new AbstractTab(new Model<String>("Advanced correlation")) {
public Panel getPanel(String panelId) {
advancedCorrelationPanel = new AdvancedCorrelationPanel(panelId);
return advancedCorrelationPanel;
}
});
layoutForm.add(new Collapsible("collapsible", tabs, Model.of(-1)));
}
private void addEventTypesToProcessAndCorrelate(AjaxRequestTarget target) {
SushiProcess selectedProcess = SushiProcess.findByName(processSelect.getChoices().get(Integer.parseInt(processSelect.getValue()))).get(0);
addEventTypesToSelectedProcess(selectedProcess);
tryToCorrelateEvents(selectedProcess, target);
}
private void addEventTypesToSelectedProcess(SushiProcess selectedProcess) {
if (simpleCorrelationWithRules) {
selectedProcess.setEventTypes(simpleCorrelationWithRulesPanel.getCorrelationEventTypes());
} else {
selectedProcess.setEventTypes(simpleCorrelationPanel.getCorrelationEventTypes());
}
selectedProcess.merge();
}
/**
* If correlation settings have been already determined for a process,
* the user is asked if the correlation settings shall be overwritten.
*/
private void tryToCorrelateEvents(SushiProcess selectedProcess, AjaxRequestTarget target){
if(SushiProcessInstance.findByProcess(selectedProcess).size() > 0){
showCorrelationExistsWarningModal(selectedProcess, target);
} else{
correlateEvents(selectedProcess);
}
}
private void showCorrelationExistsWarningModal(SushiProcess selectedProcess, AjaxRequestTarget target) {
existingCorrelationAlert.setVisible(true);
existingCorrelationAlert.setSelectedProcess(selectedProcess);
target.add(existingCorrelationAlert);
System.out.println("Correlate existing");
}
public void correlateEvents(SushiProcess selectedProcess) {
List<SushiAttribute> correlationAttributes = simpleCorrelationPanel.getSelectedCorrelationAttributes();
Set<CorrelationRule> correlationRules = new HashSet<CorrelationRule>(simpleCorrelationWithRulesPanel.getCorrelationRules());
if (simpleCorrelationWithRules) {
if (advancedCorrelationPanel.isTimeCorrelationSelected()) {
RuleCorrelator.correlate(correlationRules, selectedProcess, advancedCorrelationPanel.getTimeCondition());
} else {
RuleCorrelator.correlate(correlationRules, selectedProcess, null);
}
} else {
if (advancedCorrelationPanel.isTimeCorrelationSelected()) {
AttributeCorrelator.correlate(selectedProcess.getEventTypes(), correlationAttributes, selectedProcess, advancedCorrelationPanel.getTimeCondition());
} else {
AttributeCorrelator.correlate(selectedProcess.getEventTypes(), correlationAttributes, selectedProcess, null);
}
}
correlationPage.getFeedbackPanel().success("Correlation finished! " + SushiProcessInstance.findByProcess(selectedProcess).size() + " process instances created!");
correlationPage.getFeedbackPanel().setVisible(true);
}
public DropDownChoice<String> getProcessSelect() {
return processSelect;
}
public void addProcessToProcessNameList(String processName){
this.processNameList.add(processName);
}
public void removeProcessFromProcessNameList(String processName){
this.processNameList.remove(processName);
}
public ExistingCorrelationAlert getAlert() {
return existingCorrelationAlert;
}
public SimpleCorrelationPanel getSimpleCorrelationPanel() {
return simpleCorrelationPanel;
}
public SimpleCorrelationWithRulesPanel getSimpleCorrelationWithRulesPanel() {
return simpleCorrelationWithRulesPanel;
}
public AdvancedCorrelationPanel getAdvancedCorrelationPanel() {
return advancedCorrelationPanel;
}
protected void updateSimpleCorrelationPanelComponents(AjaxRequestTarget target) {
target.add(simpleCorrelationPanel.getCorrelationAttributesSelect());
target.add(simpleCorrelationPanel.getEventTypesCheckBoxMultipleChoice());
}
protected void updateSimpleCorrelationWithRulesPanelComponents(AjaxRequestTarget target) {
target.add(simpleCorrelationWithRulesPanel.getAddCorrelationRuleButton());
target.add(simpleCorrelationWithRulesPanel.getCorrelationRuleMarkupContainer());
}
public void setValuesOfAdvancedCorrelationPanelComponents(ArrayList<SushiEventType> eventTypes) {
correlationPage.getAdvancedCorrelationPanel().getTimeCorrelationEventTypeSelect().setChoices(eventTypes);
if (eventTypes.isEmpty()) {
correlationPage.getAdvancedCorrelationPanel().getTimeCorrelationConditionAttributeSelect().setChoices(new ArrayList<String>());
correlationPage.getAdvancedCorrelationPanel().getTimeCorrelationConditionValueSelect().setChoices(new ArrayList<Serializable>());
} else {
correlationPage.getAdvancedCorrelationPanel().getTimeCorrelationConditionAttributeSelect().setChoices(eventTypes.get(0).getAttributeExpressions());
correlationPage.getAdvancedCorrelationPanel().getTimeCorrelationConditionValueSelect().setChoices(eventTypes.get(0).findAttributeValues(eventTypes.get(0).getValueTypes().get(0).getAttributeExpression()));
}
}
public boolean isSimpleCorrelationWithRules() {
return simpleCorrelationWithRules;
}
}