/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo 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 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.foundation.wkf.node; import java.awt.Color; import java.util.Date; import java.util.Enumeration; import java.util.List; import java.util.NoSuchElementException; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.foundation.CodeType; import org.openflexo.foundation.DataModification; import org.openflexo.foundation.FlexoObservable; import org.openflexo.foundation.FlexoObserver; import org.openflexo.foundation.Inspectors; import org.openflexo.foundation.NameChanged; import org.openflexo.foundation.TargetType; import org.openflexo.foundation.action.FlexoActionizer; import org.openflexo.foundation.bindings.ComponentBindingDefinition; import org.openflexo.foundation.help.ApplicationHelpEntryPoint; import org.openflexo.foundation.ie.ComponentInstance; import org.openflexo.foundation.ie.ComponentInstanceBinding; import org.openflexo.foundation.ie.ComponentInstanceOwner; import org.openflexo.foundation.ie.IEWOComponent; import org.openflexo.foundation.ie.OperationComponentInstance; import org.openflexo.foundation.ie.TabComponentInstance; import org.openflexo.foundation.ie.cl.ComponentDefinition; import org.openflexo.foundation.ie.cl.FlexoComponentFolder; import org.openflexo.foundation.ie.cl.OperationComponentDefinition; import org.openflexo.foundation.ie.cl.TabComponentDefinition; import org.openflexo.foundation.ie.util.FolderType; import org.openflexo.foundation.ie.util.HyperlinkType; import org.openflexo.foundation.ie.widget.IEHyperlinkWidget; import org.openflexo.foundation.ie.widget.IETabWidget; import org.openflexo.foundation.rm.DuplicateResourceException; import org.openflexo.foundation.stats.OperationStatistics; import org.openflexo.foundation.utils.FlexoCSS; import org.openflexo.foundation.utils.FlexoColor; import org.openflexo.foundation.utils.FlexoIndexManager; import org.openflexo.foundation.validation.DeletionFixProposal; import org.openflexo.foundation.validation.FixProposal; import org.openflexo.foundation.validation.ParameteredFixProposal; import org.openflexo.foundation.validation.ValidationError; import org.openflexo.foundation.validation.ValidationIssue; import org.openflexo.foundation.validation.ValidationRule; import org.openflexo.foundation.validation.ValidationWarning; import org.openflexo.foundation.wkf.ActionPetriGraph; import org.openflexo.foundation.wkf.FlexoLevel; import org.openflexo.foundation.wkf.FlexoProcess; import org.openflexo.foundation.wkf.MetricsValue; import org.openflexo.foundation.wkf.MetricsValue.MetricsValueOwner; import org.openflexo.foundation.wkf.MetricsValueAdded; import org.openflexo.foundation.wkf.MetricsValueRemoved; import org.openflexo.foundation.wkf.OperationPetriGraph; import org.openflexo.foundation.wkf.Status; import org.openflexo.foundation.wkf.WKFObject; import org.openflexo.foundation.wkf.action.AddOperationMetricsValue; import org.openflexo.foundation.wkf.action.DeleteMetricsValue; import org.openflexo.foundation.wkf.action.SetAndOpenOperationComponent; import org.openflexo.foundation.wkf.dm.ComponentTextColorChanged; import org.openflexo.foundation.wkf.dm.OperationComponentHasBeenRemoved; import org.openflexo.foundation.wkf.dm.OperationComponentHasBeenSet; import org.openflexo.foundation.wkf.dm.TabOperationComponentHasBeenRemoved; import org.openflexo.foundation.wkf.dm.TabOperationComponentHasBeenSet; import org.openflexo.foundation.wkf.dm.WKFAttributeDataModification; import org.openflexo.foundation.wkf.edge.FlexoPostCondition; import org.openflexo.foundation.wkf.edge.InvalidEdgeException; import org.openflexo.foundation.wkf.edge.TokenEdge; import org.openflexo.foundation.wkf.utils.OperationAssociatedWithComponentSuccessfully; import org.openflexo.foundation.xml.FlexoProcessBuilder; import org.openflexo.localization.FlexoLocalization; import org.openflexo.toolbox.EmptyVector; import org.openflexo.toolbox.ToolBox; /** * This represents a FlexoNode at the level 'Operation' * * @author sguerin * */ public class OperationNode extends FatherNode implements ApplicationHelpEntryPoint, ChildNode, ComponentInstanceOwner, Comparable<OperationNode>, MetricsValueOwner, FlexoObserver { private static final Logger logger = Logger.getLogger(OperationNode.class.getPackage().getName()); // protected String _woComponentName; // private OperationComponentDefinition _componentDefinition; private transient OperationComponentInstance _componentInstance; private transient TabComponentInstance _tabComponentInstance; protected transient Status _newStatus; private boolean _isSynchronized = false; private String _acronym; private FlexoCSS cssSheet; private transient OperationStatistics statistics; private Vector<MetricsValue> metricsValues; public static FlexoActionizer<AddOperationMetricsValue, OperationNode, WKFObject> addMetricsActionizer; public static FlexoActionizer<DeleteMetricsValue, MetricsValue, MetricsValue> deleteMetricsActionizer; /** * Constructor used during deserialization */ public OperationNode(FlexoProcessBuilder builder) { this(builder.process); initializeDeserialization(builder); } /** * Default constructor */ public OperationNode(FlexoProcess process) { super(process); metricsValues = new Vector<MetricsValue>(); // _petriGraph = new ActionPetriGraph(getProcess()); } @Override public void setProcess(FlexoProcess p) { FlexoProcess old = getProcess(); super.setProcess(p); if (old != null) { old.deleteObserver(this); } if (p != null) { p.addObserver(this); } if (_componentInstance != null) { _componentInstance.updateDependancies(old, p); } if (_tabComponentInstance != null) { _tabComponentInstance.updateDependancies(old, p); } } @Override public void update(FlexoObservable observable, DataModification dataModification) { if (observable instanceof FlexoProcess && (dataModification instanceof NameChanged || dataModification instanceof WKFAttributeDataModification && "businessDataType".equals(((WKFAttributeDataModification) dataModification).getAttributeName()))) { // Update // business // data // accessing // methods // on // screens updateProcessBusinessDataAccessingMethod(); } } public static String DEFAULT_OPERATION_NODE_NAME() { return FlexoLocalization.localizedForKey("operation_default_name"); } @Override public String getDefaultName() { if (isBeginNode() || isEndNode()) { return super.getDefaultName(); } else { return DEFAULT_OPERATION_NODE_NAME(); } } @Override public FlexoLevel getLevel() { return FlexoLevel.OPERATION; } @Override public OperationPetriGraph getParentPetriGraph() { return (OperationPetriGraph) super.getParentPetriGraph(); } @Override public String getInspectorName() { if (getNodeType() == NodeType.BEGIN) { return Inspectors.WKF.BEGIN_OPERATION_NODE_INSPECTOR; } else if (getNodeType() == NodeType.END) { return Inspectors.WKF.END_OPERATION_NODE_INSPECTOR; } else { return Inspectors.WKF.OPERATION_NODE_INSPECTOR; } } public boolean mightHaveActionPetriGraph() { return getNodeType() == NodeType.NORMAL; } @Override public boolean hasContainedPetriGraph() { return mightHaveActionPetriGraph() && super.hasContainedPetriGraph(); } public ActionPetriGraph getActionPetriGraph() { if (mightHaveActionPetriGraph()) { return (ActionPetriGraph) getContainedPetriGraph(); } else { return null; } } public void setActionPetriGraph(ActionPetriGraph aPetriGraph) { setContainedPetriGraph(aPetriGraph); } @Override public AbstractActivityNode getFather() { return getAbstractActivityNode(); } public boolean getIsSynchronized() { return _isSynchronized; } public void setIsSynchronized(boolean isSynchronized) { if (_isSynchronized != isSynchronized) { _isSynchronized = isSynchronized; setChanged(); notifyObservers(new WKFAttributeDataModification("isSynchronized", new Boolean(!_isSynchronized), new Boolean(_isSynchronized))); } } @Override public final void delete() { if (getComponentInstance() != null) { removeComponentInstance(); } if (getTabOperationComponentInstance() != null) { removeTabComponentInstance(); } // getParentPetriGraph().removeFromNodes(this); super.delete(); deleteObservers(); } // ========================================================================== // ========================== Embedding implementation ===================== // ========================================================================== /** * Return a Vector of all embedded WKFObjects * * @return a Vector of WKFObject instances */ @Override public Vector<WKFObject> getAllEmbeddedWKFObjects() { Vector<WKFObject> returned = super.getAllEmbeddedWKFObjects(); returned.addAll(getMetricsValues()); /* * if (getComponentDefinition() != null) { returned.addAll(getComponentDefinition().getAllEmbeddedWKFObjects()); } */ return returned; } /** * Returns all the action nodes embedded in this operation. This returns also action nodes embedded in LOOPOperator and * SelfExecutableNode. * * @return all the action nodes embedded in this operation. */ public Vector<ActionNode> getAllEmbeddedActionNodes() { if (getActionPetriGraph() != null) { return getActionPetriGraph().getAllEmbeddedActionNodes(); } return new Vector<ActionNode>(); } /** * Returns a sorted vector of all the Action nodes that are in the underlying action petrigraph and the ones embedded by LOOPOperator * and SelfExecutableNode. This is done recursively on all nodes. * * @return a sorted vector of all the action nodes embedded in the underlying action petri graph. */ public Vector<ActionNode> getAllEmbeddedSortedOperationNodes() { if (getActionPetriGraph() != null) { return getActionPetriGraph().getAllEmbeddedSortedActionNodes(); } return new Vector<ActionNode>(); } public Vector<ActionNode> getAllActionNodes() { if (getActionPetriGraph() != null) { return getActionPetriGraph().getAllActionNodes(); } return new Vector<ActionNode>(); } public ActionNode getActionNodeNamed(String name) { for (ActionNode node : getAllActionNodes()) { if (node.getName().equals(name)) { return node; } } return null; } public Enumeration<ActionNode> getSortedActionNodes() { disableObserving(); ActionNode[] o = FlexoIndexManager.sortArray(getAllActionNodes().toArray(new ActionNode[0])); enableObserving(); return ToolBox.getEnumeration(o); } public Vector<OperatorNode> getAllOperatorNodes() { // TODO: optimize me later !!! Vector<OperatorNode> returned = new Vector<OperatorNode>(); if (getActionPetriGraph() != null) { return getActionPetriGraph().getAllOperatorNodes(); } return returned; } public Vector<EventNode> getAllEventNodes() { // TODO: optimize me later !!! Vector<EventNode> returned = new Vector<EventNode>(); if (getActionPetriGraph() != null) { return getActionPetriGraph().getAllEventNodes(); } return returned; } public ActionNode getActionNamed(String flexoNodeName) { Enumeration en = getAllActionNodes().elements(); ActionNode temp = null; while (en.hasMoreElements()) { temp = (ActionNode) en.nextElement(); if (temp.getNodeName() != null && temp.getNodeName().equals(flexoNodeName)) { return temp; } } if (logger.isLoggable(Level.WARNING)) { logger.warning("Could not find Action Node named " + flexoNodeName); } return null; } @Override public String getFullyQualifiedName() { if (getFather() != null) { return getFather().getFullyQualifiedName() + "." + formattedString(getNodeName()); } else { return "NULL." + formattedString(getNodeName()); } } // ========================================================================== // =============================== OperationNode // ============================ // ========================================================================== public String getWOComponentName() { if (getOperationComponent() != null) { return getOperationComponent().getComponentName(); } return null; } public void setWOComponentName(String aComponentName) throws DuplicateResourceException, OperationAssociatedWithComponentSuccessfully { if (getWOComponentName() != null && getWOComponentName().equals(aComponentName)) { return; } if (_componentInstance == null && (aComponentName == null || aComponentName.trim().equals(""))) { return; } /* * ComponentDefinition foundComponent = getProject().getFlexoComponentLibrary().getComponentNamed(aComponentName); * OperationComponentDefinition newComponent = null; if (foundComponent instanceof OperationComponentDefinition) { newComponent = * (OperationComponentDefinition) foundComponent; } else if (foundComponent != null) { if (logger.isLoggable(Level.WARNING)) * logger.warning("Found a component named " + aComponentName + " but this is not an OperationComponent. Aborting."); throw new * DuplicateResourceException(aComponentName); } if (newComponent == null) { if (logger.isLoggable(Level.INFO)) * logger.info("Creating a new Component named:" + aComponentName); FlexoComponentFolder selectedFolder = * getProject().getFlexoComponentLibrary().getRootFolder(); newComponent = new OperationComponentDefinition(aComponentName, * getProject().getFlexoComponentLibrary(), selectedFolder, getProject()); } setOperationComponent(newComponent); */ logger.warning("This implementation is not correct: you should not use FlexoAction primitive from the model !"); // TODO: Please implement this better later // Used editor will be null SetAndOpenOperationComponent action = SetAndOpenOperationComponent.actionType.makeNewAction(this, null); action.setNewComponentName(aComponentName); action.doAction(); if (action.getThrownException() != null) { if (action.getThrownException() instanceof DuplicateResourceException) { throw (DuplicateResourceException) action.getThrownException(); } else if (action.getThrownException() instanceof OperationAssociatedWithComponentSuccessfully) { throw (OperationAssociatedWithComponentSuccessfully) action.getThrownException(); } } } public OperationComponentDefinition getOperationComponent() { if (_componentInstance != null) { return _componentInstance.getOperationComponentDefinition(); } return null; } public void setOperationComponent(OperationComponentDefinition aComponentDefinition) throws OperationAssociatedWithComponentSuccessfully { if (_componentInstance != null && _componentInstance.getOperationComponentDefinition() == aComponentDefinition) { return; } Enumeration en = getAllActionNodes().elements(); while (en.hasMoreElements()) { ActionNode a = (ActionNode) en.nextElement(); if (a.getAssociatedButtonWidget() != null) { a.delete(); } } if (_componentInstance != null && aComponentDefinition == null) { removeComponentInstance(); if (getProcess() != null) { getProcess().notifyOperationChange(this); } } if (aComponentDefinition != null) { setComponentInstance(new OperationComponentInstance(aComponentDefinition, this)); } } public OperationComponentInstance getComponentInstance() { return _componentInstance; } public void setComponentInstance(OperationComponentInstance componentInstance) throws OperationAssociatedWithComponentSuccessfully { componentInstance.setOperationNode(this); OperationComponentInstance old = _componentInstance; if (_componentInstance != null) { removeComponentInstance(); } if (componentInstance.getComponentDefinition() != null || isCreatedByCloning() && componentInstance.getComponentName() != null) { // If we are created by cloning, we won't have a project and therefore, the component definition has not been resolved yet _componentInstance = componentInstance; _componentInstance.setOperationNode(this); updateProcessBusinessDataAccessingMethod(); setChanged(); if (isCreatedByCloning()) { return; } OperationComponentHasBeenSet dm = new OperationComponentHasBeenSet("operationComponent", componentInstance.getComponentDefinition(), this); notifyObservers(dm); notifyBindingsChanged(); if (getProcess() != null) { getProcess().notifyOperationChange(this); } if (!isDeserializing() && !isCreatedByCloning()) { throw new OperationAssociatedWithComponentSuccessfully(dm, this, getOperationComponent(), old); } } else if (logger.isLoggable(Level.SEVERE)) { logger.severe("ComponentInstance does not have a component definition for component named " + componentInstance.getComponentName()); } } public void removeComponentInstance() { if (_tabComponentInstance != null) { removeTabComponentInstance(); } if (_componentInstance != null) { if (getComponentDefinition() != null) { // Remove generated method for accessing process business data on component boolean needRemove = true; for (OperationNode opNode : _componentInstance.getComponentDefinition().getAllOperationNodesLinkedToThisComponent()) { if (opNode != this && opNode.getProcess() == getProcess()) { needRemove = false; break; } } if (needRemove) { _componentInstance.getComponentDefinition().getComponentDMEntity().removeAccessingBusinessDataMethod(getProcess()); } // Remove generated method for accessing process business data on all tabs used in component for (ComponentDefinition compDef : getWOComponent().getAllTabComponents(new Vector<TabComponentDefinition>())) { needRemove = true; for (OperationNode opNode : compDef.getAllOperationNodesLinkedToThisComponent()) { if (opNode != this && opNode.getProcess() == getProcess()) { needRemove = false; break; } } if (needRemove) { compDef.getComponentDMEntity().removeAccessingBusinessDataMethod(getProcess()); } } } _componentInstance.delete(); } ComponentInstance oldComponentInstance = _componentInstance; _componentInstance = null; setChanged(); notifyObservers(new OperationComponentHasBeenRemoved("WOComponentName", oldComponentInstance != null ? oldComponentInstance.getComponentDefinition() : null, this)); notifyBindingsChanged(); } public void updateProcessBusinessDataAccessingMethod() { if (getOperationComponent() != null && getProcess().getFlexoID() > 0) { // Generate method for accessing process business data on component getOperationComponent().getComponentDMEntity().addOrUpdateAccessingBusinessDataMethod(getProcess()); // Generate method for accessing process business data on all tabs used in component for (ComponentDefinition compDef : getAvailableTabs()) { compDef.getComponentDMEntity().addOrUpdateAccessingBusinessDataMethod(getProcess()); } } } public Vector<TabComponentDefinition> getAvailableTabs() { if (getOperationComponent() == null || !getOperationComponent().getHasTabContainer()) { return EmptyVector.EMPTY_VECTOR(TabComponentDefinition.class); } Vector<TabComponentDefinition> v = new Vector<TabComponentDefinition>(); for (IETabWidget tbc : getOperationComponent().getWOComponent().getAllTabWidget()) { if (tbc.isShownInOperation(this)) { v.add(tbc.getTabComponentDefinition()); } } return v; } // TABS public String getTabComponentName() { if (getTabComponent() != null) { return getTabComponent().getComponentName(); } return null; } public void setTabComponentName(String aComponentName) throws DuplicateResourceException, OperationAssociatedWithComponentSuccessfully { if (getTabComponentName() != null && getTabComponentName().equals(aComponentName)) { return; } if (_tabComponentInstance == null && (aComponentName == null || aComponentName.trim().equals(""))) { return; } ComponentDefinition foundComponent = getProject().getFlexoComponentLibrary().getComponentNamed(aComponentName); TabComponentDefinition newComponent = null; if (foundComponent instanceof TabComponentDefinition) { newComponent = (TabComponentDefinition) foundComponent; } else if (foundComponent != null) { if (logger.isLoggable(Level.WARNING)) { logger.warning("Found a component named " + aComponentName + " but this is not a TabComponent. Aborting."); } throw new DuplicateResourceException(aComponentName); } if (newComponent == null) { if (logger.isLoggable(Level.INFO)) { logger.info("Creating a new Component named:" + aComponentName); } FlexoComponentFolder selectedFolder = getProject().getFlexoComponentLibrary().getRootFolder() .getFolderTyped(FolderType.TAB_FOLDER); newComponent = new TabComponentDefinition(aComponentName, getProject().getFlexoComponentLibrary(), selectedFolder, getProject()); } setTabComponent(newComponent); } public TabComponentDefinition getTabComponent() { if (_tabComponentInstance != null) { return _tabComponentInstance.getComponentDefinition(); } return null; } public void setTabComponent(TabComponentDefinition aComponentDefinition) { if (_tabComponentInstance != null && _tabComponentInstance.getComponentDefinition() == aComponentDefinition) { return; } if (_tabComponentInstance != null && aComponentDefinition == null) { removeTabComponentInstance(); } if (aComponentDefinition != null) { setTabOperationComponentInstance(new TabComponentInstance(aComponentDefinition, this)); } } public TabComponentInstance getTabOperationComponentInstance() { return _tabComponentInstance; } public void setTabOperationComponentInstance(TabComponentInstance tabComponentInstance) { if (_tabComponentInstance != null) { removeTabComponentInstance(); } tabComponentInstance.setOperationNode(this); if (tabComponentInstance.getComponentDefinition() != null || isCreatedByCloning()) { _tabComponentInstance = tabComponentInstance; setChanged(); TabOperationComponentHasBeenSet dm = new TabOperationComponentHasBeenSet("WOComponentName", tabComponentInstance.getComponentDefinition(), this); notifyObservers(dm); } else if (logger.isLoggable(Level.SEVERE)) { logger.severe("TabComponentInstance does not have a component definition for component named " + tabComponentInstance.getComponentName()); } } public void removeTabComponentInstance() { if (_tabComponentInstance != null) { _tabComponentInstance.delete(); } ComponentInstance oldComponentInstance = _tabComponentInstance; _tabComponentInstance = null; setChanged(); notifyObservers(new TabOperationComponentHasBeenRemoved("WOComponentName", oldComponentInstance != null ? oldComponentInstance.getComponentDefinition() : null, this)); } @Override public Vector<MetricsValue> getMetricsValues() { return metricsValues; } public void setMetricsValues(Vector<MetricsValue> metricsValues) { this.metricsValues = metricsValues; setChanged(); } @Override public void addToMetricsValues(MetricsValue value) { if (value.getMetricsDefinition() != null) { metricsValues.add(value); value.setOwner(this); setChanged(); notifyObservers(new MetricsValueAdded(value, "metricsValues")); } } @Override public void removeFromMetricsValues(MetricsValue value) { metricsValues.remove(value); value.setOwner(null); setChanged(); notifyObservers(new MetricsValueRemoved(value, "metricsValues")); } @Override public void updateMetricsValues() { getWorkflow().updateMetricsForOperation(this); } public void notifyBindingsChanged() { setChanged(); notifyObservers(new WKFAttributeDataModification("componentInstance.bindings", null, null)); } public void addMetrics() { if (addMetricsActionizer != null) { addMetricsActionizer.run(this, null); } } public void deleteMetrics(MetricsValue value) { if (deleteMetricsActionizer != null) { deleteMetricsActionizer.run(value, null); } } public boolean hasWOComponent() { if (_componentInstance != null && _componentInstance.getComponentDefinition() == null) { logger.severe("_componentInstance != null && _componentInstance.getComponentDefinition()==null in operation: " + getName()); } return _componentInstance != null && _componentInstance.getComponentDefinition() != null; } public IEWOComponent getWOComponent() { return _componentInstance.getComponentDefinition().getWOComponent(); } public OperationComponentDefinition getComponentDefinition() { if (_componentInstance == null) { return null; } return (OperationComponentDefinition) _componentInstance.getComponentDefinition(); } public String getAcronym() { return _acronym; } public void setAcronym(String acronym) { String old = _acronym; _acronym = acronym; setChanged(); notifyObservers(new WKFAttributeDataModification("acronym", old, acronym)); } public static ActionNode createNewActionNodeForButton(IEHyperlinkWidget w, OperationNode node) { if (!w.getIsFlexoAction() && !w.getIsDisplayAction()) { return null; } if (node.getActionPetriGraph() == null) { new ActionPetriGraph(node); } ActionNode newNode = new ActionNode(node.getProcess()); if (w.getIsFlexoAction()) { newNode.setActionType(ActionType.FLEXO_ACTION); } else { newNode.setActionType(ActionType.DISPLAY_ACTION); } newNode.setName(w.getNameOrCalculatedLabel()); newNode.setAssociatedButtonWidget(w); node.getActionPetriGraph().addToNodes(newNode); return newNode; } public static void linkActionToBeginAndEndNode(ActionNode node) { linkActionToBeginNode(node); linkActionToEndNode(node); } public static void linkActionToBeginNode(ActionNode node) { if (node == null) { if (logger.isLoggable(Level.SEVERE)) { logger.severe("Tried to create a link with a null node"); } return; } ActionNode begin = null; try { begin = (ActionNode) node.getOperationNode().getActionPetriGraph().getAllBeginNodes().firstElement(); } catch (NoSuchElementException e1) { // The vector is empty begin = null; } if (begin != null) { try { /* * FlexoPreCondition pc = null; if (node.getPreConditions().size() == 0) { pc = new FlexoPreCondition(node); } else pc = * node.getPreConditions().firstElement(); */ new TokenEdge(begin, node); if (logger.isLoggable(Level.FINEST)) { logger.finest("Created link from begin to node"); } } catch (InvalidEdgeException e) { e.printStackTrace(); } } else if (logger.isLoggable(Level.INFO)) { logger.info("No begin node found"); } } public static void linkActionToEndNode(ActionNode node) { if (node == null) { if (logger.isLoggable(Level.SEVERE)) { logger.severe("Tried to create a link with a null node"); } return; } if (node.getActionType() == ActionType.DISPLAY_ACTION) { if (logger.isLoggable(Level.WARNING)) { logger.warning("Tried to link a display action to begin and end nodes"); } return; } ActionNode end = null; try { end = (ActionNode) node.getOperationNode().getActionPetriGraph().getAllEndNodes().firstElement(); } catch (NoSuchElementException e1) { // The vector is empty end = null; } if (end != null) { try { FlexoPreCondition pc = null; if (end.getPreConditions().size() == 0) { pc = new FlexoPreCondition(end); } else { pc = end.getPreConditions().firstElement(); } new TokenEdge(node, pc); if (logger.isLoggable(Level.FINEST)) { logger.finest("Created link from node to end"); } } catch (InvalidEdgeException e) { e.printStackTrace(); } } else if (logger.isLoggable(Level.INFO)) { logger.info("No end node found"); } } // ========================================================================== // ============================= Validation // ================================= // ========================================================================== public static class OperationMustHaveATab extends ValidationRule<OperationMustHaveATab, OperationNode> { public OperationMustHaveATab() { super(OperationNode.class, "operation_node_must_define_a_tab"); } @Override public ValidationIssue<OperationMustHaveATab, OperationNode> applyValidation(OperationNode node) { if (node.isAccessible() && !(node instanceof SelfExecutableOperationNode) && node.getNodeType() == NodeType.NORMAL && node.getComponentInstance() != null) { if (node.getComponentDefinition().getWOComponent().hasTabContainer() && node.getOperationComponent().getWOComponent().hasAtLeastOneTabDefined() && node.getSelectedTabKey() == null) { return new ValidationError<OperationMustHaveATab, OperationNode>(this, node, "operation_($object.name)_must_define_a_tab"); } } return null; } } public static class OperationMustHaveAWOComponent extends ValidationRule<OperationMustHaveAWOComponent, OperationNode> { public OperationMustHaveAWOComponent() { super(OperationNode.class, "operation_node_must_define_a_wo_component"); } @Override public ValidationIssue<OperationMustHaveAWOComponent, OperationNode> applyValidation(OperationNode node) { if (!(node instanceof SelfExecutableOperationNode) && node.getNodeType() == NodeType.NORMAL && node.getComponentInstance() == null) { ValidationError<OperationMustHaveAWOComponent, OperationNode> error = new ValidationError<OperationMustHaveAWOComponent, OperationNode>( this, node, "operation_($object.name)_defines_no_wo_component"); error.addToFixProposals(new CreateAndAssignNewWOComponent()); error.addToFixProposals(new DeletionFixProposal<OperationMustHaveAWOComponent, OperationNode>("delete_this_operation")); return error; } return null; } public class CreateAndAssignNewWOComponent extends ParameteredFixProposal<OperationMustHaveAWOComponent, OperationNode> { public CreateAndAssignNewWOComponent() { super("create_and_assign_new_wo_component_to_operation_($object.name)", "newWOName", "enter_a_name_for_the_new_wo_component", ""); } @Override protected void fixAction() { String newWOName = (String) getValueForParameter("newWOName"); String newName = newWOName; boolean isOK = false; int tryNb = 0; if (newName != null) { while (!isOK) { try { getObject().setWOComponentName(newName); isOK = true; } catch (DuplicateResourceException e) { tryNb++; newName = newWOName + "-" + tryNb; } catch (OperationAssociatedWithComponentSuccessfully e) { } } } } } } public static class OperationComponentActionsMustBeBoundToAnActionNode extends ValidationRule<OperationComponentActionsMustBeBoundToAnActionNode, OperationNode> { public OperationComponentActionsMustBeBoundToAnActionNode() { super(OperationNode.class, "flexo_action_button_of_operation_component_must_have_a_corresponding_action_node"); } @Override public ValidationIssue<OperationComponentActionsMustBeBoundToAnActionNode, OperationNode> applyValidation(OperationNode node) { ValidationError<OperationComponentActionsMustBeBoundToAnActionNode, OperationNode> err = null; if (node.getComponentInstance() == null) { return null;// If there are no component, then another rule will } // take care of this. Enumeration en = node.getOperationComponent().getWOComponent().getAvailableFlexoActions().elements(); Vector<IEHyperlinkWidget> v = new Vector<IEHyperlinkWidget>(); while (en.hasMoreElements()) { IEHyperlinkWidget w = (IEHyperlinkWidget) en.nextElement(); if (w.getIsMandatoryFlexoAction() && (w.getHyperlinkType() == null || w.getHyperlinkType() != HyperlinkType.SEARCH && w.getHyperlinkType() != HyperlinkType.CANCEL && w.getHyperlinkType() != HyperlinkType.MAILTO && w.getHyperlinkType() != HyperlinkType.URL)) { v.add(w); } } en = node.getOperationComponent().getWOComponent().getAvailableDisplayActions().elements(); while (en.hasMoreElements()) { IEHyperlinkWidget w = (IEHyperlinkWidget) en.nextElement(); if (w.getIsMandatoryFlexoAction() && (w.getHyperlinkType() == null || w.getHyperlinkType() != HyperlinkType.SEARCH && w.getHyperlinkType() != HyperlinkType.MAILTO && w.getHyperlinkType() != HyperlinkType.URL)) { v.add(w); } } en = node.getAllActionNodes().elements(); while (en.hasMoreElements()) { ActionNode a = (ActionNode) en.nextElement(); if (a.getAssociatedButtonWidget() != null) { v.remove(a.getAssociatedButtonWidget()); } } if (v.size() > 0) { err = new ValidationError<OperationComponentActionsMustBeBoundToAnActionNode, OperationNode>(this, node, "operation_must_bound_action_nodes_to_flexo_action_defined_in_the_associated_component_($object.name)"); err.addToFixProposals(new RemoveMandatoryAttributeFromWidget()); err.addToFixProposals(new AutomaticallyCreateActionNodes()); } return err; } public class RemoveMandatoryAttributeFromWidget extends FixProposal<OperationComponentActionsMustBeBoundToAnActionNode, OperationNode> { public RemoveMandatoryAttributeFromWidget() { super("modify_button_such_that_it_do_not_requires_a_flexo_action"); } @Override protected void fixAction() { OperationNode node = getObject(); if (node.getComponentInstance() == null) { return;// If there are no component, there are no errors; } Enumeration en = node.getOperationComponent().getWOComponent().getAllButtonInterface().elements(); Vector<IEHyperlinkWidget> v = new Vector<IEHyperlinkWidget>(); while (en.hasMoreElements()) { IEHyperlinkWidget w = (IEHyperlinkWidget) en.nextElement(); if (w.getIsFlexoAction() || w.getIsDisplayAction()) { v.add(w); } } Vector<ActionNode> actionNodesToRemove = new Vector<ActionNode>(); en = node.getAllActionNodes().elements(); while (en.hasMoreElements()) { ActionNode a = (ActionNode) en.nextElement(); if (a.getAssociatedButtonWidget() != null) { v.remove(a.getAssociatedButtonWidget()); } else { actionNodesToRemove.add(a); } } en = actionNodesToRemove.elements(); while (en.hasMoreElements()) { ActionNode a = (ActionNode) en.nextElement(); if (!a.isBeginNode() && !a.isEndNode()) { a.delete(); } } en = v.elements(); while (en.hasMoreElements()) { IEHyperlinkWidget w = (IEHyperlinkWidget) en.nextElement(); if (w.getIsMandatoryFlexoAction()) { w.setIsMandatoryFlexoAction(false); } } } } public class AutomaticallyCreateActionNodes extends FixProposal<OperationComponentActionsMustBeBoundToAnActionNode, OperationNode> { public AutomaticallyCreateActionNodes() { super("automatically_create_and_bound_new_action_nodes_(this_will_delete_other_action_nodes"); } @Override protected void fixAction() { OperationNode node = getObject(); if (node.getComponentInstance() == null) { return;// If there are no component, there are no errors; } Enumeration en = node.getOperationComponent().getWOComponent().getAllButtonInterface().elements(); Vector<IEHyperlinkWidget> v = new Vector<IEHyperlinkWidget>(); while (en.hasMoreElements()) { IEHyperlinkWidget w = (IEHyperlinkWidget) en.nextElement(); if (w.getIsFlexoAction() || w.getIsDisplayAction()) { v.add(w); } } Vector<ActionNode> actionNodesToRemove = new Vector<ActionNode>(); en = node.getAllActionNodes().elements(); while (en.hasMoreElements()) { ActionNode a = (ActionNode) en.nextElement(); if (a.getAssociatedButtonWidget() != null) { v.remove(a.getAssociatedButtonWidget()); } else { actionNodesToRemove.add(a); } } en = actionNodesToRemove.elements(); while (en.hasMoreElements()) { ActionNode a = (ActionNode) en.nextElement(); if (!a.isBeginNode() && !a.isEndNode()) { a.delete(); } } en = v.elements(); while (en.hasMoreElements()) { IEHyperlinkWidget w = (IEHyperlinkWidget) en.nextElement(); ActionNode newAction = createNewActionNodeForButton(w, node); if (newAction != null) { linkActionToBeginAndEndNode(newAction); } } } } } protected boolean shouldBeSynchronized() { for (Enumeration en = getAllActionNodes().elements(); en.hasMoreElements();) { ActionNode nextAction = (ActionNode) en.nextElement(); for (Enumeration<FlexoPostCondition<AbstractNode, AbstractNode>> en2 = nextAction.getOutgoingPostConditions().elements(); en2 .hasMoreElements();) { FlexoPostCondition<?, ?> nextEdge = en2.nextElement(); if (nextEdge instanceof TokenEdge) { TokenEdge edge = (TokenEdge) nextEdge; if (edge.getNextNode() != null && edge.getNextNode() instanceof ActionNode && ((ActionNode) edge.getNextNode()).isEndNode() && ((ActionNode) edge.getNextNode()).getOperationNode() == this) { return true; } } } } return false; } public static String getTypeName() { return "OPERATION"; } /** * An OperationNode containing at least one ActionNode linked to an END node should be synchronized. * * @author sguerin * @version $Id: OperationNode.java,v 1.9.2.19 2006/01/06 21:35:06 sguerin Exp $ */ public static class OperationShouldBeSynchronized extends ValidationRule<OperationShouldBeSynchronized, OperationNode> { public OperationShouldBeSynchronized() { super(OperationNode.class, "operation_node_should_be_synchronized"); } @Override public ValidationIssue<OperationShouldBeSynchronized, OperationNode> applyValidation(OperationNode node) { if (node.shouldBeSynchronized() && !node.getIsSynchronized()) { ValidationWarning<OperationShouldBeSynchronized, OperationNode> warning = new ValidationWarning<OperationShouldBeSynchronized, OperationNode>( this, node, "operation_($object.name)_should_be_synchronized"); warning.addToFixProposals(new SynchronizeOperation()); return warning; } return null; } public class SynchronizeOperation extends FixProposal<OperationShouldBeSynchronized, OperationNode> { public SynchronizeOperation() { super("set_operation_($object.name)_as_synchronized"); } @Override protected void fixAction() { getObject().setIsSynchronized(true); } } } /** * Overrides getClassNameKey * * @see org.openflexo.foundation.FlexoModelObject#getClassNameKey() */ @Override public String getClassNameKey() { return "operation_node"; } /** * Overrides setNodeName * * @see org.openflexo.foundation.wkf.node.AbstractNode#setNodeName(java.lang.String) */ @Override public void setNodeName(String aName) { super.setNodeName(aName); if (getProcess() != null) { getProcess().notifyOperationChange(this); } } protected Color componentTextColor = FlexoColor.GRAY_COLOR; public Color getComponentTextColor() { return componentTextColor; } public void setComponentTextColor(Color ctc) { Color old = componentTextColor; this.componentTextColor = ctc; setChanged(); notifyObservers(new ComponentTextColorChanged(old, componentTextColor)); } /** * @return * @deprecated */ @Deprecated public FlexoCSS getCalculatedCssSheet() { if (cssSheet == null) { if (getAbstractActivityNode() != null) { return getAbstractActivityNode().getCalculatedCssSheet(); } else { return getProject().getCssSheet(); } } else { return cssSheet; } } /** * @return * @deprecated */ @Deprecated public FlexoCSS getCssSheet() { return cssSheet; } /** * @return * @deprecated */ @Deprecated public void setCssSheet(FlexoCSS sheet) { FlexoCSS old = this.cssSheet; this.cssSheet = sheet; setChanged(); notifyAttributeModification("cssSheet", old, cssSheet); } public static class MandatoryBindingsMustHaveAValue extends ValidationRule<MandatoryBindingsMustHaveAValue, OperationNode> { public MandatoryBindingsMustHaveAValue() { super(OperationNode.class, "mandatory_bindings_must_have_a_value"); } @Override public ValidationIssue<MandatoryBindingsMustHaveAValue, OperationNode> applyValidation(OperationNode node) { if (node.getComponentInstance() == null) { return null; } Enumeration<ComponentBindingDefinition> en = node.getComponentInstance().getComponentDefinition().getBindingDefinitions() .elements(); while (en.hasMoreElements()) { ComponentBindingDefinition bd = en.nextElement(); if (!bd.getIsMandatory()) { continue; } ComponentInstanceBinding cib = node.getComponentInstance().getBinding(bd); if (cib.getBindingValue() == null) { return new ValidationError<MandatoryBindingsMustHaveAValue, OperationNode>(this, node, "some_bindings_have_no_value_in_operation_($object.name)"); } } return null; } /** * Overrides isValidForTarget * * @see org.openflexo.foundation.validation.ValidationRule#isValidForTarget(TargetType) */ @Override public boolean isValidForTarget(TargetType targetType) { return targetType != CodeType.PROTOTYPE; } } public static class MandatoryBooleanBindingsMustHaveAValue extends ValidationRule<MandatoryBooleanBindingsMustHaveAValue, OperationNode> { public MandatoryBooleanBindingsMustHaveAValue() { super(OperationNode.class, "mandatory_boolean_bindings_must_have_a_value"); } @Override public ValidationIssue<MandatoryBooleanBindingsMustHaveAValue, OperationNode> applyValidation(OperationNode node) { if (node.getComponentInstance() == null) { return null; } Enumeration<ComponentBindingDefinition> en = node.getComponentInstance().getComponentDefinition().getBindingDefinitions() .elements(); while (en.hasMoreElements()) { ComponentBindingDefinition bd = en.nextElement(); if (bd.getType() == null) { return new ValidationError<MandatoryBooleanBindingsMustHaveAValue, OperationNode>(this, node, "component_bindings_for_operation_($object.name)_have_no_type"); } if (!bd.getIsMandatory() || !bd.getType().isBoolean() && !bd.getType().isBooleanPrimitive()) { continue; } ComponentInstanceBinding cib = node.getComponentInstance().getBinding(bd); if (cib == null || cib.getBindingValue() == null) { return new ValidationError<MandatoryBooleanBindingsMustHaveAValue, OperationNode>(this, node, "some_boolean_bindings_have_no_value_in_operation_($object.name)"); } } return null; } /** * Overrides isValidForTarget * * @see org.openflexo.foundation.validation.ValidationRule#isValidForTarget(TargetType) */ @Override public boolean isValidForTarget(TargetType targetType) { return targetType == CodeType.PROTOTYPE; } } public ComponentBindingDefinition getBusinessDataBinding() { if (getComponentInstance() == null || getProcess().getBusinessDataType() == null) { return null; } for (ComponentInstanceBinding cib : getComponentInstance().getBindings()) { if (cib.getBindingDefinition().getType().getBaseEntity() == getProcess().getBusinessDataType()) { return cib.getBindingDefinition(); } } return null; } public static class OperationMustDefineABindingOfBusinessDataType extends ValidationRule<OperationMustDefineABindingOfBusinessDataType, OperationNode> { public OperationMustDefineABindingOfBusinessDataType() { super(OperationNode.class, "operation_must_define_a_binding_of_business_data_type"); } @Override public ValidationIssue<OperationMustDefineABindingOfBusinessDataType, OperationNode> applyValidation(OperationNode node) { if (node.getComponentInstance() == null || node.getProcess().getBusinessDataType() == null) { return null; } for (ComponentInstanceBinding cib : node.getComponentInstance().getBindings()) { if (cib.getBindingDefinition().getType() != null && cib.getBindingDefinition().getType().getBaseEntity() == node.getProcess().getBusinessDataType()) { return null; } } return new ValidationError<OperationMustDefineABindingOfBusinessDataType, OperationNode>(this, node, "operation_must_define_a_binding_of_business_data_type"); } /** * Overrides isValidForTarget * * @see org.openflexo.foundation.validation.ValidationRule#isValidForTarget(TargetType) */ @Override public boolean isValidForTarget(TargetType targetType) { return targetType != CodeType.PROTOTYPE; } } public ActionNode getActionNodeForButton(IEHyperlinkWidget button) { Enumeration en = getAllActionNodes().elements(); while (en.hasMoreElements()) { ActionNode action = (ActionNode) en.nextElement(); if (action.getAssociatedButtonWidget() == button && (action.getActionType() == ActionType.DISPLAY_ACTION || action.getActionType() == ActionType.FLEXO_ACTION)) { return action; } } return null; } public String getSelectedTabKey() { if (getComponentDefinition().getWOComponent().getTabWidgetForTabComponent(getTabComponent()) != null) { return getComponentDefinition().getWOComponent().getTabWidgetForTabComponent(getTabComponent()).getTabKeyForGenerator(); } /* * if (getTabOperationComponentInstance() != null) { Enumeration en = ((IEPageComponent) * getOperationComponent().getWOComponent()).topComponents(); while (en.hasMoreElements()) { IETopComponent tcc = (IETopComponent) * en.nextElement(); if (tcc instanceof IESequenceTab) { IESequenceTab w = (IESequenceTab) tcc; Enumeration en1 = * w.getAllTabs().elements(); while (en1.hasMoreElements()) { IETabWidget tab = (IETabWidget) en1.nextElement(); if * (tab.getTabComponentDefinition().equals( getTabOperationComponentInstance().getComponentDefinition())) { if * (logger.isLoggable(Level.INFO)) * logger.info("Selected tab for operation "+getName()+" is "+tab.getTabComponentDefinition().getName()); return * tab.getTabKeyForGenerator(); } } } } if (logger.isLoggable(Level.WARNING)) * logger.warning("Selected tab for operation "+getName()+" could not be found. Expected: "+getTabComponentName()); } */ return null; } private Date _lastUpdate; /** * This date is use to perform fine tuning resource dependancies computing * * @return */ @Override public Date getLastUpdate() { if (_lastUpdate == null) { _lastUpdate = lastMemoryUpdate(); } if (_lastUpdate == null) { _lastUpdate = super.getLastUpdate(); } return _lastUpdate; } public void setLastUpdate(Date lastUpdate) { _lastUpdate = lastUpdate; } @Override public void setIsModified() { if (ignoreNotifications()) { return; } _lastUpdate = null; super.setIsModified(); // _lastUpdate = lastMemoryUpdate(); // Do this to reset dependant resources cache, in order to get up-to-date // needsGeneration information on generated resources if (getXMLResourceData() != null && getXMLResourceData().getFlexoResource() != null) { getXMLResourceData().getFlexoResource().notifyResourceStatusChanged(); } if (logger.isLoggable(Level.FINE)) { logger.fine("Operation node " + getFullyQualifiedName() + " is set to be modified, date=" + _lastUpdate); } } public String getStaticDirectActionUrl() { if (getComponentInstance() == null) { return null; } StringBuffer sb = new StringBuffer(); sb.append(getProject().getPrefix()).append("DA/open").append(getComponentInstance().getComponentName()); sb.append("?").append(ToolBox.serializeHashtable(getComponentInstance().getStaticBindingValues())); if (getComponentInstance().getComponentDefinition().getHasTabContainer()) { sb.append("&tab="); if (getTabOperationComponentInstance() != null) { sb.append(getComponentInstance().getComponentDefinition().getWOComponent().getTabWidgetForTabComponent(getTabComponent()) .getTabKeyForGenerator()); } } return sb.toString(); } public boolean isUnderSubProcessNode() { return getFather() instanceof SubProcessNode; } public FlexoProcess getRelatedProcess() { if (isUnderSubProcessNode()) { return ((SubProcessNode) getFather()).getSubProcess(); } else { return getProcess(); } } /** * Overrides compareTo * * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override public int compareTo(OperationNode o) { return this.getFullyQualifiedName().compareTo(o.getFullyQualifiedName()); } public OperationStatistics getStatistics() { if (statistics == null) { statistics = new OperationStatistics(this); } return statistics; } @Override public ApplicationHelpEntryPoint getParentHelpEntry() { return getAbstractActivityNode() instanceof ApplicationHelpEntryPoint ? (ApplicationHelpEntryPoint) getAbstractActivityNode() : null; } @Override public List<ApplicationHelpEntryPoint> getChildsHelpObjects() { Vector<ApplicationHelpEntryPoint> reply = new Vector<ApplicationHelpEntryPoint>(); return reply; } @Override public String getShortHelpLabel() { return getName(); } @Override public String getTypedHelpLabel() { return "Operation : " + getName(); } }