blob: d9561d100df1677f6be2fb1f3c724cc168e8a20a [file] [log] [blame]
/*******************************************************************************
* 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.core.internal.jpa1.context.orm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
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.jpt.core.JpaStructureNode;
import org.eclipse.jpt.core.JptCorePlugin;
import org.eclipse.jpt.core.MappingKeys;
import org.eclipse.jpt.core.context.AccessType;
import org.eclipse.jpt.core.context.PersistentAttribute;
import org.eclipse.jpt.core.context.PersistentType;
import org.eclipse.jpt.core.context.java.JavaAttributeMapping;
import org.eclipse.jpt.core.context.java.JavaPersistentAttribute;
import org.eclipse.jpt.core.context.java.JavaPersistentType;
import org.eclipse.jpt.core.context.orm.EntityMappings;
import org.eclipse.jpt.core.context.orm.OrmAttributeMapping;
import org.eclipse.jpt.core.context.orm.OrmAttributeMappingDefinition;
import org.eclipse.jpt.core.context.orm.OrmPersistentAttribute;
import org.eclipse.jpt.core.context.orm.OrmPersistentType;
import org.eclipse.jpt.core.context.orm.OrmStructureNodes;
import org.eclipse.jpt.core.context.orm.OrmTypeMapping;
import org.eclipse.jpt.core.context.orm.OrmTypeMappingDefinition;
import org.eclipse.jpt.core.internal.context.orm.AbstractOrmXmlContextNode;
import org.eclipse.jpt.core.internal.validation.DefaultJpaValidationMessages;
import org.eclipse.jpt.core.internal.validation.JpaValidationMessages;
import org.eclipse.jpt.core.jpa2.JpaFactory2_0;
import org.eclipse.jpt.core.jpa2.context.PersistentType2_0;
import org.eclipse.jpt.core.jpa2.context.orm.OrmPersistentType2_0;
import org.eclipse.jpt.core.resource.java.JavaResourcePersistentAttribute;
import org.eclipse.jpt.core.resource.java.JavaResourcePersistentType;
import org.eclipse.jpt.core.resource.orm.Attributes;
import org.eclipse.jpt.core.resource.orm.OrmPackage;
import org.eclipse.jpt.core.resource.orm.XmlAttributeMapping;
import org.eclipse.jpt.core.resource.orm.XmlTypeMapping;
import org.eclipse.jpt.core.resource.xml.EmfTools;
import org.eclipse.jpt.core.utility.TextRange;
import org.eclipse.jpt.utility.internal.ClassName;
import org.eclipse.jpt.utility.internal.CollectionTools;
import org.eclipse.jpt.utility.internal.StringTools;
import org.eclipse.jpt.utility.internal.Tools;
import org.eclipse.jpt.utility.internal.iterables.CompositeIterable;
import org.eclipse.jpt.utility.internal.iterables.LiveCloneIterable;
import org.eclipse.jpt.utility.internal.iterators.ChainIterator;
import org.eclipse.jpt.utility.internal.iterators.CloneListIterator;
import org.eclipse.jpt.utility.internal.iterators.CompositeIterator;
import org.eclipse.jpt.utility.internal.iterators.CompositeListIterator;
import org.eclipse.jpt.utility.internal.iterators.EmptyListIterator;
import org.eclipse.jpt.utility.internal.iterators.FilteringIterator;
import org.eclipse.jpt.utility.internal.iterators.TransformationIterator;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
import org.eclipse.wst.validation.internal.provisional.core.IReporter;
/**
* ORM persistent type:<ul>
* <li>mapping
* <li>access
* <li>attributes
* <li>super persistent type
* <li>Java persistent type
* </ul>
*/
public class GenericOrmPersistentType
extends AbstractOrmXmlContextNode
implements OrmPersistentType2_0
{
protected OrmTypeMapping mapping;
protected AccessType defaultAccess;
protected AccessType specifiedAccess;
protected final Vector<OrmPersistentAttribute> specifiedAttributes = new Vector<OrmPersistentAttribute>();
protected final Vector<OrmPersistentAttribute> virtualAttributes = new Vector<OrmPersistentAttribute>();
protected PersistentType superPersistentType;
protected JavaPersistentType javaPersistentType;
protected final PersistentType2_0.MetamodelSynchronizer metamodelSynchronizer;
public GenericOrmPersistentType(EntityMappings parent, XmlTypeMapping resourceMapping) {
super(parent);
this.mapping = this.buildMapping(resourceMapping);
this.specifiedAccess = this.buildSpecifiedAccess();
this.defaultAccess = this.buildDefaultAccess();
this.javaPersistentType = this.buildJavaPersistentType();
this.superPersistentType = this.buildSuperPersistentType();
this.initializeAttributes();
this.metamodelSynchronizer = this.buildMetamodelSynchronizer();
}
protected PersistentType2_0.MetamodelSynchronizer buildMetamodelSynchronizer() {
return ((JpaFactory2_0) this.getJpaFactory()).buildPersistentTypeMetamodelSynchronizer(this);
}
// ********** update **********
public void update() {
this.setSpecifiedAccess(this.buildSpecifiedAccess());
this.setDefaultAccess(this.buildDefaultAccess());
this.mapping.update();
this.updateJavaPersistentType();
this.updateSuperPersistentType();
this.updateAttributes();
}
@Override
public void postUpdate() {
super.postUpdate();
if (this.javaPersistentType != null) {
this.javaPersistentType.postUpdate();
}
this.mapping.postUpdate();
for (PersistentAttribute attribute : this.getAttributes()) {
attribute.postUpdate();
}
}
// ********** name **********
public String getName() {
return this.mapping.getClass_();
}
public String getShortName(){
String className = this.getName();
return StringTools.stringIsEmpty(className) ? null : ClassName.getSimpleName(className);
}
// ********** mapping **********
public OrmTypeMapping getMapping() {
return this.mapping;
}
public void setMappingKey(String newMappingKey) {
if (this.valuesAreEqual(this.getMappingKey(), newMappingKey)) {
return;
}
OrmTypeMapping oldMapping = this.mapping;
OrmTypeMappingDefinition mappingDefinition = this.getMappingFileDefinition().getOrmTypeMappingDefinition(newMappingKey);
XmlTypeMapping resourceTypeMapping = mappingDefinition.buildResourceMapping(this.getResourceNodeFactory());
this.mapping = this.buildMapping(resourceTypeMapping);
this.getEntityMappings().changeMapping(this, oldMapping, this.mapping);
this.firePropertyChanged(MAPPING_PROPERTY, oldMapping, this.mapping);
}
protected OrmTypeMapping buildMapping(XmlTypeMapping resourceMapping) {
OrmTypeMappingDefinition mappingDefintion = this.getMappingFileDefinition().getOrmTypeMappingDefinition(resourceMapping.getMappingKey());
return mappingDefintion.buildContextMapping(this, resourceMapping, this.getXmlContextNodeFactory());
}
// ********** access **********
public AccessType getAccess() {
return (this.specifiedAccess != null) ? this.specifiedAccess : this.defaultAccess;
}
public AccessType getDefaultAccess() {
return this.defaultAccess;
}
protected void setDefaultAccess(AccessType defaultAccess) {
AccessType old = this.defaultAccess;
this.defaultAccess = defaultAccess;
this.firePropertyChanged(DEFAULT_ACCESS_PROPERTY, old, defaultAccess);
}
public AccessType getSpecifiedAccess() {
return this.specifiedAccess;
}
public void setSpecifiedAccess(AccessType specifiedAccess) {
AccessType old = this.specifiedAccess;
this.specifiedAccess = specifiedAccess;
this.getResourceTypeMapping().setAccess(AccessType.toOrmResourceModel(specifiedAccess));
this.firePropertyChanged(SPECIFIED_ACCESS_PROPERTY, old, specifiedAccess);
}
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
}
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();
}
protected AccessType buildSpecifiedAccess() {
return AccessType.fromOrmResourceModel(this.getResourceTypeMapping().getAccess());
}
// ********** attributes **********
@SuppressWarnings("unchecked")
public ListIterator<OrmPersistentAttribute> attributes() {
return new CompositeListIterator<OrmPersistentAttribute>(this.specifiedAttributes(), this.virtualAttributes());
}
@SuppressWarnings("unchecked")
protected Iterable<OrmPersistentAttribute> getAttributes() {
return new CompositeIterable<OrmPersistentAttribute>(this.getSpecifiedAttributes(), this.getVirtualAttributes());
}
public int attributesSize() {
return this.specifiedAttributesSize() + this.virtualAttributesSize();
}
public Iterator<String> allAttributeNames() {
return this.attributeNames(this.allAttributes());
}
public Iterator<PersistentAttribute> allAttributes() {
return new CompositeIterator<PersistentAttribute>(
new TransformationIterator<PersistentType, Iterator<PersistentAttribute>>(this.inheritanceHierarchy()) {
@Override
protected Iterator<PersistentAttribute> transform(PersistentType pt) {
return pt.attributes();
}
}
);
}
protected Iterator<OrmPersistentAttribute> attributesNamed(final String attributeName) {
return new FilteringIterator<OrmPersistentAttribute>(this.attributes()) {
@Override
protected boolean accept(OrmPersistentAttribute o) {
return Tools.valuesAreEqual(attributeName, o.getName());
}
};
}
public OrmPersistentAttribute getAttributeNamed(String attributeName) {
Iterator<OrmPersistentAttribute> stream = this.attributesNamed(attributeName);
return (stream.hasNext()) ? stream.next() : null;
}
public PersistentAttribute resolveAttribute(String attributeName) {
Iterator<OrmPersistentAttribute> attributes = this.attributesNamed(attributeName);
if (attributes.hasNext()) {
OrmPersistentAttribute attribute = attributes.next();
return attributes.hasNext() ? null /* more than one */: attribute;
}
return (this.superPersistentType == null) ? null : this.superPersistentType.resolveAttribute(attributeName);
}
public Iterator<String> attributeNames() {
return this.attributeNames(this.attributes());
}
protected Iterator<String> attributeNames(Iterator<? extends PersistentAttribute> attrs) {
return new TransformationIterator<PersistentAttribute, String>(attrs) {
@Override
protected String transform(PersistentAttribute attribute) {
return attribute.getName();
}
};
}
protected void initializeAttributes() {
this.initializeSpecifiedAttributes();
this.initializeVirtualAttributes();
}
protected void updateAttributes() {
this.updateSpecifiedAttributes();
this.updateVirtualAttributes();
}
protected Iterator<JavaResourcePersistentAttribute> javaPersistentAttributes() {
return (this.javaPersistentType == null) ?
EmptyListIterator.<JavaResourcePersistentAttribute>instance() :
this.javaPersistentAttributes(this.javaPersistentType.getResourcePersistentType());
}
protected Iterator<JavaResourcePersistentAttribute> javaPersistentAttributes(JavaResourcePersistentType resourcePersistentType) {
AccessType access = this.specifiedAccess;
if (access == null && ! this.mapping.isMetadataComplete()) {
access = this.getJavaPersistentType().getSpecifiedAccess();
}
if (access == null) {
access = this.defaultAccess;
}
return resourcePersistentType.persistableAttributes(AccessType.toJavaResourceModel(access));
}
// ********** specified attributes **********
public ListIterator<OrmPersistentAttribute> specifiedAttributes() {
return new CloneListIterator<OrmPersistentAttribute>(this.specifiedAttributes);
}
protected Iterable<OrmPersistentAttribute> getSpecifiedAttributes() {
return new LiveCloneIterable<OrmPersistentAttribute>(this.specifiedAttributes);
}
public int specifiedAttributesSize() {
return this.specifiedAttributes.size();
}
protected OrmPersistentAttribute getSpecifiedAttributeFor(final JavaResourcePersistentAttribute jrpa) {
for (OrmPersistentAttribute attribute : this.getSpecifiedAttributes()) {
JavaPersistentAttribute javaAttribute = attribute.getJavaPersistentAttribute();
if ((javaAttribute != null) && (javaAttribute.getResourcePersistentAttribute() == jrpa)) {
return attribute;
}
}
return null;
}
public OrmPersistentAttribute addSpecifiedAttribute(String mappingKey, String attributeName) {
Attributes resourceAttributes = this.getResourceAttributes();
if (resourceAttributes == null) {
resourceAttributes = this.createResourceAttributes();
this.mapping.getResourceTypeMapping().setAttributes(resourceAttributes);
}
OrmAttributeMappingDefinition mappingDefintion = this.getMappingFileDefinition().getOrmAttributeMappingDefinition(mappingKey);
XmlAttributeMapping resourceMapping = mappingDefintion.buildResourceMapping(getResourceNodeFactory());
OrmPersistentAttribute persistentAttribute = this.buildSpecifiedAttribute(resourceMapping);
int index = this.getSpecifiedAttributeInsertionIndex(persistentAttribute);
this.specifiedAttributes.add(index, persistentAttribute);
persistentAttribute.getMapping().addToResourceModel(resourceAttributes);
persistentAttribute.getSpecifiedMapping().setName(attributeName);
this.fireItemAdded(ATTRIBUTES_LIST, index, persistentAttribute);
return persistentAttribute;
}
public void changeMapping(OrmPersistentAttribute ormPersistentAttribute, OrmAttributeMapping oldMapping, OrmAttributeMapping newMapping) {
int sourceIndex = this.specifiedAttributes.indexOf(ormPersistentAttribute);
this.specifiedAttributes.remove(sourceIndex);
oldMapping.removeFromResourceModel(this.getResourceAttributes());
int targetIndex = getSpecifiedAttributeInsertionIndex(ormPersistentAttribute);
this.specifiedAttributes.add(targetIndex, ormPersistentAttribute);
newMapping.addToResourceModel(this.getResourceAttributes());
oldMapping.initializeOn(newMapping);
this.fireItemMoved(ATTRIBUTES_LIST, targetIndex, sourceIndex);
}
public void makeAttributeSpecified(OrmPersistentAttribute ormPersistentAttribute) {
this.makeAttributeSpecified(ormPersistentAttribute, ormPersistentAttribute.getMappingKey());
}
public void makeAttributeSpecified(OrmPersistentAttribute ormPersistentAttribute, String mappingKey) {
if ( ! ormPersistentAttribute.isVirtual()) {
throw new IllegalStateException("Attribute is already specified"); //$NON-NLS-1$
}
if (this.valuesAreEqual(mappingKey, MappingKeys.NULL_ATTRIBUTE_MAPPING_KEY)) {
throw new IllegalStateException("Use makePersistentAttributeSpecified(OrmPersistentAttribute, String) instead and specify a mapping type"); //$NON-NLS-1$
}
Attributes resourceAttributes = this.getResourceAttributes();
if (resourceAttributes == null) {
resourceAttributes = this.createResourceAttributes();
this.mapping.getResourceTypeMapping().setAttributes(resourceAttributes);
}
OrmAttributeMappingDefinition mappingDefintion = this.getMappingFileDefinition().getOrmAttributeMappingDefinition(mappingKey);
XmlAttributeMapping resourceMapping = mappingDefintion.buildResourceMapping(getResourceNodeFactory());
OrmPersistentAttribute newAttribute = this.buildSpecifiedAttribute(resourceMapping);
int insertionIndex = this.getSpecifiedAttributeInsertionIndex(newAttribute);
this.specifiedAttributes.add(insertionIndex, newAttribute);
newAttribute.getMapping().addToResourceModel(resourceAttributes);
int removalIndex = this.virtualAttributes.indexOf(ormPersistentAttribute);
this.virtualAttributes.remove(ormPersistentAttribute);
newAttribute.getSpecifiedMapping().setName(ormPersistentAttribute.getName());
if (ormPersistentAttribute.getJavaPersistentAttribute().getSpecifiedAccess() != null) {
newAttribute.setSpecifiedAccess(ormPersistentAttribute.getJavaPersistentAttribute().getSpecifiedAccess());
}
this.fireItemAdded(ATTRIBUTES_LIST, insertionIndex, newAttribute);
this.fireItemRemoved(VIRTUAL_ATTRIBUTES_LIST, removalIndex, ormPersistentAttribute);
}
protected int getSpecifiedAttributeInsertionIndex(OrmPersistentAttribute specifiedAttribute) {
return CollectionTools.insertionIndexOf(this.specifiedAttributes, specifiedAttribute, this.getAttributeComparator());
}
protected Comparator<OrmPersistentAttribute> getAttributeComparator() {
return ATTRIBUTE_COMPARATOR;
}
protected static final Comparator<OrmPersistentAttribute> ATTRIBUTE_COMPARATOR =
new Comparator<OrmPersistentAttribute>() {
public int compare(OrmPersistentAttribute o1, OrmPersistentAttribute o2) {
int o1Sequence = o1.getMapping().getXmlSequence();
int o2Sequence = o2.getMapping().getXmlSequence();
return (o1Sequence == o2Sequence) ? 0 : (o1Sequence < o2Sequence) ? -1 : 1;
}
};
protected Attributes getResourceAttributes() {
return this.getResourceTypeMapping().getAttributes();
}
protected Attributes createResourceAttributes() {
return EmfTools.create(this.getResourceNodeFactory(), OrmPackage.eINSTANCE.getAttributes(), Attributes.class);
}
protected void initializeSpecifiedAttributes() {
Attributes attributes = this.getResourceAttributes();
if (attributes == null) {
return;
}
for (XmlAttributeMapping resourceMapping : attributes.getAttributeMappings()) {
this.addSpecifiedAttribute(resourceMapping);
}
}
protected void updateSpecifiedAttributes() {
Attributes attributes = this.getResourceAttributes();
Collection<OrmPersistentAttribute> contextAttributesToRemove = CollectionTools.collection(this.specifiedAttributes());
Collection<OrmPersistentAttribute> contextAttributesToUpdate = new ArrayList<OrmPersistentAttribute>();
int resourceIndex = 0;
if (attributes != null) {
for (XmlAttributeMapping resourceMapping : attributes.getAttributeMappings()) {
boolean contextAttributeFound = false;
for (OrmPersistentAttribute contextAttribute : contextAttributesToRemove) {
if (contextAttribute.getMapping().getResourceAttributeMapping() == resourceMapping) {
this.moveSpecifiedAttribute_(resourceIndex, contextAttribute);
contextAttributesToRemove.remove(contextAttribute);
contextAttributesToUpdate.add(contextAttribute);
contextAttributeFound = true;
break;
}
}
if ( ! contextAttributeFound) {
OrmPersistentAttribute ormPersistentAttribute = this.addSpecifiedAttribute(resourceMapping);
this.fireItemAdded(ATTRIBUTES_LIST, specifiedAttributesSize(), ormPersistentAttribute);
}
resourceIndex++;
}
}
for (OrmPersistentAttribute contextAttribute : contextAttributesToRemove) {
this.removeSpecifiedAttribute_(contextAttribute);
}
//first handle adding/removing of the persistent attributes, then update the others last,
//this causes less churn in the update process
for (OrmPersistentAttribute contextAttribute : contextAttributesToUpdate) {
contextAttribute.update();
}
}
protected void removeSpecifiedAttribute_(OrmPersistentAttribute ormPersistentAttribute) {
this.removeItemFromList(ormPersistentAttribute, this.specifiedAttributes, ATTRIBUTES_LIST);
}
//not firing change notification so this can be reused in initialize and update
protected OrmPersistentAttribute addSpecifiedAttribute(XmlAttributeMapping resourceMapping) {
OrmPersistentAttribute ormPersistentAttribute = this.buildSpecifiedAttribute(resourceMapping);
this.specifiedAttributes.add(ormPersistentAttribute);
return ormPersistentAttribute;
}
protected void moveSpecifiedAttribute_(int index, OrmPersistentAttribute attribute) {
this.moveItemInList(index, this.specifiedAttributes.indexOf(attribute), this.specifiedAttributes, ATTRIBUTES_LIST);
}
public void removeSpecifiedAttribute(OrmPersistentAttribute ormPersistentAttribute) {
int index = this.specifiedAttributes.indexOf(ormPersistentAttribute);
this.specifiedAttributes.remove(ormPersistentAttribute);
ormPersistentAttribute.getMapping().removeFromResourceModel(this.getResourceAttributes());
if (this.getResourceAttributes().isUnset()) {
this.mapping.getResourceTypeMapping().setAttributes(null);
}
this.fireItemRemoved(ATTRIBUTES_LIST, index, ormPersistentAttribute);
}
protected OrmPersistentAttribute buildSpecifiedAttribute(XmlAttributeMapping resourceMapping) {
return this.buildOrmPersistentAttribute(this.buildSpecifiedAttributeOwner(), resourceMapping);
}
protected OrmPersistentAttribute.Owner buildSpecifiedAttributeOwner() {
return new SpecifiedAttributeOwner();
}
protected JavaPersistentAttribute buildJavaPersistentAttribute(JavaResourcePersistentAttribute jrpa) {
return this.getJpaFactory().buildJavaPersistentAttribute(this, jrpa);
}
// ********** virtual attributes **********
public ListIterator<OrmPersistentAttribute> virtualAttributes() {
return new CloneListIterator<OrmPersistentAttribute>(this.virtualAttributes);
}
protected Iterable<OrmPersistentAttribute> getVirtualAttributes() {
return new LiveCloneIterable<OrmPersistentAttribute>(this.virtualAttributes);
}
public int virtualAttributesSize() {
return this.virtualAttributes.size();
}
protected void addVirtualAttribute(OrmPersistentAttribute virtualAttribute) {
this.addItemToList(virtualAttribute, this.virtualAttributes, VIRTUAL_ATTRIBUTES_LIST);
}
protected void removeVirtualAttribute(OrmPersistentAttribute virtualAttribute) {
this.removeItemFromList(virtualAttribute, this.virtualAttributes, VIRTUAL_ATTRIBUTES_LIST);
}
protected void moveVirtualAttribute_(int index, OrmPersistentAttribute virtualAttribute) {
this.moveItemInList(index, this.virtualAttributes.indexOf(virtualAttribute), this.virtualAttributes, VIRTUAL_ATTRIBUTES_LIST);
}
public boolean containsVirtualAttribute(OrmPersistentAttribute ormPersistentAttribute) {
return this.virtualAttributes.contains(ormPersistentAttribute);
}
public void makeAttributeVirtual(OrmPersistentAttribute ormPersistentAttribute) {
if (ormPersistentAttribute.isVirtual()) {
throw new IllegalStateException("Attribute is already virtual"); //$NON-NLS-1$
}
JavaPersistentAttribute javaPersistentAttribute = ormPersistentAttribute.getJavaPersistentAttribute();
OrmPersistentAttribute virtualAttribute = null;
if (javaPersistentAttribute != null) {
virtualAttribute = this.addVirtualAttribute(javaPersistentAttribute.getResourcePersistentAttribute());
}
this.removeSpecifiedAttribute(ormPersistentAttribute);
if (virtualAttribute != null) {
this.fireItemAdded(VIRTUAL_ATTRIBUTES_LIST, virtualAttributesSize() - 1, virtualAttribute);
}
}
protected void initializeVirtualAttributes() {
for (Iterator<JavaResourcePersistentAttribute> stream = this.javaPersistentAttributes(); stream.hasNext(); ) {
JavaResourcePersistentAttribute javaResourceAttribute = stream.next();
if (this.getSpecifiedAttributeFor(javaResourceAttribute) == null) {
this.addVirtualAttribute(javaResourceAttribute);
}
}
}
protected void updateVirtualAttributes() {
Collection<OrmPersistentAttribute> contextAttributesToRemove = CollectionTools.collection(this.virtualAttributes());
Collection<OrmPersistentAttribute> contextAttributesToUpdate = new ArrayList<OrmPersistentAttribute>();
int resourceIndex = 0;
for (Iterator<JavaResourcePersistentAttribute> stream = this.javaPersistentAttributes(); stream.hasNext(); ) {
JavaResourcePersistentAttribute javaResourceAttribute = stream.next();
OrmPersistentAttribute specifiedAttribute = this.getSpecifiedAttributeFor(javaResourceAttribute);
if (specifiedAttribute == null) {
JavaPersistentAttribute javaAttribute = this.getJpaFactory().buildJavaPersistentAttribute(this, javaResourceAttribute);
JavaAttributeMapping javaAttributeMapping = javaAttribute.getMapping();
if (this.mapping.isMetadataComplete()) {
javaAttributeMapping = javaAttribute.getDefaultMapping();
}
boolean contextAttributeFound = false;
for (OrmPersistentAttribute contextAttribute : contextAttributesToRemove) {
JavaPersistentAttribute javaPersistentAttribute = contextAttribute.getJavaPersistentAttribute();
if (javaPersistentAttribute.getResourcePersistentAttribute() == javaResourceAttribute) {
if (this.valuesAreEqual(contextAttribute.getMappingKey(), javaAttributeMapping.getKey())) {
//the mapping key would change if metaDataComplete flag changes, rebuild the orm attribute
this.moveVirtualAttribute_(resourceIndex, contextAttribute);
contextAttributesToRemove.remove(contextAttribute);
contextAttributesToUpdate.add(contextAttribute);
contextAttributeFound = true;
break;
}
}
}
if ( ! contextAttributeFound) {
OrmPersistentAttribute virtualAttribute = this.addVirtualAttribute(javaAttributeMapping);
this.fireItemAdded(VIRTUAL_ATTRIBUTES_LIST, virtualAttributesSize() - 1, virtualAttribute);
}
resourceIndex++;
}
}
for (OrmPersistentAttribute contextAttribute : contextAttributesToRemove) {
this.removeVirtualAttribute(contextAttribute);
}
//first handle adding/removing of the persistent attributes, then update the others last,
//this causes less churn in the update process
for (OrmPersistentAttribute contextAttribute : contextAttributesToUpdate) {
contextAttribute.update();
}
}
protected OrmPersistentAttribute addVirtualAttribute(JavaResourcePersistentAttribute resourceAttribute) {
JavaPersistentAttribute javaAttribute = this.getJpaFactory().buildJavaPersistentAttribute(this, resourceAttribute);
JavaAttributeMapping javaAttributeMapping = javaAttribute.getMapping();
if (this.mapping.isMetadataComplete()) {
javaAttributeMapping = javaAttribute.getDefaultMapping();
}
return this.addVirtualAttribute(javaAttributeMapping);
}
//not firing change notification so this can be reused in initialize and update
protected OrmPersistentAttribute addVirtualAttribute(JavaAttributeMapping javaAttributeMapping) {
OrmAttributeMappingDefinition mappingDefintion = this.getMappingFileDefinition().getOrmAttributeMappingDefinition(javaAttributeMapping.getKey());
XmlAttributeMapping resourceMapping = mappingDefintion.buildVirtualResourceMapping(this.mapping, javaAttributeMapping, this.getXmlContextNodeFactory());
OrmPersistentAttribute virtualAttribute = this.buildVirtualOrmPersistentAttribute(javaAttributeMapping, resourceMapping);
this.virtualAttributes.add(virtualAttribute);
return virtualAttribute;
}
protected OrmPersistentAttribute buildVirtualOrmPersistentAttribute(JavaAttributeMapping javaAttributeMapping, XmlAttributeMapping resourceMapping) {
return this.buildOrmPersistentAttribute(this.buildVirtualAttributeOwner(javaAttributeMapping.getPersistentAttribute()), resourceMapping);
}
protected OrmPersistentAttribute buildOrmPersistentAttribute(OrmPersistentAttribute.Owner owner, XmlAttributeMapping resourceMapping) {
return this.getXmlContextNodeFactory().buildOrmPersistentAttribute(this, owner, resourceMapping);
}
protected OrmPersistentAttribute.Owner buildVirtualAttributeOwner(final JavaPersistentAttribute javaPersistentAttribute) {
return new OrmPersistentAttribute.Owner() {
public JavaPersistentAttribute findJavaPersistentAttribute(OrmPersistentAttribute ormPersistentAttribute) {
return javaPersistentAttribute;
}
public void updateJavaPersistentAttribute() {
//update the attribute, since we own it and it will not get updated otherwise
javaPersistentAttribute.update();
}
};
}
// ********** 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);
}
protected JavaPersistentType buildJavaPersistentType() {
JavaResourcePersistentType jrpt = this.getJavaResourcePersistentType();
return (jrpt == null) ? null : this.buildJavaPersistentType(jrpt);
}
protected JavaResourcePersistentType getJavaResourcePersistentType() {
String className = this.getName();
if (className == null) {
return null;
}
className = className.replace('$', '.');
// first try to resolve using only the locally specified name...
JavaResourcePersistentType jrpt = this.getJavaResourcePersistentType(className);
if (jrpt != null) {
return jrpt;
}
// ...then try to resolve by prepending the global package name
String defaultPackage = this.getDefaultPackage();
if (defaultPackage == null) {
return null;
}
return this.getJavaResourcePersistentType(defaultPackage + '.' + className);
}
protected JavaResourcePersistentType getJavaResourcePersistentType(String className) {
return this.getJpaProject().getJavaResourcePersistentType(className);
}
protected JavaPersistentType buildJavaPersistentType(JavaResourcePersistentType jrpt) {
return getJpaFactory().buildJavaPersistentType(this, jrpt);
}
protected void updateJavaPersistentType() {
JavaResourcePersistentType jrpt = this.getJavaResourcePersistentType();
if (jrpt == null) {
this.setJavaPersistentType(null);
} else {
if (this.javaPersistentType == null) {
this.setJavaPersistentType(this.buildJavaPersistentType(jrpt));
} else {
this.javaPersistentType.update(jrpt);
}
}
}
// ********** 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 void updateSuperPersistentType() {
PersistentType spt = this.buildSuperPersistentType();
// check for circular inheritance
if ((spt == null) || CollectionTools.contains(spt.inheritanceHierarchy(), this)) {
this.setSuperPersistentType(null);
} else {
this.setSuperPersistentType(spt);
}
}
protected PersistentType buildSuperPersistentType() {
return (this.javaPersistentType == null) ? null : this.javaPersistentType.getSuperPersistentType();
}
// ********** inheritance **********
public Iterator<PersistentType> inheritanceHierarchy() {
return this.inheritanceHierarchyOf(this);
}
public Iterator<PersistentType> ancestors() {
return this.inheritanceHierarchyOf(this.superPersistentType);
}
protected Iterator<PersistentType> inheritanceHierarchyOf(PersistentType start) {
// using a chain iterator to traverse up the inheritance tree
return new ChainIterator<PersistentType>(start) {
@Override
protected PersistentType nextLink(PersistentType persistentType) {
return persistentType.getSuperPersistentType();
}
};
}
// ********** metamodel **********
public IFile getMetamodelFile() {
return (this.javaPersistentType == null) ? null : this.metamodelSynchronizer.getFile();
}
public void initializeMetamodel() {
// do nothing - probably shouldn't be called...
}
/**
* All orm.xml persistent types must be able to generate a static metamodel
* because 1.0 orm.xml files can be referenced from 2.0 persistence.xml files.
*/
public void synchronizeMetamodel() {
if (this.javaPersistentType != null) {
this.metamodelSynchronizer.synchronize();
}
}
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();
}
}
// ********** 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();
}
// ********** 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) {
JptCorePlugin.log(t);
}
}
protected void validateAttributes(List<IMessage> messages, IReporter reporter) {
for (Iterator<OrmPersistentAttribute> stream = this.attributes(); stream.hasNext(); ) {
this.validateAttribute(stream.next(), messages, reporter);
}
}
protected void validateAttribute(OrmPersistentAttribute attribute, List<IMessage> messages, IReporter reporter) {
try {
attribute.validate(messages, reporter);
} catch(Throwable t) {
JptCorePlugin.log(t);
}
}
public TextRange getValidationTextRange() {
return this.mapping.getValidationTextRange();
}
// ********** misc **********
@Override
public EntityMappings getParent() {
return (EntityMappings) super.getParent();
}
public String getDefaultPackage() {
return this.getEntityMappings().getDefaultPersistentTypePackage();
}
public boolean isDefaultMetadataComplete() {
return this.getEntityMappings().isDefaultPersistentTypeMetadataComplete();
}
public boolean isFor(String typeName) {
String className = this.getName();
if (className == null) {
return false;
}
if (className.equals(typeName)) {
return true;
}
String defaultPackage = this.getDefaultPackage();
if (defaultPackage == null) {
return false;
}
return (defaultPackage + '.' + className).equals(typeName);
}
public boolean contains(int textOffset) {
return this.mapping.containsOffset(textOffset);
}
public void classChanged(String oldClass, String newClass) {
this.firePropertyChanged(NAME_PROPERTY, oldClass, newClass);
}
public boolean isMapped() {
return true;
}
public String getMappingKey() {
return this.mapping.getKey();
}
protected EntityMappings getEntityMappings() {
return this.getParent();
}
protected XmlTypeMapping getResourceTypeMapping() {
return this.mapping.getResourceTypeMapping();
}
@Override
public void toString(StringBuilder sb) {
sb.append(this.getName());
}
// ********** specified persistent attribute owner **********
protected class SpecifiedAttributeOwner
implements OrmPersistentAttribute.Owner
{
private JavaPersistentAttribute cachedJavaPersistentAttribute;
public SpecifiedAttributeOwner() {
super();
}
public JavaPersistentAttribute findJavaPersistentAttribute(OrmPersistentAttribute ormPersistentAttribute) {
if (GenericOrmPersistentType.this.javaPersistentType == null) {
return null;
}
String ormName = ormPersistentAttribute.getName();
if (ormName == null) {
return null;
}
AccessType ormAccess = ormPersistentAttribute.getAccess();
JavaPersistentAttribute javaPersistentAttribute = this.findExistingJavaPersistentAttribute(ormName);
if ((javaPersistentAttribute != null) && (javaPersistentAttribute.getAccess() == ormAccess)) {
this.cachedJavaPersistentAttribute = null; // we only want to cache the persistent attribute if we build it
return javaPersistentAttribute;
}
// if 'javaPersistentAttribute' is null, it might exist in a superclass that is not persistent, we need to build it ourselves.
// if access is different, we won't be able to find the corresponding java persistent attribute, it won't exist so we build it ourselves
return this.buildJavaPersistentAttribute(ormName, ormAccess);
}
protected JavaPersistentAttribute findExistingJavaPersistentAttribute(String attributeName) {
return GenericOrmPersistentType.this.javaPersistentType.getAttributeNamed(attributeName);
}
protected JavaPersistentAttribute buildJavaPersistentAttribute(String ormName, AccessType ormAccess) {
JavaResourcePersistentAttribute jrpa = this.getJavaResourcePersistentAttribute(this.getJavaResourcePersistentType(), ormName, ormAccess);
if (this.cachedJavaPersistentAttribute != null &&
this.cachedJavaPersistentAttribute.getResourcePersistentAttribute() == jrpa) {
return this.cachedJavaPersistentAttribute;
}
return this.cachedJavaPersistentAttribute = (jrpa == null) ? null : GenericOrmPersistentType.this.buildJavaPersistentAttribute(jrpa);
}
protected JavaResourcePersistentType getJavaResourcePersistentType() {
return GenericOrmPersistentType.this.javaPersistentType.getResourcePersistentType();
}
protected JavaResourcePersistentAttribute getJavaResourcePersistentAttribute(JavaResourcePersistentType javaResourcePersistentType, String ormName, AccessType ormAccess) {
for (Iterator<JavaResourcePersistentAttribute> stream = this.attributes(javaResourcePersistentType, ormAccess); stream.hasNext(); ) {
JavaResourcePersistentAttribute jrpa = stream.next();
if (jrpa.getName().equals(ormName)) {
return jrpa;
}
}
// climb up inheritance hierarchy
String superclassName = javaResourcePersistentType.getSuperclassQualifiedName();
if (superclassName == null) {
return null;
}
JavaResourcePersistentType superclass = GenericOrmPersistentType.this.getJavaResourcePersistentType(superclassName);
if (superclass == null) {
return null;
}
// recurse
return this.getJavaResourcePersistentAttribute(superclass, ormName, ormAccess);
}
protected Iterator<JavaResourcePersistentAttribute> attributes(JavaResourcePersistentType javaResourcePersistentType, AccessType ormAccess) {
return (ormAccess == AccessType.PROPERTY) ? javaResourcePersistentType.persistableProperties() : javaResourcePersistentType.persistableFields();
}
public void updateJavaPersistentAttribute() {
if (this.cachedJavaPersistentAttribute != null) {
this.cachedJavaPersistentAttribute.update();
}
//else {
//don't update, we don't own the java persistent attribute,
//it will be updated through the java context model
//}
}
}
}