]> 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
8d6d96784ab64562ea0e2e78b3647d01c9188b3e
[gpl/argeo-slc.git] / runtime / org.argeo.slc.support.jcr / src / main / java / org / argeo / slc / jcr / execution / JcrExecutionModulesListener.java
1 /*
2 * Copyright (C) 2007-2012 Mathieu Baudier
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16 package org.argeo.slc.jcr.execution;
17
18 import java.util.Arrays;
19 import java.util.Iterator;
20 import java.util.List;
21
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;
29
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;
48
49 /**
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.
52 */
53 public class JcrExecutionModulesListener implements ExecutionModulesListener,
54 SlcNames {
55 private final static String SLC_EXECUTION_MODULES_PROPERTY = "slc.executionModules";
56
57 private final static Log log = LogFactory
58 .getLog(JcrExecutionModulesListener.class);
59 private JcrAgent agent;
60
61 private ExecutionModulesManager modulesManager;
62
63 private Repository repository;
64 /**
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.
68 */
69 private Session session;
70
71 /*
72 * LIFECYCLE
73 */
74 public void init() {
75 try {
76 session = repository.login();
77 clearAgent();
78 if (modulesManager != null) {
79 Node agentNode = session.getNode(agent.getNodePath());
80
81 List<ModuleDescriptor> moduleDescriptors = modulesManager
82 .listModules();
83
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,
97 md.getTitle());
98 moduleNode.setProperty(Property.JCR_DESCRIPTION,
99 md.getDescription());
100 moduleNode.setProperty(SLC_STARTED, md.getStarted());
101 }
102 }
103
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);
117 moduleNode
118 .addMixin(SlcTypes.SLC_EXECUTION_MODULE);
119 moduleNode.setProperty(SLC_NAME, md.getName());
120 moduleNode.setProperty(SLC_VERSION,
121 md.getVersion());
122 moduleNode.setProperty(Property.JCR_TITLE,
123 md.getTitle());
124 moduleNode.setProperty(
125 Property.JCR_DESCRIPTION,
126 md.getDescription());
127 moduleNode.setProperty(SLC_STARTED,
128 md.getStarted());
129 break allModules;
130 }
131 }
132 }
133
134 // save if needed
135 if (session.hasPendingChanges())
136 session.save();
137 }
138 }
139 } catch (RepositoryException e) {
140 JcrUtils.discardQuietly(session);
141 JcrUtils.logoutQuietly(session);
142 throw new SlcException("Cannot initialize modules", e);
143 }
144 }
145
146 public void destroy() {
147 clearAgent();
148 JcrUtils.logoutQuietly(session);
149 }
150
151 protected synchronized void clearAgent() {
152 try {
153 Node agentNode = session.getNode(agent.getNodePath());
154 for (NodeIterator nit = agentNode.getNodes(); nit.hasNext();)
155 nit.nextNode().remove();
156 session.save();
157 } catch (RepositoryException e) {
158 JcrUtils.discardQuietly(session);
159 throw new SlcException("Cannot clear agent " + agent, e);
160 }
161 }
162
163 /*
164 * EXECUTION MODULES LISTENER
165 */
166 public synchronized void executionModuleAdded(
167 ModuleDescriptor moduleDescriptor) {
168 try {
169 Node agentNode = session.getNode(agent.getNodePath());
170 String moduleNodeName = SlcJcrUtils
171 .getModuleNodeName(moduleDescriptor);
172 Node moduleNode = agentNode.hasNode(moduleNodeName) ? agentNode
173 .getNode(moduleNodeName) : agentNode
174 .addNode(moduleNodeName);
175 moduleNode.addMixin(SlcTypes.SLC_EXECUTION_MODULE);
176 moduleNode.setProperty(SLC_NAME, moduleDescriptor.getName());
177 moduleNode.setProperty(SLC_VERSION, moduleDescriptor.getVersion());
178 moduleNode.setProperty(Property.JCR_TITLE,
179 moduleDescriptor.getTitle());
180 moduleNode.setProperty(Property.JCR_DESCRIPTION,
181 moduleDescriptor.getDescription());
182 moduleNode.setProperty(SLC_STARTED, true);
183 session.save();
184 } catch (RepositoryException e) {
185 JcrUtils.discardQuietly(session);
186 throw new SlcException("Cannot add module " + moduleDescriptor, e);
187 }
188
189 }
190
191 public synchronized void executionModuleRemoved(
192 ModuleDescriptor moduleDescriptor) {
193 try {
194 String moduleName = SlcJcrUtils.getModuleNodeName(moduleDescriptor);
195 Node agentNode = session.getNode(agent.getNodePath());
196 if (agentNode.hasNode(moduleName)) {
197 Node moduleNode = agentNode.getNode(moduleName);
198 for (NodeIterator nit = moduleNode.getNodes(); nit.hasNext();) {
199 nit.nextNode().remove();
200 }
201 moduleNode.setProperty(SLC_STARTED, false);
202 }
203 session.save();
204 } catch (RepositoryException e) {
205 JcrUtils.discardQuietly(session);
206 throw new SlcException("Cannot remove module " + moduleDescriptor,
207 e);
208 }
209 }
210
211 public synchronized void executionFlowAdded(ModuleDescriptor module,
212 ExecutionFlowDescriptor efd) {
213 try {
214 Node agentNode = session.getNode(agent.getNodePath());
215 Node moduleNode = agentNode.getNode(SlcJcrUtils
216 .getModuleNodeName(module));
217 String relativePath = getExecutionFlowRelativePath(efd);
218 @SuppressWarnings("unused")
219 Node flowNode = null;
220 if (!moduleNode.hasNode(relativePath)) {
221 flowNode = createExecutionFlowNode(moduleNode, relativePath,
222 efd);
223 session.save();
224 } else {
225 flowNode = moduleNode.getNode(relativePath);
226 }
227
228 if (log.isTraceEnabled())
229 log.trace("Flow " + efd + " added to JCR");
230 } catch (RepositoryException e) {
231 JcrUtils.discardQuietly(session);
232 throw new SlcException("Cannot add flow " + efd + " from module "
233 + module, e);
234 }
235
236 }
237
238 protected Node createExecutionFlowNode(Node moduleNode,
239 String relativePath, ExecutionFlowDescriptor efd)
240 throws RepositoryException {
241 Node flowNode = null;
242 Iterator<String> names = Arrays.asList(relativePath.split("/"))
243 .iterator();
244 // create intermediary paths
245 Node currNode = moduleNode;
246 while (names.hasNext()) {
247 String name = names.next();
248 if (currNode.hasNode(name))
249 currNode = currNode.getNode(name);
250 else {
251 if (names.hasNext())
252 currNode = currNode.addNode(name);
253 else
254 flowNode = currNode.addNode(name,
255 SlcTypes.SLC_EXECUTION_FLOW);
256 }
257 }
258
259 // name, description
260 flowNode.setProperty(SLC_NAME, efd.getName());
261 String[] tokens = relativePath.split("/");
262 String endName = tokens[tokens.length - 1];
263 flowNode.setProperty(Property.JCR_TITLE, endName);
264 if (efd.getDescription() != null
265 && !efd.getDescription().trim().equals("")) {
266 flowNode.setProperty(Property.JCR_DESCRIPTION, efd.getDescription());
267 } else {
268 flowNode.setProperty(Property.JCR_DESCRIPTION, endName);
269 }
270
271 // execution spec
272 ExecutionSpec executionSpec = efd.getExecutionSpec();
273 String esName = executionSpec.getName();
274 if (!(esName == null || esName.equals(ExecutionSpec.INTERNAL_NAME))) {
275 // reference spec node
276 Node executionSpecsNode = moduleNode.hasNode(SLC_EXECUTION_SPECS) ? moduleNode
277 .getNode(SLC_EXECUTION_SPECS) : moduleNode
278 .addNode(SLC_EXECUTION_SPECS);
279 Node executionSpecNode = executionSpecsNode.addNode(esName,
280 SlcTypes.SLC_EXECUTION_SPEC);
281 executionSpecNode.setProperty(SLC_NAME, esName);
282 executionSpecNode.setProperty(Property.JCR_TITLE, esName);
283 if (executionSpec.getDescription() != null
284 && !executionSpec.getDescription().trim().equals(""))
285 executionSpecNode.setProperty(Property.JCR_DESCRIPTION,
286 executionSpec.getDescription());
287 mapExecutionSpec(executionSpecNode, executionSpec);
288 flowNode.setProperty(SLC_SPEC, executionSpecNode);
289 } else {
290 // internal spec node
291 mapExecutionSpec(flowNode, executionSpec);
292 }
293
294 // values
295 for (String attr : efd.getValues().keySet()) {
296 ExecutionSpecAttribute esa = executionSpec.getAttributes()
297 .get(attr);
298 if (esa instanceof PrimitiveSpecAttribute) {
299 PrimitiveSpecAttribute psa = (PrimitiveSpecAttribute) esa;
300 Node valueNode = flowNode.addNode(attr);
301 valueNode.setProperty(SLC_TYPE, psa.getType());
302 SlcJcrUtils.setPrimitiveAsProperty(valueNode, SLC_VALUE,
303 (PrimitiveValue) efd.getValues().get(attr));
304 }
305 }
306
307 return flowNode;
308 }
309
310 /**
311 * Base can be either an execution spec node, or an execution flow node (in
312 * case the execution spec is internal)
313 */
314 protected void mapExecutionSpec(Node baseNode, ExecutionSpec executionSpec)
315 throws RepositoryException {
316 for (String attrName : executionSpec.getAttributes().keySet()) {
317 ExecutionSpecAttribute esa = executionSpec.getAttributes().get(
318 attrName);
319 Node attrNode = baseNode.addNode(attrName);
320 // booleans
321 attrNode.addMixin(SlcTypes.SLC_EXECUTION_SPEC_ATTRIBUTE);
322 attrNode.setProperty(SLC_IS_IMMUTABLE, esa.getIsImmutable());
323 attrNode.setProperty(SLC_IS_CONSTANT, esa.getIsConstant());
324 attrNode.setProperty(SLC_IS_HIDDEN, esa.getIsHidden());
325
326 if (esa instanceof PrimitiveSpecAttribute) {
327 attrNode.addMixin(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE);
328 PrimitiveSpecAttribute psa = (PrimitiveSpecAttribute) esa;
329 SlcJcrUtils.setPrimitiveAsProperty(attrNode, SLC_VALUE, psa);
330 attrNode.setProperty(SLC_TYPE, psa.getType());
331 } else if (esa instanceof RefSpecAttribute) {
332 attrNode.addMixin(SlcTypes.SLC_REF_SPEC_ATTRIBUTE);
333 RefSpecAttribute rsa = (RefSpecAttribute) esa;
334 attrNode.setProperty(SLC_TYPE, rsa.getTargetClassName());
335 Object value = rsa.getValue();
336 if (rsa.getChoices() != null) {
337 Integer index = null;
338 int count = 0;
339 for (RefValueChoice choice : rsa.getChoices()) {
340 String name = choice.getName();
341 if (value != null && name.equals(value.toString()))
342 index = count;
343 Node choiceNode = attrNode.addNode(choice.getName());
344 choiceNode.addMixin(NodeType.MIX_TITLE);
345 choiceNode.setProperty(Property.JCR_TITLE,
346 choice.getName());
347 if (choice.getDescription() != null
348 && !choice.getDescription().trim().equals(""))
349 choiceNode.setProperty(Property.JCR_DESCRIPTION,
350 choice.getDescription());
351 count++;
352 }
353
354 if (index != null)
355 attrNode.setProperty(SLC_VALUE, index);
356 }
357 }
358 }
359 }
360
361 public synchronized void executionFlowRemoved(ModuleDescriptor module,
362 ExecutionFlowDescriptor executionFlow) {
363 try {
364 Node agentNode = session.getNode(agent.getNodePath());
365 Node moduleNode = agentNode.getNode(SlcJcrUtils
366 .getModuleNodeName(module));
367 String relativePath = getExecutionFlowRelativePath(executionFlow);
368 if (moduleNode.hasNode(relativePath))
369 moduleNode.getNode(relativePath).remove();
370 agentNode.getSession().save();
371 } catch (RepositoryException e) {
372 throw new SlcException("Cannot remove flow " + executionFlow
373 + " from module " + module, e);
374 }
375 }
376
377 /*
378 * UTILITIES
379 */
380 /** @return the relative path, never starts with '/' */
381 @SuppressWarnings("deprecation")
382 protected String getExecutionFlowRelativePath(
383 ExecutionFlowDescriptor executionFlow) {
384 String relativePath = executionFlow.getPath() == null ? executionFlow
385 .getName() : executionFlow.getPath() + '/'
386 + executionFlow.getName();
387 // we assume that it is more than one char long
388 if (relativePath.charAt(0) == '/')
389 relativePath = relativePath.substring(1);
390 // FIXME quick hack to avoid duplicate '/'
391 relativePath = relativePath.replaceAll("//", "/");
392 return relativePath;
393 }
394
395 /*
396 * BEAN
397 */
398 public void setAgent(JcrAgent agent) {
399 this.agent = agent;
400 }
401
402 public void setRepository(Repository repository) {
403 this.repository = repository;
404 }
405
406 public void setModulesManager(ExecutionModulesManager modulesManager) {
407 this.modulesManager = modulesManager;
408 }
409
410 }