001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2008 Sun Microsystems, Inc. 025 * Portions Copyright 2014-2015 ForgeRock AS 026 */ 027package org.opends.server.types; 028 029import org.forgerock.i18n.LocalizableMessage; 030 031 032import java.security.SecureRandom; 033import java.util.Random; 034import java.util.SortedSet; 035 036import org.forgerock.opendj.config.server.ConfigException; 037 038import static org.opends.messages.UtilityMessages.*; 039import static org.opends.server.util.StaticUtils.*; 040 041 042 043/** 044 * This class provides a data structure that makes it possible to 045 * associate a name with a given set of characters. The name must 046 * consist only of ASCII alphabetic characters. 047 */ 048@org.opends.server.types.PublicAPI( 049 stability=org.opends.server.types.StabilityLevel.VOLATILE, 050 mayInstantiate=true, 051 mayExtend=false, 052 mayInvoke=true) 053public final class NamedCharacterSet 054{ 055 /** The characters contained in this character set. */ 056 private final char[] characters; 057 058 /** The random number generator to use with this character set. */ 059 private final Random random; 060 061 /** The name assigned to this character set. */ 062 private final String name; 063 064 065 066 /** 067 * Creates a new named character set with the provided information. 068 * 069 * @param name The name for this character set. 070 * @param characters The characters to include in this character 071 * set. 072 * 073 * @throws ConfigException If the provided name contains one or 074 * more illegal characters. 075 */ 076 public NamedCharacterSet(String name, char[] characters) 077 throws ConfigException 078 { 079 this(name, characters, new SecureRandom()); 080 } 081 082 083 084 /** 085 * Creates a new named character set with the provided information. 086 * 087 * @param name The name for this character set. 088 * @param characters The characters to include in this character 089 * set. 090 * @param random The random number generator to use with this 091 * character set. 092 * 093 * @throws ConfigException If the provided name contains one or 094 * more illegal characters. 095 */ 096 public NamedCharacterSet(String name, char[] characters, 097 Random random) 098 throws ConfigException 099 { 100 this.name = name; 101 this.characters = characters; 102 this.random = random; 103 104 if (name == null || name.length() == 0) 105 { 106 LocalizableMessage message = ERR_CHARSET_CONSTRUCTOR_NO_NAME.get(); 107 throw new ConfigException(message); 108 } 109 110 for (int i=0; i < name.length(); i++) 111 { 112 if (! isAlpha(name.charAt(i))) 113 { 114 throw new ConfigException(ERR_CHARSET_CONSTRUCTOR_INVALID_NAME_CHAR.get(name.charAt(i), i)); 115 } 116 } 117 } 118 119 120 121 /** 122 * Retrieves the name for this character set. 123 * 124 * @return The name for this character set. 125 */ 126 public String getName() 127 { 128 return name; 129 } 130 131 132 133 /** 134 * Retrieves the characters included in this character set. 135 * 136 * @return The characters included in this character set. 137 */ 138 public char[] getCharacters() 139 { 140 return characters; 141 } 142 143 144 145 /** 146 * Retrieves a character at random from this named character set. 147 * 148 * @return The randomly-selected character from this named 149 * character set; 150 */ 151 public char getRandomCharacter() 152 { 153 if (characters == null || characters.length == 0) 154 { 155 return 0; 156 } 157 158 return characters[random.nextInt(characters.length)]; 159 } 160 161 162 163 /** 164 * Appends the specified number of characters chosen at random from 165 * this character set to the provided buffer. 166 * 167 * @param buffer The buffer to which the characters should be 168 * appended. 169 * @param count The number of characters to append to the 170 * provided buffer. 171 */ 172 public void getRandomCharacters(StringBuilder buffer, int count) 173 { 174 if (characters == null || characters.length == 0) 175 { 176 return; 177 } 178 179 for (int i=0; i < count; i++) 180 { 181 buffer.append(characters[random.nextInt(characters.length)]); 182 } 183 } 184 185 186 187 /** 188 * Encodes this character set to a form suitable for use in the 189 * value of a configuration attribute. 190 * 191 * @return The encoded character set in a form suitable for use in 192 * the value of a configuration attribute. 193 */ 194 public String encode() 195 { 196 return name + ":" + new String(characters); 197 } 198 199 200 201 /** 202 * Decodes the values of the provided configuration attribute as a 203 * set of character set definitions. 204 * 205 * @param values The set of encoded character set values to 206 * decode. 207 * 208 * @return The decoded character set definitions. 209 * 210 * @throws ConfigException If a problem occurs while attempting to 211 * decode the character set definitions. 212 */ 213 public static NamedCharacterSet[] 214 decodeCharacterSets(SortedSet<String> values) 215 throws ConfigException 216 { 217 NamedCharacterSet[] sets = new NamedCharacterSet[values.size()]; 218 int i = 0 ; 219 for (String value : values) 220 { 221 int colonPos = value.indexOf(':'); 222 if (colonPos < 0) 223 { 224 throw new ConfigException(ERR_CHARSET_NO_COLON.get(value)); 225 } 226 else if (colonPos == 0) 227 { 228 throw new ConfigException(ERR_CHARSET_NO_NAME.get(value)); 229 } 230 else if (colonPos == (value.length() - 1)) 231 { 232 throw new ConfigException(ERR_CHARSET_NO_CHARS.get(value)); 233 } 234 else 235 { 236 String name = value.substring(0, colonPos); 237 char[] characters = value.substring(colonPos+1).toCharArray(); 238 sets[i] = new NamedCharacterSet(name, characters); 239 } 240 i++; 241 } 242 243 return sets; 244 } 245} 246