001/* 002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and contributors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Nuxeo - initial API and implementation 018 * 019 * $Id: IdUtils.java 19046 2007-05-21 13:03:50Z sfermigier $ 020 */ 021 022package org.nuxeo.common.utils; 023 024import java.util.ArrayList; 025import java.util.Date; 026import java.util.List; 027import java.util.Random; 028import java.util.regex.Pattern; 029 030/** 031 * Utils for identifier generation. 032 * 033 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a> 034 */ 035public final class IdUtils { 036 037 private static final String WORD_SPLITTING_REGEXP = "[^a-zA-Z0-9]+"; 038 039 public static final String UUID_TYPE_4_REGEXP = "[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"; 040 041 // TODO AT: dummy random, does not ensure uniqueness 042 private static final Random RANDOM = new Random(new Date().getTime()); 043 044 // This is an utility class. 045 private IdUtils() { 046 } 047 048 /** 049 * Generates an unique string identifier. 050 */ 051 public static String generateStringId() { 052 return String.valueOf(generateLongId()); 053 } 054 055 /** 056 * Generates an unique long identifier. 057 */ 058 public static long generateLongId() { 059 long r = RANDOM.nextLong(); 060 if (r < 0) { 061 r = -r; 062 } 063 return r; 064 } 065 066 /** 067 * Generates an id from a non-null String. 068 * <p> 069 * Replaces accented characters from a string by their ascii equivalent, removes non alphanumerical characters and 070 * replaces spaces by the given wordSeparator character. 071 * 072 * @param s the original String 073 * @param wordSeparator the word separator to use (usually '-') 074 * @param lower if lower is true, remove upper case 075 * @param maxChars maximum longer of identifier characters 076 * @return the identifier String 077 */ 078 public static String generateId(String s, String wordSeparator, boolean lower, int maxChars) { 079 s = StringUtils.toAscii(s); 080 s = s.trim(); 081 if (lower) { 082 s = s.toLowerCase(); 083 } 084 String[] words = s.split(WORD_SPLITTING_REGEXP); 085 // remove blank chars from words, did not get why they're not filtered 086 List<String> wordsList = new ArrayList<String>(); 087 for (String word : words) { 088 if (word != null && word.length() > 0) { 089 wordsList.add(word); 090 } 091 } 092 if (wordsList.isEmpty()) { 093 return generateStringId(); 094 } 095 StringBuilder sb = new StringBuilder(); 096 String id; 097 if (maxChars > 0) { 098 // be sure at least one word is used 099 sb.append(wordsList.get(0)); 100 for (int i = 1; i < wordsList.size(); i++) { 101 String newWord = wordsList.get(i); 102 if (sb.length() + newWord.length() > maxChars) { 103 break; 104 } else { 105 sb.append(wordSeparator).append(newWord); 106 } 107 } 108 id = sb.toString(); 109 id = id.substring(0, Math.min(id.length(), maxChars)); 110 } else { 111 id = StringUtils.join(wordsList.toArray(), wordSeparator); 112 } 113 114 return id; 115 } 116 117 /** 118 * Generates an id from a non-null String. 119 * <p> 120 * Uses default values for wordSeparator: '-', lower: true, maxChars: 24. 121 * 122 * @deprecated use {@link #generatePathSegment} instead, or {@link #generateId(String, String, boolean, int)} 123 * depending on the use cases 124 */ 125 @Deprecated 126 public static String generateId(String s) { 127 return generateId(s, "-", true, 24); 128 } 129 130 public static final Pattern STUPID_REGEXP = Pattern.compile("^[- .,;?!:/\\\\'\"]*$"); 131 132 /** 133 * Generates a Nuxeo path segment from a non-null String. 134 * <p> 135 * Basically all characters are kept, except for slashes and initial/trailing spaces. 136 * 137 * @deprecated use {@link PathSegmentService} instead 138 */ 139 @Deprecated 140 public static String generatePathSegment(String s) { 141 s = s.trim(); 142 if (STUPID_REGEXP.matcher(s).matches()) { 143 return generateStringId(); 144 } 145 return s.replace("/", "-"); 146 } 147 148 /** 149 * Check if a given string has the pattern for UUID type 4 150 * 151 * @since 5.7 152 */ 153 public static boolean isValidUUID(String uuid) { 154 if (Pattern.compile(UUID_TYPE_4_REGEXP).matcher(uuid).matches()) { 155 return true; 156 } 157 return false; 158 } 159 160}