1 package org.hibernate.cfg; 3 4 import java.util.Map ; 5 6 import org.apache.commons.logging.Log; 7 import org.apache.commons.logging.LogFactory; 8 import org.hibernate.AnnotationException; 9 import org.hibernate.AssertionFailure; 10 import org.hibernate.annotations.Index; 11 import org.hibernate.cfg.annotations.Nullability; 12 import org.hibernate.mapping.Column; 13 import org.hibernate.mapping.Join; 14 import org.hibernate.mapping.Property; 15 import org.hibernate.mapping.SimpleValue; 16 import org.hibernate.mapping.Table; 17 import org.hibernate.mapping.Formula; 18 import org.hibernate.util.StringHelper; 19 20 26 public class Ejb3Column { 27 private static final Log log = LogFactory.getLog(Ejb3Column.class); 28 private Column mappingColumn; 29 private boolean insertable = true; 30 private boolean updatable = true; 31 private String secondaryTableName; 32 protected Map <String , Join> joins; 33 protected PropertyHolder propertyHolder; 34 private Mappings mappings; 35 private boolean isImplicit; 36 public static final int DEFAULT_COLUMN_LENGTH = 255; 37 public String sqlType; 38 private int length = DEFAULT_COLUMN_LENGTH; 39 private int precision; 40 private int scale; 41 private String columnName; 42 private boolean unique; 43 private boolean nullable = true; 44 private String formulaString; 45 private Formula formula; 46 47 public String getSqlType() { 48 return sqlType; 49 } 50 51 public int getLength() { 52 return length; 53 } 54 55 public int getPrecision() { 56 return precision; 57 } 58 59 public int getScale() { 60 return scale; 61 } 62 63 public boolean isUnique() { 64 return unique; 65 } 66 67 public String getFormulaString() { 68 return formulaString; 69 } 70 71 public String getSecondaryTableName() { 72 return secondaryTableName; 73 } 74 75 public void setFormula(String formula) { 76 this.formulaString = formula; 77 } 78 79 public boolean isImplicit() { 80 return isImplicit; 81 } 82 83 public void setInsertable(boolean insertable) { 84 this.insertable = insertable; 85 } 86 87 public void setUpdatable(boolean updatable) { 88 this.updatable = updatable; 89 } 90 91 public void setMappings(Mappings mappings) { 92 this.mappings = mappings; 93 } 94 95 public void setImplicit(boolean implicit) { 96 isImplicit = implicit; 97 } 98 99 public void setSqlType(String sqlType) { 100 this.sqlType = sqlType; 101 } 102 103 public void setLength(int length) { 104 this.length = length; 105 } 106 107 public void setPrecision(int precision) { 108 this.precision = precision; 109 } 110 111 public void setScale(int scale) { 112 this.scale = scale; 113 } 114 115 public void setColumnName(String columnName) { 116 this.columnName = columnName; 117 } 118 119 public void setUnique(boolean unique) { 120 this.unique = unique; 121 } 122 123 public boolean isNullable() { 124 return mappingColumn.isNullable(); 125 } 126 127 public Ejb3Column() {} 128 129 public void bind() { 130 if ( StringHelper.isNotEmpty(formulaString) ) { 131 log.debug("binding formula " + formulaString); 132 formula = new Formula(); 133 formula.setFormula(formulaString); 134 } 135 else { 136 log.debug("Binding column " + columnName + " unique " + unique); 137 initMappingColumn(columnName, length, precision, scale, nullable, sqlType, unique); 138 } 139 } 140 141 protected void initMappingColumn(String name, int length, int precision, int scale, boolean nullable, String sqlType, boolean unique) { 142 this.mappingColumn = new Column(); 143 redefineColumnName(name); 144 this.mappingColumn.setLength(length); 145 if (precision > 0) { this.mappingColumn.setPrecision(precision); 147 this.mappingColumn.setScale(scale); 148 } 149 this.mappingColumn.setNullable(nullable); 150 this.mappingColumn.setSqlType(sqlType); 151 this.mappingColumn.setUnique(unique); 152 } 153 154 public boolean isNameDeferred() { 155 return mappingColumn == null || StringHelper.isEmpty( mappingColumn.getName() ); 156 } 157 158 public void redefineColumnName(String name) { 159 if (name != null) { 160 mappingColumn.setName( mappings.getNamingStrategy().columnName( name ) ); 161 } 162 } 163 164 public String getName() { 165 return mappingColumn.getName(); 166 } 167 168 public Column getMappingColumn() { 169 return mappingColumn; 170 } 171 172 public boolean isInsertable() { 173 return insertable; 174 } 175 176 public boolean isUpdatable() { 177 return updatable; 178 } 179 180 public void setNullable(boolean nullable) { 181 if ( mappingColumn != null ) { 182 mappingColumn.setNullable(nullable); 183 } 184 else { 185 this.nullable = nullable; 186 } 187 } 188 189 public void setJoins(Map <String , Join> joins) { 190 this.joins = joins; 191 } 192 193 public PropertyHolder getPropertyHolder() { 194 return propertyHolder; 195 } 196 197 public void setPropertyHolder(PropertyHolder propertyHolder) { 198 this.propertyHolder = propertyHolder; 199 } 200 201 protected void setMappingColumn(Column mappingColumn) { 202 this.mappingColumn = mappingColumn; 203 } 204 205 public void linkWithValue(SimpleValue value) { 206 if ( formula != null ) { 207 value.addFormula(formula); 208 } 209 else { 210 getMappingColumn().setValue(value); 211 value.addColumn( getMappingColumn() ); 212 value.getTable().addColumn( getMappingColumn() ); 213 } 214 } 215 222 public Table getTable() { 223 224 if ( isSecondary() ) { 225 return getJoin().getTable(); 226 } 227 else { 228 return propertyHolder.getTable(); 229 } 230 } 231 232 public boolean isSecondary() { 233 if (propertyHolder == null) { 234 throw new AssertionFailure("Should not call getTable() on column wo persistent class defined"); 235 } 236 if ( StringHelper.isNotEmpty(secondaryTableName) ) { 237 return true; 238 } 239 return false; 241 } 242 243 private Join getJoin() { 244 Join join = joins.get(secondaryTableName); 245 if (join == null) { 246 throw new AnnotationException("Cannot find the expected secondary table: no " 247 + secondaryTableName + " in " + propertyHolder.getClassName() ); 248 } 249 else { 250 return join; 251 } 252 } 253 254 260 public void addPropertyToMappingContainer(Property prop) { 261 if ( isSecondary() ) { 262 getJoin().addProperty(prop); 263 } 264 else { 265 propertyHolder.addProperty(prop); 266 } 267 } 268 269 public void forceNotNull() { 270 mappingColumn.setNullable(false); 271 } 272 273 public void setSecondaryTableName(String secondaryTableName) { 274 this.secondaryTableName = secondaryTableName; 275 } 276 277 public static Ejb3Column[] buildColumnFromAnnotation( 278 javax.persistence.Column[] anns, 279 org.hibernate.annotations.Formula formulaAnn, Nullability nullability, PropertyHolder propertyHolder, 280 PropertyInferredData inferredData, 281 Map <String , Join> secondaryTables, 282 ExtendedMappings mappings 283 ) { 284 Ejb3Column[] columns; 285 if (formulaAnn != null) { 286 Ejb3Column formulaColumn = new Ejb3Column(); 287 formulaColumn.setFormula( formulaAnn.value() ); 288 formulaColumn.setImplicit(false); 289 formulaColumn.setMappings(mappings); 290 formulaColumn.setPropertyHolder(propertyHolder); 291 formulaColumn.bind(); 292 columns = new Ejb3Column[] { formulaColumn }; 293 } 294 else { 295 javax.persistence.Column[] actualCols = anns; 296 javax.persistence.Column[] overriddenCols = propertyHolder.getOverriddenColumn( inferredData.getPropertyName() ); 297 if (overriddenCols != null) { 298 if (anns != null && overriddenCols.length != anns.length) { 300 throw new AnnotationException("AttributeOverride.column() should override all columns for now"); 301 } 302 actualCols = overriddenCols.length == 0 ? null : overriddenCols; 303 log.debug( "Column(s) overridden for property " + inferredData.getPropertyName() ); 304 } 305 if (actualCols == null) { 306 columns = buildImplicitColumn(inferredData, secondaryTables, propertyHolder, nullability, mappings); 307 } 308 else { 309 final int length = actualCols.length; 310 columns = new Ejb3Column[length]; 311 for (int index = 0 ; index < length ; index++) { 312 javax.persistence.Column col = actualCols[index]; 313 String sqlType = col.columnDefinition().equals("") ? null : col.columnDefinition(); 314 String name = col.name().equals("") ? inferredData.getPropertyName() : col.name(); 315 Ejb3Column column = new Ejb3Column(); 316 column.setImplicit(false); 317 column.setSqlType(sqlType); 318 column.setLength( col.length() ); 319 column.setPrecision( col.precision() ); 320 column.setScale( col.scale() ); 321 column.setColumnName(name); 322 column.setNullable( col.nullable() ); column.setUnique( col.unique() ); 324 column.setInsertable( col.insertable() ); 325 column.setUpdatable( col.updatable() ); 326 column.setSecondaryTableName( col.secondaryTable() ); 327 column.setPropertyHolder(propertyHolder); 328 column.setJoins(secondaryTables); 329 column.setMappings(mappings); 330 column.bind(); 331 columns[index] = column; 332 } 333 } 334 } 335 return columns; 336 } 337 338 private static Ejb3Column[] buildImplicitColumn( 339 PropertyInferredData inferredData, Map <String , Join> secondaryTables, PropertyHolder propertyHolder, 340 Nullability nullability, ExtendedMappings mappings 341 ) { 342 Ejb3Column[] columns; 343 columns = new Ejb3Column[1]; 344 Ejb3Column column = new Ejb3Column(); 345 column.setImplicit(false); 346 if ( nullability != Nullability.FORCED_NULL 348 && inferredData.getReturnedClassOrElement().isPrimitive() 349 && ! inferredData.isArray() ) { 350 column.setNullable(false); 351 } 352 column.setLength( DEFAULT_COLUMN_LENGTH ); 353 column.setColumnName( inferredData.getPropertyName() ); 354 column.setPropertyHolder(propertyHolder); 355 column.setJoins(secondaryTables); 356 column.setMappings(mappings); 357 column.bind(); 358 columns[0] = column; 359 return columns; 360 } 361 362 public static void checkPropertyConsistency(Ejb3Column[] columns, String propertyName) { 363 int nbrOfColumns = columns.length; 364 if (nbrOfColumns > 1) { 365 for (int currentIndex = 1 ; currentIndex < nbrOfColumns ; currentIndex++) { 366 if ( columns[currentIndex].isInsertable() != columns[currentIndex-1].isInsertable() ) { 367 throw new AnnotationException( "Mixing insertable and non insertable columns in a property is not allowed: " + propertyName ); 368 } 369 if ( columns[currentIndex].isNullable() != columns[currentIndex-1].isNullable() ) { 370 throw new AnnotationException( "Mixing nullable and non nullable columns in a property is not allowed: " + propertyName ); 371 } 372 if ( columns[currentIndex].isUpdatable() != columns[currentIndex-1].isUpdatable() ) { 373 throw new AnnotationException( "Mixing updatable and non updatable columns in a property is not allowed: " + propertyName ); 374 } 375 if ( ! columns[currentIndex].getTable().equals( columns[currentIndex-1].getTable() ) ) { 376 throw new AnnotationException( "Mixing different tables in a property is not allowed: " + propertyName ); 377 } 378 } 379 } 380 } 381 382 public void addIndex(Index index) { 383 if (index == null) return; 384 if (mappingColumn == null) { 385 throw new AnnotationException( "Index on formula not allowed: " + propertyHolder.getEntityName() ); 386 } 387 if ( StringHelper.isEmpty( secondaryTableName ) ) { 388 propertyHolder.getPersistentClass().getRootTable().getOrCreateIndex( index.name() ).addColumn( mappingColumn ); 389 } 390 else { 391 getJoin().getTable().getOrCreateIndex( index.name() ).addColumn( mappingColumn ); 392 } 393 } 394 } | Popular Tags |