1 19 20 package org.apache.cayenne.jpa.conf; 21 22 import java.sql.Time ; 23 import java.sql.Timestamp ; 24 import java.util.Collection ; 25 import java.util.Date ; 26 27 import javax.persistence.EnumType; 28 import javax.persistence.TemporalType; 29 30 import org.apache.cayenne.jpa.JpaProviderException; 31 import org.apache.cayenne.jpa.map.AccessType; 32 import org.apache.cayenne.jpa.map.JpaAttribute; 33 import org.apache.cayenne.jpa.map.JpaAttributes; 34 import org.apache.cayenne.jpa.map.JpaBasic; 35 import org.apache.cayenne.jpa.map.JpaClassDescriptor; 36 import org.apache.cayenne.jpa.map.JpaColumn; 37 import org.apache.cayenne.jpa.map.JpaEntity; 38 import org.apache.cayenne.jpa.map.JpaEntityMap; 39 import org.apache.cayenne.jpa.map.JpaId; 40 import org.apache.cayenne.jpa.map.JpaJoinColumn; 41 import org.apache.cayenne.jpa.map.JpaManyToMany; 42 import org.apache.cayenne.jpa.map.JpaManyToOne; 43 import org.apache.cayenne.jpa.map.JpaMappedSuperclass; 44 import org.apache.cayenne.jpa.map.JpaOneToMany; 45 import org.apache.cayenne.jpa.map.JpaOneToOne; 46 import org.apache.cayenne.jpa.map.JpaPropertyDescriptor; 47 import org.apache.cayenne.jpa.map.JpaRelationship; 48 import org.apache.cayenne.jpa.map.JpaTable; 49 import org.apache.cayenne.jpa.map.JpaVersion; 50 import org.apache.cayenne.project.ProjectPath; 51 import org.apache.cayenne.util.BaseTreeVisitor; 52 import org.apache.cayenne.util.HierarchicalTreeVisitor; 53 import org.apache.cayenne.util.TraversalUtil; 54 import org.apache.cayenne.util.Util; 55 import org.apache.cayenne.validation.SimpleValidationFailure; 56 57 62 public class EntityMapDefaultsProcessor { 63 64 protected HierarchicalTreeVisitor visitor; 65 protected transient EntityMapLoaderContext context; 66 67 public void applyDefaults(EntityMapLoaderContext context) throws JpaProviderException { 68 this.context = context; 69 70 if (visitor == null) { 71 visitor = createVisitor(); 72 } 73 74 TraversalUtil.traverse(context.getEntityMap(), visitor); 75 } 76 77 81 protected HierarchicalTreeVisitor createVisitor() { 82 return new EntityMapVisitor(); 83 } 84 85 abstract class AbstractEntityVisitor extends BaseTreeVisitor { 86 87 AbstractEntityVisitor() { 88 BaseTreeVisitor attributeVisitor = new BaseTreeVisitor(); 89 attributeVisitor.addChildVisitor(JpaId.class, new IdVisitor()); 90 attributeVisitor.addChildVisitor(JpaBasic.class, new BasicVisitor()); 91 attributeVisitor.addChildVisitor(JpaVersion.class, new VersionVisitor()); 92 attributeVisitor.addChildVisitor(JpaManyToOne.class, new FKVisitor()); 93 attributeVisitor.addChildVisitor(JpaOneToOne.class, new FKVisitor()); 94 attributeVisitor.addChildVisitor( 95 JpaManyToMany.class, 96 new RelationshipVisitor()); 97 attributeVisitor.addChildVisitor( 98 JpaOneToMany.class, 99 new RelationshipVisitor()); 100 101 addChildVisitor(JpaAttributes.class, attributeVisitor); 102 addChildVisitor(JpaId.class, new IdVisitor()); 103 } 104 105 @Override 106 public boolean onStartNode(ProjectPath path) { 107 JpaEntity entity = (JpaEntity) path.getObject(); 108 109 if (entity.getClassName() == null) { 111 return false; 112 } 113 114 if (entity.getName() == null) { 115 116 String fqName = entity.getClassName(); 118 int split = fqName.lastIndexOf('.'); 119 entity.setName(split > 0 ? fqName.substring(split + 1) : fqName); 120 } 121 122 if (entity.getAttributes() == null) { 123 entity.setAttributes(new JpaAttributes()); 124 } 125 126 JpaClassDescriptor descriptor = entity.getClassDescriptor(); 128 129 AccessType access = entity.getAccess(); 130 if (access == null) { 131 access = ((JpaEntityMap) path.getRoot()).getAccess(); 132 entity.setAccess(access); 133 } 134 135 if (access == AccessType.PROPERTY) { 136 for (JpaPropertyDescriptor candidate : descriptor 137 .getPropertyDescriptors()) { 138 processProperty(entity, descriptor, candidate); 139 } 140 } 141 else { 143 for (JpaPropertyDescriptor candidate : descriptor.getFieldDescriptors()) { 144 processProperty(entity, descriptor, candidate); 145 } 146 } 147 148 if (entity.getTable() == null) { 150 JpaTable table = new JpaTable(AnnotationPrototypes.getTable()); 151 152 table.setName(entity.getName()); 157 entity.setTable(table); 158 } 159 160 return true; 161 } 162 163 void processProperty( 164 JpaEntity entity, 165 JpaClassDescriptor descriptor, 166 JpaPropertyDescriptor property) { 167 168 JpaAttributes attributes = entity.getAttributes(); 169 if (attributes.getAttribute(property.getName()) != null) { 170 return; 171 } 172 173 if (property.isDefaultNonRelationalType()) { 174 175 JpaBasic attribute = new JpaBasic(); 176 177 attribute.setPropertyDescriptor(property); 178 attribute.setName(property.getName()); 179 attributes.getBasicAttributes().add(attribute); 180 } 181 else { 182 String path = descriptor.getManagedClass().getName() 183 + "." 184 + property.getName(); 185 context.recordConflict(new SimpleValidationFailure( 186 property.getMember(), 187 "Undefined property persistence status: " + path)); 188 } 189 } 190 } 191 192 class BasicVisitor extends BaseTreeVisitor { 193 194 BasicVisitor() { 195 addChildVisitor(JpaColumn.class, new ColumnVisitor()); 196 } 197 198 @Override 199 public boolean onStartNode(ProjectPath path) { 200 JpaBasic jpaBasic = (JpaBasic) path.getObject(); 201 if (jpaBasic.getColumn() == null) { 202 JpaColumn column = new JpaColumn(AnnotationPrototypes.getColumn()); 203 column.setName(jpaBasic.getName()); 204 column.setNullable(jpaBasic.isOptional()); 205 jpaBasic.setColumn(column); 206 } 207 208 JpaEntity entity = (JpaEntity) path.firstInstanceOf(JpaEntity.class); 209 210 if (jpaBasic.getTemporal() == null && jpaBasic.getEnumerated() == null) { 212 JpaClassDescriptor descriptor = entity.getClassDescriptor(); 213 JpaPropertyDescriptor property = descriptor.getProperty(jpaBasic 214 .getName()); 215 216 if (property == null) { 218 throw new IllegalStateException ("No class property found for name: " 219 + jpaBasic.getName()); 220 } 221 222 if (java.sql.Date .class.isAssignableFrom(property.getType())) { 223 jpaBasic.setTemporal(TemporalType.DATE); 224 } 225 else if (Time .class.isAssignableFrom(property.getType())) { 226 jpaBasic.setTemporal(TemporalType.TIME); 227 } 228 else if (Timestamp .class.isAssignableFrom(property.getType())) { 229 jpaBasic.setTemporal(TemporalType.TIMESTAMP); 230 } 231 else if (Date .class.isAssignableFrom(property.getType())) { 232 jpaBasic.setTemporal(TemporalType.TIMESTAMP); 233 } 234 else if (property.getType().isEnum()) { 235 jpaBasic.setEnumerated(EnumType.ORDINAL); 236 } 237 } 238 239 return true; 240 } 241 } 242 243 class VersionVisitor extends BasicVisitor { 244 245 @Override 246 public boolean onStartNode(ProjectPath path) { 247 JpaVersion jpaBasic = (JpaVersion) path.getObject(); 248 if (jpaBasic.getColumn() == null) { 249 JpaColumn column = new JpaColumn(AnnotationPrototypes.getColumn()); 250 column.setName(jpaBasic.getName()); 251 jpaBasic.setColumn(column); 252 } 253 254 if (jpaBasic.getTemporal() == null) { 255 JpaEntity entity = (JpaEntity) path.firstInstanceOf(JpaEntity.class); 256 JpaClassDescriptor descriptor = entity.getClassDescriptor(); 257 JpaPropertyDescriptor property = descriptor.getProperty(jpaBasic 258 .getName()); 259 260 if (Date .class.equals(property.getType())) { 261 jpaBasic.setTemporal(TemporalType.TIMESTAMP); 262 } 263 } 264 265 return true; 266 } 267 } 268 269 final class ColumnVisitor extends BaseTreeVisitor { 270 271 @Override 272 public boolean onStartNode(ProjectPath path) { 273 JpaColumn column = (JpaColumn) path.getObject(); 274 275 JpaAttribute parent = (JpaAttribute) path.firstInstanceOf(JpaAttribute.class); 276 277 if (column.getName() == null) { 278 column.setName(parent.getName()); 279 } 280 281 if (column.getTable() == null) { 282 JpaEntity entity = (JpaEntity) path.firstInstanceOf(JpaEntity.class); 283 column.setTable(entity.getTable().getName()); 284 } 285 286 if (parent.getPropertyDescriptor().isStringType()) { 287 if (column.getLength() < 0) { 288 column.setLength(255); 289 } 290 } 291 else { 292 column.setLength(-1); 294 } 295 296 return true; 297 } 298 } 299 300 final class EntityMapVisitor extends BaseTreeVisitor { 301 302 EntityMapVisitor() { 303 addChildVisitor(JpaEntity.class, new EntityVisitor()); 304 addChildVisitor(JpaMappedSuperclass.class, new MappedSuperclassVisitor()); 305 } 306 307 @Override 308 public boolean onStartNode(ProjectPath path) { 309 JpaEntityMap entityMap = (JpaEntityMap) path.getObject(); 310 311 314 entityMap.setAccess(AccessType.FIELD); 315 316 return true; 317 } 318 } 319 320 final class EntityVisitor extends AbstractEntityVisitor { 321 322 } 323 324 final class IdVisitor extends BaseTreeVisitor { 325 326 IdVisitor() { 327 addChildVisitor(JpaColumn.class, new ColumnVisitor()); 328 } 329 330 @Override 331 public boolean onStartNode(ProjectPath path) { 332 JpaId id = (JpaId) path.getObject(); 333 334 if (id.getColumn() == null) { 335 336 JpaColumn column = new JpaColumn(AnnotationPrototypes.getColumn()); 337 column.setName(id.getName()); 338 339 JpaEntity entity = (JpaEntity) path.firstInstanceOf(JpaEntity.class); 340 column.setTable(entity.getTable().getName()); 341 id.setColumn(column); 342 } 343 344 return true; 345 } 346 } 347 348 final class JoinColumnVisitor extends BaseTreeVisitor { 349 350 @Override 351 public boolean onStartNode(ProjectPath path) { 352 JpaRelationship relationship = (JpaRelationship) path.getObjectParent(); 353 JpaJoinColumn column = (JpaJoinColumn) path.getObject(); 354 355 if (column.getTable() == null) { 356 JpaEntity entity = (JpaEntity) path.firstInstanceOf(JpaEntity.class); 357 column.setTable(entity.getTable().getName()); 358 } 359 360 368 JpaEntityMap map = (JpaEntityMap) path.firstInstanceOf(JpaEntityMap.class); 369 JpaEntity target = map.entityForClass(relationship.getTargetEntityName()); 370 371 if (target == null) { 372 context.recordConflict(new SimpleValidationFailure( 373 relationship, 374 "Invalid relationship target " 375 + relationship.getTargetEntityName())); 376 } 377 else if (target.getAttributes() == null 378 || target.getAttributes().getIds().isEmpty()) { 379 context.recordConflict(new SimpleValidationFailure( 380 target, 381 "Relationship target has no PK defined: " 382 + relationship.getTargetEntityName())); 383 } 384 else if (target.getAttributes().getIds().size() > 1) { 385 context.recordConflict(new SimpleValidationFailure( 389 relationship, 390 "Defaults for compound FK are not implemented.")); 391 } 392 else { 393 JpaId id = target.getAttributes().getIds().iterator().next(); 394 395 String pkName = id.getColumn() != null ? id.getColumn().getName() : id 396 .getName(); 397 column.setName(relationship.getName() + '_' + pkName); 398 column.setReferencedColumnName(id.getColumn() != null ? id 399 .getColumn() 400 .getName() : id.getName()); 401 } 402 403 return true; 404 } 405 } 406 407 final class MappedSuperclassVisitor extends AbstractEntityVisitor { 408 409 } 410 411 final class FKVisitor extends RelationshipVisitor { 412 413 FKVisitor() { 414 addChildVisitor(JpaJoinColumn.class, new JoinColumnVisitor()); 415 } 416 417 @Override 418 public boolean onStartNode(ProjectPath path) { 419 420 if (!super.onStartNode(path)) { 421 return false; 422 } 423 424 Object relationship = path.getObject(); 425 Collection <JpaJoinColumn> joinColumns = null; 426 String mappedBy = null; 427 428 if (relationship instanceof JpaOneToOne) { 429 joinColumns = ((JpaOneToOne) relationship).getJoinColumns(); 430 mappedBy = ((JpaOneToOne) relationship).getMappedBy(); 431 if (joinColumns.isEmpty() && mappedBy != null) { 432 joinColumns.add(new JpaJoinColumn(AnnotationPrototypes 433 .getJoinColumn())); 434 } 435 } 436 else if (relationship instanceof JpaOneToMany) { 437 joinColumns = ((JpaOneToMany) relationship).getJoinColumns(); 438 mappedBy = ((JpaOneToMany) relationship).getMappedBy(); 439 if (joinColumns.isEmpty() && mappedBy != null) { 440 joinColumns.add(new JpaJoinColumn(AnnotationPrototypes 441 .getJoinColumn())); 442 } 443 } 444 else if (relationship instanceof JpaManyToOne) { 445 joinColumns = ((JpaManyToOne) relationship).getJoinColumns(); 446 if (joinColumns.isEmpty()) { 447 joinColumns.add(new JpaJoinColumn(AnnotationPrototypes 448 .getJoinColumn())); 449 } 450 } 451 452 return true; 453 } 454 } 455 456 class RelationshipVisitor extends BaseTreeVisitor { 457 458 @Override 459 public boolean onStartNode(ProjectPath path) { 460 461 JpaRelationship relationship = (JpaRelationship) path.getObject(); 462 if (Util.isEmptyString(relationship.getTargetEntityName())) { 463 464 JpaEntity entity = (JpaEntity) path.firstInstanceOf(JpaEntity.class); 465 466 String name = relationship.getName(); 467 468 JpaClassDescriptor srcDescriptor = entity.getClassDescriptor(); 469 JpaPropertyDescriptor property = srcDescriptor.getProperty(name); 470 471 Class targetEntityType = property.getTargetEntityType(); 472 473 if (targetEntityType == null) { 474 context.recordConflict(new SimpleValidationFailure(property 475 .getMember(), "Undefined target entity type: " + name)); 476 return false; 477 } 478 else { 479 relationship.setTargetEntityName(targetEntityType.getName()); 480 } 481 } 482 483 return true; 484 } 485 } 486 } 487 | Popular Tags |