001    /*
002      Copyright (C) 2002 Julien van Malderen, Renaud Pawlak <renaud@aopsys.com>
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful,
010      but WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012      GNU Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public License
015      along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
017    
018    package org.objectweb.jac.aspects.integrity;
019    
020    import java.util.Iterator;
021    import org.apache.log4j.Logger;
022    import org.objectweb.jac.core.ACConfiguration;
023    import org.objectweb.jac.core.ObjectRepository;
024    import org.objectweb.jac.core.rtti.ClassItem;
025    import org.objectweb.jac.core.rtti.ClassRepository;
026    import org.objectweb.jac.core.rtti.FieldItem;
027    
028    /**
029     * Some basic methods for constraints on fields values.
030     *
031     * <p>Constraint methods must return a Boolean that is
032     * <code>Boolean.TRUE</code> if the test has been validated (passed),
033     * <code>Boolean.FALSE</code> else. Their parameters are :</p>
034     * 
035     * <ul><li><code>Wrappee wrappee</code>: the  substance object
036     * (holding the field)</li>
037     *
038     * <li><code>FieldItem field</code>: the constrained field</li>
039     *
040     * <li><code>Object value</code>: the proposed future value of the
041     * field (can be refused by the contraint)</li>
042     *
043     * <li><code>Object[] values</code>: some configuration params that
044     * can be used in the test</li></ul>
045     *
046     * @see IntegrityAC#addPreCondition(FieldItem,MethodItem,Object[],String)
047     * @see IntegrityAC#addPostCondition(FieldItem,MethodItem,Object[],String)
048     * @see IntegrityAC#doCheck() */
049    
050    public class GenericConditions {
051        static final Logger logger = Logger.getLogger("integrity.conditions");
052    
053        /**
054         * If obj1 and obj2 are instances of String, uses equals(), else ==.
055         */
056        private static boolean areEqual(Object obj1, Object obj2)
057        {
058            logger.debug("areEqual("+obj1+","+obj2+")");
059            if(obj1 instanceof String && obj2 instanceof String) {
060                return ((String) obj1).equals((String) obj2);
061            }
062    
063            return (obj1 == obj2);
064        }
065    
066        /**
067         * Check if field's value is not equal to the forbidden values. If
068         * it is, the method returns <code>false</code>.
069         *
070         * @param substance the object that owns the field
071         * @param field the tested field
072         * @param value the value that is about to be set
073         * @param values the forbidden values
074         */
075        public static boolean forbiddenValues(Object substance,
076                                              FieldItem field,
077                                              Object value,
078                                              Object[] values)
079        {
080            for (int i=0; i<values.length; i++)
081                if (areEqual(value, values[i]))
082                    return false;
083            return true;
084        }
085    
086        /**
087         * Check if field's value is equal to one of the authorized
088         * values. If it is not, the method returns
089         * <code>false</code>.
090         * 
091         * @param substance the object that owns the field
092         * @param field the tested field
093         * @param value the value that is about to be set
094         * @param values the authorized values
095         */
096        public static boolean authorizedValues(Object substance,
097                                               FieldItem field,
098                                               Object value,
099                                               Object[] values)
100        {
101            for (int i=0; i<values.length; i++)
102                if (areEqual(value, values[i]))
103                    return true;
104            return false;
105        }
106    
107        /**
108         * Check if this field already has the same value in another object
109         * of the same type.
110         *
111         * @param substance the object that owns the field
112         * @param field the tested field
113         * @param value the value that is about to be set
114         * @param values unused 
115         */
116        public static boolean isUniqueValue(Object substance,
117                                            FieldItem field,
118                                            Object value,
119                                            Object[] values)
120        {
121            ClassItem cli = ClassRepository.get().getClass(substance);
122            Iterator it = ObjectRepository.getObjects(cli).iterator();
123            return true;
124        }
125    
126        /**
127         * Tells if the value is an upper-case char begining string.
128         *
129         * @param substance the object that owns the field
130         * @param field the tested field
131         * @param value the value that is about to be set
132         * @param values unused 
133         */    
134        public static boolean isBeginingWithUpperCaseChar(Object substance,
135                                                          FieldItem field,
136                                                          Object value,
137                                                          Object[] values)
138        {
139            if (value instanceof String) {
140                String s = (String)value;
141                if (s==null || s.length()==0 || 
142                    Character.isUpperCase(s.charAt(0))) 
143                {
144                    return true;
145                } else {
146                    return false;
147                }
148            }
149            throw new RuntimeException("Invalid constraint check: "+value+
150                                       " is not a string");
151        }
152    
153        public static boolean isNotNull(Object substance,
154                                        FieldItem field,
155                                        Object value,
156                                        Object[] values)
157        {
158            return value != null;
159        }
160    
161        public static boolean isNull(Object substance,
162                                     FieldItem field,
163                                     Object value,
164                                     Object[] values)
165        {
166            return value == null;
167        }
168    
169    
170        /**
171         * Tells if the value is a letter begining string.
172         *
173         * @param substance the object that owns the field
174         * @param field the tested field
175         * @param value the value that is about to be set
176         * @param values unused 
177         */
178        public static boolean isBeginingWithLetter(Object substance,
179                                                   FieldItem field,
180                                                   Object value,
181                                                   Object[] values)
182        {
183            if (value instanceof String) {
184                String s = (String)value;
185                if (s==null || s.length()==0 || 
186                    Character.isLetter(s.charAt(0))) 
187                {
188                    return true;
189                } else {
190                    return false;
191                }
192            }
193            throw new RuntimeException("Invalid constraint check: "+value+
194                                       " is not a string");
195        }
196    
197        /**
198         * Tells if the value is a valid java identifier.
199         *
200         * @param substance the object that owns the field
201         * @param field the tested field
202         * @param value the value that is about to be set
203         * @param values unused 
204         */
205        public static boolean isJavaIdentifier(Object substance,
206                                               FieldItem field,
207                                               Object value,
208                                               Object[] values)
209        {
210            if (value instanceof String) {
211                String s=(String)value;
212                if (s==null) 
213                    return true;
214                if (s.length()==0) 
215                    return false;
216                if (!Character.isJavaIdentifierStart(s.charAt(0)))
217                    return false;
218                for(int i=1;i<s.length(); i++) {
219                    if(!Character.isJavaIdentifierPart(s.charAt(i)))
220                        return false;
221                }
222                return true;
223            }
224            throw new RuntimeException("Invalid constraint check: "+value+
225                                       " is not a string");
226        }
227    
228        /**
229         * Tells if the value is greater than a given number.
230         *
231         * @param substance the object that owns the field
232         * @param field the tested field
233         * @param value the value that is about to be set
234         * @param values unused 
235         */
236        public static boolean isGreaterThan(Object substance,
237                                            FieldItem field,
238                                            Object value,
239                                            Object[] values)
240            throws Exception
241        {
242            if (value instanceof Number) {
243                Number th = (Number)ACConfiguration.convertValue(values[0],
244                                                                 value.getClass());
245                if (((Number)value).doubleValue()>th.doubleValue()) {
246                    return true;
247                } else {
248                    return false;
249                }
250            }
251            throw new RuntimeException("Invalid constraint check: "+value+
252                                       " is not a number");
253        }
254    
255        /**
256         * Tells if the value is lower than a given number.
257         *
258         * @param substance the object that owns the field
259         * @param field the tested field
260         * @param value the value that is about to be set
261         * @param values unused 
262         */
263        public static boolean isLowerThan(Object substance,
264                                          FieldItem field,
265                                          Object value,
266                                          Object[] values)
267            throws Exception
268        {
269            if (value instanceof Number) {
270                Number th = (Number)ACConfiguration.convertValue(values[0],
271                                                                 value.getClass());
272                if (((Number)value).doubleValue()<th.doubleValue()) {
273                    return true;
274                } else {
275                    return false;
276                }
277            }
278            throw new RuntimeException("Invalid constraint check: "+value+
279                                       " is not a number");
280        }
281    
282    }