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
.argeo
.api
.cms
.CmsLog
;
16 import org
.argeo
.jcr
.JcrUtils
;
17 import org
.argeo
.slc
.SlcException
;
18 import org
.argeo
.slc
.SlcNames
;
19 import org
.argeo
.slc
.SlcTypes
;
20 import org
.argeo
.slc
.deploy
.ModuleDescriptor
;
21 import org
.argeo
.slc
.execution
.ExecutionFlowDescriptor
;
22 import org
.argeo
.slc
.execution
.ExecutionModuleDescriptor
;
23 import org
.argeo
.slc
.execution
.ExecutionModulesListener
;
24 import org
.argeo
.slc
.execution
.ExecutionModulesManager
;
25 import org
.argeo
.slc
.execution
.ExecutionSpec
;
26 import org
.argeo
.slc
.execution
.ExecutionSpecAttribute
;
27 import org
.argeo
.slc
.execution
.RefSpecAttribute
;
28 import org
.argeo
.slc
.execution
.RefValueChoice
;
29 import org
.argeo
.slc
.jcr
.SlcJcrUtils
;
30 import org
.argeo
.slc
.primitive
.PrimitiveSpecAttribute
;
31 import org
.argeo
.slc
.primitive
.PrimitiveValue
;
34 * Synchronizes the local execution runtime with a JCR repository. For the time
35 * being the state is completely reset from one start to another.
37 public class JcrExecutionModulesListener
implements ExecutionModulesListener
, SlcNames
{
38 private final static String SLC_EXECUTION_MODULES_PROPERTY
= "slc.executionModules";
40 private final static CmsLog log
= CmsLog
.getLog(JcrExecutionModulesListener
.class);
41 private JcrAgent agent
;
43 private ExecutionModulesManager modulesManager
;
45 private Repository repository
;
47 * We don't use a thread bound session because many different threads will call
48 * this critical component and we don't want to login each time. We therefore
49 * rather protect access to this session via synchronized.
51 private Session session
;
58 session
= repository
.login();
60 if (modulesManager
!= null) {
61 Node agentNode
= session
.getNode(agent
.getNodePath());
63 List
<ModuleDescriptor
> moduleDescriptors
= modulesManager
.listModules();
65 // scan SLC-ExecutionModule metadata
66 for (ModuleDescriptor md
: moduleDescriptors
) {
67 if (md
.getMetadata().containsKey(ExecutionModuleDescriptor
.SLC_EXECUTION_MODULE
)) {
68 String moduleNodeName
= SlcJcrUtils
.getModuleNodeName(md
);
69 Node moduleNode
= agentNode
.hasNode(moduleNodeName
) ? agentNode
.getNode(moduleNodeName
)
70 : agentNode
.addNode(moduleNodeName
);
71 moduleNode
.addMixin(SlcTypes
.SLC_EXECUTION_MODULE
);
72 moduleNode
.setProperty(SLC_NAME
, md
.getName());
73 moduleNode
.setProperty(SLC_VERSION
, md
.getVersion());
74 moduleNode
.setProperty(Property
.JCR_TITLE
, md
.getTitle());
75 moduleNode
.setProperty(Property
.JCR_DESCRIPTION
, md
.getDescription());
76 moduleNode
.setProperty(SLC_STARTED
, md
.getStarted());
80 // scan execution modules property
81 String executionModules
= System
.getProperty(SLC_EXECUTION_MODULES_PROPERTY
);
82 if (executionModules
!= null) {
83 for (String executionModule
: executionModules
.split(",")) {
84 allModules
: for (ModuleDescriptor md
: moduleDescriptors
) {
85 String moduleNodeName
= SlcJcrUtils
.getModuleNodeName(md
);
86 if (md
.getName().equals(executionModule
)) {
87 Node moduleNode
= agentNode
.hasNode(moduleNodeName
) ? agentNode
.getNode(moduleNodeName
)
88 : agentNode
.addNode(moduleNodeName
);
89 moduleNode
.addMixin(SlcTypes
.SLC_EXECUTION_MODULE
);
90 moduleNode
.setProperty(SLC_NAME
, md
.getName());
91 moduleNode
.setProperty(SLC_VERSION
, md
.getVersion());
92 moduleNode
.setProperty(Property
.JCR_TITLE
, md
.getTitle());
93 moduleNode
.setProperty(Property
.JCR_DESCRIPTION
, md
.getDescription());
94 moduleNode
.setProperty(SLC_STARTED
, md
.getStarted());
101 if (session
.hasPendingChanges())
105 } catch (RepositoryException e
) {
106 JcrUtils
.discardQuietly(session
);
107 JcrUtils
.logoutQuietly(session
);
108 throw new SlcException("Cannot initialize modules", e
);
112 public void destroy() {
114 JcrUtils
.logoutQuietly(session
);
117 protected synchronized void clearAgent() {
119 Node agentNode
= session
.getNode(agent
.getNodePath());
120 for (NodeIterator nit
= agentNode
.getNodes(); nit
.hasNext();)
121 nit
.nextNode().remove();
123 } catch (RepositoryException e
) {
124 JcrUtils
.discardQuietly(session
);
125 throw new SlcException("Cannot clear agent " + agent
, e
);
130 * EXECUTION MODULES LISTENER
133 public synchronized void executionModuleAdded(ModuleDescriptor moduleDescriptor
) {
134 syncExecutionModule(moduleDescriptor
);
137 protected void syncExecutionModule(ModuleDescriptor moduleDescriptor
) {
139 Node agentNode
= session
.getNode(agent
.getNodePath());
140 String moduleNodeName
= SlcJcrUtils
.getModuleNodeName(moduleDescriptor
);
141 Node moduleNode
= agentNode
.hasNode(moduleNodeName
) ? agentNode
.getNode(moduleNodeName
)
142 : agentNode
.addNode(moduleNodeName
);
143 moduleNode
.addMixin(SlcTypes
.SLC_EXECUTION_MODULE
);
144 moduleNode
.setProperty(SLC_NAME
, moduleDescriptor
.getName());
145 moduleNode
.setProperty(SLC_VERSION
, moduleDescriptor
.getVersion());
146 moduleNode
.setProperty(Property
.JCR_TITLE
, moduleDescriptor
.getTitle());
147 moduleNode
.setProperty(Property
.JCR_DESCRIPTION
, moduleDescriptor
.getDescription());
148 moduleNode
.setProperty(SLC_STARTED
, moduleDescriptor
.getStarted());
150 } catch (RepositoryException e
) {
151 JcrUtils
.discardQuietly(session
);
152 throw new SlcException("Cannot sync module " + moduleDescriptor
, e
);
156 public synchronized void executionModuleRemoved(ModuleDescriptor moduleDescriptor
) {
158 String moduleName
= SlcJcrUtils
.getModuleNodeName(moduleDescriptor
);
159 Node agentNode
= session
.getNode(agent
.getNodePath());
160 if (agentNode
.hasNode(moduleName
)) {
161 Node moduleNode
= agentNode
.getNode(moduleName
);
162 for (NodeIterator nit
= moduleNode
.getNodes(); nit
.hasNext();) {
163 nit
.nextNode().remove();
165 moduleNode
.setProperty(SLC_STARTED
, false);
168 } catch (RepositoryException e
) {
169 JcrUtils
.discardQuietly(session
);
170 throw new SlcException("Cannot remove module " + moduleDescriptor
, e
);
174 public synchronized void executionFlowAdded(ModuleDescriptor module
, ExecutionFlowDescriptor efd
) {
176 Node agentNode
= session
.getNode(agent
.getNodePath());
177 Node moduleNode
= agentNode
.getNode(SlcJcrUtils
.getModuleNodeName(module
));
178 String relativePath
= getExecutionFlowRelativePath(efd
);
179 @SuppressWarnings("unused")
180 Node flowNode
= null;
181 if (!moduleNode
.hasNode(relativePath
)) {
182 flowNode
= createExecutionFlowNode(moduleNode
, relativePath
, efd
);
185 flowNode
= moduleNode
.getNode(relativePath
);
188 if (log
.isTraceEnabled())
189 log
.trace("Flow " + efd
+ " added to JCR");
190 } catch (RepositoryException e
) {
191 JcrUtils
.discardQuietly(session
);
192 throw new SlcException("Cannot add flow " + efd
+ " from module " + module
, e
);
197 protected Node
createExecutionFlowNode(Node moduleNode
, String relativePath
, ExecutionFlowDescriptor efd
)
198 throws RepositoryException
{
199 Node flowNode
= null;
200 List
<String
> pathTokens
= Arrays
.asList(relativePath
.split("/"));
202 Iterator
<String
> names
= pathTokens
.iterator();
203 // create intermediary paths
204 Node currNode
= moduleNode
;
205 while (names
.hasNext()) {
206 String name
= names
.next();
207 if (currNode
.hasNode(name
))
208 currNode
= currNode
.getNode(name
);
211 currNode
= currNode
.addNode(name
);
213 flowNode
= currNode
.addNode(name
, SlcTypes
.SLC_EXECUTION_FLOW
);
218 flowNode
.setProperty(SLC_NAME
, efd
.getName());
219 String endName
= pathTokens
.get(pathTokens
.size() - 1);
220 flowNode
.setProperty(Property
.JCR_TITLE
, endName
);
221 if (efd
.getDescription() != null && !efd
.getDescription().trim().equals("")) {
222 flowNode
.setProperty(Property
.JCR_DESCRIPTION
, efd
.getDescription());
224 flowNode
.setProperty(Property
.JCR_DESCRIPTION
, endName
);
228 ExecutionSpec executionSpec
= efd
.getExecutionSpec();
229 String esName
= executionSpec
.getName();
230 if (esName
== null || esName
.equals(ExecutionSpec
.INTERNAL_NAME
)
231 || esName
.contains("#")/* automatically generated bean name */) {
232 // internal spec node
233 mapExecutionSpec(flowNode
, executionSpec
);
235 // reference spec node
236 Node executionSpecsNode
= moduleNode
.hasNode(SLC_EXECUTION_SPECS
) ? moduleNode
.getNode(SLC_EXECUTION_SPECS
)
237 : moduleNode
.addNode(SLC_EXECUTION_SPECS
);
238 Node executionSpecNode
= executionSpecsNode
.addNode(esName
, SlcTypes
.SLC_EXECUTION_SPEC
);
239 executionSpecNode
.setProperty(SLC_NAME
, esName
);
240 executionSpecNode
.setProperty(Property
.JCR_TITLE
, esName
);
241 if (executionSpec
.getDescription() != null && !executionSpec
.getDescription().trim().equals(""))
242 executionSpecNode
.setProperty(Property
.JCR_DESCRIPTION
, executionSpec
.getDescription());
243 mapExecutionSpec(executionSpecNode
, executionSpec
);
244 flowNode
.setProperty(SLC_SPEC
, executionSpecNode
);
248 for (String attr
: efd
.getValues().keySet()) {
249 ExecutionSpecAttribute esa
= executionSpec
.getAttributes().get(attr
);
250 if (esa
instanceof PrimitiveSpecAttribute
) {
251 PrimitiveSpecAttribute psa
= (PrimitiveSpecAttribute
) esa
;
252 // if spec reference there will be no node at this stage
253 Node valueNode
= JcrUtils
.getOrAdd(flowNode
, attr
);
254 valueNode
.setProperty(SLC_TYPE
, psa
.getType());
255 SlcJcrUtils
.setPrimitiveAsProperty(valueNode
, SLC_VALUE
, (PrimitiveValue
) efd
.getValues().get(attr
));
263 * Base can be either an execution spec node, or an execution flow node (in case
264 * the execution spec is internal)
266 protected void mapExecutionSpec(Node baseNode
, ExecutionSpec executionSpec
) throws RepositoryException
{
267 for (String attrName
: executionSpec
.getAttributes().keySet()) {
268 ExecutionSpecAttribute esa
= executionSpec
.getAttributes().get(attrName
);
269 Node attrNode
= baseNode
.addNode(attrName
);
271 attrNode
.addMixin(SlcTypes
.SLC_EXECUTION_SPEC_ATTRIBUTE
);
272 attrNode
.setProperty(SLC_IS_IMMUTABLE
, esa
.getIsImmutable());
273 attrNode
.setProperty(SLC_IS_CONSTANT
, esa
.getIsConstant());
274 attrNode
.setProperty(SLC_IS_HIDDEN
, esa
.getIsHidden());
276 if (esa
instanceof PrimitiveSpecAttribute
) {
277 attrNode
.addMixin(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
);
278 PrimitiveSpecAttribute psa
= (PrimitiveSpecAttribute
) esa
;
279 SlcJcrUtils
.setPrimitiveAsProperty(attrNode
, SLC_VALUE
, psa
);
280 attrNode
.setProperty(SLC_TYPE
, psa
.getType());
281 } else if (esa
instanceof RefSpecAttribute
) {
282 attrNode
.addMixin(SlcTypes
.SLC_REF_SPEC_ATTRIBUTE
);
283 RefSpecAttribute rsa
= (RefSpecAttribute
) esa
;
284 attrNode
.setProperty(SLC_TYPE
, rsa
.getTargetClassName());
285 Object value
= rsa
.getValue();
286 if (rsa
.getChoices() != null) {
287 Integer index
= null;
289 for (RefValueChoice choice
: rsa
.getChoices()) {
290 String name
= choice
.getName();
291 if (value
!= null && name
.equals(value
.toString()))
293 Node choiceNode
= attrNode
.addNode(choice
.getName());
294 choiceNode
.addMixin(NodeType
.MIX_TITLE
);
295 choiceNode
.setProperty(Property
.JCR_TITLE
, choice
.getName());
296 if (choice
.getDescription() != null && !choice
.getDescription().trim().equals(""))
297 choiceNode
.setProperty(Property
.JCR_DESCRIPTION
, choice
.getDescription());
302 attrNode
.setProperty(SLC_VALUE
, index
);
308 public synchronized void executionFlowRemoved(ModuleDescriptor module
, ExecutionFlowDescriptor executionFlow
) {
310 Node agentNode
= session
.getNode(agent
.getNodePath());
311 Node moduleNode
= agentNode
.getNode(SlcJcrUtils
.getModuleNodeName(module
));
312 String relativePath
= getExecutionFlowRelativePath(executionFlow
);
313 if (moduleNode
.hasNode(relativePath
))
314 moduleNode
.getNode(relativePath
).remove();
315 agentNode
.getSession().save();
316 } catch (RepositoryException e
) {
317 throw new SlcException("Cannot remove flow " + executionFlow
+ " from module " + module
, e
);
324 /** @return the relative path, never starts with '/' */
325 @SuppressWarnings("deprecation")
326 protected String
getExecutionFlowRelativePath(ExecutionFlowDescriptor executionFlow
) {
327 String relativePath
= executionFlow
.getPath() == null ? executionFlow
.getName()
328 : executionFlow
.getPath() + '/' + executionFlow
.getName();
329 // we assume that it is more than one char long
330 if (relativePath
.charAt(0) == '/')
331 relativePath
= relativePath
.substring(1);
332 // FIXME quick hack to avoid duplicate '/'
333 relativePath
= relativePath
.replaceAll("//", "/");
340 public void setAgent(JcrAgent agent
) {
344 public void setRepository(Repository repository
) {
345 this.repository
= repository
;
348 public void setModulesManager(ExecutionModulesManager modulesManager
) {
349 this.modulesManager
= modulesManager
;