package pl.net.bluesoft.rnd.pt.ext.bpmnotifications.portlet.components; import com.vaadin.ui.*; import org.hibernate.Hibernate; import pl.net.bluesoft.rnd.processtool.model.config.ProcessDefinitionConfig; import pl.net.bluesoft.rnd.processtool.model.config.ProcessStateAction; import pl.net.bluesoft.rnd.processtool.model.config.ProcessStateConfiguration; import pl.net.bluesoft.rnd.processtool.plugins.ProcessToolRegistry; import pl.net.bluesoft.rnd.pt.ext.bpmnotifications.dao.BpmNotificationConfigDAO; import pl.net.bluesoft.rnd.pt.ext.bpmnotifications.dao.BpmNotificationMailPropertiesDAO; import pl.net.bluesoft.rnd.pt.ext.bpmnotifications.dao.BpmNotificationTemplateDAO; import pl.net.bluesoft.rnd.pt.ext.bpmnotifications.model.BpmNotificationConfig; import pl.net.bluesoft.rnd.pt.ext.bpmnotifications.model.BpmNotificationMailProperties; import pl.net.bluesoft.rnd.pt.ext.bpmnotifications.model.BpmNotificationTemplate; import pl.net.bluesoft.rnd.pt.ext.bpmnotifications.service.TemplateArgumentProvider; import pl.net.bluesoft.rnd.util.i18n.I18NSource; import pl.net.bluesoft.util.lang.Pair; import pl.net.bluesoft.util.lang.Tuple; import pl.net.bluesoft.util.lang.cquery.func.F; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import static pl.net.bluesoft.rnd.processtool.ProcessToolContext.Util.getThreadProcessToolContext; import static pl.net.bluesoft.util.lang.Strings.hasText; import static pl.net.bluesoft.util.lang.cquery.CQuery.from; /** * User: POlszewski * Date: 2012-10-12 * Time: 21:23 */ public class NotificationPanel extends ItemEditorLayout<BpmNotificationConfig> { private Select profileName; private Select templateName; private Select templateArgumentProvider; private CheckBox active; private CheckBox sendHtml; private TextField localeField; private TextField processTypeRegex; private TextField stateRegex; private TextField lastActionRegex; private CheckBox notifyOnProcessStart; private CheckBox notifyOnProcessEnd; private CheckBox onEnteringStep; private CheckBox skipNotificationWhenTriggeredByAssignee; private CheckBox notifyTaskAssignee; private TextField notifyEmailAddresses; private TextField notifyUserAttributes; private Button selectProcess; private Button selectState; private Button selectAction; private List<BpmNotificationMailProperties> mailProperties; private List<BpmNotificationTemplate> mailTemplates; private Collection<ProcessDefinitionConfig> processDefinitions; private Collection<TemplateArgumentProvider> templateArgumentProviders; public NotificationPanel(I18NSource i18NSource, ProcessToolRegistry registry) { super(BpmNotificationConfig.class, i18NSource, registry); buildLayout(); } @Override protected Component createItemDetailsLayout() { FormLayout formLayout = new FormLayout(); formLayout.addComponent(profileName = select(getMessage("bpmnot.profile"), 400)); formLayout.addComponent(templateName = select(getMessage("bpmnot.template"), 400)); formLayout.addComponent(templateArgumentProvider = select(getMessage("bpmnot.param.provider"), 400)); formLayout.addComponent(active = checkBox(getMessage("bpmnot.active"))); formLayout.addComponent(sendHtml = checkBox(getMessage("bpmnot.send.as.html"))); formLayout.addComponent(localeField = textField(getMessage("bpmnot.locale"))); processTypeRegex = textField(null, 400); stateRegex = textField(null, 400); lastActionRegex = textField(null, 400); selectProcess = new Button(getMessage("bpmnot.button.choose")); selectState = new Button(getMessage("bpmnot.button.choose")); selectAction = new Button(getMessage("bpmnot.button.choose")); selectProcess.addListener((Button.ClickListener)this); selectState.addListener((Button.ClickListener)this); selectAction.addListener((Button.ClickListener)this); formLayout.addComponent(hl(getMessage("bpmnot.process"), processTypeRegex, selectProcess)); formLayout.addComponent(hl(getMessage("bpmnot.state"), stateRegex, selectState)); formLayout.addComponent(hl(getMessage("bpmnot.last.action"), lastActionRegex, selectAction)); formLayout.addComponent(notifyOnProcessStart = checkBox(getMessage("bpmnot.send.on.process.start"))); formLayout.addComponent(notifyOnProcessEnd = checkBox(getMessage("bpmnot.send.on.process.end"))); formLayout.addComponent(onEnteringStep = checkBox(getMessage("bpmnot.send.on.entering.step"))); formLayout.addComponent(skipNotificationWhenTriggeredByAssignee = checkBox(getMessage("bpmnot.skip.when.triggered.by.assignee"))); formLayout.addComponent(notifyTaskAssignee = checkBox(getMessage("bpmnot.notify.assignee"))); formLayout.addComponent(notifyEmailAddresses = textField(getMessage("bpmnot.notify.emails"), 400)); formLayout.addComponent(notifyUserAttributes = textField(getMessage("bpmnot.notify.users"), 400)); formLayout.addComponent(new Label( getMessage("bpmnot.attribute.explanation"), Label.CONTENT_XHTML)); return formLayout; } @Override protected void clearDetails() { profileName.setValue(null); templateName.setValue(null); templateArgumentProvider.setValue(null); active.setValue(null); sendHtml.setValue(null); localeField.setValue(null); processTypeRegex.setValue(null); stateRegex.setValue(null); lastActionRegex.setValue(null); notifyOnProcessStart.setValue(null); notifyOnProcessEnd.setValue(null); onEnteringStep.setValue(null); skipNotificationWhenTriggeredByAssignee.setValue(null); notifyTaskAssignee.setValue(null); notifyEmailAddresses.setValue(null); notifyUserAttributes.setValue(null); } @Override protected void loadDetails(BpmNotificationConfig item) { profileName.setValue(item.getProfileName()); templateName.setValue(item.getTemplateName()); templateArgumentProvider.setValue(item.getTemplateArgumentProvider()); active.setValue(item.isActive()); sendHtml.setValue(item.isSendHtml()); localeField.setValue(item.getLocale()); processTypeRegex.setValue(item.getProcessTypeRegex()); stateRegex.setValue(item.getStateRegex()); lastActionRegex.setValue(item.getLastActionRegex()); notifyOnProcessStart.setValue(item.isNotifyOnProcessStart()); notifyOnProcessEnd.setValue(item.isNotifyOnProcessEnd()); onEnteringStep.setValue(item.isOnEnteringStep()); skipNotificationWhenTriggeredByAssignee.setValue(item.isSkipNotificationWhenTriggeredByAssignee()); notifyTaskAssignee.setValue(item.isNotifyTaskAssignee()); notifyEmailAddresses.setValue(item.getNotifyEmailAddresses()); notifyUserAttributes.setValue(item.getNotifyUserAttributes()); } @Override protected void saveDetails(BpmNotificationConfig item) { item.setProfileName(getString(profileName)); item.setTemplateName(getString(templateName)); item.setTemplateArgumentProvider(getString(templateArgumentProvider)); item.setActive(getBoolean(active)); item.setSendHtml(getBoolean(sendHtml)); item.setLocale(getString(localeField)); item.setProcessTypeRegex(getString(processTypeRegex)); item.setStateRegex(getString(stateRegex)); item.setLastActionRegex(getString(lastActionRegex)); item.setNotifyOnProcessStart(getBoolean(notifyOnProcessStart)); item.setNotifyOnProcessEnd(getBoolean(notifyOnProcessEnd)); item.setOnEnteringStep(getBoolean(onEnteringStep)); item.setSkipNotificationWhenTriggeredByAssignee(getBoolean(skipNotificationWhenTriggeredByAssignee)); item.setNotifyTaskAssignee(getBoolean(notifyTaskAssignee)); item.setNotifyEmailAddresses(getString(notifyEmailAddresses)); item.setNotifyUserAttributes(getString(notifyUserAttributes)); } @Override protected void prepareData() { mailProperties = new BpmNotificationMailPropertiesDAO().findAll(); mailTemplates = new BpmNotificationTemplateDAO().findAll(); processDefinitions = getThreadProcessToolContext() .getProcessDefinitionDAO().getActiveConfigurations(); for (ProcessDefinitionConfig processDefinition : processDefinitions) { for (ProcessStateConfiguration processStateConfiguration : processDefinition.getStates()) { Hibernate.initialize(processStateConfiguration.getActions()); } } templateArgumentProviders = getService().getTemplateArgumentProviders(); bindValues(profileName, from(mailProperties).select(new F<BpmNotificationMailProperties, String>() { @Override public String invoke(BpmNotificationMailProperties x) { return x.getProfileName(); } }).ordered().toList()); bindValues(templateName, from(mailTemplates).select(new F<BpmNotificationTemplate, String>() { @Override public String invoke(BpmNotificationTemplate x) { return x.getTemplateName(); } })); bindValues(templateArgumentProvider, from(templateArgumentProviders).select(new F<TemplateArgumentProvider, String>() { @Override public String invoke(TemplateArgumentProvider x) { return x.getName(); } })); } @Override protected List<BpmNotificationConfig> getAllItems() { return new BpmNotificationConfigDAO().findAll(); } @Override protected String getItemCaption(BpmNotificationConfig item) { return item.getTemplateName() + " (" + item.getId() + ")"; } @Override protected BpmNotificationConfig createItem() { BpmNotificationConfig item = new BpmNotificationConfig(); item.setActive(true); item.setLocale(I18NSource.ThreadUtil.getThreadI18nSource().getLocale().toString()); if (mailProperties.size() == 1) { item.setProfileName(mailProperties.get(0).getProfileName()); } return item; } @Override protected BpmNotificationConfig refreshItem(Long id) { return new BpmNotificationConfigDAO().loadById(id); } @Override protected void saveItem(BpmNotificationConfig item) { new BpmNotificationConfigDAO().saveOrUpdate(item); } @Override public void buttonClick(Button.ClickEvent event) { if (event.getSource() == selectProcess) { selectProcesses(); } else if (event.getSource() == selectState) { selectStates(); } else if (event.getSource() == selectAction) { selectActions(); } else { super.buttonClick(event); } } private void selectProcesses() { SelectValuesDialog<String> dialog = new SelectValuesDialog<String>(String.class, getMessage("bpmnot.pick.processes"), getI18NSource()) { @Override protected void valuesSelected(Set<String> items) { processTypeRegex.setValue(listToRegex(items)); } }; List<Pair<String, String>> items = new ArrayList<Pair<String, String>>(); for (ProcessDefinitionConfig processDefinition : processDefinitions) { items.add(new Pair<String, String>( getMessage(processDefinition.getDescription()), processDefinition.getProcessName() )); } items = orderByFirst(items); dialog.setAvailableItems(items); dialog.setItems(from(getCurrentlySelectedProcesses()).select(new F<ProcessDefinitionConfig, String>() { @Override public String invoke(ProcessDefinitionConfig x) { return x.getProcessName(); } }).toSet()); dialog.show(getApplication()); } private Collection<ProcessDefinitionConfig> getCurrentlySelectedProcesses() { List<ProcessDefinitionConfig> selectedDefinitions = new ArrayList<ProcessDefinitionConfig>(); for (ProcessDefinitionConfig processDefinition : processDefinitions) { if (hasMatchingProcessName(getString(processTypeRegex), processDefinition.getProcessName())) { selectedDefinitions.add(processDefinition); } } return selectedDefinitions; } private boolean hasMatchingProcessName(String processTypeRegex, String definitionName) { return !(hasText(processTypeRegex) && !definitionName.toLowerCase().matches(processTypeRegex.toLowerCase())); } private void selectStates() { SelectValuesDialog<Tuple> dialog = new SelectValuesDialog<Tuple>(Tuple.class, getMessage("bpmnot.pick.states"), getI18NSource()) { @Override protected void valuesSelected(Set<Tuple> items) { stateRegex.setValue(listToRegex(items, 1)); } }; List<Pair<String, Tuple>> items = new ArrayList<Pair<String, Tuple>>(); Collection<ProcessDefinitionConfig> currentlySelectedProcesses = getCurrentlySelectedProcesses(); for (ProcessDefinitionConfig processDefinition : currentlySelectedProcesses) { for (ProcessStateConfiguration state : processDefinition.getStates()) { String descr; if (currentlySelectedProcesses.size() == 1) { descr = getMessage(state.getDescription()); descr.length(); if(descr.isEmpty()){ descr = state.getName(); } } else { descr = getMessage(processDefinition.getDescription()) + " > " + getMessage(state.getDescription()); if(getMessage(state.getDescription()).isEmpty()){ descr = state.getName(); } } items.add(new Pair<String, Tuple>( descr, new Tuple(processDefinition.getProcessName(), state.getName()) )); } } items = orderByFirst(items); dialog.setAvailableItems(items); dialog.setItems(from(getCurrentlySelectedStates()).select(new F<ProcessStateConfiguration, Tuple>() { @Override public Tuple invoke(ProcessStateConfiguration x) { return new Tuple(x.getDefinition().getProcessName(), x.getName()); } }).toSet()); dialog.show(getApplication()); } private Collection<ProcessStateConfiguration> getCurrentlySelectedStates() { List<ProcessStateConfiguration> states = new ArrayList<ProcessStateConfiguration>(); for (ProcessDefinitionConfig processDefinition : getCurrentlySelectedProcesses()) { for (ProcessStateConfiguration state : processDefinition.getStates()) { if (hasMatchingStateName(getString(stateRegex), state.getName())) { states.add(state); } } } return states; } private boolean hasMatchingStateName(String stateRegex, String stateName) { return !hasText(stateRegex) || (stateName != null && stateName.toLowerCase().matches(stateRegex.toLowerCase())); } private void selectActions() { SelectValuesDialog<Tuple> dialog = new SelectValuesDialog<Tuple>(Tuple.class, getMessage("bpmnot.pick.actions"), getI18NSource()) { @Override protected void valuesSelected(Set<Tuple> items) { lastActionRegex.setValue(listToRegex(items, 1)); } }; List<Pair<String, Tuple>> items = new ArrayList<Pair<String, Tuple>>(); Collection<ProcessDefinitionConfig> currentlySelectedProcesses = getCurrentlySelectedProcesses(); Collection<ProcessStateConfiguration> currentlySelectedStates = getCurrentlySelectedStates(); for (ProcessStateConfiguration state : currentlySelectedStates) { for (ProcessStateAction action : state.getActions()) { String descr; if (currentlySelectedProcesses.size() > 1) { descr = getMessage(state.getDefinition().getDescription()) + " > " + getMessage(state.getDescription()) + " > " + getMessage(action.getLabel()); } else if (currentlySelectedStates.size() > 1) { descr = getMessage(state.getDescription()) + " > " + getMessage(action.getLabel()); } else { descr = getMessage(action.getLabel()); } items.add(new Pair<String, Tuple>( descr, new Tuple(state.getDefinition().getProcessName(), state.getName(), action.getBpmName()) )); } } items = orderByFirst(items); dialog.setAvailableItems(items); dialog.setItems(from(getCurrentlySelectedActions()).select(new F<ProcessStateAction, Tuple>() { @Override public Tuple invoke(ProcessStateAction x) { return new Tuple(x.getConfig().getDefinition().getProcessName(), x.getConfig().getName(), x.getBpmName()); } }).toSet()); dialog.show(getApplication()); } private Collection<ProcessStateAction> getCurrentlySelectedActions() { List<ProcessStateAction> actions = new ArrayList<ProcessStateAction>(); for (ProcessStateConfiguration state : getCurrentlySelectedStates()) { for (ProcessStateAction action : state.getActions()) { if (hasMatchingActionName(getString(lastActionRegex), action.getBpmName())) { actions.add(action); } } } return actions; } private boolean hasMatchingActionName(String actionRegex, String actionBpmName) { if (hasText(actionRegex)) { if (actionBpmName == null || !actionBpmName.toLowerCase().matches(actionRegex.toLowerCase())) { return false; } } return true; } private <T1 extends Comparable<T1>, T2> List<Pair<T1, T2>> orderByFirst(List<Pair<T1, T2>> items) { return from(items).orderBy(new F<Pair<T1, T2>, Comparable>() { @Override public T1 invoke(Pair<T1, T2> x) { return x.getFirst(); } }).toList(); } private String listToRegex(Set<String> items) { return items.isEmpty() ? null : from(items).distinct().ordered().toString("|"); } private String listToRegex(Set<Tuple> items, final int idx) { return items.isEmpty() ? null : from(items).select(new F<Tuple, String>() { @Override public String invoke(Tuple x) { return (String)x.getParts()[idx]; } }).distinct().ordered().toString("|"); } }