public class JcrUtils implements ArgeoJcrConstants {
private final static Log log = LogFactory.getLog(JcrUtils.class);
+ /**
+ * Not complete yet. See
+ * http://www.day.com/specs/jcr/2.0/3_Repository_Model.html#3.2.2%20Local
+ * %20Names
+ */
+ public final static char[] INVALID_NAME_CHARACTERS = { '/', ':', '[', ']',
+ '|', '*', /*
+ * invalid XML chars :
+ */
+ '<', '>', '&' };
+
/** Prevents instantiation */
private JcrUtils() {
}
return node;
}
- /** Removes forbidden characters from a path, replacing them with '_' */
- public static String removeForbiddenCharacters(String str) {
- return str.replace('[', '_').replace(']', '_').replace('/', '_')
- .replace('*', '_');
-
- }
-
/** Retrieves the parent path of the provided path */
public static String parentPath(String path) {
if (path.equals("/"))
*/
public static String dateAsPath(Calendar cal, Boolean addHour) {
StringBuffer buf = new StringBuffer(14);
- buf.append('Y').append(cal.get(Calendar.YEAR));// 5
- buf.append('/');// 1
+ buf.append('Y');
+ buf.append(cal.get(Calendar.YEAR));
+ buf.append('/');
+
int month = cal.get(Calendar.MONTH) + 1;
buf.append('M');
if (month < 10)
buf.append(0);
- buf.append(month);// 3
- buf.append('/');// 1
+ buf.append(month);
+ buf.append('/');
+
int day = cal.get(Calendar.DAY_OF_MONTH);
+ buf.append('D');
if (day < 10)
buf.append(0);
- buf.append('D').append(day);// 3
- buf.append('/');// 1
+ buf.append(day);
+ buf.append('/');
+
if (addHour) {
int hour = cal.get(Calendar.HOUR_OF_DAY);
+ buf.append('H');
if (hour < 10)
buf.append(0);
- buf.append('H').append(hour);// 3
- buf.append('/');// 1
+ buf.append(hour);
+ buf.append('/');
}
return buf.toString();
/** Recursively outputs the contents of the given node. */
public static void debug(Node node) {
+ debug(node, log);
+ }
+
+ /** Recursively outputs the contents of the given node. */
+ public static void debug(Node node, Log log) {
try {
// First output the node path
log.debug(node.getPath());
}
/**
- * Normalize a name so taht it can be stores in contexts not supporting
+ * Normalizes a name so that it can be stored in contexts not supporting
* names with ':' (typically databases). Replaces ':' by '_'.
*/
public static String normalize(String name) {
return name.replace(':', '_');
}
+ /**
+ * Replaces characters which are invalid in a JCR name by '_'. Currently not
+ * exhaustive.
+ *
+ * @see JcrUtils#INVALID_NAME_CHARACTERS
+ */
+ public static String replaceInvalidChars(String name) {
+ return replaceInvalidChars(name, '_');
+ }
+
+ /**
+ * Replaces characters which are invalid in a JCR name. Currently not
+ * exhaustive.
+ *
+ * @see JcrUtils#INVALID_NAME_CHARACTERS
+ */
+ public static String replaceInvalidChars(String name, char replacement) {
+ boolean modified = false;
+ char[] arr = name.toCharArray();
+ for (int i = 0; i < arr.length; i++) {
+ char c = arr[i];
+ invalid: for (char invalid : INVALID_NAME_CHARACTERS) {
+ if (c == invalid) {
+ arr[i] = replacement;
+ modified = true;
+ break invalid;
+ }
+ }
+ }
+ if (modified)
+ return new String(arr);
+ else
+ // do not create new object if unnecessary
+ return name;
+ }
+
+ /**
+ * Removes forbidden characters from a path, replacing them with '_'
+ *
+ * @deprecated use {@link #replaceInvalidChars(String)} instead
+ */
+ public static String removeForbiddenCharacters(String str) {
+ return str.replace('[', '_').replace(']', '_').replace('/', '_')
+ .replace('*', '_');
+
+ }
+
/** Cleanly disposes a {@link Binary} even if it is null. */
public static void closeQuietly(Binary binary) {
if (binary == null)
}
}
+ /**
+ * Discards the current changes in the session attached to this node. To be
+ * used typically in a catch block.
+ *
+ * @see #discardQuietly(Session)
+ */
+ public static void discardUnderlyingSessionQuietly(Node node) {
+ try {
+ discardQuietly(node.getSession());
+ } catch (RepositoryException e) {
+ log.warn("Cannot quietly discard session of node " + node + ": "
+ + e.getMessage());
+ }
+ }
+
/**
* Discards the current changes in a session by calling
* {@link Session#refresh(boolean)} with <code>false</code>, only logging
/** Logs out the session, not throwing any exception, even if it is null. */
public static void logoutQuietly(Session session) {
- if (session != null)
- session.logout();
+ try {
+ if (session != null)
+ if (session.isLive())
+ session.logout();
+ } catch (Exception e) {
+ // silent
+ }
}
/** Returns the home node of the session user or null if none was found. */
if (session.hasPendingChanges())
throw new ArgeoException(
"Session has pending changes, save them first");
+
String homePath = homeBasePath + '/'
+ firstCharsToPath(username, 2) + '/' + username;
- Node userHome = JcrUtils.mkdirs(session, homePath);
- Node userProfile = userHome.addNode(ArgeoNames.ARGEO_PROFILE);
- userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
- userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
- session.save();
- // we need to save the profile before adding the user home type
+ if (session.itemExists(homePath)) {
+ try {
+ throw new ArgeoException(
+ "Trying to create a user home that already exists");
+ } catch (Exception e) {
+ // we use this workaround to be sure to get the stack trace
+ // to identify the sink of the bug.
+ log.warn("trying to create an already existing userHome at path:"
+ + homePath + ". Stack trace : ");
+ e.printStackTrace();
+ }
+ }
+
+ Node userHome = JcrUtils.mkdirs(session, homePath);
+ Node userProfile;
+ if (userHome.hasNode(ArgeoNames.ARGEO_PROFILE)) {
+ log.warn("userProfile node already exists for userHome path: "
+ + homePath + ". We do not add a new one");
+ } else {
+ userProfile = userHome.addNode(ArgeoNames.ARGEO_PROFILE);
+ userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
+ userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+ session.save();
+ // we need to save the profile before adding the user home type
+ }
userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
// see
// http://jackrabbit.510166.n4.nabble.com/Jackrabbit-2-0-beta-6-Problem-adding-a-Mixin-type-with-mandatory-properties-after-setting-propertiesn-td1290332.html