1 package org
.argeo
.slc
.jcr
.execution
;
3 import java
.util
.Arrays
;
4 import java
.util
.Iterator
;
7 import javax
.jcr
.NodeIterator
;
8 import javax
.jcr
.Property
;
9 import javax
.jcr
.RepositoryException
;
10 import javax
.jcr
.Session
;
11 import javax
.jcr
.nodetype
.NodeType
;
13 import org
.apache
.commons
.logging
.Log
;
14 import org
.apache
.commons
.logging
.LogFactory
;
15 import org
.argeo
.jcr
.JcrUtils
;
16 import org
.argeo
.slc
.SlcException
;
17 import org
.argeo
.slc
.core
.execution
.PrimitiveSpecAttribute
;
18 import org
.argeo
.slc
.core
.execution
.RefSpecAttribute
;
19 import org
.argeo
.slc
.core
.execution
.RefValueChoice
;
20 import org
.argeo
.slc
.deploy
.ModuleDescriptor
;
21 import org
.argeo
.slc
.execution
.ExecutionFlowDescriptor
;
22 import org
.argeo
.slc
.execution
.ExecutionModulesListener
;
23 import org
.argeo
.slc
.execution
.ExecutionSpec
;
24 import org
.argeo
.slc
.execution
.ExecutionSpecAttribute
;
25 import org
.argeo
.slc
.jcr
.SlcJcrUtils
;
26 import org
.argeo
.slc
.jcr
.SlcNames
;
27 import org
.argeo
.slc
.jcr
.SlcTypes
;
30 * Synchronizes the local execution runtime with a JCR repository. For the time
31 * being the state is completely reset from one start to another.
33 public class JcrExecutionModulesListener
implements ExecutionModulesListener
,
35 private final static Log log
= LogFactory
36 .getLog(JcrExecutionModulesListener
.class);
37 private JcrAgent agent
;
40 * We don't use a thread bound session because many different threads will
41 * call this critical component and we don't want to login each time. We
42 * therefore rather protect access to this session via synchronized.
44 private Session session
;
53 public void dispose() {
58 protected synchronized void clearAgent() {
60 Node agentNode
= session
.getNode(agent
.getNodePath());
61 for (NodeIterator nit
= agentNode
.getNodes(); nit
.hasNext();)
62 nit
.nextNode().remove();
64 } catch (RepositoryException e
) {
65 JcrUtils
.discardQuietly(session
);
66 throw new SlcException("Cannot clear agent " + agent
, e
);
71 * EXECUTION MODULES LISTENER
73 public synchronized void executionModuleAdded(
74 ModuleDescriptor moduleDescriptor
) {
76 Node agentNode
= session
.getNode(agent
.getNodePath());
77 String moduleNodeName
= SlcJcrUtils
78 .getModuleNodeName(moduleDescriptor
);
79 Node moduleNode
= agentNode
.hasNode(moduleNodeName
) ? agentNode
80 .getNode(moduleNodeName
) : agentNode
81 .addNode(moduleNodeName
);
82 moduleNode
.addMixin(SlcTypes
.SLC_EXECUTION_MODULE
);
83 moduleNode
.setProperty(SLC_NAME
, moduleDescriptor
.getName());
84 moduleNode
.setProperty(SLC_VERSION
, moduleDescriptor
.getVersion());
85 moduleNode
.setProperty(Property
.JCR_TITLE
,
86 moduleDescriptor
.getTitle());
87 moduleNode
.setProperty(Property
.JCR_DESCRIPTION
,
88 moduleDescriptor
.getDescription());
90 } catch (RepositoryException e
) {
91 JcrUtils
.discardQuietly(session
);
92 throw new SlcException("Cannot add module " + moduleDescriptor
, e
);
97 public synchronized void executionModuleRemoved(
98 ModuleDescriptor moduleDescriptor
) {
100 String moduleName
= SlcJcrUtils
.getModuleNodeName(moduleDescriptor
);
101 Node agentNode
= session
.getNode(agent
.getNodePath());
102 if (agentNode
.hasNode(moduleName
))
103 agentNode
.getNode(moduleName
).remove();
104 agentNode
.getSession().save();
105 } catch (RepositoryException e
) {
106 throw new SlcException("Cannot remove module " + moduleDescriptor
,
111 public synchronized void executionFlowAdded(ModuleDescriptor module
,
112 ExecutionFlowDescriptor efd
) {
114 Node agentNode
= session
.getNode(agent
.getNodePath());
115 Node moduleNode
= agentNode
.getNode(SlcJcrUtils
116 .getModuleNodeName(module
));
117 String relativePath
= getExecutionFlowRelativePath(efd
);
118 @SuppressWarnings("unused")
119 Node flowNode
= null;
120 if (!moduleNode
.hasNode(relativePath
)) {
121 flowNode
= createExecutionFlowNode(moduleNode
, relativePath
,
125 flowNode
= moduleNode
.getNode(relativePath
);
128 if (log
.isTraceEnabled())
129 log
.trace("Flow " + efd
+ " added to JCR");
130 } catch (RepositoryException e
) {
131 JcrUtils
.discardQuietly(session
);
132 throw new SlcException("Cannot add flow " + efd
+ " from module "
138 protected Node
createExecutionFlowNode(Node moduleNode
,
139 String relativePath
, ExecutionFlowDescriptor efd
)
140 throws RepositoryException
{
141 Node flowNode
= null;
142 Iterator
<String
> names
= Arrays
.asList(relativePath
.split("/"))
144 // create intermediary paths
145 Node currNode
= moduleNode
;
146 while (names
.hasNext()) {
147 String name
= names
.next();
148 if (currNode
.hasNode(name
))
149 currNode
= currNode
.getNode(name
);
152 currNode
= currNode
.addNode(name
);
154 flowNode
= currNode
.addNode(name
,
155 SlcTypes
.SLC_EXECUTION_FLOW
);
158 flowNode
.setProperty(SLC_NAME
, efd
.getName());
159 String
[] tokens
= relativePath
.split("/");
160 flowNode
.setProperty(Property
.JCR_TITLE
, tokens
[tokens
.length
- 1]);
161 if (efd
.getDescription() != null
162 && efd
.getDescription().trim().equals(""))
163 flowNode
.setProperty(Property
.JCR_DESCRIPTION
, efd
.getDescription());
166 ExecutionSpec executionSpec
= efd
.getExecutionSpec();
167 String esName
= executionSpec
.getName();
168 if (!(esName
== null || esName
.equals(ExecutionSpec
.INTERNAL_NAME
))) {
169 Node executionSpecsNode
= moduleNode
.hasNode(SLC_EXECUTION_SPECS
) ? moduleNode
170 .getNode(SLC_EXECUTION_SPECS
) : moduleNode
171 .addNode(SLC_EXECUTION_SPECS
);
172 Node executionSpecNode
= executionSpecsNode
.addNode(esName
,
173 SlcTypes
.SLC_EXECUTION_SPEC
);
174 executionSpecNode
.setProperty(SLC_NAME
, esName
);
175 executionSpecNode
.setProperty(Property
.JCR_TITLE
, esName
);
176 if (executionSpec
.getDescription() != null
177 && !executionSpec
.getDescription().trim().equals(""))
178 executionSpecNode
.setProperty(Property
.JCR_DESCRIPTION
,
179 executionSpec
.getDescription());
180 mapExecutionSpec(executionSpecNode
, executionSpec
);
181 flowNode
.setProperty(SLC_SPEC
, executionSpecNode
);
183 mapExecutionSpec(flowNode
, executionSpec
);
189 * Base can be either an execution spec node, or an execution flow node (in
190 * case the execution spec is internal)
192 protected void mapExecutionSpec(Node baseNode
, ExecutionSpec executionSpec
)
193 throws RepositoryException
{
194 for (String attrName
: executionSpec
.getAttributes().keySet()) {
195 ExecutionSpecAttribute esa
= executionSpec
.getAttributes().get(
197 Node attrNode
= baseNode
.addNode(attrName
);
199 attrNode
.addMixin(SlcTypes
.SLC_EXECUTION_SPEC_ATTRIBUTE
);
200 attrNode
.setProperty(SLC_IS_IMMUTABLE
, esa
.getIsImmutable());
201 attrNode
.setProperty(SLC_IS_CONSTANT
, esa
.getIsConstant());
202 attrNode
.setProperty(SLC_IS_HIDDEN
, esa
.getIsHidden());
204 if (esa
instanceof PrimitiveSpecAttribute
) {
205 attrNode
.addMixin(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
);
206 PrimitiveSpecAttribute psa
= (PrimitiveSpecAttribute
) esa
;
207 SlcJcrUtils
.setPrimitiveAsProperty(attrNode
, SLC_VALUE
, psa
);
208 attrNode
.setProperty(SLC_TYPE
, psa
.getType());
209 } else if (esa
instanceof RefSpecAttribute
) {
210 attrNode
.addMixin(SlcTypes
.SLC_REF_SPEC_ATTRIBUTE
);
211 RefSpecAttribute rsa
= (RefSpecAttribute
) esa
;
212 attrNode
.setProperty(SLC_TYPE
, rsa
.getTargetClassName());
213 if (rsa
.getChoices() != null) {
214 for (RefValueChoice choice
: rsa
.getChoices()) {
215 Node choiceNode
= attrNode
.addNode(choice
.getName());
216 choiceNode
.addMixin(NodeType
.MIX_TITLE
);
217 choiceNode
.setProperty(Property
.JCR_TITLE
,
219 if (choice
.getDescription() != null
220 && !choice
.getDescription().trim().equals(""))
221 choiceNode
.setProperty(Property
.JCR_DESCRIPTION
,
222 choice
.getDescription());
229 public synchronized void executionFlowRemoved(ModuleDescriptor module
,
230 ExecutionFlowDescriptor executionFlow
) {
232 Node agentNode
= session
.getNode(agent
.getNodePath());
233 Node moduleNode
= agentNode
.getNode(SlcJcrUtils
234 .getModuleNodeName(module
));
235 String relativePath
= getExecutionFlowRelativePath(executionFlow
);
236 if (!moduleNode
.hasNode(relativePath
))
237 moduleNode
.getNode(relativePath
).remove();
238 agentNode
.getSession().save();
239 } catch (RepositoryException e
) {
240 throw new SlcException("Cannot remove flow " + executionFlow
241 + " from module " + module
, e
);
248 /** @return the relative path, never starts with '/' */
249 @SuppressWarnings("deprecation")
250 protected String
getExecutionFlowRelativePath(
251 ExecutionFlowDescriptor executionFlow
) {
252 String relativePath
= executionFlow
.getPath() == null ? executionFlow
253 .getName() : executionFlow
.getPath() + '/'
254 + executionFlow
.getName();
255 // we assume that it is more than one char long
256 if (relativePath
.charAt(0) == '/')
257 relativePath
= relativePath
.substring(1);
258 // FIXME quick hack to avoid duplicate '/'
259 relativePath
= relativePath
.replaceAll("//", "/");
266 public void setAgent(JcrAgent agent
) {
270 /** Expects a non-shared session with admin authorization */
271 public void setSession(Session session
) {
272 this.session
= session
;