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