blob: 6a6d0142518b39ded9eb350bf7fc01685d69929b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2008 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.context.java;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.core.resources.IResource;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jpt.core.internal.ITextRange;
import org.eclipse.jpt.core.internal.context.base.AccessType;
import org.eclipse.jpt.core.internal.context.base.IJpaContextNode;
import org.eclipse.jpt.core.internal.context.base.IPersistentAttribute;
import org.eclipse.jpt.core.internal.context.base.IPersistentType;
import org.eclipse.jpt.core.internal.resource.java.Annotation;
import org.eclipse.jpt.core.internal.resource.java.JavaPersistentAttributeResource;
import org.eclipse.jpt.core.internal.resource.java.JavaPersistentTypeResource;
import org.eclipse.jpt.utility.internal.CollectionTools;
import org.eclipse.jpt.utility.internal.Filter;
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.EmptyIterator;
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;
public class JavaPersistentType extends JavaContextModel implements IJavaPersistentType
{
protected String name;
protected IJavaTypeMapping mapping;
protected final List<IJavaPersistentAttribute> attributes;
protected AccessType access;
/**
* Store the parentPersistentType during default calculation. This will
* be the first persisentType found in the hierarchy, the JPA spec allows
* for non-persistent types to be part of the hierarchy.
* Example:
*
* @Entity public abstract class Model {}
*
* public abstract class Animal extends Model {}
*
* @Entity public class Cat extends Animal {}
*
* If this is the Cat JavaPersistentType then parentPersistentType is the Model JavaPersistentType
* The parentPersistentType could be found in java or xml.
*/
protected IPersistentType parentPersistentType;
protected JavaPersistentTypeResource persistentTypeResource;
public JavaPersistentType(IJpaContextNode parent) {
super(parent);
this.attributes = new ArrayList<IJavaPersistentAttribute>();
}
public void initializeFromResource(JavaPersistentTypeResource persistentTypeResource) {
this.persistentTypeResource = persistentTypeResource;
this.parentPersistentType = this.parentPersistentType(persistentTypeResource);
this.access = this.access(persistentTypeResource);
this.name = this.name(persistentTypeResource);
this.initializeMapping(persistentTypeResource);
this.initializePersistentAttributes(persistentTypeResource);
}
protected void initializeMapping(JavaPersistentTypeResource persistentTypeResource) {
this.mapping = jpaPlatform().createJavaTypeMappingFromAnnotation(this.javaMappingAnnotationName(persistentTypeResource), this);
this.mapping.initializeFromResource(persistentTypeResource);
}
protected void initializePersistentAttributes(JavaPersistentTypeResource persistentTypeResource) {
Iterator<JavaPersistentAttributeResource> resourceAttributes = persistentTypeResource.fields();
if (access() == AccessType.PROPERTY) {
resourceAttributes = persistentTypeResource.properties();
}
while (resourceAttributes.hasNext()) {
this.attributes.add(createAttribute(resourceAttributes.next()));
}
}
@Override
public IResource resource() {
return this.persistentTypeResource.resourceModel().resource().getCompilationUnit().getResource();
}
public String getName() {
return this.name;
}
protected void setName(String newName) {
String oldName = this.name;
this.name = newName;
firePropertyChanged(NAME_PROPERTY, oldName, newName);
}
public IJavaTypeMapping getMapping() {
return this.mapping;
}
public String mappingKey() {
return getMapping().getKey();
}
public void setMappingKey(String key) {
if (key == getMapping().getKey()) {
return;
}
IJavaTypeMapping oldMapping = getMapping();
IJavaTypeMapping newMapping = createJavaTypeMappingFromMappingKey(key);
setMapping(newMapping);
this.persistentTypeResource.setMappingAnnotation(newMapping.annotationName());
if (oldMapping != null) {
Collection<String> annotationsToRemove = CollectionTools.collection(oldMapping.correspondingAnnotationNames());
if (getMapping() != null) {
CollectionTools.removeAll(annotationsToRemove, getMapping().correspondingAnnotationNames());
}
for (String annotationName : annotationsToRemove) {
this.persistentTypeResource.removeAnnotation(annotationName);
}
}
}
protected void setMapping(IJavaTypeMapping newMapping) {
IJavaTypeMapping oldMapping = this.mapping;
this.mapping = newMapping;
firePropertyChanged(IPersistentType.MAPPING_PROPERTY, oldMapping, newMapping);
}
public boolean isMapped() {
return getMapping().isMapped();
}
public AccessType access() {
return this.access;
}
protected void setAccess(AccessType newAccess) {
AccessType oldAccess = this.access;
this.access = newAccess;
firePropertyChanged(ACCESS_PROPERTY, oldAccess, newAccess);
}
protected Iterator<JavaPersistentAttribute> attributesNamed(final String attributeName) {
return new FilteringIterator<IJavaPersistentAttribute, JavaPersistentAttribute>(attributes()) {
@Override
protected boolean accept(IJavaPersistentAttribute o) {
return attributeName.equals(o.getName());
}
};
}
public JavaPersistentAttribute attributeNamed(String attributeName) {
Iterator<JavaPersistentAttribute> stream = attributesNamed(attributeName);
return (stream.hasNext()) ? stream.next() : null;
}
public IPersistentAttribute resolveAttribute(String attributeName) {
Iterator<JavaPersistentAttribute> stream = attributesNamed(attributeName);
if (stream.hasNext()) {
JavaPersistentAttribute attribute = stream.next();
return (stream.hasNext()) ? null /*more than one*/: attribute;
}
return (parentPersistentType() == null) ? null : parentPersistentType().resolveAttribute(attributeName);
}
public ListIterator<IJavaPersistentAttribute> attributes() {
return new CloneListIterator<IJavaPersistentAttribute>(this.attributes);
}
public int attributesSize() {
return this.attributes.size();
}
private void addAttribute(IJavaPersistentAttribute attribute) {
addItemToList(attribute, this.attributes, IPersistentType.SPECIFIED_ATTRIBUTES_LIST);
}
private void removeAttribute(IJavaPersistentAttribute attribute) {
removeItemFromList(attribute, this.attributes, IPersistentType.SPECIFIED_ATTRIBUTES_LIST);
}
public Iterator<String> attributeNames() {
return this.attributeNames(this.attributes());
}
protected Iterator<String> attributeNames(Iterator<? extends IPersistentAttribute> attrs) {
return new TransformationIterator<IPersistentAttribute, String>(attrs) {
@Override
protected String transform(IPersistentAttribute attribute) {
return attribute.getName();
}
};
}
public Iterator<IPersistentAttribute> allAttributes() {
return new CompositeIterator<IPersistentAttribute>(new TransformationIterator<IPersistentType, Iterator<IPersistentAttribute>>(this.inheritanceHierarchy()) {
@Override
protected Iterator<IPersistentAttribute> transform(IPersistentType pt) {
return pt.attributes();
}
});
}
public Iterator<String> allAttributeNames() {
return this.attributeNames(this.allAttributes());
}
@Override
public Iterator<String> candidateValuesFor(int pos, Filter<String> filter, CompilationUnit astRoot) {
Iterator<String> result = super.candidateValuesFor(pos, filter, astRoot);
if (result != null) {
return result;
}
Iterator<String> values = this.mapping.candidateValuesFor(pos, filter, astRoot);
if (values != null) {
return values;
}
for (Iterator<IJavaPersistentAttribute> stream = attributes(); stream.hasNext();) {
values = stream.next().candidateValuesFor(pos, filter, astRoot);
if (values != null) {
return values;
}
}
return EmptyIterator.instance();
}
//
// public IJpaContentNode contentNodeAt(int offset) {
// for (Iterator<JavaPersistentAttribute> i = attributes(); i.hasNext();) {
// JavaPersistentAttribute persistentAttribute = i.next();
// if (persistentAttribute.includes(offset)) {
// return persistentAttribute;
// }
// }
// return null;
// }
// public boolean includes(int offset) {
// ITextRange fullTextRange = this.fullTextRange();
// if (fullTextRange == null) {
// //This happens if the type no longer exists in the java (rename in editor).
// //The text selection event is fired before the update from java so our
// //model has not yet had a chance to update appropriately. For now, avoid the NPE,
// //not sure of the ultimate solution to these 2 threads accessing our model
// return false;
// }
// return fullTextRange.includes(offset);
// }
//
// public ITextRange fullTextRange() {
// return this.persistentTypeResource.fullTextRange();
// }
public ITextRange validationTextRange(CompilationUnit astRoot) {
return this.selectionTextRange(astRoot);
}
public ITextRange selectionTextRange(CompilationUnit astRoot) {
return this.persistentTypeResource.textRange(astRoot);
}
public Iterator<IPersistentType> inheritanceHierarchy() {
// using a chain iterator to traverse up the inheritance tree
return new ChainIterator<IPersistentType>(this) {
@Override
protected IPersistentType nextLink(IPersistentType pt) {
return pt.parentPersistentType();
}
};
}
public IPersistentType parentPersistentType() {
return this.parentPersistentType;
}
public boolean hasAnyAttributeMappingAnnotations() {
if (this.persistentTypeResource.hasAnyAttributeAnnotations()) {
return true;
}
return false;
}
// ******************** Updating **********************
public void update(JavaPersistentTypeResource persistentTypeResource) {
this.persistentTypeResource = persistentTypeResource;
this.persistentTypeResource.resourceModel().addRootContextNode(this);
updateParentPersistentType(persistentTypeResource);
updateAccess(persistentTypeResource);
updateName(persistentTypeResource);
updateMapping(persistentTypeResource);
updatePersistentAttributes(persistentTypeResource);
}
protected void updateAccess(JavaPersistentTypeResource persistentTypeResource) {
this.setAccess(this.access(persistentTypeResource));
}
/**
* Check the access "specified" by the java resource model.
* Check xml mapping specified access first
* If still null check java annotations if the xml is not metadata-complete = true
* If still null then set to parentPersistentType access.
* If still null check entity-mappings specified access setting if this persistent-type is listed in an orm.xml file
* If still null check the persistence-unit default Access
* Default to FIELD if all else fails.
*/
protected AccessType access(JavaPersistentTypeResource persistentTypeResource) {
AccessType javaAccess = null;
boolean metadataComplete = false;
if (xmlPersistentType() != null) {
javaAccess = xmlPersistentType().getMapping().getSpecifiedAccess();
metadataComplete = xmlPersistentType().getMapping().isMetadataComplete();
}
if (javaAccess == null && !metadataComplete) {
javaAccess = AccessType.fromJavaResourceModel(persistentTypeResource.getAccess());
}
if (javaAccess == null) {
if (parentPersistentType() != null) {
javaAccess = parentPersistentType().access();
}
}
if (javaAccess == null) {
if (entityMappings() != null) {
javaAccess = entityMappings().getAccess();
}
}
if (javaAccess == null) {
//have to check persistence-unit separately in the case where it is not listed directly in an orm.xml
//if it is listed in an orm.xml then the entityMappings().getAccess() check will cover persistence-unit.defaultAccess
if (persistenceUnit() != null) {
javaAccess = persistenceUnit().getDefaultAccess();
}
}
if (javaAccess == null) {
javaAccess = AccessType.FIELD;
}
return javaAccess;
}
protected void updateName(JavaPersistentTypeResource persistentTypeResource) {
this.setName(this.name(persistentTypeResource));
}
protected String name(JavaPersistentTypeResource persistentTypeResource) {
return persistentTypeResource.getQualifiedName();
}
protected void updateMapping(JavaPersistentTypeResource persistentTypeResource) {
String javaMappingAnnotationName = this.javaMappingAnnotationName(persistentTypeResource);
if (getMapping().annotationName() != javaMappingAnnotationName) {
setMapping(createJavaTypeMappingFromAnnotation(javaMappingAnnotationName, persistentTypeResource));
}
else {
getMapping().update(persistentTypeResource);
}
}
protected IJavaTypeMapping createJavaTypeMappingFromMappingKey(String key) {
return jpaPlatform().createJavaTypeMappingFromMappingKey(key, this);
}
protected IJavaTypeMapping createJavaTypeMappingFromAnnotation(String annotationName, JavaPersistentTypeResource persistentTypeResource) {
IJavaTypeMapping mapping = jpaPlatform().createJavaTypeMappingFromAnnotation(annotationName, this);
mapping.initializeFromResource(persistentTypeResource);
return mapping;
}
protected String javaMappingAnnotationName(JavaPersistentTypeResource typeResource) {
Annotation mappingAnnotation = (Annotation) typeResource.mappingAnnotation();
if (mappingAnnotation != null) {
return mappingAnnotation.getAnnotationName();
}
return null;
}
protected void updatePersistentAttributes(JavaPersistentTypeResource persistentTypeResource) {
ListIterator<IJavaPersistentAttribute> contextAttributes = attributes();
Iterator<JavaPersistentAttributeResource> resourceAttributes = persistentTypeResource.fields();
if (access() == AccessType.PROPERTY) {
resourceAttributes = persistentTypeResource.properties();
}
while (contextAttributes.hasNext()) {
IJavaPersistentAttribute persistentAttribute = contextAttributes.next();
if (resourceAttributes.hasNext()) {
persistentAttribute.update(resourceAttributes.next());
}
else {
removeAttribute(persistentAttribute);
}
}
while (resourceAttributes.hasNext()) {
addAttribute(createAttribute(resourceAttributes.next()));
}
}
protected IJavaPersistentAttribute createAttribute(JavaPersistentAttributeResource persistentAttributeResource) {
IJavaPersistentAttribute javaPersistentAttribute = jpaFactory().createJavaPersistentAttribute(this);
javaPersistentAttribute.initializeFromResource(persistentAttributeResource);
return javaPersistentAttribute;
}
public void updateParentPersistentType(JavaPersistentTypeResource persistentTypeResource) {
//TODO do we need any change notification for this?
this.parentPersistentType = parentPersistentType(persistentTypeResource);
}
protected IPersistentType parentPersistentType(JavaPersistentTypeResource persistentTypeResource) {
return parentPersistentType(persistentTypeResource.getSuperClassQualifiedName());
}
protected IPersistentType parentPersistentType(String fullyQualifiedTypeName) {
IPersistentType possibleParent = possibleParent(fullyQualifiedTypeName);
if (possibleParent == null) {
return null;
}
if (possibleParent.isMapped()) {
return possibleParent;
}
return possibleParent.parentPersistentType();
}
/**
* JPA spec supports the case where there are non-persistent types in the hierarchy
* This will check for a PersistentType with the given name in this PersistenceUnit.
* If it is not found then find the JavaPersistentTypeResource and look for its parent type
*/
protected IPersistentType possibleParent(String fullyQualifiedTypeName) {
IPersistentType possibleParent = persistentType(fullyQualifiedTypeName);
if (possibleParent != null) {
return possibleParent;
}
JavaPersistentTypeResource javaPersistentTypeResource = jpaProject().javaPersistentTypeResource(fullyQualifiedTypeName);
if (javaPersistentTypeResource != null) {
return possibleParent(javaPersistentTypeResource.getSuperClassQualifiedName());
}
return null;
}
protected IPersistentType persistentType(String fullyQualifiedTypeName) {
return persistenceUnit().persistentType(fullyQualifiedTypeName);
}
//*************** Validation ******************************************
@Override
public void addToMessages(List<IMessage> messages, CompilationUnit astRoot) {
super.addToMessages(messages, astRoot);
//get astRoot here to pass down
astRoot = persistentTypeResource.getMember().astRoot();
mapping.addToMessages(messages, astRoot);
addAttributeMessages(messages, astRoot);
}
protected void addAttributeMessages(List<IMessage> messages, CompilationUnit astRoot) {
for (IJavaPersistentAttribute attributeContext : this.attributes) {
attributeContext.addToMessages(messages, astRoot);
}
}
@Override
public void toString(StringBuilder sb) {
super.toString(sb);
sb.append(getName());
}
}