001/* 002 * Copyright 2012 Anyware Services 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 */ 016package org.ametys.core.util; 017 018import java.io.UnsupportedEncodingException; 019import java.security.MessageDigest; 020import java.security.NoSuchAlgorithmException; 021import java.text.Normalizer; 022import java.util.ArrayList; 023import java.util.Collection; 024import java.util.Iterator; 025import java.util.List; 026import java.util.StringTokenizer; 027 028import org.apache.commons.codec.binary.Base64; 029import org.slf4j.Logger; 030import org.slf4j.LoggerFactory; 031 032import org.ametys.runtime.i18n.I18nizableText; 033 034/** 035 * A collection of String management utility methods. 036 */ 037public final class StringUtils 038{ 039 private static final Logger __LOGGER = LoggerFactory.getLogger(StringUtils.class); 040 041 private static final long __DATA_SIZE_NEXT_LIMIT = 1024; 042 private static final List<String> __DATA_SIZE_KEYS = List.of( 043 "PLUGINS_CORE_UI_FORMAT_FILE_SIZE_NOT_ESCAPED_BYTES", 044 "PLUGINS_CORE_UI_FORMAT_FILE_SIZE_NOT_ESCAPED_KB", 045 "PLUGINS_CORE_UI_FORMAT_FILE_SIZE_NOT_ESCAPED_MB", 046 "PLUGINS_CORE_UI_FORMAT_FILE_SIZE_NOT_ESCAPED_GB", 047 "PLUGINS_CORE_UI_FORMAT_FILE_SIZE_NOT_ESCAPED_TB" 048 ); 049 050 private StringUtils() 051 { 052 // empty private constructor 053 } 054 055 /** 056 * Extract String values from a comma seprated list. 057 * @param values the comma separated list 058 * @return a collection of String or an empty collection if string is null or empty. 059 */ 060 public static Collection<String> stringToCollection(String values) 061 { 062 Collection<String> result = new ArrayList<>(); 063 if (values != null && values.length() > 0) 064 { 065 // Explore the string list with a stringtokenizer with ','. 066 StringTokenizer stk = new StringTokenizer(values, ","); 067 068 while (stk.hasMoreTokens()) 069 { 070 // Don't forget to trim 071 result.add(stk.nextToken().trim()); 072 } 073 } 074 075 return result; 076 } 077 078 /** 079 * Extract String values from a comma seprated list. 080 * @param values the comma separated list 081 * @return an array of String 082 */ 083 public static String[] stringToStringArray(String values) 084 { 085 Collection<String> coll = stringToCollection(values); 086 return coll.toArray(new String[coll.size()]); 087 } 088 089 /** 090 * Generates a unique String key, based on System.currentTimeMillis() 091 * @return a unique String value 092 */ 093 public static String generateKey() 094 { 095 long value; 096 097 // Find a new value 098 synchronized (StringUtils.class) 099 { 100 value = System.currentTimeMillis(); 101 102 try 103 { 104 Thread.sleep(15); 105 } 106 catch (InterruptedException e) 107 { 108 // does nothing, continue 109 } 110 } 111 112 // Convert it to a string using radix 36 (more compact) 113 String longString = Long.toString(value, Character.MAX_RADIX); 114 115 return longString; 116 } 117 118 /** 119 * Encrypt a password by using first MD5 Hash and base64 encoding. 120 * @param password The password to be encrypted. 121 * @return The password encrypted or null if the MD5 is not supported 122 */ 123 public static String md5Base64(String password) 124 { 125 if (password == null) 126 { 127 return null; 128 } 129 130 MessageDigest md5; 131 try 132 { 133 md5 = MessageDigest.getInstance("MD5"); 134 } 135 catch (NoSuchAlgorithmException e) 136 { 137 // This error exception not be raised since MD5 is embedded in the JDK 138 __LOGGER.error("Cannot encode the password to md5Base64", e); 139 return null; 140 } 141 142 // MD5-hash the password. 143 md5.reset(); 144 try 145 { 146 md5.update(password.getBytes("UTF-8")); 147 } 148 catch (UnsupportedEncodingException e) 149 { 150 throw new IllegalStateException(e); 151 } 152 byte [] hash = md5.digest(); 153 154 // Base64-encode the result. 155 try 156 { 157 return new String(Base64.encodeBase64(hash), "UTF-8"); 158 } 159 catch (UnsupportedEncodingException e) 160 { 161 throw new IllegalStateException(e); 162 } 163 } 164 165 166 /** 167 * Normalize string. Pass to lower case and remove Unicode accents and diacritics 168 * @param value the value to normalize 169 * @return the normalized value 170 */ 171 public static String normalizeStringValue(String value) 172 { 173 return Normalizer.normalize(value.toLowerCase(), Normalizer.Form.NFD).replaceAll("[\\p{InCombiningDiacriticalMarks}]", ""); 174 } 175 176 /** 177 * Transform a size to a readable size for data (bytes, KB, MB, etc.). 178 * @param size The size to transform 179 * @return An internationalized text with the size and the unit. 180 */ 181 public static I18nizableText toReadableDataSize(Long size) 182 { 183 if (size == 1L) 184 { 185 return _createReadatableDataSize(size, "PLUGINS_CORE_UI_FORMAT_FILE_SIZE_NOT_ESCAPED_BYTE"); 186 } 187 return _toReadableDataSize(size, __DATA_SIZE_KEYS.iterator()); 188 } 189 190 private static I18nizableText _toReadableDataSize(Long size, Iterator<String> keys) 191 { 192 String key = keys.next(); 193 if (!keys.hasNext() || size < __DATA_SIZE_NEXT_LIMIT) 194 { 195 return _createReadatableDataSize(size, key); 196 } 197 return _toReadableDataSize(size / __DATA_SIZE_NEXT_LIMIT, keys); 198 } 199 200 private static I18nizableText _createReadatableDataSize(Long size, String key) 201 { 202 return new I18nizableText("plugin.core-ui", key, List.of(size.toString())); 203 } 204}