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