1 package org
.argeo
.slc
.jcr
.execution
;
3 import java
.util
.Arrays
;
4 import java
.util
.Iterator
;
8 import javax
.jcr
.NodeIterator
;
9 import javax
.jcr
.Property
;
10 import javax
.jcr
.Repository
;
11 import javax
.jcr
.RepositoryException
;
12 import javax
.jcr
.Session
;
13 import javax
.jcr
.nodetype
.NodeType
;
15 import org
.apache
.commons
.logging
.Log
;
16 import org
.apache
.commons
.logging
.LogFactory
;
17 import org
.argeo
.jcr
.JcrUtils
;
18 import org
.argeo
.slc
.SlcException
;
19 import org
.argeo
.slc
.SlcNames
;
20 import org
.argeo
.slc
.SlcTypes
;
21 import org
.argeo
.slc
.deploy
.ModuleDescriptor
;
22 import org
.argeo
.slc
.execution
.ExecutionFlowDescriptor
;
23 import org
.argeo
.slc
.execution
.ExecutionModuleDescriptor
;
24 import org
.argeo
.slc
.execution
.ExecutionModulesListener
;
25 import org
.argeo
.slc
.execution
.ExecutionModulesManager
;
26 import org
.argeo
.slc
.execution
.ExecutionSpec
;
27 import org
.argeo
.slc
.execution
.ExecutionSpecAttribute
;
28 import org
.argeo
.slc
.execution
.RefSpecAttribute
;
29 import org
.argeo
.slc
.execution
.RefValueChoice
;
30 import org
.argeo
.slc
.jcr
.SlcJcrUtils
;
31 import org
.argeo
.slc
.primitive
.PrimitiveSpecAttribute
;
32 import org
.argeo
.slc
.primitive
.PrimitiveValue
;
35 * Synchronizes the local execution runtime with a JCR repository. For the time
36 * being the state is completely reset from one start to another.
38 public class JcrExecutionModulesListener
implements ExecutionModulesListener
,
40 private final static String SLC_EXECUTION_MODULES_PROPERTY
= "slc.executionModules";
42 private final static Log log
= LogFactory
43 .getLog(JcrExecutionModulesListener
.class);
44 private JcrAgent agent
;
46 private ExecutionModulesManager modulesManager
;
48 private Repository repository
;
50 * We don't use a thread bound session because many different threads will
51 * call this critical component and we don't want to login each time. We
52 * therefore rather protect access to this session via synchronized.
54 private Session session
;
61 session
= repository
.login();
63 if (modulesManager
!= null) {
64 Node agentNode
= session
.getNode(agent
.getNodePath());
66 List
<ModuleDescriptor
> moduleDescriptors
= modulesManager
69 // scan SLC-ExecutionModule metadata
70 for (ModuleDescriptor md
: moduleDescriptors
) {
71 if (md
.getMetadata().containsKey(
72 ExecutionModuleDescriptor
.SLC_EXECUTION_MODULE
)) {
73 String moduleNodeName
= SlcJcrUtils
74 .getModuleNodeName(md
);
75 Node moduleNode
= agentNode
.hasNode(moduleNodeName
) ? agentNode
76 .getNode(moduleNodeName
) : agentNode
77 .addNode(moduleNodeName
);
78 moduleNode
.addMixin(SlcTypes
.SLC_EXECUTION_MODULE
);
79 moduleNode
.setProperty(SLC_NAME
, md
.getName());
80 moduleNode
.setProperty(SLC_VERSION
, md
.getVersion());
81 moduleNode
.setProperty(Property
.JCR_TITLE
,
83 moduleNode
.setProperty(Property
.JCR_DESCRIPTION
,
85 moduleNode
.setProperty(SLC_STARTED
, md
.getStarted());
89 // scan execution modules property
90 String executionModules
= System
91 .getProperty(SLC_EXECUTION_MODULES_PROPERTY
);
92 if (executionModules
!= null) {
93 for (String executionModule
: executionModules
.split(",")) {
94 allModules
: for (ModuleDescriptor md
: moduleDescriptors
) {
95 String moduleNodeName
= SlcJcrUtils
96 .getModuleNodeName(md
);
97 if (md
.getName().equals(executionModule
)) {
98 Node moduleNode
= agentNode
99 .hasNode(moduleNodeName
) ? agentNode
100 .getNode(moduleNodeName
) : agentNode
101 .addNode(moduleNodeName
);
103 .addMixin(SlcTypes
.SLC_EXECUTION_MODULE
);
104 moduleNode
.setProperty(SLC_NAME
, md
.getName());
105 moduleNode
.setProperty(SLC_VERSION
,
107 moduleNode
.setProperty(Property
.JCR_TITLE
,
109 moduleNode
.setProperty(
110 Property
.JCR_DESCRIPTION
,
111 md
.getDescription());
112 moduleNode
.setProperty(SLC_STARTED
,
120 if (session
.hasPendingChanges())
124 } catch (RepositoryException e
) {
125 JcrUtils
.discardQuietly(session
);
126 JcrUtils
.logoutQuietly(session
);
127 throw new SlcException("Cannot initialize modules", e
);
131 public void destroy() {
133 JcrUtils
.logoutQuietly(session
);
136 protected synchronized void clearAgent() {
138 Node agentNode
= session
.getNode(agent
.getNodePath());
139 for (NodeIterator nit
= agentNode
.getNodes(); nit
.hasNext();)
140 nit
.nextNode().remove();
142 } catch (RepositoryException e
) {
143 JcrUtils
.discardQuietly(session
);
144 throw new SlcException("Cannot clear agent " + agent
, e
);
149 * EXECUTION MODULES LISTENER
152 public synchronized void executionModuleAdded(
153 ModuleDescriptor moduleDescriptor
) {
154 syncExecutionModule(moduleDescriptor
);
157 protected void syncExecutionModule(ModuleDescriptor moduleDescriptor
) {
159 Node agentNode
= session
.getNode(agent
.getNodePath());
160 String moduleNodeName
= SlcJcrUtils
161 .getModuleNodeName(moduleDescriptor
);
162 Node moduleNode
= agentNode
.hasNode(moduleNodeName
) ? agentNode
163 .getNode(moduleNodeName
) : agentNode
164 .addNode(moduleNodeName
);
165 moduleNode
.addMixin(SlcTypes
.SLC_EXECUTION_MODULE
);
166 moduleNode
.setProperty(SLC_NAME
, moduleDescriptor
.getName());
167 moduleNode
.setProperty(SLC_VERSION
, moduleDescriptor
.getVersion());
168 moduleNode
.setProperty(Property
.JCR_TITLE
,
169 moduleDescriptor
.getTitle());
170 moduleNode
.setProperty(Property
.JCR_DESCRIPTION
,
171 moduleDescriptor
.getDescription());
172 moduleNode
.setProperty(SLC_STARTED
, moduleDescriptor
.getStarted());
174 } catch (RepositoryException e
) {
175 JcrUtils
.discardQuietly(session
);
176 throw new SlcException("Cannot sync module " + moduleDescriptor
, e
);
180 public synchronized void executionModuleRemoved(
181 ModuleDescriptor moduleDescriptor
) {
183 String moduleName
= SlcJcrUtils
.getModuleNodeName(moduleDescriptor
);
184 Node agentNode
= session
.getNode(agent
.getNodePath());
185 if (agentNode
.hasNode(moduleName
)) {
186 Node moduleNode
= agentNode
.getNode(moduleName
);
187 for (NodeIterator nit
= moduleNode
.getNodes(); nit
.hasNext();) {
188 nit
.nextNode().remove();
190 moduleNode
.setProperty(SLC_STARTED
, false);
193 } catch (RepositoryException e
) {
194 JcrUtils
.discardQuietly(session
);
195 throw new SlcException("Cannot remove module " + moduleDescriptor
,
200 public synchronized void executionFlowAdded(ModuleDescriptor module
,
201 ExecutionFlowDescriptor efd
) {
203 Node agentNode
= session
.getNode(agent
.getNodePath());
204 Node moduleNode
= agentNode
.getNode(SlcJcrUtils
205 .getModuleNodeName(module
));
206 String relativePath
= getExecutionFlowRelativePath(efd
);
207 @SuppressWarnings("unused")
208 Node flowNode
= null;
209 if (!moduleNode
.hasNode(relativePath
)) {
210 flowNode
= createExecutionFlowNode(moduleNode
, relativePath
,
214 flowNode
= moduleNode
.getNode(relativePath
);
217 if (log
.isTraceEnabled())
218 log
.trace("Flow " + efd
+ " added to JCR");
219 } catch (RepositoryException e
) {
220 JcrUtils
.discardQuietly(session
);
221 throw new SlcException("Cannot add flow " + efd
+ " from module "
227 protected Node
createExecutionFlowNode(Node moduleNode
,
228 String relativePath
, ExecutionFlowDescriptor efd
)
229 throws RepositoryException
{
230 Node flowNode
= null;
231 List
<String
> pathTokens
= Arrays
.asList(relativePath
.split("/"));
233 Iterator
<String
> names
= pathTokens
.iterator();
234 // create intermediary paths
235 Node currNode
= moduleNode
;
236 while (names
.hasNext()) {
237 String name
= names
.next();
238 if (currNode
.hasNode(name
))
239 currNode
= currNode
.getNode(name
);
242 currNode
= currNode
.addNode(name
);
244 flowNode
= currNode
.addNode(name
,
245 SlcTypes
.SLC_EXECUTION_FLOW
);
250 flowNode
.setProperty(SLC_NAME
, efd
.getName());
251 String endName
= pathTokens
.get(pathTokens
.size() - 1);
252 flowNode
.setProperty(Property
.JCR_TITLE
, endName
);
253 if (efd
.getDescription() != null
254 && !efd
.getDescription().trim().equals("")) {
255 flowNode
.setProperty(Property
.JCR_DESCRIPTION
, efd
.getDescription());
257 flowNode
.setProperty(Property
.JCR_DESCRIPTION
, endName
);
261 ExecutionSpec executionSpec
= efd
.getExecutionSpec();
262 String esName
= executionSpec
.getName();
263 if (esName
== null || esName
.equals(ExecutionSpec
.INTERNAL_NAME
)
264 || esName
.contains("#")/* automatically generated bean name */) {
265 // internal spec node
266 mapExecutionSpec(flowNode
, executionSpec
);
268 // reference spec node
269 Node executionSpecsNode
= moduleNode
.hasNode(SLC_EXECUTION_SPECS
) ? moduleNode
270 .getNode(SLC_EXECUTION_SPECS
) : moduleNode
271 .addNode(SLC_EXECUTION_SPECS
);
272 Node executionSpecNode
= executionSpecsNode
.addNode(esName
,
273 SlcTypes
.SLC_EXECUTION_SPEC
);
274 executionSpecNode
.setProperty(SLC_NAME
, esName
);
275 executionSpecNode
.setProperty(Property
.JCR_TITLE
, esName
);
276 if (executionSpec
.getDescription() != null
277 && !executionSpec
.getDescription().trim().equals(""))
278 executionSpecNode
.setProperty(Property
.JCR_DESCRIPTION
,
279 executionSpec
.getDescription());
280 mapExecutionSpec(executionSpecNode
, executionSpec
);
281 flowNode
.setProperty(SLC_SPEC
, executionSpecNode
);
285 for (String attr
: efd
.getValues().keySet()) {
286 ExecutionSpecAttribute esa
= executionSpec
.getAttributes()
288 if (esa
instanceof PrimitiveSpecAttribute
) {
289 PrimitiveSpecAttribute psa
= (PrimitiveSpecAttribute
) esa
;
290 // if spec reference there will be no node at this stage
291 Node valueNode
= JcrUtils
.getOrAdd(flowNode
, attr
);
292 valueNode
.setProperty(SLC_TYPE
, psa
.getType());
293 SlcJcrUtils
.setPrimitiveAsProperty(valueNode
, SLC_VALUE
,
294 (PrimitiveValue
) efd
.getValues().get(attr
));
302 * Base can be either an execution spec node, or an execution flow node (in
303 * case the execution spec is internal)
305 protected void mapExecutionSpec(Node baseNode
, ExecutionSpec executionSpec
)
306 throws RepositoryException
{
307 for (String attrName
: executionSpec
.getAttributes().keySet()) {
308 ExecutionSpecAttribute esa
= executionSpec
.getAttributes().get(
310 Node attrNode
= baseNode
.addNode(attrName
);
312 attrNode
.addMixin(SlcTypes
.SLC_EXECUTION_SPEC_ATTRIBUTE
);
313 attrNode
.setProperty(SLC_IS_IMMUTABLE
, esa
.getIsImmutable());
314 attrNode
.setProperty(SLC_IS_CONSTANT
, esa
.getIsConstant());
315 attrNode
.setProperty(SLC_IS_HIDDEN
, esa
.getIsHidden());
317 if (esa
instanceof PrimitiveSpecAttribute
) {
318 attrNode
.addMixin(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
);
319 PrimitiveSpecAttribute psa
= (PrimitiveSpecAttribute
) esa
;
320 SlcJcrUtils
.setPrimitiveAsProperty(attrNode
, SLC_VALUE
, psa
);
321 attrNode
.setProperty(SLC_TYPE
, psa
.getType());
322 } else if (esa
instanceof RefSpecAttribute
) {
323 attrNode
.addMixin(SlcTypes
.SLC_REF_SPEC_ATTRIBUTE
);
324 RefSpecAttribute rsa
= (RefSpecAttribute
) esa
;
325 attrNode
.setProperty(SLC_TYPE
, rsa
.getTargetClassName());
326 Object value
= rsa
.getValue();
327 if (rsa
.getChoices() != null) {
328 Integer index
= null;
330 for (RefValueChoice choice
: rsa
.getChoices()) {
331 String name
= choice
.getName();
332 if (value
!= null && name
.equals(value
.toString()))
334 Node choiceNode
= attrNode
.addNode(choice
.getName());
335 choiceNode
.addMixin(NodeType
.MIX_TITLE
);
336 choiceNode
.setProperty(Property
.JCR_TITLE
,
338 if (choice
.getDescription() != null
339 && !choice
.getDescription().trim().equals(""))
340 choiceNode
.setProperty(Property
.JCR_DESCRIPTION
,
341 choice
.getDescription());
346 attrNode
.setProperty(SLC_VALUE
, index
);
352 public synchronized void executionFlowRemoved(ModuleDescriptor module
,
353 ExecutionFlowDescriptor executionFlow
) {
355 Node agentNode
= session
.getNode(agent
.getNodePath());
356 Node moduleNode
= agentNode
.getNode(SlcJcrUtils
357 .getModuleNodeName(module
));
358 String relativePath
= getExecutionFlowRelativePath(executionFlow
);
359 if (moduleNode
.hasNode(relativePath
))
360 moduleNode
.getNode(relativePath
).remove();
361 agentNode
.getSession().save();
362 } catch (RepositoryException e
) {
363 throw new SlcException("Cannot remove flow " + executionFlow
364 + " from module " + module
, e
);
371 /** @return the relative path, never starts with '/' */
372 @SuppressWarnings("deprecation")
373 protected String
getExecutionFlowRelativePath(
374 ExecutionFlowDescriptor executionFlow
) {
375 String relativePath
= executionFlow
.getPath() == null ? executionFlow
376 .getName() : executionFlow
.getPath() + '/'
377 + executionFlow
.getName();
378 // we assume that it is more than one char long
379 if (relativePath
.charAt(0) == '/')
380 relativePath
= relativePath
.substring(1);
381 // FIXME quick hack to avoid duplicate '/'
382 relativePath
= relativePath
.replaceAll("//", "/");
389 public void setAgent(JcrAgent agent
) {
393 public void setRepository(Repository repository
) {
394 this.repository
= repository
;
397 public void setModulesManager(ExecutionModulesManager modulesManager
) {
398 this.modulesManager
= modulesManager
;