1 package org
.argeo
.slc
.jcr
;
3 import java
.util
.Calendar
;
4 import java
.util
.GregorianCalendar
;
8 import javax
.jcr
.NodeIterator
;
9 import javax
.jcr
.Property
;
10 import javax
.jcr
.RepositoryException
;
11 import javax
.jcr
.Session
;
12 import javax
.jcr
.nodetype
.NodeType
;
14 import org
.argeo
.api
.NodeUtils
;
15 import org
.argeo
.jcr
.JcrUtils
;
16 import org
.argeo
.slc
.DefaultNameVersion
;
17 import org
.argeo
.slc
.NameVersion
;
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
.primitive
.PrimitiveAccessor
;
23 import org
.argeo
.slc
.primitive
.PrimitiveUtils
;
24 import org
.argeo
.slc
.test
.TestStatus
;
27 * Utilities around the SLC JCR model. Note that it relies on fixed base paths
28 * (convention over configuration) for optimization purposes.
30 public class SlcJcrUtils
implements SlcNames
{
31 public final static Integer AGENT_FACTORY_DEPTH
= 3;
33 /** Extracts the path of a flow relative to its execution module */
34 public static String
flowRelativePath(String fullFlowPath
) {
35 String
[] tokens
= fullFlowPath
.split("/");
36 StringBuffer buf
= new StringBuffer(fullFlowPath
.length());
37 for (int i
= AGENT_FACTORY_DEPTH
+ 3; i
< tokens
.length
; i
++) {
38 buf
.append('/').append(tokens
[i
]);
40 return buf
.toString();
43 /** Extracts the path to the related execution module */
44 public static String
modulePath(String fullFlowPath
) {
45 String
[] tokens
= fullFlowPath
.split("/");
46 StringBuffer buf
= new StringBuffer(fullFlowPath
.length());
47 for (int i
= 0; i
< AGENT_FACTORY_DEPTH
+ 3; i
++) {
48 if (!tokens
[i
].equals(""))
49 buf
.append('/').append(tokens
[i
]);
51 return buf
.toString();
54 /** Extracts the module name from a flow path */
55 public static String
moduleName(String fullFlowPath
) {
56 String
[] tokens
= fullFlowPath
.split("/");
57 String moduleName
= tokens
[AGENT_FACTORY_DEPTH
+ 2];
58 moduleName
= moduleName
.substring(0, moduleName
.indexOf('_'));
62 /** Extracts the module name and version from a flow path */
63 public static NameVersion
moduleNameVersion(String fullFlowPath
) {
64 String
[] tokens
= fullFlowPath
.split("/");
65 String module
= tokens
[AGENT_FACTORY_DEPTH
+ 2];
66 String moduleName
= module
.substring(0, module
.indexOf('_'));
67 String moduleVersion
= module
.substring(module
.indexOf('_') + 1);
68 return new DefaultNameVersion(moduleName
, moduleVersion
);
71 /** Module node name based on module name and version */
72 public static String
getModuleNodeName(ModuleDescriptor moduleDescriptor
) {
73 return moduleDescriptor
.getName() + "_" + moduleDescriptor
.getVersion();
76 /** Extracts the agent factory of a flow */
77 public static String
flowAgentFactoryPath(String fullFlowPath
) {
78 String
[] tokens
= fullFlowPath
.split("/");
79 StringBuffer buf
= new StringBuffer(fullFlowPath
.length());
80 // first token is always empty
81 for (int i
= 1; i
< AGENT_FACTORY_DEPTH
+ 1; i
++) {
82 buf
.append('/').append(tokens
[i
]);
84 return buf
.toString();
87 /** Create a new execution process path based on the current time */
88 public static String
createExecutionProcessPath(Session session
, String uuid
) {
89 Calendar now
= new GregorianCalendar();
90 return getSlcProcessesBasePath(session
) + '/'
91 + JcrUtils
.dateAsPath(now
, true) + uuid
;
94 /** Get the base for the user processi. */
95 public static String
getSlcProcessesBasePath(Session session
) {
97 Node userHome
= NodeUtils
.getUserHome(session
);
99 throw new SlcException("No user home available for "
100 + session
.getUserID());
101 return userHome
.getPath() + '/' + SlcNames
.SLC_SYSTEM
+ '/'
102 + SlcNames
.SLC_PROCESSES
;
103 } catch (RepositoryException re
) {
104 throw new SlcException(
105 "Unexpected error while getting Slc Results Base Path.", re
);
110 * Create a new execution result path in the user home based on the current
113 public static String
createResultPath(Session session
, String uuid
)
114 throws RepositoryException
{
115 Calendar now
= new GregorianCalendar();
116 StringBuffer absPath
= new StringBuffer(
117 SlcJcrResultUtils
.getSlcResultsBasePath(session
) + '/');
118 // Remove hours and add title property to the result process path on
119 // request of O. Capillon
120 // return getSlcProcessesBasePath(session) + '/'
121 // + JcrUtils.dateAsPath(now, true) + uuid;
122 String relPath
= JcrUtils
.dateAsPath(now
, false);
123 List
<String
> names
= JcrUtils
.tokenize(relPath
);
124 for (String name
: names
) {
125 absPath
.append(name
+ "/");
126 Node node
= JcrUtils
.mkdirs(session
, absPath
.toString());
128 node
.addMixin(NodeType
.MIX_TITLE
);
129 node
.setProperty(Property
.JCR_TITLE
, name
.substring(1));
130 } catch (RepositoryException e
) {
131 throw new SlcException(
132 "unable to create execution process path", e
);
135 return absPath
.toString() + uuid
;
139 * Set the value of the primitive accessor as a JCR property. Does nothing
140 * if the value is null.
142 public static void setPrimitiveAsProperty(Node node
, String propertyName
,
143 PrimitiveAccessor primitiveAccessor
) {
144 String type
= primitiveAccessor
.getType();
145 Object value
= primitiveAccessor
.getValue();
146 setPrimitiveAsProperty(node
, propertyName
, type
, value
);
149 /** Map a primitive value to JCR property value. */
150 public static void setPrimitiveAsProperty(Node node
, String propertyName
,
151 String type
, Object value
) {
154 if (value
instanceof CharSequence
)
155 value
= PrimitiveUtils
.convert(type
,
156 ((CharSequence
) value
).toString());
157 if (value
instanceof char[])
158 value
= new String((char[]) value
);
161 if (type
.equals(PrimitiveAccessor
.TYPE_STRING
))
162 node
.setProperty(propertyName
, value
.toString());
163 else if (type
.equals(PrimitiveAccessor
.TYPE_PASSWORD
))
164 node
.setProperty(propertyName
, value
.toString());
165 else if (type
.equals(PrimitiveAccessor
.TYPE_INTEGER
))
166 node
.setProperty(propertyName
, (long) ((Integer
) value
));
167 else if (type
.equals(PrimitiveAccessor
.TYPE_LONG
))
168 node
.setProperty(propertyName
, ((Long
) value
));
169 else if (type
.equals(PrimitiveAccessor
.TYPE_FLOAT
))
170 node
.setProperty(propertyName
, (double) ((Float
) value
));
171 else if (type
.equals(PrimitiveAccessor
.TYPE_DOUBLE
))
172 node
.setProperty(propertyName
, ((Double
) value
));
173 else if (type
.equals(PrimitiveAccessor
.TYPE_BOOLEAN
))
174 node
.setProperty(propertyName
, ((Boolean
) value
));
176 throw new SlcException("Unsupported type " + type
);
177 } catch (RepositoryException e
) {
178 throw new SlcException("Cannot set primitive of " + type
179 + " as property " + propertyName
+ " on " + node
, e
);
183 /** Aggregates the {@link TestStatus} of this sub-tree. */
184 public static Integer
aggregateTestStatus(Node node
) {
186 Integer status
= TestStatus
.PASSED
;
187 if (node
.isNodeType(SlcTypes
.SLC_CHECK
))
188 if (node
.getProperty(SLC_SUCCESS
).getBoolean())
189 status
= TestStatus
.PASSED
;
190 else if (node
.hasProperty(SLC_ERROR_MESSAGE
))
191 status
= TestStatus
.ERROR
;
193 status
= TestStatus
.FAILED
;
195 NodeIterator it
= node
.getNodes();
196 while (it
.hasNext()) {
197 Node curr
= it
.nextNode();
199 // Manually skip aggregated status
200 if (!SlcNames
.SLC_AGGREGATED_STATUS
.equals(curr
.getName())) {
201 Integer childStatus
= aggregateTestStatus(curr
);
202 if (childStatus
> status
)
203 status
= childStatus
;
207 } catch (Exception e
) {
208 throw new SlcException("Could not aggregate test status from "
214 * Aggregates the {@link TestStatus} of this sub-tree.
216 * @return the same {@link StringBuffer}, for convenience (typically calling
219 public static StringBuffer
aggregateTestMessages(Node node
,
220 StringBuffer messages
) {
222 if (node
.isNodeType(SlcTypes
.SLC_CHECK
)) {
223 if (node
.hasProperty(SLC_MESSAGE
)) {
224 if (messages
.length() > 0)
225 messages
.append('\n');
226 messages
.append(node
.getProperty(SLC_MESSAGE
).getString());
228 if (node
.hasProperty(SLC_ERROR_MESSAGE
)) {
229 if (messages
.length() > 0)
230 messages
.append('\n');
231 messages
.append(node
.getProperty(SLC_ERROR_MESSAGE
)
235 NodeIterator it
= node
.getNodes();
236 while (it
.hasNext()) {
237 Node child
= it
.nextNode();
238 // Manually skip aggregated status
239 if (!SlcNames
.SLC_AGGREGATED_STATUS
.equals(child
.getName())) {
240 aggregateTestMessages(child
, messages
);
244 } catch (Exception e
) {
245 throw new SlcException("Could not aggregate test messages from "
250 /** Prevents instantiation */
251 private SlcJcrUtils() {