From 3781dcd363f0f6265fae0ac758fd40cf4254ebc9 Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Wed, 20 Apr 2011 18:20:06 +0000 Subject: [PATCH] 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 --- .../icons/agentFactory.gif | Bin 0 -> 568 bytes .../org.argeo.slc.client.ui/icons/choices.gif | Bin 0 -> 111 bytes .../icons/executionSpec.gif | Bin 0 -> 587 bytes .../icons/executionSpecAttribute.gif | Bin 0 -> 186 bytes .../icons/executionSpecs.gif | Bin 0 -> 387 bytes .../icons/process_completed.png | Bin 0 -> 267 bytes .../icons/process_error.png | Bin 0 -> 477 bytes .../icons/process_running.png | Bin 0 -> 355 bytes .../icons/process_scheduled.gif | Bin 0 -> 612 bytes .../org/argeo/slc/client/ui/SlcImages.java | 9 ++ .../ui/views/JcrExecutionModulesView.java | 117 +++++++++------ .../client/ui/views/JcrProcessListView.java | 28 +++- .../execution/AbstractExecutionValue.java | 4 +- .../core/execution/AbstractSpecAttribute.java | 44 ++++-- .../core/execution/DefaultExecutionSpec.java | 12 +- .../slc/core/execution/PrimitiveAccessor.java | 1 + .../slc/core/execution/PrimitiveUtils.java | 2 +- .../slc/core/execution/PrimitiveValue.java | 1 + .../argeo/slc/core/execution/RefValue.java | 1 + .../slc/core/execution/RefValueChoice.java | 1 + .../argeo/slc/execution/ExecutionSpec.java | 16 ++- .../slc/execution/ExecutionSpecAttribute.java | 41 ++++-- .../java/org/argeo/slc/jcr/SlcJcrUtils.java | 41 ++++++ .../main/java/org/argeo/slc/jcr/SlcNames.java | 8 +- .../main/java/org/argeo/slc/jcr/SlcTypes.java | 5 + .../JcrExecutionModulesListener.java | 134 ++++++++++++++---- .../main/resources/org/argeo/slc/jcr/slc.cnd | 26 ++++ 27 files changed, 393 insertions(+), 98 deletions(-) create mode 100644 eclipse/plugins/org.argeo.slc.client.ui/icons/agentFactory.gif create mode 100644 eclipse/plugins/org.argeo.slc.client.ui/icons/choices.gif create mode 100644 eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpec.gif create mode 100644 eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpecAttribute.gif create mode 100644 eclipse/plugins/org.argeo.slc.client.ui/icons/executionSpecs.gif create mode 100644 eclipse/plugins/org.argeo.slc.client.ui/icons/process_completed.png create mode 100644 eclipse/plugins/org.argeo.slc.client.ui/icons/process_error.png create mode 100644 eclipse/plugins/org.argeo.slc.client.ui/icons/process_running.png create mode 100644 eclipse/plugins/org.argeo.slc.client.ui/icons/process_scheduled.gif 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 0000000000000000000000000000000000000000..b51ae39b8ae4cb2db729d93a7b77a64cdb239423 GIT binary patch literal 568 zcmZ?wbhEHb6krfwc*el+|KI-u+b`_ce)9CWkGu9<+`RL~!es|eoO`=v$C*vL?yg*a z>ci*%i&mXDdhYG&O{bQwJ~U&|!F?xQ&04g3;mX4cR~|Zl?d_$TAC6r3wC&)7gJ)jP zUAkxP(%rKc?>ut$#oDcBk6(Cs;pXRK=byj-{Qtw3|GSRAn6YTrk#o;aUV3@z>f8ON z9v(jb^!xAspML%S{^$Sa-~Ye;`Tzaz|6l)sj{3jt)rD;@&-*MX@>^QOFoA)gpP_qd z!K67AwH>hyU5VXObNgo&PMB5FH>0R`T4Dc;;_fL0ljoFAm{~e`PQ|3zub>)mOGi;tOGD<-B0qg~P6-w1S2O$! m6$B;4MLzdAunS4?_#`B>PHm8lToJJHP_y9b_9iAq25SH$B>DsZ literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..da2f577137cada9486475d3f7492eefc82525817 GIT binary patch literal 111 zcmV-#0FeJjNk%w1VGsZi0HOc@w7b!xuE>$4$46<80Y-WOKW+d2{{R30A^8LW000I6 zEC2ui01yBW0009tXu90~Fv__|vk#Z8FcX7OEaM~!>`vLe|`M= z`}zA{Uw{1h_Vdrr-+zDq`TP9iyF0I+oqv4WYFbRfy4s|5b*UR03%7S0P7Ky-_cfgo zZaFE^X?CJ*f0XBf4A-fNzVovJm*j^oDhQgB8!#g)dR0aIn(CM(Wsx%rGB!2mZfS4Z zHPd}=%DMALXUv#5dshFyzwehVY`=Sb*W&qI^XK$#T~)VXdE@FOt$)9qKfbl_$mZgM z8_V~utK7M!`tRrSTPG@Sous^Ly4s)Ti|18}Eo+oo)+DvGNork}{O`NXGfRa3|NqZ0 zxPjtN7DfgJF9scuGeL2}z`mlvtEsuAwXNN;#j?An+sMe#ptH%6W!iKWetQQ42Ztsr z25~`#rOfUY7ItE6^md0s pO_D7cA}1OW53>tth>0z5d~vj~Tf%ss!jnadkN3;6vobMQ0{{{r%rSrQc6R2{!{wbDd*|$Jn!G)?c@3jml}<``cK^~< zt5&tNv@|p{)YjHkRaK>=r2PN?pMhwg_>+Z^fkBW#2c!dJCj+Z_f=XXX=DdtmeF4I@ z7j`-DY*{mr+44useO1<#qM1iLxLEWSd1!=t9x2vj;$UiSYAje#wf{jN2ZJ>L&XPG% literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0b63124d84c4aaace21bd218af89c32f311033e4 GIT binary patch literal 387 zcmZ?wbhEHb6krfwxXQrrxWSy(??~em=i-qVm>B z%Dbkk{dvB4UZvQwMyX{@QcIhp)^*AMzS}&rMEL*z{|tnH;!hSv1_l!b9gsqhpBUH{ zILs>W(7EJtBBf}DR2SQY7fvcMv9q>Zd~mQqPfRV!t2A(BhAe~l0kMXp`TSg8J0}W= zurW7&nUi3kqpxS8%Ec!v%;nDjGURhnOVj{uDvWu;)ql=GA)kN%wn55#AX)|U>yO}Ilv}B3Qxi#xHh_XtZ+p&vf QC!55%qfd^QI5JoR03ive1ONa4 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..0ad64e7367e543dfca4238851e23ca6b38df6934 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!73?$#)eFPFP2=EDUef;`|e}Mo0|Np;#|Gs(i z=Jo5>S5{W0r>A>*dIAN3s?b2wuXC0_A+C}jzhIyO2w>QBM&~?GlrhQM-GyIb7sE{; zhqJ&VvKUBvfU(=jY&#$$&eO#)gyVYh3{F;_1S3P?LmA=%?^%qwrif@c_GCHubjUhT##kEa hpfgvkEyWt>!LD|*+oczsxq&t@c)I$ztaD0e0suDuSyuo6 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..e66c98e50249b2b4a312e406d1c5491fab95c7df GIT binary patch literal 477 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbMffdHQn*RT0SU)wvr<`sR(D}J3@ z__eD3u2;xC@8J9X;U6QDKP6_I(=b1$X>rlQ^{#{OC-11&p$T6Sa_?jooeO>_45U54*zIJt9gxxD z>Eak7ak=*VMZP8j9@Yz;!3kDu&UX(SbSwY+KR(3iakHUG?aPzCm%Fa}cmAJnT#+aF zpA+BZPch3TNEXeQ7<6dQDXwi@EgW4_?>d}zVkpsBa&N(VIlh8(rMBu(&JBjkp0?z2 zd|m#!t^9}el%ST&S3k@C3p&+ov)(xV)!KcTugmLhHk-Fhk=x4iUOg1(9tKZWKbLh* G2~7Z8+`|e0 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..471c0918dd8ab66d44c93ffc3574f9fc533371c4 GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbK}LV!<*YtPb4htJ(zv-@01+cE~f zUIv>yhS2E@emx9swg3Om|9?Mz|9t!Zzd!unZ$GQI`2KwRJYUsATb9hp2n(?=`2YVu z&=~wc;GLWUP=#nokY6xRJqBRVzFGSUsDLra+ucQ;l~-Udki%Kv5m^kRJ;2!QWVRiU zQSIsC7$R{ww*Mkus{x1e#g`$^WY+!rzuk&W&wP4&o5|V6OP|e`7`1QBbTv(0ZtK&} z!Pl{3V~*71BWG4h8@iqS+}a&@GV+AvaxTlYO50towOq{eTsq}k!7W{lzo!<|*7Mx@ z{&K<3+Ej_PZ*O1XUGBTEbVHF_^kJJ@|ITqwSRErdjey_KcUuuYd=bhLwjxQ>v)oTJXIzS_mc+{?z=%h%-EJd;jC zmsLTMQb?LvN}F3vmR(?{a8{CIai#VN@P5H7J6Miy=aBbaQNCIwFjMDm-g$cXDrSYB?*HGG1s&d3JDV zWn?y&IAC8}d3ktsW>q7X8ck7JwRvY_GZ~j4N<>+;S4BWQ9hWpaOjdbMMoUL7C6_-e zQe9V5P*_1QTm}UL0RVa@Ej~j?PB$+Mmy0PR8yFlWTomX*aDadScX}2?sF0vSg$oJt y2}%ILL4yPq7!E9WP>_NL5++D!KtZ5H1{f` 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 -- 2.39.2