001    package org.apache.commons.contract.constraints;
002    
003    import java.util.ArrayList;
004    import java.util.Arrays;
005    import java.util.Iterator;
006    import java.util.List;
007    
008    import org.apache.commons.contract.Context;
009    import org.apache.commons.i18n.bundles.ErrorBundle;
010    import org.apache.commons.i18n.bundles.TextBundle;
011    
012    public class StringConstraints implements Constraints, Castable {
013        public final static StringConstraints UNCONSTRAINED = new StringConstraints();
014        public final static StringConstraints EMPTY = new StringConstraints(0);
015        public final static StringConstraints NOT_EMPTY = new StringConstraints(1,Integer.MAX_VALUE);
016        
017        protected boolean constrained;
018        protected List allowedValues = new ArrayList();
019        protected int minimumLength = -1, maximumLength =-1;
020        protected Object defaultValue;
021    
022        public StringConstraints() {
023            this.constrained = false;
024        }
025    
026        public StringConstraints(String[] allowedValues) {
027            this.constrained = true;
028            this.allowedValues = new ArrayList(Arrays.asList(allowedValues));
029        }
030    
031        public StringConstraints(int maximumLength) {
032            this.maximumLength = maximumLength;
033            this.constrained = true;
034        }
035    
036        public StringConstraints(int minimumLength, int maximumLength) {
037            this.minimumLength = minimumLength;
038            this.maximumLength = maximumLength;
039            this.constrained = true;
040        }
041    
042        public int getMinimumLength() {
043            return minimumLength;
044        }
045    
046        public void setMinimumLength(int minimumLength) {
047            this.minimumLength = minimumLength;
048            constrained = true;
049        }
050    
051        public int getMaximumLength() {
052            return maximumLength;
053        }
054    
055        public void setMaximumLength(int maximumLength) {
056            this.maximumLength = maximumLength;
057            constrained = true;
058        }
059    
060        public void addAllowedValue(String value) {
061            constrained = true;
062            allowedValues.add(value);
063        }
064    
065        public boolean isConstrained() {
066            return constrained;
067        }
068    
069        public boolean isEnumerable() {
070            return ( allowedValues.size() > 0 );
071        }
072    
073        public String[] getAllowedValues() {
074            return (String [])allowedValues.toArray(new String [0]);
075        }
076    
077        public Object cast(Object value, Context context) throws CastException {
078            if (value instanceof String) {
079                return value;
080            } else if (value instanceof String[]) {
081                return ((String [])value)[0];
082            } 
083            return value.toString();
084        }
085    
086        public void validate(Object value, Context context) throws ValidationException {
087            if ( constrained ) {
088                    if ( isEnumerable() ) {
089                            for ( Iterator i = allowedValues.iterator(); i.hasNext(); ) {
090                                    if (value.equals((String)i.next())) {
091                                            return;
092                                    }
093                            }
094                            throw new ValidationException(new ErrorBundle("invalidString", new String[] { (String)value, getEnumeratedValues() }));
095                    } else {
096                            if ( minimumLength != -1 && ((String)value).length() < minimumLength ) throw new ValidationException(new ErrorBundle("stringTooShort", new Object[] { new Integer(minimumLength) }));
097                            if ( maximumLength != -1 && ((String)value).length() > maximumLength ) throw new ValidationException(new ErrorBundle("stringTooLong", new Object[] { new Integer(maximumLength) }));
098                    }
099            }
100        }
101    
102        public TextBundle verboseConstraints() {
103            if ( constrained ) {
104                if ( isEnumerable() ) {
105                    return new TextBundle("enumeratedStrings", new Object[] { getEnumeratedValues() });
106                } else {
107                    if ( minimumLength != -1 && maximumLength == -1 ) {
108                        return new TextBundle("stringLengthBetween", new Object[] { new Integer(minimumLength), new Integer(maximumLength) });
109                    } else if ( minimumLength != -1 ) {
110                        return new TextBundle("stringLengthGreater", new Object[] { new Integer(minimumLength) });
111                    } else {
112                        return new TextBundle("stringLengthLess", new Object[] { new Integer(maximumLength) });
113                    }
114                }
115            } else {
116                return new TextBundle("strings");
117            }
118        }
119    
120        private String getEnumeratedValues() {
121            StringBuffer buffer = new StringBuffer(256);
122            for ( int i = 0; i < getAllowedValues().length; i++ ) {
123                if ( i > 0 && i < getAllowedValues().length ) buffer.append(", ");
124                buffer.append(getAllowedValues()[i]);
125            }
126            return buffer.toString();
127        }
128    }