001/* 002 * (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others. 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 */ 019package org.nuxeo.common.utils; 020 021import java.security.SecureRandom; 022import java.util.ArrayList; 023import java.util.List; 024import java.util.Random; 025import java.util.regex.Pattern; 026 027/** 028 * Utils for identifier generation. 029 * 030 * @author <a href="mailto:at@nuxeo.com">Anahide Tchertchian</a> 031 */ 032public final class IdUtils { 033 034 private static final String WORD_SPLITTING_REGEXP = "[^a-zA-Z0-9]+"; 035 036 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}"; 037 038 private static final Random RANDOM = new SecureRandom(); 039 040 // This is an utility class. 041 private IdUtils() { 042 } 043 044 /** 045 * Generates an unique string identifier. 046 */ 047 public static String generateStringId() { 048 return String.valueOf(generateLongId()); 049 } 050 051 /** 052 * Generates an unique long identifier. 053 */ 054 public static long generateLongId() { 055 long r = RANDOM.nextLong(); 056 if (r < 0) { 057 r = -r; 058 } 059 return r; 060 } 061 062 /** 063 * Generates an id from a non-null String. 064 * <p> 065 * Replaces accented characters from a string by their ascii equivalent, removes non alphanumerical characters and 066 * replaces spaces by the given wordSeparator character. 067 * 068 * @param s the original String 069 * @param wordSeparator the word separator to use (usually '-') 070 * @param lower if lower is true, remove upper case 071 * @param maxChars maximum longer of identifier characters 072 * @return the identifier String 073 */ 074 public static String generateId(String s, String wordSeparator, boolean lower, int maxChars) { 075 s = StringUtils.toAscii(s); 076 s = s.trim(); 077 if (lower) { 078 s = s.toLowerCase(); 079 } 080 String[] words = s.split(WORD_SPLITTING_REGEXP); 081 // remove blank chars from words, did not get why they're not filtered 082 List<String> wordsList = new ArrayList<>(); 083 for (String word : words) { 084 if (word != null && word.length() > 0) { 085 wordsList.add(word); 086 } 087 } 088 if (wordsList.isEmpty()) { 089 return generateStringId(); 090 } 091 StringBuilder sb = new StringBuilder(); 092 String id; 093 if (maxChars > 0) { 094 // be sure at least one word is used 095 sb.append(wordsList.get(0)); 096 for (int i = 1; i < wordsList.size(); i++) { 097 String newWord = wordsList.get(i); 098 if (sb.length() + newWord.length() > maxChars) { 099 break; 100 } else { 101 sb.append(wordSeparator).append(newWord); 102 } 103 } 104 id = sb.toString(); 105 id = id.substring(0, Math.min(id.length(), maxChars)); 106 } else { 107 id = String.join(wordSeparator, wordsList); 108 } 109 110 return id; 111 } 112 113 /** 114 * Check if a given string has the pattern for UUID type 4 115 * 116 * @since 5.7 117 */ 118 public static boolean isValidUUID(String uuid) { 119 return Pattern.compile(UUID_TYPE_4_REGEXP).matcher(uuid).matches(); 120 } 121 122}