2 * Copyright (C) 2007-2012 Argeo GmbH
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.argeo
.slc
.jcr
.execution
;
18 import java
.util
.Arrays
;
19 import java
.util
.Iterator
;
20 import java
.util
.List
;
22 import javax
.jcr
.Node
;
23 import javax
.jcr
.NodeIterator
;
24 import javax
.jcr
.Property
;
25 import javax
.jcr
.Repository
;
26 import javax
.jcr
.RepositoryException
;
27 import javax
.jcr
.Session
;
28 import javax
.jcr
.nodetype
.NodeType
;
30 import org
.apache
.commons
.logging
.Log
;
31 import org
.apache
.commons
.logging
.LogFactory
;
32 import org
.argeo
.jcr
.JcrUtils
;
33 import org
.argeo
.slc
.SlcException
;
34 import org
.argeo
.slc
.core
.execution
.PrimitiveSpecAttribute
;
35 import org
.argeo
.slc
.core
.execution
.PrimitiveValue
;
36 import org
.argeo
.slc
.core
.execution
.RefSpecAttribute
;
37 import org
.argeo
.slc
.core
.execution
.RefValueChoice
;
38 import org
.argeo
.slc
.deploy
.ModuleDescriptor
;
39 import org
.argeo
.slc
.execution
.ExecutionFlowDescriptor
;
40 import org
.argeo
.slc
.execution
.ExecutionModuleDescriptor
;
41 import org
.argeo
.slc
.execution
.ExecutionModulesListener
;
42 import org
.argeo
.slc
.execution
.ExecutionModulesManager
;
43 import org
.argeo
.slc
.execution
.ExecutionSpec
;
44 import org
.argeo
.slc
.execution
.ExecutionSpecAttribute
;
45 import org
.argeo
.slc
.jcr
.SlcJcrUtils
;
46 import org
.argeo
.slc
.jcr
.SlcNames
;
47 import org
.argeo
.slc
.jcr
.SlcTypes
;
50 * Synchronizes the local execution runtime with a JCR repository. For the time
51 * being the state is completely reset from one start to another.
53 public class JcrExecutionModulesListener
implements ExecutionModulesListener
,
55 private final static String SLC_EXECUTION_MODULES_PROPERTY
= "slc.executionModules";
57 private final static Log log
= LogFactory
58 .getLog(JcrExecutionModulesListener
.class);
59 private JcrAgent agent
;
61 private ExecutionModulesManager modulesManager
;
63 private Repository repository
;
65 * We don't use a thread bound session because many different threads will
66 * call this critical component and we don't want to login each time. We
67 * therefore rather protect access to this session via synchronized.
69 private Session session
;
76 session
= repository
.login();
78 if (modulesManager
!= null) {
79 Node agentNode
= session
.getNode(agent
.getNodePath());
81 List
<ModuleDescriptor
> moduleDescriptors
= modulesManager
84 // scan SLC-ExecutionModule metadata
85 for (ModuleDescriptor md
: moduleDescriptors
) {
86 if (md
.getMetadata().containsKey(
87 ExecutionModuleDescriptor
.SLC_EXECUTION_MODULE
)) {
88 String moduleNodeName
= SlcJcrUtils
89 .getModuleNodeName(md
);
90 Node moduleNode
= agentNode
.hasNode(moduleNodeName
) ? agentNode
91 .getNode(moduleNodeName
) : agentNode
92 .addNode(moduleNodeName
);
93 moduleNode
.addMixin(SlcTypes
.SLC_EXECUTION_MODULE
);
94 moduleNode
.setProperty(SLC_NAME
, md
.getName());
95 moduleNode
.setProperty(SLC_VERSION
, md
.getVersion());
96 moduleNode
.setProperty(Property
.JCR_TITLE
,
98 moduleNode
.setProperty(Property
.JCR_DESCRIPTION
,
100 moduleNode
.setProperty(SLC_STARTED
, md
.getStarted());
104 // scan execution modules property
105 String executionModules
= System
106 .getProperty(SLC_EXECUTION_MODULES_PROPERTY
);
107 if (executionModules
!= null) {
108 for (String executionModule
: executionModules
.split(",")) {
109 allModules
: for (ModuleDescriptor md
: moduleDescriptors
) {
110 String moduleNodeName
= SlcJcrUtils
111 .getModuleNodeName(md
);
112 if (md
.getName().equals(executionModule
)) {
113 Node moduleNode
= agentNode
114 .hasNode(moduleNodeName
) ? agentNode
115 .getNode(moduleNodeName
) : agentNode
116 .addNode(moduleNodeName
);
118 .addMixin(SlcTypes
.SLC_EXECUTION_MODULE
);
119 moduleNode
.setProperty(SLC_NAME
, md
.getName());
120 moduleNode
.setProperty(SLC_VERSION
,
122 moduleNode
.setProperty(Property
.JCR_TITLE
,
124 moduleNode
.setProperty(
125 Property
.JCR_DESCRIPTION
,
126 md
.getDescription());
127 moduleNode
.setProperty(SLC_STARTED
,
135 if (session
.hasPendingChanges())
139 } catch (RepositoryException e
) {
140 JcrUtils
.discardQuietly(session
);
141 JcrUtils
.logoutQuietly(session
);
142 throw new SlcException("Cannot initialize modules", e
);
146 public void destroy() {
148 JcrUtils
.logoutQuietly(session
);
151 protected synchronized void clearAgent() {
153 Node agentNode
= session
.getNode(agent
.getNodePath());
154 for (NodeIterator nit
= agentNode
.getNodes(); nit
.hasNext();)
155 nit
.nextNode().remove();
157 } catch (RepositoryException e
) {
158 JcrUtils
.discardQuietly(session
);
159 throw new SlcException("Cannot clear agent " + agent
, e
);
164 * EXECUTION MODULES LISTENER
167 public synchronized void executionModuleAdded(
168 ModuleDescriptor moduleDescriptor
) {
169 syncExecutionModule(moduleDescriptor
);
172 protected void syncExecutionModule(ModuleDescriptor moduleDescriptor
) {
174 Node agentNode
= session
.getNode(agent
.getNodePath());
175 String moduleNodeName
= SlcJcrUtils
176 .getModuleNodeName(moduleDescriptor
);
177 Node moduleNode
= agentNode
.hasNode(moduleNodeName
) ? agentNode
178 .getNode(moduleNodeName
) : agentNode
179 .addNode(moduleNodeName
);
180 moduleNode
.addMixin(SlcTypes
.SLC_EXECUTION_MODULE
);
181 moduleNode
.setProperty(SLC_NAME
, moduleDescriptor
.getName());
182 moduleNode
.setProperty(SLC_VERSION
, moduleDescriptor
.getVersion());
183 moduleNode
.setProperty(Property
.JCR_TITLE
,
184 moduleDescriptor
.getTitle());
185 moduleNode
.setProperty(Property
.JCR_DESCRIPTION
,
186 moduleDescriptor
.getDescription());
187 moduleNode
.setProperty(SLC_STARTED
, moduleDescriptor
.getStarted());
189 } catch (RepositoryException e
) {
190 JcrUtils
.discardQuietly(session
);
191 throw new SlcException("Cannot sync module " + moduleDescriptor
, e
);
195 public synchronized void executionModuleRemoved(
196 ModuleDescriptor moduleDescriptor
) {
198 String moduleName
= SlcJcrUtils
.getModuleNodeName(moduleDescriptor
);
199 Node agentNode
= session
.getNode(agent
.getNodePath());
200 if (agentNode
.hasNode(moduleName
)) {
201 Node moduleNode
= agentNode
.getNode(moduleName
);
202 for (NodeIterator nit
= moduleNode
.getNodes(); nit
.hasNext();) {
203 nit
.nextNode().remove();
205 moduleNode
.setProperty(SLC_STARTED
, false);
208 } catch (RepositoryException e
) {
209 JcrUtils
.discardQuietly(session
);
210 throw new SlcException("Cannot remove module " + moduleDescriptor
,
215 public synchronized void executionFlowAdded(ModuleDescriptor module
,
216 ExecutionFlowDescriptor efd
) {
218 Node agentNode
= session
.getNode(agent
.getNodePath());
219 Node moduleNode
= agentNode
.getNode(SlcJcrUtils
220 .getModuleNodeName(module
));
221 String relativePath
= getExecutionFlowRelativePath(efd
);
222 @SuppressWarnings("unused")
223 Node flowNode
= null;
224 if (!moduleNode
.hasNode(relativePath
)) {
225 flowNode
= createExecutionFlowNode(moduleNode
, relativePath
,
229 flowNode
= moduleNode
.getNode(relativePath
);
232 if (log
.isTraceEnabled())
233 log
.trace("Flow " + efd
+ " added to JCR");
234 } catch (RepositoryException e
) {
235 JcrUtils
.discardQuietly(session
);
236 throw new SlcException("Cannot add flow " + efd
+ " from module "
242 protected Node
createExecutionFlowNode(Node moduleNode
,
243 String relativePath
, ExecutionFlowDescriptor efd
)
244 throws RepositoryException
{
245 Node flowNode
= null;
246 List
<String
> pathTokens
= Arrays
.asList(relativePath
.split("/"));
248 Iterator
<String
> names
= pathTokens
.iterator();
249 // create intermediary paths
250 Node currNode
= moduleNode
;
251 while (names
.hasNext()) {
252 String name
= names
.next();
253 if (currNode
.hasNode(name
))
254 currNode
= currNode
.getNode(name
);
257 currNode
= currNode
.addNode(name
);
259 flowNode
= currNode
.addNode(name
,
260 SlcTypes
.SLC_EXECUTION_FLOW
);
265 flowNode
.setProperty(SLC_NAME
, efd
.getName());
266 String endName
= pathTokens
.get(pathTokens
.size() - 1);
267 flowNode
.setProperty(Property
.JCR_TITLE
, endName
);
268 if (efd
.getDescription() != null
269 && !efd
.getDescription().trim().equals("")) {
270 flowNode
.setProperty(Property
.JCR_DESCRIPTION
, efd
.getDescription());
272 flowNode
.setProperty(Property
.JCR_DESCRIPTION
, endName
);
276 ExecutionSpec executionSpec
= efd
.getExecutionSpec();
277 String esName
= executionSpec
.getName();
278 if (esName
== null || esName
.equals(ExecutionSpec
.INTERNAL_NAME
)
279 || esName
.contains("#")/* automatically generated bean name */) {
280 // internal spec node
281 mapExecutionSpec(flowNode
, executionSpec
);
283 // reference spec node
284 Node executionSpecsNode
= moduleNode
.hasNode(SLC_EXECUTION_SPECS
) ? moduleNode
285 .getNode(SLC_EXECUTION_SPECS
) : moduleNode
286 .addNode(SLC_EXECUTION_SPECS
);
287 Node executionSpecNode
= executionSpecsNode
.addNode(esName
,
288 SlcTypes
.SLC_EXECUTION_SPEC
);
289 executionSpecNode
.setProperty(SLC_NAME
, esName
);
290 executionSpecNode
.setProperty(Property
.JCR_TITLE
, esName
);
291 if (executionSpec
.getDescription() != null
292 && !executionSpec
.getDescription().trim().equals(""))
293 executionSpecNode
.setProperty(Property
.JCR_DESCRIPTION
,
294 executionSpec
.getDescription());
295 mapExecutionSpec(executionSpecNode
, executionSpec
);
296 flowNode
.setProperty(SLC_SPEC
, executionSpecNode
);
300 for (String attr
: efd
.getValues().keySet()) {
301 ExecutionSpecAttribute esa
= executionSpec
.getAttributes()
303 if (!flowNode
.hasNode(attr
))
304 throw new SlcException("No spec node for attribute '" + attr
305 + "' in flow " + flowNode
.getPath());
306 if (esa
instanceof PrimitiveSpecAttribute
) {
307 PrimitiveSpecAttribute psa
= (PrimitiveSpecAttribute
) esa
;
308 Node valueNode
= flowNode
.getNode(attr
);
309 valueNode
.setProperty(SLC_TYPE
, psa
.getType());
310 SlcJcrUtils
.setPrimitiveAsProperty(valueNode
, SLC_VALUE
,
311 (PrimitiveValue
) efd
.getValues().get(attr
));
319 * Base can be either an execution spec node, or an execution flow node (in
320 * case the execution spec is internal)
322 protected void mapExecutionSpec(Node baseNode
, ExecutionSpec executionSpec
)
323 throws RepositoryException
{
324 for (String attrName
: executionSpec
.getAttributes().keySet()) {
325 ExecutionSpecAttribute esa
= executionSpec
.getAttributes().get(
327 Node attrNode
= baseNode
.addNode(attrName
);
329 attrNode
.addMixin(SlcTypes
.SLC_EXECUTION_SPEC_ATTRIBUTE
);
330 attrNode
.setProperty(SLC_IS_IMMUTABLE
, esa
.getIsImmutable());
331 attrNode
.setProperty(SLC_IS_CONSTANT
, esa
.getIsConstant());
332 attrNode
.setProperty(SLC_IS_HIDDEN
, esa
.getIsHidden());
334 if (esa
instanceof PrimitiveSpecAttribute
) {
335 attrNode
.addMixin(SlcTypes
.SLC_PRIMITIVE_SPEC_ATTRIBUTE
);
336 PrimitiveSpecAttribute psa
= (PrimitiveSpecAttribute
) esa
;
337 SlcJcrUtils
.setPrimitiveAsProperty(attrNode
, SLC_VALUE
, psa
);
338 attrNode
.setProperty(SLC_TYPE
, psa
.getType());
339 } else if (esa
instanceof RefSpecAttribute
) {
340 attrNode
.addMixin(SlcTypes
.SLC_REF_SPEC_ATTRIBUTE
);
341 RefSpecAttribute rsa
= (RefSpecAttribute
) esa
;
342 attrNode
.setProperty(SLC_TYPE
, rsa
.getTargetClassName());
343 Object value
= rsa
.getValue();
344 if (rsa
.getChoices() != null) {
345 Integer index
= null;
347 for (RefValueChoice choice
: rsa
.getChoices()) {
348 String name
= choice
.getName();
349 if (value
!= null && name
.equals(value
.toString()))
351 Node choiceNode
= attrNode
.addNode(choice
.getName());
352 choiceNode
.addMixin(NodeType
.MIX_TITLE
);
353 choiceNode
.setProperty(Property
.JCR_TITLE
,
355 if (choice
.getDescription() != null
356 && !choice
.getDescription().trim().equals(""))
357 choiceNode
.setProperty(Property
.JCR_DESCRIPTION
,
358 choice
.getDescription());
363 attrNode
.setProperty(SLC_VALUE
, index
);
369 public synchronized void executionFlowRemoved(ModuleDescriptor module
,
370 ExecutionFlowDescriptor executionFlow
) {
372 Node agentNode
= session
.getNode(agent
.getNodePath());
373 Node moduleNode
= agentNode
.getNode(SlcJcrUtils
374 .getModuleNodeName(module
));
375 String relativePath
= getExecutionFlowRelativePath(executionFlow
);
376 if (moduleNode
.hasNode(relativePath
))
377 moduleNode
.getNode(relativePath
).remove();
378 agentNode
.getSession().save();
379 } catch (RepositoryException e
) {
380 throw new SlcException("Cannot remove flow " + executionFlow
381 + " from module " + module
, e
);
388 /** @return the relative path, never starts with '/' */
389 @SuppressWarnings("deprecation")
390 protected String
getExecutionFlowRelativePath(
391 ExecutionFlowDescriptor executionFlow
) {
392 String relativePath
= executionFlow
.getPath() == null ? executionFlow
393 .getName() : executionFlow
.getPath() + '/'
394 + executionFlow
.getName();
395 // we assume that it is more than one char long
396 if (relativePath
.charAt(0) == '/')
397 relativePath
= relativePath
.substring(1);
398 // FIXME quick hack to avoid duplicate '/'
399 relativePath
= relativePath
.replaceAll("//", "/");
406 public void setAgent(JcrAgent agent
) {
410 public void setRepository(Repository repository
) {
411 this.repository
= repository
;
414 public void setModulesManager(ExecutionModulesManager modulesManager
) {
415 this.modulesManager
= modulesManager
;