Java tutorial
/** * Licensed to the Sakai Foundation (SF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The SF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package org.sakaiproject.nakamura.util; import org.apache.jackrabbit.api.security.principal.ItemBasedPrincipal; import org.apache.jackrabbit.api.security.user.Authorizable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Principal; import java.util.Calendar; import javax.jcr.RepositoryException; /** * Generate a path prefix based on the user id. * */ public class PathUtils { /** * */ private static final Logger logger = LoggerFactory.getLogger(PathUtils.class); /** * Generate a path using a SHA-1 hash split into path parts to generate a unique path to * the user information, that will not result in too many objects in each folder. * * @param user * the user for which the path will be generated. * @return a structured path fragment for the user. */ @Deprecated public static String getUserPrefix(String user, int levels) { if (user != null) { if (user.length() == 0) { user = "anon"; } return getStructuredHash(user, levels, false); } return null; } /** * Get the prefix for a message. * * @return Prefix used to store a message. Defaults to a yyyy/mm/dd structure. * @see java.text.SimpleDateFormat for pattern definitions. */ @Deprecated public static String getMessagePath() { Calendar c = Calendar.getInstance(); String prefix = "/" + c.get(Calendar.YEAR) + "/" + c.get(Calendar.MONTH) + "/"; return prefix; } /** * @param target * the target being formed into a structured path. * @param b * @return the structured path. */ private static String getStructuredHash(String target, int levels, boolean absPath) { try { // take the first element as the key for the target so that subtrees end up in the // same place. String[] elements = StringUtils.split(target, '/', 1); String pathInfo = removeFirstElement(target); target = elements[0]; target = String.valueOf(target); MessageDigest md = MessageDigest.getInstance("SHA-1"); byte[] userHash = md.digest(target.getBytes("UTF-8")); char[] chars = new char[(absPath ? 1 : 0) + levels * 3 + target.length() + pathInfo.length()]; int j = 0; if (absPath) { chars[j++] = '/'; } for (int i = 0; i < levels; i++) { byte current = userHash[i]; int hi = (current & 0xF0) >> 4; int lo = current & 0x0F; chars[j++] = (char) (hi < 10 ? ('0' + hi) : ('a' + hi - 10)); chars[j++] = (char) (lo < 10 ? ('0' + lo) : ('a' + lo - 10)); chars[j++] = '/'; } for (int i = 0; i < target.length(); i++) { char c = target.charAt(i); if (!Character.isLetterOrDigit(c)) { c = '_'; } chars[j++] = c; } for (int i = 0; i < pathInfo.length(); i++) { chars[j++] = pathInfo.charAt(i); } return new String(chars); } catch (NoSuchAlgorithmException e) { logger.error(e.getMessage(), e); } catch (UnsupportedEncodingException e) { logger.error(e.getMessage(), e); } return null; } /** * Return the path of the parent node. * * @param resourceReference * A string that represents a path in JCR (can end with /) * @return If given "/foo/bar///" will return /foo. */ public static String getParentReference(String resourceReference) { char[] ref = resourceReference.toCharArray(); int i = ref.length - 1; while (i >= 0 && ref[i] == '/') { i--; } while (i >= 0 && ref[i] != '/') { i--; } while (i >= 0 && ref[i] == '/') { i--; } if (i == -1) { return "/"; } return new String(ref, 0, i + 1); } /** * @param path * the original path. * @return a pooled hash of the filename */ @Deprecated public static String getDatePath(String path, int levels) { String hash = getStructuredHash(path, levels, true); Calendar c = Calendar.getInstance(); StringBuilder sb = new StringBuilder(); sb.append("/").append(c.get(Calendar.YEAR)).append("/").append(c.get(Calendar.MONTH)).append(hash); return sb.toString(); } /** * @param path * the original path. * @return a pooled hash of the filename */ public static String getShardPath(String path, int levels) { return getStructuredHash(path, levels, true); } /** * Normalizes the input path to an absolute path prepending / and ensuring that the path * does not end in /. * * @param pathFragment * the path. * @return a normalized path. */ public static String normalizePath(String pathFragment) { if (pathFragment == null) { return ""; } char[] source = pathFragment.toCharArray(); char[] normalized = new char[source.length + 1]; int i = 0; int j = 0; if (source.length == 0 || source[i] != '/') { normalized[j++] = '/'; } boolean slash = false; for (; i < source.length; i++) { char c = source[i]; switch (c) { case '/': if (!slash) { normalized[j++] = c; } slash = true; break; default: slash = false; normalized[j++] = c; break; } } if (j > 1 && normalized[j - 1] == '/') { j--; } return new String(normalized, 0, j); } /** * Removes the first element of the path * * @param path * the path * @return the path with the first element removed. */ public static String removeFirstElement(String path) { if (path == null || path.length() == 0) { return path; } char[] p = path.toCharArray(); int i = 0; while (i < p.length && p[i] == '/') { i++; } while (i < p.length && p[i] != '/') { i++; } if (i < p.length) { return new String(p, i, p.length - i); } return "/"; } /** * Remove the last path element. * * @param path * the path * @return the path with the last element removed. */ public static String removeLastElement(String path) { if (path == null || path.length() == 0) { return path; } char[] p = path.toCharArray(); int i = p.length - 1; while (i >= 0 && p[i] == '/') { i--; } while (i >= 0 && p[i] != '/') { i--; } if (i > 0) { return new String(p, 0, i); } return "/"; } /** * Parses the path into all the parts before the first . in the last path element, and * everything after the first . in the last element. * * @param relativePath * @return */ public static String[] getNodePathParts(String relativePath) { char[] c = relativePath.toCharArray(); int dot = -1; for (int i = 0; i < c.length; i++) { if (c[i] == '/') { dot = -1; } else if (c[i] == '.' && dot == -1) { dot = i; } } if (dot < 0) { return new String[] { relativePath, "" }; } return new String[] { new String(c, 0, dot), new String(c, dot, c.length - dot) }; } /** * @param servletPath * @param pathInfo * @return */ public static String toInternalShardPath(String servletPath, String pathInfo, String selector) { return PathUtils.normalizePath(servletPath + PathUtils.getShardPath(pathInfo, 4) + selector); } /** * Find the last element of a path. After the last / but before the first . * If the path ends in / the last element is "" * @param dest * @return the last elemtent of a path or empty if ending in "/" */ public static String lastElement(String dest) { dest = org.apache.commons.lang.StringUtils.substringAfterLast(dest, "/"); dest = org.apache.commons.lang.StringUtils.substringBefore(dest, "."); return dest; } /** * Returns a suitable hash path that can be used to create full path's to locations. * * @param o * An object that can be adapted to something where a path can get extracted * from. Currently supported: {@link Authorizable}, {@link ItemBasedPrincipal} * and {@link SubPathProducer} * @return */ public static String getSubPath(Object o) { String sub = null; if (o instanceof Authorizable) { try { Authorizable au = (Authorizable) o; Principal p = au.getPrincipal(); if (au.hasProperty("path")) { sub = au.getProperty("path")[0].getString(); } else if (p instanceof ItemBasedPrincipal) { String path = ((ItemBasedPrincipal) p).getPath(); int i = path.lastIndexOf("rep:"); i = path.indexOf('/', i + 1); sub = path.substring(i); } else { sub = "/" + au.getID(); } } catch (RepositoryException e) { throw new RuntimeException(e); } } else if (o instanceof ItemBasedPrincipal) { try { String path = ((ItemBasedPrincipal) o).getPath(); int i = path.lastIndexOf("rep:"); i = path.indexOf('/', i + 1); sub = path.substring(i); } catch (RepositoryException e) { throw new RuntimeException(e); } } else if (o instanceof Principal) { sub = "/" + ((Principal) o).getName(); } else if (o instanceof SubPathProducer) { sub = ((SubPathProducer) o).getSubPath(); } return PathUtils.normalizePath(sub); } /** * @param messagePathBase * @param messageId * @param string * @return */ public static String toSimpleShardPath(String pathBase, String messageId, String pathEnd) { char[] shard = "________".toCharArray(); for (int i = 0; i < messageId.length() && i < shard.length; i++) { shard[i] = messageId.charAt(i); } StringBuilder sb = new StringBuilder(); sb.append(pathBase); for (int i = 0; i < 4; i++) { sb.append("/").append(new String(shard, i * 2, 2)); } sb.append("/").append(messageId); sb.append(pathEnd); return sb.toString(); } public static Object translateAuthorizablePath(Object value) { String s = String.valueOf(value); if (s != null && s.length() > 4) { if (s.charAt(0) == '/' && s.charAt(1) == '_') { if (s.length() > 16 && s.startsWith("/_user/")) { return "/~" + s.substring(16); } else if (s.length() > 17 && s.startsWith("/_group/")) { return "/~" + s.substring(17); } } else if (s.startsWith("a:")) { return "/~" + s.substring(2); // sparse } else if (s.startsWith("/a:")) { return "/~" + s.substring(3); // sparse, odd tricky case } } return value; } public static String getAuthorizableId(String path) { if (path.startsWith("a:") || path.startsWith("/~")) { path = path.substring(2); int i = path.indexOf('/'); if (i > 0) { path = path.substring(0, i); } return path; } return null; } public static String toUserContentPath(String path) { if (path != null) { if (path.startsWith("/~")) { return "a:" + path.substring(2); } else if (path.startsWith("/p/")) { return path.substring(3); } else if (path.startsWith("/user/")) { return "a:" + path.substring(6); } else if (path.startsWith("/group/")) { return "a:" + path.substring(7); } else { return path; } } return null; } }