]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.core/src/org/argeo/slc/jcr/SlcJcrUtils.java
Make processes persistence switchable
[gpl/argeo-slc.git] / org.argeo.slc.core / src / org / argeo / slc / jcr / SlcJcrUtils.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;
17
18 import java.util.Calendar;
19 import java.util.GregorianCalendar;
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.RepositoryException;
26 import javax.jcr.Session;
27 import javax.jcr.nodetype.NodeType;
28
29 import org.argeo.jcr.JcrUtils;
30 import org.argeo.node.NodeUtils;
31 import org.argeo.slc.DefaultNameVersion;
32 import org.argeo.slc.NameVersion;
33 import org.argeo.slc.SlcException;
34 import org.argeo.slc.SlcNames;
35 import org.argeo.slc.SlcTypes;
36 import org.argeo.slc.core.execution.PrimitiveAccessor;
37 import org.argeo.slc.core.execution.PrimitiveUtils;
38 import org.argeo.slc.deploy.ModuleDescriptor;
39 import org.argeo.slc.test.TestStatus;
40
41 /**
42 * Utilities around the SLC JCR model. Note that it relies on fixed base paths
43 * (convention over configuration) for optimization purposes.
44 */
45 public class SlcJcrUtils implements SlcNames {
46 public final static Integer AGENT_FACTORY_DEPTH = 3;
47
48 /** Extracts the path of a flow relative to its execution module */
49 public static String flowRelativePath(String fullFlowPath) {
50 String[] tokens = fullFlowPath.split("/");
51 StringBuffer buf = new StringBuffer(fullFlowPath.length());
52 for (int i = AGENT_FACTORY_DEPTH + 3; i < tokens.length; i++) {
53 buf.append('/').append(tokens[i]);
54 }
55 return buf.toString();
56 }
57
58 /** Extracts the path to the related execution module */
59 public static String modulePath(String fullFlowPath) {
60 String[] tokens = fullFlowPath.split("/");
61 StringBuffer buf = new StringBuffer(fullFlowPath.length());
62 for (int i = 0; i < AGENT_FACTORY_DEPTH + 3; i++) {
63 if (!tokens[i].equals(""))
64 buf.append('/').append(tokens[i]);
65 }
66 return buf.toString();
67 }
68
69 /** Extracts the module name from a flow path */
70 public static String moduleName(String fullFlowPath) {
71 String[] tokens = fullFlowPath.split("/");
72 String moduleName = tokens[AGENT_FACTORY_DEPTH + 2];
73 moduleName = moduleName.substring(0, moduleName.indexOf('_'));
74 return moduleName;
75 }
76
77 /** Extracts the module name and version from a flow path */
78 public static NameVersion moduleNameVersion(String fullFlowPath) {
79 String[] tokens = fullFlowPath.split("/");
80 String module = tokens[AGENT_FACTORY_DEPTH + 2];
81 String moduleName = module.substring(0, module.indexOf('_'));
82 String moduleVersion = module.substring(module.indexOf('_') + 1);
83 return new DefaultNameVersion(moduleName, moduleVersion);
84 }
85
86 /** Module node name based on module name and version */
87 public static String getModuleNodeName(ModuleDescriptor moduleDescriptor) {
88 return moduleDescriptor.getName() + "_" + moduleDescriptor.getVersion();
89 }
90
91 /** Extracts the agent factory of a flow */
92 public static String flowAgentFactoryPath(String fullFlowPath) {
93 String[] tokens = fullFlowPath.split("/");
94 StringBuffer buf = new StringBuffer(fullFlowPath.length());
95 // first token is always empty
96 for (int i = 1; i < AGENT_FACTORY_DEPTH + 1; i++) {
97 buf.append('/').append(tokens[i]);
98 }
99 return buf.toString();
100 }
101
102 /** Create a new execution process path based on the current time */
103 public static String createExecutionProcessPath(Session session, String uuid) {
104 Calendar now = new GregorianCalendar();
105 return getSlcProcessesBasePath(session) + '/'
106 + JcrUtils.dateAsPath(now, true) + uuid;
107 }
108
109 /** Get the base for the user processi. */
110 public static String getSlcProcessesBasePath(Session session) {
111 try {
112 Node userHome = NodeUtils.getUserHome(session);
113 if (userHome == null)
114 throw new SlcException("No user home available for "
115 + session.getUserID());
116 return userHome.getPath() + '/' + SlcNames.SLC_SYSTEM + '/'
117 + SlcNames.SLC_PROCESSES;
118 } catch (RepositoryException re) {
119 throw new SlcException(
120 "Unexpected error while getting Slc Results Base Path.", re);
121 }
122 }
123
124 /**
125 * Create a new execution result path in the user home based on the current
126 * time
127 */
128 public static String createResultPath(Session session, String uuid)
129 throws RepositoryException {
130 Calendar now = new GregorianCalendar();
131 StringBuffer absPath = new StringBuffer(
132 SlcJcrResultUtils.getSlcResultsBasePath(session) + '/');
133 // Remove hours and add title property to the result process path on
134 // request of O. Capillon
135 // return getSlcProcessesBasePath(session) + '/'
136 // + JcrUtils.dateAsPath(now, true) + uuid;
137 String relPath = JcrUtils.dateAsPath(now, false);
138 List<String> names = JcrUtils.tokenize(relPath);
139 for (String name : names) {
140 absPath.append(name + "/");
141 Node node = JcrUtils.mkdirs(session, absPath.toString());
142 try {
143 node.addMixin(NodeType.MIX_TITLE);
144 node.setProperty(Property.JCR_TITLE, name.substring(1));
145 } catch (RepositoryException e) {
146 throw new SlcException(
147 "unable to create execution process path", e);
148 }
149 }
150 return absPath.toString() + uuid;
151 }
152
153 /**
154 * Set the value of the primitive accessor as a JCR property. Does nothing
155 * if the value is null.
156 */
157 public static void setPrimitiveAsProperty(Node node, String propertyName,
158 PrimitiveAccessor primitiveAccessor) {
159 String type = primitiveAccessor.getType();
160 Object value = primitiveAccessor.getValue();
161 setPrimitiveAsProperty(node, propertyName, type, value);
162 }
163
164 /** Map a primitive value to JCR property value. */
165 public static void setPrimitiveAsProperty(Node node, String propertyName,
166 String type, Object value) {
167 if (value == null)
168 return;
169 if (value instanceof CharSequence)
170 value = PrimitiveUtils.convert(type,
171 ((CharSequence) value).toString());
172 if (value instanceof char[])
173 value = new String((char[]) value);
174
175 try {
176 if (type.equals(PrimitiveAccessor.TYPE_STRING))
177 node.setProperty(propertyName, value.toString());
178 else if (type.equals(PrimitiveAccessor.TYPE_PASSWORD))
179 node.setProperty(propertyName, value.toString());
180 else if (type.equals(PrimitiveAccessor.TYPE_INTEGER))
181 node.setProperty(propertyName, (long) ((Integer) value));
182 else if (type.equals(PrimitiveAccessor.TYPE_LONG))
183 node.setProperty(propertyName, ((Long) value));
184 else if (type.equals(PrimitiveAccessor.TYPE_FLOAT))
185 node.setProperty(propertyName, (double) ((Float) value));
186 else if (type.equals(PrimitiveAccessor.TYPE_DOUBLE))
187 node.setProperty(propertyName, ((Double) value));
188 else if (type.equals(PrimitiveAccessor.TYPE_BOOLEAN))
189 node.setProperty(propertyName, ((Boolean) value));
190 else
191 throw new SlcException("Unsupported type " + type);
192 } catch (RepositoryException e) {
193 throw new SlcException("Cannot set primitive of " + type
194 + " as property " + propertyName + " on " + node, e);
195 }
196 }
197
198 /** Aggregates the {@link TestStatus} of this sub-tree. */
199 public static Integer aggregateTestStatus(Node node) {
200 try {
201 Integer status = TestStatus.PASSED;
202 if (node.isNodeType(SlcTypes.SLC_CHECK))
203 if (node.getProperty(SLC_SUCCESS).getBoolean())
204 status = TestStatus.PASSED;
205 else if (node.hasProperty(SLC_ERROR_MESSAGE))
206 status = TestStatus.ERROR;
207 else
208 status = TestStatus.FAILED;
209
210 NodeIterator it = node.getNodes();
211 while (it.hasNext()) {
212 Node curr = it.nextNode();
213
214 // Manually skip aggregated status
215 if (!SlcNames.SLC_AGGREGATED_STATUS.equals(curr.getName())) {
216 Integer childStatus = aggregateTestStatus(curr);
217 if (childStatus > status)
218 status = childStatus;
219 }
220 }
221 return status;
222 } catch (Exception e) {
223 throw new SlcException("Could not aggregate test status from "
224 + node, e);
225 }
226 }
227
228 /**
229 * Aggregates the {@link TestStatus} of this sub-tree.
230 *
231 * @return the same {@link StringBuffer}, for convenience (typically calling
232 * toString() on it)
233 */
234 public static StringBuffer aggregateTestMessages(Node node,
235 StringBuffer messages) {
236 try {
237 if (node.isNodeType(SlcTypes.SLC_CHECK)) {
238 if (node.hasProperty(SLC_MESSAGE)) {
239 if (messages.length() > 0)
240 messages.append('\n');
241 messages.append(node.getProperty(SLC_MESSAGE).getString());
242 }
243 if (node.hasProperty(SLC_ERROR_MESSAGE)) {
244 if (messages.length() > 0)
245 messages.append('\n');
246 messages.append(node.getProperty(SLC_ERROR_MESSAGE)
247 .getString());
248 }
249 }
250 NodeIterator it = node.getNodes();
251 while (it.hasNext()) {
252 Node child = it.nextNode();
253 // Manually skip aggregated status
254 if (!SlcNames.SLC_AGGREGATED_STATUS.equals(child.getName())) {
255 aggregateTestMessages(child, messages);
256 }
257 }
258 return messages;
259 } catch (Exception e) {
260 throw new SlcException("Could not aggregate test messages from "
261 + node, e);
262 }
263 }
264
265 /** Prevents instantiation */
266 private SlcJcrUtils() {
267 }
268 }