001    /*
002     * Copyright (c) 1998-2014 ChemAxon Ltd. All Rights Reserved.
003     *
004     * This software is the confidential and proprietary information of
005     * ChemAxon. You shall not disclose such Confidential Information
006     * and shall use it only in accordance with the terms of the agreements
007     * you entered into with ChemAxon.
008     *
009     */
010    
011    package com.chemaxon.apidiscovery;
012    
013    import com.chemaxon.apidiscovery.interfaces.ValidateResult;
014    import com.chemaxon.apidiscovery.interfaces.Validator;
015    import com.chemaxon.common.annotations.PublicAPI;
016    import com.google.common.annotations.Beta;
017    import com.google.common.base.Optional;
018    
019    /**
020     * Validator related utilities.
021     *
022     * <p>Please note that this class is marked with @Beta annotation, so it can be subject of incompatible changes or
023     * removal in later releases.</p>
024     *
025     * <p>Please note that validation in this version is not supported yet.</p>
026     *
027     * @author Gabor Imre
028     */
029    
030    // TODO: Use standard Bean validation API
031    @Beta
032    @PublicAPI
033    public final class Validators {
034    
035        /**
036         * Private constructor hidden.
037         */
038        private Validators() {}
039    
040        /**
041         * A validator always result as valid.
042         * @param <T> Type to validate
043         */
044        static class NoValidator<T> implements Validator<T> {
045    
046            @Override
047            public ValidateResult<T> validateValue(Object value) {
048                return VALIDRESULT;
049            }
050    
051            @Override
052            public String getDescription() {
053                return "No restriction";
054            }
055        };
056    
057        /**
058         * Validator accepts only non negative doubles (also 0).
059         */
060        public static class NonNegativeDouble implements Validator<Double> {
061    
062            @Override
063            public ValidateResult<Double> validateValue(Double value) {
064                throw new UnsupportedOperationException("Not supported yet.");
065            }
066    
067            @Override
068            public String getDescription() {
069                return "Must be non-negative";
070            }
071        }
072    
073        /**
074         * Validator accepts double values in the unit interval (0.0 - 1.0, inclusive).
075         */
076        public static class UnitInterval implements Validator<Double> {
077    
078            /**
079             * The recommended valui in case of reject.
080             */
081            public static final double RECOMMENDED_VALUE = 0.5;
082    
083            @Override
084            public ValidateResult<Double> validateValue(Double value) {
085                if (value < 0 || value > 1) {
086                    return new InvalidResult<Double>("Value \"" + value
087                            + "\" outside the unit interval (0.0 - 1.0, inclusive)", RECOMMENDED_VALUE);
088                } else {
089                    return VALIDRESULT;
090                }
091            }
092    
093            @Override
094            public String getDescription() {
095                return "Must be part of the unit interval, between 0.0 and 1.0, inclusive.";
096            }
097        }
098    
099        /**
100         * Validator accepts only non negative integers (zero and greater).
101         */
102        public static class NonNegativeInteger implements Validator<Integer> {
103    
104            @Override
105            public ValidateResult<Integer> validateValue(Integer value) {
106                if (value < 0) {
107                    return new InvalidResult<Integer>("Negative value \"" + value + "\"", 0);
108                } else {
109                    return VALIDRESULT;
110                }
111            }
112    
113            @Override
114            public String getDescription() {
115                return "Must be non-negative.";
116            }
117        }
118    
119        /**
120         * Validator accepts only positive integers (1 or greater; excluding 0).
121         */
122        public static class PositiveInteger implements Validator<Integer> {
123    
124            @Override
125            public ValidateResult<Integer> validateValue(Integer value) {
126                if (value <= 0) {
127                    return new InvalidResult<Integer>("Negative or zero value \"" + value + "\"", 1);
128                } else {
129                    return VALIDRESULT;
130                }
131            }
132    
133            @Override
134            public String getDescription() {
135                return "Must be positive.";
136            }
137        }
138    
139        /**
140         * Ensure that parameter is multiply of 32.
141         */
142        public static class MultiplyOf32 implements Validator<Integer> {
143    
144            /**
145             * Base of multiplication
146             */
147            private static final int BASE = 32;
148    
149            @Override
150            public ValidateResult<Integer> validateValue(Integer value) {
151                if (value < BASE) {
152                    return new InvalidResult<Integer>("Value \"" + value + "\" less than " + BASE, BASE);
153                } else if ((value % BASE) != 0) {
154                    return new InvalidResult<Integer>("Value \"" + value + "\" not multiply of " + BASE,
155                            (int) Math.max(BASE, BASE * Math.ceil((double) value / BASE)));
156                } else {
157                    return VALIDRESULT;
158                }
159            }
160    
161            @Override
162            public String getDescription() {
163                return "Must be multiply of " + BASE;
164            }
165        }
166    
167        /**
168         * A valid result.
169         */
170        static final ValidateResult VALIDRESULT = new ValidateResult() {
171    
172            @Override
173            public boolean isValid() {
174                return true;
175            }
176    
177            @Override
178            public String getMessageForInvalid() throws IllegalStateException {
179                throw new IllegalStateException("Value is valid");
180            }
181    
182            @Override
183            public Optional suggestValid() throws IllegalStateException {
184                throw new IllegalStateException("Value is valid");
185            }
186    
187        };
188    
189        /**
190         * An invalid result.
191         * @param <T>   Type of validated parameter
192         */
193        static class InvalidResult<T> implements ValidateResult<T> {
194    
195            /**
196             * Message to pass.
197             */
198            private final String message;
199    
200            /**
201             * Suggestion if exists.
202             */
203            private final Optional<T> suggestion;
204    
205            /**
206             * Construct an invalid result with suggested valid value.
207             * @param message   Message to pass
208             * @param suggestion    Suggestion to pass
209             */
210            public InvalidResult(String message, T suggestion) {
211                this.message = message;
212                this.suggestion = Optional.of(suggestion);
213            }
214    
215            /**
216             * Construct an invalid result without suggestion.
217             * @param message   Message to pass
218             */
219            public InvalidResult(String message) {
220                this.message = message;
221                this.suggestion = Optional.<T>absent();
222            }
223    
224            @Override
225            public boolean isValid() {
226                return false;
227            }
228    
229            @Override
230            public String getMessageForInvalid() throws IllegalStateException {
231                return this.message;
232            }
233    
234            @Override
235            public Optional<T> suggestValid() throws IllegalStateException {
236                return this.suggestion;
237            }
238        }
239    }