]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org/argeo/jcr/JcrUtils.java
Prepare next development cycle
[lgpl/argeo-commons.git] / org / argeo / jcr / JcrUtils.java
1 /*
2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
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
17 package org.argeo.jcr;
18
19 import java.text.DateFormat;
20 import java.text.ParseException;
21 import java.util.Calendar;
22 import java.util.Date;
23 import java.util.GregorianCalendar;
24 import java.util.StringTokenizer;
25
26 import javax.jcr.NamespaceRegistry;
27 import javax.jcr.Node;
28 import javax.jcr.NodeIterator;
29 import javax.jcr.Property;
30 import javax.jcr.PropertyIterator;
31 import javax.jcr.RepositoryException;
32 import javax.jcr.Session;
33 import javax.jcr.Value;
34 import javax.jcr.query.Query;
35 import javax.jcr.query.QueryResult;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.argeo.ArgeoException;
40
41 /** Utility methods to simplify common JCR operations. */
42 public class JcrUtils {
43 private final static Log log = LogFactory.getLog(JcrUtils.class);
44
45 /**
46 * Queries one single node.
47 *
48 * @return one single node or null if none was found
49 * @throws ArgeoException
50 * if more than one node was found
51 */
52 public static Node querySingleNode(Query query) {
53 NodeIterator nodeIterator;
54 try {
55 QueryResult queryResult = query.execute();
56 nodeIterator = queryResult.getNodes();
57 } catch (RepositoryException e) {
58 throw new ArgeoException("Cannot execute query " + query, e);
59 }
60 Node node;
61 if (nodeIterator.hasNext())
62 node = nodeIterator.nextNode();
63 else
64 return null;
65
66 if (nodeIterator.hasNext())
67 throw new ArgeoException("Query returned more than one node.");
68 return node;
69 }
70
71 /** Removes forbidden characters from a path, replacing them with '_' */
72 public static String removeForbiddenCharacters(String str) {
73 return str.replace('[', '_').replace(']', '_').replace('/', '_')
74 .replace('*', '_');
75
76 }
77
78 /** Retrieves the parent path of the provided path */
79 public static String parentPath(String path) {
80 if (path.equals("/"))
81 throw new ArgeoException("Root path '/' has no parent path");
82 if (path.charAt(0) != '/')
83 throw new ArgeoException("Path " + path + " must start with a '/'");
84 String pathT = path;
85 if (pathT.charAt(pathT.length() - 1) == '/')
86 pathT = pathT.substring(0, pathT.length() - 2);
87
88 int index = pathT.lastIndexOf('/');
89 return pathT.substring(0, index);
90 }
91
92 /** The provided data as a path ('/' at the end, not the beginning) */
93 public static String dateAsPath(Calendar cal) {
94 return dateAsPath(cal, false);
95 }
96
97 /**
98 * The provided data as a path ('/' at the end, not the beginning)
99 *
100 * @param cal
101 * the date
102 * @param addHour
103 * whether to add hour as well
104 */
105 public static String dateAsPath(Calendar cal, Boolean addHour) {
106 StringBuffer buf = new StringBuffer(14);
107 buf.append('Y').append(cal.get(Calendar.YEAR));// 5
108 buf.append('/');// 1
109 int month = cal.get(Calendar.MONTH) + 1;
110 buf.append('M');
111 if (month < 10)
112 buf.append(0);
113 buf.append(month);// 3
114 buf.append('/');// 1
115 int day = cal.get(Calendar.DAY_OF_MONTH);
116 if (day < 10)
117 buf.append(0);
118 buf.append('D').append(day);// 3
119 buf.append('/');// 1
120 if (addHour) {
121 int hour = cal.get(Calendar.HOUR_OF_DAY);
122 if (hour < 10)
123 buf.append(0);
124 buf.append('H').append(hour);// 3
125 buf.append('/');// 1
126 }
127 return buf.toString();
128
129 }
130
131 /** Converts in one call a string into a gregorian calendar. */
132 public static Calendar parseCalendar(DateFormat dateFormat, String value) {
133 try {
134 Date date = dateFormat.parse(value);
135 Calendar calendar = new GregorianCalendar();
136 calendar.setTime(date);
137 return calendar;
138 } catch (ParseException e) {
139 throw new ArgeoException("Cannot parse " + value
140 + " with date format " + dateFormat, e);
141 }
142
143 }
144
145 /** Converts the FQDN of an host into a path (converts '.' into '/'). */
146 public static String hostAsPath(String host) {
147 // TODO : inverse order of the elements (to have org/argeo/test IO
148 // test/argeo/org
149 return host.replace('.', '/');
150 }
151
152 /** The last element of a path. */
153 public static String lastPathElement(String path) {
154 if (path.charAt(path.length() - 1) == '/')
155 throw new ArgeoException("Path " + path + " cannot end with '/'");
156 int index = path.lastIndexOf('/');
157 if (index < 0)
158 throw new ArgeoException("Cannot find last path element for "
159 + path);
160 return path.substring(index + 1);
161 }
162
163 /** Creates the nodes making path, if they don't exist. */
164 public static Node mkdirs(Session session, String path) {
165 return mkdirs(session, path, null, false);
166 }
167
168 /** Creates the nodes making path, if they don't exist. */
169 public static Node mkdirs(Session session, String path, String type,
170 Boolean versioning) {
171 try {
172 if (path.equals('/'))
173 return session.getRootNode();
174
175 if (session.itemExists(path)) {
176 Node node = session.getNode(path);
177 // check type
178 if (type != null
179 && !type.equals(node.getPrimaryNodeType().getName()))
180 throw new ArgeoException("Node " + node
181 + " exists but is of type "
182 + node.getPrimaryNodeType().getName()
183 + " not of type " + type);
184 // TODO: check versioning
185 return node;
186 }
187
188 StringTokenizer st = new StringTokenizer(path, "/");
189 StringBuffer current = new StringBuffer("/");
190 Node currentNode = session.getRootNode();
191 while (st.hasMoreTokens()) {
192 String part = st.nextToken();
193 current.append(part).append('/');
194 if (!session.itemExists(current.toString())) {
195 if (type != null)
196 currentNode = currentNode.addNode(part, type);
197 else
198 currentNode = currentNode.addNode(part);
199 if (versioning)
200 currentNode.addMixin(ArgeoJcrConstants.MIX_VERSIONABLE);
201 if (log.isTraceEnabled())
202 log.debug("Added folder " + part + " as " + current);
203 } else {
204 currentNode = (Node) session.getItem(current.toString());
205 }
206 }
207 session.save();
208 return currentNode;
209 } catch (RepositoryException e) {
210 throw new ArgeoException("Cannot mkdirs " + path, e);
211 }
212 }
213
214 /**
215 * Safe and repository implementation independent registration of a
216 * namespace.
217 */
218 public static void registerNamespaceSafely(Session session, String prefix,
219 String uri) {
220 try {
221 registerNamespaceSafely(session.getWorkspace()
222 .getNamespaceRegistry(), prefix, uri);
223 } catch (RepositoryException e) {
224 throw new ArgeoException("Cannot find namespace registry", e);
225 }
226 }
227
228 /**
229 * Safe and repository implementation independent registration of a
230 * namespace.
231 */
232 public static void registerNamespaceSafely(NamespaceRegistry nr,
233 String prefix, String uri) {
234 try {
235 String[] prefixes = nr.getPrefixes();
236 for (String pref : prefixes)
237 if (pref.equals(prefix)) {
238 String registeredUri = nr.getURI(pref);
239 if (!registeredUri.equals(uri))
240 throw new ArgeoException("Prefix " + pref
241 + " already registered for URI "
242 + registeredUri
243 + " which is different from provided URI "
244 + uri);
245 else
246 return;// skip
247 }
248 nr.registerNamespace(prefix, uri);
249 } catch (RepositoryException e) {
250 throw new ArgeoException("Cannot register namespace " + uri
251 + " under prefix " + prefix, e);
252 }
253 }
254
255 /** Recursively outputs the contents of the given node. */
256 public static void debug(Node node) {
257 try {
258 // First output the node path
259 log.debug(node.getPath());
260 // Skip the virtual (and large!) jcr:system subtree
261 if (node.getName().equals(ArgeoJcrConstants.JCR_SYSTEM)) {
262 return;
263 }
264
265 // Then the children nodes (recursive)
266 NodeIterator it = node.getNodes();
267 while (it.hasNext()) {
268 Node childNode = it.nextNode();
269 debug(childNode);
270 }
271
272 // Then output the properties
273 PropertyIterator properties = node.getProperties();
274 // log.debug("Property are : ");
275
276 while (properties.hasNext()) {
277 Property property = properties.nextProperty();
278 if (property.getDefinition().isMultiple()) {
279 // A multi-valued property, print all values
280 Value[] values = property.getValues();
281 for (int i = 0; i < values.length; i++) {
282 log.debug(property.getPath() + "="
283 + values[i].getString());
284 }
285 } else {
286 // A single-valued property
287 log.debug(property.getPath() + "=" + property.getString());
288 }
289 }
290 } catch (Exception e) {
291 log.error("Could not debug " + node, e);
292 }
293
294 }
295 }