]> 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
473dcb343434fc7a7a055624bafeed08fc1f5de9
[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 Argeo GmbH
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
167 public synchronized void executionModuleAdded(
168 ModuleDescriptor moduleDescriptor) {
169 syncExecutionModule(moduleDescriptor);
170 }
171
172 protected void syncExecutionModule(ModuleDescriptor moduleDescriptor) {
173 try {
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());
188 session.save();
189 } catch (RepositoryException e) {
190 JcrUtils.discardQuietly(session);
191 throw new SlcException("Cannot sync module " + moduleDescriptor, e);
192 }
193 }
194
195 public synchronized void executionModuleRemoved(
196 ModuleDescriptor moduleDescriptor) {
197 try {
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();
204 }
205 moduleNode.setProperty(SLC_STARTED, false);
206 }
207 session.save();
208 } catch (RepositoryException e) {
209 JcrUtils.discardQuietly(session);
210 throw new SlcException("Cannot remove module " + moduleDescriptor,
211 e);
212 }
213 }
214
215 public synchronized void executionFlowAdded(ModuleDescriptor module,
216 ExecutionFlowDescriptor efd) {
217 try {
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,
226 efd);
227 session.save();
228 } else {
229 flowNode = moduleNode.getNode(relativePath);
230 }
231
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 "
237 + module, e);
238 }
239
240 }
241
242 protected Node createExecutionFlowNode(Node moduleNode,
243 String relativePath, ExecutionFlowDescriptor efd)
244 throws RepositoryException {
245 Node flowNode = null;
246 Iterator<String> names = Arrays.asList(relativePath.split("/"))
247 .iterator();
248 // create intermediary paths
249 Node currNode = moduleNode;
250 while (names.hasNext()) {
251 String name = names.next();
252 if (currNode.hasNode(name))
253 currNode = currNode.getNode(name);
254 else {
255 if (names.hasNext())
256 currNode = currNode.addNode(name);
257 else
258 flowNode = currNode.addNode(name,
259 SlcTypes.SLC_EXECUTION_FLOW);
260 }
261 }
262
263 // name, description
264 flowNode.setProperty(SLC_NAME, efd.getName());
265 String[] tokens = relativePath.split("/");
266 String endName = tokens[tokens.length - 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());
271 } else {
272 flowNode.setProperty(Property.JCR_DESCRIPTION, endName);
273 }
274
275 // execution spec
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);
282 } else {
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);
297 }
298
299 // values
300 for (String attr : efd.getValues().keySet()) {
301 ExecutionSpecAttribute esa = executionSpec.getAttributes()
302 .get(attr);
303 if (esa instanceof PrimitiveSpecAttribute) {
304 PrimitiveSpecAttribute psa = (PrimitiveSpecAttribute) esa;
305 Node valueNode = flowNode.addNode(attr);
306 valueNode.setProperty(SLC_TYPE, psa.getType());
307 SlcJcrUtils.setPrimitiveAsProperty(valueNode, SLC_VALUE,
308 (PrimitiveValue) efd.getValues().get(attr));
309 }
310 }
311
312 return flowNode;
313 }
314
315 /**
316 * Base can be either an execution spec node, or an execution flow node (in
317 * case the execution spec is internal)
318 */
319 protected void mapExecutionSpec(Node baseNode, ExecutionSpec executionSpec)
320 throws RepositoryException {
321 for (String attrName : executionSpec.getAttributes().keySet()) {
322 ExecutionSpecAttribute esa = executionSpec.getAttributes().get(
323 attrName);
324 Node attrNode = baseNode.addNode(attrName);
325 // booleans
326 attrNode.addMixin(SlcTypes.SLC_EXECUTION_SPEC_ATTRIBUTE);
327 attrNode.setProperty(SLC_IS_IMMUTABLE, esa.getIsImmutable());
328 attrNode.setProperty(SLC_IS_CONSTANT, esa.getIsConstant());
329 attrNode.setProperty(SLC_IS_HIDDEN, esa.getIsHidden());
330
331 if (esa instanceof PrimitiveSpecAttribute) {
332 attrNode.addMixin(SlcTypes.SLC_PRIMITIVE_SPEC_ATTRIBUTE);
333 PrimitiveSpecAttribute psa = (PrimitiveSpecAttribute) esa;
334 SlcJcrUtils.setPrimitiveAsProperty(attrNode, SLC_VALUE, psa);
335 attrNode.setProperty(SLC_TYPE, psa.getType());
336 } else if (esa instanceof RefSpecAttribute) {
337 attrNode.addMixin(SlcTypes.SLC_REF_SPEC_ATTRIBUTE);
338 RefSpecAttribute rsa = (RefSpecAttribute) esa;
339 attrNode.setProperty(SLC_TYPE, rsa.getTargetClassName());
340 Object value = rsa.getValue();
341 if (rsa.getChoices() != null) {
342 Integer index = null;
343 int count = 0;
344 for (RefValueChoice choice : rsa.getChoices()) {
345 String name = choice.getName();
346 if (value != null && name.equals(value.toString()))
347 index = count;
348 Node choiceNode = attrNode.addNode(choice.getName());
349 choiceNode.addMixin(NodeType.MIX_TITLE);
350 choiceNode.setProperty(Property.JCR_TITLE,
351 choice.getName());
352 if (choice.getDescription() != null
353 && !choice.getDescription().trim().equals(""))
354 choiceNode.setProperty(Property.JCR_DESCRIPTION,
355 choice.getDescription());
356 count++;
357 }
358
359 if (index != null)
360 attrNode.setProperty(SLC_VALUE, index);
361 }
362 }
363 }
364 }
365
366 public synchronized void executionFlowRemoved(ModuleDescriptor module,
367 ExecutionFlowDescriptor executionFlow) {
368 try {
369 Node agentNode = session.getNode(agent.getNodePath());
370 Node moduleNode = agentNode.getNode(SlcJcrUtils
371 .getModuleNodeName(module));
372 String relativePath = getExecutionFlowRelativePath(executionFlow);
373 if (moduleNode.hasNode(relativePath))
374 moduleNode.getNode(relativePath).remove();
375 agentNode.getSession().save();
376 } catch (RepositoryException e) {
377 throw new SlcException("Cannot remove flow " + executionFlow
378 + " from module " + module, e);
379 }
380 }
381
382 /*
383 * UTILITIES
384 */
385 /** @return the relative path, never starts with '/' */
386 @SuppressWarnings("deprecation")
387 protected String getExecutionFlowRelativePath(
388 ExecutionFlowDescriptor executionFlow) {
389 String relativePath = executionFlow.getPath() == null ? executionFlow
390 .getName() : executionFlow.getPath() + '/'
391 + executionFlow.getName();
392 // we assume that it is more than one char long
393 if (relativePath.charAt(0) == '/')
394 relativePath = relativePath.substring(1);
395 // FIXME quick hack to avoid duplicate '/'
396 relativePath = relativePath.replaceAll("//", "/");
397 return relativePath;
398 }
399
400 /*
401 * BEAN
402 */
403 public void setAgent(JcrAgent agent) {
404 this.agent = agent;
405 }
406
407 public void setRepository(Repository repository) {
408 this.repository = repository;
409 }
410
411 public void setModulesManager(ExecutionModulesManager modulesManager) {
412 this.modulesManager = modulesManager;
413 }
414
415 }