1 package xdoclet.modules.ojb.constraints; 2 3 import java.util.HashMap ; 4 5 import xdoclet.modules.ojb.LogHelper; 6 import xdoclet.modules.ojb.model.FieldDescriptorDef; 7 import xdoclet.modules.ojb.model.PropertyHelper; 8 9 23 24 29 public class FieldDescriptorConstraints extends FeatureDescriptorConstraints 30 { 31 32 private final static String CONVERSION_INTERFACE = "org.apache.ojb.broker.accesslayer.conversions.FieldConversion"; 33 34 private HashMap _jdbcTypes = new HashMap (); 35 36 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 76 public void check(FieldDescriptorDef fieldDef, String 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 103 private void ensureColumn(FieldDescriptorDef fieldDef, String checkLevel) 104 { 105 if (!fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_COLUMN)) 106 { 107 String javaname = fieldDef.getName(); 108 109 if (fieldDef.isNested()) 110 { 111 int pos = javaname.indexOf("::"); 112 113 if (pos > 0) 115 { 116 StringBuffer newJavaname = new StringBuffer (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 150 private void ensureJdbcType(FieldDescriptorDef fieldDef, String 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 String 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 185 private void ensureConversion(FieldDescriptorDef fieldDef, String checkLevel) throws ConstraintException 186 { 187 if (CHECKLEVEL_NONE.equals(checkLevel)) 188 { 189 return; 190 } 191 192 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 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 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 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 240 private void ensureLength(FieldDescriptorDef fieldDef, String checkLevel) 241 { 242 if (!fieldDef.hasProperty(PropertyHelper.OJB_PROPERTY_LENGTH)) 243 { 244 String 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 263 private void ensurePrecisionAndScale(FieldDescriptorDef fieldDef, String 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 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 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 310 private void checkLocking(FieldDescriptorDef fieldDef, String checkLevel) throws ConstraintException 311 { 312 if (CHECKLEVEL_NONE.equals(checkLevel)) 313 { 314 return; 315 } 316 317 String 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 339 private void checkSequenceName(FieldDescriptorDef fieldDef, String checkLevel) throws ConstraintException 340 { 341 if (CHECKLEVEL_NONE.equals(checkLevel)) 342 { 343 return; 344 } 345 346 String autoIncr = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_AUTOINCREMENT); 347 String 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 365 private void checkId(FieldDescriptorDef fieldDef, String checkLevel) throws ConstraintException 366 { 367 if (CHECKLEVEL_NONE.equals(checkLevel)) 368 { 369 return; 370 } 371 372 String 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 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 393 private void checkReadonlyAccessForNativePKs(FieldDescriptorDef fieldDef, String checkLevel) 394 { 395 if (CHECKLEVEL_NONE.equals(checkLevel)) 396 { 397 return; 398 } 399 400 String access = fieldDef.getProperty(PropertyHelper.OJB_PROPERTY_ACCESS); 401 String 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 420 private void checkAnonymous(FieldDescriptorDef fieldDef, String checkLevel) throws ConstraintException 421 { 422 if (CHECKLEVEL_NONE.equals(checkLevel)) 423 { 424 return; 425 } 426 427 String 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 |