2 * Copyright (C) 2007-2012 Argeo GmbH
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.slc
.jcr
;
18 import java
.util
.Calendar
;
19 import java
.util
.GregorianCalendar
;
20 import java
.util
.List
;
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
;
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
;
42 * Utilities around the SLC JCR model. Note that it relies on fixed base paths
43 * (convention over configuration) for optimization purposes.
45 public class SlcJcrUtils
implements SlcNames
{
46 public final static Integer AGENT_FACTORY_DEPTH
= 3;
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
]);
55 return buf
.toString();
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
]);
66 return buf
.toString();
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('_'));
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
);
86 /** Module node name based on module name and version */
87 public static String
getModuleNodeName(ModuleDescriptor moduleDescriptor
) {
88 return moduleDescriptor
.getName() + "_" + moduleDescriptor
.getVersion();
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
]);
99 return buf
.toString();
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
;
109 /** Get the base for the user processi. */
110 public static String
getSlcProcessesBasePath(Session session
) {
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
);
125 * Create a new execution result path in the user home based on the current
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());
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
);
150 return absPath
.toString() + uuid
;
154 * Set the value of the primitive accessor as a JCR property. Does nothing
155 * if the value is null.
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
);
164 /** Map a primitive value to JCR property value. */
165 public static void setPrimitiveAsProperty(Node node
, String propertyName
,
166 String type
, Object value
) {
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
);
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
));
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
);
198 /** Aggregates the {@link TestStatus} of this sub-tree. */
199 public static Integer
aggregateTestStatus(Node node
) {
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
;
208 status
= TestStatus
.FAILED
;
210 NodeIterator it
= node
.getNodes();
211 while (it
.hasNext()) {
212 Node curr
= it
.nextNode();
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
;
222 } catch (Exception e
) {
223 throw new SlcException("Could not aggregate test status from "
229 * Aggregates the {@link TestStatus} of this sub-tree.
231 * @return the same {@link StringBuffer}, for convenience (typically calling
234 public static StringBuffer
aggregateTestMessages(Node node
,
235 StringBuffer messages
) {
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());
243 if (node
.hasProperty(SLC_ERROR_MESSAGE
)) {
244 if (messages
.length() > 0)
245 messages
.append('\n');
246 messages
.append(node
.getProperty(SLC_ERROR_MESSAGE
)
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
);
259 } catch (Exception e
) {
260 throw new SlcException("Could not aggregate test messages from "
265 /** Prevents instantiation */
266 private SlcJcrUtils() {