001package votorola.g.util.regex; // Copyright 2009, 2012, Michael Allan.  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE.
002
003import java.util.Locale;
004import java.util.regex.*;
005import org.apache.wicket.AttributeModifier;
006import org.apache.wicket.request.cycle.RequestCycle;
007import org.apache.wicket.markup.html.form.*;
008import org.apache.wicket.util.convert.*;
009import votorola.g.lang.*;
010import votorola.g.locale.BundleFormatter;
011import votorola.g.web.wic.*;
012
013
014/** A Wicket I/O converter of regular expressions.
015  */
016public @ThreadRestricted("wicket") class WicPatternConverter implements IConverter<Pattern>
017{
018
019    private static final long serialVersionUID = 1L;
020
021
022
023    /** Constructs a WicPatternConverter.
024      *
025      *     @see #maxInputLength()
026      */
027    public WicPatternConverter( int _maxInputLength ) { maxInputLength = _maxInputLength; }
028
029
030
031   // ------------------------------------------------------------------------------------
032
033
034    /** The maximum length of input that will be accepted.
035      *
036      *     @see #convertToObject(String,Locale)
037      */
038    public int maxInputLength() { return maxInputLength; }
039
040
041        private final int maxInputLength;
042
043
044
045    /** Sets the converted input to the model's current value and returns true; or, if
046      * conversion is really needed, leaves it unset and returns false.  Call this from
047      * your FormComponent.convertInput() in order to guard against multiple redundant
048      * conversions.  (Why is Wicket requesting them?)
049      *
050      *     @return true if converted input is set, false otherwise
051      *
052      *     @see FormComponent#convertInput()
053      */
054    public final boolean setConvertedInputUnaltered( final FormComponent<Pattern> component )
055    {
056     // final Pattern value = component.getConvertedInput();
057     //// not useful, because convertedInput is nulled prior to calling convertInput()
058        final Pattern value = component.getModelObject();
059        if( !ObjectX.nullEquals( normalized( component.getInput() ),
060          convertToString( value, null ))) return false;
061
062        component.setConvertedInput( value );
063        return true;
064    }
065
066
067
068    /** A convenience method to initialize a text field by adding a 'maxLength' attribute
069      * to its view, and by setting a model type of {@linkplain Pattern Pattern}.
070      *
071      *     @return the same field
072      *
073      *     @see #maxInputLength()
074      */
075    public <C extends TextField<Pattern>> C setMaxLength_Type( final C field )
076    {
077        field.add( AttributeModifier.replace( "maxlength", Integer.toString( maxInputLength )));
078
079        assert field.getType() == null: "not clobbering a pre-assigned type";
080        field.setType( Pattern.class );
081
082        return field;
083    }
084
085
086
087   // - I - C o n v e r t e r ------------------------------------------------------------
088
089
090    /** @throws IllegalArgumentException if input exceeds
091      *   {@linkplain #maxInputLength() maxInputLength}()
092      */
093    public final Pattern convertToObject( final String input, final Locale _ignored )
094      throws IllegalArgumentException
095    {
096        ModelLengthLimiter.lengthConstrained( input, maxInputLength );
097        if( normalized(input).length() == 0 ) return null; // IConverter says input never null
098
099        try
100        {
101            return patternFor( input );
102        }
103        catch( final PatternSyntaxException x )
104        {
105            throw new ConversionExceptionLM(
106              ((BundleFormatter.GProvider)RequestCycle.get()).bunG().l(
107                "g.malformedRegex", input, x.getMessage() ));
108        }
109    }
110
111
112
113    public final String convertToString( final Pattern value, final Locale _ignored )
114    {
115        return value == null? null: value.toString();
116    }
117
118
119
120   // - W i c - P a t t e r n - C o n v e r t e r ----------------------------------------
121
122
123    /** Compiles the pattern for a string value.  The base implementation of this method
124      * (in RegexConverter) simply returns Pattern.compile(value).
125      */
126    protected Pattern patternFor( final String value ) throws PatternSyntaxException
127    {
128        return Pattern.compile( value );
129    }
130
131
132
133    private static String normalized( String input )
134    {
135     // if( input != null )
136     /// guard redundant, IConverter says input never null
137        {
138            input = input.trim();
139        }
140
141        return input;
142    }
143
144
145
146}