diff options
author | kmoore | 2011-02-06 02:07:28 +0000 |
---|---|---|
committer | kmoore | 2011-02-06 02:07:28 +0000 |
commit | c9c9e2b3e236ad701f642b72bca0cfabcac1d97b (patch) | |
tree | 346196323dc94395c2348339ac67e4f4cec6ebbf /jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java | |
parent | 8f2746f6b8c2ddc81d653d54d280043c41ed4734 (diff) | |
download | webtools.dali-c9c9e2b3e236ad701f642b72bca0cfabcac1d97b.tar.gz webtools.dali-c9c9e2b3e236ad701f642b72bca0cfabcac1d97b.tar.xz webtools.dali-c9c9e2b3e236ad701f642b72bca0cfabcac1d97b.zip |
renamed org.eclipse.jpt.core to org.eclipse.jpt.jpa.core
Diffstat (limited to 'jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java')
77 files changed, 15224 insertions, 0 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaAttributeMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaAttributeMapping.java new file mode 100644 index 0000000000..1a92c17ab5 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaAttributeMapping.java @@ -0,0 +1,319 @@ +/******************************************************************************* + * Copyright (c) 2006, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.internal.Transformer; +import org.eclipse.jpt.common.utility.internal.iterators.EmptyIterator; +import org.eclipse.jpt.common.utility.internal.iterators.SingleElementIterator; +import org.eclipse.jpt.jpa.core.context.AttributeMapping; +import org.eclipse.jpt.jpa.core.context.Column; +import org.eclipse.jpt.jpa.core.context.ColumnMapping; +import org.eclipse.jpt.jpa.core.context.Relationship; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.internal.context.MappingTools; +import org.eclipse.jpt.jpa.core.internal.jpa2.context.SimpleMetamodelField; +import org.eclipse.jpt.jpa.core.internal.validation.DefaultJpaValidationMessages; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationMessages; +import org.eclipse.jpt.jpa.core.jpa2.context.AttributeMapping2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.MetamodelField; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaPersistentAttribute2_0; +import org.eclipse.jpt.jpa.core.jpa2.resource.java.JPA2_0; +import org.eclipse.jpt.jpa.core.resource.java.Annotation; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentAttribute; +import org.eclipse.jpt.jpa.db.Table; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java attribute mapping + * <p> + * The mapping annotation is <code>null</code> for default mappings. + * It will be faulted into existence whenever {@link #getAnnotationForUpdate()} + * is called. It will <em>not</em> return to <code>null</code> automatically + * when all its state is defaulted; it must be explicitly cleared via + * {@link JavaPersistentAttribute#setMappingKey(String)}. + */ +public abstract class AbstractJavaAttributeMapping<A extends Annotation> + extends AbstractJavaJpaContextNode + implements JavaAttributeMapping, AttributeMapping2_0 +{ + protected boolean default_; + + + protected AbstractJavaAttributeMapping(JavaPersistentAttribute parent) { + super(parent); + this.default_ = this.buildDefault(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.updateDefault(); + } + + @Override + public void update() { + super.update(); + } + + + // ********** name ********** + + public String getName() { + return this.getPersistentAttribute().getName(); + } + + + // ********** annotation ********** + + @SuppressWarnings("unchecked") + public A getMappingAnnotation() { + return (A) this.getAnnotation_(); + } + + protected Annotation getAnnotation_() { + return this.getResourcePersistentAttribute().getAnnotation(this.getAnnotationName()); + } + + protected abstract String getAnnotationName(); + + /** + * This method should only be called on mappings that can occur by default + * (e.g. <code>Basic</code>, <code>Embedded</code>, <code>OneToOne</code>, + * and <code>OneToMany</code>). + */ + public A getAnnotationForUpdate() { + A annotation = this.getMappingAnnotation(); + if (annotation == null) { + this.getPersistentAttribute().setMappingKey(this.getKey()); + annotation = this.getMappingAnnotation(); + if (annotation == null) { + throw new IllegalStateException("missing annotation: " + this); //$NON-NLS-1$ + } + } + return annotation; + } + + + // ********** default ********** + + public boolean isDefault() { + return this.default_; + } + + protected void setDefault(boolean default_) { + boolean old = this.default_; + this.default_ = default_; + this.firePropertyChanged(DEFAULT_PROPERTY, old, default_); + } + + public void updateDefault() { + this.setDefault(this.buildDefault()); + } + + protected boolean buildDefault() { + return this.getMappingAnnotation() == null; + } + + + // ********** misc ********** + + @Override + public JavaPersistentAttribute getParent() { + return (JavaPersistentAttribute) super.getParent(); + } + + public JavaPersistentAttribute getPersistentAttribute() { + return this.getParent(); + } + + public TypeMapping getTypeMapping() { + return this.getPersistentAttribute().getOwningTypeMapping(); + } + + public JavaResourcePersistentAttribute getResourcePersistentAttribute() { + return this.getPersistentAttribute().getResourcePersistentAttribute(); + } + + public String getPrimaryKeyColumnName() { + return null; + } + + public boolean isOverridableAttributeMapping() { + return false; + } + + public boolean isOverridableAssociationMapping() { + return false; + } + + public boolean isRelationshipOwner() { + return false; + } + + public boolean isOwnedBy(AttributeMapping mapping) { + return false; + } + + public boolean validatesAgainstDatabase() { + return this.getTypeMapping().validatesAgainstDatabase(); + } + + public Table resolveDbTable(String tableName) { + return this.getTypeMapping().resolveDbTable(tableName); + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.getName()); + } + + + // ********** embedded mappings ********** + + public Iterator<String> allMappingNames() { + return new SingleElementIterator<String>(this.getName()); + } + + public Iterator<String> allOverridableAttributeMappingNames() { + return this.isOverridableAttributeMapping() ? + new SingleElementIterator<String>(this.getName()) : + EmptyIterator.<String>instance(); + } + + public Iterator<String> allOverridableAssociationMappingNames() { + return this.isOverridableAssociationMapping() ? + new SingleElementIterator<String>(this.getName()) : + EmptyIterator.<String>instance(); + } + + public Column resolveOverriddenColumn(String attributeName) { + ColumnMapping mapping = this.resolveColumnMapping(attributeName); + return (mapping == null) ? null : mapping.getColumn(); + } + + protected ColumnMapping resolveColumnMapping(String name) { + AttributeMapping mapping = this.resolveAttributeMapping(name); + return ((mapping != null) && mapping.isOverridableAttributeMapping()) ? (ColumnMapping) mapping : null; + } + + public Relationship resolveOverriddenRelationship(String attributeName) { + RelationshipMapping mapping = this.resolveRelationshipMapping(attributeName); + return (mapping == null) ? null : mapping.getRelationship(); + } + + protected RelationshipMapping resolveRelationshipMapping(String name) { + AttributeMapping mapping = this.resolveAttributeMapping(name); + return ((mapping != null) && mapping.isOverridableAssociationMapping()) ? (RelationshipMapping) mapping : null; + } + + public AttributeMapping resolveAttributeMapping(String attributeName) { + return this.getName().equals(attributeName) ? this : null; + } + + protected Transformer<String, String> buildQualifierTransformer() { + return new MappingTools.QualifierTransformer(this.getName()); + } + + protected String unqualify(String attributeName) { + return MappingTools.unqualify(this.getName(), attributeName); + } + + + // ********** metamodel ********** + + public MetamodelField getMetamodelField() { + return new SimpleMetamodelField( + this.getMetamodelFieldModifiers(), + this.getMetamodelFieldTypeName(), + this.getMetamodelFieldTypeArgumentNames(), + this.getMetamodelFieldName() + ); + } + + protected Iterable<String> getMetamodelFieldModifiers() { + return STANDARD_METAMODEL_FIELD_MODIFIERS; + } + + /** + * most mappings are "singular" + */ + protected String getMetamodelFieldTypeName() { + return JPA2_0.SINGULAR_ATTRIBUTE; + } + + protected final Iterable<String> getMetamodelFieldTypeArgumentNames() { + ArrayList<String> typeArgumentNames = new ArrayList<String>(3); + typeArgumentNames.add(this.getTypeMapping().getPersistentType().getName()); + this.addMetamodelFieldTypeArgumentNamesTo(typeArgumentNames); + return typeArgumentNames; + } + + /** + * by default, we add only the mapping's attribute type name; + * but collection relationship mappings will also need to add the key type + * name if the "collection" is of type java.util.Map + */ + protected void addMetamodelFieldTypeArgumentNamesTo(ArrayList<String> typeArgumentNames) { + typeArgumentNames.add(this.getMetamodelTypeName()); + } + + public String getMetamodelTypeName() { + return ((JavaPersistentAttribute2_0) this.getPersistentAttribute()).getMetamodelTypeName(); + } + + protected String getMetamodelFieldName() { + return this.getName(); + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.validateMappingType(messages, astRoot); + } + + protected void validateMappingType(List<IMessage> messages, CompilationUnit astRoot) { + if ( ! this.getTypeMapping().attributeMappingKeyAllowed(this.getKey())) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.PERSISTENT_ATTRIBUTE_INVALID_MAPPING, + new String[] {this.getName()}, + this, + this.getValidationTextRange(astRoot) + ) + ); + } + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + TextRange textRange = this.getMappingAnnotationTextRange(astRoot); + return (textRange != null) ? textRange : this.getParent().getValidationTextRange(astRoot); + } + + protected TextRange getMappingAnnotationTextRange(CompilationUnit astRoot) { + A annotation = this.getMappingAnnotation(); + return (annotation == null) ? null : annotation.getTextRange(astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBaseColumn.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBaseColumn.java new file mode 100644 index 0000000000..5e2dd96aec --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBaseColumn.java @@ -0,0 +1,361 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.iterators.FilteringIterator; +import org.eclipse.jpt.jpa.core.context.ReadOnlyBaseColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaBaseColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; +import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.resource.java.BaseColumnAnnotation; + +/** + * Java column or join column + */ +public abstract class AbstractJavaBaseColumn<A extends BaseColumnAnnotation, O extends JavaBaseColumn.Owner> + extends AbstractJavaNamedColumn<A, O> + implements JavaBaseColumn +{ + protected String specifiedTable; + protected String defaultTable; + + protected Boolean specifiedUnique; + protected boolean defaultUnique; + + protected Boolean specifiedNullable; + protected boolean defaultNullable; + + protected Boolean specifiedInsertable; + protected boolean defaultInsertable; + + protected Boolean specifiedUpdatable; + protected boolean defaultUpdatable; + + + protected AbstractJavaBaseColumn(JavaJpaContextNode parent, O owner) { + this(parent, owner, null); + } + + protected AbstractJavaBaseColumn(JavaJpaContextNode parent, O owner, A columnAnnotation) { + super(parent, owner, columnAnnotation); + this.specifiedTable = this.buildSpecifiedTable(); + this.specifiedUnique = this.buildSpecifiedUnique(); + this.specifiedNullable = this.buildSpecifiedNullable(); + this.specifiedInsertable = this.buildSpecifiedInsertable(); + this.specifiedUpdatable = this.buildSpecifiedUpdatable(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setSpecifiedTable_(this.buildSpecifiedTable()); + this.setSpecifiedUnique_(this.buildSpecifiedUnique()); + this.setSpecifiedNullable_(this.buildSpecifiedNullable()); + this.setSpecifiedInsertable_(this.buildSpecifiedInsertable()); + this.setSpecifiedUpdatable_(this.buildSpecifiedUpdatable()); + } + + @Override + public void update() { + super.update(); + this.setDefaultTable(this.buildDefaultTable()); + this.setDefaultUnique(this.buildDefaultUnique()); + this.setDefaultNullable(this.buildDefaultNullable()); + this.setDefaultInsertable(this.buildDefaultInsertable()); + this.setDefaultUpdatable(this.buildDefaultUpdatable()); + } + + + // ********** table ********** + + @Override + public String getTable() { + return (this.specifiedTable != null) ? this.specifiedTable : this.defaultTable; + } + + public String getSpecifiedTable() { + return this.specifiedTable; + } + + public void setSpecifiedTable(String table) { + if (this.valuesAreDifferent(this.specifiedTable, table)) { + this.getColumnAnnotation().setTable(table); + this.removeColumnAnnotationIfUnset(); + this.setSpecifiedTable_(table); + } + } + + protected void setSpecifiedTable_(String table) { + String old = this.specifiedTable; + this.specifiedTable = table; + this.firePropertyChanged(SPECIFIED_TABLE_PROPERTY, old, table); + } + + protected String buildSpecifiedTable() { + return this.getColumnAnnotation().getTable(); + } + + public String getDefaultTable() { + return this.defaultTable; + } + + protected void setDefaultTable(String table) { + String old = this.defaultTable; + this.defaultTable = table; + this.firePropertyChanged(DEFAULT_TABLE_PROPERTY, old, table); + } + + protected String buildDefaultTable() { + return this.owner.getDefaultTableName(); + } + + public TextRange getTableTextRange(CompilationUnit astRoot) { + TextRange textRange = this.getColumnAnnotation().getTableTextRange(astRoot); + return (textRange != null) ? textRange : this.owner.getValidationTextRange(astRoot); + } + + + // ********** unique ********** + + public boolean isUnique() { + return (this.specifiedUnique != null) ? this.specifiedUnique.booleanValue() : this.isDefaultUnique(); + } + + public Boolean getSpecifiedUnique() { + return this.specifiedUnique; + } + + public void setSpecifiedUnique(Boolean unique) { + if (this.valuesAreDifferent(this.specifiedUnique, unique)) { + this.getColumnAnnotation().setUnique(unique); + this.removeColumnAnnotationIfUnset(); + this.setSpecifiedUnique_(unique); + } + } + + protected void setSpecifiedUnique_(Boolean unique) { + Boolean old = this.specifiedUnique; + this.specifiedUnique = unique; + this.firePropertyChanged(SPECIFIED_UNIQUE_PROPERTY, old, unique); + } + + protected Boolean buildSpecifiedUnique() { + return this.getColumnAnnotation().getUnique(); + } + + public boolean isDefaultUnique() { + return this.defaultUnique; + } + + protected void setDefaultUnique(boolean unique) { + boolean old = this.defaultUnique; + this.defaultUnique = unique; + this.firePropertyChanged(DEFAULT_UNIQUE_PROPERTY, old, unique); + } + + protected boolean buildDefaultUnique() { + return DEFAULT_UNIQUE; + } + + + // ********** nullable ********** + + public boolean isNullable() { + return (this.specifiedNullable != null) ? this.specifiedNullable.booleanValue() : this.isDefaultNullable(); + } + + public Boolean getSpecifiedNullable() { + return this.specifiedNullable; + } + + public void setSpecifiedNullable(Boolean nullable) { + if (this.valuesAreDifferent(this.specifiedNullable, nullable)) { + this.getColumnAnnotation().setNullable(nullable); + this.removeColumnAnnotationIfUnset(); + this.setSpecifiedNullable_(nullable); + } + } + + protected void setSpecifiedNullable_(Boolean nullable) { + Boolean old = this.specifiedNullable; + this.specifiedNullable = nullable; + this.firePropertyChanged(SPECIFIED_NULLABLE_PROPERTY, old, nullable); + } + + protected Boolean buildSpecifiedNullable() { + return this.getColumnAnnotation().getNullable(); + } + + public boolean isDefaultNullable() { + return this.defaultNullable; + } + + protected void setDefaultNullable(boolean nullable) { + boolean old = this.defaultNullable; + this.defaultNullable = nullable; + this.firePropertyChanged(DEFAULT_NULLABLE_PROPERTY, old, nullable); + } + + protected boolean buildDefaultNullable() { + return DEFAULT_NULLABLE; + } + + + // ********** insertable ********** + + public boolean isInsertable() { + return (this.specifiedInsertable != null) ? this.specifiedInsertable.booleanValue() : this.isDefaultInsertable(); + } + + public Boolean getSpecifiedInsertable() { + return this.specifiedInsertable; + } + + public void setSpecifiedInsertable(Boolean insertable) { + if (this.valuesAreDifferent(this.specifiedInsertable, insertable)) { + this.getColumnAnnotation().setInsertable(insertable); + this.removeColumnAnnotationIfUnset(); + this.setSpecifiedInsertable_(insertable); + } + } + + protected void setSpecifiedInsertable_(Boolean insertable) { + Boolean old = this.specifiedInsertable; + this.specifiedInsertable = insertable; + this.firePropertyChanged(SPECIFIED_INSERTABLE_PROPERTY, old, insertable); + } + + protected Boolean buildSpecifiedInsertable() { + return this.getColumnAnnotation().getInsertable(); + } + + public boolean isDefaultInsertable() { + return this.defaultInsertable; + } + + protected void setDefaultInsertable(boolean insertable) { + boolean old = this.defaultInsertable; + this.defaultInsertable = insertable; + this.firePropertyChanged(DEFAULT_INSERTABLE_PROPERTY, old, insertable); + } + + protected boolean buildDefaultInsertable() { + return DEFAULT_INSERTABLE; + } + + + // ********** updatable ********** + + public boolean isUpdatable() { + return (this.specifiedUpdatable != null) ? this.specifiedUpdatable.booleanValue() : this.isDefaultUpdatable(); + } + + public Boolean getSpecifiedUpdatable() { + return this.specifiedUpdatable; + } + + public void setSpecifiedUpdatable(Boolean updatable) { + if (this.valuesAreDifferent(this.specifiedUpdatable, updatable)) { + this.getColumnAnnotation().setUpdatable(updatable); + this.removeColumnAnnotationIfUnset(); + this.setSpecifiedUpdatable_(updatable); + } + } + + protected void setSpecifiedUpdatable_(Boolean updatable) { + Boolean old = this.specifiedUpdatable; + this.specifiedUpdatable = updatable; + this.firePropertyChanged(SPECIFIED_UPDATABLE_PROPERTY, old, updatable); + } + + protected Boolean buildSpecifiedUpdatable() { + return this.getColumnAnnotation().getUpdatable(); + } + + public boolean isDefaultUpdatable() { + return this.defaultUpdatable; + } + + protected void setDefaultUpdatable(boolean updatable) { + boolean old = this.defaultUpdatable; + this.defaultUpdatable = updatable; + this.firePropertyChanged(DEFAULT_UPDATABLE_PROPERTY, old, updatable); + } + + protected boolean buildDefaultUpdatable() { + return DEFAULT_UPDATABLE; + } + + + // ********** misc ********** + + protected void initializeFrom(ReadOnlyBaseColumn oldColumn) { + super.initializeFrom(oldColumn); + this.setSpecifiedTable(oldColumn.getSpecifiedTable()); + this.setSpecifiedUnique(oldColumn.getSpecifiedUnique()); + this.setSpecifiedNullable(oldColumn.getSpecifiedNullable()); + this.setSpecifiedInsertable(oldColumn.getSpecifiedInsertable()); + this.setSpecifiedUpdatable(oldColumn.getSpecifiedUpdatable()); + } + + protected void initializeFromVirtual(ReadOnlyBaseColumn virtualColumn) { + super.initializeFromVirtual(virtualColumn); + this.setSpecifiedTable(virtualColumn.getTable()); + // ignore other settings? + } + + public boolean tableNameIsInvalid() { + return this.owner.tableNameIsInvalid(this.getTable()); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + if (this.tableTouches(pos, astRoot)) { + return this.javaCandidateTableNames(filter); + } + return null; + } + + protected boolean tableTouches(int pos, CompilationUnit astRoot) { + return this.getColumnAnnotation().tableTouches(pos, astRoot); + } + + protected Iterator<String> javaCandidateTableNames(Filter<String> filter) { + return StringTools.convertToJavaStringLiterals(this.candidateTableNames(filter)); + } + + protected Iterator<String> candidateTableNames(Filter<String> filter) { + return new FilteringIterator<String>(this.candidateTableNames(), filter); + } + + public Iterator<String> candidateTableNames() { + return this.owner.candidateTableNames(); + } + + @Override + protected NamedColumnTextRangeResolver buildTextRangeResolver(CompilationUnit astRoot) { + return new JavaBaseColumnTextRangeResolver(this, astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBaseEmbeddedMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBaseEmbeddedMapping.java new file mode 100644 index 0000000000..ea3c1a97e2 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBaseEmbeddedMapping.java @@ -0,0 +1,319 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.Transformer; +import org.eclipse.jpt.common.utility.internal.iterators.CompositeIterator; +import org.eclipse.jpt.common.utility.internal.iterators.EmptyIterator; +import org.eclipse.jpt.common.utility.internal.iterators.TransformationIterator; +import org.eclipse.jpt.jpa.core.context.AttributeMapping; +import org.eclipse.jpt.jpa.core.context.AttributeOverride; +import org.eclipse.jpt.jpa.core.context.AttributeOverrideContainer; +import org.eclipse.jpt.jpa.core.context.BaseColumn; +import org.eclipse.jpt.jpa.core.context.Column; +import org.eclipse.jpt.jpa.core.context.Embeddable; +import org.eclipse.jpt.jpa.core.context.OverrideContainer; +import org.eclipse.jpt.jpa.core.context.Override_; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeOverrideContainer; +import org.eclipse.jpt.jpa.core.context.java.JavaBaseEmbeddedMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.internal.context.AttributeMappingTools; +import org.eclipse.jpt.jpa.core.internal.context.BaseColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.MappingTools; +import org.eclipse.jpt.jpa.core.internal.context.OverrideTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.AttributeOverrideColumnValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.AttributeOverrideValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.EmbeddableOverrideDescriptionProvider; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.EntityTableDescriptionProvider; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.orm.GenericOrmEmbeddedIdMapping; +import org.eclipse.jpt.jpa.core.internal.validation.DefaultJpaValidationMessages; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationMessages; +import org.eclipse.jpt.jpa.core.resource.java.Annotation; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentMember; +import org.eclipse.jpt.jpa.db.Table; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * <code>orm.xml</code> embedded or embedded ID mapping + */ +public abstract class AbstractJavaBaseEmbeddedMapping<A extends Annotation> + extends AbstractJavaAttributeMapping<A> + implements JavaBaseEmbeddedMapping +{ + protected final JavaAttributeOverrideContainer attributeOverrideContainer; + + protected Embeddable targetEmbeddable; + + + protected AbstractJavaBaseEmbeddedMapping(JavaPersistentAttribute parent) { + super(parent); + this.attributeOverrideContainer = this.buildAttributeOverrideContainer(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.attributeOverrideContainer.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + this.attributeOverrideContainer.update(); + this.setTargetEmbeddable(this.buildTargetEmbeddable()); + } + + + // ********** attribute override container ********** + + public JavaAttributeOverrideContainer getAttributeOverrideContainer() { + return this.attributeOverrideContainer; + } + + protected JavaAttributeOverrideContainer buildAttributeOverrideContainer() { + return this.getJpaFactory().buildJavaAttributeOverrideContainer(this, this.buildAttributeOverrideContainerOwner()); + } + + protected JavaAttributeOverrideContainer.Owner buildAttributeOverrideContainerOwner() { + return new AttributeOverrideContainerOwner(); + } + + + // ********** target embeddable ********** + + public Embeddable getTargetEmbeddable() { + return this.targetEmbeddable; + } + + protected void setTargetEmbeddable(Embeddable embeddable) { + Embeddable old = this.targetEmbeddable; + this.targetEmbeddable = embeddable; + this.firePropertyChanged(TARGET_EMBEDDABLE_PROPERTY, old, embeddable); + } + + protected Embeddable buildTargetEmbeddable() { + return this.getPersistentAttribute().getEmbeddable(); + } + + + // ********** embedded mappings ********** + + @Override + public Iterator<String> allOverridableAttributeMappingNames() { + return this.isJpa2_0Compatible() ? + this.embeddableOverridableAttributeMappingNames() : + super.allOverridableAttributeMappingNames(); + } + + protected Iterator<String> embeddableOverridableAttributeMappingNames() { + return this.qualifiedEmbeddableOverridableMappingNames(AttributeMappingTools.ALL_OVERRIDABLE_ATTRIBUTE_MAPPING_NAMES_TRANSFORMER); + } + + @Override + public Iterator<String> allOverridableAssociationMappingNames() { + return this.isJpa2_0Compatible() ? + this.embeddableOverridableAssociationMappingNames() : + super.allOverridableAssociationMappingNames(); + } + + protected Iterator<String> embeddableOverridableAssociationMappingNames() { + return this.qualifiedEmbeddableOverridableMappingNames(AttributeMappingTools.ALL_OVERRIDABLE_ASSOCIATION_MAPPING_NAMES_TRANSFORMER); + } + + protected Iterator<String> qualifiedEmbeddableOverridableMappingNames(Transformer<AttributeMapping, Iterator<String>> transformer) { + return new TransformationIterator<String, String>(this.embeddableAttributeMappingNames(transformer), this.buildQualifierTransformer()); + } + + protected Iterator<String> embeddableAttributeMappingNames(Transformer<AttributeMapping, Iterator<String>> transformer) { + return new CompositeIterator<String>(this.embeddableAttributeMappingNamesLists(transformer)); + } + + /** + * Return a list of lists; each nested list holds the names for one of the + * embedded mapping's target embeddable type mapping's attribute mappings + * (attribute or association mappings, depending on the specified transformer). + */ + protected Iterator<Iterator<String>> embeddableAttributeMappingNamesLists(Transformer<AttributeMapping, Iterator<String>> transformer) { + return new TransformationIterator<AttributeMapping, Iterator<String>>(this.embeddableAttributeMappings(), transformer); + } + + /** + * Return the target embeddable's attribute mappings. + */ + protected Iterator<AttributeMapping> embeddableAttributeMappings() { + return ((this.targetEmbeddable != null) && (this.targetEmbeddable != this.getTypeMapping())) ? + this.targetEmbeddable.attributeMappings() : + EmptyIterator.<AttributeMapping>instance(); + } + + + // ********** misc ********** + + @Override + public Column resolveOverriddenColumn(String attributeName) { + return this.isJpa2_0Compatible() ? this.resolveOverriddenColumn_(attributeName) : null; + } + + protected Column resolveOverriddenColumn_(String attributeName) { + attributeName = this.unqualify(attributeName); + if (attributeName == null) { + return null; + } + AttributeOverride override = this.attributeOverrideContainer.getSpecifiedOverrideNamed(attributeName); + // recurse into the target embeddable if necessary + return (override != null) ? override.getColumn() : this.resolveOverriddenColumnInTargetEmbeddable(attributeName); + } + + protected Column resolveOverriddenColumnInTargetEmbeddable(String attributeName) { + return (this.targetEmbeddable == null) ? null : this.targetEmbeddable.resolveOverriddenColumn(attributeName); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.attributeOverrideContainer.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + return null; + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + + if (this.validateTargetEmbeddable(messages, astRoot)) { + this.validateOverrides(messages, reporter, astRoot); + } + } + + protected boolean validateTargetEmbeddable(List<IMessage> messages, CompilationUnit astRoot) { + if (this.targetEmbeddable != null) { + return true; + } + String targetEmbeddableTypeName = this.getPersistentAttribute().getTypeName(); + // if the type isn't resolvable, there will already be a java compile error + if (targetEmbeddableTypeName != null) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.TARGET_NOT_AN_EMBEDDABLE, + new String[] {targetEmbeddableTypeName}, + this, + this.getValidationTextRange(astRoot) + ) + ); + } + return false; + } + + protected void validateOverrides(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + this.attributeOverrideContainer.validate(messages, reporter, astRoot); + } + + + // ********** attribute override container owner ********* + + protected class AttributeOverrideContainerOwner + implements JavaAttributeOverrideContainer.Owner + { + public JavaResourcePersistentMember getResourcePersistentMember() { + return AbstractJavaBaseEmbeddedMapping.this.getResourcePersistentAttribute(); + } + + public TypeMapping getTypeMapping() { + return AbstractJavaBaseEmbeddedMapping.this.getTypeMapping(); + } + + public TypeMapping getOverridableTypeMapping() { + return AbstractJavaBaseEmbeddedMapping.this.getTargetEmbeddable(); + } + + public Iterator<String> allOverridableNames() { + TypeMapping typeMapping = this.getOverridableTypeMapping(); + return (typeMapping != null) ? this.allOverridableAttributeNames_(typeMapping) : EmptyIterator.<String>instance(); + } + + /** + * pre-condition: type mapping is not <code>null</code> + * <p> + * NB: Overridden in {@link GenericOrmEmbeddedIdMapping.AttributeOverrideContainerOwner} + */ + protected Iterator<String> allOverridableAttributeNames_(TypeMapping typeMapping) { + return typeMapping.allOverridableAttributeNames(); + } + + public Column resolveOverriddenColumn(String attributeName) { + return MappingTools.resolveOverriddenColumn(this.getOverridableTypeMapping(), attributeName); + } + + public boolean tableNameIsInvalid(String tableName) { + return this.getTypeMapping().tableNameIsInvalid(tableName); + } + + public Iterator<String> candidateTableNames() { + return this.getTypeMapping().allAssociatedTableNames(); + } + + public Table resolveDbTable(String tableName) { + return this.getTypeMapping().resolveDbTable(tableName); + } + + public String getDefaultTableName() { + return this.getTypeMapping().getPrimaryTableName(); + } + + public String getPossiblePrefix() { + return null; + } + + public String getWritePrefix() { + return null; + } + + // no maps, so all overrides are relevant + public boolean isRelevant(String overrideName) { + return true; + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return AbstractJavaBaseEmbeddedMapping.this.getValidationTextRange(astRoot); + } + + public JptValidator buildValidator(Override_ override, OverrideContainer container, OverrideTextRangeResolver textRangeResolver) { + return new AttributeOverrideValidator((AttributeOverride) override, (AttributeOverrideContainer) container, textRangeResolver, new EmbeddableOverrideDescriptionProvider()); + } + + public JptValidator buildColumnValidator(Override_ override, BaseColumn column, BaseColumn.Owner owner, BaseColumnTextRangeResolver textRangeResolver) { + return new AttributeOverrideColumnValidator((AttributeOverride) override, column, textRangeResolver, new EntityTableDescriptionProvider()); + } + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBasicMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBasicMapping.java new file mode 100644 index 0000000000..1fa555f9cb --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBasicMapping.java @@ -0,0 +1,383 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.Association; +import org.eclipse.jpt.common.utility.internal.SimpleAssociation; +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.BaseColumn; +import org.eclipse.jpt.jpa.core.context.Converter; +import org.eclipse.jpt.jpa.core.context.FetchType; +import org.eclipse.jpt.jpa.core.context.NamedColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaBasicMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaConverter; +import org.eclipse.jpt.jpa.core.context.java.JavaEnumeratedConverter; +import org.eclipse.jpt.jpa.core.context.java.JavaLobConverter; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.java.JavaTemporalConverter; +import org.eclipse.jpt.jpa.core.internal.context.BaseColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.EntityTableDescriptionProvider; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.NamedColumnValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.NullJavaConverter; +import org.eclipse.jpt.jpa.core.resource.java.Annotation; +import org.eclipse.jpt.jpa.core.resource.java.BasicAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.ColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentAttribute; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java basic mapping + */ +public abstract class AbstractJavaBasicMapping + extends AbstractJavaAttributeMapping<BasicAnnotation> + implements JavaBasicMapping +{ + protected final JavaColumn column; + + protected FetchType specifiedFetch; + protected FetchType defaultFetch; + + protected Boolean specifiedOptional; + protected boolean defaultOptional; + + protected JavaConverter converter; // never null + + + protected static final JavaConverter.Adapter[] CONVERTER_ADAPTER_ARRAY = new JavaConverter.Adapter[] { + JavaEnumeratedConverter.Adapter.instance(), + JavaTemporalConverter.Adapter.instance(), + JavaLobConverter.Adapter.instance() + }; + protected static final Iterable<JavaConverter.Adapter> CONVERTER_ADAPTERS = new ArrayIterable<JavaConverter.Adapter>(CONVERTER_ADAPTER_ARRAY); + + + protected AbstractJavaBasicMapping(JavaPersistentAttribute parent) { + super(parent); + this.column = this.buildColumn(); + this.specifiedFetch = this.buildSpecifiedFetch(); + this.specifiedOptional = this.buildSpecifiedOptional(); + this.converter = this.buildConverter(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.column.synchronizeWithResourceModel(); + this.setSpecifiedFetch_(this.buildSpecifiedFetch()); + this.setSpecifiedOptional_(this.buildSpecifiedOptional()); + this.syncConverter(); + } + + @Override + public void update() { + super.update(); + this.column.update(); + this.setDefaultFetch(this.buildDefaultFetch()); + this.setDefaultOptional(this.buildDefaultOptional()); + this.converter.update(); + } + + + // ********** column ********** + + public JavaColumn getColumn() { + return this.column; + } + + protected JavaColumn buildColumn() { + return this.getJpaFactory().buildJavaColumn(this, this); + } + + + // ********** fetch ********** + + public FetchType getFetch() { + return (this.specifiedFetch != null) ? this.specifiedFetch : this.defaultFetch; + } + + public FetchType getSpecifiedFetch() { + return this.specifiedFetch; + } + + public void setSpecifiedFetch(FetchType fetch) { + if (this.valuesAreDifferent(fetch, this.specifiedFetch)) { + this.getAnnotationForUpdate().setFetch(FetchType.toJavaResourceModel(fetch)); + this.setSpecifiedFetch_(fetch); + } + } + + protected void setSpecifiedFetch_(FetchType fetch) { + FetchType old = this.specifiedFetch; + this.specifiedFetch = fetch; + this.firePropertyChanged(SPECIFIED_FETCH_PROPERTY, old, fetch); + } + + protected FetchType buildSpecifiedFetch() { + BasicAnnotation annotation = this.getMappingAnnotation(); + return (annotation == null) ? null : FetchType.fromJavaResourceModel(annotation.getFetch()); + } + + public FetchType getDefaultFetch() { + return this.defaultFetch; + } + + protected void setDefaultFetch(FetchType fetch) { + FetchType old = this.defaultFetch; + this.defaultFetch = fetch; + this.firePropertyChanged(DEFAULT_FETCH_PROPERTY, old, fetch); + } + + protected FetchType buildDefaultFetch() { + return DEFAULT_FETCH_TYPE; + } + + + // ********** optional ********** + + public boolean isOptional() { + return (this.specifiedOptional != null) ? this.specifiedOptional.booleanValue() : this.isDefaultOptional(); + } + + public Boolean getSpecifiedOptional() { + return this.specifiedOptional; + } + + public void setSpecifiedOptional(Boolean optional) { + if (this.valuesAreDifferent(optional, this.specifiedOptional)) { + this.getAnnotationForUpdate().setOptional(optional); + this.setSpecifiedOptional_(optional); + } + } + + protected void setSpecifiedOptional_(Boolean optional) { + Boolean old = this.specifiedOptional; + this.specifiedOptional = optional; + this.firePropertyChanged(SPECIFIED_OPTIONAL_PROPERTY, old, optional); + } + + protected Boolean buildSpecifiedOptional() { + BasicAnnotation annotation = this.getMappingAnnotation(); + return (annotation == null) ? null : annotation.getOptional(); + } + + public boolean isDefaultOptional() { + return defaultOptional; + } + + protected void setDefaultOptional(boolean optional) { + boolean old = this.defaultOptional; + this.defaultOptional = optional; + this.firePropertyChanged(DEFAULT_OPTIONAL_PROPERTY, old, optional); + } + + protected boolean buildDefaultOptional() { + return DEFAULT_OPTIONAL; + } + + + // ********** converter ********** + + public JavaConverter getConverter() { + return this.converter; + } + + public void setConverter(Class<? extends Converter> converterType) { + if (this.converter.getType() != converterType) { + this.converter.dispose(); + JavaConverter.Adapter converterAdapter = this.getConverterAdapter(converterType); + this.retainConverterAnnotation(converterAdapter); + this.setConverter_(this.buildConverter(converterAdapter)); + } + } + + protected JavaConverter buildConverter(JavaConverter.Adapter converterAdapter) { + return (converterAdapter != null) ? + converterAdapter.buildNewConverter(this, this.getJpaFactory()) : + this.buildNullConverter(); + } + + protected void setConverter_(JavaConverter converter) { + Converter old = this.converter; + this.converter = converter; + this.firePropertyChanged(CONVERTER_PROPERTY, old, converter); + } + + /** + * Clear all the converter annotations <em>except</em> for the annotation + * corresponding to the specified adapter. If the specified adapter is + * <code>null</code>, remove <em>all</em> the converter annotations. + */ + protected void retainConverterAnnotation(JavaConverter.Adapter converterAdapter) { + JavaResourcePersistentAttribute resourceAttribute = this.getResourcePersistentAttribute(); + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + if (adapter != converterAdapter) { + adapter.removeConverterAnnotation(resourceAttribute); + } + } + } + + protected JavaConverter buildConverter() { + JpaFactory jpaFactory = this.getJpaFactory(); + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + JavaConverter javaConverter = adapter.buildConverter(this, jpaFactory); + if (javaConverter != null) { + return javaConverter; + } + } + return this.buildNullConverter(); + } + + protected void syncConverter() { + Association<JavaConverter.Adapter, Annotation> assoc = this.getConverterAnnotation(); + if (assoc == null) { + if (this.converter.getType() != null) { + this.setConverter_(this.buildNullConverter()); + } + } else { + JavaConverter.Adapter adapter = assoc.getKey(); + Annotation annotation = assoc.getValue(); + if ((this.converter.getType() == adapter.getConverterType()) && + (this.converter.getConverterAnnotation() == annotation)) { + this.converter.synchronizeWithResourceModel(); + } else { + this.setConverter_(adapter.buildConverter(annotation, this, this.getJpaFactory())); + } + } + } + + /** + * Return the first converter annotation we find along with its corresponding + * adapter. Return <code>null</code> if there are no converter annotations. + */ + protected Association<JavaConverter.Adapter, Annotation> getConverterAnnotation() { + JavaResourcePersistentAttribute resourceAttribute = this.getResourcePersistentAttribute(); + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + Annotation annotation = adapter.getConverterAnnotation(resourceAttribute); + if (annotation != null) { + return new SimpleAssociation<JavaConverter.Adapter, Annotation>(adapter, annotation); + } + } + return null; + } + + protected JavaConverter buildNullConverter() { + return new NullJavaConverter(this); + } + + + // ********** converter adapters ********** + + /** + * Return the converter adapter for the specified converter type. + */ + protected JavaConverter.Adapter getConverterAdapter(Class<? extends Converter> converterType) { + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + if (adapter.getConverterType() == converterType) { + return adapter; + } + } + return null; + } + + protected Iterable<JavaConverter.Adapter> getConverterAdapters() { + return CONVERTER_ADAPTERS; + } + + + // ********** misc ********** + + public String getKey() { + return MappingKeys.BASIC_ATTRIBUTE_MAPPING_KEY; + } + + @Override + protected String getAnnotationName() { + return BasicAnnotation.ANNOTATION_NAME; + } + + @Override + public boolean isOverridableAttributeMapping() { + return true; + } + + + // ********** JavaColumn.Owner implementation ********** + + public ColumnAnnotation getColumnAnnotation() { + return (ColumnAnnotation) this.getResourcePersistentAttribute().getNonNullAnnotation(ColumnAnnotation.ANNOTATION_NAME); + } + + public void removeColumnAnnotation() { + this.getResourcePersistentAttribute().removeAnnotation(ColumnAnnotation.ANNOTATION_NAME); + } + + public String getDefaultColumnName() { + return this.getName(); + } + + public String getDefaultTableName() { + return this.getTypeMapping().getPrimaryTableName(); + } + + public boolean tableNameIsInvalid(String tableName) { + return this.getTypeMapping().tableNameIsInvalid(tableName); + } + + public Iterator<String> candidateTableNames() { + return this.getTypeMapping().allAssociatedTableNames(); + } + + public JptValidator buildColumnValidator(NamedColumn column, NamedColumnTextRangeResolver textRangeResolver) { + return new NamedColumnValidator((BaseColumn) column, (BaseColumnTextRangeResolver) textRangeResolver, new EntityTableDescriptionProvider()); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + result = this.column.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + result = this.converter.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + return null; + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.column.validate(messages, reporter, astRoot); + this.converter.validate(messages, reporter, astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBasicMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBasicMappingDefinition.java new file mode 100644 index 0000000000..e9db78d75f --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaBasicMappingDefinition.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.DefaultJavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.BasicAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.ColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.EnumeratedAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.LobAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.TemporalAnnotation; + +public abstract class AbstractJavaBasicMappingDefinition + implements DefaultJavaAttributeMappingDefinition +{ + protected AbstractJavaBasicMappingDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.BASIC_ATTRIBUTE_MAPPING_KEY; + } + + public String getAnnotationName() { + return BasicAnnotation.ANNOTATION_NAME; + } + + public boolean isSpecified(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.getResourcePersistentAttribute().getAnnotation(this.getAnnotationName()) != null; + } + + public Iterable<String> getSupportingAnnotationNames() { + return SUPPORTING_ANNOTATION_NAMES; + } + + protected static final String[] SUPPORTING_ANNOTATION_NAMES_ARRAY = new String[] { + ColumnAnnotation.ANNOTATION_NAME, + LobAnnotation.ANNOTATION_NAME, + TemporalAnnotation.ANNOTATION_NAME, + EnumeratedAnnotation.ANNOTATION_NAME + }; + protected static final Iterable<String> SUPPORTING_ANNOTATION_NAMES = new ArrayIterable<String>(SUPPORTING_ANNOTATION_NAMES_ARRAY); + + public JavaAttributeMapping buildMapping(JavaPersistentAttribute persistentAttribute, JpaFactory factory) { + return factory.buildJavaBasicMapping(persistentAttribute); + } + + public boolean isDefault(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.typeIsBasic(); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaEmbeddable.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaEmbeddable.java new file mode 100644 index 0000000000..991d67b0d2 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaEmbeddable.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaEmbeddable; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType; +import org.eclipse.jpt.jpa.core.resource.java.EmbeddableAnnotation; + +/** + * Java embeddable type mapping + */ +public abstract class AbstractJavaEmbeddable + extends AbstractJavaTypeMapping<EmbeddableAnnotation> + implements JavaEmbeddable +{ + protected AbstractJavaEmbeddable(JavaPersistentType parent, EmbeddableAnnotation mappingAnnotation) { + super(parent, mappingAnnotation); + } + + public String getKey() { + return MappingKeys.EMBEDDABLE_TYPE_MAPPING_KEY; + } + + public JavaPersistentType getIdClass() { + return null; + } + + public boolean isMapped() { + return true; + } + + public boolean tableNameIsInvalid(String tableName) { + return false; + } + + @Override + public boolean validatesAgainstDatabase() { + return false; + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaEmbeddedMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaEmbeddedMappingDefinition.java new file mode 100644 index 0000000000..4460a740a3 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaEmbeddedMappingDefinition.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.DefaultJavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.AttributeOverrideAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.AttributeOverridesAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.EmbeddedAnnotation; + +public abstract class AbstractJavaEmbeddedMappingDefinition + implements DefaultJavaAttributeMappingDefinition +{ + protected AbstractJavaEmbeddedMappingDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.EMBEDDED_ATTRIBUTE_MAPPING_KEY; + } + + public String getAnnotationName() { + return EmbeddedAnnotation.ANNOTATION_NAME; + } + + public boolean isSpecified(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.getResourcePersistentAttribute().getAnnotation(this.getAnnotationName()) != null; + } + + public Iterable<String> getSupportingAnnotationNames() { + return SUPPORTING_ANNOTATION_NAMES; + } + + protected static final String[] SUPPORTING_ANNOTATION_NAMES_ARRAY = new String[] { + AttributeOverrideAnnotation.ANNOTATION_NAME, + AttributeOverridesAnnotation.ANNOTATION_NAME, + }; + protected static final Iterable<String> SUPPORTING_ANNOTATION_NAMES = new ArrayIterable<String>(SUPPORTING_ANNOTATION_NAMES_ARRAY); + + public JavaAttributeMapping buildMapping(JavaPersistentAttribute persistentAttribute, JpaFactory factory) { + return factory.buildJavaEmbeddedMapping(persistentAttribute); + } + + public boolean isDefault(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.getEmbeddable() != null; + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaEntity.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaEntity.java new file mode 100644 index 0000000000..11157f3cb5 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaEntity.java @@ -0,0 +1,1816 @@ +/******************************************************************************* + * Copyright (c) 2006, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Vector; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.HashBag; +import org.eclipse.jpt.common.utility.internal.NotNullFilter; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.Tools; +import org.eclipse.jpt.common.utility.internal.iterables.CompositeIterable; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.FilteringIterable; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.SingleElementListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.SubIterableWrapper; +import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable; +import org.eclipse.jpt.common.utility.internal.iterators.CompositeIterator; +import org.eclipse.jpt.common.utility.internal.iterators.EmptyIterator; +import org.eclipse.jpt.common.utility.internal.iterators.FilteringIterator; +import org.eclipse.jpt.common.utility.internal.iterators.TransformationIterator; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.JpaPlatformVariation.Supported; +import org.eclipse.jpt.jpa.core.context.AssociationOverride; +import org.eclipse.jpt.jpa.core.context.AssociationOverrideContainer; +import org.eclipse.jpt.jpa.core.context.AttributeMapping; +import org.eclipse.jpt.jpa.core.context.AttributeOverride; +import org.eclipse.jpt.jpa.core.context.AttributeOverrideContainer; +import org.eclipse.jpt.jpa.core.context.BaseColumn; +import org.eclipse.jpt.jpa.core.context.BaseJoinColumn; +import org.eclipse.jpt.jpa.core.context.Column; +import org.eclipse.jpt.jpa.core.context.DiscriminatorColumn; +import org.eclipse.jpt.jpa.core.context.DiscriminatorType; +import org.eclipse.jpt.jpa.core.context.Entity; +import org.eclipse.jpt.jpa.core.context.InheritanceType; +import org.eclipse.jpt.jpa.core.context.JoinColumn; +import org.eclipse.jpt.jpa.core.context.JoinTable; +import org.eclipse.jpt.jpa.core.context.NamedColumn; +import org.eclipse.jpt.jpa.core.context.OverrideContainer; +import org.eclipse.jpt.jpa.core.context.Override_; +import org.eclipse.jpt.jpa.core.context.PersistentAttribute; +import org.eclipse.jpt.jpa.core.context.PersistentType; +import org.eclipse.jpt.jpa.core.context.PrimaryKeyJoinColumn; +import org.eclipse.jpt.jpa.core.context.ReadOnlyBaseJoinColumn; +import org.eclipse.jpt.jpa.core.context.ReadOnlyTable; +import org.eclipse.jpt.jpa.core.context.Relationship; +import org.eclipse.jpt.jpa.core.context.SecondaryTable; +import org.eclipse.jpt.jpa.core.context.Table; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.JoinColumn.Owner; +import org.eclipse.jpt.jpa.core.context.java.JavaAssociationOverrideContainer; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeOverrideContainer; +import org.eclipse.jpt.jpa.core.context.java.JavaBaseJoinColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaDiscriminatorColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaEntity; +import org.eclipse.jpt.jpa.core.context.java.JavaGeneratorContainer; +import org.eclipse.jpt.jpa.core.context.java.JavaIdClassReference; +import org.eclipse.jpt.jpa.core.context.java.JavaNamedColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaOverrideContainer; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType; +import org.eclipse.jpt.jpa.core.context.java.JavaPrimaryKeyJoinColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaQueryContainer; +import org.eclipse.jpt.jpa.core.context.java.JavaSecondaryTable; +import org.eclipse.jpt.jpa.core.context.java.JavaTable; +import org.eclipse.jpt.jpa.core.context.java.JavaTypeMapping; +import org.eclipse.jpt.jpa.core.internal.context.BaseColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.BaseJoinColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.ContextContainerTools; +import org.eclipse.jpt.jpa.core.internal.context.EntityTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.JoinColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.MappingTools; +import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.OverrideTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.TableTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.TypeMappingTools; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.AssociationOverrideInverseJoinColumnValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.AssociationOverrideJoinColumnValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.AssociationOverrideJoinTableValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.AssociationOverrideValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.AttributeOverrideColumnValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.AttributeOverrideValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.DiscriminatorColumnValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.EntityPrimaryKeyJoinColumnValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.EntityTableDescriptionProvider; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.GenericEntityPrimaryKeyValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.JoinTableTableDescriptionProvider; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.MappedSuperclassOverrideDescriptionProvider; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.SecondaryTableValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.TableValidator; +import org.eclipse.jpt.jpa.core.internal.resource.java.NullPrimaryKeyJoinColumnAnnotation; +import org.eclipse.jpt.jpa.core.internal.validation.DefaultJpaValidationMessages; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationMessages; +import org.eclipse.jpt.jpa.core.jpa2.context.SingleRelationshipMapping2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaCacheableHolder2_0; +import org.eclipse.jpt.jpa.core.resource.java.DiscriminatorValueAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.EntityAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.InheritanceAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentMember; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentType; +import org.eclipse.jpt.jpa.core.resource.java.NestableAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.PrimaryKeyJoinColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.PrimaryKeyJoinColumnsAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.SecondaryTableAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.SecondaryTablesAnnotation; +import org.eclipse.jpt.jpa.db.Schema; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java entity + */ +public abstract class AbstractJavaEntity + extends AbstractJavaTypeMapping<EntityAnnotation> + implements JavaEntity, JavaCacheableHolder2_0, JavaGeneratorContainer.Owner, JavaQueryContainer.Owner +{ + protected String specifiedName; + protected String defaultName; + + protected Entity rootEntity; + protected final Vector<Entity> descendants = new Vector<Entity>(); + + protected final JavaIdClassReference idClassReference; + + protected final JavaTable table; + protected boolean specifiedTableIsAllowed; + protected boolean tableIsUndefined; + + protected final Vector<JavaSecondaryTable> specifiedSecondaryTables = new Vector<JavaSecondaryTable>(); + protected final SpecifiedSecondaryTableContainerAdapter specifiedSecondaryTableContainerAdapter = new SpecifiedSecondaryTableContainerAdapter(); + protected final Table.Owner specifiedSecondaryTableOwner; + + protected final PrimaryKeyJoinColumnOwner primaryKeyJoinColumnOwner; + protected final Vector<JavaPrimaryKeyJoinColumn> specifiedPrimaryKeyJoinColumns = new Vector<JavaPrimaryKeyJoinColumn>(); + protected final SpecifiedPrimaryKeyJoinColumnContainerAdapter specifiedPrimaryKeyJoinColumnContainerAdapter = new SpecifiedPrimaryKeyJoinColumnContainerAdapter(); + protected JavaPrimaryKeyJoinColumn defaultPrimaryKeyJoinColumn; + + protected InheritanceType specifiedInheritanceStrategy; + protected InheritanceType defaultInheritanceStrategy; + + protected String specifiedDiscriminatorValue; + protected String defaultDiscriminatorValue; + protected boolean specifiedDiscriminatorValueIsAllowed; + protected boolean discriminatorValueIsUndefined; + + protected final JavaDiscriminatorColumn discriminatorColumn; + protected boolean specifiedDiscriminatorColumnIsAllowed; + protected boolean discriminatorColumnIsUndefined; + + protected final JavaAttributeOverrideContainer attributeOverrideContainer; + protected final JavaAssociationOverrideContainer associationOverrideContainer; + + protected final JavaGeneratorContainer generatorContainer; + protected final JavaQueryContainer queryContainer; + + + // ********** construction ********** + + protected AbstractJavaEntity(JavaPersistentType parent, EntityAnnotation mappingAnnotation) { + super(parent, mappingAnnotation); + this.specifiedName = this.mappingAnnotation.getName(); + this.idClassReference = this.buildIdClassReference(); + this.table = this.buildTable(); + this.specifiedSecondaryTableOwner = this.buildSpecifiedSecondaryTableOwner(); + this.initializeSpecifiedSecondaryTables(); + this.primaryKeyJoinColumnOwner = this.buildPrimaryKeyJoinColumnOwner(); + this.initializeSpecifiedPrimaryKeyJoinColumns(); + this.specifiedInheritanceStrategy = this.buildSpecifiedInheritanceStrategy(); + this.specifiedDiscriminatorValue = this.getDiscriminatorValueAnnotation().getValue(); + this.discriminatorColumn = this.buildDiscriminatorColumn(); + // start with the entity as the root - it will be recalculated in update() + this.rootEntity = this; + this.attributeOverrideContainer = this.buildAttributeOverrideContainer(); + this.associationOverrideContainer = this.buildAssociationOverrideContainer(); + this.generatorContainer = this.buildGeneratorContainer(); + this.queryContainer = this.buildQueryContainer(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setSpecifiedName_(this.mappingAnnotation.getName()); + this.idClassReference.synchronizeWithResourceModel(); + this.table.synchronizeWithResourceModel(); + this.syncSpecifiedSecondaryTables(); + this.syncSpecifiedPrimaryKeyJoinColumns(); + this.setSpecifiedInheritanceStrategy_(this.buildSpecifiedInheritanceStrategy()); + this.setSpecifiedDiscriminatorValue_(this.getDiscriminatorValueAnnotation().getValue()); + this.discriminatorColumn.synchronizeWithResourceModel(); + this.attributeOverrideContainer.synchronizeWithResourceModel(); + this.associationOverrideContainer.synchronizeWithResourceModel(); + this.generatorContainer.synchronizeWithResourceModel(); + this.queryContainer.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + + this.setDefaultName(this.buildDefaultName()); + + // calculate root entity early - other things depend on it + this.setRootEntity(this.buildRootEntity()); + this.updateDescendants(); + + this.idClassReference.update(); + + this.table.update(); + this.setSpecifiedTableIsAllowed(this.buildSpecifiedTableIsAllowed()); + this.setTableIsUndefined(this.buildTableIsUndefined()); + + this.updateNodes(this.getSecondaryTables()); + + this.updateDefaultPrimaryKeyJoinColumn(); + this.updateNodes(this.getPrimaryKeyJoinColumns()); + + this.setDefaultInheritanceStrategy(this.buildDefaultInheritanceStrategy()); + + this.setDefaultDiscriminatorValue(this.buildDefaultDiscriminatorValue()); + this.setSpecifiedDiscriminatorValueIsAllowed(this.buildSpecifiedDiscriminatorValueIsAllowed()); + this.setDiscriminatorValueIsUndefined(this.buildDiscriminatorValueIsUndefined()); + + this.discriminatorColumn.update(); + this.setSpecifiedDiscriminatorColumnIsAllowed(this.buildSpecifiedDiscriminatorColumnIsAllowed()); + this.setDiscriminatorColumnIsUndefined(this.buildDiscriminatorColumnIsUndefined()); + + this.attributeOverrideContainer.update(); + this.associationOverrideContainer.update(); + + this.generatorContainer.update(); + this.queryContainer.update(); + } + + + // ********** name ********** + + @Override + public String getName() { + return (this.specifiedName != null) ? this.specifiedName : this.defaultName; + } + + public String getSpecifiedName() { + return this.specifiedName; + } + + public void setSpecifiedName(String name) { + this.mappingAnnotation.setName(name); + this.setSpecifiedName_(name); + } + + protected void setSpecifiedName_(String name) { + String old = this.specifiedName; + this.specifiedName = name; + this.firePropertyChanged(SPECIFIED_NAME_PROPERTY, old, name); + } + + public String getDefaultName() { + return this.defaultName; + } + + protected void setDefaultName(String name) { + String old = this.defaultName; + this.defaultName = name; + this.firePropertyChanged(DEFAULT_NAME_PROPERTY, old, name); + } + + protected String buildDefaultName() { + return this.getResourcePersistentType().getName(); + } + + + // ********** root entity ********** + + public Entity getRootEntity() { + return this.rootEntity; + } + + protected void setRootEntity(Entity entity) { + Entity old = this.rootEntity; + this.rootEntity = entity; + this.firePropertyChanged(ROOT_ENTITY_PROPERTY, old, entity); + } + + protected Entity buildRootEntity() { + Entity root = this; + for (TypeMapping typeMapping : this.getAncestors()) { + if (typeMapping instanceof Entity) { + root = (Entity) typeMapping; + } + } + return root; + } + + + // ********** descendants ********** + + public Iterable<Entity> getDescendants() { + return new LiveCloneListIterable<Entity>(this.descendants); + } + + protected void updateDescendants() { + this.synchronizeCollection(this.buildDescendants(), this.descendants, DESCENDANTS_COLLECTION); + } + + protected Iterable<Entity> buildDescendants() { + return new FilteringIterable<Entity>(this.getPersistenceUnit().getEntities()) { + @Override + protected boolean accept(Entity entity) { + return AbstractJavaEntity.this.entityIsDescendant(entity); + } + }; + } + + /** + * Return whether specified entity is a descendant of the entity. + */ + protected boolean entityIsDescendant(Entity entity) { + String typeName = this.getPersistentType().getName(); + String entityTypeName = entity.getPersistentType().getName(); + String rootEntityTypeName = entity.getRootEntity().getPersistentType().getName(); + return Tools.valuesAreDifferent(typeName, entityTypeName) && + Tools.valuesAreEqual(typeName, rootEntityTypeName); + } + + + // ********** id class ********** + + public JavaIdClassReference getIdClassReference() { + return this.idClassReference; + } + + protected JavaIdClassReference buildIdClassReference() { + return new GenericJavaIdClassReference(this); + } + + public JavaPersistentType getIdClass() { + return this.idClassReference.getIdClass(); + } + + + // ********** table ********** + + public JavaTable getTable() { + return this.table; + } + + protected JavaTable buildTable() { + return this.getJpaFactory().buildJavaTable(this, this.buildTableOwner()); + } + + protected JavaTable.Owner buildTableOwner() { + return new TableOwner(); + } + + public boolean specifiedTableIsAllowed() { + return this.specifiedTableIsAllowed; + } + + protected void setSpecifiedTableIsAllowed(boolean specifiedTableIsAllowed) { + boolean old = this.specifiedTableIsAllowed; + this.specifiedTableIsAllowed = specifiedTableIsAllowed; + this.firePropertyChanged(SPECIFIED_TABLE_IS_ALLOWED_PROPERTY, old, specifiedTableIsAllowed); + } + + protected boolean buildSpecifiedTableIsAllowed() { + return ! this.isAbstractTablePerClass() && ! this.isSingleTableDescendant(); + } + + public boolean tableIsUndefined() { + return this.tableIsUndefined; + } + + protected void setTableIsUndefined(boolean tableIsUndefined) { + boolean old = this.tableIsUndefined; + this.tableIsUndefined = tableIsUndefined; + this.firePropertyChanged(TABLE_IS_UNDEFINED_PROPERTY, old, tableIsUndefined); + } + + protected boolean buildTableIsUndefined() { + return this.isAbstractTablePerClass(); + } + + /** + * <ul> + * <li>If the entity is part of a single table inheritance hierarchy, the table + * name defaults to the root entity's table name. + * <li>If the entity is abstract and part of a table per class + * inheritance hierarchy, the table name defaults to null, as no table applies. + * <li>Otherwise, the table name defaults to the entity name. + * </ul> + */ + public String getDefaultTableName() { + return this.isSingleTableDescendant() ? + this.rootEntity.getTable().getName() : + this.isAbstractTablePerClass() ? null : this.getName(); + } + + /** + * @see #getDefaultTableName() + */ + public String getDefaultSchema() { + return this.isSingleTableDescendant() ? + this.rootEntity.getTable().getSchema() : + this.isAbstractTablePerClass() ? null : this.getContextDefaultSchema(); + } + + /** + * @see #getDefaultTableName() + */ + public String getDefaultCatalog() { + return this.isSingleTableDescendant() ? + this.rootEntity.getTable().getCatalog() : + this.isAbstractTablePerClass() ? null : this.getContextDefaultCatalog(); + } + + + // ********** secondary tables ********** + + public ListIterator<JavaSecondaryTable> secondaryTables() { + return this.specifiedSecondaryTables(); + } + + protected ListIterable<JavaSecondaryTable> getSecondaryTables() { + return this.getSpecifiedSecondaryTables(); + } + + public int secondaryTablesSize() { + return this.specifiedSecondaryTablesSize(); + } + + + // ********** specified secondary tables ********** + + public ListIterator<JavaSecondaryTable> specifiedSecondaryTables() { + return this.getSpecifiedSecondaryTables().iterator(); + } + + protected ListIterable<JavaSecondaryTable> getSpecifiedSecondaryTables() { + return new LiveCloneListIterable<JavaSecondaryTable>(this.specifiedSecondaryTables); + } + + public int specifiedSecondaryTablesSize() { + return this.specifiedSecondaryTables.size(); + } + + public JavaSecondaryTable addSpecifiedSecondaryTable() { + return this.addSpecifiedSecondaryTable(this.specifiedSecondaryTables.size()); + } + + public JavaSecondaryTable addSpecifiedSecondaryTable(int index) { + SecondaryTableAnnotation annotation = this.buildSecondaryTableAnnotation(index); + return this.addSpecifiedSecondaryTable_(index, annotation); + } + + protected SecondaryTableAnnotation buildSecondaryTableAnnotation(int index) { + return (SecondaryTableAnnotation) this.getResourcePersistentType().addAnnotation(index, SecondaryTableAnnotation.ANNOTATION_NAME, SecondaryTablesAnnotation.ANNOTATION_NAME); + } + + public void removeSpecifiedSecondaryTable(SecondaryTable secondaryTable) { + this.removeSpecifiedSecondaryTable(this.specifiedSecondaryTables.indexOf(secondaryTable)); + } + + public void removeSpecifiedSecondaryTable(int index) { + this.getResourcePersistentType().removeAnnotation(index, SecondaryTableAnnotation.ANNOTATION_NAME, SecondaryTablesAnnotation.ANNOTATION_NAME); + this.removeSpecifiedSecondaryTable_(index); + } + + protected void removeSpecifiedSecondaryTable_(int index) { + this.removeItemFromList(index, this.specifiedSecondaryTables, SPECIFIED_SECONDARY_TABLES_LIST); + } + + public void moveSpecifiedSecondaryTable(int targetIndex, int sourceIndex) { + this.getResourceAnnotatedElement().moveAnnotation(targetIndex, sourceIndex, SecondaryTablesAnnotation.ANNOTATION_NAME); + this.moveItemInList(targetIndex, sourceIndex, this.specifiedSecondaryTables, SPECIFIED_SECONDARY_TABLES_LIST); + } + + protected void initializeSpecifiedSecondaryTables() { + for (SecondaryTableAnnotation annotation : this.getSecondaryTableAnnotations()) { + this.specifiedSecondaryTables.add(this.buildSecondaryTable(annotation)); + } + } + + protected JavaSecondaryTable buildSecondaryTable(SecondaryTableAnnotation secondaryTableAnnotation) { + return this.getJpaFactory().buildJavaSecondaryTable(this, this.specifiedSecondaryTableOwner, secondaryTableAnnotation); + } + + protected void syncSpecifiedSecondaryTables() { + ContextContainerTools.synchronizeWithResourceModel(this.specifiedSecondaryTableContainerAdapter); + } + + protected Iterable<SecondaryTableAnnotation> getSecondaryTableAnnotations() { + return new SubIterableWrapper<NestableAnnotation, SecondaryTableAnnotation>( + CollectionTools.iterable(this.secondaryTableAnnotations()) + ); + } + + protected Iterator<NestableAnnotation> secondaryTableAnnotations() { + return this.getResourceAnnotatedElement().annotations(SecondaryTableAnnotation.ANNOTATION_NAME, SecondaryTablesAnnotation.ANNOTATION_NAME); + } + + protected void moveSpecifiedSecondaryTable_(int index, JavaSecondaryTable secondaryTable) { + this.moveItemInList(index, secondaryTable, this.specifiedSecondaryTables, SPECIFIED_SECONDARY_TABLES_LIST); + } + + protected JavaSecondaryTable addSpecifiedSecondaryTable_(int index, SecondaryTableAnnotation secondaryTableAnnotation) { + JavaSecondaryTable secondaryTable = this.buildSecondaryTable(secondaryTableAnnotation); + this.addItemToList(index, secondaryTable, this.specifiedSecondaryTables, SPECIFIED_SECONDARY_TABLES_LIST); + return secondaryTable; + } + + protected void removeSpecifiedSecondaryTable_(JavaSecondaryTable secondaryTable) { + this.removeSpecifiedSecondaryTable_(this.specifiedSecondaryTables.indexOf(secondaryTable)); + } + + /** + * specified secondary table container adapter + */ + protected class SpecifiedSecondaryTableContainerAdapter + implements ContextContainerTools.Adapter<JavaSecondaryTable, SecondaryTableAnnotation> + { + public Iterable<JavaSecondaryTable> getContextElements() { + return AbstractJavaEntity.this.getSpecifiedSecondaryTables(); + } + public Iterable<SecondaryTableAnnotation> getResourceElements() { + return AbstractJavaEntity.this.getSecondaryTableAnnotations(); + } + public SecondaryTableAnnotation getResourceElement(JavaSecondaryTable contextElement) { + return contextElement.getTableAnnotation(); + } + public void moveContextElement(int index, JavaSecondaryTable element) { + AbstractJavaEntity.this.moveSpecifiedSecondaryTable_(index, element); + } + public void addContextElement(int index, SecondaryTableAnnotation resourceElement) { + AbstractJavaEntity.this.addSpecifiedSecondaryTable_(index, resourceElement); + } + public void removeContextElement(JavaSecondaryTable element) { + AbstractJavaEntity.this.removeSpecifiedSecondaryTable_(element); + } + } + + protected Table.Owner buildSpecifiedSecondaryTableOwner() { + return new SecondaryTableOwner(); + } + + + // ********** primary key join columns ********** + + public ListIterator<JavaPrimaryKeyJoinColumn> primaryKeyJoinColumns() { + return this.getPrimaryKeyJoinColumns().iterator(); + } + + protected ListIterable<JavaPrimaryKeyJoinColumn> getPrimaryKeyJoinColumns() { + return this.hasSpecifiedPrimaryKeyJoinColumns() ? this.getSpecifiedPrimaryKeyJoinColumns() : this.getDefaultPrimaryKeyJoinColumns(); + } + + public int primaryKeyJoinColumnsSize() { + return this.hasSpecifiedPrimaryKeyJoinColumns() ? this.specifiedPrimaryKeyJoinColumnsSize() : this.defaultPrimaryKeyJoinColumnsSize(); + } + + + // ********** specified primary key join columns ********** + + public ListIterator<JavaPrimaryKeyJoinColumn> specifiedPrimaryKeyJoinColumns() { + return this.getSpecifiedPrimaryKeyJoinColumns().iterator(); + } + + protected ListIterable<JavaPrimaryKeyJoinColumn> getSpecifiedPrimaryKeyJoinColumns() { + return new LiveCloneListIterable<JavaPrimaryKeyJoinColumn>(this.specifiedPrimaryKeyJoinColumns); + } + + public int specifiedPrimaryKeyJoinColumnsSize() { + return this.specifiedPrimaryKeyJoinColumns.size(); + } + + protected boolean hasSpecifiedPrimaryKeyJoinColumns() { + return this.specifiedPrimaryKeyJoinColumns.size() != 0; + } + + public JavaPrimaryKeyJoinColumn addSpecifiedPrimaryKeyJoinColumn() { + return this.addSpecifiedPrimaryKeyJoinColumn(this.specifiedPrimaryKeyJoinColumns.size()); + } + + public JavaPrimaryKeyJoinColumn addSpecifiedPrimaryKeyJoinColumn(int index) { + PrimaryKeyJoinColumnAnnotation annotation = this.buildPrimaryKeyJoinColumnAnnotation(index); + return this.addSpecifiedPrimaryKeyJoinColumn_(index, annotation); + } + + protected PrimaryKeyJoinColumnAnnotation buildPrimaryKeyJoinColumnAnnotation(int index) { + return (PrimaryKeyJoinColumnAnnotation) this.getResourcePersistentType().addAnnotation(index, PrimaryKeyJoinColumnAnnotation.ANNOTATION_NAME, PrimaryKeyJoinColumnsAnnotation.ANNOTATION_NAME); + } + + public void removeSpecifiedPrimaryKeyJoinColumn(PrimaryKeyJoinColumn primaryKeyJoinColumn) { + this.removeSpecifiedPrimaryKeyJoinColumn(this.specifiedPrimaryKeyJoinColumns.indexOf(primaryKeyJoinColumn)); + } + + public void removeSpecifiedPrimaryKeyJoinColumn(int index) { + this.getResourcePersistentType().removeAnnotation(index, PrimaryKeyJoinColumnAnnotation.ANNOTATION_NAME, PrimaryKeyJoinColumnsAnnotation.ANNOTATION_NAME); + this.removeSpecifiedPrimaryKeyJoinColumn_(index); + } + + protected void removeSpecifiedPrimaryKeyJoinColumn_(int index) { + this.removeItemFromList(index, this.specifiedPrimaryKeyJoinColumns, SPECIFIED_PRIMARY_KEY_JOIN_COLUMNS_LIST); + } + + public void moveSpecifiedPrimaryKeyJoinColumn(int targetIndex, int sourceIndex) { + this.getResourcePersistentType().moveAnnotation(targetIndex, sourceIndex, PrimaryKeyJoinColumnsAnnotation.ANNOTATION_NAME); + this.moveItemInList(targetIndex, sourceIndex, this.specifiedPrimaryKeyJoinColumns, SPECIFIED_PRIMARY_KEY_JOIN_COLUMNS_LIST); + } + + protected PrimaryKeyJoinColumnOwner buildPrimaryKeyJoinColumnOwner() { + return new PrimaryKeyJoinColumnOwner(); + } + + protected void initializeSpecifiedPrimaryKeyJoinColumns() { + for (PrimaryKeyJoinColumnAnnotation annotation : this.getPrimaryKeyJoinColumnAnnotations()) { + this.specifiedPrimaryKeyJoinColumns.add(this.buildPrimaryKeyJoinColumn(annotation)); + } + } + + protected JavaPrimaryKeyJoinColumn buildPrimaryKeyJoinColumn(PrimaryKeyJoinColumnAnnotation primaryKeyJoinColumnAnnotation) { + return this.getJpaFactory().buildJavaPrimaryKeyJoinColumn(this, this.primaryKeyJoinColumnOwner, primaryKeyJoinColumnAnnotation); + } + + protected void syncSpecifiedPrimaryKeyJoinColumns() { + ContextContainerTools.synchronizeWithResourceModel(this.specifiedPrimaryKeyJoinColumnContainerAdapter); + } + + protected Iterable<PrimaryKeyJoinColumnAnnotation> getPrimaryKeyJoinColumnAnnotations() { + return new SubIterableWrapper<NestableAnnotation, PrimaryKeyJoinColumnAnnotation>( + CollectionTools.iterable(this.primaryKeyJoinColumnAnnotations()) + ); + } + + protected Iterator<NestableAnnotation> primaryKeyJoinColumnAnnotations() { + return this.getResourceAnnotatedElement().annotations(PrimaryKeyJoinColumnAnnotation.ANNOTATION_NAME, PrimaryKeyJoinColumnsAnnotation.ANNOTATION_NAME); + } + + protected void moveSpecifiedPrimaryKeyJoinColumn_(int index, JavaPrimaryKeyJoinColumn primaryKeyJoinColumn) { + this.moveItemInList(index, primaryKeyJoinColumn, this.specifiedPrimaryKeyJoinColumns, SPECIFIED_PRIMARY_KEY_JOIN_COLUMNS_LIST); + } + + protected JavaPrimaryKeyJoinColumn addSpecifiedPrimaryKeyJoinColumn_(int index, PrimaryKeyJoinColumnAnnotation primaryKeyJoinColumnAnnotation) { + JavaPrimaryKeyJoinColumn primaryKeyJoinColumn = this.buildPrimaryKeyJoinColumn(primaryKeyJoinColumnAnnotation); + this.addItemToList(index, primaryKeyJoinColumn, this.specifiedPrimaryKeyJoinColumns, SPECIFIED_PRIMARY_KEY_JOIN_COLUMNS_LIST); + return primaryKeyJoinColumn; + } + + protected void removeSpecifiedPrimaryKeyJoinColumn_(JavaPrimaryKeyJoinColumn primaryKeyJoinColumn) { + this.removeSpecifiedPrimaryKeyJoinColumn_(this.specifiedPrimaryKeyJoinColumns.indexOf(primaryKeyJoinColumn)); + } + + /** + * specified primary key join column container adapter + */ + protected class SpecifiedPrimaryKeyJoinColumnContainerAdapter + implements ContextContainerTools.Adapter<JavaPrimaryKeyJoinColumn, PrimaryKeyJoinColumnAnnotation> + { + public Iterable<JavaPrimaryKeyJoinColumn> getContextElements() { + return AbstractJavaEntity.this.getSpecifiedPrimaryKeyJoinColumns(); + } + public Iterable<PrimaryKeyJoinColumnAnnotation> getResourceElements() { + return AbstractJavaEntity.this.getPrimaryKeyJoinColumnAnnotations(); + } + public PrimaryKeyJoinColumnAnnotation getResourceElement(JavaPrimaryKeyJoinColumn contextElement) { + return contextElement.getColumnAnnotation(); + } + public void moveContextElement(int index, JavaPrimaryKeyJoinColumn element) { + AbstractJavaEntity.this.moveSpecifiedPrimaryKeyJoinColumn_(index, element); + } + public void addContextElement(int index, PrimaryKeyJoinColumnAnnotation resourceElement) { + AbstractJavaEntity.this.addSpecifiedPrimaryKeyJoinColumn_(index, resourceElement); + } + public void removeContextElement(JavaPrimaryKeyJoinColumn element) { + AbstractJavaEntity.this.removeSpecifiedPrimaryKeyJoinColumn_(element); + } + } + + + // ********** default primary key join column ********** + + public JavaPrimaryKeyJoinColumn getDefaultPrimaryKeyJoinColumn() { + return this.defaultPrimaryKeyJoinColumn; + } + + protected void setDefaultPrimaryKeyJoinColumn(JavaPrimaryKeyJoinColumn pkJoinColumn) { + JavaPrimaryKeyJoinColumn old = this.defaultPrimaryKeyJoinColumn; + this.defaultPrimaryKeyJoinColumn = pkJoinColumn; + this.firePropertyChanged(DEFAULT_PRIMARY_KEY_JOIN_COLUMN_PROPERTY, old, pkJoinColumn); + } + + protected ListIterable<JavaPrimaryKeyJoinColumn> getDefaultPrimaryKeyJoinColumns() { + return (this.defaultPrimaryKeyJoinColumn != null) ? + new SingleElementListIterable<JavaPrimaryKeyJoinColumn>(this.defaultPrimaryKeyJoinColumn) : + EmptyListIterable.<JavaPrimaryKeyJoinColumn>instance(); + } + + protected int defaultPrimaryKeyJoinColumnsSize() { + return (this.defaultPrimaryKeyJoinColumn == null) ? 0 : 1; + } + + protected void updateDefaultPrimaryKeyJoinColumn() { + if (this.buildsDefaultPrimaryKeyJoinColumn()) { + if (this.defaultPrimaryKeyJoinColumn == null) { + this.setDefaultPrimaryKeyJoinColumn(this.buildDefaultPrimaryKeyJoinColumn()); + } else { + this.defaultPrimaryKeyJoinColumn.update(); + } + } else { + this.setDefaultPrimaryKeyJoinColumn(null); + } + } + + protected boolean buildsDefaultPrimaryKeyJoinColumn() { + return ! this.hasSpecifiedPrimaryKeyJoinColumns(); + } + + protected JavaPrimaryKeyJoinColumn buildDefaultPrimaryKeyJoinColumn() { + return this.buildPrimaryKeyJoinColumn(new NullPrimaryKeyJoinColumnAnnotation(this.getResourcePersistentType())); + } + + + // ********** inheritance strategy ********** + + public InheritanceType getInheritanceStrategy() { + return (this.specifiedInheritanceStrategy != null) ? this.specifiedInheritanceStrategy : this.defaultInheritanceStrategy; + } + + public InheritanceType getSpecifiedInheritanceStrategy() { + return this.specifiedInheritanceStrategy; + } + + public void setSpecifiedInheritanceStrategy(InheritanceType inheritanceType) { + if (this.valuesAreDifferent(this.specifiedInheritanceStrategy, inheritanceType)) { + this.getInheritanceAnnotation().setStrategy(InheritanceType.toJavaResourceModel(inheritanceType)); + this.removeInheritanceAnnotationIfUnset(); + this.setSpecifiedInheritanceStrategy_(inheritanceType); + } + } + + protected void setSpecifiedInheritanceStrategy_(InheritanceType inheritanceType) { + InheritanceType old = this.specifiedInheritanceStrategy; + this.specifiedInheritanceStrategy = inheritanceType; + this.firePropertyChanged(SPECIFIED_INHERITANCE_STRATEGY_PROPERTY, old, inheritanceType); + } + + protected InheritanceType buildSpecifiedInheritanceStrategy() { + return InheritanceType.fromJavaResourceModel(this.getInheritanceAnnotation().getStrategy()); + } + + public InheritanceType getDefaultInheritanceStrategy() { + return this.defaultInheritanceStrategy; + } + + protected void setDefaultInheritanceStrategy(InheritanceType inheritanceType) { + InheritanceType old = this.defaultInheritanceStrategy; + this.defaultInheritanceStrategy = inheritanceType; + this.firePropertyChanged(DEFAULT_INHERITANCE_STRATEGY_PROPERTY, old, inheritanceType); + } + + protected InheritanceType buildDefaultInheritanceStrategy() { + return this.isRoot() ? InheritanceType.SINGLE_TABLE : this.rootEntity.getInheritanceStrategy(); + } + + + // ********** inheritance annotation ********** + + protected InheritanceAnnotation getInheritanceAnnotation() { + return (InheritanceAnnotation) this.getResourcePersistentType().getNonNullAnnotation(InheritanceAnnotation.ANNOTATION_NAME); + } + + protected void removeInheritanceAnnotationIfUnset() { + if (this.getInheritanceAnnotation().isUnset()) { + this.removeInheritanceAnnotation(); + } + } + + protected void removeInheritanceAnnotation() { + this.getResourcePersistentType().removeAnnotation(InheritanceAnnotation.ANNOTATION_NAME); + } + + + // ********** discriminator value ********** + + public String getDiscriminatorValue() { + return (this.specifiedDiscriminatorValue != null) ? this.specifiedDiscriminatorValue : this.defaultDiscriminatorValue; + } + + public String getSpecifiedDiscriminatorValue() { + return this.specifiedDiscriminatorValue; + } + + public void setSpecifiedDiscriminatorValue(String discriminatorValue) { + if (this.valuesAreDifferent(this.specifiedDiscriminatorValue, discriminatorValue)) { + this.getDiscriminatorValueAnnotation().setValue(discriminatorValue); + this.removeDiscriminatorValueAnnotationIfUnset(); + this.setSpecifiedDiscriminatorValue_(discriminatorValue); + } + } + + protected void setSpecifiedDiscriminatorValue_(String discriminatorValue) { + String old = this.specifiedDiscriminatorValue; + this.specifiedDiscriminatorValue = discriminatorValue; + this.firePropertyChanged(SPECIFIED_DISCRIMINATOR_VALUE_PROPERTY, old, discriminatorValue); + } + + public String getDefaultDiscriminatorValue() { + return this.defaultDiscriminatorValue; + } + + protected void setDefaultDiscriminatorValue(String discriminatorValue) { + String old = this.defaultDiscriminatorValue; + this.defaultDiscriminatorValue = discriminatorValue; + this.firePropertyChanged(DEFAULT_DISCRIMINATOR_VALUE_PROPERTY, old, discriminatorValue); + } + + /** + * From the Spec: + * If the DiscriminatorValue annotation is not specified, a + * provider-specific function to generate a value representing + * the entity type is used for the value of the discriminator + * column. If the DiscriminatorType is STRING, the discriminator + * value default is the entity name. + */ + // TODO extension point for provider-specific function? + protected String buildDefaultDiscriminatorValue() { + if (this.discriminatorValueIsUndefined) { + return null; + } + return (this.getDiscriminatorType() == DiscriminatorType.STRING) ? this.getName() : null; + } + + protected DiscriminatorType getDiscriminatorType() { + return this.discriminatorColumn.getDiscriminatorType(); + } + + public boolean specifiedDiscriminatorValueIsAllowed() { + return this.specifiedDiscriminatorValueIsAllowed; + } + + protected void setSpecifiedDiscriminatorValueIsAllowed(boolean allowed) { + boolean old = this.specifiedDiscriminatorValueIsAllowed; + this.specifiedDiscriminatorValueIsAllowed = allowed; + this.firePropertyChanged(SPECIFIED_DISCRIMINATOR_VALUE_IS_ALLOWED_PROPERTY, old, allowed); + } + + protected boolean buildSpecifiedDiscriminatorValueIsAllowed() { + return ! this.isTablePerClass() && ! this.isAbstract(); + } + + public boolean discriminatorValueIsUndefined() { + return this.discriminatorValueIsUndefined; + } + + protected void setDiscriminatorValueIsUndefined(boolean undefined) { + boolean old = this.discriminatorValueIsUndefined; + this.discriminatorValueIsUndefined = undefined; + this.firePropertyChanged(DISCRIMINATOR_VALUE_IS_UNDEFINED_PROPERTY, old, undefined); + } + + protected boolean buildDiscriminatorValueIsUndefined() { + return this.isTablePerClass() || + this.isAbstract() || + this.isRootNoDescendantsNoStrategyDefined(); + } + + + // ********** discriminator value annotation ********** + + protected DiscriminatorValueAnnotation getDiscriminatorValueAnnotation() { + return (DiscriminatorValueAnnotation) this.getResourcePersistentType().getNonNullAnnotation(DiscriminatorValueAnnotation.ANNOTATION_NAME); + } + + protected void removeDiscriminatorValueAnnotationIfUnset() { + if (this.getDiscriminatorValueAnnotation().isUnset()) { + this.removeDiscriminatorValueAnnotation(); + } + } + + protected void removeDiscriminatorValueAnnotation() { + this.getResourcePersistentType().removeAnnotation(DiscriminatorValueAnnotation.ANNOTATION_NAME); + } + + + // ********** discriminator column ********** + + public JavaDiscriminatorColumn getDiscriminatorColumn() { + return this.discriminatorColumn; + } + + protected JavaDiscriminatorColumn buildDiscriminatorColumn() { + return this.getJpaFactory().buildJavaDiscriminatorColumn(this, this.buildDiscriminatorColumnOwner()); + } + + protected JavaDiscriminatorColumn.Owner buildDiscriminatorColumnOwner() { + return new DiscriminatorColumnOwner(); + } + + public boolean specifiedDiscriminatorColumnIsAllowed() { + return this.specifiedDiscriminatorColumnIsAllowed; + } + + protected void setSpecifiedDiscriminatorColumnIsAllowed(boolean allowed) { + boolean old = this.specifiedDiscriminatorColumnIsAllowed; + this.specifiedDiscriminatorColumnIsAllowed = allowed; + this.firePropertyChanged(SPECIFIED_DISCRIMINATOR_COLUMN_IS_ALLOWED_PROPERTY, old, allowed); + } + + protected boolean buildSpecifiedDiscriminatorColumnIsAllowed() { + return ! this.isTablePerClass() && this.isRoot(); + } + + public boolean discriminatorColumnIsUndefined() { + return this.discriminatorColumnIsUndefined; + } + + protected void setDiscriminatorColumnIsUndefined(boolean undefined) { + boolean old = this.discriminatorColumnIsUndefined; + this.discriminatorColumnIsUndefined = undefined; + this.firePropertyChanged(DISCRIMINATOR_COLUMN_IS_UNDEFINED_PROPERTY, old, undefined); + } + + protected boolean buildDiscriminatorColumnIsUndefined() { + return this.isTablePerClass() || + this.isRootNoDescendantsNoStrategyDefined(); + } + + + // ********** attribute override container ********** + + public JavaAttributeOverrideContainer getAttributeOverrideContainer() { + return this.attributeOverrideContainer; + } + + protected JavaAttributeOverrideContainer buildAttributeOverrideContainer() { + return this.getJpaFactory().buildJavaAttributeOverrideContainer(this, new AttributeOverrideContainerOwner()); + } + + public TypeMapping getOverridableTypeMapping() { + PersistentType superPersistentType = this.getPersistentType().getSuperPersistentType(); + return (superPersistentType == null) ? null : superPersistentType.getMapping(); + } + + + // ********** association override container ********** + + public JavaAssociationOverrideContainer getAssociationOverrideContainer() { + return this.associationOverrideContainer; + } + + protected JavaAssociationOverrideContainer buildAssociationOverrideContainer() { + return this.getJpaFactory().buildJavaAssociationOverrideContainer(this, new AssociationOverrideContainerOwner()); + } + + @Override + public Relationship resolveOverriddenRelationship(String attributeName) { + // check for an override before looking at attribute mappings + AssociationOverride override = this.associationOverrideContainer.getSpecifiedOverrideNamed(attributeName); + return (override != null) ? override.getRelationship() : super.resolveOverriddenRelationship(attributeName); + } + + + // ********** generator container ********** + + public JavaGeneratorContainer getGeneratorContainer() { + return this.generatorContainer; + } + + protected JavaGeneratorContainer buildGeneratorContainer() { + return this.getJpaFactory().buildJavaGeneratorContainer(this, this); + } + + public JavaResourcePersistentMember getResourceAnnotatedElement() { + return this.getResourcePersistentType(); + } + + + // ********** query container ********** + + public JavaQueryContainer getQueryContainer() { + return this.queryContainer; + } + + protected JavaQueryContainer buildQueryContainer() { + return this.getJpaFactory().buildJavaQueryContainer(this, this); + } + + + // ********** associated tables ********** + + @Override + public Iterator<ReadOnlyTable> associatedTables() { + return this.getAssociatedTables().iterator(); + } + + public Iterable<ReadOnlyTable> getAssociatedTables() { + return new CompositeIterable<ReadOnlyTable>(this.table, this.getSecondaryTables()); + } + + @Override + public Iterator<ReadOnlyTable> allAssociatedTables() { + return new CompositeIterator<ReadOnlyTable>(this.allAssociatedTablesLists()); + } + + public Iterable<ReadOnlyTable> getAllAssociatedTables() { + return CollectionTools.iterable(this.allAssociatedTables()); + } + + // TODO eliminate duplicate tables? + protected Iterator<Iterator<ReadOnlyTable>> allAssociatedTablesLists() { + return new TransformationIterator<TypeMapping, Iterator<ReadOnlyTable>>(this.inheritanceHierarchy(), TypeMappingTools.ASSOCIATED_TABLES_TRANSFORMER); + } + + @Override + public Iterator<String> allAssociatedTableNames() { + return this.getAllAssociatedTableNames().iterator(); + } + + public Iterable<String> getAllAssociatedTableNames() { + return this.convertToNames(this.getAllAssociatedTables()); + } + + /** + * strip out <code>null</code> names + */ + protected Iterable<String> convertToNames(Iterable<ReadOnlyTable> tables) { + return new FilteringIterable<String>(this.convertToNames_(tables), NotNullFilter.<String>instance()); + } + + protected Iterable<String> convertToNames_(Iterable<ReadOnlyTable> tables) { + return new TransformationIterable<ReadOnlyTable, String>(tables) { + @Override + protected String transform(ReadOnlyTable t) { + return t.getName(); + } + }; + } + + public boolean tableNameIsInvalid(String tableName) { + return ! this.tableNameIsValid(tableName); + } + + protected boolean tableNameIsValid(String tableName) { + return this.tableIsUndefined || CollectionTools.contains(this.getAllAssociatedTableNames(), tableName); + } + + + // ********** database ********** + + @Override + public String getPrimaryTableName() { + return this.table.getName(); + } + + @Override + public org.eclipse.jpt.jpa.db.Table getPrimaryDbTable() { + return this.table.getDbTable(); + } + + @Override + public org.eclipse.jpt.jpa.db.Table resolveDbTable(String tableName) { + // matching database objects and identifiers is database platform-specific + return this.getDataSource().selectDatabaseObjectForIdentifier(this.getAllAssociatedDbTables(), tableName); + } + + /** + * strip out null db tables + */ + protected Iterable<org.eclipse.jpt.jpa.db.Table> getAllAssociatedDbTables() { + return new FilteringIterable<org.eclipse.jpt.jpa.db.Table>(this.getAllAssociatedDbTables_(), NotNullFilter.<org.eclipse.jpt.jpa.db.Table>instance()); + } + + protected Iterable<org.eclipse.jpt.jpa.db.Table> getAllAssociatedDbTables_() { + return new TransformationIterable<ReadOnlyTable, org.eclipse.jpt.jpa.db.Table>(this.getAllAssociatedTables()) { + @Override + protected org.eclipse.jpt.jpa.db.Table transform(ReadOnlyTable entityTable) { + return entityTable.getDbTable(); + } + }; + } + + @Override + public Schema getDbSchema() { + return this.table.getDbSchema(); + } + + + // ********** primary key ********** + + public String getPrimaryKeyColumnName() { + return MappingTools.getPrimaryKeyColumnName(this); + } + + public PersistentAttribute getIdAttribute() { + Iterator<AttributeMapping> idAttributeMappings = this.getAllAttributeMappings(MappingKeys.ID_ATTRIBUTE_MAPPING_KEY).iterator(); + if (idAttributeMappings.hasNext()) { + PersistentAttribute attribute = idAttributeMappings.next().getPersistentAttribute(); + return idAttributeMappings.hasNext() ? null /*more than one*/: attribute; + } + return null; + } + + + // ********** misc ********** + + public String getKey() { + return MappingKeys.ENTITY_TYPE_MAPPING_KEY; + } + + public boolean isMapped() { + return true; + } + + @Override + public JavaResourcePersistentType getResourcePersistentType() { + return super.getResourcePersistentType(); + } + + + // ********** attribute mappings ********** + + @Override + public Column resolveOverriddenColumn(String attributeName) { + // check for an override before looking at attribute mappings + AttributeOverride override = this.attributeOverrideContainer.getSpecifiedOverrideNamed(attributeName); + return (override != null) ? override.getColumn() : super.resolveOverriddenColumn(attributeName); + } + + @Override + public Iterator<String> overridableAttributeNames() { + return this.isTablePerClass() ? + super.overridableAttributeNames() : + EmptyIterator.<String>instance(); + } + + @Override + public Iterator<String> overridableAssociationNames() { + return this.isTablePerClass() ? + super.overridableAssociationNames() : + EmptyIterator.<String>instance(); + } + + public AttributeMapping resolveAttributeMapping(String name) { + for (AttributeMapping attributeMapping : CollectionTools.iterable(this.allAttributeMappings())) { + AttributeMapping resolvedMapping = attributeMapping.resolveAttributeMapping(name); + if (resolvedMapping != null) { + return resolvedMapping; + } + } + return null; + } + + + // ********** inheritance ********** + + public Entity getParentEntity() { + for (TypeMapping typeMapping : this.getAncestors()) { + if (typeMapping instanceof Entity) { + return (Entity) typeMapping; + } + } + return null; + } + + public boolean isRoot() { + return this == this.rootEntity; + } + + /** + * Return whether the entity is a descendant in (as opposed to the root of) + * an inheritance hierarchy. + */ + protected boolean isDescendant() { + return ! this.isRoot(); + } + + /** + * Return whether the entity is a descendant of the root entity + * of a "single table" inheritance hierarchy. + */ + protected boolean isSingleTableDescendant() { + return this.isDescendant() && + (this.getInheritanceStrategy() == InheritanceType.SINGLE_TABLE); + } + + /** + * Return whether the entity is the top of an inheritance hierarchy + * and has no descendants and no specified inheritance strategy has been defined. + */ + protected boolean isRootNoDescendantsNoStrategyDefined() { + return this.isRoot() && + this.descendants.isEmpty() && + (this.specifiedInheritanceStrategy == null); + } + + /** + * Return whether the entity is abstract and is a part of a + * "table per class" inheritance hierarchy. + */ + protected boolean isAbstractTablePerClass() { + return this.isAbstract() && this.isTablePerClass(); + } + + /** + * Return whether the entity is a part of a "table per class" + * inheritance hierarchy. + */ + protected boolean isTablePerClass() { + return this.getInheritanceStrategy() == InheritanceType.TABLE_PER_CLASS; + } + + /** + * Return whether the entity is a part of a "table per class" + * inheritance hierarchy. + */ + protected boolean isTablePerClassDescendant() { + return this.isTablePerClass() && this.isDescendant(); + } + + /** + * Return whether the type is abstract. + */ + protected boolean isAbstract() { + return this.getResourcePersistentType().isAbstract(); + } + + /** + * Return whether the entity's type is final. + */ + protected boolean isFinal() { + return this.getResourcePersistentType().isFinal(); + } + + /** + * Return whether the entity's type is a member of another type. + */ + protected boolean isMember() { + return this.getResourcePersistentType().isMemberType(); + } + + /** + * Return whether the entity's type is static. + */ + protected boolean isStatic() { + return this.getResourcePersistentType().isStatic(); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + result = this.table.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + for (JavaSecondaryTable secondaryTable : CollectionTools.iterable(this.secondaryTables())) { + result = secondaryTable.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + } + for (JavaPrimaryKeyJoinColumn pkJoinColumn : CollectionTools.iterable(this.primaryKeyJoinColumns())) { + result = pkJoinColumn.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + } + result = this.attributeOverrideContainer.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + result = this.associationOverrideContainer.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + result = this.discriminatorColumn.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + result = this.generatorContainer.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + return null; + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + + this.validatePrimaryKey(messages, reporter, astRoot); + this.validateTable(messages, reporter, astRoot); + for (JavaSecondaryTable secondaryTable : this.getSecondaryTables()) { + secondaryTable.validate(messages, reporter, astRoot); + } + this.validateInheritance(messages, reporter, astRoot); + for (JavaPrimaryKeyJoinColumn pkJoinColumn : this.getPrimaryKeyJoinColumns()) { + pkJoinColumn.validate(messages, reporter, astRoot); + } + this.generatorContainer.validate(messages, reporter, astRoot); + this.queryContainer.validate(messages, reporter, astRoot); + this.attributeOverrideContainer.validate(messages, reporter, astRoot); + this.associationOverrideContainer.validate(messages, reporter, astRoot); + this.validateEntityName(messages, reporter, astRoot); + this.validateDuplicateEntityNames(messages, reporter, astRoot); + } + + @Override + public boolean validatesAgainstDatabase() { + return super.validatesAgainstDatabase() && ! this.isAbstractTablePerClass(); + } + + protected void validateEntityName(List<IMessage> messages, + IReporter reporter, CompilationUnit astRoot) { + if (StringTools.stringIsEmpty(this.getName())){ + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.ENTITY_NAME_MISSING, + new String[] {this.getPersistentType().getName()}, + this, + this.getMappingAnnotation().getNameTextRange(astRoot) + ) + ); + } + } + + protected void validateDuplicateEntityNames(List<IMessage> messages, + IReporter reporter, CompilationUnit astRoot) { + HashBag<String> javaEntityNamesExclOverridden = new HashBag<String>(); + CollectionTools.addAll(javaEntityNamesExclOverridden, this.getPersistenceUnit().javaEntityNamesExclOverridden()); + HashBag<String> ormEntityNames = new HashBag<String>(); + CollectionTools.addAll(ormEntityNames, this.getPersistenceUnit().ormEntityNames()); + String javaEntityName = this.getName(); + if ((javaEntityName != null) + // Check whether or not this entity name has duplicates among + // the java entities that are not overridden by orm entities + && ((javaEntityNamesExclOverridden.count(javaEntityName) > 1) + //Check whether or not this entity name has duplicates + //with the names of orm entities + || (ormEntityNames.contains(javaEntityName)))) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.PERSISTENCE_UNIT_ENTITY_NAME_ATTRIBUTE_MISSING, + new String[] {javaEntityName}, + this, + this.getMappingAnnotation().getNameTextRange(astRoot) + ) + ); + } + } + + protected void validatePrimaryKey(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + this.buildPrimaryKeyValidator(astRoot).validate(messages, reporter); + } + + protected JptValidator buildPrimaryKeyValidator(CompilationUnit astRoot) { + return new GenericEntityPrimaryKeyValidator(this, this.buildTextRangeResolver(astRoot)); + } + + @Override + protected EntityTextRangeResolver buildTextRangeResolver(CompilationUnit astRoot) { + return new JavaEntityTextRangeResolver(this, astRoot); + } + + protected void validateTable(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + if (this.isAbstractTablePerClass()) { + if (this.table.isSpecifiedInResource()) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.ENTITY_ABSTRACT_TABLE_PER_CLASS_DEFINES_TABLE, + new String[] {this.getName()}, + this, + this.table.getValidationTextRange(astRoot) + ) + ); + } + return; + } + if (this.isSingleTableDescendant()) { + if (this.table.isSpecifiedInResource()) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.ENTITY_SINGLE_TABLE_DESCENDANT_DEFINES_TABLE, + new String[] {this.getName()}, + this, + this.table.getValidationTextRange(astRoot) + ) + ); + } + return; + } + this.table.validate(messages, reporter, astRoot); + } + + protected void validateInheritance(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + this.validateInheritanceStrategy(messages, astRoot); + this.validateDiscriminatorColumn(messages, reporter, astRoot); + this.validateDiscriminatorValue(messages, astRoot); + } + + protected void validateDiscriminatorColumn(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + if (this.specifiedDiscriminatorColumnIsAllowed && ! this.discriminatorColumnIsUndefined) { + this.discriminatorColumn.validate(messages, reporter, astRoot); + } + else if (this.discriminatorColumn.isResourceSpecified()) { + if (this.isDescendant()) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.ENTITY_NON_ROOT_DISCRIMINATOR_COLUMN_DEFINED, + new String[] {this.getName()}, + this, + this.getDiscriminatorColumnTextRange(astRoot) + ) + ); + } + else if (this.isTablePerClass()) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.ENTITY_TABLE_PER_CLASS_DISCRIMINATOR_COLUMN_DEFINED, + new String[] {this.getName()}, + this, + this.getDiscriminatorColumnTextRange(astRoot) + ) + ); + } + } + } + + protected void validateDiscriminatorValue(List<IMessage> messages, CompilationUnit astRoot) { + if (this.discriminatorValueIsUndefined && (this.specifiedDiscriminatorValue != null)) { + if (this.isAbstract()) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.NORMAL_SEVERITY, + JpaValidationMessages.ENTITY_ABSTRACT_DISCRIMINATOR_VALUE_DEFINED, + new String[] {this.getName()}, + this, + this.getDiscriminatorValueTextRange(astRoot) + ) + ); + } + else if (this.isTablePerClass()) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.NORMAL_SEVERITY, + JpaValidationMessages.ENTITY_TABLE_PER_CLASS_DISCRIMINATOR_VALUE_DEFINED, + new String[] {this.getName()}, + this, + this.getDiscriminatorValueTextRange(astRoot) + ) + ); + } + } + } + + protected void validateInheritanceStrategy(List<IMessage> messages, CompilationUnit astRoot) { + Supported tablePerConcreteClassInheritanceIsSupported = this.getJpaPlatformVariation().getTablePerConcreteClassInheritanceIsSupported(); + if (tablePerConcreteClassInheritanceIsSupported == Supported.YES) { + return; + } + if ((this.getInheritanceStrategy() == InheritanceType.TABLE_PER_CLASS) && this.isRoot()) { + if (tablePerConcreteClassInheritanceIsSupported == Supported.NO) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.ENTITY_TABLE_PER_CLASS_NOT_SUPPORTED_ON_PLATFORM, + new String[] {this.getName()}, + this, + this.getInheritanceStrategyTextRange(astRoot) + ) + ); + } + else { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.NORMAL_SEVERITY, + JpaValidationMessages.ENTITY_TABLE_PER_CLASS_NOT_PORTABLE_ON_PLATFORM, + new String[] {this.getName()}, + this, + this.getInheritanceStrategyTextRange(astRoot) + ) + ); + } + } + } + + protected TextRange getDiscriminatorValueTextRange(CompilationUnit astRoot) { + return this.getDiscriminatorValueAnnotation().getTextRange(astRoot); + } + + protected TextRange getDiscriminatorColumnTextRange(CompilationUnit astRoot) { + return this.discriminatorColumn.getValidationTextRange(astRoot); + } + + protected TextRange getInheritanceStrategyTextRange(CompilationUnit astRoot) { + return this.getInheritanceAnnotation().getStrategyTextRange(astRoot); + } + + + // ********** OrmOverrideContainer.Owner implementation ********** + + /** + * some common behavior + */ + protected abstract class OverrideContainerOwner + implements JavaOverrideContainer.Owner + { + public JavaResourcePersistentMember getResourcePersistentMember() { + return AbstractJavaEntity.this.getResourcePersistentType(); + } + + public JavaTypeMapping getTypeMapping() { + return AbstractJavaEntity.this; + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return AbstractJavaEntity.this.getValidationTextRange(astRoot); + } + + public TypeMapping getOverridableTypeMapping() { + return AbstractJavaEntity.this.getOverridableTypeMapping(); + } + + public Iterator<String> allOverridableNames() { + TypeMapping typeMapping = this.getOverridableTypeMapping(); + return (typeMapping != null) ? this.allOverridableNames_(typeMapping) : EmptyIterator.<String>instance(); + } + + /** + * pre-condition: <code>typeMapping</code> is not <code>null</code> + */ + protected abstract Iterator<String> allOverridableNames_(TypeMapping typeMapping); + + public String getDefaultTableName() { + return AbstractJavaEntity.this.getPrimaryTableName(); + } + + public boolean tableNameIsInvalid(String tableName) { + return AbstractJavaEntity.this.tableNameIsInvalid(tableName); + } + + public org.eclipse.jpt.jpa.db.Table resolveDbTable(String tableName) { + return AbstractJavaEntity.this.resolveDbTable(tableName); + } + + public Iterator<String> candidateTableNames() { + return AbstractJavaEntity.this.allAssociatedTableNames(); + } + + public String getPossiblePrefix() { + return null; + } + + public String getWritePrefix() { + return null; + } + + // no maps, so all overrides are relevant + public boolean isRelevant(String overrideName) { + return true; + } + + } + + + // ********** JavaAttributeOverrideContainer.Owner implementation ********** + + protected class AttributeOverrideContainerOwner + extends OverrideContainerOwner + implements JavaAttributeOverrideContainer.Owner + { + @Override + protected Iterator<String> allOverridableNames_(TypeMapping typeMapping) { + final Collection<String> mappedByRelationshipAttributes = CollectionTools.collection( + new TransformationIterator<SingleRelationshipMapping2_0, String>(this.getMapsIdRelationships()) { + @Override + protected String transform(SingleRelationshipMapping2_0 mapping) { + return mapping.getDerivedIdentity().getMapsIdDerivedIdentityStrategy().getValue(); + } + }); + return new FilteringIterator<String>(typeMapping.allOverridableAttributeNames()) { + @Override + protected boolean accept(String name) { + if (mappedByRelationshipAttributes.isEmpty()) { + return true; + } + // overridable names are (usually?) qualified with a container mapping, + // which may also be the one mapped by a relationship + int index = name.indexOf('.'); + String qualifier = (index > 0) ? name.substring(0, index) : name; + return ! mappedByRelationshipAttributes.contains(qualifier); + } + }; + } + + protected Iterable<SingleRelationshipMapping2_0> getMapsIdRelationships() { + return new FilteringIterable<SingleRelationshipMapping2_0>(this.getSingleRelationshipMappings()) { + @Override + protected boolean accept(SingleRelationshipMapping2_0 mapping) { + return mapping.getDerivedIdentity().usesMapsIdDerivedIdentityStrategy(); + } + }; + } + + protected Iterable<SingleRelationshipMapping2_0> getSingleRelationshipMappings() { + return new SubIterableWrapper<AttributeMapping, SingleRelationshipMapping2_0>(this.getSingleRelationshipMappings_()); + } + + @SuppressWarnings("unchecked") + protected Iterable<AttributeMapping> getSingleRelationshipMappings_() { + return new CompositeIterable<AttributeMapping>( + this.getTypeMapping().getAllAttributeMappings(MappingKeys.ONE_TO_ONE_ATTRIBUTE_MAPPING_KEY), + this.getTypeMapping().getAllAttributeMappings(MappingKeys.MANY_TO_ONE_ATTRIBUTE_MAPPING_KEY) + ); + } + public Column resolveOverriddenColumn(String attributeName) { + return MappingTools.resolveOverriddenColumn(this.getOverridableTypeMapping(), attributeName); + } + + public JptValidator buildValidator(Override_ override, OverrideContainer container, OverrideTextRangeResolver textRangeResolver) { + return new AttributeOverrideValidator((AttributeOverride) override, (AttributeOverrideContainer) container, textRangeResolver, new MappedSuperclassOverrideDescriptionProvider()); + } + + public JptValidator buildColumnValidator(Override_ override, BaseColumn column, BaseColumn.Owner owner, BaseColumnTextRangeResolver textRangeResolver) { + return new AttributeOverrideColumnValidator((AttributeOverride) override, column, textRangeResolver, new EntityTableDescriptionProvider()); + } + } + + + // ********** JavaAssociationOverrideContainer.Owner implementation ********** + + protected class AssociationOverrideContainerOwner + extends OverrideContainerOwner + implements JavaAssociationOverrideContainer.Owner + { + @Override + protected Iterator<String> allOverridableNames_(TypeMapping typeMapping) { + return typeMapping.allOverridableAssociationNames(); + } + + public Relationship resolveOverriddenRelationship(String attributeName) { + return MappingTools.resolveOverriddenRelationship(this.getOverridableTypeMapping(), attributeName); + } + + public JptValidator buildValidator(Override_ override, OverrideContainer container, OverrideTextRangeResolver textRangeResolver) { + return new AssociationOverrideValidator((AssociationOverride) override, (AssociationOverrideContainer) container, textRangeResolver, new MappedSuperclassOverrideDescriptionProvider()); + } + + public JptValidator buildColumnValidator(Override_ override, BaseColumn column, BaseColumn.Owner owner, BaseColumnTextRangeResolver textRangeResolver) { + return new AssociationOverrideJoinColumnValidator((AssociationOverride) override, (JoinColumn) column, (JoinColumn.Owner) owner, (JoinColumnTextRangeResolver) textRangeResolver, new EntityTableDescriptionProvider()); + } + + public JptValidator buildJoinTableJoinColumnValidator(AssociationOverride override, JoinColumn column, JoinColumn.Owner owner, JoinColumnTextRangeResolver textRangeResolver) { + return new AssociationOverrideJoinColumnValidator(override, column, owner, textRangeResolver, new JoinTableTableDescriptionProvider()); + } + + public JptValidator buildJoinTableInverseJoinColumnValidator(AssociationOverride override, JoinColumn column, Owner owner, JoinColumnTextRangeResolver textRangeResolver) { + return new AssociationOverrideInverseJoinColumnValidator(override, column, owner, textRangeResolver, new JoinTableTableDescriptionProvider()); + } + + public JptValidator buildTableValidator(AssociationOverride override, Table t, TableTextRangeResolver textRangeResolver) { + return new AssociationOverrideJoinTableValidator(override, (JoinTable) t, textRangeResolver); + } + } + + + // ********** JavaNamedColumn.Owner implementation ********** + + /** + * some common behavior + */ + protected abstract class NamedColumnOwner + implements JavaNamedColumn.Owner + { + public TypeMapping getTypeMapping() { + return AbstractJavaEntity.this; + } + + public String getDefaultTableName() { + return AbstractJavaEntity.this.getPrimaryTableName(); + } + + public org.eclipse.jpt.jpa.db.Table resolveDbTable(String tableName) { + return AbstractJavaEntity.this.resolveDbTable(tableName); + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return AbstractJavaEntity.this.getValidationTextRange(astRoot); + } + } + + + // ********** JavaBaseJoinColumn.Owner implementation ********** + + protected class PrimaryKeyJoinColumnOwner + extends NamedColumnOwner + implements JavaBaseJoinColumn.Owner + { + public org.eclipse.jpt.jpa.db.Table getReferencedColumnDbTable() { + Entity parentEntity = AbstractJavaEntity.this.getParentEntity(); + return (parentEntity == null) ? null : parentEntity.getPrimaryDbTable(); + } + + public int joinColumnsSize() { + return AbstractJavaEntity.this.primaryKeyJoinColumnsSize(); + } + + public boolean joinColumnIsDefault(ReadOnlyBaseJoinColumn joinColumn) { + return AbstractJavaEntity.this.defaultPrimaryKeyJoinColumn == joinColumn; + } + + public String getDefaultColumnName() { + if (this.joinColumnsSize() != 1) { + return null; + } + Entity parentEntity = AbstractJavaEntity.this.getParentEntity(); + return (parentEntity == null) ? AbstractJavaEntity.this.getPrimaryKeyColumnName() : parentEntity.getPrimaryKeyColumnName(); + } + + public JptValidator buildColumnValidator(NamedColumn column, NamedColumnTextRangeResolver textRangeResolver) { + return new EntityPrimaryKeyJoinColumnValidator((BaseJoinColumn) column, this, (BaseJoinColumnTextRangeResolver) textRangeResolver); + } + } + + + // ********** JavaDiscriminatorColumn.Owner implementation ********** + + protected class DiscriminatorColumnOwner + extends NamedColumnOwner + implements JavaDiscriminatorColumn.Owner + { + public String getDefaultColumnName() { + return this.isDescendant() ? + this.getRootDiscriminatorColumn().getName() : + this.discriminatorColumnIsUndefined() ? null : DiscriminatorColumn.DEFAULT_NAME; + } + + public int getDefaultLength() { + return this.isDescendant() ? + this.getRootDiscriminatorColumn().getLength() : + this.discriminatorColumnIsUndefined() ? 0 : DiscriminatorColumn.DEFAULT_LENGTH; + } + + public DiscriminatorType getDefaultDiscriminatorType() { + return this.isDescendant() ? + this.getRootDiscriminatorColumn().getDiscriminatorType() : + this.discriminatorColumnIsUndefined() ? null : DiscriminatorColumn.DEFAULT_DISCRIMINATOR_TYPE; + } + + protected boolean isDescendant() { + return AbstractJavaEntity.this.isDescendant(); + } + + protected DiscriminatorColumn getRootDiscriminatorColumn() { + return AbstractJavaEntity.this.rootEntity.getDiscriminatorColumn(); + } + + protected boolean discriminatorColumnIsUndefined() { + return AbstractJavaEntity.this.discriminatorColumnIsUndefined; + } + + public JptValidator buildColumnValidator(NamedColumn column, NamedColumnTextRangeResolver textRangeResolver) { + return new DiscriminatorColumnValidator(column, textRangeResolver); + } + } + + + // ********** table owner ********** + + protected class TableOwner implements Table.Owner { + public JptValidator buildTableValidator(Table t, TableTextRangeResolver textRangeResolver) { + return new TableValidator(t, textRangeResolver); + } + } + + + // ********** secondary table owner ********** + + protected class SecondaryTableOwner implements Table.Owner { + public JptValidator buildTableValidator(Table t, TableTextRangeResolver textRangeResolver) { + return new SecondaryTableValidator((SecondaryTable) t, textRangeResolver); + } + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaGenerator.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaGenerator.java new file mode 100644 index 0000000000..cc79849d49 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaGenerator.java @@ -0,0 +1,225 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.Generator; +import org.eclipse.jpt.jpa.core.context.java.JavaGenerator; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; +import org.eclipse.jpt.jpa.core.internal.context.MappingTools; +import org.eclipse.jpt.jpa.core.resource.java.GeneratorAnnotation; +import org.eclipse.jpt.jpa.db.Catalog; +import org.eclipse.jpt.jpa.db.Schema; +import org.eclipse.jpt.jpa.db.SchemaContainer; + +/** + * Java sequence or table generator + */ +public abstract class AbstractJavaGenerator<A extends GeneratorAnnotation> + extends AbstractJavaJpaContextNode + implements JavaGenerator +{ + protected final A generatorAnnotation; + + protected String name; + + protected Integer specifiedInitialValue; + protected int defaultInitialValue; + + protected Integer specifiedAllocationSize; + protected int defaultAllocationSize; + + + protected AbstractJavaGenerator(JavaJpaContextNode parent, A generatorAnnotation) { + super(parent); + this.generatorAnnotation = generatorAnnotation; + this.name = generatorAnnotation.getName(); + this.specifiedInitialValue = generatorAnnotation.getInitialValue(); + this.specifiedAllocationSize = generatorAnnotation.getAllocationSize(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setName_(this.generatorAnnotation.getName()); + this.setSpecifiedInitialValue_(this.generatorAnnotation.getInitialValue()); + this.setSpecifiedAllocationSize_(this.generatorAnnotation.getAllocationSize()); + } + + @Override + public void update() { + super.update(); + this.setDefaultInitialValue(this.buildDefaultInitialValue()); + this.setDefaultAllocationSize(this.buildDefaultAllocationSize()); + this.getPersistenceUnit().addGenerator(this); + } + + + // ********** name ********** + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.generatorAnnotation.setName(name); + this.setName_(name); + } + + protected void setName_(String name) { + String old = this.name; + this.name = name; + this.firePropertyChanged(NAME_PROPERTY, old, name); + } + + + // ********** initial value ********** + + public int getInitialValue() { + return (this.specifiedInitialValue != null) ? this.specifiedInitialValue.intValue() : this.defaultInitialValue; + } + + public Integer getSpecifiedInitialValue() { + return this.specifiedInitialValue; + } + + public void setSpecifiedInitialValue(Integer value) { + this.generatorAnnotation.setInitialValue(value); + this.setSpecifiedInitialValue_(value); + } + + protected void setSpecifiedInitialValue_(Integer value) { + Integer old = this.specifiedInitialValue; + this.specifiedInitialValue = value; + this.firePropertyChanged(SPECIFIED_INITIAL_VALUE_PROPERTY, old, value); + } + + public int getDefaultInitialValue() { + return this.defaultInitialValue; + } + + protected void setDefaultInitialValue(int value) { + int old = this.defaultInitialValue; + this.defaultInitialValue = value; + this.firePropertyChanged(DEFAULT_INITIAL_VALUE_PROPERTY, old, value); + } + + protected abstract int buildDefaultInitialValue(); + + + // ********** allocation size ********** + + public int getAllocationSize() { + return (this.specifiedAllocationSize != null) ? this.specifiedAllocationSize.intValue() : this.defaultAllocationSize; + } + + public Integer getSpecifiedAllocationSize() { + return this.specifiedAllocationSize; + } + + public void setSpecifiedAllocationSize(Integer size) { + this.generatorAnnotation.setAllocationSize(size); + this.setSpecifiedAllocationSize_(size); + } + + protected void setSpecifiedAllocationSize_(Integer size) { + Integer old = this.specifiedAllocationSize; + this.specifiedAllocationSize = size; + this.firePropertyChanged(SPECIFIED_ALLOCATION_SIZE_PROPERTY, old, size); + } + + public int getDefaultAllocationSize() { + return this.defaultAllocationSize; + } + + protected void setDefaultAllocationSize(int size) { + int old = this.defaultAllocationSize; + this.defaultAllocationSize = size; + this.firePropertyChanged(DEFAULT_ALLOCATION_SIZE_PROPERTY, old, size); + } + + protected int buildDefaultAllocationSize() { + return DEFAULT_ALLOCATION_SIZE; + } + + + // ********** text ranges ********** + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return this.getSelectionTextRange(astRoot); + } + + public TextRange getSelectionTextRange(CompilationUnit astRoot) { + return this.generatorAnnotation.getTextRange(astRoot); + } + + public TextRange getNameTextRange(CompilationUnit astRoot) { + return this.generatorAnnotation.getNameTextRange(astRoot); + } + + + // ********** database stuff ********** + + public Schema getDbSchema() { + SchemaContainer dbSchemaContainer = this.getDbSchemaContainer(); + return (dbSchemaContainer == null) ? null : dbSchemaContainer.getSchemaForIdentifier(this.getSchema()); + } + + /** + * If we don't have a catalog (i.e. we don't even have a <em>default</em> catalog), + * then the database probably does not support catalogs; and we need to + * get the schema directly from the database. + */ + public SchemaContainer getDbSchemaContainer() { + String catalog = this.getCatalog(); + return (catalog != null) ? this.resolveDbCatalog(catalog) : this.getDatabase(); + } + + protected abstract String getSchema(); + + /** + * If we don't have a catalog (i.e. we don't even have a <em>default</em> + * catalog), then the database probably does not support catalogs. + */ + public Catalog getDbCatalog() { + String catalog = this.getCatalog(); + return (catalog == null) ? null : this.resolveDbCatalog(catalog); + } + + protected abstract String getCatalog(); + + + // ********** JpaNamedContextNode implementation ********** + + public boolean overrides(Generator other) { + return MappingTools.nodeOverrides(this, other, PRECEDENCE_TYPE_LIST); + } + + public boolean duplicates(Generator other) { + return MappingTools.nodesAreDuplicates(this, other); + } + + + // ********** misc ********** + + public A getGeneratorAnnotation() { + return this.generatorAnnotation; + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.name); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaIdMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaIdMapping.java new file mode 100644 index 0000000000..ac83d194a1 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaIdMapping.java @@ -0,0 +1,476 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.ArrayTools; +import org.eclipse.jpt.common.utility.internal.Association; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.SimpleAssociation; +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.BaseColumn; +import org.eclipse.jpt.jpa.core.context.Converter; +import org.eclipse.jpt.jpa.core.context.NamedColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaConverter; +import org.eclipse.jpt.jpa.core.context.java.JavaGeneratedValue; +import org.eclipse.jpt.jpa.core.context.java.JavaGeneratorContainer; +import org.eclipse.jpt.jpa.core.context.java.JavaIdMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.java.JavaTemporalConverter; +import org.eclipse.jpt.jpa.core.internal.context.BaseColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.TypeMappingTools; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.EntityTableDescriptionProvider; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.NamedColumnValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.NullJavaConverter; +import org.eclipse.jpt.jpa.core.internal.validation.DefaultJpaValidationMessages; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationDescriptionMessages; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationMessages; +import org.eclipse.jpt.jpa.core.jpa2.context.IdMapping2_0; +import org.eclipse.jpt.jpa.core.resource.java.Annotation; +import org.eclipse.jpt.jpa.core.resource.java.ColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.GeneratedValueAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.IdAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentMember; +import org.eclipse.osgi.util.NLS; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java ID mapping + */ +public abstract class AbstractJavaIdMapping + extends AbstractJavaAttributeMapping<IdAnnotation> + implements JavaIdMapping, IdMapping2_0 +{ + protected final JavaColumn column; + + protected final JavaGeneratorContainer generatorContainer; + + protected JavaGeneratedValue generatedValue; + + protected JavaConverter converter; // never null + + /* 2.0 feature - a relationship may map this id */ + protected boolean mappedByRelationship; + + + protected static final JavaConverter.Adapter[] CONVERTER_ADAPTER_ARRAY = new JavaConverter.Adapter[] { + JavaTemporalConverter.Adapter.instance(), + }; + protected static final Iterable<JavaConverter.Adapter> CONVERTER_ADAPTERS = new ArrayIterable<JavaConverter.Adapter>(CONVERTER_ADAPTER_ARRAY); + + + protected AbstractJavaIdMapping(JavaPersistentAttribute parent) { + super(parent); + this.column = this.buildColumn(); + this.generatorContainer = this.buildGeneratorContainer(); + this.generatedValue = this.buildGeneratedValue(); + this.converter = this.buildConverter(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.column.synchronizeWithResourceModel(); + this.generatorContainer.synchronizeWithResourceModel(); + this.syncGeneratedValue(); + this.syncConverter(); + } + + @Override + public void update() { + super.update(); + this.column.update(); + this.generatorContainer.update(); + if (this.generatedValue != null) { + this.generatedValue.update(); + } + this.converter.update(); + this.setMappedByRelationship(this.buildMappedByRelationship()); + } + + + // ********** column ********** + + public JavaColumn getColumn() { + return this.column; + } + + protected JavaColumn buildColumn() { + return this.getJpaFactory().buildJavaColumn(this, this); + } + + + // ********** generator container ********** + + public JavaGeneratorContainer getGeneratorContainer() { + return this.generatorContainer; + } + + private JavaGeneratorContainer buildGeneratorContainer() { + return this.getJpaFactory().buildJavaGeneratorContainer(this, this); + } + + + // ********** generated value ********** + + public JavaGeneratedValue getGeneratedValue() { + return this.generatedValue; + } + + public JavaGeneratedValue addGeneratedValue() { + if (this.generatedValue != null) { + throw new IllegalStateException("generated value already exists: " + this.generatedValue); //$NON-NLS-1$ + } + GeneratedValueAnnotation annotation = this.buildGeneratedValueAnnotation(); + JavaGeneratedValue value = this.buildGeneratedValue(annotation); + this.setGeneratedValue(value); + return value; + } + + protected GeneratedValueAnnotation buildGeneratedValueAnnotation() { + return (GeneratedValueAnnotation) this.getResourcePersistentAttribute().addAnnotation(GeneratedValueAnnotation.ANNOTATION_NAME); + } + + public void removeGeneratedValue() { + if (this.generatedValue == null) { + throw new IllegalStateException("generated value does not exist"); //$NON-NLS-1$ + } + this.getResourcePersistentAttribute().removeAnnotation(GeneratedValueAnnotation.ANNOTATION_NAME); + this.setGeneratedValue(null); + } + + protected JavaGeneratedValue buildGeneratedValue() { + GeneratedValueAnnotation annotation = this.getGeneratedValueAnnotation(); + return (annotation == null) ? null : this.buildGeneratedValue(annotation); + } + + protected GeneratedValueAnnotation getGeneratedValueAnnotation() { + return (GeneratedValueAnnotation) this.getResourcePersistentAttribute().getAnnotation(GeneratedValueAnnotation.ANNOTATION_NAME); + } + + protected JavaGeneratedValue buildGeneratedValue(GeneratedValueAnnotation generatedValueAnnotation) { + return this.getJpaFactory().buildJavaGeneratedValue(this, generatedValueAnnotation); + } + + protected void syncGeneratedValue() { + GeneratedValueAnnotation annotation = this.getGeneratedValueAnnotation(); + if (annotation == null) { + if (this.generatedValue != null) { + this.setGeneratedValue(null); + } + } + else { + if ((this.generatedValue != null) && (this.generatedValue.getGeneratedValueAnnotation() == annotation)) { + this.generatedValue.synchronizeWithResourceModel(); + } else { + this.setGeneratedValue(this.buildGeneratedValue(annotation)); + } + } + } + + protected void setGeneratedValue(JavaGeneratedValue value) { + JavaGeneratedValue old = this.generatedValue; + this.generatedValue = value; + this.firePropertyChanged(GENERATED_VALUE_PROPERTY, old, value); + } + + + // ********** converter ********** + + public JavaConverter getConverter() { + return this.converter; + } + + public void setConverter(Class<? extends Converter> converterType) { + if (this.converter.getType() != converterType) { + this.converter.dispose(); + JavaConverter.Adapter converterAdapter = this.getConverterAdapter(converterType); + this.retainConverterAnnotation(converterAdapter); + this.setConverter_(this.buildConverter(converterAdapter)); + } + } + + protected JavaConverter buildConverter(JavaConverter.Adapter converterAdapter) { + return (converterAdapter != null) ? + converterAdapter.buildNewConverter(this, this.getJpaFactory()) : + this.buildNullConverter(); + } + + protected void setConverter_(JavaConverter converter) { + Converter old = this.converter; + this.converter = converter; + this.firePropertyChanged(CONVERTER_PROPERTY, old, converter); + } + + /** + * Clear all the converter annotations <em>except</em> for the annotation + * corresponding to the specified adapter. If the specified adapter is + * <code>null</code>, remove <em>all</em> the converter annotations. + */ + protected void retainConverterAnnotation(JavaConverter.Adapter converterAdapter) { + JavaResourcePersistentAttribute resourceAttribute = this.getResourcePersistentAttribute(); + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + if (adapter != converterAdapter) { + adapter.removeConverterAnnotation(resourceAttribute); + } + } + } + + protected JavaConverter buildConverter() { + JpaFactory jpaFactory = this.getJpaFactory(); + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + JavaConverter javaConverter = adapter.buildConverter(this, jpaFactory); + if (javaConverter != null) { + return javaConverter; + } + } + return this.buildNullConverter(); + } + + protected void syncConverter() { + Association<JavaConverter.Adapter, Annotation> assoc = this.getConverterAnnotation(); + if (assoc == null) { + if (this.converter.getType() != null) { + this.setConverter_(this.buildNullConverter()); + } + } else { + JavaConverter.Adapter adapter = assoc.getKey(); + Annotation annotation = assoc.getValue(); + if ((this.converter.getType() == adapter.getConverterType()) && + (this.converter.getConverterAnnotation() == annotation)) { + this.converter.synchronizeWithResourceModel(); + } else { + this.setConverter_(adapter.buildConverter(annotation, this, this.getJpaFactory())); + } + } + } + + /** + * Return the first converter annotation we find along with its corresponding + * adapter. Return <code>null</code> if there are no converter annotations. + */ + protected Association<JavaConverter.Adapter, Annotation> getConverterAnnotation() { + JavaResourcePersistentAttribute resourceAttribute = this.getResourcePersistentAttribute(); + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + Annotation annotation = adapter.getConverterAnnotation(resourceAttribute); + if (annotation != null) { + return new SimpleAssociation<JavaConverter.Adapter, Annotation>(adapter, annotation); + } + } + return null; + } + + protected JavaConverter buildNullConverter() { + return new NullJavaConverter(this); + } + + + // ********** converter adapters ********** + + /** + * Return the converter adapter for the specified converter type. + */ + protected JavaConverter.Adapter getConverterAdapter(Class<? extends Converter> converterType) { + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + if (adapter.getConverterType() == converterType) { + return adapter; + } + } + return null; + } + + protected Iterable<JavaConverter.Adapter> getConverterAdapters() { + return CONVERTER_ADAPTERS; + } + + + // ********** mapped by relationship ********** + + public boolean isMappedByRelationship() { + return this.mappedByRelationship; + } + + protected void setMappedByRelationship(boolean mappedByRelationship) { + boolean old = this.mappedByRelationship; + this.mappedByRelationship = mappedByRelationship; + this.firePropertyChanged(MAPPED_BY_RELATIONSHIP_PROPERTY, old, mappedByRelationship); + } + + protected boolean buildMappedByRelationship() { + return this.isJpa2_0Compatible() && this.buildMappedByRelationship_(); + } + + protected boolean buildMappedByRelationship_() { + return CollectionTools.contains(this.getMappedByRelationshipAttributeNames(), this.getName()); + } + + protected Iterable<String> getMappedByRelationshipAttributeNames() { + return TypeMappingTools.getMappedByRelationshipAttributeNames(this.getTypeMapping()); + } + + + // ********** misc ********** + + public String getKey() { + return MappingKeys.ID_ATTRIBUTE_MAPPING_KEY; + } + + @Override + protected String getAnnotationName() { + return IdAnnotation.ANNOTATION_NAME; + } + + @Override + public String getPrimaryKeyColumnName() { + return this.column.getName(); + } + + protected boolean columnIsSpecified() { + return this.getResourcePersistentAttribute().getAnnotation(ColumnAnnotation.ANNOTATION_NAME) != null; + } + + @Override + public boolean isOverridableAttributeMapping() { + return true; + } + + + // ********** JavaGeneratorContainer implementation ********** + + public JavaResourcePersistentMember getResourceAnnotatedElement() { + return this.getResourcePersistentAttribute(); + } + + + // ********** JavaColumn.Owner implementation ********** + + public ColumnAnnotation getColumnAnnotation() { + return (ColumnAnnotation) this.getResourcePersistentAttribute().getNonNullAnnotation(ColumnAnnotation.ANNOTATION_NAME); + } + + public void removeColumnAnnotation() { + this.getResourcePersistentAttribute().removeAnnotation(ColumnAnnotation.ANNOTATION_NAME); + } + + public String getDefaultColumnName() { + return (this.mappedByRelationship && ! this.columnIsSpecified()) ? null : this.getName(); + } + + public String getDefaultTableName() { + return (this.mappedByRelationship && ! this.columnIsSpecified()) ? null : this.getTypeMapping().getPrimaryTableName(); + } + + public boolean tableNameIsInvalid(String tableName) { + return this.getTypeMapping().tableNameIsInvalid(tableName); + } + + public Iterator<String> candidateTableNames() { + return this.getTypeMapping().allAssociatedTableNames(); + } + + public JptValidator buildColumnValidator(NamedColumn column, NamedColumnTextRangeResolver textRangeResolver) { + return new NamedColumnValidator((BaseColumn) column, (BaseColumnTextRangeResolver) textRangeResolver, new EntityTableDescriptionProvider()); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.column.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.generatorContainer.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + if (this.generatedValue != null) { + result = this.generatedValue.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + } + + result = this.converter.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + return null; + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + + // [JPA 2.0] if the column is specified, or if the id is not mapped by a relationship, + // then the column is validated. + // (In JPA 1.0, the column will always be validated, since the id is never mapped by a + // relationship) + if (this.columnIsSpecified() || ! this.mappedByRelationship) { + this.column.validate(messages, reporter, astRoot); + } + + // [JPA 2.0] if the column is specified and the id is mapped by a relationship, + // then that is an error + // (In JPA 1.0, this will never be the case, since the id is never mapped by a relationship) + if (this.columnIsSpecified() && this.mappedByRelationship) { + messages.add( + this.buildMessage( + JpaValidationMessages.ID_MAPPING_MAPPED_BY_RELATIONSHIP_AND_COLUMN_SPECIFIED, + EMPTY_STRING_ARRAY, + this.column.getValidationTextRange(astRoot) + ) + ); + } + + this.generatorContainer.validate(messages, reporter, astRoot); + if (this.generatedValue != null) { + this.generatedValue.validate(messages, reporter, astRoot); + } + this.converter.validate(messages, reporter, astRoot); + } + + protected IMessage buildMessage(String msgID, String[] parms, TextRange textRange) { + String attributeDescription = NLS.bind(JpaValidationDescriptionMessages.ATTRIBUTE_DESC, this.getPersistentAttribute().getName()); + parms = ArrayTools.add(parms, 0, attributeDescription); + return DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + msgID, + parms, + this, + textRange + ); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaIdMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaIdMappingDefinition.java new file mode 100644 index 0000000000..1ba4b92315 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaIdMappingDefinition.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2009, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.ColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.GeneratedValueAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.IdAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.SequenceGeneratorAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.TableGeneratorAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.TemporalAnnotation; + +public abstract class AbstractJavaIdMappingDefinition + implements JavaAttributeMappingDefinition +{ + protected AbstractJavaIdMappingDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.ID_ATTRIBUTE_MAPPING_KEY; + } + + public String getAnnotationName() { + return IdAnnotation.ANNOTATION_NAME; + } + + public boolean isSpecified(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.getResourcePersistentAttribute().getAnnotation(this.getAnnotationName()) != null; + } + + public Iterable<String> getSupportingAnnotationNames() { + return SUPPORTING_ANNOTATION_NAMES; + } + + protected static final String[] SUPPORTING_ANNOTATION_NAMES_ARRAY = new String[] { + ColumnAnnotation.ANNOTATION_NAME, + GeneratedValueAnnotation.ANNOTATION_NAME, + TemporalAnnotation.ANNOTATION_NAME, + TableGeneratorAnnotation.ANNOTATION_NAME, + SequenceGeneratorAnnotation.ANNOTATION_NAME + }; + protected static final Iterable<String> SUPPORTING_ANNOTATION_NAMES = new ArrayIterable<String>(SUPPORTING_ANNOTATION_NAMES_ARRAY); + + public JavaAttributeMapping buildMapping(JavaPersistentAttribute persistentAttribute, JpaFactory factory) { + return factory.buildJavaIdMapping(persistentAttribute); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaJoinColumnRelationshipStrategy.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaJoinColumnRelationshipStrategy.java new file mode 100644 index 0000000000..b133a319f7 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaJoinColumnRelationshipStrategy.java @@ -0,0 +1,348 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Vector; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.SingleElementListIterable; +import org.eclipse.jpt.common.utility.internal.iterators.EmptyIterator; +import org.eclipse.jpt.jpa.core.context.JoinColumn; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinColumn; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinColumnRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinColumnRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinColumnRelationshipStrategy; +import org.eclipse.jpt.jpa.core.internal.context.ContextContainerTools; +import org.eclipse.jpt.jpa.core.resource.java.JoinColumnAnnotation; +import org.eclipse.jpt.jpa.db.Table; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +public abstract class AbstractJavaJoinColumnRelationshipStrategy + extends AbstractJavaJpaContextNode + implements JavaJoinColumnRelationshipStrategy +{ + protected final Vector<JavaJoinColumn> specifiedJoinColumns = new Vector<JavaJoinColumn>(); + protected final SpecifiedJoinColumnContainerAdapter specifiedJoinColumnContainerAdapter; + protected final JavaJoinColumn.Owner joinColumnOwner; + + protected JavaJoinColumn defaultJoinColumn; + + + protected AbstractJavaJoinColumnRelationshipStrategy(JavaJoinColumnRelationship parent) { + super(parent); + this.specifiedJoinColumnContainerAdapter = this.buildSpecifiedJoinColumnContainerAdapter(); + this.joinColumnOwner = this.buildJoinColumnOwner(); + this.initializeSpecifiedJoinColumns(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.syncSpecifiedJoinColumns(); + } + + @Override + public void update() { + super.update(); + this.updateNodes(this.getSpecifiedJoinColumns()); + this.updateDefaultJoinColumn(); + } + + + // ********** join columns ********** + + public ListIterator<JavaJoinColumn> joinColumns() { + return this.getJoinColumns().iterator(); + } + + protected ListIterable<JavaJoinColumn> getJoinColumns() { + return this.hasSpecifiedJoinColumns() ? this.getSpecifiedJoinColumns() : this.getDefaultJoinColumns(); + } + + public int joinColumnsSize() { + return this.hasSpecifiedJoinColumns() ? this.specifiedJoinColumnsSize() : this.getDefaultJoinColumnsSize(); + } + + + // ********** specified join columns ********** + + public ListIterator<JavaJoinColumn> specifiedJoinColumns() { + return this.getSpecifiedJoinColumns().iterator(); + } + + protected ListIterable<JavaJoinColumn> getSpecifiedJoinColumns() { + return new LiveCloneListIterable<JavaJoinColumn>(this.specifiedJoinColumns); + } + + public int specifiedJoinColumnsSize() { + return this.specifiedJoinColumns.size(); + } + + public boolean hasSpecifiedJoinColumns() { + return this.specifiedJoinColumns.size() != 0; + } + + public JavaJoinColumn getSpecifiedJoinColumn(int index) { + return this.specifiedJoinColumns.get(index); + } + + public JavaJoinColumn addSpecifiedJoinColumn() { + return this.addSpecifiedJoinColumn(this.specifiedJoinColumns.size()); + } + + public JavaJoinColumn addSpecifiedJoinColumn(int index) { + JoinColumnAnnotation annotation = this.addJoinColumnAnnotation(index); + return this.addSpecifiedJoinColumn_(index, annotation); + } + + public void removeSpecifiedJoinColumn(JoinColumn joinColumn) { + this.removeSpecifiedJoinColumn(this.specifiedJoinColumns.indexOf(joinColumn)); + } + + public void removeSpecifiedJoinColumn(int index) { + this.removeJoinColumnAnnotation(index); + this.removeSpecifiedJoinColumn_(index); + } + + protected void removeSpecifiedJoinColumn_(int index) { + this.removeItemFromList(index, this.specifiedJoinColumns, SPECIFIED_JOIN_COLUMNS_LIST); + } + + public void moveSpecifiedJoinColumn(int targetIndex, int sourceIndex) { + this.moveJoinColumnAnnotation(targetIndex, sourceIndex); + this.moveItemInList(targetIndex, sourceIndex, this.specifiedJoinColumns, SPECIFIED_JOIN_COLUMNS_LIST); + } + + protected void initializeSpecifiedJoinColumns() { + for (JoinColumnAnnotation joinColumnAnnotation : this.getJoinColumnAnnotations()) { + this.specifiedJoinColumns.add(this.buildJoinColumn(joinColumnAnnotation)); + } + } + + protected void syncSpecifiedJoinColumns() { + ContextContainerTools.synchronizeWithResourceModel(this.specifiedJoinColumnContainerAdapter); + } + + protected Iterable<JoinColumnAnnotation> getJoinColumnAnnotations() { + return CollectionTools.iterable(this.joinColumnAnnotations()); + } + + protected void moveSpecifiedJoinColumn_(int index, JavaJoinColumn joinColumn) { + this.moveItemInList(index, joinColumn, this.specifiedJoinColumns, SPECIFIED_JOIN_COLUMNS_LIST); + } + + protected JavaJoinColumn addSpecifiedJoinColumn_(int index, JoinColumnAnnotation joinColumnAnnotation) { + JavaJoinColumn joinColumn = this.buildJoinColumn(joinColumnAnnotation); + this.addItemToList(index, joinColumn, this.specifiedJoinColumns, SPECIFIED_JOIN_COLUMNS_LIST); + return joinColumn; + } + + protected void removeSpecifiedJoinColumn_(JavaJoinColumn joinColumn) { + this.removeSpecifiedJoinColumn_(this.specifiedJoinColumns.indexOf(joinColumn)); + } + + protected SpecifiedJoinColumnContainerAdapter buildSpecifiedJoinColumnContainerAdapter() { + return new SpecifiedJoinColumnContainerAdapter(); + } + + /** + * specified join column container adapter + */ + protected class SpecifiedJoinColumnContainerAdapter + implements ContextContainerTools.Adapter<JavaJoinColumn, JoinColumnAnnotation> + { + public Iterable<JavaJoinColumn> getContextElements() { + return AbstractJavaJoinColumnRelationshipStrategy.this.getSpecifiedJoinColumns(); + } + public Iterable<JoinColumnAnnotation> getResourceElements() { + return AbstractJavaJoinColumnRelationshipStrategy.this.getJoinColumnAnnotations(); + } + public JoinColumnAnnotation getResourceElement(JavaJoinColumn contextElement) { + return contextElement.getColumnAnnotation(); + } + public void moveContextElement(int index, JavaJoinColumn element) { + AbstractJavaJoinColumnRelationshipStrategy.this.moveSpecifiedJoinColumn_(index, element); + } + public void addContextElement(int index, JoinColumnAnnotation resourceElement) { + AbstractJavaJoinColumnRelationshipStrategy.this.addSpecifiedJoinColumn_(index, resourceElement); + } + public void removeContextElement(JavaJoinColumn element) { + AbstractJavaJoinColumnRelationshipStrategy.this.removeSpecifiedJoinColumn_(element); + } + } + + protected abstract JavaJoinColumn.Owner buildJoinColumnOwner(); + + + // ********** default join column ********** + + public JavaJoinColumn getDefaultJoinColumn() { + return this.defaultJoinColumn; + } + + protected void setDefaultJoinColumn(JavaJoinColumn joinColumn) { + JavaJoinColumn old = this.defaultJoinColumn; + this.defaultJoinColumn = joinColumn; + this.firePropertyChanged(DEFAULT_JOIN_COLUMN_PROPERTY, old, joinColumn); + } + + protected ListIterable<JavaJoinColumn> getDefaultJoinColumns() { + return (this.defaultJoinColumn != null) ? + new SingleElementListIterable<JavaJoinColumn>(this.defaultJoinColumn) : + EmptyListIterable.<JavaJoinColumn>instance(); + } + + protected int getDefaultJoinColumnsSize() { + return (this.defaultJoinColumn == null) ? 0 : 1; + } + + protected void updateDefaultJoinColumn() { + if (this.buildsDefaultJoinColumn()) { + if (this.defaultJoinColumn == null) { + this.setDefaultJoinColumn(this.buildJoinColumn(this.buildNullJoinColumnAnnotation())); + } else { + this.defaultJoinColumn.update(); + } + } else { + this.setDefaultJoinColumn(null); + } + } + + protected boolean buildsDefaultJoinColumn() { + return ! this.hasSpecifiedJoinColumns() && + this.getRelationship().mayHaveDefaultJoinColumn(); + } + + + // ********** join column annotations ********** + + protected abstract Iterator<JoinColumnAnnotation> joinColumnAnnotations(); + + protected abstract JoinColumnAnnotation addJoinColumnAnnotation(int index); + + protected abstract void removeJoinColumnAnnotation(int index); + + protected abstract void moveJoinColumnAnnotation(int targetIndex, int sourceIndex); + + protected abstract JoinColumnAnnotation buildNullJoinColumnAnnotation(); + + + // ********** misc ********** + + @Override + public JavaJoinColumnRelationship getParent() { + return (JavaJoinColumnRelationship) super.getParent(); + } + + public JavaJoinColumnRelationship getRelationship() { + return this.getParent(); + } + + protected JavaJoinColumn buildJoinColumn(JoinColumnAnnotation joinColumnAnnotation) { + return this.getJpaFactory().buildJavaJoinColumn(this, this.joinColumnOwner, joinColumnAnnotation); + } + + public void initializeFrom(ReadOnlyJoinColumnRelationshipStrategy oldStrategy) { + for (ReadOnlyJoinColumn joinColumn : CollectionTools.iterable(oldStrategy.specifiedJoinColumns())) { + this.addSpecifiedJoinColumn().initializeFrom(joinColumn); + } + } + + public void initializeFromVirtual(ReadOnlyJoinColumnRelationshipStrategy virtualStrategy) { + for (ReadOnlyJoinColumn joinColumn : CollectionTools.iterable(virtualStrategy.joinColumns())) { + this.addSpecifiedJoinColumn().initializeFromVirtual(joinColumn); + } + } + + public RelationshipMapping getRelationshipMapping() { + return this.getRelationship().getMapping(); + } + + public String getTableName() { + TypeMapping typeMapping = this.getRelationshipSource(); + return (typeMapping == null) ? null : typeMapping.getPrimaryTableName(); + } + + public Table resolveDbTable(String tableName) { + TypeMapping typeMapping = this.getRelationshipSource(); + return (typeMapping == null) ? null : typeMapping.resolveDbTable(tableName); + } + + public boolean tableNameIsInvalid(String tableName) { + TypeMapping typeMapping = this.getRelationshipSource(); + return (typeMapping != null) && typeMapping.tableNameIsInvalid(tableName); + } + + // subclasses like this to be public + public Table getReferencedColumnDbTable() { + TypeMapping relationshipTarget = this.getRelationshipTarget(); + return (relationshipTarget == null) ? null : relationshipTarget.getPrimaryDbTable(); + } + + protected Iterator<String> candidateTableNames() { + TypeMapping typeMapping = this.getRelationshipSource(); + return (typeMapping != null) ? typeMapping.allAssociatedTableNames() : EmptyIterator.<String>instance(); + } + + public void addStrategy() { + if (this.specifiedJoinColumnsSize() == 0) { + this.addSpecifiedJoinColumn(); + } + } + + public void removeStrategy() { + for (int i = this.specifiedJoinColumns.size(); i-- > 0; ) { + this.removeSpecifiedJoinColumn(i); + } + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + for (JavaJoinColumn joinColumn : this.getJoinColumns()) { + result = joinColumn.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + } + return null; + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + for (JavaJoinColumn joinColumn : this.getJoinColumns()) { + joinColumn.validate(messages, reporter, astRoot); + } + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaJoinTableRelationshipStrategy.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaJoinTableRelationshipStrategy.java new file mode 100644 index 0000000000..6eafead62c --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaJoinTableRelationshipStrategy.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.Tools; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinTable; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.Table; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinTable; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinTableRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.internal.context.MappingTools; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationDescriptionMessages; +import org.eclipse.jpt.jpa.core.resource.java.JoinTableAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +public abstract class AbstractJavaJoinTableRelationshipStrategy + extends AbstractJavaJpaContextNode + implements JavaJoinTableRelationshipStrategy, Table.Owner +{ + protected JavaJoinTable joinTable; + + + protected AbstractJavaJoinTableRelationshipStrategy(JavaJoinTableRelationship parent) { + super(parent); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + if (this.joinTable != null) { + this.joinTable.synchronizeWithResourceModel(); + } + } + + @Override + public void update() { + super.update(); + this.updateJoinTable(); + } + + + // ********** join table ********** + + public JavaJoinTable getJoinTable() { + return this.joinTable; + } + + protected void setJoinTable(JavaJoinTable joinTable) { + JavaJoinTable old = this.joinTable; + this.joinTable = joinTable; + this.firePropertyChanged(JOIN_TABLE_PROPERTY, old, joinTable); + } + + protected void updateJoinTable() { + if (this.buildsJoinTable()) { + if (this.joinTable == null) { + this.setJoinTable(this.buildJoinTable()); + } else { + this.joinTable.update(); + } + } else { + if (this.joinTable != null) { + this.setJoinTable(null); + } + } + } + + /** + * The strategy can have a join table if either the table annotation is present + * or the [mapping] relationship supports a default join table. + */ + protected boolean buildsJoinTable() { + return this.getJoinTableAnnotation().isSpecified() + || this.getRelationship().mayHaveDefaultJoinTable(); + } + + protected JavaJoinTable buildJoinTable() { + return this.getJpaFactory().buildJavaJoinTable(this, this); + } + + + // ********** join table annotation ********** + + protected abstract JoinTableAnnotation addJoinTableAnnotation(); + + protected abstract void removeJoinTableAnnotation(); + + + // ********** misc ********** + + @Override + public JavaJoinTableRelationship getParent() { + return (JavaJoinTableRelationship) super.getParent(); + } + + public JavaJoinTableRelationship getRelationship() { + return this.getParent(); + } + + public RelationshipMapping getRelationshipMapping() { + return this.getRelationship().getMapping(); + } + + public void initializeFrom(ReadOnlyJoinTableRelationshipStrategy oldStrategy) { + ReadOnlyJoinTable oldJoinTable = oldStrategy.getJoinTable(); + if (oldJoinTable != null) { + this.addStrategy(); + this.joinTable.initializeFrom(oldJoinTable); + } + } + + public void initializeFromVirtual(ReadOnlyJoinTableRelationshipStrategy virtualStrategy) { + ReadOnlyJoinTable oldJoinTable = virtualStrategy.getJoinTable(); + if (oldJoinTable != null) { + this.addStrategy(); + this.joinTable.initializeFromVirtual(oldJoinTable); + } + } + + public String getTableName() { + return (this.joinTable == null) ? null : this.joinTable.getName(); + } + + public org.eclipse.jpt.jpa.db.Table resolveDbTable(String tableName) { + return (this.joinTable == null) ? null : this.joinTable.getDbTable(); + } + + public boolean tableNameIsInvalid(String tableName) { + return Tools.valuesAreDifferent(this.getTableName(), tableName); + } + + public String getColumnTableNotValidDescription() { + return JpaValidationDescriptionMessages.DOES_NOT_MATCH_JOIN_TABLE; + } + + public String getJoinTableDefaultName() { + return MappingTools.buildJoinTableDefaultName(this.getRelationship()); + } + + public void addStrategy() { + if (this.joinTable == null) { + this.addJoinTableAnnotation(); + this.setJoinTable(this.buildJoinTable()); + } + } + + public void removeStrategy() { + if (this.joinTable != null) { + this.removeJoinTableAnnotation(); + this.setJoinTable(null); + } + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + if (this.joinTable != null) { + result = this.joinTable.javaCompletionProposals(pos, filter, astRoot); + } + return result; + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + if (this.joinTable != null) { + this.joinTable.validate(messages, reporter, astRoot); + } + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaJpaContextNode.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaJpaContextNode.java new file mode 100644 index 0000000000..92643cc26a --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaJpaContextNode.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.JptCommonCorePlugin; +import org.eclipse.jpt.common.core.JptResourceType; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.jpa.core.context.JpaContextNode; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; +import org.eclipse.jpt.jpa.core.internal.context.AbstractJpaContextNode; +import org.eclipse.jst.j2ee.model.internal.validation.ValidationCancelledException; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +public abstract class AbstractJavaJpaContextNode + extends AbstractJpaContextNode + implements JavaJpaContextNode +{ + protected AbstractJavaJpaContextNode(JpaContextNode parent) { + super(parent); + } + + @Override + public JptResourceType getResourceType() { + return JptCommonCorePlugin.JAVA_SOURCE_RESOURCE_TYPE; + } + + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + if (this.connectionProfileIsActive()) { + Iterator<String> result = this.connectedJavaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + } + return null; + } + + /** + * This method is called if the database is connected, allowing us to + * get candidates from the various database tables etc. + * This method should NOT be cascaded to "child" objects; it should + * only return candidates for the current object. The cascading is + * handled by #javaCompletionProposals(int, Filter, CompilationUnit). + */ + @SuppressWarnings("unused") + public Iterator<String> connectedJavaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + return null; + } + + // ********** validation ********** + + /** + * All subclass implementations + * should be preceded by a "super" call to this method. + */ + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + if (reporter.isCancelled()) { + throw new ValidationCancelledException(); + } + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToManyMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToManyMapping.java new file mode 100644 index 0000000000..22c5d8c9e3 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToManyMapping.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2006, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaManyToManyRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaMappingRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaManyToManyMapping2_0; +import org.eclipse.jpt.jpa.core.resource.java.ManyToManyAnnotation; + +public abstract class AbstractJavaManyToManyMapping + extends AbstractJavaMultiRelationshipMapping<ManyToManyAnnotation> + implements JavaManyToManyMapping2_0 +{ + protected AbstractJavaManyToManyMapping(JavaPersistentAttribute parent) { + super(parent); + } + + + // ********** relationship ********** + + @Override + public JavaManyToManyRelationship getRelationship() { + return (JavaManyToManyRelationship) super.getRelationship(); + } + + @Override + protected JavaMappingRelationship buildRelationship() { + return new GenericJavaManyToManyRelationship(this); + } + + + // ********** misc ********** + + public String getKey() { + return MappingKeys.MANY_TO_MANY_ATTRIBUTE_MAPPING_KEY; + } + + @Override + protected String getAnnotationName() { + return ManyToManyAnnotation.ANNOTATION_NAME; + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToManyMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToManyMappingDefinition.java new file mode 100644 index 0000000000..9677d6b81e --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToManyMappingDefinition.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.JoinTableAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.ManyToManyAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.MapKeyAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.OrderByAnnotation; + +public abstract class AbstractJavaManyToManyMappingDefinition + implements JavaAttributeMappingDefinition +{ + protected AbstractJavaManyToManyMappingDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.MANY_TO_MANY_ATTRIBUTE_MAPPING_KEY; + } + + public String getAnnotationName() { + return ManyToManyAnnotation.ANNOTATION_NAME; + } + + public boolean isSpecified(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.getResourcePersistentAttribute().getAnnotation(this.getAnnotationName()) != null; + } + + public Iterable<String> getSupportingAnnotationNames() { + return SUPPORTING_ANNOTATION_NAMES; + } + + protected static final String[] SUPPORTING_ANNOTATION_NAMES_ARRAY = new String[] { + JoinTableAnnotation.ANNOTATION_NAME, + MapKeyAnnotation.ANNOTATION_NAME, + OrderByAnnotation.ANNOTATION_NAME + }; + protected static final Iterable<String> SUPPORTING_ANNOTATION_NAMES = new ArrayIterable<String>(SUPPORTING_ANNOTATION_NAMES_ARRAY); + + public JavaAttributeMapping buildMapping(JavaPersistentAttribute persistentAttribute, JpaFactory factory) { + return factory.buildJavaManyToManyMapping(persistentAttribute); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToOneMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToOneMapping.java new file mode 100644 index 0000000000..42a93b9b37 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToOneMapping.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2006, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaManyToOneRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaManyToOneMapping2_0; +import org.eclipse.jpt.jpa.core.resource.java.ManyToOneAnnotation; + +public abstract class AbstractJavaManyToOneMapping + extends AbstractJavaSingleRelationshipMapping<ManyToOneAnnotation> + implements JavaManyToOneMapping2_0 +{ + protected AbstractJavaManyToOneMapping(JavaPersistentAttribute parent) { + super(parent); + } + + + // ********** relationship ********** + + @Override + public JavaManyToOneRelationship getRelationship() { + return (JavaManyToOneRelationship) super.getRelationship(); + } + + @Override + protected JavaManyToOneRelationship buildRelationship() { + return new GenericJavaManyToOneRelationship(this); + } + + + // ********** misc ********** + + public String getKey() { + return MappingKeys.MANY_TO_ONE_ATTRIBUTE_MAPPING_KEY; + } + + @Override + protected String getAnnotationName() { + return ManyToOneAnnotation.ANNOTATION_NAME; + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToOneMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToOneMappingDefinition.java new file mode 100644 index 0000000000..9534ff5126 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaManyToOneMappingDefinition.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.JoinColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JoinColumnsAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JoinTableAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.ManyToOneAnnotation; + +public abstract class AbstractJavaManyToOneMappingDefinition + implements JavaAttributeMappingDefinition +{ + protected AbstractJavaManyToOneMappingDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.MANY_TO_ONE_ATTRIBUTE_MAPPING_KEY; + } + + public String getAnnotationName() { + return ManyToOneAnnotation.ANNOTATION_NAME; + } + + public boolean isSpecified(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.getResourcePersistentAttribute().getAnnotation(this.getAnnotationName()) != null; + } + + public Iterable<String> getSupportingAnnotationNames() { + return SUPPORTING_ANNOTATION_NAMES; + } + + protected static final String[] SUPPORTING_ANNOTATION_NAMES_ARRAY = new String[] { + JoinTableAnnotation.ANNOTATION_NAME, + JoinColumnAnnotation.ANNOTATION_NAME, + JoinColumnsAnnotation.ANNOTATION_NAME + }; + protected static final Iterable<String> SUPPORTING_ANNOTATION_NAMES = new ArrayIterable<String>(SUPPORTING_ANNOTATION_NAMES_ARRAY); + + public JavaAttributeMapping buildMapping(JavaPersistentAttribute persistentAttribute, JpaFactory factory) { + return factory.buildJavaManyToOneMapping(persistentAttribute); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaMappedSuperclass.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaMappedSuperclass.java new file mode 100644 index 0000000000..b4255f5a56 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaMappedSuperclass.java @@ -0,0 +1,112 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaIdClassReference; +import org.eclipse.jpt.jpa.core.context.java.JavaMappedSuperclass; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.PrimaryKeyTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.GenericMappedSuperclassPrimaryKeyValidator; +import org.eclipse.jpt.jpa.core.resource.java.MappedSuperclassAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java mapped superclass + */ +public abstract class AbstractJavaMappedSuperclass + extends AbstractJavaTypeMapping<MappedSuperclassAnnotation> + implements JavaMappedSuperclass +{ + protected final JavaIdClassReference idClassReference; + + + protected AbstractJavaMappedSuperclass(JavaPersistentType parent, MappedSuperclassAnnotation mappingAnnotation) { + super(parent, mappingAnnotation); + this.idClassReference = this.buildIdClassReference(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.idClassReference.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + this.idClassReference.update(); + } + + + // ********** id class ********** + + public JavaIdClassReference getIdClassReference() { + return this.idClassReference; + } + + protected JavaIdClassReference buildIdClassReference() { + return new GenericJavaIdClassReference(this); + } + + public JavaPersistentType getIdClass() { + return this.idClassReference.getIdClass(); + } + + + // ********** misc ********** + + public String getKey() { + return MappingKeys.MAPPED_SUPERCLASS_TYPE_MAPPING_KEY; + } + + public boolean isMapped() { + return true; + } + + public boolean tableNameIsInvalid(String tableName) { + return false; + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.validatePrimaryKey(messages, reporter, astRoot); + } + + @Override + public boolean validatesAgainstDatabase() { + return false; + } + + protected void validatePrimaryKey(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + this.buildPrimaryKeyValidator(astRoot).validate(messages, reporter); + } + + protected JptValidator buildPrimaryKeyValidator(CompilationUnit astRoot) { + return new GenericMappedSuperclassPrimaryKeyValidator(this, this.buildTextRangeResolver(astRoot)); + // TODO - JPA 2.0 validation + } + + @Override + protected PrimaryKeyTextRangeResolver buildTextRangeResolver(CompilationUnit astRoot) { + return new JavaMappedSuperclassTextRangeResolver(this, astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaMappingRelationship.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaMappingRelationship.java new file mode 100644 index 0000000000..852474ce29 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaMappingRelationship.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.Entity; +import org.eclipse.jpt.jpa.core.context.MappedByRelationship; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinColumnRelationship; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinTableRelationship; +import org.eclipse.jpt.jpa.core.context.ReadOnlyRelationship; +import org.eclipse.jpt.jpa.core.context.RelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaMappingRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaRelationshipMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaRelationshipStrategy; + +/** + * <strong>NB:</strong> Subclasses may want to set the {@link #strategy} at the + * end of their constructors; otherwise, it will be <code>null</code> until it + * is set during {@link #update()}. + */ +public abstract class AbstractJavaMappingRelationship<M extends JavaRelationshipMapping> + extends AbstractJavaJpaContextNode + implements JavaMappingRelationship +{ + protected JavaRelationshipStrategy strategy; + + + public AbstractJavaMappingRelationship(M parent) { + super(parent); + } + + + // ********** synchronize/update ********** + + @Override + public void update() { + super.update(); + this.updateStrategy(); + } + + + // ********** strategy ********** + + public JavaRelationshipStrategy getStrategy() { + return this.strategy; + } + + protected void setStrategy(JavaRelationshipStrategy strategy) { + RelationshipStrategy old = this.strategy; + this.strategy = strategy; + this.firePropertyChanged(STRATEGY_PROPERTY, old, strategy); + } + + protected abstract JavaRelationshipStrategy buildStrategy(); + + /** + * This is called by subclasses when the various supported strategies are + * added or removed; allowing the strategy to be set synchronously. (?) + */ + protected void updateStrategy() { + this.setStrategy(this.buildStrategy()); + } + + + // ********** conversions ********** + + public void initializeFrom(ReadOnlyRelationship oldRelationship) { + oldRelationship.initializeOn(this); + } + + public void initializeFromMappedByRelationship(MappedByRelationship oldRelationship) { + // NOP + } + + public void initializeFromJoinTableRelationship(ReadOnlyJoinTableRelationship oldRelationship) { + // NOP + } + + public void initializeFromJoinColumnRelationship(ReadOnlyJoinColumnRelationship oldRelationship) { + // NOP + } + + + // ********** misc ********** + + @Override + @SuppressWarnings("unchecked") + public M getParent() { + return (M) super.getParent(); + } + + public JavaRelationshipMapping getMapping() { + return this.getParent(); + } + + public TypeMapping getTypeMapping() { + return this.getMapping().getTypeMapping(); + } + + public Entity getEntity() { + TypeMapping typeMapping = this.getTypeMapping(); + return (typeMapping instanceof Entity) ? (Entity) typeMapping : null; + } + + public boolean isOverridable() { + return this.strategy.isOverridable(); + } + + public boolean isVirtual() { + return this.getMapping().getPersistentAttribute().isVirtual(); + } + + public boolean isTargetForeignKey() { + return false; + } + + + // ********** validation ********** + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return this.getMapping().getValidationTextRange(astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaMultiRelationshipMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaMultiRelationshipMapping.java new file mode 100644 index 0000000000..bb0e245fe8 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaMultiRelationshipMapping.java @@ -0,0 +1,780 @@ +/******************************************************************************* + * Copyright (c) 2006, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.Tools; +import org.eclipse.jpt.common.utility.internal.iterators.EmptyIterator; +import org.eclipse.jpt.common.utility.internal.iterators.FilteringIterator; +import org.eclipse.jpt.jpa.core.context.AttributeOverride; +import org.eclipse.jpt.jpa.core.context.AttributeOverrideContainer; +import org.eclipse.jpt.jpa.core.context.BaseColumn; +import org.eclipse.jpt.jpa.core.context.Column; +import org.eclipse.jpt.jpa.core.context.Embeddable; +import org.eclipse.jpt.jpa.core.context.Entity; +import org.eclipse.jpt.jpa.core.context.FetchType; +import org.eclipse.jpt.jpa.core.context.NamedColumn; +import org.eclipse.jpt.jpa.core.context.OverrideContainer; +import org.eclipse.jpt.jpa.core.context.Override_; +import org.eclipse.jpt.jpa.core.context.RelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeOverrideContainer; +import org.eclipse.jpt.jpa.core.context.java.JavaColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaMultiRelationshipMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaOrderable; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.java.JavaRelationshipStrategy; +import org.eclipse.jpt.jpa.core.internal.context.BaseColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.MappingTools; +import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.OverrideTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.EmbeddableOverrideDescriptionProvider; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.MapKeyAttributeOverrideColumnValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.MapKeyAttributeOverrideValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.MapKeyColumnValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.RelationshipStrategyTableDescriptionProvider; +import org.eclipse.jpt.jpa.core.internal.jpa2.context.java.NullJavaMapKeyColumn2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.Orderable2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaCollectionMapping2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaPersistentAttribute2_0; +import org.eclipse.jpt.jpa.core.jpa2.resource.java.MapKeyClass2_0Annotation; +import org.eclipse.jpt.jpa.core.jpa2.resource.java.MapKeyColumn2_0Annotation; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentMember; +import org.eclipse.jpt.jpa.core.resource.java.MapKeyAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.RelationshipMappingAnnotation; +import org.eclipse.jpt.jpa.db.Table; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java multi-relationship (m:m, 1:m) mapping + */ +public abstract class AbstractJavaMultiRelationshipMapping<A extends RelationshipMappingAnnotation> + extends AbstractJavaRelationshipMapping<A> + implements JavaMultiRelationshipMapping, JavaCollectionMapping2_0 +{ + protected final JavaOrderable orderable; + + protected String specifiedMapKey; + protected boolean noMapKey = false; + protected boolean pkMapKey = false; + protected boolean customMapKey = false; + + protected String specifiedMapKeyClass; + protected String defaultMapKeyClass; + protected String fullyQualifiedMapKeyClass; + + protected Type valueType; + protected Type keyType; + + protected final JavaColumn mapKeyColumn; + + protected final JavaAttributeOverrideContainer mapKeyAttributeOverrideContainer; + + + protected AbstractJavaMultiRelationshipMapping(JavaPersistentAttribute parent) { + super(parent); + this.orderable = this.buildOrderable(); + + this.specifiedMapKey = this.buildSpecifiedMapKey(); + this.noMapKey = this.buildNoMapKey(); + this.pkMapKey = this.buildPkMapKey(); + this.customMapKey = this.buildCustomMapKey(); + + this.specifiedMapKeyClass = this.buildSpecifiedMapKeyClass(); + + this.mapKeyColumn = this.buildMapKeyColumn(); + this.mapKeyAttributeOverrideContainer = this.buildMapKeyAttributeOverrideContainer(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.orderable.synchronizeWithResourceModel(); + + this.setSpecifiedMapKey_(this.buildSpecifiedMapKey()); + this.setNoMapKey_(this.buildNoMapKey()); + this.setPkMapKey_(this.buildPkMapKey()); + this.setCustomMapKey_(this.buildCustomMapKey()); + + this.setSpecifiedMapKeyClass_(this.buildSpecifiedMapKeyClass()); + + this.mapKeyColumn.synchronizeWithResourceModel(); + + this.mapKeyAttributeOverrideContainer.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + + this.orderable.update(); + + this.setDefaultMapKeyClass(this.buildDefaultMapKeyClass()); + this.setFullyQualifiedMapKeyClass(this.buildFullyQualifiedMapKeyClass()); + + this.setValueType(this.buildValueType()); + this.setKeyType(this.buildKeyType()); + + this.mapKeyColumn.update(); + + this.mapKeyAttributeOverrideContainer.update(); + } + + + // ********** orderable ********** + + public JavaOrderable getOrderable() { + return this.orderable; + } + + protected JavaOrderable buildOrderable() { + return this.isJpa2_0Compatible() ? + this.getJpaFactory2_0().buildJavaOrderable(this, this.buildOrderableOwner()) : + this.getJpaFactory().buildJavaOrderable(this); + } + + protected Orderable2_0.Owner buildOrderableOwner() { + return new OrderableOwner(); + } + + protected class OrderableOwner + implements Orderable2_0.Owner + { + public String getTableName() { + return this.getRelationshipStrategy().getTableName(); + } + public Table resolveDbTable(String tableName) { + return this.getRelationshipStrategy().resolveDbTable(tableName); + } + protected JavaRelationshipStrategy getRelationshipStrategy() { + return AbstractJavaMultiRelationshipMapping.this.getRelationship().getStrategy(); + } + } + + + // ********** map key ********** + + public String getMapKey() { + if (this.noMapKey) { + return null; + } + if (this.pkMapKey) { + return this.getTargetEntityIdAttributeName(); + } + if (this.customMapKey) { + return this.specifiedMapKey; + } + throw new IllegalStateException("unknown map key"); //$NON-NLS-1$ + } + + + // ********** specified map key ********** + + public String getSpecifiedMapKey() { + return this.specifiedMapKey; + } + + public void setSpecifiedMapKey(String mapKey) { + if (mapKey != null) { + this.getMapKeyAnnotationForUpdate().setName(mapKey); + + this.setSpecifiedMapKey_(mapKey); + this.setNoMapKey_(false); + this.setPkMapKey_(false); + this.setCustomMapKey_(true); + } else { + this.setPkMapKey(true); // hmmm... + } + } + + protected void setSpecifiedMapKey_(String mapKey) { + String old = this.specifiedMapKey; + this.specifiedMapKey = mapKey; + this.firePropertyChanged(SPECIFIED_MAP_KEY_PROPERTY, old, mapKey); + } + + protected String buildSpecifiedMapKey() { + MapKeyAnnotation mapKeyAnnotation = this.getMapKeyAnnotation(); + return (mapKeyAnnotation == null) ? null : mapKeyAnnotation.getName(); + } + + + // ********** no map key ********** + + public boolean isNoMapKey() { + return this.noMapKey; + } + + public void setNoMapKey(boolean noMapKey) { + if (noMapKey) { + if (this.getMapKeyAnnotation() != null) { + this.removeMapKeyAnnotation(); + } + + this.setSpecifiedMapKey_(null); + this.setNoMapKey_(true); + this.setPkMapKey_(false); + this.setCustomMapKey_(false); + } else { + this.setPkMapKey(true); // hmmm... + } + } + + protected void setNoMapKey_(boolean noMapKey) { + boolean old = this.noMapKey; + this.noMapKey = noMapKey; + this.firePropertyChanged(NO_MAP_KEY_PROPERTY, old, noMapKey); + } + + protected boolean buildNoMapKey() { + return this.getMapKeyAnnotation() == null; + } + + + // ********** pk map key ********** + + public boolean isPkMapKey() { + return this.pkMapKey; + } + + public void setPkMapKey(boolean pkMapKey) { + if (pkMapKey) { + MapKeyAnnotation mapKeyAnnotation = this.getMapKeyAnnotation(); + if (mapKeyAnnotation == null) { + mapKeyAnnotation = this.addMapKeyAnnotation(); + } else { + mapKeyAnnotation.setName(null); + } + + this.setSpecifiedMapKey_(null); + this.setNoMapKey_(false); + this.setPkMapKey_(true); + this.setCustomMapKey_(false); + } else { + this.setNoMapKey(true); // hmmm... + } + } + + protected void setPkMapKey_(boolean pkMapKey) { + boolean old = this.pkMapKey; + this.pkMapKey = pkMapKey; + this.firePropertyChanged(PK_MAP_KEY_PROPERTY, old, pkMapKey); + } + + protected boolean buildPkMapKey() { + MapKeyAnnotation mapKeyAnnotation = this.getMapKeyAnnotation(); + return (mapKeyAnnotation != null) && (mapKeyAnnotation.getName() == null); + } + + + // ********** custom map key ********** + + public boolean isCustomMapKey() { + return this.customMapKey; + } + + public void setCustomMapKey(boolean customMapKey) { + if (customMapKey) { + this.setSpecifiedMapKey(""); //$NON-NLS-1$ + } else { + this.setNoMapKey(true); // hmmm... + } + } + + protected void setCustomMapKey_(boolean customMapKey) { + boolean old = this.customMapKey; + this.customMapKey = customMapKey; + this.firePropertyChanged(CUSTOM_MAP_KEY_PROPERTY, old, customMapKey); + } + + protected boolean buildCustomMapKey() { + MapKeyAnnotation mapKeyAnnotation = this.getMapKeyAnnotation(); + return (mapKeyAnnotation != null) && (mapKeyAnnotation.getName() != null); + } + + + // ********** map key annotation ********** + + protected MapKeyAnnotation getMapKeyAnnotation() { + return (MapKeyAnnotation) this.getResourcePersistentAttribute().getAnnotation(MapKeyAnnotation.ANNOTATION_NAME); + } + + protected MapKeyAnnotation getMapKeyAnnotationForUpdate() { + MapKeyAnnotation mapKeyAnnotation = this.getMapKeyAnnotation(); + return (mapKeyAnnotation != null) ? mapKeyAnnotation : this.addMapKeyAnnotation(); + } + + protected MapKeyAnnotation addMapKeyAnnotation() { + return (MapKeyAnnotation) this.getResourcePersistentAttribute().addAnnotation(MapKeyAnnotation.ANNOTATION_NAME); + } + + protected void removeMapKeyAnnotation() { + this.getResourcePersistentAttribute().removeAnnotation(MapKeyAnnotation.ANNOTATION_NAME); + } + + + // ********** map key class ********** + + public String getMapKeyClass() { + return (this.specifiedMapKeyClass != null) ? this.specifiedMapKeyClass : this.defaultMapKeyClass; + } + + public String getSpecifiedMapKeyClass() { + return this.specifiedMapKeyClass; + } + + public void setSpecifiedMapKeyClass(String mapKeyClass) { + if (this.valuesAreDifferent(mapKeyClass, this.specifiedMapKeyClass)) { + MapKeyClass2_0Annotation annotation = this.getMapKeyClassAnnotation(); + if (mapKeyClass == null) { + if (annotation != null) { + this.removeMapKeyClassAnnotation(); + } + } else { + if (annotation == null) { + annotation = this.addMapKeyClassAnnotation(); + } + annotation.setValue(mapKeyClass); + } + + this.setSpecifiedMapKeyClass_(mapKeyClass); + } + } + + protected void setSpecifiedMapKeyClass_(String mapKeyClass) { + String old = this.specifiedMapKeyClass; + this.specifiedMapKeyClass = mapKeyClass; + this.firePropertyChanged(SPECIFIED_MAP_KEY_CLASS_PROPERTY, old, mapKeyClass); + } + + protected String buildSpecifiedMapKeyClass() { + MapKeyClass2_0Annotation annotation = this.getMapKeyClassAnnotation(); + return (annotation == null) ? null : annotation.getValue(); + } + + public String getDefaultMapKeyClass() { + return this.defaultMapKeyClass; + } + + protected void setDefaultMapKeyClass(String mapKeyClass) { + String old = this.defaultMapKeyClass; + this.defaultMapKeyClass = mapKeyClass; + this.firePropertyChanged(DEFAULT_MAP_KEY_CLASS_PROPERTY, old, mapKeyClass); + } + + protected String buildDefaultMapKeyClass() { + return this.isJpa2_0Compatible() ? this.getPersistentAttribute().getMultiReferenceMapKeyTypeName() : null; + } + + public String getFullyQualifiedMapKeyClass() { + return this.fullyQualifiedMapKeyClass; + } + + protected void setFullyQualifiedMapKeyClass(String mapKeyClass) { + String old = this.fullyQualifiedMapKeyClass; + this.fullyQualifiedMapKeyClass = mapKeyClass; + this.firePropertyChanged(FULLY_QUALIFIED_MAP_KEY_CLASS_PROPERTY, old, mapKeyClass); + } + + protected String buildFullyQualifiedMapKeyClass() { + return this.isJpa2_0Compatible() ? this.buildFullyQualifiedMapKeyClass_() : null; + } + + protected String buildFullyQualifiedMapKeyClass_() { + return (this.specifiedMapKeyClass == null) ? + this.defaultMapKeyClass : + this.getMapKeyClassAnnotation().getFullyQualifiedClassName(); + } + + public char getMapKeyClassEnclosingTypeSeparator() { + return '.'; + } + + + // ********** resolved map key embeddable/entity ********** + + protected Embeddable getResolvedMapKeyEmbeddable() { + return this.getPersistenceUnit().getEmbeddable(this.fullyQualifiedMapKeyClass); + } + + protected Entity getResolvedMapKeyEntity() { + return this.getPersistenceUnit().getEntity(this.fullyQualifiedMapKeyClass); + } + + + // ********** map key class annotation ********** + + protected MapKeyClass2_0Annotation getMapKeyClassAnnotation() { + return this.isJpa2_0Compatible() ? this.getMapKeyClassAnnotation_() : null; + } + + protected MapKeyClass2_0Annotation getMapKeyClassAnnotation_() { + return (MapKeyClass2_0Annotation) this.getResourcePersistentAttribute().getAnnotation(MapKeyClass2_0Annotation.ANNOTATION_NAME); + } + + protected MapKeyClass2_0Annotation addMapKeyClassAnnotation() { + return (MapKeyClass2_0Annotation) this.getResourcePersistentAttribute().addAnnotation(MapKeyClass2_0Annotation.ANNOTATION_NAME); + } + + protected void removeMapKeyClassAnnotation() { + this.getResourcePersistentAttribute().removeAnnotation(MapKeyClass2_0Annotation.ANNOTATION_NAME); + } + + + // ********** value type ********** + + public Type getValueType() { + return this.valueType; + } + + protected void setValueType(Type valueType) { + Type old = this.valueType; + this.valueType = valueType; + this.firePropertyChanged(VALUE_TYPE_PROPERTY, old, valueType); + } + + protected Type buildValueType() { + if (this.getResolvedTargetEntity() != null) { + return Type.ENTITY_TYPE; + } + if (this.getResolvedTargetEmbeddable() != null) { + return Type.EMBEDDABLE_TYPE; + } + if (this.getTargetEntity() == null) { + return Type.NO_TYPE; + } + return Type.BASIC_TYPE; + } + + protected Embeddable getResolvedTargetEmbeddable() { + return this.getPersistenceUnit().getEmbeddable(this.fullyQualifiedTargetEntity); + } + + + // ********** key type ********** + + public Type getKeyType() { + return this.keyType; + } + + protected void setKeyType(Type keyType) { + Type old = this.keyType; + this.keyType = keyType; + this.firePropertyChanged(KEY_TYPE_PROPERTY, old, keyType); + } + + protected Type buildKeyType() { + if (this.getResolvedMapKeyEmbeddable() != null) { + return Type.EMBEDDABLE_TYPE; + } + if (this.getResolvedMapKeyEntity() != null) { + return Type.ENTITY_TYPE; + } + if (this.getMapKeyClass() == null) { + return Type.NO_TYPE; + } + return Type.BASIC_TYPE; + } + + + // ********** map key column ********** + + public JavaColumn getMapKeyColumn() { + return this.mapKeyColumn; + } + + protected JavaColumn buildMapKeyColumn() { + return this.isJpa2_0Compatible() ? + this.getJpaFactory2_0().buildJavaMapKeyColumn(this, this.buildMapKeyColumnOwner()) : + new NullJavaMapKeyColumn2_0(this); + } + + protected JavaColumn.Owner buildMapKeyColumnOwner() { + return new MapKeyColumnOwner(); + } + + protected MapKeyColumn2_0Annotation getMapKeyColumnAnnotation() { + return this.isJpa2_0Compatible() ? this.getMapKeyColumnAnnotation_() : null; + } + + protected MapKeyColumn2_0Annotation getMapKeyColumnAnnotation_() { + return (MapKeyColumn2_0Annotation) this.getResourcePersistentAttribute().getNonNullAnnotation(MapKeyColumn2_0Annotation.ANNOTATION_NAME); + } + + protected void removeMapKeyColumnAnnotation() { + if (this.isJpa2_0Compatible()) { + this.removeMapKeyColumnAnnotation_(); + } else { + throw new IllegalStateException(); + } + } + + protected void removeMapKeyColumnAnnotation_() { + this.getResourcePersistentAttribute().removeAnnotation(MapKeyColumn2_0Annotation.ANNOTATION_NAME); + } + + + // ********** map key attribute override container ********** + + public JavaAttributeOverrideContainer getMapKeyAttributeOverrideContainer() { + return this.mapKeyAttributeOverrideContainer; + } + + public JavaAttributeOverrideContainer buildMapKeyAttributeOverrideContainer() { + return this.getJpaFactory().buildJavaAttributeOverrideContainer(this, this.buildMapKeyAttributeOverrideContainerOwner()); + } + + protected JavaAttributeOverrideContainer.Owner buildMapKeyAttributeOverrideContainerOwner() { + return new MapKeyAttributeOverrideContainerOwner(); + } + + + // ********** misc ********** + + @Override + protected String buildDefaultTargetEntity() { + return this.getPersistentAttribute().getMultiReferenceTargetTypeName(); + } + + @Override + protected FetchType buildDefaultFetch() { + return DEFAULT_FETCH_TYPE; + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.orderable.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + if (this.mapKeyNameTouches(pos, astRoot)) { + return this.javaCandidateMapKeyNames(filter); + } + + result = this.mapKeyColumn.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.mapKeyAttributeOverrideContainer.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + return null; + } + + protected boolean mapKeyNameTouches(int pos, CompilationUnit astRoot) { + MapKeyAnnotation mapKeyAnnotation = this.getMapKeyAnnotation(); + return (mapKeyAnnotation != null) && mapKeyAnnotation.nameTouches(pos, astRoot); + } + + protected Iterator<String> javaCandidateMapKeyNames(Filter<String> filter) { + return StringTools.convertToJavaStringLiterals(this.candidateMapKeyNames(filter)); + } + + protected Iterator<String> candidateMapKeyNames(Filter<String> filter) { + return new FilteringIterator<String>(this.candidateMapKeyNames(), filter); + } + + public Iterator<String> candidateMapKeyNames() { + return this.allTargetEntityAttributeNames(); + } + + + // ********** metamodel ********** + + @Override + protected String getMetamodelFieldTypeName() { + return ((JavaPersistentAttribute2_0) this.getPersistentAttribute()).getMetamodelContainerFieldTypeName(); + } + + @Override + protected void addMetamodelFieldTypeArgumentNamesTo(ArrayList<String> typeArgumentNames) { + this.addMetamodelFieldMapKeyTypeArgumentNameTo(typeArgumentNames); + super.addMetamodelFieldTypeArgumentNamesTo(typeArgumentNames); + } + + protected void addMetamodelFieldMapKeyTypeArgumentNameTo(ArrayList<String> typeArgumentNames) { + String keyTypeName = ((JavaPersistentAttribute2_0) this.getPersistentAttribute()).getMetamodelContainerFieldMapKeyTypeName(); + if (keyTypeName != null) { + typeArgumentNames.add(keyTypeName); + } + } + + public String getMetamodelFieldMapKeyTypeName() { + return MappingTools.getMetamodelFieldMapKeyTypeName(this); + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.orderable.validate(messages, reporter, astRoot); + this.validateMapKey(messages, reporter, astRoot); + } + + protected void validateMapKey(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + if (this.getMapKeyAnnotation() != null) {//If MapKey annotation specified, no other MapKey* annotations can be specified, don't validate them + //TODO validate that the map key refers to an existing attribute + return; + } + if (this.getKeyType() == Type.BASIC_TYPE) { + this.mapKeyColumn.validate(messages, reporter, astRoot); + //validate map key converter + } + else if (this.getKeyType() == Type.ENTITY_TYPE) { + //validate map key join columns + } + else if (this.getKeyType() == Type.EMBEDDABLE_TYPE) { + this.mapKeyAttributeOverrideContainer.validate(messages, reporter, astRoot); + //validate map key association overrides - for eclipselink + } + } + + + // ********** abstract owner ********** + + /** + * some common behavior + */ + protected abstract class AbstractOwner + { + public TypeMapping getTypeMapping() { + return AbstractJavaMultiRelationshipMapping.this.getTypeMapping(); + } + + public String getDefaultTableName() { + return this.getRelationshipStrategy().getTableName(); + } + + public Table resolveDbTable(String tableName) { + return this.getRelationshipStrategy().resolveDbTable(tableName); + } + + public Iterator<String> candidateTableNames() { + return EmptyIterator.instance(); + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return AbstractJavaMultiRelationshipMapping.this.getValidationTextRange(astRoot); + } + + protected RelationshipStrategy getRelationshipStrategy() { + return AbstractJavaMultiRelationshipMapping.this.getRelationship().getStrategy(); + } + } + + + // ********** map key column owner ********** + + protected class MapKeyColumnOwner + extends AbstractOwner + implements JavaColumn.Owner + { + public MapKeyColumn2_0Annotation getColumnAnnotation() { + return AbstractJavaMultiRelationshipMapping.this.getMapKeyColumnAnnotation(); + } + + public void removeColumnAnnotation() { + AbstractJavaMultiRelationshipMapping.this.removeMapKeyColumnAnnotation(); + } + + public String getDefaultColumnName() { + return AbstractJavaMultiRelationshipMapping.this.getName() + "_KEY"; //$NON-NLS-1$ + } + + public boolean tableNameIsInvalid(String tableName) { + return this.getRelationshipStrategy().tableNameIsInvalid(tableName); + } + + public JptValidator buildColumnValidator(NamedColumn column, NamedColumnTextRangeResolver textRangeResolver) { + return new MapKeyColumnValidator((BaseColumn) column, (BaseColumnTextRangeResolver) textRangeResolver, new RelationshipStrategyTableDescriptionProvider(this.getRelationshipStrategy())); + } + } + + + // ********** map key attribute override owner ********** + + protected class MapKeyAttributeOverrideContainerOwner + extends AbstractOwner + implements JavaAttributeOverrideContainer.Owner + { + public JavaResourcePersistentMember getResourcePersistentMember() { + return AbstractJavaMultiRelationshipMapping.this.getResourcePersistentAttribute(); + } + + public TypeMapping getOverridableTypeMapping() { + return AbstractJavaMultiRelationshipMapping.this.getResolvedMapKeyEmbeddable(); + } + + /** + * If there is a specified table name it needs to be the same + * the default table name. the table is always the collection table + */ + public boolean tableNameIsInvalid(String tableName) { + return Tools.valuesAreDifferent(this.getDefaultTableName(), tableName); + } + + public Iterator<String> allOverridableNames() { + TypeMapping typeMapping = this.getOverridableTypeMapping(); + return (typeMapping != null) ? typeMapping.allOverridableAttributeNames() : EmptyIterator.<String>instance(); + } + + protected static final String POSSIBLE_PREFIX = "key"; //$NON-NLS-1$ + public String getPossiblePrefix() { + return POSSIBLE_PREFIX; + } + + public String getWritePrefix() { + return this.getPossiblePrefix(); + } + + // since only a map's key can be an embeddable on a 1-m or m-m; + // all overrides are relevant + public boolean isRelevant(String overrideName) { + return true; + } + + public Column resolveOverriddenColumn(String attributeName) { + return MappingTools.resolveOverriddenColumn(this.getOverridableTypeMapping(), attributeName); + } + + public JptValidator buildValidator(Override_ override, OverrideContainer container, OverrideTextRangeResolver textRangeResolver) { + return new MapKeyAttributeOverrideValidator((AttributeOverride) override, (AttributeOverrideContainer) container, textRangeResolver, new EmbeddableOverrideDescriptionProvider()); + } + + public JptValidator buildColumnValidator(Override_ override, BaseColumn column, BaseColumn.Owner owner, BaseColumnTextRangeResolver textRangeResolver) { + return new MapKeyAttributeOverrideColumnValidator((AttributeOverride) override, column, textRangeResolver, new RelationshipStrategyTableDescriptionProvider(this.getRelationshipStrategy())); + } + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaNamedColumn.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaNamedColumn.java new file mode 100644 index 0000000000..fa129f27da --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaNamedColumn.java @@ -0,0 +1,292 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.common.utility.internal.iterables.FilteringIterable; +import org.eclipse.jpt.jpa.core.context.ReadOnlyNamedColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; +import org.eclipse.jpt.jpa.core.context.java.JavaNamedColumn; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.resource.java.NamedColumnAnnotation; +import org.eclipse.jpt.jpa.db.Column; +import org.eclipse.jpt.jpa.db.Table; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java<ul> + * <li>column + * <li>join column + * <li>discriminator column + * <li>order column + * <li>primary key join column + * </ul> + * <strong>NB:</strong> any subclass that directly holds its column annotation + * must:<ul> + * <li>call the "super" constructor that takes a column annotation + * {@link #AbstractJavaNamedColumn(JavaJpaContextNode, JavaNamedColumn.Owner, NamedColumnAnnotation)} + * <li>override {@link #setColumnAnnotation(NamedColumnAnnotation)} to set the column annotation + * so it is in place before the column's state (e.g. {@link #specifiedName}) + * is initialized + * </ul> + */ +public abstract class AbstractJavaNamedColumn<A extends NamedColumnAnnotation, O extends JavaNamedColumn.Owner> + extends AbstractJavaJpaContextNode + implements JavaNamedColumn +{ + protected final O owner; + + protected String specifiedName; + protected String defaultName; + + protected String columnDefinition; + + + protected AbstractJavaNamedColumn(JavaJpaContextNode parent, O owner) { + this(parent, owner, null); + } + + protected AbstractJavaNamedColumn(JavaJpaContextNode parent, O owner, A columnAnnotation) { + super(parent); + this.owner = owner; + this.setColumnAnnotation(columnAnnotation); + this.specifiedName = this.buildSpecifiedName(); + this.columnDefinition = this.buildColumnDefinition(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setSpecifiedName_(this.buildSpecifiedName()); + this.setColumnDefinition_(this.buildColumnDefinition()); + } + + @Override + public void update() { + super.update(); + this.setDefaultName(this.buildDefaultName()); + } + + + // ********** column annotation ********** + + /** + * Return the Java column annotation. Do not return <code>null</code> if the + * Java annotation does not exist; return a <em>null</em> column annotation + * instead. + */ + public abstract A getColumnAnnotation(); + + /** + * see class comment... ({@link AbstractJavaNamedColumn}) + */ + protected void setColumnAnnotation(A columnAnnotation) { + if (columnAnnotation != null) { + throw new IllegalArgumentException("this method must be overridden if the column annotation is not null: " + columnAnnotation); //$NON-NLS-1$ + } + } + + protected void removeColumnAnnotationIfUnset() { + if (this.getColumnAnnotation().isUnset()) { + this.removeColumnAnnotation(); + } + } + + protected abstract void removeColumnAnnotation(); + + + // ********** name ********** + + public String getName() { + return (this.specifiedName != null) ? this.specifiedName : this.defaultName; + } + + public String getSpecifiedName() { + return this.specifiedName; + } + + public void setSpecifiedName(String name) { + if (this.valuesAreDifferent(this.specifiedName, name)) { + this.getColumnAnnotation().setName(name); + this.removeColumnAnnotationIfUnset(); + this.setSpecifiedName_(name); + } + } + + protected void setSpecifiedName_(String name) { + String old = this.specifiedName; + this.specifiedName = name; + this.firePropertyChanged(SPECIFIED_NAME_PROPERTY, old, name); + } + + protected String buildSpecifiedName() { + return this.getColumnAnnotation().getName(); + } + + public String getDefaultName() { + return this.defaultName; + } + + protected void setDefaultName(String name) { + String old = this.defaultName; + this.defaultName = name; + this.firePropertyChanged(DEFAULT_NAME_PROPERTY, old, name); + } + + protected String buildDefaultName() { + return this.owner.getDefaultColumnName(); + } + + + // ********** column definition ********** + + public String getColumnDefinition() { + return this.columnDefinition; + } + + public void setColumnDefinition(String columnDefinition) { + if (this.valuesAreDifferent(this.columnDefinition, columnDefinition)) { + this.getColumnAnnotation().setColumnDefinition(columnDefinition); + this.removeColumnAnnotationIfUnset(); + this.setColumnDefinition_(columnDefinition); + } + } + + protected void setColumnDefinition_(String columnDefinition) { + String old = this.columnDefinition; + this.columnDefinition = columnDefinition; + this.firePropertyChanged(COLUMN_DEFINITION_PROPERTY, old, columnDefinition); + } + + public String buildColumnDefinition() { + return this.getColumnAnnotation().getColumnDefinition(); + } + + + // ********** database stuff ********** + + protected Column getDbColumn() { + Table table = this.getDbTable(); + return (table == null) ? null : table.getColumnForIdentifier(this.getName()); + } + + public Table getDbTable() { + return this.owner.resolveDbTable(this.getTable()); + } + + /** + * Return the name of the column's table. This is overridden + * in {@link AbstractJavaBaseColumn} where a table can be defined. + */ + public String getTable() { + return this.owner.getTypeMapping().getPrimaryTableName(); + } + + public boolean isResolved() { + return this.getDbColumn() != null; + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> connectedJavaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.connectedJavaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + if (this.nameTouches(pos, astRoot)) { + return this.getJavaCandidateNames(filter).iterator(); + } + return null; + } + + protected boolean nameTouches(int pos, CompilationUnit astRoot) { + return this.getColumnAnnotation().nameTouches(pos, astRoot); + } + + protected Iterable<String> getJavaCandidateNames(Filter<String> filter) { + return StringTools.convertToJavaStringLiterals(this.getCandidateNames(filter)); + } + + protected Iterable<String> getCandidateNames(Filter<String> filter) { + return new FilteringIterable<String>(this.getCandidateNames(), filter); + } + + protected Iterable<String> getCandidateNames() { + Table dbTable = this.getDbTable(); + return (dbTable != null) ? dbTable.getSortedColumnIdentifiers() : EmptyIterable.<String> instance(); + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.buildColumnValidator(astRoot).validate(messages, reporter); + } + + protected JptValidator buildColumnValidator(CompilationUnit astRoot) { + return this.owner.buildColumnValidator(this, buildTextRangeResolver(astRoot)); + } + + protected NamedColumnTextRangeResolver buildTextRangeResolver(CompilationUnit astRoot) { + return new JavaNamedColumnTextRangeResolver(this, astRoot); + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + TextRange textRange = this.getColumnAnnotation().getTextRange(astRoot); + return (textRange != null) ? textRange : this.owner.getValidationTextRange(astRoot); + } + + public TextRange getNameTextRange(CompilationUnit astRoot) { + TextRange textRange = this.getColumnAnnotation().getNameTextRange(astRoot); + return (textRange != null) ? textRange : this.owner.getValidationTextRange(astRoot); + } + + + // ********** misc ********** + + public boolean isVirtual() { + return false; + } + + protected void initializeFrom(ReadOnlyNamedColumn oldColumn) { + this.setSpecifiedName(oldColumn.getSpecifiedName()); + this.setColumnDefinition(oldColumn.getColumnDefinition()); + } + + protected void initializeFromVirtual(ReadOnlyNamedColumn virtualColumn) { + this.setSpecifiedName(virtualColumn.getName()); + this.setColumnDefinition(virtualColumn.getColumnDefinition()); + } + + @Override + public void toString(StringBuilder sb) { + String table = this.getTable(); + if (table != null) { + sb.append(table); + sb.append('.'); + } + sb.append(this.getName()); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToManyMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToManyMapping.java new file mode 100644 index 0000000000..a7614b8d84 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToManyMapping.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2006, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaMappingRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaOneToManyRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.internal.jpa2.context.java.NullJavaOrphanRemoval2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaOneToManyMapping2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaOrphanRemovable2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaOrphanRemovalHolder2_0; +import org.eclipse.jpt.jpa.core.resource.java.OneToManyAnnotation; + +public abstract class AbstractJavaOneToManyMapping + extends AbstractJavaMultiRelationshipMapping<OneToManyAnnotation> + implements JavaOneToManyMapping2_0, JavaOrphanRemovalHolder2_0 +{ + protected final JavaOrphanRemovable2_0 orphanRemoval; + + + protected AbstractJavaOneToManyMapping(JavaPersistentAttribute parent) { + super(parent); + this.orphanRemoval = this.buildOrphanRemoval(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.orphanRemoval.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + this.orphanRemoval.update(); + } + + + // ********** relationship ********** + + @Override + public JavaOneToManyRelationship getRelationship() { + return (JavaOneToManyRelationship) super.getRelationship(); + } + + @Override + protected JavaMappingRelationship buildRelationship() { + return new GenericJavaOneToManyRelationship(this, this.isJpa2_0Compatible()); + } + + + // ********** orphan removal ********** + + public JavaOrphanRemovable2_0 getOrphanRemoval() { + return this.orphanRemoval; + } + + protected JavaOrphanRemovable2_0 buildOrphanRemoval() { + return this.isJpa2_0Compatible() ? + this.getJpaFactory2_0().buildJavaOrphanRemoval(this) : + new NullJavaOrphanRemoval2_0(this); + } + + + // ********** misc ********** + + public String getKey() { + return MappingKeys.ONE_TO_MANY_ATTRIBUTE_MAPPING_KEY; + } + + @Override + protected String getAnnotationName() { + return OneToManyAnnotation.ANNOTATION_NAME; + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToManyMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToManyMappingDefinition.java new file mode 100644 index 0000000000..fbc1bffffd --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToManyMappingDefinition.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.JoinColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JoinColumnsAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JoinTableAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.MapKeyAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.OneToManyAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.OrderByAnnotation; + +public abstract class AbstractJavaOneToManyMappingDefinition + implements JavaAttributeMappingDefinition +{ + protected AbstractJavaOneToManyMappingDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.ONE_TO_MANY_ATTRIBUTE_MAPPING_KEY; + } + + public String getAnnotationName() { + return OneToManyAnnotation.ANNOTATION_NAME; + } + + public boolean isSpecified(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.getResourcePersistentAttribute().getAnnotation(this.getAnnotationName()) != null; + } + + public Iterable<String> getSupportingAnnotationNames() { + return SUPPORTING_ANNOTATION_NAMES; + } + + protected static final String[] SUPPORTING_ANNOTATION_NAMES_ARRAY = new String[] { + JoinTableAnnotation.ANNOTATION_NAME, + MapKeyAnnotation.ANNOTATION_NAME, + OrderByAnnotation.ANNOTATION_NAME, + JoinColumnAnnotation.ANNOTATION_NAME, + JoinColumnsAnnotation.ANNOTATION_NAME + }; + protected static final Iterable<String> SUPPORTING_ANNOTATION_NAMES = new ArrayIterable<String>(SUPPORTING_ANNOTATION_NAMES_ARRAY); + + public JavaAttributeMapping buildMapping(JavaPersistentAttribute persistentAttribute, JpaFactory factory) { + return factory.buildJavaOneToManyMapping(persistentAttribute); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToOneMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToOneMapping.java new file mode 100644 index 0000000000..1fca5e88aa --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToOneMapping.java @@ -0,0 +1,86 @@ +/******************************************************************************* + * Copyright (c) 2007, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaOneToOneRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.internal.jpa2.context.java.NullJavaOrphanRemoval2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaOneToOneMapping2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaOrphanRemovable2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaOrphanRemovalHolder2_0; +import org.eclipse.jpt.jpa.core.resource.java.OneToOneAnnotation; + + +public abstract class AbstractJavaOneToOneMapping + extends AbstractJavaSingleRelationshipMapping<OneToOneAnnotation> + implements JavaOneToOneMapping2_0, JavaOrphanRemovalHolder2_0 +{ + protected final JavaOrphanRemovable2_0 orphanRemoval; + + + protected AbstractJavaOneToOneMapping(JavaPersistentAttribute parent) { + super(parent); + this.orphanRemoval = this.buildOrphanRemoval(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.orphanRemoval.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + this.orphanRemoval.update(); + } + + + // ********** relationship ********** + + @Override + public JavaOneToOneRelationship getRelationship() { + return (JavaOneToOneRelationship) super.getRelationship(); + } + + @Override + protected JavaOneToOneRelationship buildRelationship() { + return new GenericJavaOneToOneRelationship(this); + } + + + // ********** orphan removal ********** + + public JavaOrphanRemovable2_0 getOrphanRemoval() { + return this.orphanRemoval; + } + + protected JavaOrphanRemovable2_0 buildOrphanRemoval() { + return this.isJpa2_0Compatible() ? + this.getJpaFactory2_0().buildJavaOrphanRemoval(this) : + new NullJavaOrphanRemoval2_0(this); + } + + + // ********** misc ********** + + public String getKey() { + return MappingKeys.ONE_TO_ONE_ATTRIBUTE_MAPPING_KEY; + } + + @Override + protected String getAnnotationName() { + return OneToOneAnnotation.ANNOTATION_NAME; + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToOneMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToOneMappingDefinition.java new file mode 100644 index 0000000000..e5df782d91 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOneToOneMappingDefinition.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.JoinColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JoinColumnsAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JoinTableAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.OneToOneAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.PrimaryKeyJoinColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.PrimaryKeyJoinColumnsAnnotation; + +public abstract class AbstractJavaOneToOneMappingDefinition + implements JavaAttributeMappingDefinition +{ + protected AbstractJavaOneToOneMappingDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.ONE_TO_ONE_ATTRIBUTE_MAPPING_KEY; + } + + public String getAnnotationName() { + return OneToOneAnnotation.ANNOTATION_NAME; + } + + public boolean isSpecified(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.getResourcePersistentAttribute().getAnnotation(this.getAnnotationName()) != null; + } + + public Iterable<String> getSupportingAnnotationNames() { + return SUPPORTING_ANNOTATION_NAMES; + } + + protected static final String[] SUPPORTING_ANNOTATION_NAMES_ARRAY = new String[] { + JoinTableAnnotation.ANNOTATION_NAME, + JoinColumnAnnotation.ANNOTATION_NAME, + JoinColumnsAnnotation.ANNOTATION_NAME, + PrimaryKeyJoinColumnAnnotation.ANNOTATION_NAME, + PrimaryKeyJoinColumnsAnnotation.ANNOTATION_NAME + }; + protected static final Iterable<String> SUPPORTING_ANNOTATION_NAMES = new ArrayIterable<String>(SUPPORTING_ANNOTATION_NAMES_ARRAY); + + public JavaAttributeMapping buildMapping(JavaPersistentAttribute persistentAttribute, JpaFactory factory) { + return factory.buildJavaOneToOneMapping(persistentAttribute); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOverride.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOverride.java new file mode 100644 index 0000000000..f460c8dbfa --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaOverride.java @@ -0,0 +1,215 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.iterators.FilteringIterator; +import org.eclipse.jpt.jpa.core.context.ReadOnlyOverride; +import org.eclipse.jpt.jpa.core.context.java.JavaOverride; +import org.eclipse.jpt.jpa.core.context.java.JavaOverrideContainer; +import org.eclipse.jpt.jpa.core.context.java.JavaVirtualOverride; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.OverrideTextRangeResolver; +import org.eclipse.jpt.jpa.core.resource.java.OverrideAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Specified Java override + */ +public abstract class AbstractJavaOverride<C extends JavaOverrideContainer, A extends OverrideAnnotation> + extends AbstractJavaJpaContextNode + implements JavaOverride +{ + protected final A overrideAnnotation; + + protected String name; + + + protected AbstractJavaOverride(C parent, A overrideAnnotation) { + super(parent); + this.overrideAnnotation = overrideAnnotation; + this.name = this.buildName(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setName_(this.buildName()); + } + + + // ********** name ********** + + public String getName() { + return this.name; + } + + /** + * Strip the prefix (if necessary) before storing the name in the context + * model. Pass the unchanged name to the annotation. + */ + public void setName(String name) { + this.overrideAnnotation.setName(name); + this.setName_(this.stripPrefix(name)); + } + + protected void setName_(String name) { + String old = this.name; + this.name = name; + this.firePropertyChanged(NAME_PROPERTY, old, name); + } + + /** + * Strip the prefix (if necessary) from the name taken from the annotation + * before storing it in the context model. + */ + protected String buildName() { + return this.stripPrefix(this.overrideAnnotation.getName()); + } + + protected String stripPrefix(String rawName) { + if (rawName == null) { + return null; + } + String prefix = this.getPossiblePrefix(); + if (prefix == null) { + return rawName; + } + int prefixLength = prefix.length(); + if ((rawName.length() > prefixLength) && + (rawName.charAt(prefixLength) == '.') && + rawName.startsWith(prefix)) { + return rawName.substring(prefixLength + 1); + } + return rawName; + } + + protected String getPossiblePrefix() { + return this.getContainer().getPossiblePrefix(); + } + + + // ********** specified/virtual ********** + + public boolean isVirtual() { + return false; + } + + public JavaVirtualOverride convertToVirtual() { + return this.getContainer().convertOverrideToVirtual(this); + } + + + // ********** misc ********** + + @Override + @SuppressWarnings("unchecked") + public C getParent() { + return (C) super.getParent(); + } + + public C getContainer() { + return this.getParent(); + } + + public A getOverrideAnnotation() { + return this.overrideAnnotation; + } + + protected void initializeFrom(ReadOnlyOverride oldOverride) { + this.setName(this.prefix(oldOverride.getName())); + } + + protected void initializeFromVirtual(ReadOnlyOverride virtualOverride) { + this.setName(this.prefix(virtualOverride.getName())); + } + + protected String prefix(String oldName) { + if (oldName == null) { + return null; + } + String prefix = this.getWritePrefix(); + return (prefix == null) ? oldName : (prefix + '.' + oldName); + } + + protected String getWritePrefix() { + return this.getContainer().getWritePrefix(); + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.name); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + if (this.nameTouches(pos, astRoot)) { + return this.javaCandidateNames(filter); + } + return null; + } + + protected boolean nameTouches(int pos, CompilationUnit astRoot) { + return this.overrideAnnotation.nameTouches(pos, astRoot); + } + + protected Iterator<String> javaCandidateNames(Filter<String> filter) { + return StringTools.convertToJavaStringLiterals(this.candidateNames(filter)); + } + + private Iterator<String> candidateNames(Filter<String> filter) { + return new FilteringIterator<String>(this.candidateNames(), filter); + } + + protected abstract Iterator<String> candidateNames(); + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.buildValidator(astRoot).validate(messages, reporter); + } + + protected JptValidator buildValidator(CompilationUnit astRoot) { + return this.getContainer().buildValidator(this, buildTextRangeResolver(astRoot)); + } + + protected OverrideTextRangeResolver buildTextRangeResolver(CompilationUnit astRoot) { + return new JavaOverrideTextRangeResolver(this, astRoot); + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + TextRange textRange = this.overrideAnnotation.getTextRange(astRoot); + return (textRange != null) ? textRange : this.getParent().getValidationTextRange(astRoot); + } + + public TextRange getNameTextRange(CompilationUnit astRoot) { + TextRange textRange = this.overrideAnnotation.getNameTextRange(astRoot); + return (textRange != null) ? textRange : this.getValidationTextRange(astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaPersistentAttribute.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaPersistentAttribute.java new file mode 100644 index 0000000000..10d11930cd --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaPersistentAttribute.java @@ -0,0 +1,816 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.Modifier; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.ArrayTools; +import org.eclipse.jpt.common.utility.internal.ClassName; +import org.eclipse.jpt.common.utility.internal.ReflectionTools; +import org.eclipse.jpt.common.utility.internal.Tools; +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.jpa.core.JpaStructureNode; +import org.eclipse.jpt.jpa.core.context.AccessType; +import org.eclipse.jpt.jpa.core.context.CollectionMapping; +import org.eclipse.jpt.jpa.core.context.Embeddable; +import org.eclipse.jpt.jpa.core.context.PersistentType; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.java.DefaultJavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.java.JavaStructureNodes; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.PersistentAttributeTextRangeResolver; +import org.eclipse.jpt.jpa.core.jpa2.context.MetamodelField; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaPersistentAttribute2_0; +import org.eclipse.jpt.jpa.core.jpa2.resource.java.JPA2_0; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentAttribute; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java persistent attributes + */ +public abstract class AbstractJavaPersistentAttribute + extends AbstractJavaJpaContextNode + implements JavaPersistentAttribute2_0 +{ + protected final JavaResourcePersistentAttribute resourcePersistentAttribute; + + protected String name; + + protected AccessType defaultAccess; + + protected JavaAttributeMapping mapping; // never null + protected String defaultMappingKey; + + + protected AbstractJavaPersistentAttribute(PersistentType parent, JavaResourcePersistentAttribute resourcePersistentAttribute) { + super(parent); + this.resourcePersistentAttribute = resourcePersistentAttribute; + this.name = resourcePersistentAttribute.getName(); + + // this is determined directly from the resource model + this.defaultAccess = this.buildDefaultAccess(); + + // keep non-null at all times + this.mapping = this.buildMapping(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setName(this.resourcePersistentAttribute.getName()); + // this is determined directly from the resource model + this.setDefaultAccess(this.buildDefaultAccess()); + this.syncMapping(); + } + + @Override + public void update() { + super.update(); + this.updateMapping(); + } + + + // ********** name ********** + + public String getName() { + return this.name; + } + + protected void setName(String name) { + String old = this.name; + this.name = name; + this.firePropertyChanged(NAME_PROPERTY, old, name); + } + + + // ********** access ********** + + /** + * Subclasses determine the specified access. + */ + public AccessType getAccess() { + AccessType access = this.getSpecifiedAccess(); + return (access != null) ? access : this.defaultAccess; + } + + public abstract AccessType getSpecifiedAccess(); + + public AccessType getDefaultAccess() { + return this.defaultAccess; + } + + protected void setDefaultAccess(AccessType access) { + AccessType old = this.defaultAccess; + this.defaultAccess = access; + this.firePropertyChanged(DEFAULT_ACCESS_PROPERTY, old, access); + } + + protected AccessType buildDefaultAccess() { + return this.resourcePersistentAttribute.isField() ? AccessType.FIELD : AccessType.PROPERTY; + } + + + // ********** mapping ********** + + public JavaAttributeMapping getMapping() { + return this.mapping; + } + + /** + * Clients do not set the mapping directly. + * @see #setMappingKey(String) + */ + protected void setMapping(JavaAttributeMapping mapping) { + JavaAttributeMapping old = this.mapping; + this.mapping = mapping; + this.firePropertyChanged(MAPPING_PROPERTY, old, mapping); + } + + public String getMappingKey() { + return this.mapping.getKey(); + } + + /** + * Possible transitions: + * <table border> + * <th> + * <th>null mapping/default<br> + * <code>key = null</code> + * <th>specified mapping A<br> + * <code>key = "A"</code> + * <th>specified mapping B<br> + * <code>key = "B"</code> + * <tr> + * <th>[default] null mapping + * <td>do nothing + * <td>add annotation A<br> + * set new mapping A + * <td>add annotation B<br> + * set new mapping B + * <tr> + * <th>default mapping A + * <td>do nothing + * <td>add annotation A<br> + * <em>re-use</em> default mapping A + * <td>add annotation B<br> + * set new mapping B + * <tr> + * <th>specified mapping A + * <td>remove annotation A<br> + * set new default or null mapping + * <td>do nothing + * <td>remove annotation A<br> + * add annotation B<br> + * set new mapping B + * </table> + * The "do nothing" transitions are handled in this method. + */ + public JavaAttributeMapping setMappingKey(String key) { + if (this.mapping.isDefault()) { + if (key == null) { + // leave the default mapping unchanged + } else { + this.setMappingKey_(key); // replace the default mapping + } + } else { + if (this.valuesAreEqual(key, this.mapping.getKey())) { + // leave the specified mapping unchanged + } else { + this.setMappingKey_(key); // replace the specified mapping + } + } + return this.mapping; + } + + /** + * We have either:<ul> + * <li>a <em>default</em> mapping and a non-<code>null</code> key + * </ul>or<ul> + * <li>a <em>specified</em> mapping and a different (possibly + * <code>null</code>) key + * </ul> + */ + protected void setMappingKey_(String key) { + JavaAttributeMappingDefinition definition = this.getSpecifiedMappingDefinition(key); + if (definition == null) { + // our mapping is "specified" and the key is null; + // check for a default definition + definition = this.getDefaultMappingDefinition(); + Iterable<String> supportingAnnotationNames = (definition != null) ? definition.getSupportingAnnotationNames() : EmptyIterable.<String>instance(); + // clear any mapping annotation(s); + // leave the "default" mapping's supporting annotations; + // if there is no "default" mapping, clear all supporting annotations too(?) + this.setMappingAnnotation(null, supportingAnnotationNames); + } else { + this.setMappingAnnotation(definition); + } + // note: 'definition' can still be null (if the key is null and there is no "default" mapping) + this.setMapping(this.buildMapping(definition)); + } + + /** + * pre-condition: definition is not <code>null</code> + */ + protected void setMappingAnnotation(JavaAttributeMappingDefinition definition) { + this.setMappingAnnotation(definition.getAnnotationName(), definition.getSupportingAnnotationNames()); + } + + protected void setMappingAnnotation(String primaryAnnotationName, Iterable<String> supportingAnnotationNames) { + this.resourcePersistentAttribute.setPrimaryAnnotation(primaryAnnotationName, supportingAnnotationNames); + } + + protected JavaAttributeMapping buildMapping(JavaAttributeMappingDefinition definition) { + return (definition == null) ? this.buildNullMapping() : this.buildMapping_(definition); + } + + protected JavaAttributeMapping buildNullMapping() { + return this.getJpaFactory().buildJavaNullAttributeMapping(this); + } + + /** + * pre-condition: definition is not null + * <p> + * If we are converting a <em>default</em> mapping to its <em>specified</em> + * manifestation, we just keep the same mapping and create its annotation. + * We do <em>not</em> do the same thing when converting a <em>specified</em> + * mapping to its <em>default</em> manifestation. We rebuild the + * entire mapping, simplifying the clearing of all its state. We do this + * because we allow clients to modify a <em>default</em> mapping (or any of + * its components) directly, + * modifying its state and triggering a conversion to a <em>specified</em> + * mapping. The only way to convert a <em>specified</em> mapping to a + * <em>default</em> mapping is by {@link #setMappingKey(String) setting the + * mapping key} to <code>null</code>. + */ + protected JavaAttributeMapping buildMapping_(JavaAttributeMappingDefinition definition) { + // 'mapping' is null during construction + if ((this.mapping != null) && this.mapping.isDefault() && Tools.valuesAreEqual(this.mapping.getKey(), definition.getKey())) { + this.mapping.updateDefault(); // since nothing here changes, we need to update the mapping's flag + return this.mapping; + } + return definition.buildMapping(this, this.getJpaFactory()); + } + + /** + * We only look for a <em>specified</em> mapping here. + * We look for a default mapping during <em>update</em>. + */ + protected JavaAttributeMapping buildMapping() { + return this.buildMapping(this.getSpecifiedMappingDefinition()); + } + + /** + * Look for a <em>specified</em> mapping and sync our mapping. + */ + protected void syncMapping() { + JavaAttributeMappingDefinition definition = this.getSpecifiedMappingDefinition(); + if (definition == null) { + if (this.mapping.isDefault()) { + // null/default => null/default + this.mapping.synchronizeWithResourceModel(); + } else { + // specified => null/default + definition = this.getDefaultMappingDefinition(); + this.setMapping(this.buildMapping(definition)); + } + } else { + if (this.mapping.isDefault()) { + // null/default => specified + this.setMapping(this.buildMapping(definition)); + } else { + // specified => specified + if (this.valuesAreEqual(definition.getKey(), this.mapping.getKey())) { + this.mapping.synchronizeWithResourceModel(); + } else { + this.setMapping(this.buildMapping(definition)); + } + } + } + } + + /** + * Return the "specified" mapping definition for the specified key. + */ + protected JavaAttributeMappingDefinition getSpecifiedMappingDefinition(String key) { + if (key == null) { + return null; + } + for (JavaAttributeMappingDefinition definition : this.getSpecifiedMappingDefinitions()) { + if (Tools.valuesAreEqual(definition.getKey(), key)) { + return definition; + } + } + throw new IllegalArgumentException("invalid mapping key: " + key); //$NON-NLS-1$ + } + + /** + * Return the mapping definition for the mapping currently specified in the + * source code. + */ + protected JavaAttributeMappingDefinition getSpecifiedMappingDefinition() { + for (JavaAttributeMappingDefinition definition : this.getSpecifiedMappingDefinitions()) { + if (definition.isSpecified(this)) { + return definition; + } + } + return null; + } + + protected Iterable<JavaAttributeMappingDefinition> getSpecifiedMappingDefinitions() { + return this.getJpaPlatform().getSpecifiedJavaAttributeMappingDefinitions(); + } + + + // ********** default mapping ********** + + public String getDefaultMappingKey() { + return this.defaultMappingKey; + } + + protected void setDefaultMappingKey(String mappingKey) { + String old = this.defaultMappingKey; + this.defaultMappingKey = mappingKey; + this.firePropertyChanged(DEFAULT_MAPPING_KEY_PROPERTY, old, mappingKey); + } + + /** + * If a mapping annotation is specified, we would have already set a + * <em>specified</em> mapping in {@link #syncMapping()}. We need only check + * for changes to the <em>default</em> mapping. + */ + protected void updateMapping() { + JavaAttributeMappingDefinition definition = this.getDefaultMappingDefinition(); + String newDefaultKey = (definition == null) ? null : definition.getKey(); + if (this.mapping.isDefault() && Tools.valuesAreDifferent(this.mapping.getKey(), newDefaultKey)) { + this.setMapping(this.buildMapping(definition)); // the default mapping has changed + } else { + this.mapping.update(); + } + this.setDefaultMappingKey(newDefaultKey); + } + + protected JavaAttributeMappingDefinition getDefaultMappingDefinition() { + for (DefaultJavaAttributeMappingDefinition definition : this.getDefaultMappingDefinitions()) { + if (definition.isDefault(this)) { + return definition; + } + } + return null; + } + + protected Iterable<DefaultJavaAttributeMappingDefinition> getDefaultMappingDefinitions() { + return this.getJpaPlatform().getDefaultJavaAttributeMappingDefinitions(); + } + + + // ********** JpaStructureNode implementation ********** + + public String getId() { + return JavaStructureNodes.PERSISTENT_ATTRIBUTE_ID; + } + + public JpaStructureNode getStructureNode(int textOffset) { + return this; + } + + public TextRange getSelectionTextRange() { + return this.getSelectionTextRange(this.buildASTRoot()); + } + + protected TextRange getSelectionTextRange(CompilationUnit astRoot) { + return this.resourcePersistentAttribute.getNameTextRange(astRoot); + } + + protected CompilationUnit buildASTRoot() { + return this.resourcePersistentAttribute.getJavaResourceCompilationUnit().buildASTRoot(); + } + + public void dispose() { + // nothing to dispose + } + + + // ********** type ********** + + /** + * From the JPA spec, when the basic mapping applies:<br> + * If the type of the attribute (field or property) is one of the following + * it must be mapped as <code>@javax.persistence.Basic</code>:<ul> + * <li><code>byte[]</code> + * <li><code>java.lang.Byte[]</code> + * <li><code>char[]</code> + * <li><code>java.lang.Character[]</code> + * <li>primitive types (except <code>void</code>) + * <li>primitive wrappers (except <code>java.lang.Void</code>) + * <li><code>java.lang.String</code> + * <li><code>java.math.BigInteger</code> + * <li><code>java.math.BigDecimal</code> + * <li><code>java.util.Date</code> + * <li><code>java.util.Calendar</code> + * <li><code>java.sql.Date</code> + * <li><code>java.sql.Time</code> + * <li><code>java.sql.Timestamp</code> + * <li><code>enum</code>s + * <li>any other type that implements <code>java.io.Serializable</code> + * </ul> + */ + public boolean typeIsBasic() { + // 'typeName' may include array brackets but not generic type arguments + String typeName = this.getTypeName(); + if (typeName == null) { + return false; + } + + int arrayDepth = ReflectionTools.getArrayDepthForTypeDeclaration(typeName); + if (arrayDepth > 1) { + return false; // multi-dimensional arrays are not supported + } + + if (arrayDepth == 1) { + String elementTypeName = ReflectionTools.getElementTypeNameForTypeDeclaration(typeName, 1); + return this.elementTypeIsValidForBasicArray(elementTypeName); + } + + // arrayDepth == 0 + if (ClassName.isVariablePrimitive(typeName)) { + return true; // any primitive but 'void' + } + if (ClassName.isVariablePrimitiveWrapper(typeName)) { + return true; // any primitive wrapper but 'java.lang.Void' + } + if (this.typeIsOtherValidBasicType(typeName)) { + return true; + } + if (this.resourcePersistentAttribute.typeIsEnum()) { + return true; + } + if (this.resourcePersistentAttribute.typeIsSubTypeOf(SERIALIZABLE_TYPE_NAME)) { + return true; + } + return false; + } + + /** + * Return whether the specified type is a valid element type for + * a one-dimensional array that can default to a basic mapping:<ul> + * <li><code>byte</code> + * <li><code>java.lang.Byte</code> + * <li><code>char</code> + * <li><code>java.lang.Character</code> + * </ul> + */ + protected boolean elementTypeIsValidForBasicArray(String elementTypeName) { + return ArrayTools.contains(VALID_BASIC_ARRAY_ELEMENT_TYPE_NAMES, elementTypeName); + } + + protected static final String[] VALID_BASIC_ARRAY_ELEMENT_TYPE_NAMES = { + byte.class.getName(), + char.class.getName(), + java.lang.Byte.class.getName(), + java.lang.Character.class.getName() + }; + + /** + * Return whether the specified type is among the various "other" types + * that can default to a basic mapping. + */ + protected boolean typeIsOtherValidBasicType(String typeName) { + return ArrayTools.contains(OTHER_VALID_BASIC_TYPE_NAMES, typeName); + } + + protected static final String[] OTHER_VALID_BASIC_TYPE_NAMES = { + java.lang.String.class.getName(), + java.math.BigInteger.class.getName(), + java.math.BigDecimal.class.getName(), + java.util.Date.class.getName(), + java.util.Calendar.class.getName(), + java.sql.Date.class.getName(), + java.sql.Time.class.getName(), + java.sql.Timestamp.class.getName(), + }; + + protected static final String SERIALIZABLE_TYPE_NAME = java.io.Serializable.class.getName(); + + public String getSingleReferenceTargetTypeName() { + // 'typeName' may include array brackets ("[]") + // but not generic type arguments (e.g. "<java.lang.String>") + String typeName = this.getTypeName(); + if (typeName == null) { + return null; + } + if (ReflectionTools.getArrayDepthForTypeDeclaration(typeName) != 0) { + return null; // arrays cannot be entities + } + if (this.typeIsContainer(typeName)) { + return null; // "containers" cannot be entities + } + return typeName; + } + + public String getMultiReferenceTargetTypeName() { + return this.getJpaContainerDefinition().getMultiReferenceTargetTypeName(this.resourcePersistentAttribute); + } + + public String getMultiReferenceMapKeyTypeName() { + return this.getJpaContainerDefinition().getMultiReferenceMapKeyTypeName(this.resourcePersistentAttribute); + } + + /** + * return whether the specified type is one of the container + * types allowed by the JPA spec + */ + protected boolean typeIsContainer(String typeName) { + return this.getJpaContainerDefinition(typeName).isContainer(); + } + + + // ********** misc ********** + + @Override + public PersistentType getParent() { + return (PersistentType) super.getParent(); + } + + public PersistentType getOwningPersistentType() { + return this.getParent(); + } + + public TypeMapping getOwningTypeMapping() { + return this.getOwningPersistentType().getMapping(); + } + + public JavaPersistentAttribute getJavaPersistentAttribute() { + return this; + } + + public JavaResourcePersistentAttribute getResourcePersistentAttribute() { + return this.resourcePersistentAttribute; + } + + public String getPrimaryKeyColumnName() { + return this.getMapping().getPrimaryKeyColumnName(); + } + + public String getTypeName() { + return this.resourcePersistentAttribute.getTypeName(); + } + + /** + * Java attributes always correspond to attributes in the source code. + */ + public boolean isVirtual() { + return false; + } + + public boolean contains(int offset, CompilationUnit astRoot) { + TextRange fullTextRange = this.getFullTextRange(astRoot); + // 'fullTextRange' will be null if the attribute no longer exists in the java; + // the context model can be out of synch with the resource model + // when a selection event occurs before the context model has a + // chance to synch with the resource model via the update thread + return (fullTextRange == null) ? false : fullTextRange.includes(offset); + } + + protected TextRange getFullTextRange(CompilationUnit astRoot) { + return this.resourcePersistentAttribute.getTextRange(astRoot); + } + + public Embeddable getEmbeddable() { + String typeName = this.getTypeName(); + return (typeName == null) ? null : this.getPersistenceUnit().getEmbeddable(typeName); + } + + public boolean isField() { + return this.resourcePersistentAttribute.isField(); + } + + public boolean isProperty() { + return this.resourcePersistentAttribute.isProperty(); + } + + public boolean isPublic() { + return Modifier.isPublic(this.resourcePersistentAttribute.getModifiers()); + } + + public boolean isFinal() { + return Modifier.isFinal(this.resourcePersistentAttribute.getModifiers()); + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.name); + } + + + // ********** validation ********** + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return this.getSelectionTextRange(astRoot); + } + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + + this.validateAttribute(messages, reporter, astRoot); + + this.getMapping().validate(messages, reporter, astRoot); + } + + protected void validateAttribute(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + this.buildAttibuteValidator(astRoot).validate(messages, reporter); + } + + protected abstract JptValidator buildAttibuteValidator(CompilationUnit astRoot); + + protected PersistentAttributeTextRangeResolver buildTextRangeResolver(CompilationUnit astRoot) { + return new JavaPersistentAttributeTextRangeResolver(this, astRoot); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + return this.getMapping().javaCompletionProposals(pos, filter, astRoot); + } + + + // ********** metamodel ********** + + public String getMetamodelContainerFieldTypeName() { + return this.getJpaContainerDefinition().getMetamodelContainerFieldTypeName(); + } + + public String getMetamodelContainerFieldMapKeyTypeName() { + return this.getJpaContainerDefinition().getMetamodelContainerFieldMapKeyTypeName((CollectionMapping) this.getMapping()); + } + + public String getMetamodelTypeName() { + String typeName = this.getTypeName(); + if (typeName == null) { + return MetamodelField.DEFAULT_TYPE_NAME; + } + if (ClassName.isPrimitive(typeName)) { + return ClassName.getWrapperClassName(typeName); // ??? + } + return typeName; + } + + + // ********** JPA container definition ********** + + public JpaContainerDefinition getJpaContainerDefinition() { + // 'typeName' may include array brackets ("[]") + // but not generic type arguments (e.g. "<java.lang.String>") + return this.getJpaContainerDefinition(this.resourcePersistentAttribute.getTypeName()); + } + + /** + * Return the JPA container definition corresponding to the specified type; + * return a "null" definition if the specified type is not one of the + * container types allowed by the JPA spec. + */ + protected JpaContainerDefinition getJpaContainerDefinition(String typeName) { + for (JpaContainerDefinition definition : this.getJpaContainerDefinitions()) { + if (definition.getTypeName().equals(typeName)) { + return definition; + } + } + return JpaContainerDefinition.Null.instance(); + } + + protected Iterable<JpaContainerDefinition> getJpaContainerDefinitions() { + return JPA_CONTAINER_DEFINITIONS; + } + + protected static final JpaContainerDefinition[] JPA_CONTAINER_DEFINITION_ARRAY = new JpaContainerDefinition[] { + new CollectionJpaContainerDefinition(java.util.Collection.class, JPA2_0.COLLECTION_ATTRIBUTE), + new CollectionJpaContainerDefinition(java.util.Set.class, JPA2_0.SET_ATTRIBUTE), + new CollectionJpaContainerDefinition(java.util.List.class, JPA2_0.LIST_ATTRIBUTE), + new MapJpaContainerDefinition(java.util.Map.class, JPA2_0.MAP_ATTRIBUTE) + }; + + protected static final Iterable<JpaContainerDefinition> JPA_CONTAINER_DEFINITIONS = new ArrayIterable<JpaContainerDefinition>(JPA_CONTAINER_DEFINITION_ARRAY); + + + /** + * Abstract JPA container definition + */ + protected abstract static class AbstractJpaContainerDefinition + implements JpaContainerDefinition + { + protected final String typeName; + protected final String metamodelContainerFieldTypeName; + + protected AbstractJpaContainerDefinition(Class<?> containerClass, String metamodelContainerFieldTypeName) { + this(containerClass.getName(), metamodelContainerFieldTypeName); + } + + protected AbstractJpaContainerDefinition(String typeName, String metamodelContainerFieldTypeName) { + super(); + if ((typeName == null) || (metamodelContainerFieldTypeName == null)) { + throw new NullPointerException(); + } + this.typeName = typeName; + this.metamodelContainerFieldTypeName = metamodelContainerFieldTypeName; + } + + public String getTypeName() { + return this.typeName; + } + + public boolean isContainer() { + return true; + } + + public String getMetamodelContainerFieldTypeName() { + return this.metamodelContainerFieldTypeName; + } + + } + + /** + * Collection JPA container definition + */ + protected static class CollectionJpaContainerDefinition + extends AbstractJpaContainerDefinition + { + protected CollectionJpaContainerDefinition(Class<?> collectionClass, String staticMetamodelTypeDeclarationTypeName) { + super(collectionClass, staticMetamodelTypeDeclarationTypeName); + } + + public String getMultiReferenceTargetTypeName(JavaResourcePersistentAttribute resourcePersistentAttribute) { + return (resourcePersistentAttribute.typeTypeArgumentNamesSize() == 1) ? + resourcePersistentAttribute.getTypeTypeArgumentName(0) : + null; + } + + public String getMultiReferenceMapKeyTypeName(JavaResourcePersistentAttribute resourcePersistentAttribute) { + return null; + } + + public String getMetamodelContainerFieldMapKeyTypeName(CollectionMapping mapping) { + return null; + } + + public boolean isMap() { + return false; + } + } + + /** + * Map JPA container definition + */ + protected static class MapJpaContainerDefinition + extends AbstractJpaContainerDefinition + { + protected MapJpaContainerDefinition(Class<?> mapClass, String staticMetamodelTypeDeclarationTypeName) { + super(mapClass, staticMetamodelTypeDeclarationTypeName); + } + + public String getMultiReferenceTargetTypeName(JavaResourcePersistentAttribute resourcePersistentAttribute) { + return (resourcePersistentAttribute.typeTypeArgumentNamesSize() == 2) ? + resourcePersistentAttribute.getTypeTypeArgumentName(1) : + null; + } + + public String getMultiReferenceMapKeyTypeName(JavaResourcePersistentAttribute resourcePersistentAttribute) { + return (resourcePersistentAttribute.typeTypeArgumentNamesSize() == 2) ? + resourcePersistentAttribute.getTypeTypeArgumentName(0) : + null; + } + + public String getMetamodelContainerFieldMapKeyTypeName(CollectionMapping mapping) { + return mapping.getMetamodelFieldMapKeyTypeName(); + } + + public boolean isMap() { + return true; + } + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaPersistentType.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaPersistentType.java new file mode 100644 index 0000000000..3891dcca22 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaPersistentType.java @@ -0,0 +1,722 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Vector; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IResource; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.ClassName; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.Tools; +import org.eclipse.jpt.common.utility.internal.iterables.ChainIterable; +import org.eclipse.jpt.common.utility.internal.iterables.CompositeIterable; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.common.utility.internal.iterables.FilteringIterable; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.SnapshotCloneIterable; +import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable; +import org.eclipse.jpt.common.utility.internal.iterators.EmptyIterator; +import org.eclipse.jpt.jpa.core.JpaFile; +import org.eclipse.jpt.jpa.core.JpaStructureNode; +import org.eclipse.jpt.jpa.core.JptJpaCorePlugin; +import org.eclipse.jpt.jpa.core.context.AccessType; +import org.eclipse.jpt.jpa.core.context.PersistentType; +import org.eclipse.jpt.jpa.core.context.ReadOnlyPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType; +import org.eclipse.jpt.jpa.core.context.java.JavaStructureNodes; +import org.eclipse.jpt.jpa.core.context.java.JavaTypeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaTypeMappingDefinition; +import org.eclipse.jpt.jpa.core.internal.context.ContextContainerTools; +import org.eclipse.jpt.jpa.core.internal.resource.java.source.SourceNode; +import org.eclipse.jpt.jpa.core.resource.java.Annotation; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentType; +import org.eclipse.jst.j2ee.model.internal.validation.ValidationCancelledException; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java persistent type:<ul> + * <li>name + * <li>access + * <li>mapping + * <li>attributes + * <li>super persistent type + * </ul> + */ +public abstract class AbstractJavaPersistentType + extends AbstractJavaJpaContextNode + implements JavaPersistentType +{ + protected final JavaResourcePersistentType resourcePersistentType; + + protected String name; + + protected PersistentType superPersistentType; + + protected AccessType specifiedAccess; + protected AccessType defaultAccess; // never null + + protected JavaTypeMapping mapping; // never null + + protected final Vector<JavaPersistentAttribute> attributes = new Vector<JavaPersistentAttribute>(); + protected final AttributeContainerAdapter attributeContainerAdapter = new AttributeContainerAdapter(); + + + protected AbstractJavaPersistentType(PersistentType.Owner parent, JavaResourcePersistentType resourcePersistentType) { + super(parent); + this.resourcePersistentType = resourcePersistentType; + this.name = resourcePersistentType.getQualifiedName(); + this.specifiedAccess = this.buildSpecifiedAccess(); + + // keep this non-null + this.defaultAccess = AccessType.FIELD; + + this.mapping = this.buildMapping(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setName(this.resourcePersistentType.getQualifiedName()); + this.setSpecifiedAccess_(this.buildSpecifiedAccess()); + this.syncMapping(); + this.synchronizeNodesWithResourceModel(this.getAttributes()); + } + + @Override + public void update() { + super.update(); + this.setSuperPersistentType(this.buildSuperPersistentType()); + this.setDefaultAccess(this.buildDefaultAccess()); + this.mapping.update(); + this.updateAttributes(); + this.registerRootStructureNode(); + } + + + // ********** name ********** + + public String getName() { + return this.name; + } + + public String getSimpleName(){ + return ClassName.getSimpleName(this.name); + } + + protected void setName(String name) { + String old = this.name; + this.name = name; + this.firePropertyChanged(NAME_PROPERTY, old, name); + } + + + // ********** super persistent type ********** + + public PersistentType getSuperPersistentType() { + return this.superPersistentType; + } + + protected void setSuperPersistentType(PersistentType superPersistentType) { + PersistentType old = this.superPersistentType; + this.superPersistentType = superPersistentType; + this.firePropertyChanged(SUPER_PERSISTENT_TYPE_PROPERTY, old, superPersistentType); + } + + protected PersistentType buildSuperPersistentType() { + HashSet<JavaResourcePersistentType> visited = new HashSet<JavaResourcePersistentType>(); + visited.add(this.resourcePersistentType); + PersistentType spt = this.resolveSuperPersistentType(this.resourcePersistentType.getSuperclassQualifiedName(), visited); + if (spt == null) { + return null; + } + if (CollectionTools.contains(spt.inheritanceHierarchy(), this)) { + return null; // short-circuit in this case, we have circular inheritance + } + return spt.isMapped() ? spt : spt.getSuperPersistentType(); + } + + /** + * The JPA spec allows non-persistent types in a persistent type's + * inheritance hierarchy. We check for a persistent type with the + * specified name in the persistence unit. If it is not found we use + * resource persistent type and look for <em>its</em> super type. + * <p> + * The <code>visited</code> collection is used to detect a cycle in the + * <em>resource</em> type inheritance hierarchy and prevent the resulting + * stack overflow. Any cycles in the <em>context</em> type inheritance + * hierarchy are handled in {@link #buildSuperPersistentType()}. + */ + protected PersistentType resolveSuperPersistentType(String typeName, Collection<JavaResourcePersistentType> visited) { + if (typeName == null) { + return null; + } + JavaResourcePersistentType resourceType = this.getJpaProject().getJavaResourcePersistentType(typeName); + if ((resourceType == null) || visited.contains(resourceType)) { + return null; + } + visited.add(resourceType); + PersistentType spt = this.resolvePersistentType(typeName); + return (spt != null) ? spt : this.resolveSuperPersistentType(resourceType.getSuperclassQualifiedName(), visited); // recurse + } + + protected PersistentType resolvePersistentType(String typeName) { + return this.getPersistenceUnit().getPersistentType(typeName); + } + + + // ********** access ********** + + public AccessType getAccess() { + return (this.specifiedAccess != null) ? this.specifiedAccess : this.defaultAccess; + } + + public AccessType getSpecifiedAccess() { + return this.specifiedAccess; + } + + protected void setSpecifiedAccess_(AccessType access) { + AccessType old = this.specifiedAccess; + this.specifiedAccess = access; + this.firePropertyChanged(SPECIFIED_ACCESS_PROPERTY, old, access); + } + + /** + * Build an access type based on annotations from the resource model. + * (This is JPA platform-dependent.) + */ + protected abstract AccessType buildSpecifiedAccess(); + + public AccessType getDefaultAccess() { + return this.defaultAccess; + } + + protected void setDefaultAccess(AccessType access) { + AccessType old = this.defaultAccess; + this.defaultAccess = access; + this.firePropertyChanged(DEFAULT_ACCESS_PROPERTY, old, access); + } + + /** + * Check the access "specified" by the Java resource model:<ul> + * <li>Check Java annotations first + * <li>If <code>null</code>, check XML mapping specified access + * <li>If still <code>null</code>, check {@link #superPersistentType} access + * <li>If still <code>null</code>, check <code>entity-mappings</code> + * specified access setting if the corresponding <code>persistent-type</code> + * is listed in a mapping (<code>orm.xml</code>) file + * <li>If still <code>null</code>, check the <code>persistence-unit</code> + * default Access + * <li>Default to {@link AccessType#FIELD FIELD} if all else fails. + * </ul> + */ + protected AccessType buildDefaultAccess() { + AccessType accessType = AccessType.fromJavaResourceModel(JavaResourcePersistentType.Tools.buildAccess(this.resourcePersistentType)); + if (accessType != null) { + return accessType; + } + accessType = this.getOwnerOverrideAccess(); + if (accessType != null) { + return accessType; + } + + if (this.superPersistentType != null) { + accessType = this.superPersistentType.getAccess(); + if (accessType != null) { + return accessType; + } + } + + accessType = this.getOwnerDefaultAccess(); + if (accessType != null) { + return accessType; + } + + // last ditch attempt to allow the user to annotate *something* + return AccessType.FIELD; + } + + + // ********** mapping ********** + + public JavaTypeMapping getMapping() { + return this.mapping; + } + + public String getMappingKey() { + return this.mapping.getKey(); + } + + public void setMappingKey(String key) { + if (this.valuesAreDifferent(key, this.getMappingKey())) { + this.setMapping(this.buildMapping(key)); + } + } + + protected JavaTypeMapping buildMapping(String key) { + for (JavaTypeMappingDefinition definition : this.getMappingDefinitions()) { + if (Tools.valuesAreEqual(definition.getKey(), key)) { + Annotation annotation = this.resourcePersistentType.setPrimaryAnnotation(definition.getAnnotationName(), definition.getSupportingAnnotationNames()); + return definition.buildMapping(this, annotation, this.getJpaFactory()); + } + } + this.resourcePersistentType.setPrimaryAnnotation(null, EmptyIterable.<String>instance()); + return this.buildNullMapping(); + } + + /** + * Clients do not set the mapping directly. + * @see #setMappingKey(String) + */ + protected void setMapping(JavaTypeMapping mapping) { + JavaTypeMapping old = this.mapping; + this.mapping = mapping; + this.firePropertyChanged(MAPPING_PROPERTY, old, mapping); + } + + protected JavaTypeMapping buildMapping() { + for (JavaTypeMappingDefinition definition : this.getMappingDefinitions()) { + Annotation annotation = this.resourcePersistentType.getAnnotation(definition.getAnnotationName()); + if (annotation != null) { + return definition.buildMapping(this, annotation, this.getJpaFactory()); + } + } + return this.buildNullMapping(); + } + + protected void syncMapping() { + JavaTypeMappingDefinition definition = null; + Annotation annotation = null; + for (Iterator<JavaTypeMappingDefinition> stream = this.mappingDefinitions(); stream.hasNext(); ) { + definition = stream.next(); + annotation = this.resourcePersistentType.getAnnotation(definition.getAnnotationName()); + if (annotation != null) { + break; + } + } + // 'annotation' can still be null when we get here + if (this.mapping.getMappingAnnotation() == annotation) { + this.mapping.synchronizeWithResourceModel(); + } else { + this.setMapping(this.buildMapping(annotation, definition)); + } + } + + protected JavaTypeMapping buildMapping(Annotation annotation, JavaTypeMappingDefinition definition) { + return (annotation != null) ? + definition.buildMapping(this, annotation, this.getJpaFactory()) : + this.buildNullMapping(); + } + + protected Iterator<JavaTypeMappingDefinition> mappingDefinitions() { + return this.getMappingDefinitions().iterator(); + } + + protected Iterable<JavaTypeMappingDefinition> getMappingDefinitions() { + return this.getJpaPlatform().getJavaTypeMappingDefinitions(); + } + + protected JavaTypeMapping buildNullMapping() { + return this.getJpaFactory().buildJavaNullTypeMapping(this); + } + + public boolean isMapped() { + return this.mapping.isMapped(); + } + + + // ********** attributes ********** + + public ListIterator<JavaPersistentAttribute> attributes() { + return this.getAttributes().iterator(); + } + + protected ListIterable<JavaPersistentAttribute> getAttributes() { + return new LiveCloneListIterable<JavaPersistentAttribute>(this.attributes); + } + + public int attributesSize() { + return this.attributes.size(); + } + + public Iterator<String> attributeNames() { + return this.getAttributeNames().iterator(); + } + + protected Iterable<String> getAttributeNames() { + return this.convertToNames(this.getAttributes()); + } + + public JavaPersistentAttribute getAttributeNamed(String attributeName) { + Iterator<JavaPersistentAttribute> stream = this.getAttributesNamed(attributeName).iterator(); + return stream.hasNext() ? stream.next() : null; + } + + public JavaPersistentAttribute getAttributeFor(JavaResourcePersistentAttribute javaResourceAttribute) { + for (JavaPersistentAttribute javaAttribute : this.getAttributes()) { + if (javaAttribute.getResourcePersistentAttribute() == javaResourceAttribute) { + return javaAttribute; + } + } + return null; + } + + public Iterator<ReadOnlyPersistentAttribute> allAttributes() { + return this.getAllAttributes().iterator(); + } + + protected Iterable<ReadOnlyPersistentAttribute> getAllAttributes() { + return new CompositeIterable<ReadOnlyPersistentAttribute>( + new TransformationIterable<PersistentType, Iterable<ReadOnlyPersistentAttribute>>(this.getInheritanceHierarchy()) { + @Override + protected Iterable<ReadOnlyPersistentAttribute> transform(PersistentType pt) { + return new SnapshotCloneIterable<ReadOnlyPersistentAttribute>(pt.attributes()); + } + } + ); + } + + public Iterator<String> allAttributeNames() { + return this.getAllAttributeNames().iterator(); + } + + protected Iterable<String> getAllAttributeNames() { + return this.convertToNames(this.getAllAttributes()); + } + + protected Iterable<JavaPersistentAttribute> getAttributesNamed(final String attributeName) { + return new FilteringIterable<JavaPersistentAttribute>(this.getAttributes()) { + @Override + protected boolean accept(JavaPersistentAttribute attribute) { + return Tools.valuesAreEqual(attributeName, attribute.getName()); + } + }; + } + + public ReadOnlyPersistentAttribute resolveAttribute(String attributeName) { + Iterator<JavaPersistentAttribute> stream = this.getAttributesNamed(attributeName).iterator(); + if (stream.hasNext()) { + JavaPersistentAttribute attribute = stream.next(); + // return null if we have more than one + return stream.hasNext() ? null : attribute; + } + // recurse + return (this.superPersistentType == null) ? null : this.superPersistentType.resolveAttribute(attributeName); + } + + protected Iterable<String> convertToNames(Iterable<? extends ReadOnlyPersistentAttribute> attrs) { + return new TransformationIterable<ReadOnlyPersistentAttribute, String>(attrs) { + @Override + protected String transform(ReadOnlyPersistentAttribute attribute) { + return attribute.getName(); + } + }; + } + + protected Iterator<JavaResourcePersistentAttribute> resourceAttributes() { + return (this.getAccess() == AccessType.PROPERTY) ? + this.resourcePersistentType.persistableProperties() : + this.resourcePersistentType.persistableFields(); + } + + protected Iterable<JavaResourcePersistentAttribute> getResourceAttributes() { + return CollectionTools.iterable(this.resourceAttributes()); + } + + protected JavaPersistentAttribute buildAttribute(JavaResourcePersistentAttribute resourceAttribute) { + return this.getJpaFactory().buildJavaPersistentAttribute(this, resourceAttribute); + } + + public boolean hasAnyAnnotatedAttributes() { + return this.resourcePersistentType.hasAnyAnnotatedAttributes(); + } + + /** + * The attributes are synchronized during the <em>update</em> because + * the list of resource attributes is determined by the access type + * which can be controlled in a number of different places.... + */ + protected void updateAttributes() { + ContextContainerTools.update(this.attributeContainerAdapter); + } + + protected void moveAttribute(int index, JavaPersistentAttribute attribute) { + this.moveItemInList(index, attribute, this.attributes, ATTRIBUTES_LIST); + } + + protected void addAttribute(int index, JavaResourcePersistentAttribute resourceAttribute) { + this.addItemToList(index, this.buildAttribute(resourceAttribute), this.attributes, ATTRIBUTES_LIST); + } + + protected void removeAttribute(JavaPersistentAttribute attribute) { + this.removeItemFromList(attribute, this.attributes, ATTRIBUTES_LIST); + } + + /** + * attribute container adapter + */ + protected class AttributeContainerAdapter + implements ContextContainerTools.Adapter<JavaPersistentAttribute, JavaResourcePersistentAttribute> + { + public Iterable<JavaPersistentAttribute> getContextElements() { + return AbstractJavaPersistentType.this.getAttributes(); + } + public Iterable<JavaResourcePersistentAttribute> getResourceElements() { + return AbstractJavaPersistentType.this.getResourceAttributes(); + } + public JavaResourcePersistentAttribute getResourceElement(JavaPersistentAttribute contextElement) { + return contextElement.getResourcePersistentAttribute(); + } + public void moveContextElement(int index, JavaPersistentAttribute element) { + AbstractJavaPersistentType.this.moveAttribute(index, element); + } + public void addContextElement(int index, JavaResourcePersistentAttribute resourceElement) { + AbstractJavaPersistentType.this.addAttribute(index, resourceElement); + } + public void removeContextElement(JavaPersistentAttribute element) { + AbstractJavaPersistentType.this.removeAttribute(element); + } + } + + + // ********** inheritance ********** + + public Iterator<PersistentType> inheritanceHierarchy() { + return this.getInheritanceHierarchy().iterator(); + } + + public Iterable<PersistentType> getInheritanceHierarchy() { + return this.getInheritanceHierarchyOf(this); + } + + public Iterator<PersistentType> ancestors() { + return this.getAncestors().iterator(); + } + + public Iterable<PersistentType> getAncestors() { + return this.getInheritanceHierarchyOf(this.superPersistentType); + } + + protected Iterable<PersistentType> getInheritanceHierarchyOf(PersistentType start) { + // using a chain iterable to traverse up the inheritance tree + return new ChainIterable<PersistentType>(start) { + @Override + protected PersistentType nextLink(PersistentType persistentType) { + return persistentType.getSuperPersistentType(); + } + }; + } + + + // ********** JpaStructureNode implementation ********** + + public String getId() { + return JavaStructureNodes.PERSISTENT_TYPE_ID; + } + + // it would be nice if the we passed in an astRoot here, but then we + // would need to pass it to the XML structure nodes too... + public JpaStructureNode getStructureNode(int offset) { + CompilationUnit astRoot = this.buildASTRoot(); + + if (this.contains(offset, astRoot)) { + for (JavaPersistentAttribute persistentAttribute : this.getAttributes()) { + if (persistentAttribute.contains(offset, astRoot)) { + return persistentAttribute; + } + } + return this; + } + return null; + } + + protected boolean contains(int offset, CompilationUnit astRoot) { + TextRange fullTextRange = this.getFullTextRange(astRoot); + // 'fullTextRange' will be null if the type no longer exists in the java; + // the context model can be out of synch with the resource model + // when a selection event occurs before the context model has a + // chance to synch with the resource model via the update thread + return (fullTextRange == null) ? false : fullTextRange.includes(offset); + } + + protected TextRange getFullTextRange(CompilationUnit astRoot) { + return this.resourcePersistentType.getTextRange(astRoot); + } + + public TextRange getSelectionTextRange() { + return this.getSelectionTextRange(this.buildASTRoot()); + } + + protected TextRange getSelectionTextRange(CompilationUnit astRoot) { + return this.resourcePersistentType.getNameTextRange(astRoot); + } + + public void dispose() { + this.unregisterRootStructureNode(); + } + + protected void registerRootStructureNode() { + JpaFile jpaFile = this.getJpaFile(); + // the JPA file can be null if the resource type is "external" + if (jpaFile != null) { + jpaFile.addRootStructureNode(this.name, this); + } + } + + protected void unregisterRootStructureNode() { + JpaFile jpaFile = this.getJpaFile(); + // the JPA file can be null if the .java file was deleted + // or the resource type is "external" + if (jpaFile != null) { + jpaFile.removeRootStructureNode(this.name, this); + } + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + Iterator<String> values = this.mapping.javaCompletionProposals(pos, filter, astRoot); + if (values != null) { + return values; + } + for (JavaPersistentAttribute attribute : this.getAttributes()) { + values = attribute.javaCompletionProposals(pos, filter, astRoot); + if (values != null) { + return values; + } + } + return EmptyIterator.instance(); + } + + + // ********** validation ********** + + public void validate(List<IMessage> messages, IReporter reporter) { + if (reporter.isCancelled()) { + throw new ValidationCancelledException(); + } + // TODO temporary hack since we don't know yet where to put + // any messages for types in another project (e.g. referenced by + // persistence.xml) + IFile file = this.resourcePersistentType.getFile(); + // 'file' will be null if the type is "external" and binary; + // the file will be in a different project if the type is "external" and source; + // the type will be binary if it is in a JAR in the current project + if ((file != null) && file.getProject().equals(this.getJpaProject().getProject()) && + (this.resourcePersistentType instanceof SourceNode)) { + // build the AST root here to pass down + this.validate(messages, reporter, this.buildASTRoot()); + } + } + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.validateMapping(messages, reporter, astRoot); + this.validateAttributes(messages, reporter, astRoot); + } + + protected void validateMapping(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + try { + this.mapping.validate(messages, reporter, astRoot); + } catch(Throwable t) { + JptJpaCorePlugin.log(t); + } + } + + protected void validateAttributes(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + for (JavaPersistentAttribute attribute : this.getAttributes()) { + this.validateAttribute(attribute, reporter, messages, astRoot); + } + } + + protected void validateAttribute(JavaPersistentAttribute attribute, IReporter reporter, List<IMessage> messages, CompilationUnit astRoot) { + try { + attribute.validate(messages, reporter, astRoot); + } catch(Throwable t) { + JptJpaCorePlugin.log(t); + } + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return this.getSelectionTextRange(astRoot); + } + + + // ********** misc ********** + + @Override + public PersistentType.Owner getParent() { + return (PersistentType.Owner) super.getParent(); + } + + @Override + public IResource getResource() { + return this.resourcePersistentType.getFile(); + } + + public JavaResourcePersistentType getResourcePersistentType() { + return this.resourcePersistentType; + } + + public AccessType getOwnerOverrideAccess() { + return this.getParent().getOverridePersistentTypeAccess(); + } + + public AccessType getOwnerDefaultAccess() { + return this.getParent().getDefaultPersistentTypeAccess(); + } + + protected CompilationUnit buildASTRoot() { + return this.resourcePersistentType.getJavaResourceCompilationUnit().buildASTRoot(); + } + + protected JpaFile getJpaFile() { + return this.getJpaFile(this.resourcePersistentType.getFile()); + } + + public boolean isFor(String typeName) { + return Tools.valuesAreEqual(typeName, this.getName()); + } + + public boolean isIn(IPackageFragment packageFragment) { + return Tools.valuesAreEqual(packageFragment.getElementName(), this.getPackageName()); + } + + protected String getPackageName() { + return this.getResourcePersistentType().getPackageName(); + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.name); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaQuery.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaQuery.java new file mode 100644 index 0000000000..9f92fa8592 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaQuery.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.Vector; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable; +import org.eclipse.jpt.jpa.core.context.Query; +import org.eclipse.jpt.jpa.core.context.QueryHint; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; +import org.eclipse.jpt.jpa.core.context.java.JavaQuery; +import org.eclipse.jpt.jpa.core.context.java.JavaQueryHint; +import org.eclipse.jpt.jpa.core.internal.context.ContextContainerTools; +import org.eclipse.jpt.jpa.core.internal.context.MappingTools; +import org.eclipse.jpt.jpa.core.resource.java.QueryAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.QueryHintAnnotation; + +/** + * Java query + */ +public abstract class AbstractJavaQuery<A extends QueryAnnotation> + extends AbstractJavaJpaContextNode + implements JavaQuery +{ + protected final A queryAnnotation; + + protected String name; + + protected String query; + + protected final Vector<JavaQueryHint> hints = new Vector<JavaQueryHint>(); + protected final HintContainerAdapter hintContainerAdapter = new HintContainerAdapter(); + + + protected AbstractJavaQuery(JavaJpaContextNode parent, A queryAnnotation) { + super(parent); + this.queryAnnotation = queryAnnotation; + this.name = queryAnnotation.getName(); + this.query = queryAnnotation.getQuery(); + this.initializeHints(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setName_(this.queryAnnotation.getName()); + this.setQuery_(this.queryAnnotation.getQuery()); + this.syncHints(); + } + + @Override + public void update() { + super.update(); + this.updateNodes(this.getHints()); + this.getPersistenceUnit().addQuery(this); + } + + + // ********** name ********** + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.queryAnnotation.setName(name); + this.setName_(name); + } + + protected void setName_(String name) { + String old = this.name; + this.name = name; + this.firePropertyChanged(NAME_PROPERTY, old, name); + } + + + // ********** query ********** + + public String getQuery() { + return this.query; + } + + public void setQuery(String query) { + this.queryAnnotation.setQuery(query); + this.setQuery_(query); + } + + protected void setQuery_(String query) { + String old = this.query; + this.query = query; + this.firePropertyChanged(QUERY_PROPERTY, old, query); + } + + + // ********** hints ********** + + public ListIterable<JavaQueryHint> getHints() { + return new LiveCloneListIterable<JavaQueryHint>(this.hints); + } + + public int getHintsSize() { + return this.hints.size(); + } + + public JavaQueryHint addHint() { + return this.addHint(this.hints.size()); + } + + public JavaQueryHint addHint(int index) { + QueryHintAnnotation annotation = this.queryAnnotation.addHint(index); + return this.addHint_(index, annotation); + } + + public void removeHint(QueryHint hint) { + this.removeHint(this.hints.indexOf(hint)); + } + + public void removeHint(int index) { + this.queryAnnotation.removeHint(index); + this.removeHint_(index); + } + + protected void removeHint_(int index) { + this.removeItemFromList(index, this.hints, HINTS_LIST); + } + + public void moveHint(int targetIndex, int sourceIndex) { + this.queryAnnotation.moveHint(targetIndex, sourceIndex); + this.moveItemInList(targetIndex, sourceIndex, this.hints, HINTS_LIST); + } + + protected void initializeHints() { + for (Iterator<QueryHintAnnotation> stream = this.queryAnnotation.hints(); stream.hasNext(); ) { + this.hints.add(this.buildHint(stream.next())); + } + } + + protected JavaQueryHint buildHint(QueryHintAnnotation hintAnnotation) { + return this.getJpaFactory().buildJavaQueryHint(this, hintAnnotation); + } + + protected void syncHints() { + ContextContainerTools.synchronizeWithResourceModel(this.hintContainerAdapter); + } + + protected Iterable<QueryHintAnnotation> getHintAnnotations() { + return CollectionTools.iterable(this.queryAnnotation.hints()); + } + + protected void moveHint_(int index, JavaQueryHint hint) { + this.moveItemInList(index, hint, this.hints, HINTS_LIST); + } + + protected JavaQueryHint addHint_(int index, QueryHintAnnotation hintAnnotation) { + JavaQueryHint hint = this.buildHint(hintAnnotation); + this.addItemToList(index, hint, this.hints, HINTS_LIST); + return hint; + } + + protected void removeHint_(JavaQueryHint hint) { + this.removeHint_(this.hints.indexOf(hint)); + } + + /** + * hint container adapter + */ + protected class HintContainerAdapter + implements ContextContainerTools.Adapter<JavaQueryHint, QueryHintAnnotation> + { + public Iterable<JavaQueryHint> getContextElements() { + return AbstractJavaQuery.this.getHints(); + } + public Iterable<QueryHintAnnotation> getResourceElements() { + return AbstractJavaQuery.this.getHintAnnotations(); + } + public QueryHintAnnotation getResourceElement(JavaQueryHint contextElement) { + return contextElement.getQueryHintAnnotation(); + } + public void moveContextElement(int index, JavaQueryHint element) { + AbstractJavaQuery.this.moveHint_(index, element); + } + public void addContextElement(int index, QueryHintAnnotation resourceElement) { + AbstractJavaQuery.this.addHint_(index, resourceElement); + } + public void removeContextElement(JavaQueryHint element) { + AbstractJavaQuery.this.removeHint_(element); + } + } + + + // ********** misc ********** + + public A getQueryAnnotation() { + return this.queryAnnotation; + } + + public boolean overrides(Query other) { + return MappingTools.nodeOverrides(this, other, PRECEDENCE_TYPE_LIST); + } + + public boolean duplicates(Query other) { + return MappingTools.nodesAreDuplicates(this, other); + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return this.queryAnnotation.getTextRange(astRoot); + } + + public TextRange getNameTextRange(CompilationUnit astRoot) { + return this.queryAnnotation.getNameTextRange(astRoot); + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.name); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaReadOnlyUniqueConstraint.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaReadOnlyUniqueConstraint.java new file mode 100644 index 0000000000..053fe6fb83 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaReadOnlyUniqueConstraint.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2008, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Vector; +import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneIterable; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; +import org.eclipse.jpt.jpa.core.context.java.JavaReadOnlyUniqueConstraint; + +public abstract class AbstractJavaReadOnlyUniqueConstraint + extends AbstractJavaJpaContextNode + implements JavaReadOnlyUniqueConstraint +{ + protected final Vector<String> columnNames = new Vector<String>(); + + + public AbstractJavaReadOnlyUniqueConstraint(JavaJpaContextNode parent) { + super(parent); + } + + + // ********** column names ********** + + public Iterable<String> getColumnNames() { + return new LiveCloneIterable<String>(this.columnNames); + } + + public int getColumnNamesSize() { + return this.columnNames.size(); + } + + public String getColumnName(int index) { + return this.columnNames.get(index); + } + + protected void syncColumnNames() { + this.synchronizeList(this.getResourceColumnNames(), this.columnNames, COLUMN_NAMES_LIST); + } + + protected abstract Iterable<String> getResourceColumnNames(); + + @Override + public void toString(StringBuilder sb) { + sb.append(this.columnNames); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaRelationshipMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaRelationshipMapping.java new file mode 100644 index 0000000000..95788f0127 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaRelationshipMapping.java @@ -0,0 +1,347 @@ +/******************************************************************************* + * Copyright (c) 2006, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.iterators.CompositeIterator; +import org.eclipse.jpt.common.utility.internal.iterators.EmptyIterator; +import org.eclipse.jpt.common.utility.internal.iterators.TransformationIterator; +import org.eclipse.jpt.jpa.core.context.AttributeMapping; +import org.eclipse.jpt.jpa.core.context.Entity; +import org.eclipse.jpt.jpa.core.context.FetchType; +import org.eclipse.jpt.jpa.core.context.PersistentAttribute; +import org.eclipse.jpt.jpa.core.context.PersistentType; +import org.eclipse.jpt.jpa.core.context.ReadOnlyPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaCascade; +import org.eclipse.jpt.jpa.core.context.java.JavaMappingRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.java.JavaRelationshipMapping; +import org.eclipse.jpt.jpa.core.internal.context.AttributeMappingTools; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.GenericJavaCascade; +import org.eclipse.jpt.jpa.core.internal.validation.DefaultJpaValidationMessages; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationMessages; +import org.eclipse.jpt.jpa.core.jpa2.context.MetamodelField; +import org.eclipse.jpt.jpa.core.resource.java.RelationshipMappingAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java relationship mapping (1:1, 1:m, m:1, m:m) + */ +public abstract class AbstractJavaRelationshipMapping<A extends RelationshipMappingAnnotation> + extends AbstractJavaAttributeMapping<A> + implements JavaRelationshipMapping +{ + protected String specifiedTargetEntity; + protected String defaultTargetEntity; + protected String fullyQualifiedTargetEntity; + + protected final JavaMappingRelationship relationship; + + protected final JavaCascade cascade; + + protected FetchType specifiedFetch; + protected FetchType defaultFetch; + + + protected AbstractJavaRelationshipMapping(JavaPersistentAttribute parent) { + super(parent); + this.specifiedTargetEntity = this.buildSpecifiedTargetEntity(); + this.relationship = this.buildRelationship(); + this.cascade = this.buildCascade(); + this.specifiedFetch = this.buildSpecifiedFetch(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setSpecifiedTargetEntity_(this.buildSpecifiedTargetEntity()); + this.relationship.synchronizeWithResourceModel(); + this.cascade.synchronizeWithResourceModel(); + this.setSpecifiedFetch_(this.buildSpecifiedFetch()); + } + + @Override + public void update() { + super.update(); + this.setDefaultTargetEntity(this.buildDefaultTargetEntity()); + this.setFullyQualifiedTargetEntity(this.buildFullyQualifiedTargetEntity()); + this.relationship.update(); + this.cascade.update(); + this.setDefaultFetch(this.buildDefaultFetch()); + } + + + // ********** target entity ********** + + public String getTargetEntity() { + return (this.specifiedTargetEntity != null) ? this.specifiedTargetEntity : this.defaultTargetEntity; + } + + public String getSpecifiedTargetEntity() { + return this.specifiedTargetEntity; + } + + public void setSpecifiedTargetEntity(String entity) { + if (this.valuesAreDifferent(entity, this.specifiedTargetEntity)) { + this.getAnnotationForUpdate().setTargetEntity(entity); + this.setSpecifiedTargetEntity_(entity); + } + } + + protected void setSpecifiedTargetEntity_(String entity) { + String old = this.specifiedTargetEntity; + this.specifiedTargetEntity = entity; + this.firePropertyChanged(SPECIFIED_TARGET_ENTITY_PROPERTY, old, entity); + } + + protected String buildSpecifiedTargetEntity() { + A annotation = this.getMappingAnnotation(); + return (annotation == null) ? null : annotation.getTargetEntity(); + } + + public String getDefaultTargetEntity() { + return this.defaultTargetEntity; + } + + protected void setDefaultTargetEntity(String entity) { + String old = this.defaultTargetEntity; + this.defaultTargetEntity = entity; + this.firePropertyChanged(DEFAULT_TARGET_ENTITY_PROPERTY, old, entity); + } + + protected abstract String buildDefaultTargetEntity(); + + public String getFullyQualifiedTargetEntity() { + return this.fullyQualifiedTargetEntity; + } + + protected void setFullyQualifiedTargetEntity(String entity) { + String old = this.fullyQualifiedTargetEntity; + this.fullyQualifiedTargetEntity = entity; + this.firePropertyChanged(FULLY_QUALIFIED_TARGET_ENTITY_PROPERTY, old, entity); + } + + protected String buildFullyQualifiedTargetEntity() { + return (this.specifiedTargetEntity == null) ? + this.defaultTargetEntity : + this.getMappingAnnotation().getFullyQualifiedTargetEntityClassName(); + } + + public Entity getResolvedTargetEntity() { + return (this.fullyQualifiedTargetEntity == null) ? null : this.getPersistenceUnit().getEntity(this.fullyQualifiedTargetEntity); + } + + // sub-classes like this to be public + public PersistentType getResolvedTargetType() { + return (this.fullyQualifiedTargetEntity == null) ? null : this.getPersistenceUnit().getPersistentType(this.fullyQualifiedTargetEntity); + } + + public char getTargetEntityEnclosingTypeSeparator() { + return '.'; + } + + + // ********** relationship reference ********** + + public JavaMappingRelationship getRelationship() { + return this.relationship; + } + + protected abstract JavaMappingRelationship buildRelationship(); + + + // ********** cascade ********** + + public JavaCascade getCascade() { + return this.cascade; + } + + protected JavaCascade buildCascade() { + // NB: we don't use the platform + return new GenericJavaCascade(this); + } + + + // ********** fetch ********** + + public FetchType getFetch() { + return (this.specifiedFetch != null) ? this.specifiedFetch : this.defaultFetch; + } + + public FetchType getSpecifiedFetch() { + return this.specifiedFetch; + } + + public void setSpecifiedFetch(FetchType fetch) { + if (this.valuesAreDifferent(fetch, this.specifiedFetch)) { + this.getAnnotationForUpdate().setFetch(FetchType.toJavaResourceModel(fetch)); + this.setSpecifiedFetch_(fetch); + } + } + + protected void setSpecifiedFetch_(FetchType fetch) { + FetchType old = this.specifiedFetch; + this.specifiedFetch = fetch; + this.firePropertyChanged(SPECIFIED_FETCH_PROPERTY, old, fetch); + } + + protected FetchType buildSpecifiedFetch() { + A annotation = this.getMappingAnnotation(); + return (annotation == null) ? null : FetchType.fromJavaResourceModel(annotation.getFetch()); + } + + public FetchType getDefaultFetch() { + return this.defaultFetch; + } + + protected void setDefaultFetch(FetchType fetch) { + FetchType old = this.defaultFetch; + this.defaultFetch = fetch; + this.firePropertyChanged(DEFAULT_FETCH_PROPERTY, old, fetch); + } + + protected abstract FetchType buildDefaultFetch(); + + + // ********** misc ********** + + @Override + public boolean isRelationshipOwner() { + return this.relationship.isOwner(); + } + + @Override + public boolean isOwnedBy(AttributeMapping mapping) { + return mapping.isRelationshipOwner() && + this.relationship.isOwnedBy((RelationshipMapping) mapping); + } + + public RelationshipMapping getRelationshipOwner() { + Entity entity = this.getResolvedTargetEntity(); + if (entity == null) { + return null; + } + for (ReadOnlyPersistentAttribute attribute : CollectionTools.iterable(entity.getPersistentType().allAttributes())) { + AttributeMapping mapping = attribute.getMapping(); + if (this.isOwnedBy(mapping)) { + return (RelationshipMapping) mapping; + } + } + return null; + } + + @Override + public boolean isOverridableAssociationMapping() { + return this.relationship.isOverridable(); + } + + public Iterator<String> allTargetEntityAttributeNames() { + return new CompositeIterator<String>(this.allTargetEntityAttributeNamesLists()); + } + + protected Iterator<Iterator<String>> allTargetEntityAttributeNamesLists() { + return new TransformationIterator<AttributeMapping, Iterator<String>>(this.allTargetEntityAttributeMappings(), AttributeMappingTools.ALL_MAPPING_NAMES_TRANSFORMER); + } + + protected Iterator<AttributeMapping> allTargetEntityAttributeMappings() { + Entity entity = this.getResolvedTargetEntity(); + return (entity != null) ? entity.allAttributeMappings() : EmptyIterator.<AttributeMapping> instance(); + } + + protected String getTargetEntityIdAttributeName() { + PersistentAttribute attribute = this.getTargetEntityIdAttribute(); + return (attribute == null) ? null : attribute.getName(); + } + + protected PersistentAttribute getTargetEntityIdAttribute() { + Entity entity = this.getResolvedTargetEntity(); + return (entity == null) ? null : entity.getIdAttribute(); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.relationship.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + return null; + } + + + // ********** metamodel ********** + + @Override + public String getMetamodelTypeName() { + return (this.fullyQualifiedTargetEntity != null) ? this.fullyQualifiedTargetEntity : MetamodelField.DEFAULT_TYPE_NAME; + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.validateTargetEntity(messages, astRoot); + this.relationship.validate(messages, reporter, astRoot); + } + + protected void validateTargetEntity(List<IMessage> messages, CompilationUnit astRoot) { + if (this.getTargetEntity() == null) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.TARGET_ENTITY_NOT_DEFINED, + new String[] {this.getName()}, + this, + this.getValidationTextRange(astRoot) + ) + ); + } + else if (this.getResolvedTargetEntity() == null) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.TARGET_ENTITY_IS_NOT_AN_ENTITY, + new String[] {this.getTargetEntity(), this.getName()}, + this, + this.getTargetEntityTextRange(astRoot) + ) + ); + } + } + + protected TextRange getTargetEntityTextRange(CompilationUnit astRoot) { + A annotation = this.getMappingAnnotation(); + return (annotation == null) ? null : this.getTextRange(annotation.getTargetEntityTextRange(astRoot), astRoot); + } + + protected TextRange getTextRange(TextRange textRange, CompilationUnit astRoot) { + return (textRange != null) ? textRange : this.getParent().getValidationTextRange(astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaSequenceGenerator.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaSequenceGenerator.java new file mode 100644 index 0000000000..c81dbb41b1 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaSequenceGenerator.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.common.utility.internal.iterables.FilteringIterable; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; +import org.eclipse.jpt.jpa.core.context.java.JavaSequenceGenerator; +import org.eclipse.jpt.jpa.core.resource.java.SequenceGeneratorAnnotation; +import org.eclipse.jpt.jpa.db.Schema; + +/** + * Java sequence generator + */ +public abstract class AbstractJavaSequenceGenerator<A extends SequenceGeneratorAnnotation> + extends AbstractJavaGenerator<A> + implements JavaSequenceGenerator +{ + protected String specifiedSequenceName; + protected String defaultSequenceName; + + + protected AbstractJavaSequenceGenerator(JavaJpaContextNode parent, A generatorAnnotation) { + super(parent, generatorAnnotation); + this.specifiedSequenceName = generatorAnnotation.getSequenceName(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setSpecifiedSequenceName_(this.generatorAnnotation.getSequenceName()); + } + + @Override + public void update() { + super.update(); + this.setDefaultSequenceName(this.buildDefaultSequenceName()); + } + + + // ********** initial value ********** + + @Override + protected int buildDefaultInitialValue() { + return DEFAULT_INITIAL_VALUE; + } + + + // ********** sequence name ********** + + public String getSequenceName() { + return (this.specifiedSequenceName != null) ? this.specifiedSequenceName : this.defaultSequenceName; + } + + public String getSpecifiedSequenceName() { + return this.specifiedSequenceName; + } + + public void setSpecifiedSequenceName(String name) { + this.generatorAnnotation.setSequenceName(name); + this.setSpecifiedSequenceName_(name); + } + + protected void setSpecifiedSequenceName_(String name) { + String old = this.specifiedSequenceName; + this.specifiedSequenceName = name; + this.firePropertyChanged(SPECIFIED_SEQUENCE_NAME_PROPERTY, old, name); + } + + public String getDefaultSequenceName() { + return this.defaultSequenceName; + } + + protected void setDefaultSequenceName(String name) { + String old = this.defaultSequenceName; + this.defaultSequenceName = name; + this.firePropertyChanged(DEFAULT_SEQUENCE_NAME_PROPERTY, old, name); + } + + protected String buildDefaultSequenceName() { + return null; // TODO the default sequence name is determined by the runtime provider... + } + + + // ********** Java completion proposals ********** + + /** + * called if the database is connected: + * sequenceName + */ + @Override + public Iterator<String> connectedJavaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.connectedJavaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + if (this.sequenceNameTouches(pos, astRoot)) { + return this.getJavaCandidateSequences(filter).iterator(); + } + return null; + } + + protected boolean sequenceNameTouches(int pos, CompilationUnit astRoot) { + return this.generatorAnnotation.sequenceNameTouches(pos, astRoot); + } + + protected Iterable<String> getJavaCandidateSequences(Filter<String> filter) { + return StringTools.convertToJavaStringLiterals(this.getCandidateSequences(filter)); + } + + protected Iterable<String> getCandidateSequences(Filter<String> filter) { + return new FilteringIterable<String>(this.getCandidateSequences(), filter); + } + + protected Iterable<String> getCandidateSequences() { + Schema dbSchema = this.getDbSchema(); + return (dbSchema != null) ? dbSchema.getSortedSequenceIdentifiers() : EmptyIterable.<String> instance(); + } + +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaSingleRelationshipMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaSingleRelationshipMapping.java new file mode 100644 index 0000000000..38ee6dc2c2 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaSingleRelationshipMapping.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.jpa.core.context.FetchType; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.internal.jpa2.context.java.NullJavaDerivedIdentity2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaDerivedIdentity2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaSingleRelationshipMapping2_0; +import org.eclipse.jpt.jpa.core.resource.java.SingleRelationshipMappingAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java single relationship mapping (1:1, m:1) + */ +public abstract class AbstractJavaSingleRelationshipMapping<A extends SingleRelationshipMappingAnnotation> + extends AbstractJavaRelationshipMapping<A> + implements JavaSingleRelationshipMapping2_0 +{ + protected Boolean specifiedOptional; + protected boolean defaultOptional; + + protected final JavaDerivedIdentity2_0 derivedIdentity; + + + protected AbstractJavaSingleRelationshipMapping(JavaPersistentAttribute parent) { + super(parent); + this.specifiedOptional = this.buildSpecifiedOptional(); + this.derivedIdentity = this.buildDerivedIdentity(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setSpecifiedOptional_(this.buildSpecifiedOptional()); + this.derivedIdentity.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + this.setDefaultOptional(this.buildDefaultOptional()); + this.derivedIdentity.update(); + } + + + // ********** optional ********** + + public boolean isOptional() { + return (this.specifiedOptional != null) ? this.specifiedOptional.booleanValue() : this.defaultOptional; + } + + public Boolean getSpecifiedOptional() { + return this.specifiedOptional; + } + + public void setSpecifiedOptional(Boolean optional) { + if (this.valuesAreDifferent(optional, this.specifiedOptional)) { + this.getAnnotationForUpdate().setOptional(optional); + this.setSpecifiedOptional_(optional); + } + } + + protected void setSpecifiedOptional_(Boolean optional) { + Boolean old = this.specifiedOptional; + this.specifiedOptional = optional; + this.firePropertyChanged(SPECIFIED_OPTIONAL_PROPERTY, old, optional); + } + + protected Boolean buildSpecifiedOptional() { + A annotation = this.getMappingAnnotation(); + return (annotation == null) ? null : annotation.getOptional(); + } + + public boolean isDefaultOptional() { + return this.defaultOptional; + } + + protected void setDefaultOptional(boolean optional) { + boolean old = this.defaultOptional; + this.defaultOptional = optional; + this.firePropertyChanged(DEFAULT_OPTIONAL_PROPERTY, old, optional); + } + + protected boolean buildDefaultOptional() { + return DEFAULT_OPTIONAL; + } + + + // ********** derived identity ********** + + public JavaDerivedIdentity2_0 getDerivedIdentity() { + return this.derivedIdentity; + } + + protected JavaDerivedIdentity2_0 buildDerivedIdentity() { + return this.isJpa2_0Compatible() ? + this.getJpaFactory2_0().buildJavaDerivedIdentity(this) : + new NullJavaDerivedIdentity2_0(this); + } + + + // ********** misc ********** + + @Override + protected FetchType buildDefaultFetch() { + return DEFAULT_FETCH_TYPE; + } + + @Override + protected String buildDefaultTargetEntity() { + return this.getPersistentAttribute().getSingleReferenceTargetTypeName(); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.derivedIdentity.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + return null; + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.derivedIdentity.validate(messages, reporter, astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaTable.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaTable.java new file mode 100644 index 0000000000..302f4af238 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaTable.java @@ -0,0 +1,584 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Vector; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.NameTools; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.common.utility.internal.iterables.FilteringIterable; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable; +import org.eclipse.jpt.common.utility.internal.iterators.EmptyIterator; +import org.eclipse.jpt.jpa.core.context.ReadOnlyTable; +import org.eclipse.jpt.jpa.core.context.ReadOnlyUniqueConstraint; +import org.eclipse.jpt.jpa.core.context.UniqueConstraint; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; +import org.eclipse.jpt.jpa.core.context.java.JavaTable; +import org.eclipse.jpt.jpa.core.context.java.JavaUniqueConstraint; +import org.eclipse.jpt.jpa.core.internal.context.ContextContainerTools; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.TableTextRangeResolver; +import org.eclipse.jpt.jpa.core.resource.java.BaseTableAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.UniqueConstraintAnnotation; +import org.eclipse.jpt.jpa.db.Catalog; +import org.eclipse.jpt.jpa.db.Database; +import org.eclipse.jpt.jpa.db.Schema; +import org.eclipse.jpt.jpa.db.SchemaContainer; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java table, secondary table, join table, or collection table + * <p> + * <strong>NB:</strong> any subclass that directly holds its table + * annotation must:<ul> + * <li>call the "super" constructor that takes a table annotation + * {@link #AbstractJavaTable(JavaJpaContextNode, org.eclipse.jpt.jpa.core.context.Table.Owner, BaseTableAnnotation)} + * <li>override {@link #setTableAnnotation(BaseTableAnnotation)} to set the table + * annotation so it is in place before the table's state + * (e.g. {@link #specifiedName}) is initialized + * </ul> + */ +public abstract class AbstractJavaTable<A extends BaseTableAnnotation> + extends AbstractJavaJpaContextNode + implements JavaTable, UniqueConstraint.Owner +{ + protected final Owner owner; + + protected String specifiedName; + protected String defaultName; + + protected String specifiedSchema; + protected String defaultSchema; + + protected String specifiedCatalog; + protected String defaultCatalog; + + protected final Vector<JavaUniqueConstraint> uniqueConstraints = new Vector<JavaUniqueConstraint>(); + protected final UniqueConstraintContainerAdapter uniqueConstraintContainerAdapter = new UniqueConstraintContainerAdapter(); + + + protected AbstractJavaTable(JavaJpaContextNode parent, Owner owner) { + this(parent, owner, null); + } + + protected AbstractJavaTable(JavaJpaContextNode parent, Owner owner, A tableAnnotation) { + super(parent); + this.owner = owner; + this.setTableAnnotation(tableAnnotation); + this.specifiedName = this.buildSpecifiedName(); + this.specifiedSchema = this.buildSpecifiedSchema(); + this.specifiedCatalog = this.buildSpecifiedCatalog(); + this.initializeUniqueConstraints(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setSpecifiedName_(this.buildSpecifiedName()); + this.setSpecifiedSchema_(this.buildSpecifiedSchema()); + this.setSpecifiedCatalog_(this.buildSpecifiedCatalog()); + this.syncUniqueConstraints(); + } + + @Override + public void update() { + super.update(); + this.setDefaultName(this.buildDefaultName()); + this.setDefaultSchema(this.buildDefaultSchema()); + this.setDefaultCatalog(this.buildDefaultCatalog()); + this.updateNodes(this.getUniqueConstraints()); + } + + + // ********** table annotation ********** + + /** + * Return the Java table annotation. Do not return <code>null</code> if the + * Java annotation does not exist; return a <em>null</em> table annotation + * instead. + */ + public abstract A getTableAnnotation(); + + /** + * see class comment... ({@link AbstractJavaTable}) + */ + protected void setTableAnnotation(A tableAnnotation) { + if (tableAnnotation != null) { + throw new IllegalArgumentException("this method must be overridden if the table annotation is not null: " + tableAnnotation); //$NON-NLS-1$ + } + } + + protected void removeTableAnnotationIfUnset() { + if (this.getTableAnnotation().isUnset()) { + this.removeTableAnnotation(); + } + } + + protected abstract void removeTableAnnotation(); + + public boolean isSpecifiedInResource() { + return this.getTableAnnotation().isSpecified(); + } + + + // ********** name ********** + + public String getName() { + return (this.specifiedName != null) ? this.specifiedName : this.defaultName; + } + + public String getSpecifiedName() { + return this.specifiedName; + } + + public void setSpecifiedName(String name) { + if (this.valuesAreDifferent(this.specifiedName, name)) { + this.getTableAnnotation().setName(name); + this.removeTableAnnotationIfUnset(); + this.setSpecifiedName_(name); + } + } + + protected void setSpecifiedName_(String name) { + String old = this.specifiedName; + this.specifiedName = name; + this.firePropertyChanged(SPECIFIED_NAME_PROPERTY, old, name); + } + + protected String buildSpecifiedName() { + return this.getTableAnnotation().getName(); + } + + public String getDefaultName() { + return this.defaultName; + } + + protected void setDefaultName(String name) { + String old = this.defaultName; + this.defaultName = name; + this.firePropertyChanged(DEFAULT_NAME_PROPERTY, old, name); + } + + protected abstract String buildDefaultName(); + + + // ********** schema ********** + + public String getSchema() { + return (this.specifiedSchema != null) ? this.specifiedSchema : this.defaultSchema; + } + + public String getSpecifiedSchema() { + return this.specifiedSchema; + } + + public void setSpecifiedSchema(String schema) { + if (this.valuesAreDifferent(this.specifiedSchema, schema)) { + this.getTableAnnotation().setSchema(schema); + this.removeTableAnnotationIfUnset(); + this.setSpecifiedSchema_(schema); + } + } + + protected void setSpecifiedSchema_(String schema) { + String old = this.specifiedSchema; + this.specifiedSchema = schema; + this.firePropertyChanged(SPECIFIED_SCHEMA_PROPERTY, old, schema); + } + + protected String buildSpecifiedSchema() { + return this.getTableAnnotation().getSchema(); + } + + public String getDefaultSchema() { + return this.defaultSchema; + } + + protected void setDefaultSchema(String schema) { + String old = this.defaultSchema; + this.defaultSchema = schema; + this.firePropertyChanged(DEFAULT_SCHEMA_PROPERTY, old, schema); + } + + protected abstract String buildDefaultSchema(); + + + // ********** catalog ********** + + public String getCatalog() { + return (this.specifiedCatalog != null) ? this.specifiedCatalog : this.defaultCatalog; + } + + public String getSpecifiedCatalog() { + return this.specifiedCatalog; + } + + public void setSpecifiedCatalog(String catalog) { + if (this.valuesAreDifferent(this.specifiedCatalog, catalog)) { + this.getTableAnnotation().setCatalog(catalog); + this.removeTableAnnotationIfUnset(); + this.setSpecifiedCatalog_(catalog); + } + } + + protected void setSpecifiedCatalog_(String catalog) { + String old = this.specifiedCatalog; + this.specifiedCatalog = catalog; + this.firePropertyChanged(SPECIFIED_CATALOG_PROPERTY, old, catalog); + } + + protected String buildSpecifiedCatalog() { + return this.getTableAnnotation().getCatalog(); + } + + public String getDefaultCatalog() { + return this.defaultCatalog; + } + + protected void setDefaultCatalog(String catalog) { + String old = this.defaultCatalog; + this.defaultCatalog = catalog; + this.firePropertyChanged(DEFAULT_CATALOG_PROPERTY, old, catalog); + } + + protected abstract String buildDefaultCatalog(); + + + // ********** unique constraints ********** + + public ListIterator<JavaUniqueConstraint> uniqueConstraints() { + return this.getUniqueConstraints().iterator(); + } + + protected ListIterable<JavaUniqueConstraint> getUniqueConstraints() { + return new LiveCloneListIterable<JavaUniqueConstraint>(this.uniqueConstraints); + } + + public int uniqueConstraintsSize() { + return this.uniqueConstraints.size(); + } + + public JavaUniqueConstraint getUniqueConstraint(int index) { + return this.uniqueConstraints.get(index); + } + + public JavaUniqueConstraint addUniqueConstraint() { + return this.addUniqueConstraint(this.uniqueConstraints.size()); + } + + public JavaUniqueConstraint addUniqueConstraint(int index) { + UniqueConstraintAnnotation annotation = this.getTableAnnotation().addUniqueConstraint(index); + return this.addUniqueConstraint_(index, annotation); + } + + public void removeUniqueConstraint(UniqueConstraint constraint) { + this.removeUniqueConstraint(this.uniqueConstraints.indexOf(constraint)); + } + + public void removeUniqueConstraint(int index) { + this.getTableAnnotation().removeUniqueConstraint(index); + this.removeTableAnnotationIfUnset(); + this.removeUniqueConstraint_(index); + } + + protected void removeUniqueConstraint_(int index) { + this.removeItemFromList(index, this.uniqueConstraints, UNIQUE_CONSTRAINTS_LIST); + } + + public void moveUniqueConstraint(int targetIndex, int sourceIndex) { + this.getTableAnnotation().moveUniqueConstraint(targetIndex, sourceIndex); + this.moveItemInList(targetIndex, sourceIndex, this.uniqueConstraints, UNIQUE_CONSTRAINTS_LIST); + } + + protected void initializeUniqueConstraints() { + for (Iterator<UniqueConstraintAnnotation> stream = this.getTableAnnotation().uniqueConstraints(); stream.hasNext(); ) { + this.uniqueConstraints.add(this.buildUniqueConstraint(stream.next())); + } + } + + protected JavaUniqueConstraint buildUniqueConstraint(UniqueConstraintAnnotation constraintAnnotation) { + return this.getJpaFactory().buildJavaUniqueConstraint(this, this, constraintAnnotation); + } + + protected void syncUniqueConstraints() { + ContextContainerTools.synchronizeWithResourceModel(this.uniqueConstraintContainerAdapter); + } + + protected Iterable<UniqueConstraintAnnotation> getUniqueConstraintAnnotations() { + return CollectionTools.iterable(this.getTableAnnotation().uniqueConstraints()); + } + + protected void moveUniqueConstraint_(int index, JavaUniqueConstraint constraint) { + this.moveItemInList(index, constraint, this.uniqueConstraints, UNIQUE_CONSTRAINTS_LIST); + } + + protected JavaUniqueConstraint addUniqueConstraint_(int index, UniqueConstraintAnnotation constraintAnnotation) { + JavaUniqueConstraint constraint = this.buildUniqueConstraint(constraintAnnotation); + this.addItemToList(index, constraint, this.uniqueConstraints, UNIQUE_CONSTRAINTS_LIST); + return constraint; + } + + protected void removeUniqueConstraint_(JavaUniqueConstraint constraint) { + this.removeUniqueConstraint_(this.uniqueConstraints.indexOf(constraint)); + } + + /** + * unique constraint container adapter + */ + protected class UniqueConstraintContainerAdapter + implements ContextContainerTools.Adapter<JavaUniqueConstraint, UniqueConstraintAnnotation> + { + public Iterable<JavaUniqueConstraint> getContextElements() { + return AbstractJavaTable.this.getUniqueConstraints(); + } + public Iterable<UniqueConstraintAnnotation> getResourceElements() { + return AbstractJavaTable.this.getUniqueConstraintAnnotations(); + } + public UniqueConstraintAnnotation getResourceElement(JavaUniqueConstraint contextElement) { + return contextElement.getUniqueConstraintAnnotation(); + } + public void moveContextElement(int index, JavaUniqueConstraint element) { + AbstractJavaTable.this.moveUniqueConstraint_(index, element); + } + public void addContextElement(int index, UniqueConstraintAnnotation resourceElement) { + AbstractJavaTable.this.addUniqueConstraint_(index, resourceElement); + } + public void removeContextElement(JavaUniqueConstraint element) { + AbstractJavaTable.this.removeUniqueConstraint_(element); + } + } + + + // ********** database stuff ********** + + public org.eclipse.jpt.jpa.db.Table getDbTable() { + Schema dbSchema = this.getDbSchema(); + return (dbSchema == null) ? null : dbSchema.getTableForIdentifier(this.getName()); + } + + public Schema getDbSchema() { + SchemaContainer dbSchemaContainer = this.getDbSchemaContainer(); + return (dbSchemaContainer == null) ? null : dbSchemaContainer.getSchemaForIdentifier(this.getSchema()); + } + + /** + * If we don't have a catalog (i.e. we don't even have a <em>default</em> catalog), + * then the database probably does not support catalogs; and we need to + * get the schema directly from the database. + */ + public SchemaContainer getDbSchemaContainer() { + String catalog = this.getCatalog(); + return (catalog != null) ? this.resolveDbCatalog(catalog) : this.getDatabase(); + } + + /** + * If we don't have a catalog (i.e. we don't even have a <em>default</em> + * catalog), then the database probably does not support catalogs. + */ + public Catalog getDbCatalog() { + String catalog = this.getCatalog(); + return (catalog == null) ? null : this.resolveDbCatalog(catalog); + } + + public boolean isResolved() { + return this.getDbTable() != null; + } + + public boolean schemaIsResolved() { + return this.getDbSchema() != null; + } + + /** + * If we don't have a catalog (i.e. we don't even have a <em>default</em> + * catalog), then the database probably does not support catalogs. + */ + public boolean catalogIsResolved() { + String catalog = this.getCatalog(); + return (catalog == null) || (this.resolveDbCatalog(catalog) != null); + } + + + // ********** UniqueConstraint.Owner implementation ********** + + public Iterator<String> candidateUniqueConstraintColumnNames() { + org.eclipse.jpt.jpa.db.Table dbTable = this.getDbTable(); + return (dbTable != null) ? dbTable.getSortedColumnIdentifiers().iterator() : EmptyIterator.<String>instance(); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + for (JavaUniqueConstraint constraint : CollectionTools.iterable(this.uniqueConstraints())) { + result = constraint.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + } + return null; + } + + /** + * called if the database is connected: + * name, schema, catalog + */ + @Override + public Iterator<String> connectedJavaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.connectedJavaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + if (this.nameTouches(pos, astRoot)) { + return this.getJavaCandidateNames(filter).iterator(); + } + if (this.schemaTouches(pos, astRoot)) { + return this.getJavaCandidateSchemata(filter).iterator(); + } + if (this.catalogTouches(pos, astRoot)) { + return this.getJavaCandidateCatalogs(filter).iterator(); + } + return null; + } + + protected boolean nameTouches(int pos, CompilationUnit astRoot) { + return this.getTableAnnotation().nameTouches(pos, astRoot); + } + + protected Iterable<String> getJavaCandidateNames(Filter<String> filter) { + return StringTools.convertToJavaStringLiterals(this.getCandidateNames(filter)); + } + + protected Iterable<String> getCandidateNames(Filter<String> filter) { + return new FilteringIterable<String>(this.getCandidateNames(), filter); + } + + protected Iterable<String> getCandidateNames() { + Schema dbSchema = this.getDbSchema(); + return (dbSchema != null) ? dbSchema.getSortedTableIdentifiers() : EmptyIterable.<String> instance(); + } + + protected boolean schemaTouches(int pos, CompilationUnit astRoot) { + return this.getTableAnnotation().schemaTouches(pos, astRoot); + } + + protected Iterable<String> getJavaCandidateSchemata(Filter<String> filter) { + return StringTools.convertToJavaStringLiterals(this.getCandidateSchemata(filter)); + } + + protected Iterable<String> getCandidateSchemata(Filter<String> filter) { + return new FilteringIterable<String>(this.getCandidateSchemata(), filter); + } + + protected Iterable<String> getCandidateSchemata() { + return this.getDbSchemaContainer().getSortedSchemaIdentifiers(); + } + + protected boolean catalogTouches(int pos, CompilationUnit astRoot) { + return this.getTableAnnotation().catalogTouches(pos, astRoot); + } + + protected Iterable<String> getJavaCandidateCatalogs(Filter<String> filter) { + return StringTools.convertToJavaStringLiterals(this.getCandidateCatalogs(filter)); + } + + protected Iterable<String> getCandidateCatalogs(Filter<String> filter) { + return new FilteringIterable<String>(this.getCandidateCatalogs(), filter); + } + + protected Iterable<String> getCandidateCatalogs() { + Database db = this.getDatabase(); + return (db != null) ? db.getSortedCatalogIdentifiers() : EmptyIterable.<String> instance(); + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.buildTableValidator(astRoot).validate(messages, reporter); + } + + protected JptValidator buildTableValidator(CompilationUnit astRoot) { + return this.owner.buildTableValidator(this, buildTextRangeResolver(astRoot)); + } + + protected TableTextRangeResolver buildTextRangeResolver(CompilationUnit astRoot) { + return new JavaTableTextRangeResolver(this, astRoot); + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return this.getTextRange(this.getTableAnnotation().getTextRange(astRoot), astRoot); + } + + public TextRange getNameTextRange(CompilationUnit astRoot) { + return this.getTextRange(this.getTableAnnotation().getNameTextRange(astRoot), astRoot); + } + + public TextRange getSchemaTextRange(CompilationUnit astRoot) { + return this.getTextRange(this.getTableAnnotation().getSchemaTextRange(astRoot), astRoot); + } + + public TextRange getCatalogTextRange(CompilationUnit astRoot) { + return this.getTextRange(this.getTableAnnotation().getCatalogTextRange(astRoot), astRoot); + } + + protected TextRange getTextRange(TextRange textRange, CompilationUnit astRoot) { + return (textRange != null) ? textRange : this.getParent().getValidationTextRange(astRoot); + } + + + // ********** misc ********** + + @Override + public JavaJpaContextNode getParent() { + return (JavaJpaContextNode) super.getParent(); + } + + protected void initializeFrom(ReadOnlyTable oldTable) { + this.setSpecifiedName(oldTable.getSpecifiedName()); + this.setSpecifiedCatalog(oldTable.getSpecifiedCatalog()); + this.setSpecifiedSchema(oldTable.getSpecifiedSchema()); + for (ReadOnlyUniqueConstraint constraint : CollectionTools.iterable(oldTable.uniqueConstraints())) { + this.addUniqueConstraint().initializeFrom(constraint); + } + } + + protected void initializeFromVirtual(ReadOnlyTable virtualTable) { + this.setSpecifiedName(virtualTable.getName()); + // ignore other settings? + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.buildQualifiedName()); + } + + protected String buildQualifiedName() { + return NameTools.buildQualifiedDatabaseObjectName(this.getCatalog(), this.getSchema(), this.getName()); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaTypeMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaTypeMapping.java new file mode 100644 index 0000000000..7aeada737c --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaTypeMapping.java @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright (c) 2006, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.NotNullFilter; +import org.eclipse.jpt.common.utility.internal.Tools; +import org.eclipse.jpt.common.utility.internal.iterables.FilteringIterable; +import org.eclipse.jpt.common.utility.internal.iterators.CompositeIterator; +import org.eclipse.jpt.common.utility.internal.iterators.EmptyIterator; +import org.eclipse.jpt.common.utility.internal.iterators.FilteringIterator; +import org.eclipse.jpt.common.utility.internal.iterators.TransformationIterator; +import org.eclipse.jpt.jpa.core.context.AttributeMapping; +import org.eclipse.jpt.jpa.core.context.Column; +import org.eclipse.jpt.jpa.core.context.PersistentType; +import org.eclipse.jpt.jpa.core.context.ReadOnlyTable; +import org.eclipse.jpt.jpa.core.context.Relationship; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType; +import org.eclipse.jpt.jpa.core.context.java.JavaTypeMapping; +import org.eclipse.jpt.jpa.core.internal.context.AttributeMappingTools; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.TypeMappingTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.TypeMappingTools; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.GenericTypeMappingValidator; +import org.eclipse.jpt.jpa.core.resource.java.Annotation; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentType; +import org.eclipse.jpt.jpa.db.Schema; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java type mapping + */ +public abstract class AbstractJavaTypeMapping<A extends Annotation> + extends AbstractJavaJpaContextNode + implements JavaTypeMapping +{ + // this can be null for a "null" type mapping + protected final A mappingAnnotation; + + + protected AbstractJavaTypeMapping(JavaPersistentType parent, A mappingAnnotation) { + super(parent); + this.mappingAnnotation = mappingAnnotation; + } + + + // ********** misc ********** + + @Override + public JavaPersistentType getParent() { + return (JavaPersistentType) super.getParent(); + } + + public JavaPersistentType getPersistentType() { + return this.getParent(); + } + + public JavaResourcePersistentType getResourcePersistentType() { + return this.getPersistentType().getResourcePersistentType(); + } + + public String getName() { + return this.getPersistentType().getName(); + } + + public A getMappingAnnotation() { + return this.mappingAnnotation; + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.getPersistentType().getName()); + } + + + // ********** tables ********** + + public String getPrimaryTableName() { + return null; + } + + public org.eclipse.jpt.jpa.db.Table getPrimaryDbTable() { + return null; + } + + public Schema getDbSchema() { + return null; + } + + public Iterator<ReadOnlyTable> associatedTables() { + return EmptyIterator.instance(); + } + + public Iterator<ReadOnlyTable> allAssociatedTables() { + return EmptyIterator.instance(); + } + + public Iterator<String> allAssociatedTableNames() { + return EmptyIterator.instance(); + } + + public org.eclipse.jpt.jpa.db.Table resolveDbTable(String tableName) { + return null; + } + + + // ********** inheritance ********** + + public TypeMapping getSuperTypeMapping() { + PersistentType superPersistentType = this.getPersistentType().getSuperPersistentType(); + return (superPersistentType == null) ? null : superPersistentType.getMapping(); + } + + public Iterator<TypeMapping> inheritanceHierarchy() { + return this.convertToMappings(this.getPersistentType().inheritanceHierarchy()); + } + + protected Iterable<TypeMapping> getInheritanceHierarchy() { + return CollectionTools.iterable(this.inheritanceHierarchy()); + } + + /** + * Return the type mapping's "persistence" ancestors, + * <em>excluding</em> the type mapping itself. + * The returned iterator will return elements infinitely if the hierarchy + * has a loop. + */ + protected Iterator<TypeMapping> ancestors() { + return this.convertToMappings(this.getPersistentType().ancestors()); + } + + protected Iterable<TypeMapping> getAncestors() { + return CollectionTools.iterable(this.ancestors()); + } + + protected Iterator<TypeMapping> convertToMappings(Iterator<PersistentType> types) { + return new TransformationIterator<PersistentType, TypeMapping>(types) { + @Override + protected TypeMapping transform(PersistentType type) { + return type.getMapping(); + } + }; + } + + + // ********** attribute mappings ********** + + public Iterator<JavaAttributeMapping> attributeMappings() { + return new TransformationIterator<JavaPersistentAttribute, JavaAttributeMapping>(this.getPersistentType().attributes()) { + @Override + protected JavaAttributeMapping transform(JavaPersistentAttribute attribute) { + return attribute.getMapping(); + } + }; + } + + public Iterable<JavaAttributeMapping> getAttributeMappings(final String mappingKey) { + return new FilteringIterable<JavaAttributeMapping>(CollectionTools.collection(this.attributeMappings())) { + @Override + protected boolean accept(JavaAttributeMapping o) { + return Tools.valuesAreEqual(o.getKey(), mappingKey); + } + }; + } + + public Iterator<AttributeMapping> allAttributeMappings() { + return new CompositeIterator<AttributeMapping>(this.allAttributeMappingsLists()); + } + + protected Iterator<Iterator<AttributeMapping>> allAttributeMappingsLists() { + return new TransformationIterator<TypeMapping, Iterator<AttributeMapping>>(this.nonNullInheritanceHierarchy(), TypeMappingTools.ATTRIBUTE_MAPPINGS_TRANSFORMER); + } + + protected Iterator<TypeMapping> nonNullInheritanceHierarchy() { + return new FilteringIterator<TypeMapping>(this.inheritanceHierarchy(), NotNullFilter.<TypeMapping>instance()); + } + + public Iterable<AttributeMapping> getAllAttributeMappings(final String mappingKey) { + return new FilteringIterable<AttributeMapping>(CollectionTools.collection(this.allAttributeMappings())) { + @Override + protected boolean accept(AttributeMapping o) { + return Tools.valuesAreEqual(o.getKey(), mappingKey); + } + }; + } + + public boolean attributeMappingKeyAllowed(String attributeMappingKey) { + return true; + } + + + // ********** attribute overrides ********** + + public Iterator<String> overridableAttributeNames() { + return new CompositeIterator<String>(this.overridableAttributeNamesLists()); + } + + protected Iterator<Iterator<String>> overridableAttributeNamesLists() { + return new TransformationIterator<AttributeMapping, Iterator<String>>(this.attributeMappings(), AttributeMappingTools.ALL_OVERRIDABLE_ATTRIBUTE_MAPPING_NAMES_TRANSFORMER); + } + + public Iterator<String> allOverridableAttributeNames() { + return new CompositeIterator<String>(this.allOverridableAttributeNamesLists()); + } + + protected Iterator<Iterator<String>> allOverridableAttributeNamesLists() { + return new TransformationIterator<TypeMapping, Iterator<String>>(this.inheritanceHierarchy(), TypeMappingTools.OVERRIDABLE_ATTRIBUTE_NAMES_TRANSFORMER); + } + + public Column resolveOverriddenColumn(String attributeName) { + for (AttributeMapping attributeMapping : CollectionTools.iterable(this.attributeMappings())) { + Column column = attributeMapping.resolveOverriddenColumn(attributeName); + if (column != null) { + return column; + } + } + return null; + } + + + // ********** association overrides ********** + + public Iterator<String> overridableAssociationNames() { + return new CompositeIterator<String>(this.overridableAssociationNamesLists()); + } + + protected Iterator<Iterator<String>> overridableAssociationNamesLists() { + return new TransformationIterator<AttributeMapping, Iterator<String>>(this.attributeMappings(), AttributeMappingTools.ALL_OVERRIDABLE_ASSOCIATION_MAPPING_NAMES_TRANSFORMER); + } + + public Iterator<String> allOverridableAssociationNames() { + return new CompositeIterator<String>(this.allOverridableAssociationNamesLists()); + } + + protected Iterator<Iterator<String>> allOverridableAssociationNamesLists() { + return new TransformationIterator<TypeMapping, Iterator<String>>(this.inheritanceHierarchy(), TypeMappingTools.OVERRIDABLE_ASSOCIATION_NAMES_TRANSFORMER); + } + + public Relationship resolveOverriddenRelationship(String attributeName) { + for (AttributeMapping attributeMapping : CollectionTools.iterable(this.attributeMappings())) { + Relationship relationship = attributeMapping.resolveOverriddenRelationship(attributeName); + if (relationship != null) { + return relationship; + } + } + return null; + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.validateType(messages, reporter, astRoot); + } + + protected void validateType(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + this.buildTypeMappingValidator(astRoot).validate(messages, reporter); + } + + protected JptValidator buildTypeMappingValidator(CompilationUnit astRoot) { + return new GenericTypeMappingValidator(this, this.getResourcePersistentType(), buildTextRangeResolver(astRoot)); + } + + protected TypeMappingTextRangeResolver buildTextRangeResolver(CompilationUnit astRoot) { + return new JavaTypeMappingTextRangeResolver(this, astRoot); + } + + public boolean validatesAgainstDatabase() { + return this.getPersistenceUnit().validatesAgainstDatabase(); + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + TextRange textRange = this.mappingAnnotation.getTextRange(astRoot); + return (textRange != null) ? textRange : this.getPersistentType().getValidationTextRange(astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVersionMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVersionMapping.java new file mode 100644 index 0000000000..b88646d9e0 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVersionMapping.java @@ -0,0 +1,276 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.Association; +import org.eclipse.jpt.common.utility.internal.SimpleAssociation; +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.BaseColumn; +import org.eclipse.jpt.jpa.core.context.Converter; +import org.eclipse.jpt.jpa.core.context.NamedColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaConverter; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.java.JavaTemporalConverter; +import org.eclipse.jpt.jpa.core.context.java.JavaVersionMapping; +import org.eclipse.jpt.jpa.core.internal.context.BaseColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.EntityTableDescriptionProvider; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.NamedColumnValidator; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.NullJavaConverter; +import org.eclipse.jpt.jpa.core.resource.java.Annotation; +import org.eclipse.jpt.jpa.core.resource.java.ColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.VersionAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java version mapping + */ +public abstract class AbstractJavaVersionMapping + extends AbstractJavaAttributeMapping<VersionAnnotation> + implements JavaVersionMapping +{ + protected final JavaColumn column; + + protected JavaConverter converter; // never null + + + // the spec does not list Temporal explicitly, + // but it is included in the orm.xml schema... + protected static final JavaConverter.Adapter[] CONVERTER_ADAPTER_ARRAY = new JavaConverter.Adapter[] { + JavaTemporalConverter.Adapter.instance(), + }; + protected static final Iterable<JavaConverter.Adapter> CONVERTER_ADAPTERS = new ArrayIterable<JavaConverter.Adapter>(CONVERTER_ADAPTER_ARRAY); + + + protected AbstractJavaVersionMapping(JavaPersistentAttribute parent) { + super(parent); + this.column = this.buildColumn(); + this.converter = this.buildConverter(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.column.synchronizeWithResourceModel(); + this.syncConverter(); + } + + @Override + public void update() { + super.update(); + this.column.update(); + this.converter.update(); + } + + + // ********** column ********** + + public JavaColumn getColumn() { + return this.column; + } + + protected JavaColumn buildColumn() { + return this.getJpaFactory().buildJavaColumn(this, this); + } + + + // ********** converter ********** + + public JavaConverter getConverter() { + return this.converter; + } + + public void setConverter(Class<? extends Converter> converterType) { + if (this.converter.getType() != converterType) { + this.converter.dispose(); + JavaConverter.Adapter converterAdapter = this.getConverterAdapter(converterType); + this.retainConverterAnnotation(converterAdapter); + this.setConverter_(this.buildConverter(converterAdapter)); + } + } + + protected JavaConverter buildConverter(JavaConverter.Adapter converterAdapter) { + return (converterAdapter != null) ? + converterAdapter.buildNewConverter(this, this.getJpaFactory()) : + this.buildNullConverter(); + } + + protected void setConverter_(JavaConverter converter) { + Converter old = this.converter; + this.converter = converter; + this.firePropertyChanged(CONVERTER_PROPERTY, old, converter); + } + + /** + * Clear all the converter annotations <em>except</em> for the annotation + * corresponding to the specified adapter. If the specified adapter is + * <code>null</code>, remove <em>all</em> the converter annotations. + */ + protected void retainConverterAnnotation(JavaConverter.Adapter converterAdapter) { + JavaResourcePersistentAttribute resourceAttribute = this.getResourcePersistentAttribute(); + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + if (adapter != converterAdapter) { + adapter.removeConverterAnnotation(resourceAttribute); + } + } + } + + protected JavaConverter buildConverter() { + JpaFactory jpaFactory = this.getJpaFactory(); + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + JavaConverter javaConverter = adapter.buildConverter(this, jpaFactory); + if (javaConverter != null) { + return javaConverter; + } + } + return this.buildNullConverter(); + } + + protected void syncConverter() { + Association<JavaConverter.Adapter, Annotation> assoc = this.getConverterAnnotation(); + if (assoc == null) { + if (this.converter.getType() != null) { + this.setConverter_(this.buildNullConverter()); + } + } else { + JavaConverter.Adapter adapter = assoc.getKey(); + Annotation annotation = assoc.getValue(); + if ((this.converter.getType() == adapter.getConverterType()) && + (this.converter.getConverterAnnotation() == annotation)) { + this.converter.synchronizeWithResourceModel(); + } else { + this.setConverter_(adapter.buildConverter(annotation, this, this.getJpaFactory())); + } + } + } + + /** + * Return the first converter annotation we find along with its corresponding + * adapter. Return <code>null</code> if there are no converter annotations. + */ + protected Association<JavaConverter.Adapter, Annotation> getConverterAnnotation() { + JavaResourcePersistentAttribute resourceAttribute = this.getResourcePersistentAttribute(); + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + Annotation annotation = adapter.getConverterAnnotation(resourceAttribute); + if (annotation != null) { + return new SimpleAssociation<JavaConverter.Adapter, Annotation>(adapter, annotation); + } + } + return null; + } + + protected JavaConverter buildNullConverter() { + return new NullJavaConverter(this); + } + + + // ********** converter adapters ********** + + /** + * Return the converter adapter for the specified converter type. + */ + protected JavaConverter.Adapter getConverterAdapter(Class<? extends Converter> converterType) { + for (JavaConverter.Adapter adapter : this.getConverterAdapters()) { + if (adapter.getConverterType() == converterType) { + return adapter; + } + } + return null; + } + + protected Iterable<JavaConverter.Adapter> getConverterAdapters() { + return CONVERTER_ADAPTERS; + } + + + // ********** misc ********** + + public String getKey() { + return MappingKeys.VERSION_ATTRIBUTE_MAPPING_KEY; + } + + @Override + protected String getAnnotationName() { + return VersionAnnotation.ANNOTATION_NAME; + } + + + // ********** JavaColumn.Owner implementation ********** + + public ColumnAnnotation getColumnAnnotation() { + return (ColumnAnnotation) this.getResourcePersistentAttribute().getNonNullAnnotation(ColumnAnnotation.ANNOTATION_NAME); + } + + public void removeColumnAnnotation() { + this.getResourcePersistentAttribute().removeAnnotation(ColumnAnnotation.ANNOTATION_NAME); + } + + public String getDefaultColumnName() { + return this.getName(); + } + + public String getDefaultTableName() { + return this.getTypeMapping().getPrimaryTableName(); + } + + public boolean tableNameIsInvalid(String tableName) { + return this.getTypeMapping().tableNameIsInvalid(tableName); + } + + public Iterator<String> candidateTableNames() { + return this.getTypeMapping().allAssociatedTableNames(); + } + + public JptValidator buildColumnValidator(NamedColumn column, NamedColumnTextRangeResolver textRangeResolver) { + return new NamedColumnValidator((BaseColumn) column, (BaseColumnTextRangeResolver) textRangeResolver, new EntityTableDescriptionProvider()); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + result = this.column.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + result = this.converter.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + return null; + } + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.column.validate(messages, reporter, astRoot); + this.converter.validate(messages, reporter, astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVersionMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVersionMappingDefinition.java new file mode 100644 index 0000000000..5c62ad3ecc --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVersionMappingDefinition.java @@ -0,0 +1,59 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.ColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.TemporalAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.VersionAnnotation; + +public abstract class AbstractJavaVersionMappingDefinition + implements JavaAttributeMappingDefinition +{ + protected AbstractJavaVersionMappingDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.VERSION_ATTRIBUTE_MAPPING_KEY; + } + + public String getAnnotationName() { + return VersionAnnotation.ANNOTATION_NAME; + } + + public boolean isSpecified(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.getResourcePersistentAttribute().getAnnotation(this.getAnnotationName()) != null; + } + + public Iterable<String> getSupportingAnnotationNames() { + return SUPPORTING_ANNOTATION_NAMES; + } + + protected static final String[] SUPPORTING_ANNOTATION_NAMES_ARRAY = new String[] { + ColumnAnnotation.ANNOTATION_NAME, + TemporalAnnotation.ANNOTATION_NAME, + }; + protected static final Iterable<String> SUPPORTING_ANNOTATION_NAMES = new ArrayIterable<String>(SUPPORTING_ANNOTATION_NAMES_ARRAY); + + public JavaAttributeMapping buildMapping(JavaPersistentAttribute persistentAttribute, JpaFactory factory) { + return factory.buildJavaVersionMapping(persistentAttribute); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualBaseColumn.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualBaseColumn.java new file mode 100644 index 0000000000..a28099d901 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualBaseColumn.java @@ -0,0 +1,238 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.context.BaseColumn; +import org.eclipse.jpt.jpa.core.context.ReadOnlyNamedColumn; +import org.eclipse.jpt.jpa.core.context.VirtualBaseColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; + +public abstract class AbstractJavaVirtualBaseColumn<O extends ReadOnlyNamedColumn.Owner, C extends BaseColumn> + extends AbstractJavaVirtualNamedColumn<O, C> + implements VirtualBaseColumn +{ + protected String specifiedTable; + protected String defaultTable; + + protected Boolean specifiedUnique; + protected boolean defaultUnique; + + protected Boolean specifiedNullable; + protected boolean defaultNullable; + + protected Boolean specifiedInsertable; + protected boolean defaultInsertable; + + protected Boolean specifiedUpdatable; + protected boolean defaultUpdatable; + + + protected AbstractJavaVirtualBaseColumn(JavaJpaContextNode parent, O owner) { + super(parent, owner); + } + + + // ********** synchronize/update ********** + + @Override + public void update() { + super.update(); + + this.setSpecifiedTable(this.buildSpecifiedTable()); + this.setDefaultTable(this.buildDefaultTable()); + + this.setSpecifiedUnique(this.buildSpecifiedUnique()); + this.setDefaultUnique(this.buildDefaultUnique()); + + this.setSpecifiedNullable(this.buildSpecifiedNullable()); + this.setDefaultNullable(this.buildDefaultNullable()); + + this.setSpecifiedInsertable(this.buildSpecifiedInsertable()); + this.setDefaultInsertable(this.buildDefaultInsertable()); + + this.setSpecifiedUpdatable(this.buildSpecifiedUpdatable()); + this.setDefaultUpdatable(this.buildDefaultUpdatable()); + } + + + // ********** table ********** + + public String getTable() { + return (this.specifiedTable != null) ? this.specifiedTable : this.defaultTable; + } + + public String getSpecifiedTable() { + return this.specifiedTable; + } + + protected void setSpecifiedTable(String table) { + String old = this.specifiedTable; + this.specifiedTable = table; + this.firePropertyChanged(SPECIFIED_TABLE_PROPERTY, old, table); + } + + protected String buildSpecifiedTable() { + return this.getOverriddenColumn().getSpecifiedTable(); + } + + public String getDefaultTable() { + return this.defaultTable; + } + + protected void setDefaultTable(String table) { + String old = this.defaultTable; + this.defaultTable = table; + this.firePropertyChanged(DEFAULT_TABLE_PROPERTY, old, table); + } + + protected String buildDefaultTable() { + return this.owner.getDefaultTableName(); + } + + + // ********** unique ********** + + public boolean isUnique() { + return (this.specifiedUnique != null) ? this.specifiedUnique.booleanValue() : this.isDefaultUnique(); + } + + public Boolean getSpecifiedUnique() { + return this.specifiedUnique; + } + + protected void setSpecifiedUnique(Boolean unique) { + Boolean old = this.specifiedUnique; + this.specifiedUnique = unique; + this.firePropertyChanged(SPECIFIED_UNIQUE_PROPERTY, old, unique); + } + + protected Boolean buildSpecifiedUnique() { + return this.getOverriddenColumn().getSpecifiedUnique(); + } + + public boolean isDefaultUnique() { + return this.defaultUnique; + } + + protected void setDefaultUnique(boolean unique) { + boolean old = this.defaultUnique; + this.defaultUnique = unique; + this.firePropertyChanged(DEFAULT_UNIQUE_PROPERTY, old, unique); + } + + protected boolean buildDefaultUnique() { + return DEFAULT_UNIQUE; + } + + + // ********** nullable ********** + + public boolean isNullable() { + return (this.specifiedNullable != null) ? this.specifiedNullable.booleanValue() : this.isDefaultNullable(); + } + + public Boolean getSpecifiedNullable() { + return this.specifiedNullable; + } + + protected void setSpecifiedNullable(Boolean nullable) { + Boolean old = this.specifiedNullable; + this.specifiedNullable = nullable; + this.firePropertyChanged(SPECIFIED_NULLABLE_PROPERTY, old, nullable); + } + + protected Boolean buildSpecifiedNullable() { + return this.getOverriddenColumn().getSpecifiedNullable(); + } + + public boolean isDefaultNullable() { + return this.defaultNullable; + } + + protected void setDefaultNullable(boolean nullable) { + boolean old = this.defaultNullable; + this.defaultNullable = nullable; + this.firePropertyChanged(DEFAULT_NULLABLE_PROPERTY, old, nullable); + } + + protected boolean buildDefaultNullable() { + return DEFAULT_NULLABLE; + } + + + // ********** insertable ********** + + public boolean isInsertable() { + return (this.specifiedInsertable != null) ? this.specifiedInsertable.booleanValue() : this.isDefaultInsertable(); + } + + public Boolean getSpecifiedInsertable() { + return this.specifiedInsertable; + } + + protected void setSpecifiedInsertable(Boolean insertable) { + Boolean old = this.specifiedInsertable; + this.specifiedInsertable = insertable; + this.firePropertyChanged(SPECIFIED_INSERTABLE_PROPERTY, old, insertable); + } + + protected Boolean buildSpecifiedInsertable() { + return this.getOverriddenColumn().getSpecifiedInsertable(); + } + + public boolean isDefaultInsertable() { + return this.defaultInsertable; + } + + protected void setDefaultInsertable(boolean insertable) { + boolean old = this.defaultInsertable; + this.defaultInsertable = insertable; + this.firePropertyChanged(DEFAULT_INSERTABLE_PROPERTY, old, insertable); + } + + protected boolean buildDefaultInsertable() { + return DEFAULT_INSERTABLE; + } + + + // ********** updatable ********** + + public boolean isUpdatable() { + return (this.specifiedUpdatable != null) ? this.specifiedUpdatable.booleanValue() : this.isDefaultUpdatable(); + } + + public Boolean getSpecifiedUpdatable() { + return this.specifiedUpdatable; + } + + protected void setSpecifiedUpdatable(Boolean updatable) { + Boolean old = this.specifiedUpdatable; + this.specifiedUpdatable = updatable; + this.firePropertyChanged(SPECIFIED_UPDATABLE_PROPERTY, old, updatable); + } + + protected Boolean buildSpecifiedUpdatable() { + return this.getOverriddenColumn().getSpecifiedUpdatable(); + } + + public boolean isDefaultUpdatable() { + return this.defaultUpdatable; + } + + protected void setDefaultUpdatable(boolean updatable) { + boolean old = this.defaultUpdatable; + this.defaultUpdatable = updatable; + this.firePropertyChanged(DEFAULT_UPDATABLE_PROPERTY, old, updatable); + } + + protected boolean buildDefaultUpdatable() { + return DEFAULT_UPDATABLE; + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualNamedColumn.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualNamedColumn.java new file mode 100644 index 0000000000..517dbeab97 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualNamedColumn.java @@ -0,0 +1,141 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.NamedColumn; +import org.eclipse.jpt.jpa.core.context.ReadOnlyNamedColumn; +import org.eclipse.jpt.jpa.core.context.VirtualNamedColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; + +/** + * Java virtual<ul> + * <li>column + * <li>join column + * </ul> + * <strong>NB:</strong> all state is sync'ed/updated in {@link #update()} + * because <em>all</em> of its derived from the context model (i.e. none of it + * is derived from the resource model). + */ +public abstract class AbstractJavaVirtualNamedColumn<O extends ReadOnlyNamedColumn.Owner, C extends NamedColumn> + extends AbstractJavaJpaContextNode + implements VirtualNamedColumn +{ + protected final O owner; + + protected String specifiedName; + protected String defaultName; + + protected String columnDefinition; + + + protected AbstractJavaVirtualNamedColumn(JavaJpaContextNode parent, O owner) { + super(parent); + this.owner = owner; + } + + + // ********** synchronize/update ********** + + @Override + public void update() { + super.update(); + + this.setSpecifiedName(this.buildSpecifiedName()); + this.setDefaultName(this.buildDefaultName()); + + this.setColumnDefinition(this.buildColumnDefinition()); + } + + + // ********** column ********** + + /** + * This should never return <code>null</code>. + */ + public abstract C getOverriddenColumn(); + + + // ********** name ********** + + public String getName() { + return (this.specifiedName != null) ? this.specifiedName : this.defaultName; + } + + public String getSpecifiedName() { + return this.specifiedName; + } + + protected void setSpecifiedName(String name) { + String old = this.specifiedName; + this.specifiedName = name; + this.firePropertyChanged(SPECIFIED_NAME_PROPERTY, old, name); + } + + protected String buildSpecifiedName() { + return this.getOverriddenColumn().getSpecifiedName(); + } + + public String getDefaultName() { + return this.defaultName; + } + + protected void setDefaultName(String name) { + String old = this.defaultName; + this.defaultName = name; + this.firePropertyChanged(DEFAULT_NAME_PROPERTY, old, name); + } + + protected String buildDefaultName() { + return this.owner.getDefaultColumnName(); + } + + + // ********** column definition ********** + + public String getColumnDefinition() { + return this.columnDefinition; + } + + protected void setColumnDefinition(String columnDefinition) { + String old = this.columnDefinition; + this.columnDefinition = columnDefinition; + this.firePropertyChanged(COLUMN_DEFINITION_PROPERTY, old, columnDefinition); + } + + protected String buildColumnDefinition() { + return this.getOverriddenColumn().getColumnDefinition(); + } + + + // ********** validation ********** + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return null; // not sure this column is validated... + } + + + // ********** misc ********** + + public boolean isVirtual() { + return true; + } + + @Override + public void toString(StringBuilder sb) { + String table = this.getTable(); + if (table != null) { + sb.append(table); + sb.append('.'); + } + sb.append(this.getName()); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualOverride.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualOverride.java new file mode 100644 index 0000000000..6f589efad7 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualOverride.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.java.JavaOverride; +import org.eclipse.jpt.jpa.core.context.java.JavaOverrideContainer; +import org.eclipse.jpt.jpa.core.context.java.JavaVirtualOverride; + +/** + * Virtual Java override + */ +public abstract class AbstractJavaVirtualOverride<C extends JavaOverrideContainer> + extends AbstractJavaJpaContextNode + implements JavaVirtualOverride +{ + protected final String name; // never null + + + protected AbstractJavaVirtualOverride(C parent, String name) { + super(parent); + this.name = name; + } + + public String getName() { + return this.name; + } + + public boolean isVirtual() { + return true; + } + + public JavaOverride convertToSpecified() { + return this.getContainer().convertOverrideToSpecified(this); + } + + @Override + @SuppressWarnings("unchecked") + public C getParent() { + return (C) super.getParent(); + } + + public C getContainer() { + return this.getParent(); + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return this.getParent().getValidationTextRange(astRoot); + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.name); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualReferenceTable.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualReferenceTable.java new file mode 100644 index 0000000000..ec4d5b507f --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualReferenceTable.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.ListIterator; +import java.util.Vector; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.SingleElementListIterable; +import org.eclipse.jpt.jpa.core.context.JoinColumn; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinColumn; +import org.eclipse.jpt.jpa.core.context.ReferenceTable; +import org.eclipse.jpt.jpa.core.context.VirtualReferenceTable; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; +import org.eclipse.jpt.jpa.core.context.java.JavaVirtualJoinColumn; +import org.eclipse.jpt.jpa.core.internal.context.ContextContainerTools; + +public abstract class AbstractJavaVirtualReferenceTable<T extends ReferenceTable> + extends AbstractJavaVirtualTable<T> + implements VirtualReferenceTable +{ + protected final Vector<JavaVirtualJoinColumn> specifiedJoinColumns = new Vector<JavaVirtualJoinColumn>(); + protected final SpecifiedJoinColumnContainerAdapter specifiedJoinColumnContainerAdapter = new SpecifiedJoinColumnContainerAdapter(); + protected final ReadOnlyJoinColumn.Owner joinColumnOwner; + + protected JavaVirtualJoinColumn defaultJoinColumn; + + + protected AbstractJavaVirtualReferenceTable(JavaJpaContextNode parent) { + super(parent); + this.joinColumnOwner = this.buildJoinColumnOwner(); + } + + + // ********** synchronize/update ********** + + @Override + public void update() { + super.update(); + this.updateSpecifiedJoinColumns(); + this.updateDefaultJoinColumn(); + } + + + // ********** join columns ********** + + public ListIterator<JavaVirtualJoinColumn> joinColumns() { + return this.getJoinColumns().iterator(); + } + + protected ListIterable<JavaVirtualJoinColumn> getJoinColumns() { + return this.hasSpecifiedJoinColumns() ? this.getSpecifiedJoinColumns() : this.getDefaultJoinColumns(); + } + + public int joinColumnsSize() { + return this.hasSpecifiedJoinColumns() ? this.specifiedJoinColumnsSize() : this.getDefaultJoinColumnsSize(); + } + + + // ********** specified join columns ********** + + public ListIterator<JavaVirtualJoinColumn> specifiedJoinColumns() { + return this.getSpecifiedJoinColumns().iterator(); + } + + protected ListIterable<JavaVirtualJoinColumn> getSpecifiedJoinColumns() { + return new LiveCloneListIterable<JavaVirtualJoinColumn>(this.specifiedJoinColumns); + } + + public int specifiedJoinColumnsSize() { + return this.specifiedJoinColumns.size(); + } + + public boolean hasSpecifiedJoinColumns() { + return this.specifiedJoinColumns.size() != 0; + } + + public JavaVirtualJoinColumn getSpecifiedJoinColumn(int index) { + return this.specifiedJoinColumns.get(index); + } + + protected void updateSpecifiedJoinColumns() { + ContextContainerTools.update(this.specifiedJoinColumnContainerAdapter); + } + + protected Iterable<JoinColumn> getOverriddenJoinColumns() { + return CollectionTools.iterable(this.getOverriddenTable().specifiedJoinColumns()); + } + + protected void moveSpecifiedJoinColumn(int index, JavaVirtualJoinColumn joinColumn) { + this.moveItemInList(index, joinColumn, this.specifiedJoinColumns, SPECIFIED_JOIN_COLUMNS_LIST); + } + + protected JavaVirtualJoinColumn addSpecifiedJoinColumn(int index, JoinColumn joinColumn) { + JavaVirtualJoinColumn virtualJoinColumn = this.buildJoinColumn(joinColumn); + this.addItemToList(index, virtualJoinColumn, this.specifiedJoinColumns, SPECIFIED_JOIN_COLUMNS_LIST); + return virtualJoinColumn; + } + + protected void removeSpecifiedJoinColumn(JavaVirtualJoinColumn joinColumn) { + this.removeItemFromList(joinColumn, this.specifiedJoinColumns, SPECIFIED_JOIN_COLUMNS_LIST); + } + + /** + * specified join column container adapter + */ + protected class SpecifiedJoinColumnContainerAdapter + implements ContextContainerTools.Adapter<JavaVirtualJoinColumn, JoinColumn> + { + public Iterable<JavaVirtualJoinColumn> getContextElements() { + return AbstractJavaVirtualReferenceTable.this.getSpecifiedJoinColumns(); + } + public Iterable<JoinColumn> getResourceElements() { + return AbstractJavaVirtualReferenceTable.this.getOverriddenJoinColumns(); + } + public JoinColumn getResourceElement(JavaVirtualJoinColumn contextElement) { + return contextElement.getOverriddenColumn(); + } + public void moveContextElement(int index, JavaVirtualJoinColumn element) { + AbstractJavaVirtualReferenceTable.this.moveSpecifiedJoinColumn(index, element); + } + public void addContextElement(int index, JoinColumn element) { + AbstractJavaVirtualReferenceTable.this.addSpecifiedJoinColumn(index, element); + } + public void removeContextElement(JavaVirtualJoinColumn element) { + AbstractJavaVirtualReferenceTable.this.removeSpecifiedJoinColumn(element); + } + } + + + // ********** default join column ********** + + public JavaVirtualJoinColumn getDefaultJoinColumn() { + return this.defaultJoinColumn; + } + + protected void setDefaultJoinColumn(JavaVirtualJoinColumn joinColumn) { + JavaVirtualJoinColumn old = this.defaultJoinColumn; + this.defaultJoinColumn = joinColumn; + this.firePropertyChanged(DEFAULT_JOIN_COLUMN_PROPERTY, old, joinColumn); + } + + protected ListIterable<JavaVirtualJoinColumn> getDefaultJoinColumns() { + return (this.defaultJoinColumn != null) ? + new SingleElementListIterable<JavaVirtualJoinColumn>(this.defaultJoinColumn) : + EmptyListIterable.<JavaVirtualJoinColumn>instance(); + } + + protected int getDefaultJoinColumnsSize() { + return (this.defaultJoinColumn == null) ? 0 : 1; + } + + protected void updateDefaultJoinColumn() { + if (this.buildsDefaultJoinColumn()) { + if (this.defaultJoinColumn == null) { + this.setDefaultJoinColumn(this.buildJoinColumn(this.getOverriddenTable().getDefaultJoinColumn())); + } else { + this.defaultJoinColumn.update(); + } + } else { + this.setDefaultJoinColumn(null); + } + } + + protected boolean buildsDefaultJoinColumn() { + return ! this.hasSpecifiedJoinColumns(); + } + + + // ********** misc ********** + + protected JavaVirtualJoinColumn buildJoinColumn(JoinColumn joinColumn) { + return this.buildJoinColumn(this.joinColumnOwner, joinColumn); + } + + protected JavaVirtualJoinColumn buildJoinColumn(ReadOnlyJoinColumn.Owner owner, JoinColumn joinColumn) { + return this.getJpaFactory().buildJavaVirtualJoinColumn(this, owner, joinColumn); + } + + protected abstract ReadOnlyJoinColumn.Owner buildJoinColumnOwner(); + + @Override + protected String buildDefaultSchema() { + return this.getContextDefaultSchema(); + } + + @Override + protected String buildDefaultCatalog() { + return this.getContextDefaultCatalog(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualTable.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualTable.java new file mode 100644 index 0000000000..466112abe3 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/AbstractJavaVirtualTable.java @@ -0,0 +1,315 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.ListIterator; +import java.util.Vector; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.NameTools; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable; +import org.eclipse.jpt.jpa.core.context.Table; +import org.eclipse.jpt.jpa.core.context.UniqueConstraint; +import org.eclipse.jpt.jpa.core.context.VirtualTable; +import org.eclipse.jpt.jpa.core.context.java.JavaJpaContextNode; +import org.eclipse.jpt.jpa.core.context.java.JavaVirtualUniqueConstraint; +import org.eclipse.jpt.jpa.core.internal.context.ContextContainerTools; +import org.eclipse.jpt.jpa.db.Catalog; +import org.eclipse.jpt.jpa.db.Schema; +import org.eclipse.jpt.jpa.db.SchemaContainer; + +public abstract class AbstractJavaVirtualTable<T extends Table> + extends AbstractJavaJpaContextNode + implements VirtualTable +{ + protected String specifiedName; + protected String defaultName; + + protected String specifiedSchema; + protected String defaultSchema; + + protected String specifiedCatalog; + protected String defaultCatalog; + + protected final Vector<JavaVirtualUniqueConstraint> uniqueConstraints = new Vector<JavaVirtualUniqueConstraint>(); + protected final UniqueConstraintContainerAdapter uniqueConstraintContainerAdapter = new UniqueConstraintContainerAdapter(); + + + protected AbstractJavaVirtualTable(JavaJpaContextNode parent) { + super(parent); + } + + + // ********** synchronize/update ********** + + @Override + public void update() { + super.update(); + + this.setSpecifiedName(this.buildSpecifiedName()); + this.setDefaultName(this.buildDefaultName()); + + this.setSpecifiedSchema(this.buildSpecifiedSchema()); + this.setDefaultSchema(this.buildDefaultSchema()); + + this.setSpecifiedCatalog(this.buildSpecifiedCatalog()); + this.setDefaultCatalog(this.buildDefaultCatalog()); + + this.updateUniqueConstraints(); + } + + + // ********** table ********** + + /** + * This should never return <code>null</code>. + */ + public abstract T getOverriddenTable(); + + + // ********** name ********** + + public String getName() { + return (this.specifiedName != null) ? this.specifiedName : this.defaultName; + } + + public String getSpecifiedName() { + return this.specifiedName; + } + + protected void setSpecifiedName(String name) { + String old = this.specifiedName; + this.specifiedName = name; + this.firePropertyChanged(SPECIFIED_NAME_PROPERTY, old, name); + } + + protected String buildSpecifiedName() { + return this.getOverriddenTable().getSpecifiedName(); + } + + public String getDefaultName() { + return this.defaultName; + } + + protected void setDefaultName(String name) { + String old = this.defaultName; + this.defaultName = name; + this.firePropertyChanged(DEFAULT_NAME_PROPERTY, old, name); + } + + protected abstract String buildDefaultName(); + + + // ********** schema ********** + + public String getSchema() { + return (this.specifiedSchema != null) ? this.specifiedSchema : this.defaultSchema; + } + + public String getSpecifiedSchema() { + return this.specifiedSchema; + } + + protected void setSpecifiedSchema(String schema) { + String old = this.specifiedSchema; + this.specifiedSchema = schema; + this.firePropertyChanged(SPECIFIED_SCHEMA_PROPERTY, old, schema); + } + + protected String buildSpecifiedSchema() { + return this.getOverriddenTable().getSchema(); + } + + public String getDefaultSchema() { + return this.defaultSchema; + } + + protected void setDefaultSchema(String schema) { + String old = this.defaultSchema; + this.defaultSchema = schema; + this.firePropertyChanged(DEFAULT_SCHEMA_PROPERTY, old, schema); + } + + protected abstract String buildDefaultSchema(); + + + // ********** catalog ********** + + public String getCatalog() { + return (this.specifiedCatalog != null) ? this.specifiedCatalog : this.defaultCatalog; + } + + public String getSpecifiedCatalog() { + return this.specifiedCatalog; + } + + protected void setSpecifiedCatalog(String catalog) { + String old = this.specifiedCatalog; + this.specifiedCatalog = catalog; + this.firePropertyChanged(SPECIFIED_CATALOG_PROPERTY, old, catalog); + } + + protected String buildSpecifiedCatalog() { + return this.getOverriddenTable().getCatalog(); + } + + public String getDefaultCatalog() { + return this.defaultCatalog; + } + + protected void setDefaultCatalog(String catalog) { + String old = this.defaultCatalog; + this.defaultCatalog = catalog; + this.firePropertyChanged(DEFAULT_CATALOG_PROPERTY, old, catalog); + } + + protected abstract String buildDefaultCatalog(); + + + // ********** unique constraints ********** + + public ListIterator<JavaVirtualUniqueConstraint> uniqueConstraints() { + return this.getUniqueConstraints().iterator(); + } + + protected ListIterable<JavaVirtualUniqueConstraint> getUniqueConstraints() { + return new LiveCloneListIterable<JavaVirtualUniqueConstraint>(this.uniqueConstraints); + } + + public int uniqueConstraintsSize() { + return this.uniqueConstraints.size(); + } + + public JavaVirtualUniqueConstraint getUniqueConstraint(int index) { + return this.uniqueConstraints.get(index); + } + + protected void updateUniqueConstraints() { + ContextContainerTools.update(this.uniqueConstraintContainerAdapter); + } + + protected Iterable<UniqueConstraint> getOverriddenUniqueConstraints() { + return CollectionTools.iterable(this.getOverriddenTable().uniqueConstraints()); + } + + protected void moveUniqueConstraint(int index, JavaVirtualUniqueConstraint constraint) { + this.moveItemInList(index, constraint, this.uniqueConstraints, UNIQUE_CONSTRAINTS_LIST); + } + + protected JavaVirtualUniqueConstraint addUniqueConstraint(int index, UniqueConstraint uniqueConstraint) { + JavaVirtualUniqueConstraint virtualConstraint = this.buildUniqueConstraint(uniqueConstraint); + this.addItemToList(index, virtualConstraint, this.uniqueConstraints, UNIQUE_CONSTRAINTS_LIST); + return virtualConstraint; + } + + protected JavaVirtualUniqueConstraint buildUniqueConstraint(UniqueConstraint uniqueConstraint) { + return this.getJpaFactory().buildJavaVirtualUniqueConstraint(this, uniqueConstraint); + } + + protected void removeUniqueConstraint(JavaVirtualUniqueConstraint constraint) { + this.removeItemFromList(constraint, this.uniqueConstraints, UNIQUE_CONSTRAINTS_LIST); + } + + /** + * unique constraint container adapter + */ + protected class UniqueConstraintContainerAdapter + implements ContextContainerTools.Adapter<JavaVirtualUniqueConstraint, UniqueConstraint> + { + public Iterable<JavaVirtualUniqueConstraint> getContextElements() { + return AbstractJavaVirtualTable.this.getUniqueConstraints(); + } + public Iterable<UniqueConstraint> getResourceElements() { + return AbstractJavaVirtualTable.this.getOverriddenUniqueConstraints(); + } + public UniqueConstraint getResourceElement(JavaVirtualUniqueConstraint contextElement) { + return contextElement.getOverriddenUniqueConstraint(); + } + public void moveContextElement(int index, JavaVirtualUniqueConstraint element) { + AbstractJavaVirtualTable.this.moveUniqueConstraint(index, element); + } + public void addContextElement(int index, UniqueConstraint resourceElement) { + AbstractJavaVirtualTable.this.addUniqueConstraint(index, resourceElement); + } + public void removeContextElement(JavaVirtualUniqueConstraint element) { + AbstractJavaVirtualTable.this.removeUniqueConstraint(element); + } + } + + + // ********** database stuff ********** + + public org.eclipse.jpt.jpa.db.Table getDbTable() { + Schema dbSchema = this.getDbSchema(); + return (dbSchema == null) ? null : dbSchema.getTableForIdentifier(this.getName()); + } + + public Schema getDbSchema() { + SchemaContainer dbSchemaContainer = this.getDbSchemaContainer(); + return (dbSchemaContainer == null) ? null : dbSchemaContainer.getSchemaForIdentifier(this.getSchema()); + } + + /** + * If we don't have a catalog (i.e. we don't even have a <em>default</em> catalog), + * then the database probably does not support catalogs; and we need to + * get the schema directly from the database. + */ + public SchemaContainer getDbSchemaContainer() { + String catalog = this.getCatalog(); + return (catalog != null) ? this.resolveDbCatalog(catalog) : this.getDatabase(); + } + + /** + * If we don't have a catalog (i.e. we don't even have a <em>default</em> + * catalog), then the database probably does not support catalogs. + */ + public Catalog getDbCatalog() { + String catalog = this.getCatalog(); + return (catalog == null) ? null : this.resolveDbCatalog(catalog); + } + + protected boolean isResolved() { + return this.getDbTable() != null; + } + + protected boolean hasResolvedSchema() { + return this.getDbSchema() != null; + } + + /** + * If we don't have a catalog (i.e. we don't even have a <em>default</em> + * catalog), then the database probably does not support catalogs. + */ + protected boolean hasResolvedCatalog() { + String catalog = this.getCatalog(); + return (catalog == null) || (this.resolveDbCatalog(catalog) != null); + } + + + // ********** validation ********** + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return null; + } + + + // ********** misc ********** + + @Override + public void toString(StringBuilder sb) { + sb.append(this.buildQualifiedName()); + } + + protected String buildQualifiedName() { + return NameTools.buildQualifiedDatabaseObjectName(this.getCatalog(), this.getSchema(), this.getName()); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaIdClassReference.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaIdClassReference.java new file mode 100644 index 0000000000..b4a89125dc --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaIdClassReference.java @@ -0,0 +1,239 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.AccessType; +import org.eclipse.jpt.jpa.core.context.java.JavaIdClassReference; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType; +import org.eclipse.jpt.jpa.core.context.java.JavaTypeMapping; +import org.eclipse.jpt.jpa.core.resource.java.IdClassAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentType; + +/** + * Java ID class reference + */ +public class GenericJavaIdClassReference + extends AbstractJavaJpaContextNode + implements JavaIdClassReference +{ + protected String idClassName; + protected String fullyQualifiedIdClassName; + // the ref holds the type directly because the ref is the type's parent + protected JavaPersistentType idClass; + + + public GenericJavaIdClassReference(JavaTypeMapping parent) { + super(parent); + this.idClassName = this.buildIdClassName(); + // 'idClass' is resolved in the update + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setIdClassName_(this.buildIdClassName()); + if (this.idClass != null) { + this.idClass.synchronizeWithResourceModel(); + } + } + + @Override + public void update() { + super.update(); + this.setFullyQualifiedIdClassName(this.buildFullyQualifiedIdClassName()); + this.updateIdClass(); + } + + + // ********** id class name ********** + + public String getIdClassName() { + return this.getSpecifiedIdClassName(); + } + + public String getSpecifiedIdClassName() { + return this.idClassName; + } + + public void setSpecifiedIdClassName(String name) { + if (this.valuesAreDifferent(name, this.idClassName)) { + this.getIdClassAnnotationForUpdate().setValue(name); + this.removeIdClassAnnotationIfUnset(); + this.setIdClassName_(name); + } + } + + protected void setIdClassName_(String name) { + String old = this.idClassName; + this.idClassName = name; + this.firePropertyChanged(SPECIFIED_ID_CLASS_NAME_PROPERTY, old, name); + } + + protected String buildIdClassName() { + IdClassAnnotation annotation = this.getIdClassAnnotation(); + return (annotation == null) ? null : annotation.getValue(); + } + + public String getDefaultIdClassName() { + return null; + } + + public boolean isSpecified() { + return this.idClassName != null; + } + + + // ********** id class annotation ********** + + /** + * Return <code>null</code> if the annotation does not exists. + */ + protected IdClassAnnotation getIdClassAnnotation() { + return (IdClassAnnotation) this.getResourcePersistentType().getAnnotation(this.getIdClassAnnotationName()); + } + + /** + * Build the annotation if it does not exist. + */ + protected IdClassAnnotation getIdClassAnnotationForUpdate() { + IdClassAnnotation annotation = this.getIdClassAnnotation(); + return (annotation != null) ? annotation : this.buildIdClassAnnotation(); + } + + protected IdClassAnnotation buildIdClassAnnotation() { + return (IdClassAnnotation) this.getResourcePersistentType().addAnnotation(this.getIdClassAnnotationName()); + } + + protected void removeIdClassAnnotationIfUnset() { + if (this.getIdClassAnnotation().isUnset()) { + this.removeIdClassAnnotation(); + } + } + + protected void removeIdClassAnnotation() { + this.getResourcePersistentType().removeAnnotation(this.getIdClassAnnotationName()); + } + + protected String getIdClassAnnotationName() { + return IdClassAnnotation.ANNOTATION_NAME; + } + + + // ********** fully-qualified id class name ********** + + public String getFullyQualifiedIdClassName() { + return this.fullyQualifiedIdClassName; + } + + protected void setFullyQualifiedIdClassName(String name) { + String old = this.fullyQualifiedIdClassName; + this.fullyQualifiedIdClassName = name; + this.firePropertyChanged(FULLY_QUALIFIED_ID_CLASS_PROPERTY, old, name); + } + + protected String buildFullyQualifiedIdClassName() { + IdClassAnnotation annotation = this.getIdClassAnnotation(); + return (annotation == null) ? null : annotation.getFullyQualifiedClassName(); + } + + + // ********** id class ********** + + public JavaPersistentType getIdClass() { + return this.idClass; + } + + protected void setIdClass(JavaPersistentType idClass) { + JavaPersistentType old = this.idClass; + this.idClass = idClass; + this.firePropertyChanged(ID_CLASS_PROPERTY, old, idClass); + } + + protected void updateIdClass() { + JavaResourcePersistentType resourceIdClass = this.resolveResourceIdClass(); + if (resourceIdClass == null) { + if (this.idClass != null) { + this.idClass.dispose(); + this.setIdClass(null); + } + } else { + if (this.idClass == null) { + this.setIdClass(this.buildIdClass(resourceIdClass)); + } else { + if (this.idClass.getResourcePersistentType() == resourceIdClass) { + this.idClass.update(); + } else { + this.idClass.dispose(); + this.setIdClass(this.buildIdClass(resourceIdClass)); + } + } + } + } + + protected JavaResourcePersistentType resolveResourceIdClass() { + return (this.fullyQualifiedIdClassName == null) ? + null : this.getJpaProject().getJavaResourcePersistentType(this.fullyQualifiedIdClassName); + } + + protected JavaPersistentType buildIdClass(JavaResourcePersistentType resourceClass) { + return this.getJpaFactory().buildJavaPersistentType(this, resourceClass); + } + + public char getIdClassEnclosingTypeSeparator() { + return '.'; + } + + + // ********** misc ********** + + @Override + public JavaTypeMapping getParent() { + return (JavaTypeMapping) super.getParent(); + } + + protected JavaTypeMapping getTypeMapping() { + return this.getParent(); + } + + protected JavaPersistentType getPersistentType() { + return this.getTypeMapping().getPersistentType(); + } + + protected JavaResourcePersistentType getResourcePersistentType() { + return this.getPersistentType().getResourcePersistentType(); + } + + + // ********** PersistentType.Owner implementation ********** + + public AccessType getOverridePersistentTypeAccess() { + return this.getPersistentType().getAccess(); + } + + public AccessType getDefaultPersistentTypeAccess() { + // this shouldn't be needed, since we've specified an override access, but just to be safe ... + return this.getPersistentType().getAccess(); + } + + + // ********** validation ********** + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + IdClassAnnotation annotation = this.getIdClassAnnotation(); + return (annotation == null) ? + this.getTypeMapping().getValidationTextRange(astRoot) : + annotation.getTextRange(astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaManyToManyRelationship.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaManyToManyRelationship.java new file mode 100644 index 0000000000..acbd82eeb9 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaManyToManyRelationship.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.AttributeMapping; +import org.eclipse.jpt.jpa.core.context.MappedByRelationship; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinTableRelationship; +import org.eclipse.jpt.jpa.core.context.Relationship; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaManyToManyMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaManyToManyRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaMappedByRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaRelationshipStrategy; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.GenericJavaMappingJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.resource.java.OwnableRelationshipMappingAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +public class GenericJavaManyToManyRelationship + extends AbstractJavaMappingRelationship<JavaManyToManyMapping> + implements JavaManyToManyRelationship +{ + protected final JavaMappedByRelationshipStrategy mappedByStrategy; + + protected final JavaJoinTableRelationshipStrategy joinTableStrategy; + + + public GenericJavaManyToManyRelationship(JavaManyToManyMapping parent) { + super(parent); + this.mappedByStrategy = this.buildMappedByStrategy(); + this.joinTableStrategy = this.buildJoinTableStrategy(); + + this.strategy = this.buildStrategy(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.mappedByStrategy.synchronizeWithResourceModel(); + this.joinTableStrategy.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + this.mappedByStrategy.update(); + this.joinTableStrategy.update(); + } + + + // ********** strategy ********** + + @Override + protected JavaRelationshipStrategy buildStrategy() { + if (this.mappedByStrategy.getMappedByAttribute() != null) { + return this.mappedByStrategy; + } + return this.joinTableStrategy; + } + + + // ********** mapped by strategy ********** + + public JavaMappedByRelationshipStrategy getMappedByStrategy() { + return this.mappedByStrategy; + } + + public boolean strategyIsMappedBy() { + return this.strategy == this.mappedByStrategy; + } + + public void setStrategyToMappedBy() { + this.mappedByStrategy.addStrategy(); + this.joinTableStrategy.removeStrategy(); + this.updateStrategy(); + } + + public boolean mayBeMappedBy(AttributeMapping mapping) { + return mapping.getKey() == MappingKeys.MANY_TO_MANY_ATTRIBUTE_MAPPING_KEY; + } + + protected JavaMappedByRelationshipStrategy buildMappedByStrategy() { + return new GenericJavaMappedByRelationshipStrategy(this); + } + + + // ********** join table strategy ********** + + public JavaJoinTableRelationshipStrategy getJoinTableStrategy() { + return this.joinTableStrategy; + } + + public boolean strategyIsJoinTable() { + return this.strategy == this.joinTableStrategy; + } + + public void setStrategyToJoinTable() { + // join table is default option, so no need to add to resource + this.mappedByStrategy.removeStrategy(); + this.updateStrategy(); + } + + public boolean mayHaveDefaultJoinTable() { + return this.getMappedByStrategy().getMappedByAttribute() == null; + } + + protected JavaJoinTableRelationshipStrategy buildJoinTableStrategy() { + return new GenericJavaMappingJoinTableRelationshipStrategy(this); + } + + + // ********** conversions ********** + + public void initializeOn(Relationship newRelationship) { + newRelationship.initializeFromMappedByRelationship(this); + newRelationship.initializeFromJoinTableRelationship(this); + } + + @Override + public void initializeFromMappedByRelationship(MappedByRelationship oldRelationship) { + super.initializeFromMappedByRelationship(oldRelationship); + this.mappedByStrategy.initializeFrom(oldRelationship.getMappedByStrategy()); + } + + @Override + public void initializeFromJoinTableRelationship(ReadOnlyJoinTableRelationship oldRelationship) { + super.initializeFromJoinTableRelationship(oldRelationship); + this.joinTableStrategy.initializeFrom(oldRelationship.getJoinTableStrategy()); + } + + + // ********** misc ********** + + @Override + public JavaManyToManyMapping getMapping() { + return this.getParent(); + } + + public OwnableRelationshipMappingAnnotation getMappingAnnotation() { + return this.getMapping().getMappingAnnotation(); + } + + public OwnableRelationshipMappingAnnotation getMappingAnnotationForUpdate() { + return this.getMapping().getAnnotationForUpdate(); + } + + public boolean isOwner() { + return this.mappedByStrategy.getMappedByAttribute() == null; + } + + public boolean isOwnedBy(RelationshipMapping mapping) { + return this.mappedByStrategy.relationshipIsOwnedBy(mapping); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.mappedByStrategy.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + return this.joinTableStrategy.javaCompletionProposals(pos, filter, astRoot); + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.mappedByStrategy.validate(messages, reporter, astRoot); + this.joinTableStrategy.validate(messages, reporter, astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaManyToOneRelationship.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaManyToOneRelationship.java new file mode 100644 index 0000000000..c0ad6c945b --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaManyToOneRelationship.java @@ -0,0 +1,194 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinColumnRelationship; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinTableRelationship; +import org.eclipse.jpt.jpa.core.context.Relationship; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinColumnRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaManyToOneMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaRelationshipStrategy; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.GenericJavaMappingJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.NullJavaJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaManyToOneRelationship2_0; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +public class GenericJavaManyToOneRelationship + extends AbstractJavaMappingRelationship<JavaManyToOneMapping> + implements JavaManyToOneRelationship2_0 +{ + protected final JavaJoinColumnRelationshipStrategy joinColumnStrategy; + + // JPA 2.0 + protected final JavaJoinTableRelationshipStrategy joinTableStrategy; + + + public GenericJavaManyToOneRelationship(JavaManyToOneMapping parent) { + super(parent); + this.joinColumnStrategy = this.buildJoinColumnStrategy(); + this.joinTableStrategy = this.buildJoinTableStrategy(); + + this.strategy = this.buildStrategy(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.joinColumnStrategy.synchronizeWithResourceModel(); + this.joinTableStrategy.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + this.joinColumnStrategy.update(); + this.joinTableStrategy.update(); + } + + + // ********** strategy ********** + + @Override + protected JavaRelationshipStrategy buildStrategy() { + if (this.isJpa2_0Compatible()) { + if (this.joinTableStrategy.getJoinTable() != null) { + return this.joinTableStrategy; + } + } + return this.joinColumnStrategy; + } + + + // ********** join table strategy ********** + + public JavaJoinTableRelationshipStrategy getJoinTableStrategy() { + return this.joinTableStrategy; + } + + public boolean strategyIsJoinTable() { + return this.strategy == this.joinTableStrategy; + } + + public final void setStrategyToJoinTable() { + this.joinTableStrategy.addStrategy(); + this.joinColumnStrategy.removeStrategy(); + this.updateStrategy(); + } + + public boolean mayHaveDefaultJoinTable() { + return false; + } + + protected JavaJoinTableRelationshipStrategy buildJoinTableStrategy() { + return this.isJpa2_0Compatible() ? + new GenericJavaMappingJoinTableRelationshipStrategy(this) : + new NullJavaJoinTableRelationshipStrategy(this); + } + + + // ********** join column strategy ********** + + public JavaJoinColumnRelationshipStrategy getJoinColumnStrategy() { + return this.joinColumnStrategy; + } + + public boolean strategyIsJoinColumn() { + return this.strategy == this.joinColumnStrategy; + } + + public void setStrategyToJoinColumn() { + // join column strategy is the default; so no need to add stuff, + // just remove all the others + this.joinTableStrategy.removeStrategy(); + this.updateStrategy(); + } + + public boolean mayHaveDefaultJoinColumn() { + return this.joinTableStrategy.getJoinTable() == null; + } + + protected JavaJoinColumnRelationshipStrategy buildJoinColumnStrategy() { + return new GenericJavaMappingJoinColumnRelationshipStrategy(this); + } + + + // ********** conversions ********** + + public void initializeOn(Relationship newRelationship) { + newRelationship.initializeFromJoinColumnRelationship(this); + newRelationship.initializeFromJoinTableRelationship(this); + } + + @Override + public void initializeFromJoinTableRelationship(ReadOnlyJoinTableRelationship oldRelationship) { + super.initializeFromJoinTableRelationship(oldRelationship); + this.joinTableStrategy.initializeFrom(oldRelationship.getJoinTableStrategy()); + } + + @Override + public void initializeFromJoinColumnRelationship(ReadOnlyJoinColumnRelationship oldRelationship) { + super.initializeFromJoinColumnRelationship(oldRelationship); + this.joinColumnStrategy.initializeFrom(oldRelationship.getJoinColumnStrategy()); + } + + + // ********** misc ********** + + @Override + public JavaManyToOneMapping getMapping() { + return this.getParent(); + } + + public boolean isOwner() { + return true; + } + + public boolean isOwnedBy(RelationshipMapping mapping) { + return false; + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.joinColumnStrategy.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + return this.joinTableStrategy.javaCompletionProposals(pos, filter, astRoot); + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.joinColumnStrategy.validate(messages, reporter, astRoot); + this.joinTableStrategy.validate(messages, reporter, astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaMappedByRelationshipStrategy.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaMappedByRelationshipStrategy.java new file mode 100644 index 0000000000..f682c69d90 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaMappedByRelationshipStrategy.java @@ -0,0 +1,262 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.ArrayTools; +import org.eclipse.jpt.common.utility.internal.StringTools; +import org.eclipse.jpt.common.utility.internal.Tools; +import org.eclipse.jpt.common.utility.internal.iterators.FilteringIterator; +import org.eclipse.jpt.jpa.core.context.AttributeMapping; +import org.eclipse.jpt.jpa.core.context.Entity; +import org.eclipse.jpt.jpa.core.context.MappedByRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.PersistentAttribute; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaMappedByRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaMappedByRelationshipStrategy; +import org.eclipse.jpt.jpa.core.internal.validation.DefaultJpaValidationMessages; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationDescriptionMessages; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationMessages; +import org.eclipse.jpt.jpa.core.resource.java.OwnableRelationshipMappingAnnotation; +import org.eclipse.jpt.jpa.db.Table; +import org.eclipse.osgi.util.NLS; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +public class GenericJavaMappedByRelationshipStrategy + extends AbstractJavaJpaContextNode + implements JavaMappedByRelationshipStrategy +{ + protected String mappedByAttribute; + + + public GenericJavaMappedByRelationshipStrategy(JavaMappedByRelationship parent) { + super(parent); + this.mappedByAttribute = this.buildMappedByAttribute(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.setMappedByAttribute_(this.buildMappedByAttribute()); + } + + + // ********** mapped by attribute ********** + + public String getMappedByAttribute() { + return this.mappedByAttribute; + } + + public void setMappedByAttribute(String mappedByAttribute) { + if (this.valuesAreDifferent(mappedByAttribute, this.mappedByAttribute)) { + this.getMappingAnnotationForUpdate().setMappedBy(mappedByAttribute); + this.setMappedByAttribute_(mappedByAttribute); + } + } + + protected void setMappedByAttribute_(String mappedByAttribute) { + String old = this.mappedByAttribute; + this.mappedByAttribute = mappedByAttribute; + this.firePropertyChanged(MAPPED_BY_ATTRIBUTE_PROPERTY, old, mappedByAttribute); + } + + protected String buildMappedByAttribute() { + OwnableRelationshipMappingAnnotation annotation = this.getMappingAnnotation(); + return (annotation == null) ? null : annotation.getMappedBy(); + } + + + // ********** misc ********** + + protected OwnableRelationshipMappingAnnotation getMappingAnnotation() { + return this.getRelationship().getMappingAnnotation(); + } + + protected OwnableRelationshipMappingAnnotation getMappingAnnotationForUpdate() { + return this.getRelationship().getMappingAnnotationForUpdate(); + } + + @Override + public JavaMappedByRelationship getParent() { + return (JavaMappedByRelationship) super.getParent(); + } + + public JavaMappedByRelationship getRelationship() { + return this.getParent(); + } + + public void initializeFrom(MappedByRelationshipStrategy oldStrategy) { + this.setMappedByAttribute(oldStrategy.getMappedByAttribute()); + } + + public String getTableName() { + RelationshipMapping owner = this.getRelationshipOwner(); + return (owner == null) ? null : owner.getRelationship().getStrategy().getTableName(); + } + + public Table resolveDbTable(String tableName) { + RelationshipMapping owner = this.getRelationshipOwner(); + return (owner == null) ? null : owner.getRelationship().getStrategy().resolveDbTable(tableName); + } + + public boolean tableNameIsInvalid(String tableName) { + RelationshipMapping owner = this.getRelationshipOwner(); + return (owner != null) && owner.getRelationship().getStrategy().tableNameIsInvalid(tableName); + } + + public String getColumnTableNotValidDescription() { + //this will not be called if getRelationshipOwner() is null + return this.getRelationshipOwner().getRelationship().getStrategy().getColumnTableNotValidDescription(); + } + + protected RelationshipMapping getRelationshipOwner() { + return this.getRelationshipMapping().getRelationshipOwner(); + } + + public boolean isOverridable() { + return false; + } + + protected RelationshipMapping getRelationshipMapping() { + return this.getRelationship().getMapping(); + } + + public boolean relationshipIsOwnedBy(RelationshipMapping otherMapping) { + String thisEntityName = this.getEntityName(); + Entity otherEntity = otherMapping.getResolvedTargetEntity(); + String otherEntityName = (otherEntity == null) ? null : otherEntity.getName(); + return Tools.valuesAreEqual(thisEntityName, otherEntityName) && + Tools.valuesAreEqual(this.mappedByAttribute, otherMapping.getName()); + } + + protected String getEntityName() { + Entity entity = this.getRelationship().getEntity(); + return (entity == null) ? null : entity.getName(); + } + + public void addStrategy() { + if (this.mappedByAttribute == null) { + this.setMappedByAttribute(""); //$NON-NLS-1$ + } + } + + public void removeStrategy() { + if (this.mappedByAttribute != null) { + this.setMappedByAttribute(null); + } + } + + + // ********** java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + OwnableRelationshipMappingAnnotation annotation = this.getMappingAnnotation(); + if ((annotation != null) && annotation.mappedByTouches(pos, astRoot)) { + result = this.javaCandidateMappedByAttributeNames(filter); + } + return result; + } + + public Iterator<String> candidateMappedByAttributeNames() { + return this.getRelationshipMapping().allTargetEntityAttributeNames(); + } + + protected Iterator<String> candidateMappedByAttributeNames(Filter<String> filter) { + return new FilteringIterator<String>(this.candidateMappedByAttributeNames(), filter); + } + + protected Iterator<String> javaCandidateMappedByAttributeNames(Filter<String> filter) { + return StringTools.convertToJavaStringLiterals(this.candidateMappedByAttributeNames(filter)); + } + + + // ********** validation ********** + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + OwnableRelationshipMappingAnnotation annotation = this.getMappingAnnotation(); + return (annotation == null) ? null : annotation.getMappedByTextRange(astRoot); + } + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + + if (this.mappedByAttribute == null) { + return; + } + + Entity targetEntity = this.getRelationshipMapping().getResolvedTargetEntity(); + if (targetEntity == null) { + return; // null target entity is validated elsewhere + } + + AttributeMapping mappedByMapping = targetEntity.resolveAttributeMapping(this.mappedByAttribute); + + if (mappedByMapping == null) { + messages.add( + this.buildMessage( + JpaValidationMessages.MAPPING_UNRESOLVED_MAPPED_BY, + new String[] {this.mappedByAttribute}, + astRoot + ) + ); + return; + } + + if ( ! this.getRelationship().mayBeMappedBy(mappedByMapping)) { + messages.add( + this.buildMessage( + JpaValidationMessages.MAPPING_INVALID_MAPPED_BY, + new String[] {this.mappedByAttribute}, + astRoot + ) + ); + return; + } + + // if mappedByMapping is not a relationship owner, then it should have + // been flagged in above rule (mappedByIsValid) + if ( ! ((RelationshipMapping) mappedByMapping).isRelationshipOwner()) { + messages.add( + this.buildMessage( + JpaValidationMessages.MAPPING_MAPPED_BY_ON_BOTH_SIDES, + new String[] {this.mappedByAttribute}, + astRoot + ) + ); + } + } + + protected IMessage buildMessage(String msgID, String[] parms, CompilationUnit astRoot) { + PersistentAttribute attribute = this.getRelationshipMapping().getPersistentAttribute(); + String attributeDescription = NLS.bind(JpaValidationDescriptionMessages.ATTRIBUTE_DESC, attribute.getName()); + parms = ArrayTools.add(parms, 0, attributeDescription); + return DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + msgID, + parms, + this, + this.getValidationTextRange(astRoot) + ); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaMappingJoinColumnRelationshipStrategy.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaMappingJoinColumnRelationshipStrategy.java new file mode 100644 index 0000000000..79b88ac1c5 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaMappingJoinColumnRelationshipStrategy.java @@ -0,0 +1,216 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.internal.iterators.SubIteratorWrapper; +import org.eclipse.jpt.jpa.core.context.Entity; +import org.eclipse.jpt.jpa.core.context.JoinColumn; +import org.eclipse.jpt.jpa.core.context.NamedColumn; +import org.eclipse.jpt.jpa.core.context.PersistentAttribute; +import org.eclipse.jpt.jpa.core.context.ReadOnlyBaseJoinColumn; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaMappingJoinColumnRelationship; +import org.eclipse.jpt.jpa.core.internal.context.JoinColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.EntityTableDescriptionProvider; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.JoinColumnValidator; +import org.eclipse.jpt.jpa.core.internal.resource.java.NullJoinColumnAnnotation; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationDescriptionMessages; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.JoinColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JoinColumnsAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.NestableAnnotation; +import org.eclipse.jpt.jpa.db.Table; + +public class GenericJavaMappingJoinColumnRelationshipStrategy + extends AbstractJavaJoinColumnRelationshipStrategy +{ + protected final boolean targetForeignKey; + + + /** + * The default strategy is for a "source" foreign key. + */ + public GenericJavaMappingJoinColumnRelationshipStrategy(JavaMappingJoinColumnRelationship parent) { + this(parent, false); + } + + public GenericJavaMappingJoinColumnRelationshipStrategy(JavaMappingJoinColumnRelationship parent, boolean targetForeignKey) { + super(parent); + this.targetForeignKey = targetForeignKey; + } + + + // ********** join column annotations ********** + + @Override + protected Iterator<JoinColumnAnnotation> joinColumnAnnotations() { + return new SubIteratorWrapper<NestableAnnotation, JoinColumnAnnotation>(this.joinColumnAnnotations_()); + } + + protected Iterator<NestableAnnotation> joinColumnAnnotations_() { + return this.getResourcePersistentAttribute().annotations(JoinColumnAnnotation.ANNOTATION_NAME, JoinColumnsAnnotation.ANNOTATION_NAME); + } + + @Override + protected JoinColumnAnnotation addJoinColumnAnnotation(int index) { + return (JoinColumnAnnotation) this.getResourcePersistentAttribute().addAnnotation(index, JoinColumnAnnotation.ANNOTATION_NAME, JoinColumnsAnnotation.ANNOTATION_NAME); + } + + @Override + protected void removeJoinColumnAnnotation(int index) { + this.getResourcePersistentAttribute().removeAnnotation(index, JoinColumnAnnotation.ANNOTATION_NAME, JoinColumnsAnnotation.ANNOTATION_NAME); + } + + @Override + protected void moveJoinColumnAnnotation(int targetIndex, int sourceIndex) { + this.getResourcePersistentAttribute().moveAnnotation(targetIndex, sourceIndex, JoinColumnsAnnotation.ANNOTATION_NAME); + } + + @Override + protected JoinColumnAnnotation buildNullJoinColumnAnnotation() { + return new NullJoinColumnAnnotation(this.getResourcePersistentAttribute()); + } + + + // ********** misc ********** + + protected JavaResourcePersistentAttribute getResourcePersistentAttribute() { + return this.getRelationship().getMapping().getResourcePersistentAttribute(); + } + + @Override + public JavaMappingJoinColumnRelationship getRelationship() { + return (JavaMappingJoinColumnRelationship) super.getRelationship(); + } + + @Override + protected JavaJoinColumn.Owner buildJoinColumnOwner() { + return new JoinColumnOwner(); + } + + public boolean isOverridable() { + return true; + } + + public TypeMapping getRelationshipSource() { + RelationshipMapping mapping = this.getRelationshipMapping(); + return this.targetForeignKey ? + mapping.getResolvedTargetEntity() : + mapping.getTypeMapping(); + } + + public TypeMapping getRelationshipTarget() { + RelationshipMapping mapping = this.getRelationshipMapping(); + return this.targetForeignKey ? + mapping.getTypeMapping() : + mapping.getResolvedTargetEntity(); + } + + protected Entity getRelationshipTargetEntity() { + TypeMapping target = this.getRelationshipTarget(); + return (target instanceof Entity) ? (Entity) target : null; + } + + public boolean isTargetForeignKey() { + return this.targetForeignKey; + } + + + // ********** validation ********** + + public String getColumnTableNotValidDescription() { + return JpaValidationDescriptionMessages.NOT_VALID_FOR_THIS_ENTITY; + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return this.getRelationship().getValidationTextRange(astRoot); + } + + + // ********** join column owner ********** + + protected class JoinColumnOwner + implements JavaJoinColumn.Owner + { + protected JoinColumnOwner() { + super(); + } + + /** + * by default, the join column is in the type mapping's primary table + */ + public String getDefaultTableName() { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.getTableName(); + } + + public String getDefaultColumnName() { + //built in MappingTools.buildJoinColumnDefaultName() + return null; + } + + public String getAttributeName() { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.getRelationshipMapping().getName(); + } + + public PersistentAttribute getPersistentAttribute() { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.getRelationshipMapping().getPersistentAttribute(); + } + + public TypeMapping getTypeMapping() { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.getRelationshipSource(); + } + + public Entity getRelationshipTarget() { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.getRelationshipTargetEntity(); + } + + public boolean tableNameIsInvalid(String tableName) { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.tableNameIsInvalid(tableName); + } + + /** + * the join column can be on a secondary table + */ + public Iterator<String> candidateTableNames() { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.candidateTableNames(); + } + + public Table resolveDbTable(String tableName) { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.resolveDbTable(tableName); + } + + public Table getReferencedColumnDbTable() { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.getReferencedColumnDbTable(); + } + + public boolean joinColumnIsDefault(ReadOnlyBaseJoinColumn joinColumn) { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.defaultJoinColumn == joinColumn; + } + + public int joinColumnsSize() { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.joinColumnsSize(); + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return GenericJavaMappingJoinColumnRelationshipStrategy.this.getValidationTextRange(astRoot); + } + + public JptValidator buildColumnValidator(NamedColumn column, NamedColumnTextRangeResolver textRangeResolver) { + return new JoinColumnValidator((JoinColumn) column, this, (JoinColumnTextRangeResolver) textRangeResolver, new EntityTableDescriptionProvider()); + } + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaOneToManyRelationship.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaOneToManyRelationship.java new file mode 100644 index 0000000000..318babfe30 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaOneToManyRelationship.java @@ -0,0 +1,272 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.AttributeMapping; +import org.eclipse.jpt.jpa.core.context.MappedByRelationship; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinColumnRelationship; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinTableRelationship; +import org.eclipse.jpt.jpa.core.context.Relationship; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinColumnRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaMappedByRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaOneToManyMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaRelationshipStrategy; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.GenericJavaMappingJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.NullJavaJoinColumnRelationshipStrategy; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaOneToManyRelationship2_0; +import org.eclipse.jpt.jpa.core.resource.java.OneToManyAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +public class GenericJavaOneToManyRelationship + extends AbstractJavaMappingRelationship<JavaOneToManyMapping> + implements JavaOneToManyRelationship2_0 +{ + protected final JavaMappedByRelationshipStrategy mappedByStrategy; + + protected final JavaJoinTableRelationshipStrategy joinTableStrategy; + + // JPA 2.0 or EclipseLink + protected final boolean supportsJoinColumnStrategy; + protected final JavaJoinColumnRelationshipStrategy joinColumnStrategy; + + + public GenericJavaOneToManyRelationship(JavaOneToManyMapping parent, boolean supportsJoinColumnStrategy) { + super(parent); + this.mappedByStrategy = this.buildMappedByStrategy(); + this.supportsJoinColumnStrategy = supportsJoinColumnStrategy; + this.joinColumnStrategy = this.buildJoinColumnStrategy(); + + // build join table strategy last since it's dependent on the other strategies + this.joinTableStrategy = this.buildJoinTableStrategy(); + + this.strategy = this.buildStrategy(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.mappedByStrategy.synchronizeWithResourceModel(); + this.joinColumnStrategy.synchronizeWithResourceModel(); + this.joinTableStrategy.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + this.mappedByStrategy.update(); + this.joinColumnStrategy.update(); + this.joinTableStrategy.update(); + } + + + // ********** strategy ********** + + @Override + protected JavaRelationshipStrategy buildStrategy() { + if (this.mappedByStrategy.getMappedByAttribute() != null) { + return this.mappedByStrategy; + } + if (this.supportsJoinColumnStrategy) { + if (this.joinColumnStrategy.hasSpecifiedJoinColumns()) { + return this.joinColumnStrategy; + } + } + return this.joinTableStrategy; + } + + + // ********** mapped by strategy ********** + + public JavaMappedByRelationshipStrategy getMappedByStrategy() { + return this.mappedByStrategy; + } + + public boolean strategyIsMappedBy() { + return this.strategy == this.mappedByStrategy; + } + + public final void setStrategyToMappedBy() { + this.mappedByStrategy.addStrategy(); + this.joinTableStrategy.removeStrategy(); + this.joinColumnStrategy.removeStrategy(); + this.updateStrategy(); + } + + public boolean mayBeMappedBy(AttributeMapping mapping) { + String key = mapping.getKey(); + if (key == MappingKeys.MANY_TO_ONE_ATTRIBUTE_MAPPING_KEY) { + return true; + } + if (this.supportsJoinColumnStrategy) { + return key == MappingKeys.ONE_TO_ONE_ATTRIBUTE_MAPPING_KEY; + } + return false; + } + + protected JavaMappedByRelationshipStrategy buildMappedByStrategy() { + return new GenericJavaMappedByRelationshipStrategy(this); + } + + + // ********** join table strategy ********** + + public JavaJoinTableRelationshipStrategy getJoinTableStrategy() { + return this.joinTableStrategy; + } + + public boolean strategyIsJoinTable() { + return this.strategy == this.joinTableStrategy; + } + + public final void setStrategyToJoinTable() { + // join table is default, so no need to add annotation + this.mappedByStrategy.removeStrategy(); + this.joinColumnStrategy.removeStrategy(); + this.updateStrategy(); + } + + public boolean mayHaveDefaultJoinTable() { + return (this.mappedByStrategy.getMappedByAttribute() == null) && + ! this.joinColumnStrategy.hasSpecifiedJoinColumns(); + } + + protected JavaJoinTableRelationshipStrategy buildJoinTableStrategy() { + return new GenericJavaMappingJoinTableRelationshipStrategy(this); + } + + + // ********** join column strategy ********** + + public JavaJoinColumnRelationshipStrategy getJoinColumnStrategy() { + return this.joinColumnStrategy; + } + + public boolean strategyIsJoinColumn() { + return this.strategy == this.joinColumnStrategy; + } + + public void setStrategyToJoinColumn() { + this.joinColumnStrategy.addStrategy(); + this.mappedByStrategy.removeStrategy(); + this.joinTableStrategy.removeStrategy(); + this.updateStrategy(); + } + + public boolean mayHaveDefaultJoinColumn() { + return false; + } + + protected JavaJoinColumnRelationshipStrategy buildJoinColumnStrategy() { + return this.supportsJoinColumnStrategy ? + new GenericJavaMappingJoinColumnRelationshipStrategy(this, true) : // true = target foreign key + new NullJavaJoinColumnRelationshipStrategy(this); + } + + + // ********** conversions ********** + + public void initializeOn(Relationship newRelationship) { + newRelationship.initializeFromMappedByRelationship(this); + newRelationship.initializeFromJoinTableRelationship(this); + newRelationship.initializeFromJoinColumnRelationship(this); + } + + @Override + public void initializeFromMappedByRelationship(MappedByRelationship oldRelationship) { + super.initializeFromMappedByRelationship(oldRelationship); + this.mappedByStrategy.initializeFrom(oldRelationship.getMappedByStrategy()); + } + + @Override + public void initializeFromJoinTableRelationship(ReadOnlyJoinTableRelationship oldRelationship) { + super.initializeFromJoinTableRelationship(oldRelationship); + this.joinTableStrategy.initializeFrom(oldRelationship.getJoinTableStrategy()); + } + + @Override + public void initializeFromJoinColumnRelationship(ReadOnlyJoinColumnRelationship oldRelationship) { + super.initializeFromJoinColumnRelationship(oldRelationship); + this.joinColumnStrategy.initializeFrom(oldRelationship.getJoinColumnStrategy()); + } + + + // ********** misc ********** + + @Override + public JavaOneToManyMapping getMapping() { + return this.getParent(); + } + + public OneToManyAnnotation getMappingAnnotation() { + return this.getMapping().getMappingAnnotation(); + } + + public OneToManyAnnotation getMappingAnnotationForUpdate() { + return this.getMapping().getAnnotationForUpdate(); + } + + public boolean isOwner() { + return this.mappedByStrategy.getMappedByAttribute() == null; + } + + public boolean isOwnedBy(RelationshipMapping mapping) { + return this.mappedByStrategy.relationshipIsOwnedBy(mapping); + } + + @Override + public boolean isTargetForeignKey() { + return this.joinColumnStrategy.isTargetForeignKey(); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.mappedByStrategy.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.joinTableStrategy.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + return this.joinColumnStrategy.javaCompletionProposals(pos, filter, astRoot); + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.mappedByStrategy.validate(messages, reporter, astRoot); + this.joinTableStrategy.validate(messages, reporter, astRoot); + this.joinColumnStrategy.validate(messages, reporter, astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaOneToOneRelationship.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaOneToOneRelationship.java new file mode 100644 index 0000000000..8ea6e4ef66 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaOneToOneRelationship.java @@ -0,0 +1,300 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.AttributeMapping; +import org.eclipse.jpt.jpa.core.context.MappedByRelationship; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinColumnRelationship; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinTableRelationship; +import org.eclipse.jpt.jpa.core.context.Relationship; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinColumnRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaMappedByRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaOneToOneMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaPrimaryKeyJoinColumnRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaRelationshipStrategy; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.GenericJavaMappingJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.NullJavaJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaOneToOneRelationship2_0; +import org.eclipse.jpt.jpa.core.resource.java.OwnableRelationshipMappingAnnotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +public class GenericJavaOneToOneRelationship + extends AbstractJavaMappingRelationship<JavaOneToOneMapping> + implements JavaOneToOneRelationship2_0 +{ + protected final JavaMappedByRelationshipStrategy mappedByStrategy; + + protected final JavaPrimaryKeyJoinColumnRelationshipStrategy primaryKeyJoinColumnStrategy; + + // JPA 2.0 + protected final JavaJoinTableRelationshipStrategy joinTableStrategy; + + protected final JavaJoinColumnRelationshipStrategy joinColumnStrategy; + + + public GenericJavaOneToOneRelationship(JavaOneToOneMapping parent) { + super(parent); + this.mappedByStrategy = this.buildMappedByStrategy(); + this.primaryKeyJoinColumnStrategy = this.buildPrimaryKeyJoinColumnStrategy(); + this.joinTableStrategy = this.buildJoinTableStrategy(); + this.joinColumnStrategy = this.buildJoinColumnStrategy(); + + this.strategy = this.buildStrategy(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.mappedByStrategy.synchronizeWithResourceModel(); + this.primaryKeyJoinColumnStrategy.synchronizeWithResourceModel(); + this.joinTableStrategy.synchronizeWithResourceModel(); + this.joinColumnStrategy.synchronizeWithResourceModel(); + } + + @Override + public void update() { + super.update(); + this.mappedByStrategy.update(); + this.primaryKeyJoinColumnStrategy.update(); + this.joinTableStrategy.update(); + this.joinColumnStrategy.update(); + } + + + // ********** strategy ********** + + @Override + protected JavaRelationshipStrategy buildStrategy() { + if (this.mappedByStrategy.getMappedByAttribute() != null) { + return this.mappedByStrategy; + } + if (this.primaryKeyJoinColumnStrategy.hasPrimaryKeyJoinColumns()) { + return this.primaryKeyJoinColumnStrategy; + } + if (this.isJpa2_0Compatible()) { + if (this.joinTableStrategy.getJoinTable() != null) { + return this.joinTableStrategy; + } + } + return this.joinColumnStrategy; + } + + + // ********** mapped by strategy ********** + + public JavaMappedByRelationshipStrategy getMappedByStrategy() { + return this.mappedByStrategy; + } + + public boolean strategyIsMappedBy() { + return this.strategy == this.mappedByStrategy; + } + + public void setStrategyToMappedBy() { + this.mappedByStrategy.addStrategy(); + this.joinColumnStrategy.removeStrategy(); + this.primaryKeyJoinColumnStrategy.removeStrategy(); + this.joinTableStrategy.removeStrategy(); + this.updateStrategy(); + } + + public boolean mayBeMappedBy(AttributeMapping mapping) { + return mapping.getKey() == MappingKeys.ONE_TO_ONE_ATTRIBUTE_MAPPING_KEY; + } + + protected JavaMappedByRelationshipStrategy buildMappedByStrategy() { + return new GenericJavaMappedByRelationshipStrategy(this); + } + + + // ********** primary key join column strategy ********** + + public JavaPrimaryKeyJoinColumnRelationshipStrategy getPrimaryKeyJoinColumnStrategy() { + return this.primaryKeyJoinColumnStrategy; + } + + public boolean strategyIsPrimaryKeyJoinColumn() { + return this.strategy == this.primaryKeyJoinColumnStrategy; + } + + public void setStrategyToPrimaryKeyJoinColumn() { + this.primaryKeyJoinColumnStrategy.addStrategy(); + this.mappedByStrategy.removeStrategy(); + this.joinColumnStrategy.removeStrategy(); + this.joinTableStrategy.removeStrategy(); + this.updateStrategy(); + } + + protected JavaPrimaryKeyJoinColumnRelationshipStrategy buildPrimaryKeyJoinColumnStrategy() { + return new GenericJavaPrimaryKeyJoinColumnRelationshipStrategy(this); + } + + + // ********** join table strategy ********** + + public JavaJoinTableRelationshipStrategy getJoinTableStrategy() { + return this.joinTableStrategy; + } + + public boolean strategyIsJoinTable() { + return this.strategy == this.joinTableStrategy; + } + + public final void setStrategyToJoinTable() { + this.joinTableStrategy.addStrategy(); + this.mappedByStrategy.removeStrategy(); + this.joinColumnStrategy.removeStrategy(); + this.primaryKeyJoinColumnStrategy.removeStrategy(); + this.updateStrategy(); + } + + public boolean mayHaveDefaultJoinTable() { + return false; + } + + protected JavaJoinTableRelationshipStrategy buildJoinTableStrategy() { + return this.isJpa2_0Compatible() ? + new GenericJavaMappingJoinTableRelationshipStrategy(this) : + new NullJavaJoinTableRelationshipStrategy(this); + } + + + // ********** join column strategy ********** + + public JavaJoinColumnRelationshipStrategy getJoinColumnStrategy() { + return this.joinColumnStrategy; + } + + public boolean strategyIsJoinColumn() { + return this.strategy == this.joinColumnStrategy; + } + + public void setStrategyToJoinColumn() { + // join column strategy is the default; so no need to add stuff, + // just remove all the others + this.mappedByStrategy.removeStrategy(); + this.primaryKeyJoinColumnStrategy.removeStrategy(); + this.joinTableStrategy.removeStrategy(); + this.updateStrategy(); + } + + public boolean mayHaveDefaultJoinColumn() { + return (this.mappedByStrategy.getMappedByAttribute() == null) && + (this.primaryKeyJoinColumnStrategy.primaryKeyJoinColumnsSize() == 0) && + (this.joinTableStrategy.getJoinTable() == null); + } + + protected JavaJoinColumnRelationshipStrategy buildJoinColumnStrategy() { + return new GenericJavaMappingJoinColumnRelationshipStrategy(this); + } + + + // ********** conversions ********** + + public void initializeOn(Relationship newRelationship) { + newRelationship.initializeFromMappedByRelationship(this); + newRelationship.initializeFromJoinTableRelationship(this); + newRelationship.initializeFromJoinColumnRelationship(this); + // no other pk join column relationships yet + } + + @Override + public void initializeFromMappedByRelationship(MappedByRelationship oldRelationship) { + super.initializeFromMappedByRelationship(oldRelationship); + this.mappedByStrategy.initializeFrom(oldRelationship.getMappedByStrategy()); + } + + @Override + public void initializeFromJoinTableRelationship(ReadOnlyJoinTableRelationship oldRelationship) { + super.initializeFromJoinTableRelationship(oldRelationship); + this.joinTableStrategy.initializeFrom(oldRelationship.getJoinTableStrategy()); + } + + @Override + public void initializeFromJoinColumnRelationship(ReadOnlyJoinColumnRelationship oldRelationship) { + super.initializeFromJoinColumnRelationship(oldRelationship); + this.joinColumnStrategy.initializeFrom(oldRelationship.getJoinColumnStrategy()); + } + + + // ********** misc ********** + + @Override + public JavaOneToOneMapping getMapping() { + return this.getParent(); + } + + public OwnableRelationshipMappingAnnotation getMappingAnnotation() { + return this.getMapping().getMappingAnnotation(); + } + + public OwnableRelationshipMappingAnnotation getMappingAnnotationForUpdate() { + return this.getMapping().getAnnotationForUpdate(); + } + + public boolean isOwner() { + return this.mappedByStrategy.getMappedByAttribute() == null; + } + + public boolean isOwnedBy(RelationshipMapping mapping) { + return this.mappedByStrategy.relationshipIsOwnedBy(mapping); + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.mappedByStrategy.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.primaryKeyJoinColumnStrategy.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + result = this.joinTableStrategy.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + + return this.joinColumnStrategy.javaCompletionProposals(pos, filter, astRoot); + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + this.mappedByStrategy.validate(messages, reporter, astRoot); + this.primaryKeyJoinColumnStrategy.validate(messages, reporter, astRoot); + this.joinColumnStrategy.validate(messages, reporter, astRoot); + this.joinTableStrategy.validate(messages, reporter, astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaOverrideJoinColumnRelationshipStrategy.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaOverrideJoinColumnRelationshipStrategy.java new file mode 100644 index 0000000000..9190e16939 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaOverrideJoinColumnRelationshipStrategy.java @@ -0,0 +1,249 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.ListIterator; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.BaseColumn; +import org.eclipse.jpt.jpa.core.context.Entity; +import org.eclipse.jpt.jpa.core.context.NamedColumn; +import org.eclipse.jpt.jpa.core.context.PersistentAttribute; +import org.eclipse.jpt.jpa.core.context.ReadOnlyBaseJoinColumn; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAssociationOverride; +import org.eclipse.jpt.jpa.core.context.java.JavaAssociationOverrideContainer; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaOverrideRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinColumn.Owner; +import org.eclipse.jpt.jpa.core.internal.context.BaseColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.resource.java.NullJoinColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.AssociationOverrideAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JoinColumnAnnotation; +import org.eclipse.jpt.jpa.db.Table; + +public class GenericJavaOverrideJoinColumnRelationshipStrategy + extends AbstractJavaJoinColumnRelationshipStrategy +{ + public GenericJavaOverrideJoinColumnRelationshipStrategy(JavaOverrideRelationship parent) { + super(parent); + } + + + // ********** join column annotations ********** + + @Override + protected ListIterator<JoinColumnAnnotation> joinColumnAnnotations() { + return this.getOverrideAnnotation().joinColumns(); + } + + @Override + protected JoinColumnAnnotation addJoinColumnAnnotation(int index) { + return this.getOverrideAnnotation().addJoinColumn(index); + } + + @Override + protected void removeJoinColumnAnnotation(int index) { + this.getOverrideAnnotation().removeJoinColumn(index); + } + + @Override + protected void moveJoinColumnAnnotation(int targetIndex, int sourceIndex) { + this.getOverrideAnnotation().moveJoinColumn(targetIndex, sourceIndex); + } + + @Override + protected JoinColumnAnnotation buildNullJoinColumnAnnotation() { + return new NullJoinColumnAnnotation(this.getOverrideAnnotation()); + } + + protected AssociationOverrideAnnotation getOverrideAnnotation() { + return this.getAssociationOverride().getOverrideAnnotation(); + } + + + // ********** misc ********** + + @Override + protected Owner buildJoinColumnOwner() { + return new JoinColumnOwner(); + } + + public boolean isTargetForeignKey() { + RelationshipMapping relationshipMapping = this.getRelationshipMapping(); + return (relationshipMapping != null) && + relationshipMapping.getRelationship().isTargetForeignKey(); + } + + public TypeMapping getRelationshipSource() { + return this.isTargetForeignKey() ? + this.getRelationshipMapping().getResolvedTargetEntity() : + this.getAssociationOverrideContainer().getTypeMapping(); + } + + public TypeMapping getRelationshipTarget() { + return this.isTargetForeignKey() ? + this.getAssociationOverrideContainer().getTypeMapping() : + this.getRelationshipMappingTargetEntity(); + } + + protected TypeMapping getRelationshipMappingTargetEntity() { + RelationshipMapping mapping = this.getRelationshipMapping(); + return (mapping == null) ? null : mapping.getResolvedTargetEntity(); + } + + protected Entity getRelationshipTargetEntity() { + TypeMapping target = this.getRelationshipTarget(); + return (target instanceof Entity) ? (Entity) target : null; + } + + @Override + public RelationshipMapping getRelationshipMapping() { + return this.getAssociationOverride().getMapping(); + } + + protected String getAttributeName() { + return this.getAssociationOverride().getName(); + } + + @Override + public String getTableName() { + return this.isTargetForeignKey() ? + super.getTableName() : + this.getAssociationOverrideContainer().getDefaultTableName(); + } + + @Override + public Table resolveDbTable(String tableName) { + return this.isTargetForeignKey() ? + super.resolveDbTable(tableName) : + this.getAssociationOverrideContainer().resolveDbTable(tableName); + } + + @Override + public boolean tableNameIsInvalid(String tableName) { + return this.isTargetForeignKey() ? + super.tableNameIsInvalid(tableName) : + this.getAssociationOverrideContainer().tableNameIsInvalid(tableName); + } + + @Override + public Iterator<String> candidateTableNames() { + return this.isTargetForeignKey() ? + super.candidateTableNames() : + this.getAssociationOverrideContainer().candidateTableNames(); + } + + public String getColumnTableNotValidDescription() { + return null; + } + + public boolean isOverridable() { + return false; + } + + protected JavaAssociationOverride getAssociationOverride() { + return this.getRelationship().getAssociationOverride(); + } + + protected JavaAssociationOverrideContainer getAssociationOverrideContainer() { + return this.getAssociationOverride().getContainer(); + } + + @Override + public JavaOverrideRelationship getRelationship() { + return (JavaOverrideRelationship) super.getRelationship(); + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return this.getRelationship().getValidationTextRange(astRoot); + } + + + // ********** join column owner adapter ********** + + protected class JoinColumnOwner + implements JavaJoinColumn.Owner + { + protected JoinColumnOwner() { + super(); + } + + public String getDefaultTableName() { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.getTableName(); + } + + public String getDefaultColumnName() { + //built in MappingTools.buildJoinColumnDefaultName() + return null; + } + + public String getAttributeName() { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.getAttributeName(); + } + + public PersistentAttribute getPersistentAttribute() { + RelationshipMapping relationshipMapping = GenericJavaOverrideJoinColumnRelationshipStrategy.this.getRelationshipMapping(); + return relationshipMapping == null ? null : relationshipMapping.getPersistentAttribute(); + } + + public TypeMapping getTypeMapping() { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.getRelationshipSource(); + } + + public Entity getRelationshipTarget() { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.getRelationshipTargetEntity(); + } + + public boolean tableNameIsInvalid(String tableName) { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.tableNameIsInvalid(tableName); + } + + public Iterator<String> candidateTableNames() { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.candidateTableNames(); + } + + public Table resolveDbTable(String tableName) { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.resolveDbTable(tableName); + } + + public Table getReferencedColumnDbTable() { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.getReferencedColumnDbTable(); + } + + public boolean joinColumnIsDefault(ReadOnlyBaseJoinColumn joinColumn) { + return false; + } + + public int joinColumnsSize() { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.joinColumnsSize(); + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.getValidationTextRange(astRoot); + } + + public JptValidator buildColumnValidator(NamedColumn column, NamedColumnTextRangeResolver textRangeResolver) { + return this.getAssociationOverrideContainer().buildColumnValidator(this.getAssociationOverride(), (BaseColumn) column, this, (BaseColumnTextRangeResolver) textRangeResolver); + } + + protected JavaAssociationOverride getAssociationOverride() { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.getAssociationOverride(); + } + + protected JavaAssociationOverrideContainer getAssociationOverrideContainer() { + return GenericJavaOverrideJoinColumnRelationshipStrategy.this.getAssociationOverrideContainer(); + } + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.java new file mode 100644 index 0000000000..188364f29b --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.java @@ -0,0 +1,385 @@ +/******************************************************************************* + * Copyright (c) 2009, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Vector; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.common.utility.Filter; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable; +import org.eclipse.jpt.common.utility.internal.iterators.SubIteratorWrapper; +import org.eclipse.jpt.jpa.core.context.BaseJoinColumn; +import org.eclipse.jpt.jpa.core.context.Entity; +import org.eclipse.jpt.jpa.core.context.NamedColumn; +import org.eclipse.jpt.jpa.core.context.PersistentAttribute; +import org.eclipse.jpt.jpa.core.context.PrimaryKeyJoinColumn; +import org.eclipse.jpt.jpa.core.context.ReadOnlyBaseJoinColumn; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaPrimaryKeyJoinColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaPrimaryKeyJoinColumnRelationship; +import org.eclipse.jpt.jpa.core.context.java.JavaPrimaryKeyJoinColumnRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaRelationshipMapping; +import org.eclipse.jpt.jpa.core.internal.context.BaseJoinColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.context.ContextContainerTools; +import org.eclipse.jpt.jpa.core.internal.context.JptValidator; +import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; +import org.eclipse.jpt.jpa.core.internal.jpa1.context.OneToOnePrimaryKeyJoinColumnValidator; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationDescriptionMessages; +import org.eclipse.jpt.jpa.core.resource.java.JavaResourcePersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.NestableAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.PrimaryKeyJoinColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.PrimaryKeyJoinColumnsAnnotation; +import org.eclipse.jpt.jpa.db.Table; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +public class GenericJavaPrimaryKeyJoinColumnRelationshipStrategy + extends AbstractJavaJpaContextNode + implements JavaPrimaryKeyJoinColumnRelationshipStrategy +{ + protected final Vector<JavaPrimaryKeyJoinColumn> primaryKeyJoinColumns = new Vector<JavaPrimaryKeyJoinColumn>(); + protected final PrimaryKeyJoinColumnContainerAdapter primaryKeyJoinColumnContainerAdapter; + protected final JavaJoinColumn.Owner primaryKeyJoinColumnOwner; + + + public GenericJavaPrimaryKeyJoinColumnRelationshipStrategy(JavaPrimaryKeyJoinColumnRelationship parent) { + super(parent); + this.primaryKeyJoinColumnContainerAdapter = this.buildPrimaryKeyJoinColumnContainerAdapter(); + this.primaryKeyJoinColumnOwner = this.buildPrimaryKeyJoinColumnOwner(); + this.initializePrimaryKeyJoinColumns(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.syncPrimaryKeyJoinColumns(); + } + + @Override + public void update() { + super.update(); + this.updateNodes(this.getPrimaryKeyJoinColumns()); + } + + + // ********** primary key join columns ********** + + public ListIterator<JavaPrimaryKeyJoinColumn> primaryKeyJoinColumns() { + return this.getPrimaryKeyJoinColumns().iterator(); + } + + public ListIterable<JavaPrimaryKeyJoinColumn> getPrimaryKeyJoinColumns() { + return new LiveCloneListIterable<JavaPrimaryKeyJoinColumn>(this.primaryKeyJoinColumns); + } + + public int primaryKeyJoinColumnsSize() { + return this.primaryKeyJoinColumns.size(); + } + + public boolean hasPrimaryKeyJoinColumns() { + return this.primaryKeyJoinColumns.size() != 0; + } + + public JavaPrimaryKeyJoinColumn getPrimaryKeyJoinColumn(int index) { + return this.primaryKeyJoinColumns.get(index); + } + + public JavaPrimaryKeyJoinColumn addPrimaryKeyJoinColumn() { + return this.addPrimaryKeyJoinColumn(this.primaryKeyJoinColumns.size()); + } + + public JavaPrimaryKeyJoinColumn addPrimaryKeyJoinColumn(int index) { + PrimaryKeyJoinColumnAnnotation annotation = this.addPrimaryKeyJoinColumnAnnotation(index); + return this.addPrimaryKeyJoinColumn_(index, annotation); + } + + public void removePrimaryKeyJoinColumn(PrimaryKeyJoinColumn joinColumn) { + this.removePrimaryKeyJoinColumn(this.primaryKeyJoinColumns.indexOf(joinColumn)); + } + + public void removePrimaryKeyJoinColumn(int index) { + this.removePrimaryKeyJoinColumnAnnotation(index); + this.removePrimaryKeyJoinColumn_(index); + } + + protected void removePrimaryKeyJoinColumn_(int index) { + this.removeItemFromList(index, this.primaryKeyJoinColumns, PRIMARY_KEY_JOIN_COLUMNS_LIST); + } + + public void movePrimaryKeyJoinColumn(int targetIndex, int sourceIndex) { + this.movePrimaryKeyJoinColumnAnnotation(targetIndex, sourceIndex); + this.moveItemInList(targetIndex, sourceIndex, this.primaryKeyJoinColumns, PRIMARY_KEY_JOIN_COLUMNS_LIST); + } + + protected void initializePrimaryKeyJoinColumns() { + for (PrimaryKeyJoinColumnAnnotation annotation : this.getPrimaryKeyJoinColumnAnnotations()) { + this.primaryKeyJoinColumns.add(this.buildPrimaryKeyJoinColumn(annotation)); + } + } + + protected void syncPrimaryKeyJoinColumns() { + ContextContainerTools.synchronizeWithResourceModel(this.primaryKeyJoinColumnContainerAdapter); + } + + protected Iterable<PrimaryKeyJoinColumnAnnotation> getPrimaryKeyJoinColumnAnnotations() { + return CollectionTools.iterable(this.primaryKeyJoinColumnAnnotations()); + } + + protected void movePrimaryKeyJoinColumn_(int index, JavaPrimaryKeyJoinColumn joinColumn) { + this.moveItemInList(index, joinColumn, this.primaryKeyJoinColumns, PRIMARY_KEY_JOIN_COLUMNS_LIST); + } + + protected JavaPrimaryKeyJoinColumn addPrimaryKeyJoinColumn_(int index, PrimaryKeyJoinColumnAnnotation pkJoinColumnAnnotation) { + JavaPrimaryKeyJoinColumn joinColumn = this.buildPrimaryKeyJoinColumn(pkJoinColumnAnnotation); + this.addItemToList(index, joinColumn, this.primaryKeyJoinColumns, PRIMARY_KEY_JOIN_COLUMNS_LIST); + return joinColumn; + } + + protected void removePrimaryKeyJoinColumn_(JavaPrimaryKeyJoinColumn joinColumn) { + this.removePrimaryKeyJoinColumn_(this.primaryKeyJoinColumns.indexOf(joinColumn)); + } + + protected PrimaryKeyJoinColumnContainerAdapter buildPrimaryKeyJoinColumnContainerAdapter() { + return new PrimaryKeyJoinColumnContainerAdapter(); + } + + /** + * primary key join column container adapter + */ + protected class PrimaryKeyJoinColumnContainerAdapter + implements ContextContainerTools.Adapter<JavaPrimaryKeyJoinColumn, PrimaryKeyJoinColumnAnnotation> + { + public Iterable<JavaPrimaryKeyJoinColumn> getContextElements() { + return GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.this.getPrimaryKeyJoinColumns(); + } + public Iterable<PrimaryKeyJoinColumnAnnotation> getResourceElements() { + return GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.this.getPrimaryKeyJoinColumnAnnotations(); + } + public PrimaryKeyJoinColumnAnnotation getResourceElement(JavaPrimaryKeyJoinColumn contextElement) { + return contextElement.getColumnAnnotation(); + } + public void moveContextElement(int index, JavaPrimaryKeyJoinColumn element) { + GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.this.movePrimaryKeyJoinColumn_(index, element); + } + public void addContextElement(int index, PrimaryKeyJoinColumnAnnotation resourceElement) { + GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.this.addPrimaryKeyJoinColumn_(index, resourceElement); + } + public void removeContextElement(JavaPrimaryKeyJoinColumn element) { + GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.this.removePrimaryKeyJoinColumn_(element); + } + } + + protected JavaJoinColumn.Owner buildPrimaryKeyJoinColumnOwner() { + return new PrimaryKeyJoinColumnOwner(); + } + + protected JavaPrimaryKeyJoinColumn buildPrimaryKeyJoinColumn(PrimaryKeyJoinColumnAnnotation annotation) { + return this.getJpaFactory().buildJavaPrimaryKeyJoinColumn(this, this.primaryKeyJoinColumnOwner, annotation); + } + + + // ********** primary key join column annotations ********** + + protected Iterator<PrimaryKeyJoinColumnAnnotation> primaryKeyJoinColumnAnnotations() { + return new SubIteratorWrapper<NestableAnnotation, PrimaryKeyJoinColumnAnnotation>(this.primaryKeyJoinColumnAnnotations_()); + } + + protected Iterator<NestableAnnotation> primaryKeyJoinColumnAnnotations_() { + return this.getResourcePersistentAttribute().annotations(PrimaryKeyJoinColumnAnnotation.ANNOTATION_NAME, PrimaryKeyJoinColumnsAnnotation.ANNOTATION_NAME); + } + + protected PrimaryKeyJoinColumnAnnotation addPrimaryKeyJoinColumnAnnotation(int index) { + return (PrimaryKeyJoinColumnAnnotation) this.getResourcePersistentAttribute().addAnnotation(index, PrimaryKeyJoinColumnAnnotation.ANNOTATION_NAME, PrimaryKeyJoinColumnsAnnotation.ANNOTATION_NAME); + } + + protected void removePrimaryKeyJoinColumnAnnotation(int index) { + this.getResourcePersistentAttribute().removeAnnotation(index, PrimaryKeyJoinColumnAnnotation.ANNOTATION_NAME, PrimaryKeyJoinColumnsAnnotation.ANNOTATION_NAME); + } + + protected void movePrimaryKeyJoinColumnAnnotation(int targetIndex, int sourceIndex) { + this.getResourcePersistentAttribute().moveAnnotation(targetIndex, sourceIndex, PrimaryKeyJoinColumnsAnnotation.ANNOTATION_NAME); + } + + + // ********** misc ********** + + @Override + public JavaPrimaryKeyJoinColumnRelationship getParent() { + return (JavaPrimaryKeyJoinColumnRelationship) super.getParent(); + } + + public JavaPrimaryKeyJoinColumnRelationship getRelationship() { + return this.getParent(); + } + + protected JavaRelationshipMapping getRelationshipMapping() { + return this.getRelationship().getMapping(); + } + + protected JavaResourcePersistentAttribute getResourcePersistentAttribute() { + return this.getRelationship().getMapping().getResourcePersistentAttribute(); + } + + public String getTableName() { + return this.getTypeMapping().getPrimaryTableName(); + } + + public Table resolveDbTable(String tableName) { + return this.getTypeMapping().resolveDbTable(tableName); + } + + public boolean tableNameIsInvalid(String tableName) { + return this.getTypeMapping().tableNameIsInvalid(tableName); + } + + public boolean isOverridable() { + return false; + } + + public String getColumnTableNotValidDescription() { + return JpaValidationDescriptionMessages.NOT_VALID_FOR_THIS_ENTITY; + } + + protected TypeMapping getTypeMapping() { + return this.getRelationshipMapping().getTypeMapping(); + } + + public void addStrategy() { + if (this.primaryKeyJoinColumns.size() == 0) { + this.addPrimaryKeyJoinColumn(); + } + } + + public void removeStrategy() { + for (int i = this.primaryKeyJoinColumns.size(); i-- > 0; ) { + this.removePrimaryKeyJoinColumn(i); + } + } + + + // ********** Java completion proposals ********** + + @Override + public Iterator<String> javaCompletionProposals(int pos, Filter<String> filter, CompilationUnit astRoot) { + Iterator<String> result = super.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + for (JavaPrimaryKeyJoinColumn column : this.getPrimaryKeyJoinColumns()) { + result = column.javaCompletionProposals(pos, filter, astRoot); + if (result != null) { + return result; + } + } + return null; + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + for (JavaPrimaryKeyJoinColumn pkJoinColumn : this.getPrimaryKeyJoinColumns()) { + pkJoinColumn.validate(messages, reporter, astRoot); + } + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return this.getRelationship().getValidationTextRange(astRoot); + } + + + // ********** join column owner ********** + + protected class PrimaryKeyJoinColumnOwner + implements JavaJoinColumn.Owner + { + protected PrimaryKeyJoinColumnOwner() { + super(); + } + + /** + * by default, the join column is in the type mapping's primary table + */ + public String getDefaultTableName() { + return GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.this.getTableName(); + } + + public Entity getRelationshipTarget() { + return this.getRelationshipMapping().getResolvedTargetEntity(); + } + + public String getAttributeName() { + return this.getRelationshipMapping().getName(); + } + + public PersistentAttribute getPersistentAttribute() { + return this.getRelationshipMapping().getPersistentAttribute(); + } + + public boolean tableNameIsInvalid(String tableName) { + return this.getTypeMapping().tableNameIsInvalid(tableName); + } + + /** + * the join column can be on a secondary table + */ + public Iterator<String> candidateTableNames() { + return this.getTypeMapping().allAssociatedTableNames(); + } + + public TypeMapping getTypeMapping() { + return GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.this.getTypeMapping(); + } + + public Table resolveDbTable(String tableName) { + return this.getTypeMapping().resolveDbTable(tableName); + } + + public Table getReferencedColumnDbTable() { + Entity targetEntity = this.getRelationshipTarget(); + return (targetEntity == null) ? null : targetEntity.getPrimaryDbTable(); + } + + public boolean joinColumnIsDefault(ReadOnlyBaseJoinColumn joinColumn) { + return false; + } + + public String getDefaultColumnName() { + return null; + } + + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.this.getValidationTextRange(astRoot); + } + + public int joinColumnsSize() { + return GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.this.primaryKeyJoinColumnsSize(); + } + + public JptValidator buildColumnValidator(NamedColumn column, NamedColumnTextRangeResolver textRangeResolver) { + return new OneToOnePrimaryKeyJoinColumnValidator((BaseJoinColumn) column, this, (BaseJoinColumnTextRangeResolver) textRangeResolver); + } + + protected JavaRelationshipMapping getRelationshipMapping() { + return GenericJavaPrimaryKeyJoinColumnRelationshipStrategy.this.getRelationshipMapping(); + } + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaVirtualJoinTable.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaVirtualJoinTable.java new file mode 100644 index 0000000000..f27ca4df39 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/GenericJavaVirtualJoinTable.java @@ -0,0 +1,333 @@ +/******************************************************************************* + * Copyright (c) 2010, 2011 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.ListIterator; +import java.util.Vector; +import org.eclipse.jpt.common.utility.internal.CollectionTools; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.ListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.SingleElementListIterable; +import org.eclipse.jpt.jpa.core.context.Entity; +import org.eclipse.jpt.jpa.core.context.JoinColumn; +import org.eclipse.jpt.jpa.core.context.JoinTable; +import org.eclipse.jpt.jpa.core.context.PersistentAttribute; +import org.eclipse.jpt.jpa.core.context.ReadOnlyBaseJoinColumn; +import org.eclipse.jpt.jpa.core.context.ReadOnlyJoinColumn; +import org.eclipse.jpt.jpa.core.context.RelationshipMapping; +import org.eclipse.jpt.jpa.core.context.TypeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaVirtualJoinColumn; +import org.eclipse.jpt.jpa.core.context.java.JavaVirtualJoinTable; +import org.eclipse.jpt.jpa.core.context.java.JavaVirtualJoinTableRelationshipStrategy; +import org.eclipse.jpt.jpa.core.context.java.JavaVirtualRelationship; +import org.eclipse.jpt.jpa.core.internal.context.ContextContainerTools; +import org.eclipse.jpt.jpa.core.internal.context.MappingTools; + +/** + * Java virtual join table + */ +public class GenericJavaVirtualJoinTable + extends AbstractJavaVirtualReferenceTable<JoinTable> + implements JavaVirtualJoinTable +{ + protected final JoinTable overriddenTable; + + protected final Vector<JavaVirtualJoinColumn> specifiedInverseJoinColumns = new Vector<JavaVirtualJoinColumn>(); + protected final SpecifiedInverseJoinColumnContainerAdapter specifiedInverseJoinColumnContainerAdapter = new SpecifiedInverseJoinColumnContainerAdapter(); + protected final ReadOnlyJoinColumn.Owner inverseJoinColumnOwner; + + protected JavaVirtualJoinColumn defaultInverseJoinColumn; + + + public GenericJavaVirtualJoinTable(JavaVirtualJoinTableRelationshipStrategy parent, JoinTable overriddenTable) { + super(parent); + this.overriddenTable = overriddenTable; + this.inverseJoinColumnOwner = this.buildInverseJoinColumnOwner(); + } + + + // ********** synchronize/update ********** + + @Override + public void update() { + super.update(); + this.updateSpecifiedInverseJoinColumns(); + this.updateDefaultInverseJoinColumn(); + } + + + // ********** table ********** + + @Override + public JoinTable getOverriddenTable() { + return this.overriddenTable; + } + + + // ********** inverse join columns ********** + + public ListIterator<JavaVirtualJoinColumn> inverseJoinColumns() { + return this.getInverseJoinColumns().iterator(); + } + + protected ListIterable<JavaVirtualJoinColumn> getInverseJoinColumns() { + return this.hasSpecifiedInverseJoinColumns() ? this.getSpecifiedInverseJoinColumns() : this.getDefaultInverseJoinColumns(); + } + + public int inverseJoinColumnsSize() { + return this.hasSpecifiedInverseJoinColumns() ? this.specifiedInverseJoinColumnsSize() : this.getDefaultInverseJoinColumnsSize(); + } + + + // ********** inverse specified join columns ********** + + public ListIterator<JavaVirtualJoinColumn> specifiedInverseJoinColumns() { + return this.getSpecifiedInverseJoinColumns().iterator(); + } + + protected ListIterable<JavaVirtualJoinColumn> getSpecifiedInverseJoinColumns() { + return new LiveCloneListIterable<JavaVirtualJoinColumn>(this.specifiedInverseJoinColumns); + } + + public int specifiedInverseJoinColumnsSize() { + return this.specifiedInverseJoinColumns.size(); + } + + public boolean hasSpecifiedInverseJoinColumns() { + return this.specifiedInverseJoinColumns.size() != 0; + } + + public JavaVirtualJoinColumn getSpecifiedInverseJoinColumn(int index) { + return this.specifiedInverseJoinColumns.get(index); + } + + protected void updateSpecifiedInverseJoinColumns() { + ContextContainerTools.update(this.specifiedInverseJoinColumnContainerAdapter); + } + + protected Iterable<JoinColumn> getOverriddenInverseJoinColumns() { + return CollectionTools.iterable(this.getOverriddenTable().specifiedInverseJoinColumns()); + } + + protected void moveSpecifiedInverseJoinColumn(int index, JavaVirtualJoinColumn joinColumn) { + this.moveItemInList(index, joinColumn, this.specifiedInverseJoinColumns, SPECIFIED_INVERSE_JOIN_COLUMNS_LIST); + } + + protected JavaVirtualJoinColumn addSpecifiedInverseJoinColumn(int index, JoinColumn joinColumn) { + JavaVirtualJoinColumn virtualJoinColumn = this.buildInverseJoinColumn(joinColumn); + this.addItemToList(index, virtualJoinColumn, this.specifiedInverseJoinColumns, SPECIFIED_INVERSE_JOIN_COLUMNS_LIST); + return virtualJoinColumn; + } + + protected void removeSpecifiedInverseJoinColumn(JavaVirtualJoinColumn joinColumn) { + this.removeItemFromList(joinColumn, this.specifiedInverseJoinColumns, SPECIFIED_INVERSE_JOIN_COLUMNS_LIST); + } + + /** + * specified inverse join column container adapter + */ + protected class SpecifiedInverseJoinColumnContainerAdapter + implements ContextContainerTools.Adapter<JavaVirtualJoinColumn, JoinColumn> + { + public Iterable<JavaVirtualJoinColumn> getContextElements() { + return GenericJavaVirtualJoinTable.this.getSpecifiedInverseJoinColumns(); + } + public Iterable<JoinColumn> getResourceElements() { + return GenericJavaVirtualJoinTable.this.getOverriddenInverseJoinColumns(); + } + public JoinColumn getResourceElement(JavaVirtualJoinColumn contextElement) { + return contextElement.getOverriddenColumn(); + } + public void moveContextElement(int index, JavaVirtualJoinColumn element) { + GenericJavaVirtualJoinTable.this.moveSpecifiedInverseJoinColumn(index, element); + } + public void addContextElement(int index, JoinColumn element) { + GenericJavaVirtualJoinTable.this.addSpecifiedInverseJoinColumn(index, element); + } + public void removeContextElement(JavaVirtualJoinColumn element) { + GenericJavaVirtualJoinTable.this.removeSpecifiedInverseJoinColumn(element); + } + } + + + // ********** default inverse join column ********** + + public JavaVirtualJoinColumn getDefaultInverseJoinColumn() { + return this.defaultInverseJoinColumn; + } + + protected void setDefaultInverseJoinColumn(JavaVirtualJoinColumn joinColumn) { + JavaVirtualJoinColumn old = this.defaultInverseJoinColumn; + this.defaultInverseJoinColumn = joinColumn; + this.firePropertyChanged(DEFAULT_INVERSE_JOIN_COLUMN, old, joinColumn); + } + + protected ListIterable<JavaVirtualJoinColumn> getDefaultInverseJoinColumns() { + return (this.defaultInverseJoinColumn != null) ? + new SingleElementListIterable<JavaVirtualJoinColumn>(this.defaultInverseJoinColumn) : + EmptyListIterable.<JavaVirtualJoinColumn>instance(); + } + + protected int getDefaultInverseJoinColumnsSize() { + return (this.defaultInverseJoinColumn == null) ? 0 : 1; + } + + protected void updateDefaultInverseJoinColumn() { + if (this.buildsDefaultInverseJoinColumn()) { + if (this.defaultInverseJoinColumn == null) { + this.setDefaultInverseJoinColumn(this.buildInverseJoinColumn(this.getOverriddenTable().getDefaultInverseJoinColumn())); + } else { + this.defaultInverseJoinColumn.update(); + } + } else { + this.setDefaultInverseJoinColumn(null); + } + } + + protected boolean buildsDefaultInverseJoinColumn() { + return ! this.hasSpecifiedInverseJoinColumns(); + } + + + // ********** misc ********** + + @Override + public JavaVirtualJoinTableRelationshipStrategy getParent() { + return (JavaVirtualJoinTableRelationshipStrategy) super.getParent(); + } + + protected JavaVirtualJoinTableRelationshipStrategy getJoinStrategy() { + return this.getParent(); + } + + @Override + protected ReadOnlyJoinColumn.Owner buildJoinColumnOwner() { + return new JoinColumnOwner(); + } + + protected ReadOnlyJoinColumn.Owner buildInverseJoinColumnOwner() { + return new InverseJoinColumnOwner(); + } + + protected JavaVirtualJoinColumn buildInverseJoinColumn(JoinColumn joinColumn) { + return this.buildJoinColumn(this.inverseJoinColumnOwner, joinColumn); + } + + @Override + protected String buildDefaultName() { + return this.getJoinStrategy().getJoinTableDefaultName(); + } + + public RelationshipMapping getRelationshipMapping() { + return this.getJoinStrategy().getRelationship().getMapping(); + } + + public PersistentAttribute getPersistentAttribute() { + return this.getRelationshipMapping().getPersistentAttribute(); + } + + + // ********** join column owners ********** + + /** + * just a little common behavior + */ + protected abstract class AbstractJoinColumnOwner + implements ReadOnlyJoinColumn.Owner + { + protected AbstractJoinColumnOwner() { + super(); + } + + public TypeMapping getTypeMapping() { + return this.getRelationship().getTypeMapping(); + } + + /** + * by default, the join column is, obviously, in the join table; + * not sure whether it can be anywhere else... + */ + public String getDefaultTableName() { + return GenericJavaVirtualJoinTable.this.getName(); + } + + /** + * @see MappingTools#buildJoinColumnDefaultName(org.eclipse.jpt.jpa.core.context.ReadOnlyJoinColumn, org.eclipse.jpt.jpa.core.context.ReadOnlyJoinColumn.Owner) + */ + public String getDefaultColumnName() { + throw new UnsupportedOperationException(); + } + + protected JavaVirtualRelationship getRelationship() { + return GenericJavaVirtualJoinTable.this.getJoinStrategy().getRelationship(); + } + } + + + /** + * owner for "back-pointer" join columns; + * these point at the source/owning entity + */ + protected class JoinColumnOwner + extends AbstractJoinColumnOwner + { + protected JoinColumnOwner() { + super(); + } + + public Entity getRelationshipTarget() { + return this.getRelationship().getEntity(); + } + + public String getAttributeName() { + return MappingTools.getTargetAttributeName(GenericJavaVirtualJoinTable.this.getRelationshipMapping()); + } + + public boolean joinColumnIsDefault(ReadOnlyBaseJoinColumn joinColumn) { + return GenericJavaVirtualJoinTable.this.defaultJoinColumn == joinColumn; + } + + public int joinColumnsSize() { + return GenericJavaVirtualJoinTable.this.joinColumnsSize(); + } + } + + + /** + * owner for "forward-pointer" join columns; + * these point at the target/inverse entity + */ + protected class InverseJoinColumnOwner + extends AbstractJoinColumnOwner + { + protected InverseJoinColumnOwner() { + super(); + } + + public Entity getRelationshipTarget() { + RelationshipMapping relationshipMapping = GenericJavaVirtualJoinTable.this.getRelationshipMapping(); + return (relationshipMapping == null) ? null : relationshipMapping.getResolvedTargetEntity(); + } + + public String getAttributeName() { + RelationshipMapping relationshipMapping = GenericJavaVirtualJoinTable.this.getRelationshipMapping(); + return (relationshipMapping == null) ? null : relationshipMapping.getName(); + } + + public boolean joinColumnIsDefault(ReadOnlyBaseJoinColumn joinColumn) { + return GenericJavaVirtualJoinTable.this.defaultInverseJoinColumn == joinColumn; + } + + public int joinColumnsSize() { + return GenericJavaVirtualJoinTable.this.inverseJoinColumnsSize(); + } + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaBaseColumnTextRangeResolver.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaBaseColumnTextRangeResolver.java new file mode 100644 index 0000000000..951094aed6 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaBaseColumnTextRangeResolver.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Oracle - initial API and implementation + *******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.java.JavaBaseColumn; +import org.eclipse.jpt.jpa.core.internal.context.BaseColumnTextRangeResolver; + +public class JavaBaseColumnTextRangeResolver + extends JavaNamedColumnTextRangeResolver + implements BaseColumnTextRangeResolver +{ + + public JavaBaseColumnTextRangeResolver(JavaBaseColumn column, CompilationUnit astRoot) { + super(column, astRoot); + } + + @Override + protected JavaBaseColumn getColumn() { + return (JavaBaseColumn) super.getColumn(); + } + public TextRange getTableTextRange() { + return this.getColumn().getTableTextRange(this.astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaBasicMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaBasicMappingDefinition.java new file mode 100644 index 0000000000..7d13a41785 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaBasicMappingDefinition.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.context.java.DefaultJavaAttributeMappingDefinition; + +public class JavaBasicMappingDefinition + extends AbstractJavaBasicMappingDefinition +{ + // singleton + private static final DefaultJavaAttributeMappingDefinition INSTANCE = new JavaBasicMappingDefinition(); + + /** + * Return the singleton. + */ + public static DefaultJavaAttributeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaBasicMappingDefinition() { + super(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEmbeddableDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEmbeddableDefinition.java new file mode 100644 index 0000000000..db5e442034 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEmbeddableDefinition.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaEmbeddable; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType; +import org.eclipse.jpt.jpa.core.context.java.JavaTypeMappingDefinition; +import org.eclipse.jpt.jpa.core.resource.java.Annotation; +import org.eclipse.jpt.jpa.core.resource.java.EmbeddableAnnotation; + +public class JavaEmbeddableDefinition + implements JavaTypeMappingDefinition +{ + // singleton + private static final JavaEmbeddableDefinition INSTANCE = new JavaEmbeddableDefinition(); + + /** + * Return the singleton + */ + public static JavaTypeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaEmbeddableDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.EMBEDDABLE_TYPE_MAPPING_KEY; + } + + public String getAnnotationName() { + return EmbeddableAnnotation.ANNOTATION_NAME; + } + + public Iterable<String> getSupportingAnnotationNames() { + return EmptyIterable.instance(); + } + + public JavaEmbeddable buildMapping(JavaPersistentType persistentType, Annotation mappingAnnotation, JpaFactory factory) { + return factory.buildJavaEmbeddable(persistentType, (EmbeddableAnnotation) mappingAnnotation); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEmbeddedIdMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEmbeddedIdMappingDefinition.java new file mode 100644 index 0000000000..9695b24aca --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEmbeddedIdMappingDefinition.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.AttributeOverrideAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.AttributeOverridesAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.EmbeddedIdAnnotation; + +public class JavaEmbeddedIdMappingDefinition + implements JavaAttributeMappingDefinition +{ + // singleton + private static final JavaAttributeMappingDefinition INSTANCE = new JavaEmbeddedIdMappingDefinition(); + + /** + * Return the singleton. + */ + public static JavaAttributeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singletong usage + */ + private JavaEmbeddedIdMappingDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.EMBEDDED_ID_ATTRIBUTE_MAPPING_KEY; + } + + public String getAnnotationName() { + return EmbeddedIdAnnotation.ANNOTATION_NAME; + } + + public boolean isSpecified(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.getResourcePersistentAttribute().getAnnotation(this.getAnnotationName()) != null; + } + + public Iterable<String> getSupportingAnnotationNames() { + return SUPPORTING_ANNOTATION_NAMES; + } + + protected static final String[] SUPPORTING_ANNOTATION_NAMES_ARRAY = new String[] { + AttributeOverrideAnnotation.ANNOTATION_NAME, + AttributeOverridesAnnotation.ANNOTATION_NAME, + }; + protected static final Iterable<String> SUPPORTING_ANNOTATION_NAMES = new ArrayIterable<String>(SUPPORTING_ANNOTATION_NAMES_ARRAY); + + public JavaAttributeMapping buildMapping(JavaPersistentAttribute persistentAttribute, JpaFactory factory) { + return factory.buildJavaEmbeddedIdMapping(persistentAttribute); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEmbeddedMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEmbeddedMappingDefinition.java new file mode 100644 index 0000000000..fc94ac724a --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEmbeddedMappingDefinition.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.context.java.DefaultJavaAttributeMappingDefinition; + +public class JavaEmbeddedMappingDefinition + extends AbstractJavaEmbeddedMappingDefinition +{ + // singleton + private static final DefaultJavaAttributeMappingDefinition INSTANCE = new JavaEmbeddedMappingDefinition(); + + /** + * Return the singleton. + */ + public static DefaultJavaAttributeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaEmbeddedMappingDefinition() { + super(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEntityDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEntityDefinition.java new file mode 100644 index 0000000000..485e0b658b --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEntityDefinition.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaEntity; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType; +import org.eclipse.jpt.jpa.core.context.java.JavaTypeMappingDefinition; +import org.eclipse.jpt.jpa.core.resource.java.Annotation; +import org.eclipse.jpt.jpa.core.resource.java.AssociationOverrideAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.AssociationOverridesAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.AttributeOverrideAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.AttributeOverridesAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.DiscriminatorColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.DiscriminatorValueAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.EntityAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.IdClassAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.InheritanceAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JPA; +import org.eclipse.jpt.jpa.core.resource.java.NamedNativeQueriesAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.NamedNativeQueryAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.NamedQueriesAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.NamedQueryAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.PrimaryKeyJoinColumnAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.PrimaryKeyJoinColumnsAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.SecondaryTableAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.SecondaryTablesAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.SequenceGeneratorAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.TableAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.TableGeneratorAnnotation; + +public class JavaEntityDefinition + implements JavaTypeMappingDefinition +{ + // singleton + private static final JavaEntityDefinition INSTANCE = new JavaEntityDefinition(); + + /** + * Return the singleton + */ + public static JavaTypeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaEntityDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.ENTITY_TYPE_MAPPING_KEY; + } + + public String getAnnotationName() { + return EntityAnnotation.ANNOTATION_NAME; + } + + public Iterable<String> getSupportingAnnotationNames() { + return SUPPORTING_ANNOTATION_NAMES; + } + + protected static final String[] SUPPORTING_ANNOTATION_NAMES_ARRAY = new String[] { + TableAnnotation.ANNOTATION_NAME, + SecondaryTableAnnotation.ANNOTATION_NAME, + SecondaryTablesAnnotation.ANNOTATION_NAME, + PrimaryKeyJoinColumnAnnotation.ANNOTATION_NAME, + PrimaryKeyJoinColumnsAnnotation.ANNOTATION_NAME, + IdClassAnnotation.ANNOTATION_NAME, + InheritanceAnnotation.ANNOTATION_NAME, + DiscriminatorValueAnnotation.ANNOTATION_NAME, + DiscriminatorColumnAnnotation.ANNOTATION_NAME, + SequenceGeneratorAnnotation.ANNOTATION_NAME, + TableGeneratorAnnotation.ANNOTATION_NAME, + NamedQueryAnnotation.ANNOTATION_NAME, + NamedQueriesAnnotation.ANNOTATION_NAME, + NamedNativeQueryAnnotation.ANNOTATION_NAME, + NamedNativeQueriesAnnotation.ANNOTATION_NAME, + JPA.SQL_RESULT_SET_MAPPING, + JPA.EXCLUDE_DEFAULT_LISTENERS, + JPA.EXCLUDE_SUPERCLASS_LISTENERS, + JPA.ENTITY_LISTENERS, + JPA.PRE_PERSIST, + JPA.POST_PERSIST, + JPA.PRE_REMOVE, + JPA.POST_REMOVE, + JPA.PRE_UPDATE, + JPA.POST_UPDATE, + JPA.POST_LOAD, + AttributeOverrideAnnotation.ANNOTATION_NAME, + AttributeOverridesAnnotation.ANNOTATION_NAME, + AssociationOverrideAnnotation.ANNOTATION_NAME, + AssociationOverridesAnnotation.ANNOTATION_NAME + }; + protected static final Iterable<String> SUPPORTING_ANNOTATION_NAMES = new ArrayIterable<String>(SUPPORTING_ANNOTATION_NAMES_ARRAY); + + public JavaEntity buildMapping(JavaPersistentType persistentType, Annotation mappingAnnotation, JpaFactory factory) { + return factory.buildJavaEntity(persistentType, (EntityAnnotation) mappingAnnotation); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEntityTextRangeResolver.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEntityTextRangeResolver.java new file mode 100644 index 0000000000..af74224308 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaEntityTextRangeResolver.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Oracle - initial API and implementation + *******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.java.JavaEntity; +import org.eclipse.jpt.jpa.core.internal.context.EntityTextRangeResolver; + +public class JavaEntityTextRangeResolver + implements EntityTextRangeResolver +{ + private JavaEntity entity; + + private CompilationUnit astRoot; + + + public JavaEntityTextRangeResolver(JavaEntity entity, CompilationUnit astRoot) { + this.entity = entity; + this.astRoot = astRoot; + } + + + public TextRange getTypeMappingTextRange() { + return this.entity.getValidationTextRange(this.astRoot); + } + + public TextRange getIdClassTextRange() { + return this.entity.getIdClassReference().getValidationTextRange(this.astRoot); + } + + public TextRange getAttributeMappingTextRange(String attributeName) { + return this.entity.getPersistentType(). + getAttributeNamed(attributeName).getMapping().getValidationTextRange(this.astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaIdMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaIdMappingDefinition.java new file mode 100644 index 0000000000..1297324074 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaIdMappingDefinition.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; + +public class JavaIdMappingDefinition + extends AbstractJavaIdMappingDefinition +{ + // singleton + private static final JavaAttributeMappingDefinition INSTANCE = new JavaIdMappingDefinition(); + + /** + * Return the singleton. + */ + public static JavaAttributeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaIdMappingDefinition() { + super(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaJoinColumnTextRangeResolver.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaJoinColumnTextRangeResolver.java new file mode 100644 index 0000000000..e715135955 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaJoinColumnTextRangeResolver.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Oracle - initial API and implementation + *******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.java.JavaJoinColumn; +import org.eclipse.jpt.jpa.core.internal.context.JoinColumnTextRangeResolver; + +public class JavaJoinColumnTextRangeResolver + extends JavaNamedColumnTextRangeResolver + implements JoinColumnTextRangeResolver +{ + public JavaJoinColumnTextRangeResolver(JavaJoinColumn column, CompilationUnit astRoot) { + super(column, astRoot); + } + + @Override + protected JavaJoinColumn getColumn() { + return (JavaJoinColumn) super.getColumn(); + } + + public TextRange getTableTextRange() { + return this.getColumn().getTableTextRange(this.astRoot); + } + + public TextRange getReferencedColumnNameTextRange() { + return this.getColumn().getReferencedColumnNameTextRange(this.astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaManyToManyMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaManyToManyMappingDefinition.java new file mode 100644 index 0000000000..dbce1decd9 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaManyToManyMappingDefinition.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; + +public class JavaManyToManyMappingDefinition + extends AbstractJavaManyToManyMappingDefinition +{ + // singleton + private static final JavaAttributeMappingDefinition INSTANCE = new JavaManyToManyMappingDefinition(); + + /** + * Return the singleton. + */ + public static JavaAttributeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaManyToManyMappingDefinition() { + super(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaManyToOneMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaManyToOneMappingDefinition.java new file mode 100644 index 0000000000..f93744128a --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaManyToOneMappingDefinition.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; + +public class JavaManyToOneMappingDefinition + extends AbstractJavaManyToOneMappingDefinition +{ + // singleton + private static final JavaAttributeMappingDefinition INSTANCE = new JavaManyToOneMappingDefinition(); + + /** + * Return the singleton. + */ + public static JavaAttributeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaManyToOneMappingDefinition() { + super(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaMappedSuperclassDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaMappedSuperclassDefinition.java new file mode 100644 index 0000000000..ce234ec00c --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaMappedSuperclassDefinition.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaMappedSuperclass; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType; +import org.eclipse.jpt.jpa.core.context.java.JavaTypeMappingDefinition; +import org.eclipse.jpt.jpa.core.resource.java.Annotation; +import org.eclipse.jpt.jpa.core.resource.java.IdClassAnnotation; +import org.eclipse.jpt.jpa.core.resource.java.JPA; +import org.eclipse.jpt.jpa.core.resource.java.MappedSuperclassAnnotation; + +public class JavaMappedSuperclassDefinition + implements JavaTypeMappingDefinition +{ + // singleton + private static final JavaMappedSuperclassDefinition INSTANCE = new JavaMappedSuperclassDefinition(); + + /** + * Return the singleton + */ + public static JavaTypeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaMappedSuperclassDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.MAPPED_SUPERCLASS_TYPE_MAPPING_KEY; + } + + public String getAnnotationName() { + return MappedSuperclassAnnotation.ANNOTATION_NAME; + } + + public Iterable<String> getSupportingAnnotationNames() { + return SUPPORTING_ANNOTATION_NAMES; + } + + protected static final String[] SUPPORTING_ANNOTATION_NAMES_ARRAY = new String[] { + IdClassAnnotation.ANNOTATION_NAME, + JPA.EXCLUDE_DEFAULT_LISTENERS, + JPA.EXCLUDE_SUPERCLASS_LISTENERS, + JPA.ENTITY_LISTENERS, + JPA.PRE_PERSIST, + JPA.POST_PERSIST, + JPA.PRE_REMOVE, + JPA.POST_REMOVE, + JPA.PRE_UPDATE, + JPA.POST_UPDATE, + JPA.POST_LOAD + }; + protected static final Iterable<String> SUPPORTING_ANNOTATION_NAMES = new ArrayIterable<String>(SUPPORTING_ANNOTATION_NAMES_ARRAY); + + public JavaMappedSuperclass buildMapping(JavaPersistentType persistentType, Annotation mappingAnnotation, JpaFactory factory) { + return factory.buildJavaMappedSuperclass(persistentType, (MappedSuperclassAnnotation) mappingAnnotation); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaMappedSuperclassTextRangeResolver.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaMappedSuperclassTextRangeResolver.java new file mode 100644 index 0000000000..c9319716ea --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaMappedSuperclassTextRangeResolver.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Oracle - initial API and implementation + *******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.java.JavaMappedSuperclass; +import org.eclipse.jpt.jpa.core.internal.context.PrimaryKeyTextRangeResolver; + +public class JavaMappedSuperclassTextRangeResolver + implements PrimaryKeyTextRangeResolver +{ + private JavaMappedSuperclass mappedSuperclass; + + private CompilationUnit astRoot; + + + public JavaMappedSuperclassTextRangeResolver( + JavaMappedSuperclass mappedSuperclass, CompilationUnit astRoot) { + + this.mappedSuperclass = mappedSuperclass; + this.astRoot = astRoot; + } + + + public TextRange getTypeMappingTextRange() { + return this.mappedSuperclass.getValidationTextRange(this.astRoot); + } + + public TextRange getIdClassTextRange() { + return this.mappedSuperclass.getIdClassReference().getValidationTextRange(this.astRoot); + } + + public TextRange getAttributeMappingTextRange(String attributeName) { + return this.mappedSuperclass.getPersistentType(). + getAttributeNamed(attributeName).getMapping().getValidationTextRange(this.astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaNamedColumnTextRangeResolver.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaNamedColumnTextRangeResolver.java new file mode 100644 index 0000000000..cab6e08e67 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaNamedColumnTextRangeResolver.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Oracle - initial API and implementation + *******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.java.JavaNamedColumn; +import org.eclipse.jpt.jpa.core.internal.context.NamedColumnTextRangeResolver; + +public class JavaNamedColumnTextRangeResolver + implements NamedColumnTextRangeResolver +{ + protected final JavaNamedColumn javaNamedColumn; + + protected final CompilationUnit astRoot; + + public JavaNamedColumnTextRangeResolver(JavaNamedColumn javaNamedColumn, CompilationUnit astRoot) { + this.javaNamedColumn = javaNamedColumn; + this.astRoot = astRoot; + } + + protected JavaNamedColumn getColumn() { + return this.javaNamedColumn; + } + + public TextRange getNameTextRange() { + return this.javaNamedColumn.getNameTextRange(this.astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaNullTypeMapping.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaNullTypeMapping.java new file mode 100644 index 0000000000..b48a3deef0 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaNullTypeMapping.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import java.util.List; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType; +import org.eclipse.jpt.jpa.core.internal.validation.DefaultJpaValidationMessages; +import org.eclipse.jpt.jpa.core.internal.validation.JpaValidationMessages; +import org.eclipse.jpt.jpa.core.resource.java.Annotation; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * Java null type mapping + */ +public class JavaNullTypeMapping + extends AbstractJavaTypeMapping<Annotation> +{ + public JavaNullTypeMapping(JavaPersistentType parent) { + super(parent, null); + } + + public String getKey() { + return MappingKeys.NULL_TYPE_MAPPING_KEY; + } + + public JavaPersistentType getIdClass() { + return null; + } + + public boolean isMapped() { + return false; + } + + public boolean tableNameIsInvalid(String tableName) { + return false; + } + + + // ********** validation ********** + + /** + * We added this message here because the most likely solution is to add + * an annotation to the .java file. + * This message used to be found on the <class> tag in persistence.xml. + * The other possible way to fix the error is to remove it from persistence.xml. + * This can be accomplished with the Synchronize Classes action. + * We could also add a quick fix for this error. + */ + @Override + public void validate(List<IMessage> messages, IReporter reporter, CompilationUnit astRoot) { + super.validate(messages, reporter, astRoot); + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.PERSISTENCE_UNIT_INVALID_CLASS, + new String[] {this.getPersistentType().getName()}, + this, + this.getValidationTextRange(astRoot) + ) + ); + } + + @Override + public boolean validatesAgainstDatabase() { + return false; + } + + @Override + public TextRange getValidationTextRange(CompilationUnit astRoot) { + return this.getPersistentType().getValidationTextRange(astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaOneToManyMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaOneToManyMappingDefinition.java new file mode 100644 index 0000000000..e2029a4f07 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaOneToManyMappingDefinition.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; + +public class JavaOneToManyMappingDefinition + extends AbstractJavaOneToManyMappingDefinition +{ + // singleton + private static final JavaAttributeMappingDefinition INSTANCE = new JavaOneToManyMappingDefinition(); + + /** + * Return the singleton + */ + public static JavaAttributeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaOneToManyMappingDefinition() { + super(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaOneToOneMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaOneToOneMappingDefinition.java new file mode 100644 index 0000000000..6ed2d0b317 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaOneToOneMappingDefinition.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; + +public class JavaOneToOneMappingDefinition + extends AbstractJavaOneToOneMappingDefinition +{ + // singleton + private static final JavaAttributeMappingDefinition INSTANCE = new JavaOneToOneMappingDefinition(); + + /** + * Return the singleton. + */ + public static JavaAttributeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaOneToOneMappingDefinition() { + super(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaOverrideTextRangeResolver.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaOverrideTextRangeResolver.java new file mode 100644 index 0000000000..7dcd7ce470 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaOverrideTextRangeResolver.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Oracle - initial API and implementation + *******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.java.JavaOverride; +import org.eclipse.jpt.jpa.core.internal.context.OverrideTextRangeResolver; + +public class JavaOverrideTextRangeResolver + implements OverrideTextRangeResolver +{ + protected final JavaOverride javaOverride; + + protected final CompilationUnit astRoot; + + public JavaOverrideTextRangeResolver(JavaOverride javaOverride, CompilationUnit astRoot) { + this.javaOverride = javaOverride; + this.astRoot = astRoot; + } + + protected JavaOverride getOverride() { + return this.javaOverride; + } + + public TextRange getNameTextRange() { + return this.javaOverride.getNameTextRange(this.astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaPersistentAttributeTextRangeResolver.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaPersistentAttributeTextRangeResolver.java new file mode 100644 index 0000000000..83fe6f95ca --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaPersistentAttributeTextRangeResolver.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Oracle - initial API and implementation + *******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.internal.context.PersistentAttributeTextRangeResolver; + +public class JavaPersistentAttributeTextRangeResolver + implements PersistentAttributeTextRangeResolver +{ + private JavaPersistentAttribute javaPersistentAttribute; + + private CompilationUnit astRoot; + + public JavaPersistentAttributeTextRangeResolver(JavaPersistentAttribute javaPersistentAttribute, CompilationUnit astRoot) { + this.javaPersistentAttribute = javaPersistentAttribute; + this.astRoot = astRoot; + } + + public TextRange getAttributeTextRange() { + return this.javaPersistentAttribute.getValidationTextRange(this.astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaPrimaryKeyJoinColumnTextRangeResolver.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaPrimaryKeyJoinColumnTextRangeResolver.java new file mode 100644 index 0000000000..261f522f4a --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaPrimaryKeyJoinColumnTextRangeResolver.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Oracle - initial API and implementation + *******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.java.JavaPrimaryKeyJoinColumn; +import org.eclipse.jpt.jpa.core.internal.context.BaseJoinColumnTextRangeResolver; + +public class JavaPrimaryKeyJoinColumnTextRangeResolver + extends JavaNamedColumnTextRangeResolver + implements BaseJoinColumnTextRangeResolver +{ + + public JavaPrimaryKeyJoinColumnTextRangeResolver(JavaPrimaryKeyJoinColumn column, CompilationUnit astRoot) { + super(column, astRoot); + } + + @Override + protected JavaPrimaryKeyJoinColumn getColumn() { + return (JavaPrimaryKeyJoinColumn) super.getColumn(); + } + + public TextRange getReferencedColumnNameTextRange() { + return this.getColumn().getReferencedColumnNameTextRange(this.astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaTableTextRangeResolver.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaTableTextRangeResolver.java new file mode 100644 index 0000000000..2f431635bb --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaTableTextRangeResolver.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Oracle - initial API and implementation + *******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.java.JavaTable; +import org.eclipse.jpt.jpa.core.internal.context.TableTextRangeResolver; + +public class JavaTableTextRangeResolver + implements TableTextRangeResolver +{ + protected final JavaTable javaTable; + + protected final CompilationUnit astRoot; + + public JavaTableTextRangeResolver(JavaTable javaTable, CompilationUnit astRoot) { + this.javaTable = javaTable; + this.astRoot = astRoot; + } + + protected JavaTable getTable() { + return this.javaTable; + } + + public TextRange getNameTextRange() { + return this.javaTable.getNameTextRange(this.astRoot); + } + + public TextRange getCatalogTextRange() { + return this.javaTable.getCatalogTextRange(this.astRoot); + } + + public TextRange getSchemaTextRange() { + return this.javaTable.getSchemaTextRange(this.astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaTransientMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaTransientMappingDefinition.java new file mode 100644 index 0000000000..4618a9ec32 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaTransientMappingDefinition.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +import org.eclipse.jpt.jpa.core.JpaFactory; +import org.eclipse.jpt.jpa.core.MappingKeys; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; +import org.eclipse.jpt.jpa.core.resource.java.TransientAnnotation; + +public class JavaTransientMappingDefinition + implements JavaAttributeMappingDefinition +{ + // singleton + private static final JavaAttributeMappingDefinition INSTANCE = new JavaTransientMappingDefinition(); + + /** + * Return the singleton. + */ + public static JavaAttributeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaTransientMappingDefinition() { + super(); + } + + public String getKey() { + return MappingKeys.TRANSIENT_ATTRIBUTE_MAPPING_KEY; + } + + public String getAnnotationName() { + return TransientAnnotation.ANNOTATION_NAME; + } + + public boolean isSpecified(JavaPersistentAttribute persistentAttribute) { + return persistentAttribute.getResourcePersistentAttribute().getAnnotation(this.getAnnotationName()) != null; + } + + public Iterable<String> getSupportingAnnotationNames() { + return EmptyIterable.instance(); + } + + public JavaAttributeMapping buildMapping(JavaPersistentAttribute persistentAttribute, JpaFactory factory) { + return factory.buildJavaTransientMapping(persistentAttribute); + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaTypeMappingTextRangeResolver.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaTypeMappingTextRangeResolver.java new file mode 100644 index 0000000000..174e6b2b7a --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaTypeMappingTextRangeResolver.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2010 Oracle. + * All rights reserved. This program and the accompanying materials are + * made available under the terms of the Eclipse Public License v1.0 which + * accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Oracle - initial API and implementation + *******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jpt.common.core.utility.TextRange; +import org.eclipse.jpt.jpa.core.context.java.JavaTypeMapping; +import org.eclipse.jpt.jpa.core.internal.context.TypeMappingTextRangeResolver; + +public class JavaTypeMappingTextRangeResolver + implements TypeMappingTextRangeResolver +{ + private JavaTypeMapping typeMapping; + + private CompilationUnit astRoot; + + public JavaTypeMappingTextRangeResolver(JavaTypeMapping typeMapping, CompilationUnit astRoot) { + this.typeMapping = typeMapping; + this.astRoot = astRoot; + } + + public TextRange getTypeMappingTextRange() { + return this.typeMapping.getValidationTextRange(this.astRoot); + } +} diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaVersionMappingDefinition.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaVersionMappingDefinition.java new file mode 100644 index 0000000000..c078d6fced --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/java/JavaVersionMappingDefinition.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 Oracle. All rights reserved. + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0, which accompanies this distribution + * and is available at http://www.eclipse.org/legal/epl-v10.html. + * + * Contributors: + * Oracle - initial API and implementation + ******************************************************************************/ +package org.eclipse.jpt.jpa.core.internal.context.java; + +import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMappingDefinition; + +public class JavaVersionMappingDefinition + extends AbstractJavaVersionMappingDefinition +{ + // singleton + private static final JavaAttributeMappingDefinition INSTANCE = new JavaVersionMappingDefinition(); + + /** + * Return the singleton. + */ + public static JavaAttributeMappingDefinition instance() { + return INSTANCE; + } + + + /** + * Enforce singleton usage + */ + private JavaVersionMappingDefinition() { + super(); + } +} |