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