001    /*******************************************************************************
002     * Portions created by Sebastian Thomschke are copyright (c) 2005-2011 Sebastian
003     * Thomschke.
004     * 
005     * All Rights Reserved. This program and the accompanying materials
006     * are made available under the terms of the Eclipse Public License v1.0
007     * which accompanies this distribution, and is available at
008     * http://www.eclipse.org/legal/epl-v10.html
009     * 
010     * Contributors:
011     *     Sebastian Thomschke - initial implementation.
012     *******************************************************************************/
013    package net.sf.oval.constraint;
014    
015    import static net.sf.oval.Validator.*;
016    
017    import java.math.BigDecimal;
018    import java.math.BigInteger;
019    import java.util.Map;
020    
021    import net.sf.oval.ConstraintTarget;
022    import net.sf.oval.Validator;
023    import net.sf.oval.configuration.annotation.AbstractAnnotationCheck;
024    import net.sf.oval.context.OValContext;
025    import net.sf.oval.internal.Log;
026    
027    /**
028     * @author Sebastian Thomschke
029     */
030    public class DigitsCheck extends AbstractAnnotationCheck<Digits>
031    {
032            private static final Log LOG = Log.getLog(DigitsCheck.class);
033    
034            private static final long serialVersionUID = 1L;
035    
036            private int maxFraction = Integer.MAX_VALUE;
037            private int maxInteger = Integer.MAX_VALUE;
038            private int minFraction = 0;
039            private int minInteger = 0;
040    
041            /**
042             * {@inheritDoc}
043             */
044            @Override
045            public void configure(final Digits constraintAnnotation)
046            {
047                    super.configure(constraintAnnotation);
048                    setMinInteger(constraintAnnotation.minInteger());
049                    setMaxInteger(constraintAnnotation.maxInteger());
050                    setMinFraction(constraintAnnotation.minFraction());
051                    setMaxFraction(constraintAnnotation.maxFraction());
052            }
053    
054            /**
055             * {@inheritDoc}
056             */
057            @Override
058            protected Map<String, String> createMessageVariables()
059            {
060                    final Map<String, String> messageVariables = getCollectionFactory().createMap(2);
061                    messageVariables.put("maxInteger", Integer.toString(maxInteger));
062                    messageVariables.put("minInteger", Integer.toString(minInteger));
063                    messageVariables.put("maxFraction", Integer.toString(maxFraction));
064                    messageVariables.put("minFraction", Integer.toString(minFraction));
065                    return messageVariables;
066            }
067    
068            /**
069             * {@inheritDoc}
070             */
071            @Override
072            protected ConstraintTarget[] getAppliesToDefault()
073            {
074                    return new ConstraintTarget[]{ConstraintTarget.VALUES};
075            }
076    
077            /**
078             * @return the maxFraction
079             */
080            public int getMaxFraction()
081            {
082                    return maxFraction;
083            }
084    
085            /**
086             * @return the maxInteger
087             */
088            public int getMaxInteger()
089            {
090                    return maxInteger;
091            }
092    
093            /**
094             * @return the minFraction
095             */
096            public int getMinFraction()
097            {
098                    return minFraction;
099            }
100    
101            /**
102             * @return the minInteger
103             */
104            public int getMinInteger()
105            {
106                    return minInteger;
107            }
108    
109            /**
110             * {@inheritDoc}
111             */
112            public boolean isSatisfied(final Object validatedObject, final Object valueToValidate, final OValContext context,
113                            final Validator validator)
114            {
115                    if (valueToValidate == null) return true;
116    
117                    final int fractLen, intLen;
118                    if (valueToValidate instanceof Integer)
119                    {
120                            final int value = (Integer) valueToValidate;
121                            intLen = value == 0 ? 1 : (int) Math.log10(value) + 1;
122                            fractLen = 0;
123                    }
124                    else if (valueToValidate instanceof Long)
125                    {
126                            final long value = (Long) valueToValidate;
127                            intLen = value == 0 ? 1 : (int) Math.log10(value) + 1;
128                            fractLen = 0;
129                    }
130                    else if (valueToValidate instanceof Short)
131                    {
132                            final short value = (Short) valueToValidate;
133                            intLen = value == 0 ? 1 : (int) Math.log10(value) + 1;
134                            fractLen = 0;
135                    }
136                    else if (valueToValidate instanceof Byte)
137                    {
138                            final byte value = (Byte) valueToValidate;
139                            intLen = value == 0 ? 1 : (int) Math.log10(value) + 1;
140                            fractLen = 0;
141                    }
142                    else if (valueToValidate instanceof BigInteger)
143                    {
144                            final long value = ((BigInteger) valueToValidate).longValue();
145                            intLen = value == 0 ? 1 : (int) Math.log10(value) + 1;
146                            fractLen = 0;
147                    }
148                    else
149                    {
150                            BigDecimal value = null;
151                            if (valueToValidate instanceof BigDecimal)
152                                    value = (BigDecimal) valueToValidate;
153                            else
154                                    try
155                                    {
156                                            value = new BigDecimal(valueToValidate.toString());
157                                    }
158                                    catch (final NumberFormatException ex)
159                                    {
160                                            LOG.debug("Failed to parse numeric value: " + valueToValidate, ex);
161                                            return false;
162                                    }
163                            final int valueScale = value.scale();
164                            final long longValue = value.longValue();
165                            intLen = longValue == 0 ? 1 : (int) Math.log10(longValue) + 1;
166                            fractLen = valueScale > 0 ? valueScale : 0;
167                    }
168    
169                    return intLen <= maxInteger && intLen >= minInteger && fractLen <= maxFraction && fractLen >= minFraction;
170            }
171    
172            /**
173             * @param maxFraction the maxFraction to set
174             */
175            public void setMaxFraction(final int maxFraction)
176            {
177                    this.maxFraction = maxFraction;
178            }
179    
180            /**
181             * @param maxInteger the maxInteger to set
182             */
183            public void setMaxInteger(final int maxInteger)
184            {
185                    this.maxInteger = maxInteger;
186            }
187    
188            /**
189             * @param minFraction the minFraction to set
190             */
191            public void setMinFraction(final int minFraction)
192            {
193                    this.minFraction = minFraction;
194            }
195    
196            /**
197             * @param minInteger the minInteger to set
198             */
199            public void setMinInteger(final int minInteger)
200            {
201                    this.minInteger = minInteger;
202            }
203    }