KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > xdoclet > modules > ojb > constraints > FieldDescriptorConstraints


1 package xdoclet.modules.ojb.constraints;
2
3 import java.util.HashMap JavaDoc;
4
5 import xdoclet.modules.ojb.LogHelper;
6 import xdoclet.modules.ojb.model.FieldDescriptorDef;
7 import xdoclet.modules.ojb.model.PropertyHelper;
8
9 /* Copyright 2004-2005 The Apache Software Foundation
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */

23
24 /**
25  * Checks constraints for field descriptors. Note that constraints may modify the field descriptor.
26  *
27  * @author <a HREF="mailto:tomdz@apache.org">Thomas Dudziak</a>
28  */

29 public class FieldDescriptorConstraints extends FeatureDescriptorConstraints
30 {
31     /** The interface that conversion classes must implement */
32     private final static String JavaDoc CONVERSION_INTERFACE = "org.apache.ojb.broker.accesslayer.conversions.FieldConversion";
33     /** The allowed jdbc types */
34     private HashMap JavaDoc _jdbcTypes = new HashMap JavaDoc();
35
36     /**
37      * Creates a new field descriptor constraints object.
38      */

39     public FieldDescriptorConstraints()
40     {
41         _jdbcTypes.put("BIT", null);
42         _jdbcTypes.put("TINYINT", null);
43         _jdbcTypes.put("SMALLINT", null);
44         _jdbcTypes.put("INTEGER", null);
45         _jdbcTypes.put("BIGINT", null);
46         _jdbcTypes.put("DOUBLE", null);
47         _jdbcTypes.put("FLOAT", null);
48         _jdbcTypes.put("REAL", null);
49         _jdbcTypes.put("NUMERIC", null);
50         _jdbcTypes.put("DECIMAL", null);
51         _jdbcTypes.put("CHAR", null);
52         _jdbcTypes.put("VARCHAR", null);
53         _jdbcTypes.put("LONGVARCHAR", null);
54         _jdbcTypes.put("DATE", null);
55         _jdbcTypes.put("TIME", null);
56         _jdbcTypes.put("TIMESTAMP", null);
57         _jdbcTypes.put("BINARY", null);
58         _jdbcTypes.put("VARBINARY", null);
59         _jdbcTypes.put("LONGVARBINARY", null);
60         _jdbcTypes.put("CLOB", null);
61         _jdbcTypes.put("BLOB", null);
62         _jdbcTypes.put("STRUCT", null);
63         _jdbcTypes.put("ARRAY", null);
64         _jdbcTypes.put("REF", null);
65         _jdbcTypes.put("BOOLEAN", null);
66         _jdbcTypes.put("DATALINK", null);
67     }
68
69     /**
70      * Checks the given field descriptor.
71      *
72      * @param fieldDef The field descriptor
73      * @param checkLevel The amount of checks to perform
74      * @exception ConstraintException If a constraint has been violated
75      */

76     public void check(FieldDescriptorDef fieldDef, String JavaDoc checkLevel) throws ConstraintException
77     {
78         ensureColumn(fieldDef, checkLevel);
79         ensureJdbcType(fieldDef, checkLevel);
80         ensureConversion(fieldDef, checkLevel);
81         ensureLength(fieldDef, checkLevel);
82         ensurePrecisionAndScale(fieldDef, checkLevel);
83         checkLocking(fieldDef, checkLevel);
84         checkSequenceName(fieldDef, checkLevel);
85         checkId(fieldDef, checkLevel);
86         if (fieldDef.isAnonymous())
87         {
88             checkAnonymous(fieldDef, checkLevel);
89         }
90         else
91         {
92             checkReadonlyAccessForNativePKs(fieldDef, checkLevel);
93         }
94     }
95
96     /**
97      * Constraint that ensures that the field has a column property. If none is specified, then
98      * the name of the field is used.
99      *
100      * @param fieldDef The field descriptor
101      * @param checkLevel The current check level (this constraint is checked in all levels)
102      */

103     private void ensureColumn(FieldDescriptorDef fieldDef, String JavaDoc checkLevel)
104     {
105         if (!fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_COLUMN))
106         {
107             String JavaDoc javaname = fieldDef.getName();
108
109             if (fieldDef.isNested())
110             {
111                 int pos = javaname.indexOf("::");
112
113                 // we convert nested names ('_' for '::')
114
if (pos > 0)
115                 {
116                     StringBuffer JavaDoc newJavaname = new StringBuffer JavaDoc(javaname.substring(0, pos));
117                     int lastPos = pos + 2;
118
119                     do
120                     {
121                         pos = javaname.indexOf("::", lastPos);
122                         newJavaname.append("_");
123                         if (pos > 0)
124                         {
125                             newJavaname.append(javaname.substring(lastPos, pos));
126                             lastPos = pos + 2;
127                         }
128                         else
129                         {
130                             newJavaname.append(javaname.substring(lastPos));
131                         }
132                     }
133                     while (pos > 0);
134                     javaname = newJavaname.toString();
135                 }
136             }
137             fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_COLUMN, javaname);
138         }
139     }
140
141     /**
142      * Constraint that ensures that the field has a jdbc type. If none is specified, then
143      * the default type is used (which has been determined when the field descriptor was added)
144      * and - if necessary - the default conversion is set.
145      *
146      * @param fieldDef The field descriptor
147      * @param checkLevel The current check level (this constraint is checked in all levels)
148      * @exception ConstraintException If the constraint has been violated
149      */

150     private void ensureJdbcType(FieldDescriptorDef fieldDef, String JavaDoc checkLevel) throws ConstraintException
151     {
152         if (!fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE))
153         {
154             if (!fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_JDBC_TYPE))
155             {
156                 throw new ConstraintException("No jdbc-type specified for the field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName());
157             }
158
159             fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE, fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_JDBC_TYPE));
160             if (!fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_CONVERSION) && fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_CONVERSION))
161             {
162                 fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_CONVERSION, fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_CONVERSION));
163             }
164         }
165         else
166         {
167             // we could let XDoclet check the type for field declarations but not for modifications (as we could
168
// not specify the empty string anymore)
169
String JavaDoc jdbcType = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE);
170
171             if (!_jdbcTypes.containsKey(jdbcType))
172             {
173                 throw new ConstraintException("The field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName()+" specifies the invalid jdbc type "+jdbcType);
174             }
175         }
176     }
177
178     /**
179      * Constraint that ensures that the field has a conversion if the java type requires it. Also checks the conversion class.
180      *
181      * @param fieldDef The field descriptor
182      * @param checkLevel The current check level (this constraint is checked in basic (partly) and strict)
183      * @exception ConstraintException If the conversion class is invalid
184      */

185     private void ensureConversion(FieldDescriptorDef fieldDef, String JavaDoc checkLevel) throws ConstraintException
186     {
187         if (CHECKLEVEL_NONE.equals(checkLevel))
188         {
189             return;
190         }
191
192         // we issue a warning if we encounter a field with a java.util.Date java type without a conversion
193
if ("java.util.Date".equals(fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_JAVA_TYPE)) &&
194             !fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_CONVERSION))
195         {
196             LogHelper.warn(true,
197                            FieldDescriptorConstraints.class,
198                            "ensureConversion",
199                            "The field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName()+
200                                " of type java.util.Date is directly mapped to jdbc-type "+
201                                fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE)+
202                                ". However, most JDBC drivers can't handle java.util.Date directly so you might want to "+
203                                " use a conversion for converting it to a JDBC datatype like TIMESTAMP.");
204         }
205
206         String JavaDoc conversionClass = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_CONVERSION);
207
208         if (((conversionClass == null) || (conversionClass.length() == 0)) &&
209             fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_CONVERSION) &&
210             fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_JDBC_TYPE).equals(fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE)))
211         {
212             conversionClass = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_CONVERSION);
213             fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_CONVERSION, conversionClass);
214         }
215         // now checking
216
if (CHECKLEVEL_STRICT.equals(checkLevel) && (conversionClass != null) && (conversionClass.length() > 0))
217         {
218             InheritanceHelper helper = new InheritanceHelper();
219
220             try
221             {
222                 if (!helper.isSameOrSubTypeOf(conversionClass, CONVERSION_INTERFACE))
223                 {
224                     throw new ConstraintException("The conversion class specified for field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName()+" does not implement the necessary interface "+CONVERSION_INTERFACE);
225                 }
226             }
227             catch (ClassNotFoundException JavaDoc ex)
228             {
229                 throw new ConstraintException("The class "+ex.getMessage()+" hasn't been found on the classpath while checking the conversion class specified for field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName());
230             }
231         }
232 }
233
234     /**
235      * Constraint that ensures that the field has a length if the jdbc type requires it.
236      *
237      * @param fieldDef The field descriptor
238      * @param checkLevel The current check level (this constraint is checked in all levels)
239      */

240     private void ensureLength(FieldDescriptorDef fieldDef, String JavaDoc checkLevel)
241     {
242         if (!fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_LENGTH))
243         {
244             String JavaDoc defaultLength = JdbcTypeHelper.getDefaultLengthFor(fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE));
245
246             if (defaultLength != null)
247             {
248                 LogHelper.warn(true,
249                                FieldDescriptorConstraints.class,
250                                "ensureLength",
251                                "The field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName()+" has no length setting though its jdbc type requires it (in most databases); using default length of "+defaultLength);
252                 fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_LENGTH, defaultLength);
253             }
254         }
255     }
256
257     /**
258      * Constraint that ensures that the field has precision and scale settings if the jdbc type requires it.
259      *
260      * @param fieldDef The field descriptor
261      * @param checkLevel The current check level (this constraint is checked in all levels)
262      */

263     private void ensurePrecisionAndScale(FieldDescriptorDef fieldDef, String JavaDoc checkLevel)
264     {
265         fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_PRECISION, null);
266         fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_SCALE, null);
267         if (!fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_PRECISION))
268         {
269             String JavaDoc defaultPrecision = JdbcTypeHelper.getDefaultPrecisionFor(fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE));
270
271             if (defaultPrecision != null)
272             {
273                 LogHelper.warn(true,
274                                FieldDescriptorConstraints.class,
275                                "ensureLength",
276                                "The field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName()+" has no precision setting though its jdbc type requires it (in most databases); using default precision of "+defaultPrecision);
277                 fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_PRECISION, defaultPrecision);
278             }
279             else if (fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_SCALE))
280             {
281                 fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_PRECISION, "1");
282             }
283         }
284         if (!fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_SCALE))
285          {
286             String JavaDoc defaultScale = JdbcTypeHelper.getDefaultScaleFor(fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE));
287
288             if (defaultScale != null)
289             {
290                 LogHelper.warn(true,
291                                FieldDescriptorConstraints.class,
292                                "ensureLength",
293                                "The field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName()+" has no scale setting though its jdbc type requires it (in most databases); using default scale of "+defaultScale);
294                 fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_SCALE, defaultScale);
295             }
296             else if (fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_PRECISION) || fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_PRECISION))
297             {
298                 fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_DEFAULT_SCALE, "0");
299             }
300         }
301     }
302
303     /**
304      * Checks that locking and update-lock are only used for fields of TIMESTAMP or INTEGER type.
305      *
306      * @param fieldDef The field descriptor
307      * @param checkLevel The current check level (this constraint is checked in basic and strict)
308      * @exception ConstraintException If the constraint has been violated
309      */

310     private void checkLocking(FieldDescriptorDef fieldDef, String JavaDoc checkLevel) throws ConstraintException
311     {
312         if (CHECKLEVEL_NONE.equals(checkLevel))
313         {
314             return;
315         }
316
317         String JavaDoc jdbcType = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_JDBC_TYPE);
318
319         if (!"TIMESTAMP".equals(jdbcType) && !"INTEGER".equals(jdbcType))
320         {
321             if (fieldDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_LOCKING, false))
322             {
323                 throw new ConstraintException("The field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName()+" has locking set to true though it is not of TIMESTAMP or INTEGER type");
324             }
325             if (fieldDef.getBooleanProperty(PropertyHelper.OJB_PROPERTY_UPDATE_LOCK, false))
326             {
327                 throw new ConstraintException("The field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName()+" has update-lock set to true though it is not of TIMESTAMP or INTEGER type");
328             }
329         }
330     }
331
332     /**
333      * Checks that sequence-name is only used with autoincrement='ojb'
334      *
335      * @param fieldDef The field descriptor
336      * @param checkLevel The current check level (this constraint is checked in basic and strict)
337      * @exception ConstraintException If the constraint has been violated
338      */

339     private void checkSequenceName(FieldDescriptorDef fieldDef, String JavaDoc checkLevel) throws ConstraintException
340     {
341         if (CHECKLEVEL_NONE.equals(checkLevel))
342         {
343             return;
344         }
345
346         String JavaDoc autoIncr = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_AUTOINCREMENT);
347         String JavaDoc seqName = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_SEQUENCE_NAME);
348
349         if ((seqName != null) && (seqName.length() > 0))
350         {
351             if (!"ojb".equals(autoIncr) && !"database".equals(autoIncr))
352             {
353                 throw new ConstraintException("The field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName()+" has sequence-name set though it's autoincrement value is not set to 'ojb'");
354             }
355         }
356     }
357
358     /**
359      * Checks the id value.
360      *
361      * @param fieldDef The field descriptor
362      * @param checkLevel The current check level (this constraint is checked in basic and strict)
363      * @exception ConstraintException If the constraint has been violated
364      */

365     private void checkId(FieldDescriptorDef fieldDef, String JavaDoc checkLevel) throws ConstraintException
366     {
367         if (CHECKLEVEL_NONE.equals(checkLevel))
368         {
369             return;
370         }
371
372         String JavaDoc id = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_ID);
373
374         if ((id != null) && (id.length() > 0))
375         {
376             try
377             {
378                 Integer.parseInt(id);
379             }
380             catch (NumberFormatException JavaDoc ex)
381             {
382                 throw new ConstraintException("The id attribute of field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName()+" is not a valid number");
383             }
384         }
385     }
386
387     /**
388      * Checks that native primarykey fields have readonly access, and warns if not.
389      *
390      * @param fieldDef The field descriptor
391      * @param checkLevel The current check level (this constraint is checked in basic and strict)
392      */

393     private void checkReadonlyAccessForNativePKs(FieldDescriptorDef fieldDef, String JavaDoc checkLevel)
394     {
395         if (CHECKLEVEL_NONE.equals(checkLevel))
396         {
397             return;
398         }
399
400         String JavaDoc access = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_ACCESS);
401         String JavaDoc autoInc = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_AUTOINCREMENT);
402
403         if ("database".equals(autoInc) && !"readonly".equals(access))
404         {
405             LogHelper.warn(true,
406                            FieldDescriptorConstraints.class,
407                            "checkAccess",
408                            "The field "+fieldDef.getName()+" in class "+fieldDef.getOwner().getName()+" is set to database auto-increment. Therefore the field's access is set to 'readonly'.");
409             fieldDef.setProperty(PropertyHelper.OJB_PROPERTY_ACCESS, "readonly");
410         }
411     }
412
413     /**
414      * Checks anonymous fields.
415      *
416      * @param fieldDef The field descriptor
417      * @param checkLevel The current check level (this constraint is checked in basic and strict)
418      * @exception ConstraintException If the constraint has been violated
419      */

420     private void checkAnonymous(FieldDescriptorDef fieldDef, String JavaDoc checkLevel) throws ConstraintException
421     {
422         if (CHECKLEVEL_NONE.equals(checkLevel))
423         {
424             return;
425         }
426
427         String JavaDoc access = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_ACCESS);
428
429         if (!"anonymous".equals(access))
430         {
431             throw new ConstraintException("The access property of the field "+fieldDef.getName()+" defined in class "+fieldDef.getOwner().getName()+" cannot be changed");
432         }
433
434         if ((fieldDef.getName() == null) || (fieldDef.getName().length() == 0))
435         {
436             throw new ConstraintException("An anonymous field defined in class "+fieldDef.getOwner().getName()+" has no name");
437         }
438     }
439 }
440
Popular Tags