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