001// Copyright 2007, 2013 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry5.test; 016 017import org.slf4j.Logger; 018import org.slf4j.LoggerFactory; 019 020import java.io.*; 021import java.util.ArrayList; 022import java.util.List; 023import java.util.Random; 024 025/** 026 * Provides access to random data that can be used when populating a test database with "reasonable" data. The majority 027 * of this is access to random words from an american english dictionary, which can be strung together to form names, 028 * sentences and paragraphs. 029 */ 030public final class RandomDataSource 031{ 032 private static final Logger LOGGER = LoggerFactory.getLogger(RandomDataSource.class); 033 034 private final Random random = new Random(System.currentTimeMillis()); 035 036 private final static List<String> words = new ArrayList<String>(); 037 038 private static void loadWords() 039 { 040 if (words.isEmpty()) 041 { 042 043 for (int i = 0; i < 4; i++) 044 readWords("english." + i); 045 046 for (int i = 0; i < 3; i++) 047 readWords("american." + i); 048 049 LOGGER.info(String.format("Dictionary contains %,d words.", words.size())); 050 } 051 } 052 053 private static void readWords(String name) 054 { 055 LOGGER.info("Reading {} ...", name); 056 057 int count = 0; 058 059 InputStream is = RandomDataSource.class.getResourceAsStream(name); 060 061 if (is == null) throw new RuntimeException(String.format("File '%s' not found.", name)); 062 063 try 064 { 065 BufferedInputStream bis = new BufferedInputStream(is); 066 InputStreamReader isr = new InputStreamReader(bis); 067 LineNumberReader r = new LineNumberReader(isr); 068 069 while (true) 070 { 071 String word = r.readLine(); 072 073 if (word == null) break; 074 075 count++; 076 words.add(word); 077 } 078 079 r.close(); 080 } catch (IOException ex) 081 { 082 throw new RuntimeException(String.format("Error reading '%s': %s", name + ex.getMessage()), ex); 083 } 084 085 LOGGER.info(String.format("... %,d words", count)); 086 } 087 088 public boolean maybe(int percent) 089 { 090 assert percent > 0 && percent <= 100; 091 092 return random.nextInt(100) < percent; 093 } 094 095 public int random(int min, int max) 096 { 097 assert min <= max; 098 099 return random.nextInt(max - min + 1) + min; 100 } 101 102 /** 103 * Returns a random word frm the dictionary. These words are usually all lowercase. 104 */ 105 public String word() 106 { 107 loadWords(); 108 109 int index = random.nextInt(words.size()); 110 111 return words.get(index); 112 } 113 114 /** 115 * Returns a random word, capitalized. Useful when create random names. 116 */ 117 public String capitalizedWord() 118 { 119 String word = word(); 120 121 char[] chars = word.toCharArray(); 122 123 chars[0] = Character.toUpperCase(chars[0]); 124 125 return new String(chars); 126 } 127 128 /** 129 * Returns a word that is "safe" for use in an email address. 130 */ 131 public String safeWord() 132 { 133 String word = word(); 134 135 int x = word.indexOf('\''); 136 137 return x < 0 ? word : word.substring(0, x); 138 } 139 140 /** 141 * Returns a random value from the list of values supplied. 142 */ 143 public <T> T oneOf(T... values) 144 { 145 assert values.length > 0; 146 147 int index = random.nextInt(values.length); 148 149 return values[index]; 150 } 151 152 /** 153 * Returns a random enum value, given the enum type. 154 */ 155 public <T extends Enum> T oneOf(Class<T> enumClass) 156 { 157 return oneOf(enumClass.getEnumConstants()); 158 } 159 160 /** 161 * Creates a space-separated list of random words. If in sentence form, then the first word is capitalized, and a 162 * period is appended. 163 * 164 * @param minWords 165 * minimun number of words in the list 166 * @param maxWords 167 * maximum number of words in the list 168 * @param asSentence 169 * if true, the output is "dressed up" as a non-sensical sentence 170 * @return the word list / sentence 171 */ 172 public String wordList(int minWords, int maxWords, boolean asSentence) 173 { 174 assert minWords <= maxWords; 175 assert minWords > 0; 176 177 StringBuilder builder = new StringBuilder(); 178 179 int count = random(minWords, maxWords); 180 181 for (int i = 0; i < count; i++) 182 { 183 184 if (i > 0) builder.append(' '); 185 186 if (i == 0 && asSentence) 187 builder.append(capitalizedWord()); 188 else 189 builder.append(word()); 190 } 191 192 if (asSentence) builder.append('.'); 193 194 return builder.toString(); 195 } 196 197 /** 198 * Strings together a random number of word lists (in sentence form) to create something that looks like a 199 * paragraph. 200 * 201 * @param minSentences 202 * per paragraph 203 * @param maxSentences 204 * per paragraph 205 * @param minWords 206 * per sentence 207 * @param maxWords 208 * per sentence 209 * @return the random paragraph 210 */ 211 public String paragraph(int minSentences, int maxSentences, int minWords, int maxWords) 212 { 213 assert minSentences < maxSentences; 214 assert minSentences > 0; 215 216 int count = random(minSentences, maxSentences); 217 218 StringBuilder builder = new StringBuilder(); 219 220 for (int i = 0; i < count; i++) 221 { 222 if (i > 0) builder.append(' '); 223 224 builder.append(wordList(minWords, maxWords, true)); 225 } 226 227 return builder.toString(); 228 } 229}