From: Mathieu Baudier Date: Wed, 20 Apr 2011 18:20:06 +0000 (+0000) Subject: Document and improve execution model X-Git-Tag: argeo-slc-2.1.7~969 X-Git-Url: http://git.argeo.org/?a=commitdiff_plain;ds=sidebyside;h=3781dcd363f0f6265fae0ac758fd40cf4254ebc9;p=gpl%2Fargeo-slc.git Document and improve execution model Improve UI ASSIGNED - bug 17: Generalize agent management and registration beyond JMS https://bugzilla.argeo.org/show_bug.cgi?id=17 git-svn-id: https://svn.argeo.org/slc/trunk@4466 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/eclipse/plugins/org.argeo.slc.client.ui/icons/agentFactory.gif b/eclipse/plugins/org.argeo.slc.client.ui/icons/agentFactory.gif new file mode 100644 index 000000000..b51ae39b8 Binary files /dev/null and b/eclipse/plugins/org.argeo.slc.client.ui/icons/agentFactory.gif differ diff --git a/eclipse/plugins/org.argeo.slc.client.ui/icons/choices.gif b/eclipse/plugins/org.argeo.slc.client.ui/icons/choices.gif new file mode 100644 index 000000000..da2f57713 Binary files /dev/null and b/eclipse/plugins/org.argeo.slc.client.ui/icons/choices.gif differ diff --git a/eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpec.gif b/eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpec.gif new file mode 100644 index 000000000..1ff93cb93 Binary files /dev/null and b/eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpec.gif differ diff --git a/eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpecAttribute.gif b/eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpecAttribute.gif new file mode 100644 index 000000000..bee687ce3 Binary files /dev/null and b/eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpecAttribute.gif differ diff --git a/eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpecs.gif b/eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpecs.gif new file mode 100644 index 000000000..0b63124d8 Binary files /dev/null and b/eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpecs.gif differ diff --git a/eclipse/plugins/org.argeo.slc.client.ui/icons/process_completed.png b/eclipse/plugins/org.argeo.slc.client.ui/icons/process_completed.png new file mode 100644 index 000000000..0ad64e736 Binary files /dev/null and b/eclipse/plugins/org.argeo.slc.client.ui/icons/process_completed.png differ diff --git a/eclipse/plugins/org.argeo.slc.client.ui/icons/process_error.png b/eclipse/plugins/org.argeo.slc.client.ui/icons/process_error.png new file mode 100644 index 000000000..e66c98e50 Binary files /dev/null and b/eclipse/plugins/org.argeo.slc.client.ui/icons/process_error.png differ diff --git a/eclipse/plugins/org.argeo.slc.client.ui/icons/process_running.png b/eclipse/plugins/org.argeo.slc.client.ui/icons/process_running.png new file mode 100644 index 000000000..471c0918d Binary files /dev/null and b/eclipse/plugins/org.argeo.slc.client.ui/icons/process_running.png differ diff --git a/eclipse/plugins/org.argeo.slc.client.ui/icons/process_scheduled.gif b/eclipse/plugins/org.argeo.slc.client.ui/icons/process_scheduled.gif new file mode 100644 index 000000000..b7f03d567 Binary files /dev/null and b/eclipse/plugins/org.argeo.slc.client.ui/icons/process_scheduled.gif differ diff --git a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/SlcImages.java b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/SlcImages.java index d9fe3cddb..6254166c5 100644 --- a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/SlcImages.java +++ b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/SlcImages.java @@ -6,6 +6,7 @@ import static org.argeo.slc.client.ui.ClientUiPlugin.img; /** Shared images. */ public class SlcImages { public final static Image AGENT = img("icons/agent.gif"); + public final static Image AGENT_FACTORY = img("icons/agentFactory.gif"); public final static Image MODULE = img("icons/module.png"); public final static Image FOLDER = img("icons/folder.gif"); public final static Image FLOW = img("icons/flow.png"); @@ -16,4 +17,12 @@ public class SlcImages { public final static Image RELAUNCH = img("icons/relaunch.gif"); public final static Image REMOVE_ONE = img("icons/remove_one.gif"); public final static Image REMOVE_ALL = img("icons/removeAll.png"); + public final static Image EXECUTION_SPECS = img("icons/executionSpecs.gif"); + public final static Image EXECUTION_SPEC = img("icons/executionSpec.gif"); + public final static Image EXECUTION_SPEC_ATTRIBUTE = img("icons/executionSpecAttribute.gif"); + public final static Image CHOICES = img("icons/choices.gif"); + public final static Image PROCESS_ERROR = img("icons/process_error.png"); + public final static Image PROCESS_SCHEDULED = img("icons/process_scheduled.gif"); + public final static Image PROCESS_RUNNING = img("icons/process_running.png"); + public final static Image PROCESS_COMPLETED = img("icons/process_completed.png"); } diff --git a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrExecutionModulesView.java b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrExecutionModulesView.java index 59157a370..e5696ee9e 100644 --- a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrExecutionModulesView.java +++ b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrExecutionModulesView.java @@ -9,6 +9,7 @@ import javax.jcr.Node; import javax.jcr.Property; import javax.jcr.RepositoryException; import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; import javax.jcr.observation.Event; import javax.jcr.observation.EventIterator; @@ -103,17 +104,19 @@ public class JcrExecutionModulesView extends ViewPart implements SlcTypes, new String[] { SlcJcrConstants.VM_AGENT_FACTORY_PATH }); } -// @Override -// protected Object[] getChildren(Node node) throws RepositoryException { -// if (node.isNodeType(SlcTypes.SLC_AGENT_FACTORY)) { -// List wrappers = new ArrayList(); -// for (NodeIterator nit = node.getNodes(); nit.hasNext();) { -// wrappers.add(new AgentNodesWrapper(nit.nextNode())); -// } -// return wrappers.toArray(); -// } -// return super.getChildren(node); -// } + // @Override + // protected Object[] getChildren(Node node) throws RepositoryException + // { + // if (node.isNodeType(SlcTypes.SLC_AGENT_FACTORY)) { + // List wrappers = new + // ArrayList(); + // for (NodeIterator nit = node.getNodes(); nit.hasNext();) { + // wrappers.add(new AgentNodesWrapper(nit.nextNode())); + // } + // return wrappers.toArray(); + // } + // return super.getChildren(node); + // } @Override protected Object[] sort(Object parent, Object[] children) { @@ -131,6 +134,12 @@ public class JcrExecutionModulesView extends ViewPart implements SlcTypes, if (o1 instanceof Node && o2 instanceof Node) { Node node1 = (Node) o1; Node node2 = (Node) o2; + + if (node1.getName().equals(SLC_EXECUTION_SPECS)) + return -100; + if (node2.getName().equals(SLC_EXECUTION_SPECS)) + return 100; + if (node1.isNodeType(SLC_EXECUTION_FLOW) && node2.isNodeType(SLC_EXECUTION_FLOW)) { return node1.getName().compareTo(node2.getName()); @@ -154,27 +163,27 @@ public class JcrExecutionModulesView extends ViewPart implements SlcTypes, } -// /** Wraps the execution modules of an agent. */ -// static class AgentNodesWrapper extends NodesWrapper { -// -// public AgentNodesWrapper(Node node) { -// super(node); -// } -// -// protected List getWrappedNodes() -// throws RepositoryException { -// List children = new ArrayList(); -// Node executionModules = getNode(); -// for (NodeIterator nit = executionModules.getNodes(); nit.hasNext();) { -// for (NodeIterator nitVersions = nit.nextNode().getNodes(); nitVersions -// .hasNext();) { -// children.add(new WrappedNode(this, nitVersions.nextNode())); -// } -// } -// return children; -// } -// -// } + // /** Wraps the execution modules of an agent. */ + // static class AgentNodesWrapper extends NodesWrapper { + // + // public AgentNodesWrapper(Node node) { + // super(node); + // } + // + // protected List getWrappedNodes() + // throws RepositoryException { + // List children = new ArrayList(); + // Node executionModules = getNode(); + // for (NodeIterator nit = executionModules.getNodes(); nit.hasNext();) { + // for (NodeIterator nitVersions = nit.nextNode().getNodes(); nitVersions + // .hasNext();) { + // children.add(new WrappedNode(this, nitVersions.nextNode())); + // } + // } + // return children; + // } + // + // } class VmAgentObserver extends AsyncUiEventListener { protected void onEventInUiThread(EventIterator events) { @@ -184,32 +193,56 @@ public class JcrExecutionModulesView extends ViewPart implements SlcTypes, class ViewLabelProvider extends DefaultNodeLabelProvider implements ITableLabelProvider { - public String getColumnText(Object obj, int index) { - return getText(obj); - } - public Image getColumnImage(Object obj, int index) { - return getImage(obj); + @Override + protected String getText(Node node) throws RepositoryException { + if (node.getName().equals(SLC_EXECUTION_SPECS)) + return "Execution Specifications"; + else if (node.getPath().equals( + SlcJcrConstants.VM_AGENT_FACTORY_PATH)) + return "Internal Agents"; + return super.getText(node); } + @Override public Image getImage(Node node) throws RepositoryException { - if (node.isNodeType(SlcTypes.SLC_AGENT)) - return SlcImages.AGENT; - else if (node.isNodeType(SlcTypes.SLC_MODULE)) - return SlcImages.MODULE; + // we try to optimize a bit by putting deeper nodes first + if (node.getParent().isNodeType( + SlcTypes.SLC_EXECUTION_SPEC_ATTRIBUTE)) + return SlcImages.CHOICES; + else if (node.isNodeType(SlcTypes.SLC_EXECUTION_SPEC_ATTRIBUTE)) + return SlcImages.EXECUTION_SPEC_ATTRIBUTE; + else if (node.isNodeType(SlcTypes.SLC_EXECUTION_SPEC)) + return SlcImages.EXECUTION_SPEC; + else if (node.getName().equals(SLC_EXECUTION_SPECS)) + return SlcImages.EXECUTION_SPECS; else if (node.isNodeType(SlcTypes.SLC_EXECUTION_FLOW)) return SlcImages.FLOW; + else if (node.isNodeType(SlcTypes.SLC_MODULE)) + return SlcImages.MODULE; + else if (node.isNodeType(SlcTypes.SLC_AGENT)) + return SlcImages.AGENT; + else if (node.isNodeType(SlcTypes.SLC_AGENT_FACTORY)) + return SlcImages.AGENT_FACTORY; else return SlcImages.FOLDER; } public String getToolTipText(Node node) throws RepositoryException { - if (node.isNodeType(SlcTypes.SLC_MODULE) + if (node.isNodeType(NodeType.MIX_TITLE) && node.hasProperty(Property.JCR_DESCRIPTION)) return node.getProperty(Property.JCR_DESCRIPTION).getString(); return super.getToolTipText(node); } + public String getColumnText(Object obj, int index) { + return getText(obj); + } + + public Image getColumnImage(Object obj, int index) { + return getImage(obj); + } + } class ViewDoubleClickListener implements IDoubleClickListener { diff --git a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrProcessListView.java b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrProcessListView.java index ddc34a581..2df53034b 100644 --- a/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrProcessListView.java +++ b/eclipse/plugins/org.argeo.slc.client.ui/src/main/java/org/argeo/slc/client/ui/views/JcrProcessListView.java @@ -19,8 +19,10 @@ import javax.jcr.query.Query; import org.argeo.eclipse.ui.jcr.AsyncUiEventListener; import org.argeo.jcr.JcrUtils; import org.argeo.slc.SlcException; +import org.argeo.slc.client.ui.SlcImages; import org.argeo.slc.client.ui.editors.ProcessEditor; import org.argeo.slc.client.ui.editors.ProcessEditorInput; +import org.argeo.slc.execution.ExecutionProcess; import org.argeo.slc.jcr.SlcJcrConstants; import org.argeo.slc.jcr.SlcNames; import org.argeo.slc.jcr.SlcTypes; @@ -68,6 +70,7 @@ public class JcrProcessListView extends ViewPart { processesObserver = new AsyncUiEventListener() { protected void onEventInUiThread(EventIterator events) { + // TODO optimize by updating only the changed process viewer.refresh(); } }; @@ -157,8 +160,29 @@ public class JcrProcessListView extends ViewPart { class LabelProvider extends ColumnLabelProvider implements ITableLabelProvider { - public Image getColumnImage(Object element, int columnIndex) { - return null; + public Image getColumnImage(Object obj, int columnIndex) { + if (columnIndex != 0) + return null; + try { + Node node = (Node) obj; + String status = node.getProperty(SlcNames.SLC_STATUS) + .getString(); + if (status.equals(ExecutionProcess.NEW) + || status.equals(ExecutionProcess.INITIALIZED) + || status.equals(ExecutionProcess.SCHEDULED)) + return SlcImages.PROCESS_SCHEDULED; + else if (status.equals(ExecutionProcess.ERROR) + || status.equals(ExecutionProcess.UNKOWN)) + return SlcImages.PROCESS_ERROR; + else if (status.equals(ExecutionProcess.COMPLETED)) + return SlcImages.PROCESS_COMPLETED; + else if (status.equals(ExecutionProcess.RUNNING)) + return SlcImages.PROCESS_RUNNING; + else + throw new SlcException("Unkown status " + status); + } catch (RepositoryException e) { + throw new SlcException("Cannot get column text", e); + } } public String getColumnText(Object obj, int index) { diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractExecutionValue.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractExecutionValue.java index be5a367d8..4aaf800e2 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractExecutionValue.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractExecutionValue.java @@ -18,7 +18,7 @@ package org.argeo.slc.core.execution; import java.io.Serializable; -public abstract class AbstractExecutionValue implements Serializable{ +/** Value to be used by an execution */ +public abstract class AbstractExecutionValue implements Serializable { private static final long serialVersionUID = 1558444746120706961L; - } diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractSpecAttribute.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractSpecAttribute.java index dd976f223..abe045114 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractSpecAttribute.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/AbstractSpecAttribute.java @@ -20,29 +20,30 @@ import java.io.Serializable; import org.argeo.slc.execution.ExecutionSpecAttribute; +/** Canonical implementation of the execution spec attribute booleans. */ public abstract class AbstractSpecAttribute implements ExecutionSpecAttribute, Serializable { private static final long serialVersionUID = 6494963738891709440L; - private Boolean isParameter = false; - private Boolean isFrozen = false; + private Boolean isImmutable = false; + private Boolean isConstant = false; private Boolean isHidden = false; /** Has to be set at instantiation */ - public Boolean getIsParameter() { - return isParameter; + public Boolean getIsImmutable() { + return isImmutable; } - public void setIsParameter(Boolean isParameter) { - this.isParameter = isParameter; + public void setIsImmutable(Boolean isImmutable) { + this.isImmutable = isImmutable; } /** Cannot be overridden at runtime */ - public Boolean getIsFrozen() { - return isFrozen; + public Boolean getIsConstant() { + return isConstant; } - public void setIsFrozen(Boolean isFinal) { - this.isFrozen = isFinal; + public void setIsConstant(Boolean isConstant) { + this.isConstant = isConstant; } /** Should not be shown to the end user */ @@ -54,4 +55,27 @@ public abstract class AbstractSpecAttribute implements ExecutionSpecAttribute, this.isHidden = isHidden; } + /* + * DEPRECATED + */ + /** @deprecated use {@link #getIsImmutable()} instead */ + public Boolean getIsParameter() { + return isImmutable; + } + + /** @deprecated use {@link #getIsConstant()} instead */ + public Boolean getIsFrozen() { + return isConstant; + } + + /** @deprecated use {@link #setIsImmutable(Boolean)} instead */ + public void setIsParameter(Boolean isParameter) { + this.isImmutable = isParameter; + } + + /** @deprecated use {@link #setIsConstant(Boolean)} instead */ + public void setIsFrozen(Boolean isFrozen) { + this.isConstant = isFrozen; + } + } diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionSpec.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionSpec.java index d47325d34..f7d64b9e2 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionSpec.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/DefaultExecutionSpec.java @@ -21,7 +21,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.UUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -36,6 +35,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; +/** Spring based implementation of execution specifications. */ public class DefaultExecutionSpec implements ExecutionSpec, BeanNameAware, ApplicationContextAware, InitializingBean, Serializable { private static final long serialVersionUID = 5159882223926926539L; @@ -46,7 +46,7 @@ public class DefaultExecutionSpec implements ExecutionSpec, BeanNameAware, private String description; private Map attributes = new HashMap(); - private String name = getClass().getName() + "#" + UUID.randomUUID(); + private String name = INTERNAL_NAME; public Map getAttributes() { return attributes; @@ -60,6 +60,10 @@ public class DefaultExecutionSpec implements ExecutionSpec, BeanNameAware, this.name = name; } + /** + * The Spring bean name (only relevant for specs declared has high-level + * beans) + */ public String getName() { return name; } @@ -68,6 +72,10 @@ public class DefaultExecutionSpec implements ExecutionSpec, BeanNameAware, return ((ExecutionSpec) obj).getName().equals(name); } + /** + * The Spring bean description (only relevant for specs declared has + * high-level beans) + */ public String getDescription() { return description; } diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveAccessor.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveAccessor.java index 21756907f..c5b29dfb8 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveAccessor.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveAccessor.java @@ -16,6 +16,7 @@ package org.argeo.slc.core.execution; +/** Abstraction of access to primitive values */ public interface PrimitiveAccessor { public String getType(); diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveUtils.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveUtils.java index a4e09f650..c5a3a8605 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveUtils.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveUtils.java @@ -16,7 +16,7 @@ package org.argeo.slc.core.execution; - +/** Converts to and from primitive types. */ public class PrimitiveUtils { public final static String TYPE_STRING = "string"; public final static String TYPE_INTEGER = "integer"; diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveValue.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveValue.java index c19cfa4c3..4dffd7928 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveValue.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/PrimitiveValue.java @@ -16,6 +16,7 @@ package org.argeo.slc.core.execution; +/** Primitive value to be used by an execution. */ public class PrimitiveValue extends AbstractExecutionValue implements PrimitiveAccessor { private static final long serialVersionUID = 533414290998374166L; diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/RefValue.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/RefValue.java index fb5bf2e82..3795100f6 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/RefValue.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/RefValue.java @@ -16,6 +16,7 @@ package org.argeo.slc.core.execution; +/** Reference value to be used by an execution */ public class RefValue extends AbstractExecutionValue { private static final long serialVersionUID = -8951231456757181687L; private String ref; diff --git a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/RefValueChoice.java b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/RefValueChoice.java index e1ac35e71..51531d336 100644 --- a/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/RefValueChoice.java +++ b/runtime/org.argeo.slc.core/src/main/java/org/argeo/slc/core/execution/RefValueChoice.java @@ -18,6 +18,7 @@ package org.argeo.slc.core.execution; import java.io.Serializable; +/** A choice of ref value to be shown to the end user. */ public class RefValueChoice implements Serializable { private static final long serialVersionUID = -1133645722307507774L; private String name; diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionSpec.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionSpec.java index 8111cc7d9..e437740eb 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionSpec.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionSpec.java @@ -23,9 +23,23 @@ import java.util.Map; * necessary for the corresponding ExecutionFlow. */ public interface ExecutionSpec { - public Map getAttributes(); + /** + * The name for an internal spec (for backward compatibility where a + * non-null name is expected) + */ + public final static String INTERNAL_NAME = "__SLC_EXECUTION_SPEC_INTERNAL"; + /** + * The name identifying the execution spec within its application context. + * Can be null. An execution spec can be referenced only if its name is not + * null or different from {@link #INTERNAL_NAME} + */ public String getName(); + /** An optional description. Can be null. */ public String getDescription(); + + /** The attributes managed by this execution spec */ + public Map getAttributes(); + } diff --git a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionSpecAttribute.java b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionSpecAttribute.java index 4866f6377..e7259b8f7 100644 --- a/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionSpecAttribute.java +++ b/runtime/org.argeo.slc.specs/src/main/java/org/argeo/slc/execution/ExecutionSpecAttribute.java @@ -17,16 +17,14 @@ package org.argeo.slc.execution; /** - * This interface stands for one attribute of a given flow. - * - * We mainly have two implementations : + * Possible attribute of an execution flow. * + * There are mainly two implementations :
* + Primitive attributes (no predefined choice, the end user must compute a - * String, a Float, an Integer...) - * - * + RefSpecAttribute which enable two things + a reference to another object of - * the application context + the display of some choices among which the end - * user can choose. + * String, a Float, an Integer...)
+ * + RefSpecAttribute which enable two things
+ * ++ a reference to another object of the application context
+ * ++ the display of some choices among which the end user can choose.
* * @see org.argeo.slc.core.execution.PrimitiveSpecAttribute * @see org.argeo.slc.core.execution.RefSpecAttribute @@ -34,12 +32,35 @@ package org.argeo.slc.execution; * helper, among others to cast the various type of primitive attribute. */ public interface ExecutionSpecAttribute { + /** + * Whether this attribute has to be set at instantiation of the flow and + * cannot be modified afterwards. If the attribute is not immutable (that + * is, this method returns false), it can be set at execution time. + */ + public Boolean getIsImmutable(); + + /** + * Whether this attribute must be explicitly set and cannot be modified. + * This attribute is then basically a constant within a given application + * context. {@link #getValue()} cannot return null if the attribute is a + * constant. + */ + public Boolean getIsConstant(); + + /** Whether this attribute will be hidden to end users. */ + public Boolean getIsHidden(); + + /** + * The default value for this attribute. Can be null, except if + * {@link #getIsFrozen()} is true, in which case it represents + * the constant value of this attribute. + */ public Object getValue(); + /** @deprecated use {@link #getIsImmutable()} instead */ public Boolean getIsParameter(); + /** @deprecated use {@link #getIsConstant()} instead */ public Boolean getIsFrozen(); - public Boolean getIsHidden(); - } diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrUtils.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrUtils.java index 7f0f18a0c..e4d5d6e6e 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrUtils.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcJcrUtils.java @@ -3,7 +3,13 @@ package org.argeo.slc.jcr; import java.util.Calendar; import java.util.GregorianCalendar; +import javax.jcr.Node; +import javax.jcr.RepositoryException; + import org.argeo.jcr.JcrUtils; +import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.PrimitiveAccessor; +import org.argeo.slc.core.execution.PrimitiveUtils; import org.argeo.slc.deploy.ModuleDescriptor; /** @@ -61,6 +67,41 @@ public class SlcJcrUtils { } + /** + * Set the value of the primitive accessor as a JCR property. Does nothing + * if the value is null. + */ + public static void setPrimitiveAsProperty(Node node, String propertyName, + PrimitiveAccessor primitiveAccessor) { + String type = primitiveAccessor.getType(); + Object value = primitiveAccessor.getValue(); + if (value == null) + return; + if (value instanceof CharSequence) + value = PrimitiveUtils.convert(type, + ((CharSequence) value).toString()); + + try { + if (type.equals(PrimitiveUtils.TYPE_STRING)) + node.setProperty(propertyName, value.toString()); + else if (type.equals(PrimitiveUtils.TYPE_INTEGER)) + node.setProperty(propertyName, (long) ((Integer) value)); + else if (type.equals(PrimitiveUtils.TYPE_LONG)) + node.setProperty(propertyName, ((Long) value)); + else if (type.equals(PrimitiveUtils.TYPE_FLOAT)) + node.setProperty(propertyName, (double) ((Float) value)); + else if (type.equals(PrimitiveUtils.TYPE_DOUBLE)) + node.setProperty(propertyName, ((Double) value)); + else if (type.equals(PrimitiveUtils.TYPE_BOOLEAN)) + node.setProperty(propertyName, ((Boolean) value)); + else + throw new SlcException("Unsupported type " + type); + } catch (RepositoryException e) { + throw new SlcException("Cannot set primitive " + primitiveAccessor + + " as property " + propertyName + " on " + node, e); + } + } + /** Prevents instantiation */ private SlcJcrUtils() { diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java index 15d1e4428..7d906c036 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcNames.java @@ -5,11 +5,17 @@ public interface SlcNames { public final static String SLC_UUID = "slc:uuid"; public final static String SLC_STATUS = "slc:status"; + public final static String SLC_TYPE = "slc:type"; public final static String SLC_NAME = "slc:name"; public final static String SLC_VERSION = "slc:version"; + public final static String SLC_VALUE = "slc:value"; public final static String SLC_ADDRESS = "slc:address"; + public final static String SLC_EXECUTION_SPECS = "slc:executionSpecs"; public final static String SLC_FLOW = "slc:flow"; - //public final static String SLC_EXECUTION_MODULES = "slc:executionModules"; + + public final static String SLC_IS_IMMUTABLE = "slc:isImmutable"; + public final static String SLC_IS_CONSTANT = "slc:isConstant"; + public final static String SLC_IS_HIDDEN = "slc:isHidden"; } diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java index 4a3afc933..6ac10e3b0 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/SlcTypes.java @@ -7,8 +7,13 @@ public interface SlcTypes { public final static String SLC_AGENT = "slc:agent"; public final static String SLC_MODULE = "slc:module"; public final static String SLC_EXECUTION_MODULE = "slc:executionModule"; + public final static String SLC_EXECUTION_SPEC = "slc:executionSpec"; public final static String SLC_EXECUTION_FLOW = "slc:executionFlow"; public final static String SLC_PROCESS = "slc:process"; public final static String SLC_REALIZED_FLOW = "slc:realizedFlow"; + public final static String SLC_EXECUTION_SPEC_ATTRIBUTE = "slc:executionSpecAttribute"; + public final static String SLC_PRIMITIVE_SPEC_ATTRIBUTE = "slc:primitiveSpecAttribute"; + public final static String SLC_REF_SPEC_ATTRIBUTE = "slc:refSpecAttribute"; + } diff --git a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java index b019ff970..27d7b6b3b 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java +++ b/runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java @@ -8,14 +8,20 @@ import javax.jcr.NodeIterator; import javax.jcr.Property; import javax.jcr.RepositoryException; import javax.jcr.Session; +import javax.jcr.nodetype.NodeType; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.argeo.jcr.JcrUtils; import org.argeo.slc.SlcException; +import org.argeo.slc.core.execution.PrimitiveSpecAttribute; +import org.argeo.slc.core.execution.RefSpecAttribute; +import org.argeo.slc.core.execution.RefValueChoice; import org.argeo.slc.deploy.ModuleDescriptor; import org.argeo.slc.execution.ExecutionFlowDescriptor; import org.argeo.slc.execution.ExecutionModulesListener; +import org.argeo.slc.execution.ExecutionSpec; +import org.argeo.slc.execution.ExecutionSpecAttribute; import org.argeo.slc.jcr.SlcJcrUtils; import org.argeo.slc.jcr.SlcNames; import org.argeo.slc.jcr.SlcTypes; @@ -24,7 +30,8 @@ import org.argeo.slc.jcr.SlcTypes; * Synchronizes the local execution runtime with a JCR repository. For the time * being the state is completely reset from one start to another. */ -public class JcrExecutionModulesListener implements ExecutionModulesListener { +public class JcrExecutionModulesListener implements ExecutionModulesListener, + SlcNames { private final static Log log = LogFactory .getLog(JcrExecutionModulesListener.class); private JcrAgent agent; @@ -73,10 +80,8 @@ public class JcrExecutionModulesListener implements ExecutionModulesListener { .getNode(moduleNodeName) : agentNode .addNode(moduleNodeName); moduleNode.addMixin(SlcTypes.SLC_EXECUTION_MODULE); - moduleNode.setProperty(SlcNames.SLC_NAME, - moduleDescriptor.getName()); - moduleNode.setProperty(SlcNames.SLC_VERSION, - moduleDescriptor.getVersion()); + moduleNode.setProperty(SLC_NAME, moduleDescriptor.getName()); + moduleNode.setProperty(SLC_VERSION, moduleDescriptor.getVersion()); moduleNode.setProperty(Property.JCR_TITLE, moduleDescriptor.getTitle()); moduleNode.setProperty(Property.JCR_DESCRIPTION, @@ -104,44 +109,119 @@ public class JcrExecutionModulesListener implements ExecutionModulesListener { } public synchronized void executionFlowAdded(ModuleDescriptor module, - ExecutionFlowDescriptor executionFlow) { + ExecutionFlowDescriptor efd) { try { Node agentNode = session.getNode(agent.getNodePath()); Node moduleNode = agentNode.getNode(SlcJcrUtils .getModuleNodeName(module)); - String relativePath = getExecutionFlowRelativePath(executionFlow); + String relativePath = getExecutionFlowRelativePath(efd); + @SuppressWarnings("unused") Node flowNode = null; if (!moduleNode.hasNode(relativePath)) { - Iterator names = Arrays.asList(relativePath.split("/")) - .iterator(); - // create intermediary paths - Node currNode = moduleNode; - while (names.hasNext()) { - String name = names.next(); - if (currNode.hasNode(name)) - currNode = currNode.getNode(name); - else { - if (names.hasNext()) - currNode = currNode.addNode(name); - else - flowNode = currNode.addNode(name, - SlcTypes.SLC_EXECUTION_FLOW); - } - } - flowNode.setProperty(SlcNames.SLC_NAME, executionFlow.getName()); + flowNode = createExecutionFlowNode(moduleNode, relativePath, + efd); session.save(); } else { flowNode = moduleNode.getNode(relativePath); } if (log.isTraceEnabled()) - log.trace("Flow " + executionFlow + " added to JCR"); + log.trace("Flow " + efd + " added to JCR"); } catch (RepositoryException e) { JcrUtils.discardQuietly(session); - throw new SlcException("Cannot add flow " + executionFlow - + " from module " + module, e); + throw new SlcException("Cannot add flow " + efd + " from module " + + module, e); + } + + } + + protected Node createExecutionFlowNode(Node moduleNode, + String relativePath, ExecutionFlowDescriptor efd) + throws RepositoryException { + Node flowNode = null; + Iterator names = Arrays.asList(relativePath.split("/")) + .iterator(); + // create intermediary paths + Node currNode = moduleNode; + while (names.hasNext()) { + String name = names.next(); + if (currNode.hasNode(name)) + currNode = currNode.getNode(name); + else { + if (names.hasNext()) + currNode = currNode.addNode(name); + else + flowNode = currNode.addNode(name, + SlcTypes.SLC_EXECUTION_FLOW); + } } + flowNode.setProperty(SLC_NAME, efd.getName()); + String[] tokens = relativePath.split("/"); + flowNode.setProperty(Property.JCR_TITLE, tokens[tokens.length - 1]); + if (efd.getDescription() != null + && efd.getDescription().trim().equals("")) + flowNode.setProperty(Property.JCR_DESCRIPTION, efd.getDescription()); + // execution spec + ExecutionSpec executionSpec = efd.getExecutionSpec(); + String esName = executionSpec.getName(); + if (esName != null && !esName.equals(ExecutionSpec.INTERNAL_NAME)) { + Node executionSpecsNode = moduleNode.hasNode(SLC_EXECUTION_SPECS) ? moduleNode + .getNode(SLC_EXECUTION_SPECS) : moduleNode + .addNode(SLC_EXECUTION_SPECS); + Node executionSpecNode = executionSpecsNode.addNode(esName, + SlcTypes.SLC_EXECUTION_SPEC); + executionSpecNode.setProperty(Property.JCR_TITLE, esName); + if (executionSpec.getDescription() != null + && !executionSpec.getDescription().trim().equals("")) + executionSpecNode.setProperty(Property.JCR_DESCRIPTION, + executionSpec.getDescription()); + mapExecutionSpec(executionSpecNode, executionSpec); + } else { + mapExecutionSpec(flowNode, executionSpec); + } + return flowNode; + } + + /** + * Base can be either an execution spec node, or an execution flow node (in + * case the execution spec is internal) + */ + protected void mapExecutionSpec(Node baseNode, ExecutionSpec executionSpec) + throws RepositoryException { + for (String attrName : executionSpec.getAttributes().keySet()) { + ExecutionSpecAttribute esa = executionSpec.getAttributes().get( + attrName); + Node attrNode = baseNode.addNode(attrName); + // booleans + attrNode.addMixin(SlcTypes.SLC_EXECUTION_SPEC_ATTRIBUTE); + attrNode.setProperty(SLC_IS_IMMUTABLE, esa.getIsImmutable()); + attrNode.setProperty(SLC_IS_CONSTANT, esa.getIsConstant()); + attrNode.setProperty(SLC_IS_HIDDEN, esa.getIsHidden()); + + if (esa instanceof PrimitiveSpecAttribute) { + attrNode.addMixin(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE); + PrimitiveSpecAttribute psa = (PrimitiveSpecAttribute) esa; + SlcJcrUtils.setPrimitiveAsProperty(attrNode, SLC_VALUE, psa); + attrNode.setProperty(SLC_TYPE, psa.getType()); + } else if (esa instanceof RefSpecAttribute) { + attrNode.addMixin(SlcTypes.SLC_REF_SPEC_ATTRIBUTE); + RefSpecAttribute rsa = (RefSpecAttribute) esa; + attrNode.setProperty(SLC_TYPE, rsa.getTargetClassName()); + if (rsa.getChoices() != null) { + for (RefValueChoice choice : rsa.getChoices()) { + Node choiceNode = attrNode.addNode(choice.getName()); + choiceNode.addMixin(NodeType.MIX_TITLE); + choiceNode.setProperty(Property.JCR_TITLE, + choice.getName()); + if (choice.getDescription() != null + && !choice.getDescription().trim().equals("")) + choiceNode.setProperty(Property.JCR_DESCRIPTION, + choice.getDescription()); + } + } + } + } } public synchronized void executionFlowRemoved(ModuleDescriptor module, diff --git a/runtime/org.argeo.slc.support.jcr/src/main/resources/org/argeo/slc/jcr/slc.cnd b/runtime/org.argeo.slc.support.jcr/src/main/resources/org/argeo/slc/jcr/slc.cnd index 6b79bc9c4..3bdf51ce9 100644 --- a/runtime/org.argeo.slc.support.jcr/src/main/resources/org/argeo/slc/jcr/slc.cnd +++ b/runtime/org.argeo.slc.support.jcr/src/main/resources/org/argeo/slc/jcr/slc.cnd @@ -22,8 +22,34 @@ mixin [slc:executionModule] > slc:activableModule mixin +[slc:executionSpec] > nt:unstructured, mix:referenceable, mix:title +- slc:name (STRING) ++ * (slc:executionSpecAttribute) * + +[slc:executionSpecAttribute] > nt:base +mixin abstract +- slc:isImmutable (BOOLEAN) m +- slc:isConstant (BOOLEAN) m +- slc:isHidden (BOOLEAN) m + +[slc:primitiveSpecAttribute] > slc:executionSpecAttribute +mixin +- slc:type (STRING) m +- slc:value (UNDEFINED) + +[slc:refSpecAttribute] > slc:executionSpecAttribute +mixin +// typically a class name +- slc:type (STRING) ++ slc:value ++ * (mix:title) + [slc:executionFlow] > nt:unstructured, mix:title - slc:name (STRING) m +// if the execution spec is a referenceable node +- slc:executionSpec (REFERENCE) +// if the execution spec is internal (without name) ++ * (slc:executionSpecAttribute) * // PROCESS [slc:process] > nt:unstructured, mix:created, mix:lastModified