diff options
author | kmoore | 2012-01-20 19:34:35 +0000 |
---|---|---|
committer | kmoore | 2012-01-20 19:34:35 +0000 |
commit | 2258fbd13be54d5fccdbb1d24970472f993b57c5 (patch) | |
tree | 16f51029f718adc444206e778263c866cdb4cb3f /jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context | |
parent | 2906afe6464d3be54b3d0455f1b3dd71603f7efd (diff) | |
download | webtools.dali-2258fbd13be54d5fccdbb1d24970472f993b57c5.tar.gz webtools.dali-2258fbd13be54d5fccdbb1d24970472f993b57c5.tar.xz webtools.dali-2258fbd13be54d5fccdbb1d24970472f993b57c5.zip |
added preliminary support for EclipseLink access-methods and VIRTUAL access type
Diffstat (limited to 'jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context')
6 files changed, 1408 insertions, 7 deletions
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 index 6438772fb5..bddecd461e 100644 --- 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 @@ -176,7 +176,7 @@ public abstract class AbstractJavaPersistentAttribute */ protected AccessType buildSpecifiedAccess() { Access2_0Annotation accessAnnotation = this.getAccessAnnotation(); - return (accessAnnotation == null) ? null : AccessType.fromJavaResourceModel(accessAnnotation.getValue()); + return (accessAnnotation == null) ? null : AccessType.fromJavaResourceModel(accessAnnotation.getValue(), this.getJpaPlatform(), this.getResourceType()); } protected Access2_0Annotation getAccessAnnotation() { 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 index 8b7c8ae5e4..53506af8ce 100644 --- 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2011 Oracle. All rights reserved. + * Copyright (c) 2006, 2012 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. @@ -240,7 +240,7 @@ public abstract class AbstractJavaPersistentType } protected AccessType buildSpecifiedAccess() { - return AccessType.fromJavaResourceModel(this.getAccessAnnotation().getValue()); + return AccessType.fromJavaResourceModel(this.getAccessAnnotation().getValue(), this.getJpaPlatform(), this.getResourceType()); } public AccessType getDefaultAccess() { diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractEntityMappings.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractEntityMappings.java index 8184ae5fa5..0e6a9023ab 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractEntityMappings.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractEntityMappings.java @@ -332,7 +332,7 @@ public abstract class AbstractEntityMappings } protected AccessType buildSpecifiedAccess() { - return AccessType.fromOrmResourceModel(this.xmlEntityMappings.getAccess()); + return AccessType.fromOrmResourceModel(this.xmlEntityMappings.getAccess(), this.getJpaPlatform(), this.getResourceType()); } public AccessType getDefaultAccess() { diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractOrmXmlContextNode.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractOrmXmlContextNode.java index d6ec443ca7..75569ed57a 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractOrmXmlContextNode.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/AbstractOrmXmlContextNode.java @@ -60,7 +60,7 @@ public abstract class AbstractOrmXmlContextNode protected boolean isOrmXml2_0Compatible() { String version = this.getMappingFileRoot().getVersion(); try { - return (version != null) && SimpleVersion.JPA_VERSION_COMPARATOR.compare(version, "2.0") >= 0; //$NON-NLS-1$ + return (version != null) && SimpleVersion.VERSION_COMPARATOR.compare(version, "2.0") >= 0; //$NON-NLS-1$ } catch (VersionFormatException ex) { return false; } diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/SpecifiedOrmPersistentAttribute.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/SpecifiedOrmPersistentAttribute.java index 04178ae078..b2fc33f978 100644 --- a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/SpecifiedOrmPersistentAttribute.java +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/SpecifiedOrmPersistentAttribute.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2006, 2011 Oracle. All rights reserved. + * Copyright (c) 2006, 2012 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. @@ -380,7 +380,7 @@ public abstract class SpecifiedOrmPersistentAttribute } protected AccessType buildSpecifiedAccess() { - return AccessType.fromOrmResourceModel(this.getXmlAccessHolder().getAccess()); + return AccessType.fromOrmResourceModel(this.getXmlAccessHolder().getAccess(), this.getJpaPlatform(), this.getResourceType()); } protected XmlAccessHolder getXmlAccessHolder() { diff --git a/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/SpecifiedOrmPersistentType.java b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/SpecifiedOrmPersistentType.java new file mode 100644 index 0000000000..aad8269592 --- /dev/null +++ b/jpa/plugins/org.eclipse.jpt.jpa.core/src/org/eclipse/jpt/jpa/core/internal/context/orm/SpecifiedOrmPersistentType.java @@ -0,0 +1,1401 @@ +/******************************************************************************* + * Copyright (c) 2006, 2012 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.orm; + +import java.util.Collection; +import java.util.Comparator; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Vector; +import org.eclipse.core.resources.IFile; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IType; +import org.eclipse.jpt.common.core.resource.java.JavaResourceAbstractType; +import org.eclipse.jpt.common.core.resource.java.JavaResourceAnnotatedElement.Kind; +import org.eclipse.jpt.common.core.resource.java.JavaResourceField; +import org.eclipse.jpt.common.core.resource.java.JavaResourceMethod; +import org.eclipse.jpt.common.core.resource.java.JavaResourceType; +import org.eclipse.jpt.common.core.utility.BodySourceWriter; +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.StringTools; +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.CompositeListIterable; +import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; +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.SingleElementIterable; +import org.eclipse.jpt.common.utility.internal.iterables.SuperListIterableWrapper; +import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable; +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.JavaPersistentType; +import org.eclipse.jpt.jpa.core.context.orm.EntityMappings; +import org.eclipse.jpt.jpa.core.context.orm.OrmAttributeMapping; +import org.eclipse.jpt.jpa.core.context.orm.OrmAttributeMappingDefinition; +import org.eclipse.jpt.jpa.core.context.orm.OrmPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.orm.OrmPersistentType; +import org.eclipse.jpt.jpa.core.context.orm.OrmReadOnlyPersistentAttribute; +import org.eclipse.jpt.jpa.core.context.orm.OrmStructureNodes; +import org.eclipse.jpt.jpa.core.context.orm.OrmTypeMapping; +import org.eclipse.jpt.jpa.core.context.orm.OrmTypeMappingDefinition; +import org.eclipse.jpt.jpa.core.internal.context.ContextContainerTools; +import org.eclipse.jpt.jpa.core.internal.context.java.AbstractJavaPersistentType; +import org.eclipse.jpt.jpa.core.internal.context.java.PropertyAccessor; +import org.eclipse.jpt.jpa.core.internal.context.orm.AbstractOrmXmlContextNode; +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.MetamodelSourceType; +import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaPersistentType2_0; +import org.eclipse.jpt.jpa.core.jpa2.context.orm.OrmPersistentType2_0; +import org.eclipse.jpt.jpa.core.resource.orm.Attributes; +import org.eclipse.jpt.jpa.core.resource.orm.OrmPackage; +import org.eclipse.jpt.jpa.core.resource.orm.XmlAttributeMapping; +import org.eclipse.jpt.jpa.core.resource.orm.XmlTypeMapping; +import org.eclipse.jpt.jpa.core.resource.xml.EmfTools; +import org.eclipse.text.edits.DeleteEdit; +import org.eclipse.text.edits.ReplaceEdit; +import org.eclipse.wst.validation.internal.provisional.core.IMessage; +import org.eclipse.wst.validation.internal.provisional.core.IReporter; + +/** + * specified <code>orm.xml</code> persistent type:<ul> + * <li>mapping + * <li>access + * <li>attributes + * <li>super persistent type + * <li>Java persistent type + * </ul> + */ +public abstract class SpecifiedOrmPersistentType + extends AbstractOrmXmlContextNode + implements OrmPersistentType2_0 +{ + protected OrmTypeMapping mapping; // never null + + protected JavaPersistentType javaPersistentType; + + protected AccessType specifiedAccess; + protected AccessType defaultAccess; // never null + + protected final Vector<OrmPersistentAttribute> specifiedAttributes = new Vector<OrmPersistentAttribute>(); + protected final SpecifiedAttributeContainerAdapter specifiedAttributeContainerAdapter = new SpecifiedAttributeContainerAdapter(); + + protected final Vector<OrmReadOnlyPersistentAttribute> virtualAttributes = new Vector<OrmReadOnlyPersistentAttribute>(); + + protected PersistentType superPersistentType; + + protected String declaringTypeName; + + protected final MetamodelSourceType.Synchronizer metamodelSynchronizer; + + + protected SpecifiedOrmPersistentType(EntityMappings parent, XmlTypeMapping xmlTypeMapping) { + super(parent); + this.mapping = this.buildMapping(xmlTypeMapping); + // 'javaPersistentType' is resolved in the update + this.specifiedAccess = this.buildSpecifiedAccess(); + this.defaultAccess = AccessType.FIELD; // keep this non-null + this.initializeSpecifiedAttributes(); + this.metamodelSynchronizer = this.buildMetamodelSynchronizer(); + } + + + // ********** synchronize/update ********** + + @Override + public void synchronizeWithResourceModel() { + super.synchronizeWithResourceModel(); + this.mapping.synchronizeWithResourceModel(); + this.syncJavaPersistentType(); + this.setSpecifiedAccess_(this.buildSpecifiedAccess()); + this.syncSpecifiedAttributes(); + this.synchronizeNodesWithResourceModel(this.getVirtualAttributes()); + } + + @Override + public void update() { + super.update(); + this.mapping.update(); + this.updateJavaPersistentType(); + this.setDefaultAccess(this.buildDefaultAccess()); + this.updateNodes(this.getSpecifiedAttributes()); + this.updateVirtualAttributes(); + this.setSuperPersistentType(this.buildSuperPersistentType()); + this.setDeclaringTypeName(this.buildDeclaringTypeName()); + } + + + // ********** mapping ********** + + public OrmTypeMapping getMapping() { + return this.mapping; + } + + public String getMappingKey() { + return this.mapping.getKey(); + } + + public void setMappingKey(String mappingKey) { + if (this.valuesAreDifferent(this.getMappingKey(), mappingKey)) { + this.setMappingKey_(mappingKey); + } + } + + protected void setMappingKey_(String mappingKey) { + OrmTypeMapping old = this.mapping; + OrmTypeMappingDefinition mappingDefinition = this.getMappingFileDefinition().getTypeMappingDefinition(mappingKey); + XmlTypeMapping xmlTypeMapping = mappingDefinition.buildResourceMapping(this.getResourceNodeFactory()); + this.mapping = this.buildMapping(xmlTypeMapping); + this.getEntityMappings().changeMapping(this, old, this.mapping); + this.firePropertyChanged(MAPPING_PROPERTY, old, this.mapping); + } + + protected OrmTypeMapping buildMapping(XmlTypeMapping xmlTypeMapping) { + OrmTypeMappingDefinition md = this.getMappingFileDefinition().getTypeMappingDefinition(xmlTypeMapping.getMappingKey()); + return md.buildContextMapping(this, xmlTypeMapping, this.getContextNodeFactory()); + } + + protected XmlTypeMapping getXmlTypeMapping() { + return this.mapping.getXmlTypeMapping(); + } + + public boolean isMapped() { + return true; + } + + + // ********** name ********** + + public String getName() { + return (this.javaPersistentType != null) ? + this.javaPersistentType.getName() : + this.getMappingClassName(); + } + + protected String getMappingClassName() { + return this.convertMappingClassName(this.mapping.getClass_()); + } + + public String getSimpleName(){ + String className = this.getName(); + return StringTools.stringIsEmpty(className) ? null : ClassName.getSimpleName(className); + } + + /** + * We clear out {@link #javaPersistentType} here because we cannot compare its name + * to the mapping's class name, since it may have been prefixed by the entity + * mappings package. + */ + public void mappingClassChanged(String oldClass, String newClass) { + this.firePropertyChanged(NAME_PROPERTY, this.convertMappingClassName(oldClass), this.convertMappingClassName(newClass)); + // clear out the Java type here, it will be rebuilt during "update" + if (this.javaPersistentType != null) { + this.javaPersistentType.dispose(); + this.setJavaPersistentType(null); + } + } + + /** + * Nested class names are specified with a <code>'$'</code> + * in <code>orm.xml</code>. + */ + protected String convertMappingClassName(String name) { + return (name == null) ? null : name.replace('$', '.'); + } + + + // ********** Java persistent type ********** + + public JavaPersistentType getJavaPersistentType() { + return this.javaPersistentType; + } + + protected void setJavaPersistentType(JavaPersistentType javaPersistentType) { + JavaPersistentType old = this.javaPersistentType; + this.javaPersistentType = javaPersistentType; + this.firePropertyChanged(JAVA_PERSISTENT_TYPE_PROPERTY, old, javaPersistentType); + } + + /** + * If the persistent type's mapping's class (name) changes during + * <em>sync</em>, the Java persistent type will be cleared out in + * {@link #mappingClassChanged(String, String)}. If we get here and + * the Java persistent type is still present, we can + * <em>sync</em> it. Of course, it might still be obsolete if the + * entity mappings's package has changed.... + * + * @see #updateJavaPersistentType() + */ + protected void syncJavaPersistentType() { + if (this.javaPersistentType != null) { + this.javaPersistentType.synchronizeWithResourceModel(); + } + } + + /** + * @see #syncJavaPersistentType() + */ + protected void updateJavaPersistentType() { + JavaResourceAbstractType resourceType = this.resolveJavaResourceType(); + if (resourceType == null) { + if (this.javaPersistentType != null) { + this.javaPersistentType.dispose(); + this.setJavaPersistentType(null); + } + } else { + if (this.javaPersistentType == null) { + this.setJavaPersistentType(this.buildJavaPersistentType(resourceType)); + } else { + if (this.javaPersistentType.getJavaResourceType() == resourceType) { + this.javaPersistentType.update(); + } else { + this.javaPersistentType.dispose(); + this.setJavaPersistentType(this.buildJavaPersistentType(resourceType)); + } + } + } + } + + /** + * Use {@link #getMappingClassName()} instead of {@link #getName()} to + * look up the Java resource type because {@link #getName()} + * simply delegates to the existing Java resource persistent type. (In + * which case we wouldn't need to resolve it, would we?) [bug 339560] + * @see #updateJavaPersistentType() + */ + protected JavaResourceAbstractType resolveJavaResourceType() { + return this.getEntityMappings().resolveJavaResourceType(this.getMappingClassName()); + } + + /** + * Return null it's an enum; don't build a JavaPersistentType + */ + protected JavaPersistentType buildJavaPersistentType(JavaResourceAbstractType jrat) { + return jrat.getKind() == Kind.TYPE ? this.buildJavaPersistentType((JavaResourceType) jrat) : null; + } + + protected JavaPersistentType buildJavaPersistentType(JavaResourceType jrpt) { + return this.getJpaFactory().buildJavaPersistentType(this, jrpt); + } + + + // ********** access ********** + + public AccessType getAccess() { + return (this.specifiedAccess != null) ? this.specifiedAccess : this.defaultAccess; + } + + public AccessType getSpecifiedAccess() { + return this.specifiedAccess; + } + + public void setSpecifiedAccess(AccessType access) { + this.setSpecifiedAccess_(access); + this.getXmlTypeMapping().setAccess(AccessType.toOrmResourceModel(access)); + } + + protected void setSpecifiedAccess_(AccessType access) { + AccessType old = this.specifiedAccess; + this.specifiedAccess = access; + this.firePropertyChanged(SPECIFIED_ACCESS_PROPERTY, old, access); + } + + protected AccessType buildSpecifiedAccess() { + return AccessType.fromOrmResourceModel(this.getXmlTypeMapping().getAccess(), this.getJpaPlatform(), this.getResourceType()); + } + + 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() { + if ( ! this.mapping.isMetadataComplete()) { + if (this.javaPersistentType != null) { + if (this.javaPersistentTypeHasSpecifiedAccess()) { + return this.javaPersistentType.getAccess(); + } + if (this.superPersistentType != null) { + return this.superPersistentType.getAccess(); + } + } + } + AccessType access = this.getMappingFileRoot().getAccess(); + return (access != null) ? access : AccessType.FIELD; // default to FIELD if no specified access found + } + + /** + * pre-condition: {@link #javaPersistentType} is not <code>null</code> + */ + protected boolean javaPersistentTypeHasSpecifiedAccess() { + return (this.javaPersistentType.getSpecifiedAccess() != null) || + this.javaPersistentType.hasAnyAnnotatedAttributes(); + } + + public AccessType getOwnerOverrideAccess() { + return this.getEntityMappings().getOverridePersistentTypeAccess(); + } + + public AccessType getOwnerDefaultAccess() { + return this.getEntityMappings().getDefaultPersistentTypeAccess(); + } + + + // ********** attributes ********** + + @SuppressWarnings("unchecked") + public ListIterable<OrmReadOnlyPersistentAttribute> getAttributes() { + return new CompositeListIterable<OrmReadOnlyPersistentAttribute>(this.getReadOnlySpecifiedAttributes(), this.getVirtualAttributes()); + } + + //TODO remove this compatibility method in the Juno release + public ListIterator<OrmReadOnlyPersistentAttribute> attributes() { + return this.getAttributes().iterator(); + } + + + public int getAttributesSize() { + return this.getSpecifiedAttributesSize() + this.getVirtualAttributesSize(); + } + + public Iterable<String> getAttributeNames() { + return this.convertToNames(this.getAttributes()); + } + + public OrmReadOnlyPersistentAttribute getAttributeNamed(String attributeName) { + Iterator<OrmReadOnlyPersistentAttribute> stream = this.getAttributesNamed(attributeName).iterator(); + return stream.hasNext() ? stream.next() : null; + } + + public Iterable<ReadOnlyPersistentAttribute> getAllAttributes() { + return new CompositeIterable<ReadOnlyPersistentAttribute>( + new TransformationIterable<PersistentType, Iterable<ReadOnlyPersistentAttribute>>(this.getInheritanceHierarchy()) { + @Override + protected Iterable<ReadOnlyPersistentAttribute> transform(PersistentType pt) { + return new SuperListIterableWrapper<ReadOnlyPersistentAttribute>(pt.getAttributes()); + } + } + ); + } + + //TODO remove this compatibility method in the Juno release + public Iterator<ReadOnlyPersistentAttribute> allAttributes() { + return getAllAttributes().iterator(); + } + + public Iterable<String> getAllAttributeNames() { + return this.convertToNames(this.getAllAttributes()); + } + + protected Iterable<OrmReadOnlyPersistentAttribute> getAttributesNamed(final String attributeName) { + return new FilteringIterable<OrmReadOnlyPersistentAttribute>(this.getAttributes()) { + @Override + protected boolean accept(OrmReadOnlyPersistentAttribute attribute) { + return Tools.valuesAreEqual(attributeName, attribute.getName()); + } + }; + } + + public ReadOnlyPersistentAttribute resolveAttribute(String attributeName) { + Iterator<OrmReadOnlyPersistentAttribute> attributes = this.getAttributesNamed(attributeName).iterator(); + if (attributes.hasNext()) { + OrmReadOnlyPersistentAttribute attribute = attributes.next(); + return attributes.hasNext() ? null /* more than one */: attribute; + } + // recurse + return (this.superPersistentType == null) ? null : this.superPersistentType.resolveAttribute(attributeName); + } + + protected Iterable<String> convertToNames(Iterable<? extends ReadOnlyPersistentAttribute> attributes) { + return new TransformationIterable<ReadOnlyPersistentAttribute, String>(attributes) { + @Override + protected String transform(ReadOnlyPersistentAttribute attribute) { + return attribute.getName(); + } + }; + } + + + // ********** attribute conversions ********** + + public OrmPersistentAttribute convertAttributeToSpecified(OrmReadOnlyPersistentAttribute virtualAttribute) { + return this.convertAttributeToSpecified(virtualAttribute, virtualAttribute.getMappingKey()); + } + + public OrmPersistentAttribute convertAttributeToSpecified(OrmReadOnlyPersistentAttribute virtualAttribute, String mappingKey) { + if ( ! virtualAttribute.isVirtual()) { + throw new IllegalArgumentException("Attribute is already specified: " + virtualAttribute); //$NON-NLS-1$ + } + if (mappingKey == null) { + // this typically happens when the virtual attribute does not have a mapping + throw new IllegalArgumentException("Use convertAttributeToSpecified(OrmReadOnlyPersistentAttribute, String) instead and specify a mapping key"); //$NON-NLS-1$ + } + return this.convertAttributeToSpecified_(virtualAttribute, mappingKey); + } + + /** + * <em>Silently</em> remove the virtual attribute and add specified + * attribute before triggering an <em>update</em> or the dangling + * virtual attribute will be removed preemptively. + */ + protected OrmPersistentAttribute convertAttributeToSpecified_(OrmReadOnlyPersistentAttribute virtualAttribute, String mappingKey) { + // silently remove the virtual attribute + int virtualIndex = this.virtualAttributes.indexOf(virtualAttribute); + this.virtualAttributes.remove(virtualIndex); + virtualAttribute.dispose(); + + // silently add the specified attribute + OrmAttributeMappingDefinition md = this.getMappingFileDefinition().getAttributeMappingDefinition(mappingKey); + XmlAttributeMapping xmlMapping = md.buildResourceMapping(this.getResourceNodeFactory()); + + OrmPersistentAttribute specifiedAttribute = this.buildSpecifiedAttribute(xmlMapping); + // we need to add the attribute to the right spot in the list - stupid spec... + int specifiedIndex = this.getSpecifiedAttributeInsertionIndex(specifiedAttribute); + this.specifiedAttributes.add(specifiedIndex, specifiedAttribute); + + // this will trigger the initial update; + // no changes to either collection (virtual or specified) should be detected at this point + specifiedAttribute.getMapping().setName(virtualAttribute.getName()); + + // fire the list change events + this.fireItemRemoved(VIRTUAL_ATTRIBUTES_LIST, virtualIndex, virtualAttribute); + this.fireItemAdded(SPECIFIED_ATTRIBUTES_LIST, specifiedIndex, specifiedAttribute); + + // it should be safe to update the XML now + Attributes xmlAttributes = this.getXmlAttributesForUpdate(); + specifiedAttribute.getMapping().addXmlAttributeMappingTo(xmlAttributes); + // possibly a NOP, but needed when we trigger the creation of a new 'attributes' + this.getXmlTypeMapping().setAttributes(xmlAttributes); + + // copy over the specified access(?) + AccessType oldAccess = virtualAttribute.getJavaPersistentAttribute().getSpecifiedAccess(); + if (oldAccess != null) { + specifiedAttribute.setSpecifiedAccess(oldAccess); + } + return specifiedAttribute; + } + + // TODO this is used only by our tests... + // we cannot delegate to getAttributeNamed(String).convertToSpecified() + // because the tests use this method to add "orphan" xml attributes (that + // do not have a corresponding java attribute :( ) + public OrmPersistentAttribute addSpecifiedAttribute(String mappingKey, String attributeName) { + // force the creation of an empty xml attribute container beforehand or it will trigger + // a sync and, if we do this after adding the attribute, clear out our context attributes + Attributes xmlAttributes = this.getXmlAttributesForUpdate(); + this.getXmlTypeMapping().setAttributes(xmlAttributes); // possibly a NOP + + OrmAttributeMappingDefinition md = this.getMappingFileDefinition().getAttributeMappingDefinition(mappingKey); + XmlAttributeMapping xmlMapping = md.buildResourceMapping(this.getResourceNodeFactory()); + + OrmPersistentAttribute specifiedAttribute = this.buildSpecifiedAttribute(xmlMapping); + // we need to add the attribute to the right spot in the list - stupid spec... + int specifiedIndex = this.getSpecifiedAttributeInsertionIndex(specifiedAttribute); + // the virtual attributes list should remain unchanged since the specified attribute has no name + this.addItemToList(specifiedIndex, specifiedAttribute, this.specifiedAttributes, SPECIFIED_ATTRIBUTES_LIST); + specifiedAttribute.getMapping().addXmlAttributeMappingTo(xmlAttributes); + + // this will trigger the update of the virtual attributes list + specifiedAttribute.getMapping().setName(attributeName); + + return specifiedAttribute; + } + + protected int getSpecifiedAttributeInsertionIndex(OrmPersistentAttribute attribute) { + return CollectionTools.insertionIndexOf(this.specifiedAttributes, attribute, this.getAttributeComparator()); + } + + protected Comparator<OrmPersistentAttribute> getAttributeComparator() { + return ATTRIBUTE_COMPARATOR; + } + + protected static final Comparator<OrmPersistentAttribute> ATTRIBUTE_COMPARATOR = + new Comparator<OrmPersistentAttribute>() { + public int compare(OrmPersistentAttribute attribute1, OrmPersistentAttribute attribute2) { + int seq1 = attribute1.getMapping().getXmlSequence(); + int seq2 = attribute2.getMapping().getXmlSequence(); + return (seq1 == seq2) ? 0 : (seq1 < seq2) ? -1 : 1; + } + }; + + /** + * <em>Silently</em> add the new virtual attribute before removing the + * specified attribute, or the <em>update</em> will discover the missing + * virtual attribute and add it preemptively. + */ + public OrmReadOnlyPersistentAttribute convertAttributeToVirtual(OrmPersistentAttribute specifiedAttribute) { + if (specifiedAttribute.isVirtual()) { + throw new IllegalArgumentException("Attribute is already virtual: " + specifiedAttribute); //$NON-NLS-1$ + } + + int virtualIndex = this.virtualAttributes.size(); + OrmReadOnlyPersistentAttribute virtualAttribute = null; + // make sure the corresponding resource Java attribute actually exists in the *current* type; + // do *not* take the context Java attribute directly from the specified ORM + // attribute we are converting since it may have come from a superclass; + // instead, use its resource Java attribute (which will match both name and access type, + // but we still need to check its parent type) + if (specifiedAttribute.getJavaResourceAttribute() != null) { + if (specifiedAttribute.getJavaResourceAttribute().getKind() == Kind.FIELD) { + JavaResourceField javaResourceField = (JavaResourceField) specifiedAttribute.getJavaResourceAttribute(); + if (this.javaResourceFieldWillBeVirtual(javaResourceField, specifiedAttribute)) { + virtualAttribute = this.buildVirtualAttribute(javaResourceField); + this.virtualAttributes.add(virtualIndex, virtualAttribute); + } + } + else { + PropertyAccessor propertyAccessor = (PropertyAccessor) specifiedAttribute.getJavaPersistentAttribute().getAccessor(); + JavaResourceMethod resourceGetter = propertyAccessor.getResourceGetter(); + JavaResourceMethod resourceSetter = propertyAccessor.getResourceSetter(); + + if (this.javaResourcePropertyWillBeVirtual(resourceGetter, resourceSetter, specifiedAttribute)) { + virtualAttribute = this.buildVirtualAttribute(resourceGetter, resourceSetter); + this.virtualAttributes.add(virtualIndex, virtualAttribute); + } + } + } + + this.removeSpecifiedAttribute(specifiedAttribute); // trigger update + + if (virtualAttribute != null) { + this.fireItemAdded(VIRTUAL_ATTRIBUTES_LIST, virtualIndex, virtualAttribute); + } + return virtualAttribute; + } + + /** + * Return whether the specified Java resource attribute will be a + * <em>virtual</em> attribute when the specified specified attribute is + * removed from the type. The Java resource attribute must be among the + * valid Java resource attributes and it must not correspond to any of the + * remaining specified attributes. + */ + protected boolean javaResourceFieldWillBeVirtual(JavaResourceField javaResourceField, OrmPersistentAttribute specifiedAttributeToBeRemoved) { + return CollectionTools.contains(this.getJavaResourceFields(), javaResourceField) && + (this.getSpecifiedAttributeFor(javaResourceField, specifiedAttributeToBeRemoved) == null); + } + + /** + * Return whether the specified Java resource attribute will be a + * <em>virtual</em> attribute when the specified specified attribute is + * removed from the type. The Java resource attribute must be among the + * valid Java resource attributes and it must not correspond to any of the + * remaining specified attributes. + */ + protected boolean javaResourcePropertyWillBeVirtual(JavaResourceMethod javaResourceGetter, JavaResourceMethod javaResourceSetter, OrmPersistentAttribute specifiedAttributeToBeRemoved) { + return CollectionTools.contains(this.getJavaResourceMethods(), javaResourceGetter) && + CollectionTools.contains(this.getJavaResourceMethods(), javaResourceSetter) && + (this.getSpecifiedAttributeFor(javaResourceGetter, javaResourceSetter, specifiedAttributeToBeRemoved) == null); + } + + + // ********** xml attributes ********** + + /** + * Return <code>null</code> if the <code>attributes</code> element is missing. + */ + protected Attributes getXmlAttributes() { + return this.getXmlTypeMapping().getAttributes(); + } + + /** + * Build a new <code>attributes</code> element if it is not present; + * but do <em>not</em> add it to the XML type mapping. Callers will have + * to add it to the XML type mapping when appropriate. + */ + protected Attributes getXmlAttributesForUpdate() { + Attributes xmlAttributes = this.getXmlAttributes(); + return (xmlAttributes != null) ? xmlAttributes : this.buildXmlAttributes(); + } + + protected Attributes buildXmlAttributes() { + return EmfTools.create(this.getResourceNodeFactory(), OrmPackage.eINSTANCE.getAttributes(), Attributes.class); + } + + protected void removeXmlAttributesIfUnset() { + if (this.getXmlAttributes().isUnset()) { + this.getXmlTypeMapping().setAttributes(null); + } + } + + + // ********** specified attributes ********** + + public ListIterable<OrmPersistentAttribute> getSpecifiedAttributes() { + return new LiveCloneListIterable<OrmPersistentAttribute>(this.specifiedAttributes); + } + + protected ListIterable<OrmReadOnlyPersistentAttribute> getReadOnlySpecifiedAttributes() { + return new SuperListIterableWrapper<OrmReadOnlyPersistentAttribute>(this.getSpecifiedAttributes()); + } + + public int getSpecifiedAttributesSize() { + return this.specifiedAttributes.size(); + } + + protected void removeSpecifiedAttribute(OrmPersistentAttribute attribute) { + this.removeSpecifiedAttribute_(attribute); + attribute.getMapping().removeXmlAttributeMappingFrom(this.getXmlAttributes()); + this.removeXmlAttributesIfUnset(); + } + + public void changeMapping(OrmPersistentAttribute attribute, OrmAttributeMapping oldMapping, OrmAttributeMapping newMapping) { + // keep the context model in sync with each change to the resource model + int sourceIndex = this.specifiedAttributes.indexOf(attribute); + this.specifiedAttributes.remove(sourceIndex); + oldMapping.removeXmlAttributeMappingFrom(this.getXmlAttributes()); + + int targetIndex = this.getSpecifiedAttributeInsertionIndex(attribute); + this.specifiedAttributes.add(targetIndex, attribute); + newMapping.addXmlAttributeMappingTo(this.getXmlAttributes()); + + oldMapping.initializeOn(newMapping); + + this.fireItemMoved(SPECIFIED_ATTRIBUTES_LIST, targetIndex, sourceIndex); + } + + protected void initializeSpecifiedAttributes() { + for (XmlAttributeMapping xmlMapping : this.getXmlAttributeMappings()) { + this.specifiedAttributes.add(this.buildSpecifiedAttribute(xmlMapping)); + } + } + + protected Iterable<XmlAttributeMapping> getXmlAttributeMappings() { + Attributes xmlAttributes = this.getXmlAttributes(); + return (xmlAttributes != null) ? xmlAttributes.getAttributeMappings() : EmptyIterable.<XmlAttributeMapping>instance(); + } + + protected OrmPersistentAttribute buildSpecifiedAttribute(XmlAttributeMapping xmlMapping) { + return this.getContextNodeFactory().buildOrmPersistentAttribute(this, xmlMapping); + } + + protected void syncSpecifiedAttributes() { + ContextContainerTools.synchronizeWithResourceModel(this.specifiedAttributeContainerAdapter); + } + + protected void moveSpecifiedAttribute_(int index, OrmPersistentAttribute attribute) { + this.moveItemInList(index, attribute, this.specifiedAttributes, SPECIFIED_ATTRIBUTES_LIST); + } + + protected void addSpecifiedAttribute_(int index, XmlAttributeMapping xmlMapping) { + OrmPersistentAttribute attribute = this.buildSpecifiedAttribute(xmlMapping); + this.addItemToList(index, attribute, this.specifiedAttributes, SPECIFIED_ATTRIBUTES_LIST); + } + + protected void removeSpecifiedAttribute_(OrmPersistentAttribute attribute) { + this.removeItemFromList(attribute, this.specifiedAttributes, SPECIFIED_ATTRIBUTES_LIST); + } + + /** + * specified attribute container adapter + */ + protected class SpecifiedAttributeContainerAdapter + implements ContextContainerTools.Adapter<OrmPersistentAttribute, XmlAttributeMapping> + { + public Iterable<OrmPersistentAttribute> getContextElements() { + return SpecifiedOrmPersistentType.this.getSpecifiedAttributes(); + } + public Iterable<XmlAttributeMapping> getResourceElements() { + return SpecifiedOrmPersistentType.this.getXmlAttributeMappings(); + } + public XmlAttributeMapping getResourceElement(OrmPersistentAttribute contextElement) { + return contextElement.getMapping().getXmlAttributeMapping(); + } + public void moveContextElement(int index, OrmPersistentAttribute element) { + SpecifiedOrmPersistentType.this.moveSpecifiedAttribute_(index, element); + } + public void addContextElement(int index, XmlAttributeMapping resourceElement) { + SpecifiedOrmPersistentType.this.addSpecifiedAttribute_(index, resourceElement); + } + public void removeContextElement(OrmPersistentAttribute element) { + SpecifiedOrmPersistentType.this.removeSpecifiedAttribute_(element); + } + } + + + // ********** virtual attributes ********** + + public ListIterable<OrmReadOnlyPersistentAttribute> getVirtualAttributes() { + return new LiveCloneListIterable<OrmReadOnlyPersistentAttribute>(this.virtualAttributes); + } + + public int getVirtualAttributesSize() { + return this.virtualAttributes.size(); + } + + /** + * 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 updateVirtualAttributes() { + if (getVirtualJavaAccess() == AccessType.FIELD) { + this.syncFieldAccessVirtualAttributes(); + } + else if (getVirtualJavaAccess() == AccessType.PROPERTY) { + this.syncPropertyAccessVirtualAttributes(); + } + } + + /** + * Initialize the attributes for AccessType.FIELD + * 1. all non-transient, non-static fields + * 2. all annotated methods(getters/setters) + */ + private void syncFieldAccessVirtualAttributes() { + HashSet<OrmReadOnlyPersistentAttribute> contextAttributes = CollectionTools.set(this.getVirtualAttributes()); + + this.syncFieldVirtualAttributes(contextAttributes, buildNonTransientNonStaticResourceFieldsFilter()); + if (!getMapping().isMetadataComplete()) { + this.syncAnnotatedPropertyVirtualAttributes(contextAttributes); + } + + // remove any leftover context attributes + for (OrmReadOnlyPersistentAttribute contextAttribute : contextAttributes) { + this.removeVirtualAttribute(contextAttribute); + } + } + + /** + * Initialize the attributes for XmlAccessType.PROPERTY + * 1. all getter/setter javabeans pairs + * 2. all annotated fields + * 3. all annotated methods getters/setters that don't have a matching pair + */ + private void syncPropertyAccessVirtualAttributes() { + HashSet<OrmReadOnlyPersistentAttribute> contextAttributes = CollectionTools.set(this.getVirtualAttributes()); + + if (!getMapping().isMetadataComplete()) { + this.syncFieldVirtualAttributes(contextAttributes, AbstractJavaPersistentType.ANNOTATED_RESOURCE_FIELDS_FILTER); + } + + Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getJavaResourceMethods()); + //iterate through all resource methods searching for persistable getters + for (JavaResourceMethod getterMethod : this.getJavaResourceMethods(this.buildPersistablePropertyGetterMethodsFilter())) { + JavaResourceMethod setterMethod = AbstractJavaPersistentType.getValidSiblingSetMethod(getterMethod, resourceMethods); + if (javaResourcePropertyIsVirtual(getterMethod, setterMethod)) { + if (AbstractJavaPersistentType.methodsArePersistableProperties(getterMethod, setterMethod)) { + boolean match = false; + for (Iterator<OrmReadOnlyPersistentAttribute> stream = contextAttributes.iterator(); stream.hasNext();) { + OrmReadOnlyPersistentAttribute contextAttribute = stream.next(); + if (contextAttribute.isFor(getterMethod, setterMethod)) { + match = true; + contextAttribute.update(); + stream.remove(); + break; + } + } + if (!match) { + this.addVirtualAttribute(getVirtualAttributesSize(), this.buildVirtualAttribute(getterMethod, setterMethod)); + } + } + } + resourceMethods.remove(getterMethod); + resourceMethods.remove(setterMethod); + } + this.syncRemainingResourceVirtualMethods(contextAttributes, resourceMethods); + + // remove any leftover context attributes + for (OrmReadOnlyPersistentAttribute contextAttribute : contextAttributes) { + this.removeVirtualAttribute(contextAttribute); + } + } + + private void syncAnnotatedPropertyVirtualAttributes(HashSet<OrmReadOnlyPersistentAttribute> contextAttributes) { + Collection<JavaResourceMethod> resourceMethods = CollectionTools.collection(this.getJavaResourceMethods()); + //iterate through all resource methods searching for persistable getters + for (JavaResourceMethod getterMethod : this.getJavaResourceMethods(buildPersistablePropertyGetterMethodsFilter())) { + JavaResourceMethod setterMethod = AbstractJavaPersistentType.getValidSiblingSetMethod(getterMethod, resourceMethods); + if (javaResourcePropertyIsVirtual(getterMethod, setterMethod)) { + if (getterMethod.isAnnotated() || (setterMethod != null && setterMethod.isAnnotated())) { + boolean match = false; + for (Iterator<OrmReadOnlyPersistentAttribute> stream = contextAttributes.iterator(); stream.hasNext();) { + OrmReadOnlyPersistentAttribute contextAttribute = stream.next(); + if (contextAttribute.isFor(getterMethod, setterMethod)) { + match = true; + contextAttribute.update(); + stream.remove(); + break; + } + } + if (!match) { + this.addVirtualAttribute(getVirtualAttributesSize(), this.buildVirtualAttribute(getterMethod, setterMethod)); + } + } + } + resourceMethods.remove(getterMethod); + resourceMethods.remove(setterMethod); + } + this.syncRemainingResourceVirtualMethods(contextAttributes, resourceMethods); + } + + private void syncFieldVirtualAttributes(HashSet<OrmReadOnlyPersistentAttribute> contextAttributes, Filter<JavaResourceField> filter) { + for (JavaResourceField resourceField : this.getVirtualJavaResourceFields(filter)) { + boolean match = false; + for (Iterator<OrmReadOnlyPersistentAttribute> stream = contextAttributes.iterator(); stream.hasNext(); ) { + OrmReadOnlyPersistentAttribute contextAttribute = stream.next(); + if (contextAttribute.isFor(resourceField)) { + match = true; + contextAttribute.update(); + stream.remove(); + break; + } + } + if (!match) { + // added elements are sync'ed during construction or will be + // updated during the next "update" (which is triggered by + // their addition to the model) + this.addVirtualAttribute(this.getVirtualAttributesSize(), this.buildVirtualAttribute(resourceField)); + } + } + } + + private void syncRemainingResourceVirtualMethods(HashSet<OrmReadOnlyPersistentAttribute> contextAttributes, Collection<JavaResourceMethod> resourceMethods) { + //iterate through remaining resource methods and search for those that are annotated. + //all getter methods will already be used. + for (JavaResourceMethod resourceMethod : resourceMethods) { + if (resourceMethod.isAnnotated()) { + boolean match = false; + //annotated setter(or other random method) with no corresponding getter, bring into context model for validation purposes + for (Iterator<OrmReadOnlyPersistentAttribute> stream = contextAttributes.iterator(); stream.hasNext();) { + OrmReadOnlyPersistentAttribute contextAttribute = stream.next(); + if (contextAttribute.isFor(null, resourceMethod)) { + match = true; + contextAttribute.update(); + stream.remove(); + break; + } + } + if (!match) { + this.addVirtualAttribute(getVirtualAttributesSize(), this.buildVirtualAttribute(null, resourceMethod)); + } + } + } + } + + /** + * Return all the Java resource fields that do not have a + * corresponding <code>orm.xml</code> mapping currently + * specified in the <code>orm.xml</code> persistent type. + */ + protected Iterable<JavaResourceField> getVirtualJavaResourceFields() { + return new FilteringIterable<JavaResourceField>(this.getJavaResourceFields()) { + @Override + protected boolean accept(JavaResourceField javaResourceField) { + return SpecifiedOrmPersistentType.this.javaResourceFieldIsVirtual(javaResourceField); + } + }; + } + + protected Iterable<JavaResourceField> getJavaResourceFields() { + JavaResourceType javaResourceType = this.getJavaResourceType(); + if (javaResourceType == null) { + return EmptyListIterable.instance(); + } + return javaResourceType.getFields(); + } + + protected Iterable<JavaResourceField> getVirtualJavaResourceFields(Filter<JavaResourceField> filter) { + return new FilteringIterable<JavaResourceField>(getVirtualJavaResourceFields(), filter); + } + + protected Iterable<JavaResourceMethod> getJavaResourceMethods(Filter<JavaResourceMethod> filter) { + return new FilteringIterable<JavaResourceMethod>(getJavaResourceMethods(), filter); + } + + protected Iterable<JavaResourceMethod> getJavaResourceMethods() { + JavaResourceType javaResourceType = this.getJavaResourceType(); + if (javaResourceType == null) { + return EmptyListIterable.instance(); + } + return javaResourceType.getMethods(); + } + + public static Filter<JavaResourceField> buildNonTransientNonStaticResourceFieldsFilter() { + return AbstractJavaPersistentType.buildNonTransientNonStaticResourceFieldsFilter(); + } + + protected Filter<JavaResourceMethod> buildPersistablePropertyGetterMethodsFilter() { + return new Filter<JavaResourceMethod>() { + public boolean accept(JavaResourceMethod resourceMethod) { + return AbstractJavaPersistentType.methodIsPersistablePropertyGetter(resourceMethod, getJavaResourceMethods()); + } + }; + } + + protected JavaResourceType getJavaResourceType() { + return (this.javaPersistentType == null) ? null : this.javaPersistentType.getJavaResourceType(); + } + + /** + * Return the access type that determines which Java attributes are to be + * used for the <code>orm.xml</code> type's <em>virtual</em> attributes. + */ + protected AccessType getVirtualJavaAccess() { + if (this.specifiedAccess != null) { + return this.specifiedAccess; + } + if (this.mapping.isMetadataComplete()) { + return this.defaultAccess; + } + AccessType javaAccess = this.javaPersistentType == null ? null : this.javaPersistentType.getSpecifiedAccess(); + return (javaAccess != null) ? javaAccess : this.defaultAccess; + } + + protected boolean javaResourceFieldIsVirtual(JavaResourceField javaResourceField) { + return this.getSpecifiedAttributeFor(javaResourceField) == null; + } + + protected OrmPersistentAttribute getSpecifiedAttributeFor(JavaResourceField javaResourceField) { + return this.getSpecifiedAttributeFor(javaResourceField, null); + } + + /** + * Return the specified attribute corresponding to the specified Java + * resource field, ignoring the specified excluded attribute (since + * there can be more than one specified attribute per Java resource + * attribute; albeit erroneously). + */ + protected OrmPersistentAttribute getSpecifiedAttributeFor(JavaResourceField javaResourceField, OrmPersistentAttribute exclude) { + for (OrmPersistentAttribute ormAttribute : this.getSpecifiedAttributes()) { + if (ormAttribute == exclude) { + continue; // skip + } + if (ormAttribute.isFor(javaResourceField)) { + return ormAttribute; + } + } + return null; + } + + protected boolean javaResourcePropertyIsVirtual(JavaResourceMethod javaResourceGetter, JavaResourceMethod javaResourceSetter) { + return this.getSpecifiedAttributeFor(javaResourceGetter, javaResourceSetter) == null; + } + + protected OrmPersistentAttribute getSpecifiedAttributeFor(JavaResourceMethod javaResourceGetter, JavaResourceMethod javaResourceSetter) { + return this.getSpecifiedAttributeFor(javaResourceGetter, javaResourceSetter, null); + } + + /** + * Return the specified attribute corresponding to the specified Java + * resource field, ignoring the specified excluded attribute (since + * there can be more than one specified attribute per Java resource + * attribute; albeit erroneously). + */ + protected OrmPersistentAttribute getSpecifiedAttributeFor(JavaResourceMethod javaResourceGetter, JavaResourceMethod javaResourceSetter, OrmPersistentAttribute exclude) { + for (OrmPersistentAttribute ormAttribute : this.getSpecifiedAttributes()) { + if (ormAttribute == exclude) { + continue; // skip + } + if (ormAttribute.isFor(javaResourceGetter, javaResourceSetter)) { + return ormAttribute; + } + } + return null; + } + + protected void moveVirtualAttribute(int index, OrmReadOnlyPersistentAttribute virtualAttribute) { + this.moveItemInList(index, virtualAttribute, this.virtualAttributes, VIRTUAL_ATTRIBUTES_LIST); + } + + protected void addVirtualAttribute(int index, OrmReadOnlyPersistentAttribute virtualAttribute) { + this.addItemToList(index, virtualAttribute, this.virtualAttributes, VIRTUAL_ATTRIBUTES_LIST); + } + + protected OrmReadOnlyPersistentAttribute buildVirtualAttribute(JavaResourceField javaResourceField) { + return this.getContextNodeFactory().buildVirtualOrmPersistentField(this, javaResourceField); + } + + protected OrmReadOnlyPersistentAttribute buildVirtualAttribute(JavaResourceMethod javaResourceGetter, JavaResourceMethod javaResourceSetter) { + return this.getContextNodeFactory().buildVirtualOrmPersistentProperty(this, javaResourceGetter, javaResourceSetter); + } + + protected void removeVirtualAttribute(OrmReadOnlyPersistentAttribute virtualAttribute) { + virtualAttribute.dispose(); + this.removeItemFromList(virtualAttribute, this.virtualAttributes, VIRTUAL_ATTRIBUTES_LIST); + } + + + // ********** super persistent type ********** + + public PersistentType getSuperPersistentType() { + return this.superPersistentType; + } + + protected void setSuperPersistentType(PersistentType persistentType) { + PersistentType old = this.superPersistentType; + this.superPersistentType = persistentType; + this.firePropertyChanged(SUPER_PERSISTENT_TYPE_PROPERTY, old, persistentType); + } + + protected PersistentType buildSuperPersistentType() { + PersistentType spt = this.buildSuperPersistentType_(); + if (spt == null) { + return null; + } + // check for circular inheritance + return CollectionTools.contains(spt.getInheritanceHierarchy(), this) ? null : spt; + } + + protected PersistentType buildSuperPersistentType_() { + return (this.javaPersistentType == null) ? null : this.javaPersistentType.getSuperPersistentType(); + } + + + // ********** inheritance ********** + + public Iterable<PersistentType> getInheritanceHierarchy() { + return this.getInheritanceHierarchyOf(this); + } + + 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(); + } + }; + } + + + // ********** declaring type name ********** + + public String getDeclaringTypeName() { + return this.declaringTypeName; + } + + protected void setDeclaringTypeName(String name) { + String old = this.declaringTypeName; + this.declaringTypeName = name; + this.firePropertyChanged(DECLARING_TYPE_NAME_PROPERTY, old, name); + } + + protected String buildDeclaringTypeName() { + return this.isJpa2_0Compatible() ? this.buildDeclaringTypeName_() : null; + } + + protected String buildDeclaringTypeName_() { + return (this.javaPersistentType == null) ? + null : ((JavaPersistentType2_0) this.javaPersistentType).getDeclaringTypeName(); + } + + + // ********** metamodel ********** + + protected MetamodelSourceType.Synchronizer buildMetamodelSynchronizer() { + return this.isJpa2_0Compatible() ? + this.getJpaFactory2_0().buildMetamodelSynchronizer(this) : + null; + } + + public IFile getMetamodelFile() { + return (this.javaPersistentType == null) ? null : this.metamodelSynchronizer.getFile(); + } + + public void initializeMetamodel() { + // do nothing - probably shouldn't be called... + } + + public boolean isManaged() { + return true; + } + + /** + * All <code>orm.xml</code> persistent types must be able to generate a static metamodel + * because 1.0 <code>orm.xml</code> files can be referenced from 2.0 persistence.xml files. + */ + public void synchronizeMetamodel(Map<String, Collection<MetamodelSourceType>> memberTypeTree) { + if (this.javaPersistentType != null) { + this.metamodelSynchronizer.synchronize(memberTypeTree); + } + } + + public void printBodySourceOn(BodySourceWriter pw, Map<String, Collection<MetamodelSourceType>> memberTypeTree) { + if (this.javaPersistentType != null) { + this.metamodelSynchronizer.printBodySourceOn(pw, memberTypeTree); + } + } + + public void disposeMetamodel() { + // do nothing - probably shouldn't be called... + } + + + // ********** JpaStructureNode implementation ********** + + public String getId() { + return OrmStructureNodes.PERSISTENT_TYPE_ID; + } + + public JpaStructureNode getStructureNode(int textOffset) { + for (OrmPersistentAttribute attribute : this.getSpecifiedAttributes()) { + if (attribute.contains(textOffset)) { + return attribute; + } + } + return this; + } + + public TextRange getSelectionTextRange() { + return this.mapping.getSelectionTextRange(); + } + + public void dispose() { + if (this.javaPersistentType != null) { + this.javaPersistentType.dispose(); + } + for (OrmReadOnlyPersistentAttribute virtualAttribute : this.getVirtualAttributes()) { + virtualAttribute.dispose(); + } + } + + + // ********** PersistentType.Owner implementation ********** + + public AccessType getOverridePersistentTypeAccess() { + if (this.specifiedAccess != null) { + return this.specifiedAccess; + } + + if (this.superPersistentType instanceof OrmPersistentType) { + AccessType accessType = ((OrmPersistentType) this.superPersistentType).getSpecifiedAccess(); + if (accessType != null) { + return accessType; + } + } + + if (this.mapping.isMetadataComplete()) { + AccessType accessType = this.getOwnerDefaultAccess(); + if (accessType != null) { + return accessType; + } + } + + // no override access type + return null; + } + + public AccessType getDefaultPersistentTypeAccess() { + if (this.superPersistentType instanceof OrmPersistentType) { + AccessType accessType = ((OrmPersistentType) this.superPersistentType).getDefaultAccess(); + if (accessType != null) { + return accessType; + } + } + + return this.getOwnerDefaultAccess(); + } + + + //*********** refactoring *********** + + public Iterable<DeleteEdit> createDeleteTypeEdits(IType type) { + return this.isFor(type.getFullyQualifiedName('.')) ? + new SingleElementIterable<DeleteEdit>(this.mapping.createDeleteEdit()) : + EmptyIterable.<DeleteEdit>instance(); + } + + @SuppressWarnings("unchecked") + public Iterable<ReplaceEdit> createRenameTypeEdits(IType originalType, String newName) { + return new CompositeIterable<ReplaceEdit>( + this.mapping.createRenameTypeEdits(originalType, newName), + this.createSpecifiedAttributesRenameTypeEdits(originalType, newName) + ); + } + + protected Iterable<ReplaceEdit> createSpecifiedAttributesRenameTypeEdits(final IType originalType, final String newName) { + return new CompositeIterable<ReplaceEdit>( + new TransformationIterable<OrmPersistentAttribute, Iterable<ReplaceEdit>>(this.getSpecifiedAttributes()) { + @Override + protected Iterable<ReplaceEdit> transform(OrmPersistentAttribute persistentAttribute) { + return persistentAttribute.createRenameTypeEdits(originalType, newName); + } + } + ); + } + + @SuppressWarnings("unchecked") + public Iterable<ReplaceEdit> createMoveTypeEdits(IType originalType, IPackageFragment newPackage) { + return new CompositeIterable<ReplaceEdit>( + this.mapping.createMoveTypeEdits(originalType, newPackage), + this.createSpecifiedAttributesMoveTypeEdits(originalType, newPackage) + ); + } + + protected Iterable<ReplaceEdit> createSpecifiedAttributesMoveTypeEdits(final IType originalType, final IPackageFragment newPackage) { + return new CompositeIterable<ReplaceEdit>( + new TransformationIterable<OrmPersistentAttribute, Iterable<ReplaceEdit>>(this.getSpecifiedAttributes()) { + @Override + protected Iterable<ReplaceEdit> transform(OrmPersistentAttribute persistentAttribute) { + return persistentAttribute.createMoveTypeEdits(originalType, newPackage); + } + } + ); + } + + @SuppressWarnings("unchecked") + public Iterable<ReplaceEdit> createRenamePackageEdits(IPackageFragment originalPackage, String newName) { + return new CompositeIterable<ReplaceEdit>( + this.mapping.createRenamePackageEdits(originalPackage, newName), + this.createSpecifiedAttributesRenamePackageEdits(originalPackage, newName) + ); + } + + protected Iterable<ReplaceEdit> createSpecifiedAttributesRenamePackageEdits(final IPackageFragment originalPackage, final String newName) { + return new CompositeIterable<ReplaceEdit>( + new TransformationIterable<OrmPersistentAttribute, Iterable<ReplaceEdit>>(this.getSpecifiedAttributes()) { + @Override + protected Iterable<ReplaceEdit> transform(OrmPersistentAttribute persistentAttribute) { + return persistentAttribute.createRenamePackageEdits(originalPackage, newName); + } + } + ); + } + + + // ********** validation ********** + + @Override + public void validate(List<IMessage> messages, IReporter reporter) { + super.validate(messages, reporter); + this.validateClass(messages); + this.validateMapping(messages, reporter); + this.validateAttributes(messages, reporter); + } + + protected void validateClass(List<IMessage> messages) { + if (this.javaPersistentType == null) { + messages.add( + DefaultJpaValidationMessages.buildMessage( + IMessage.HIGH_SEVERITY, + JpaValidationMessages.PERSISTENT_TYPE_UNRESOLVED_CLASS, + new String[] {this.getName()}, + this, + this.mapping.getClassTextRange() + ) + ); + } + } + + protected void validateMapping(List<IMessage> messages, IReporter reporter) { + try { + this.mapping.validate(messages, reporter); + } catch(Throwable t) { + JptJpaCorePlugin.log(t); + } + } + + protected void validateAttributes(List<IMessage> messages, IReporter reporter) { + for (OrmReadOnlyPersistentAttribute attribute : this.getAttributes()) { + this.validateAttribute(attribute, messages, reporter); + } + } + + protected void validateAttribute(OrmReadOnlyPersistentAttribute attribute, List<IMessage> messages, IReporter reporter) { + try { + attribute.validate(messages, reporter); + } catch(Throwable t) { + JptJpaCorePlugin.log(t); + } + } + + public TextRange getValidationTextRange() { + return this.mapping.getValidationTextRange(); + } + + + // ********** misc ********** + + @Override + public EntityMappings getParent() { + return (EntityMappings) super.getParent(); + } + + protected EntityMappings getEntityMappings() { + return this.getParent(); + } + + public String getDefaultPackage() { + return this.getEntityMappings().getPackage(); + } + + public boolean isFor(String typeName) { + String name = this.getName(); + if (name == null) { + return false; + } + if (name.equals(typeName)) { + return true; + } + String defaultPackage = this.getDefaultPackage(); + if (defaultPackage == null) { + return false; + } + return (defaultPackage + '.' + name).equals(typeName); + } + + public boolean isIn(IPackageFragment packageFragment) { + String packageName = this.getPackageName(); + if (Tools.valuesAreEqual(packageName, packageFragment.getElementName())) { + return true; + } + String defaultPackage = this.getDefaultPackage(); + if (defaultPackage == null) { + return false; + } + packageName = (packageName == null) ? defaultPackage : defaultPackage + '.' + packageName; + return packageName.equals(packageFragment.getElementName()); + } + + protected String getPackageName() { + String className = this.getName(); + if (className == null) { + return null; + } + int lastPeriod = className.lastIndexOf('.'); + return (lastPeriod == -1) ? null : className.substring(0, lastPeriod); + } + + public boolean contains(int textOffset) { + return this.mapping.containsOffset(textOffset); + } + + public PersistentType getOverriddenPersistentType() { + return this.mapping.isMetadataComplete() ? null : this.javaPersistentType; + } + + @Override + public void toString(StringBuilder sb) { + sb.append(this.getName()); + } +} |