]> git.argeo.org Git - gpl/argeo-slc.git/blob - runtime/org.argeo.slc.support.jcr/src/main/java/org/argeo/slc/jcr/execution/JcrExecutionModulesListener.java
Introduce JCR test result
[gpl/argeo-slc.git] / runtime / org.argeo.slc.support.jcr / src / main / java / org / argeo / slc / jcr / execution / JcrExecutionModulesListener.java
1 package org.argeo.slc.jcr.execution;
2
3 import java.util.Arrays;
4 import java.util.Iterator;
5 import java.util.List;
6
7 import javax.jcr.Node;
8 import javax.jcr.NodeIterator;
9 import javax.jcr.Property;
10 import javax.jcr.RepositoryException;
11 import javax.jcr.Session;
12 import javax.jcr.nodetype.NodeType;
13
14 import org.apache.commons.logging.Log;
15 import org.apache.commons.logging.LogFactory;
16 import org.argeo.jcr.JcrUtils;
17 import org.argeo.slc.SlcException;
18 import org.argeo.slc.core.execution.PrimitiveSpecAttribute;
19 import org.argeo.slc.core.execution.PrimitiveValue;
20 import org.argeo.slc.core.execution.RefSpecAttribute;
21 import org.argeo.slc.core.execution.RefValueChoice;
22 import org.argeo.slc.deploy.ModuleDescriptor;
23 import org.argeo.slc.execution.ExecutionFlowDescriptor;
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.jcr.SlcJcrUtils;
29 import org.argeo.slc.jcr.SlcNames;
30 import org.argeo.slc.jcr.SlcTypes;
31
32 /**
33 * Synchronizes the local execution runtime with a JCR repository. For the time
34 * being the state is completely reset from one start to another.
35 */
36 public class JcrExecutionModulesListener implements ExecutionModulesListener,
37 SlcNames {
38 private final static String SLC_EXECUTION_MODULES_PROPERTY = "slc.executionModules";
39
40 private final static Log log = LogFactory
41 .getLog(JcrExecutionModulesListener.class);
42 private JcrAgent agent;
43
44 private ExecutionModulesManager modulesManager;
45
46 /**
47 * We don't use a thread bound session because many different threads will
48 * call this critical component and we don't want to login each time. We
49 * therefore rather protect access to this session via synchronized.
50 */
51 private Session session;
52
53 /*
54 * LIFECYCLE
55 */
56 public void init() {
57 clearAgent();
58 if (modulesManager != null) {
59 List<ModuleDescriptor> moduleDescriptors = modulesManager
60 .listModules();
61 String executionModules = System
62 .getProperty(SLC_EXECUTION_MODULES_PROPERTY);
63 if (executionModules != null)
64 try {
65 Node agentNode = session.getNode(agent.getNodePath());
66 for (String executionModule : executionModules.split(",")) {
67 for (ModuleDescriptor moduleDescriptor : moduleDescriptors) {
68 String moduleNodeName = SlcJcrUtils
69 .getModuleNodeName(moduleDescriptor);
70 if (moduleDescriptor.getName().equals(
71 executionModule)) {
72 Node moduleNode = agentNode
73 .hasNode(moduleNodeName) ? agentNode
74 .getNode(moduleNodeName) : agentNode
75 .addNode(moduleNodeName);
76 moduleNode
77 .addMixin(SlcTypes.SLC_EXECUTION_MODULE);
78 moduleNode.setProperty(SLC_NAME,
79 moduleDescriptor.getName());
80 moduleNode.setProperty(SLC_VERSION,
81 moduleDescriptor.getVersion());
82 moduleNode.setProperty(Property.JCR_TITLE,
83 moduleDescriptor.getTitle());
84 moduleNode.setProperty(
85 Property.JCR_DESCRIPTION,
86 moduleDescriptor.getDescription());
87 moduleNode.setProperty(SLC_STARTED, false);
88 }
89 }
90 }
91 session.save();
92 } catch (RepositoryException e) {
93 JcrUtils.discardQuietly(session);
94 throw new SlcException("Cannot initialize modules", e);
95 }
96 }
97 }
98
99 public void dispose() {
100 clearAgent();
101 session.logout();
102 }
103
104 protected synchronized void clearAgent() {
105 try {
106 Node agentNode = session.getNode(agent.getNodePath());
107 for (NodeIterator nit = agentNode.getNodes(); nit.hasNext();)
108 nit.nextNode().remove();
109 session.save();
110 } catch (RepositoryException e) {
111 JcrUtils.discardQuietly(session);
112 throw new SlcException("Cannot clear agent " + agent, e);
113 }
114 }
115
116 /*
117 * EXECUTION MODULES LISTENER
118 */
119 public synchronized void executionModuleAdded(
120 ModuleDescriptor moduleDescriptor) {
121 try {
122 Node agentNode = session.getNode(agent.getNodePath());
123 String moduleNodeName = SlcJcrUtils
124 .getModuleNodeName(moduleDescriptor);
125 Node moduleNode = agentNode.hasNode(moduleNodeName) ? agentNode
126 .getNode(moduleNodeName) : agentNode
127 .addNode(moduleNodeName);
128 moduleNode.addMixin(SlcTypes.SLC_EXECUTION_MODULE);
129 moduleNode.setProperty(SLC_NAME, moduleDescriptor.getName());
130 moduleNode.setProperty(SLC_VERSION, moduleDescriptor.getVersion());
131 moduleNode.setProperty(Property.JCR_TITLE,
132 moduleDescriptor.getTitle());
133 moduleNode.setProperty(Property.JCR_DESCRIPTION,
134 moduleDescriptor.getDescription());
135 moduleNode.setProperty(SLC_STARTED, true);
136 session.save();
137 } catch (RepositoryException e) {
138 JcrUtils.discardQuietly(session);
139 throw new SlcException("Cannot add module " + moduleDescriptor, e);
140 }
141
142 }
143
144 public synchronized void executionModuleRemoved(
145 ModuleDescriptor moduleDescriptor) {
146 try {
147 String moduleName = SlcJcrUtils.getModuleNodeName(moduleDescriptor);
148 Node agentNode = session.getNode(agent.getNodePath());
149 if (agentNode.hasNode(moduleName)) {
150 Node moduleNode = agentNode.getNode(moduleName);
151 for (NodeIterator nit = moduleNode.getNodes(); nit.hasNext();) {
152 nit.nextNode().remove();
153 }
154 moduleNode.setProperty(SLC_STARTED, false);
155 }
156 session.save();
157 } catch (RepositoryException e) {
158 JcrUtils.discardQuietly(session);
159 throw new SlcException("Cannot remove module " + moduleDescriptor,
160 e);
161 }
162 }
163
164 public synchronized void executionFlowAdded(ModuleDescriptor module,
165 ExecutionFlowDescriptor efd) {
166 try {
167 Node agentNode = session.getNode(agent.getNodePath());
168 Node moduleNode = agentNode.getNode(SlcJcrUtils
169 .getModuleNodeName(module));
170 String relativePath = getExecutionFlowRelativePath(efd);
171 @SuppressWarnings("unused")
172 Node flowNode = null;
173 if (!moduleNode.hasNode(relativePath)) {
174 flowNode = createExecutionFlowNode(moduleNode, relativePath,
175 efd);
176 session.save();
177 } else {
178 flowNode = moduleNode.getNode(relativePath);
179 }
180
181 if (log.isTraceEnabled())
182 log.trace("Flow " + efd + " added to JCR");
183 } catch (RepositoryException e) {
184 JcrUtils.discardQuietly(session);
185 throw new SlcException("Cannot add flow " + efd + " from module "
186 + module, e);
187 }
188
189 }
190
191 protected Node createExecutionFlowNode(Node moduleNode,
192 String relativePath, ExecutionFlowDescriptor efd)
193 throws RepositoryException {
194 Node flowNode = null;
195 Iterator<String> names = Arrays.asList(relativePath.split("/"))
196 .iterator();
197 // create intermediary paths
198 Node currNode = moduleNode;
199 while (names.hasNext()) {
200 String name = names.next();
201 if (currNode.hasNode(name))
202 currNode = currNode.getNode(name);
203 else {
204 if (names.hasNext())
205 currNode = currNode.addNode(name);
206 else
207 flowNode = currNode.addNode(name,
208 SlcTypes.SLC_EXECUTION_FLOW);
209 }
210 }
211
212 // name, description
213 flowNode.setProperty(SLC_NAME, efd.getName());
214 String[] tokens = relativePath.split("/");
215 String endName = tokens[tokens.length - 1];
216 if (efd.getDescription() != null
217 && !efd.getDescription().trim().equals("")) {
218 flowNode.setProperty(Property.JCR_TITLE, efd.getDescription());
219 } else {
220 flowNode.setProperty(Property.JCR_TITLE, endName);
221 }
222 flowNode.setProperty(Property.JCR_DESCRIPTION, endName);
223
224 // execution spec
225 ExecutionSpec executionSpec = efd.getExecutionSpec();
226 String esName = executionSpec.getName();
227 if (!(esName == null || esName.equals(ExecutionSpec.INTERNAL_NAME))) {
228 // reference spec node
229 Node executionSpecsNode = moduleNode.hasNode(SLC_EXECUTION_SPECS) ? moduleNode
230 .getNode(SLC_EXECUTION_SPECS) : moduleNode
231 .addNode(SLC_EXECUTION_SPECS);
232 Node executionSpecNode = executionSpecsNode.addNode(esName,
233 SlcTypes.SLC_EXECUTION_SPEC);
234 executionSpecNode.setProperty(SLC_NAME, esName);
235 executionSpecNode.setProperty(Property.JCR_TITLE, esName);
236 if (executionSpec.getDescription() != null
237 && !executionSpec.getDescription().trim().equals(""))
238 executionSpecNode.setProperty(Property.JCR_DESCRIPTION,
239 executionSpec.getDescription());
240 mapExecutionSpec(executionSpecNode, executionSpec);
241 flowNode.setProperty(SLC_SPEC, executionSpecNode);
242 } else {
243 // internal spec node
244 mapExecutionSpec(flowNode, executionSpec);
245 }
246
247 // values
248 for (String attr : efd.getValues().keySet()) {
249 ExecutionSpecAttribute esa = executionSpec.getAttributes()
250 .get(attr);
251 if (esa instanceof PrimitiveSpecAttribute) {
252 PrimitiveSpecAttribute psa = (PrimitiveSpecAttribute) esa;
253 Node valueNode = flowNode.addNode(attr);
254 valueNode.setProperty(SLC_TYPE, psa.getType());
255 SlcJcrUtils.setPrimitiveAsProperty(valueNode, SLC_VALUE,
256 (PrimitiveValue) efd.getValues().get(attr));
257 }
258 }
259
260 return flowNode;
261 }
262
263 /**
264 * Base can be either an execution spec node, or an execution flow node (in
265 * case the execution spec is internal)
266 */
267 protected void mapExecutionSpec(Node baseNode, ExecutionSpec executionSpec)
268 throws RepositoryException {
269 for (String attrName : executionSpec.getAttributes().keySet()) {
270 ExecutionSpecAttribute esa = executionSpec.getAttributes().get(
271 attrName);
272 Node attrNode = baseNode.addNode(attrName);
273 // booleans
274 attrNode.addMixin(SlcTypes.SLC_EXECUTION_SPEC_ATTRIBUTE);
275 attrNode.setProperty(SLC_IS_IMMUTABLE, esa.getIsImmutable());
276 attrNode.setProperty(SLC_IS_CONSTANT, esa.getIsConstant());
277 attrNode.setProperty(SLC_IS_HIDDEN, esa.getIsHidden());
278
279 if (esa instanceof PrimitiveSpecAttribute) {
280 attrNode.addMixin(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE);
281 PrimitiveSpecAttribute psa = (PrimitiveSpecAttribute) esa;
282 SlcJcrUtils.setPrimitiveAsProperty(attrNode, SLC_VALUE, psa);
283 attrNode.setProperty(SLC_TYPE, psa.getType());
284 } else if (esa instanceof RefSpecAttribute) {
285 attrNode.addMixin(SlcTypes.SLC_REF_SPEC_ATTRIBUTE);
286 RefSpecAttribute rsa = (RefSpecAttribute) esa;
287 attrNode.setProperty(SLC_TYPE, rsa.getTargetClassName());
288 if (rsa.getChoices() != null) {
289 for (RefValueChoice choice : rsa.getChoices()) {
290 Node choiceNode = attrNode.addNode(choice.getName());
291 choiceNode.addMixin(NodeType.MIX_TITLE);
292 choiceNode.setProperty(Property.JCR_TITLE,
293 choice.getName());
294 if (choice.getDescription() != null
295 && !choice.getDescription().trim().equals(""))
296 choiceNode.setProperty(Property.JCR_DESCRIPTION,
297 choice.getDescription());
298 }
299 }
300 }
301 }
302 }
303
304 public synchronized void executionFlowRemoved(ModuleDescriptor module,
305 ExecutionFlowDescriptor executionFlow) {
306 try {
307 Node agentNode = session.getNode(agent.getNodePath());
308 Node moduleNode = agentNode.getNode(SlcJcrUtils
309 .getModuleNodeName(module));
310 String relativePath = getExecutionFlowRelativePath(executionFlow);
311 if (!moduleNode.hasNode(relativePath))
312 moduleNode.getNode(relativePath).remove();
313 agentNode.getSession().save();
314 } catch (RepositoryException e) {
315 throw new SlcException("Cannot remove flow " + executionFlow
316 + " from module " + module, e);
317 }
318 }
319
320 /*
321 * UTILITIES
322 */
323 /** @return the relative path, never starts with '/' */
324 @SuppressWarnings("deprecation")
325 protected String getExecutionFlowRelativePath(
326 ExecutionFlowDescriptor executionFlow) {
327 String relativePath = executionFlow.getPath() == null ? executionFlow
328 .getName() : executionFlow.getPath() + '/'
329 + executionFlow.getName();
330 // we assume that it is more than one char long
331 if (relativePath.charAt(0) == '/')
332 relativePath = relativePath.substring(1);
333 // FIXME quick hack to avoid duplicate '/'
334 relativePath = relativePath.replaceAll("//", "/");
335 return relativePath;
336 }
337
338 /*
339 * BEAN
340 */
341 public void setAgent(JcrAgent agent) {
342 this.agent = agent;
343 }
344
345 /** Expects a non-shared session with admin authorization */
346 public void setSession(Session session) {
347 this.session = session;
348 }
349
350 public void setModulesManager(ExecutionModulesManager modulesManager) {
351 this.modulesManager = modulesManager;
352 }
353
354 }