001: /*
002: * (c) Copyright 2006 by Volker Bergmann. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, is permitted under the terms of the
006: * GNU General Public License.
007: *
008: * For redistributing this software or a derivative work under a license other
009: * than the GPL-compatible Free Software License as defined by the Free
010: * Software Foundation or approved by OSI, you must first obtain a commercial
011: * license to this software product from Volker Bergmann.
012: *
013: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
014: * WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED CONDITIONS,
015: * REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF
016: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE
017: * HEREBY EXCLUDED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
018: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
019: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
020: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
021: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
022: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
023: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
024: * POSSIBILITY OF SUCH DAMAGE.
025: */
026:
027: package org.databene.benerator.primitive.regex;
028:
029: import org.databene.benerator.LightweightGenerator;
030: import org.databene.benerator.Generator;
031: import org.databene.benerator.InvalidGeneratorSetupException;
032: import org.databene.benerator.MultiGeneratorWrapper;
033: import org.databene.benerator.wrapper.UniqueCompositeGenerator;
034: import org.databene.benerator.wrapper.CompositeArrayGenerator;
035: import org.databene.regex.*;
036: import org.databene.commons.LocaleUtil;
037:
038: import java.util.Locale;
039: import java.text.ParseException;
040:
041: /**
042: * Generates Strings that comply to a regular expression.<br/>
043: * <br/>
044: * Created: 18.07.2006 19:32:52
045: */
046: public class RegexStringGenerator extends LightweightGenerator<String> {
047:
048: /** Optional String representation of a regular expression */
049: private String pattern;
050:
051: /** Object representation of the regular expression to match */
052: private Regex regex;
053:
054: /** The locale from which to choose letters */
055: private Locale locale;
056:
057: /** maximum value for unlimited quantities */
058: private int maxQuantity;
059:
060: private boolean unique;
061:
062: /** Validity flag for consistency check */
063: private boolean dirty;
064:
065: private MultiGeneratorWrapper<String, String[]> partsGenerator;
066:
067: // constructors ----------------------------------------------------------------------------------------------------
068:
069: /** Initializes the generator to an empty regular expression, a maxQuantity of 30 and the fallback locale */
070: public RegexStringGenerator() {
071: this (30);
072: }
073:
074: /** Initializes the generator to an empty regular expression and the fallback locale */
075: public RegexStringGenerator(int maxQuantity) {
076: this ((String) null, maxQuantity);
077: }
078:
079: /** Initializes the generator to a maxQuantity of 30 and the fallback locale */
080: public RegexStringGenerator(String pattern) {
081: this (pattern, 30);
082: }
083:
084: /** Initializes the generator to the fallback locale */
085: public RegexStringGenerator(String pattern, int maxQuantity) {
086: this (pattern, LocaleUtil.getFallbackLocale(), maxQuantity);
087: }
088:
089: public RegexStringGenerator(String pattern, Locale locale,
090: Integer maxQuantity) {
091: this (pattern, locale, maxQuantity, false);
092: }
093:
094: /** Initializes the generator with the String representation of a regular expression */
095: public RegexStringGenerator(String pattern, Locale locale,
096: Integer maxQuantity, boolean unique) {
097: this (parse(pattern, locale), maxQuantity, unique);
098: partsGenerator = (unique ? new UniqueCompositeGenerator<String>(
099: String.class)
100: : new CompositeArrayGenerator<String>(String.class));
101: this .locale = locale;
102: this .pattern = pattern;
103: this .maxQuantity = (maxQuantity != null ? maxQuantity : 30);
104: this .unique = unique;
105: this .dirty = true;
106: }
107:
108: public RegexStringGenerator(Regex regex, Integer maxQuantity) {
109: this (regex, maxQuantity, false);
110: }
111:
112: /** Initializes the generator with the object representation of a regular expression */
113: public RegexStringGenerator(Regex regex, Integer maxQuantity,
114: boolean unique) {
115: partsGenerator = (unique ? new UniqueCompositeGenerator<String>(
116: String.class)
117: : new CompositeArrayGenerator<String>(String.class));
118: this .regex = regex;
119: this .maxQuantity = (maxQuantity != null ? maxQuantity : 30);
120: this .unique = unique;
121: this .dirty = true;
122: }
123:
124: // config properties -----------------------------------------------------------------------------------------------
125:
126: /** Sets the String representation of the regular expression */
127: public String getPattern() {
128: return pattern;
129: }
130:
131: /** Returns the String representation of the regular expression */
132: public void setPattern(String pattern) {
133: this .dirty = true;
134: this .pattern = pattern;
135: this .regex = null;
136: }
137:
138: public Locale getLocale() {
139: return locale;
140: }
141:
142: public void setLocale(Locale locale) {
143: this .dirty = true;
144: this .locale = locale;
145: }
146:
147: public int getMaxQuantity() {
148: return maxQuantity;
149: }
150:
151: public void setMaxQuantity(int maxQuantity) {
152: this .dirty = true;
153: this .maxQuantity = maxQuantity;
154: }
155:
156: // Generator interface ---------------------------------------------------------------------------------------------
157:
158: /** ensures consistency of the generators state */
159: public void validate() {
160: if (dirty) {
161: try {
162: if (regex == null)
163: regex = parse(pattern, locale);
164: if (regex == null)
165: return;
166: RegexPart[] parts = regex.getParts();
167: Generator<String>[] sources = new Generator[parts.length];
168: for (int i = 0; i < parts.length; i++)
169: sources[i] = RegexPartGeneratorFactory
170: .createRegexPartGenerator(parts[i],
171: maxQuantity, unique);
172: partsGenerator.setSources(sources);
173: } catch (Exception e) {
174: throw new InvalidGeneratorSetupException(e);
175: }
176: dirty = false;
177: }
178: }
179:
180: public boolean available() {
181: if (dirty)
182: validate();
183: return partsGenerator.available();
184: }
185:
186: /** Calls all sub generators and assembles their products to a string */
187: public String generate() {
188: if (dirty)
189: validate();
190: if (regex == null)
191: return null;
192: StringBuffer buffer = new StringBuffer();
193: Object[] parts = partsGenerator.generate();
194: for (Object part : parts)
195: buffer.append(part);
196: return buffer.toString();
197: }
198:
199: public Class<String> getGeneratedType() {
200: return String.class;
201: }
202:
203: public void reset() {
204: partsGenerator.reset();
205: }
206:
207: public void close() {
208: partsGenerator.close();
209: }
210:
211: // java.lang.Object overrides --------------------------------------------------------------------------------------
212:
213: public String toString() {
214: return getClass().getSimpleName() + "["
215: + (unique ? "unique '" : "'") + regex + "']";
216: }
217:
218: // private helpers -------------------------------------------------------------------------------------------------
219:
220: /** parses the string representation of a regular expression into an object representation */
221: private static Regex parse(String pattern, Locale locale) {
222: if (pattern == null)
223: return null;
224: try {
225: return new RegexParser(locale).parse(pattern);
226: } catch (ParseException e) {
227: throw new InvalidGeneratorSetupException("pattern", e
228: .toString());
229: }
230: }
231:
232: }
|