blob: ee47c331c555e5a65249e343dccc92b23e3fb160 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2015 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0, which accompanies this distribution
* and is available at http://www.eclipse.org/legal/epl-v10.html.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.jpa.core.internal.context.java;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import org.eclipse.jpt.common.core.resource.java.Annotation;
import org.eclipse.jpt.common.core.resource.java.JavaResourceAbstractType;
import org.eclipse.jpt.common.core.resource.java.JavaResourceAnnotatedElement;
import org.eclipse.jpt.common.core.resource.java.JavaResourceAttribute;
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.TextRange;
import org.eclipse.jpt.common.core.utility.jdt.TypeBinding;
import org.eclipse.jpt.common.utility.internal.ObjectTools;
import org.eclipse.jpt.common.utility.internal.collection.CollectionTools;
import org.eclipse.jpt.common.utility.internal.iterable.EmptyIterable;
import org.eclipse.jpt.common.utility.internal.iterable.IterableTools;
import org.eclipse.jpt.common.utility.internal.transformer.TransformerAdapter;
import org.eclipse.jpt.common.utility.iterable.ListIterable;
import org.eclipse.jpt.common.utility.predicate.Predicate;
import org.eclipse.jpt.jpa.core.JpaFile;
import org.eclipse.jpt.jpa.core.JpaStructureNode;
import org.eclipse.jpt.jpa.core.context.AccessType;
import org.eclipse.jpt.jpa.core.context.PersistentAttribute;
import org.eclipse.jpt.jpa.core.context.PersistentType;
import org.eclipse.jpt.jpa.core.context.TypeMapping;
import org.eclipse.jpt.jpa.core.context.java.JavaManagedType;
import org.eclipse.jpt.jpa.core.context.java.JavaPersistentType;
import org.eclipse.jpt.jpa.core.context.java.JavaSpecifiedPersistentAttribute;
import org.eclipse.jpt.jpa.core.context.java.JavaTypeMapping;
import org.eclipse.jpt.jpa.core.context.java.JavaTypeMappingDefinition;
import org.eclipse.jpt.jpa.core.internal.context.MappingTools;
import org.eclipse.jpt.jpa.core.internal.plugin.JptJpaCorePlugin;
import org.eclipse.jpt.jpa.core.jpa2.resource.java.AccessAnnotation2_0;
import org.eclipse.wst.validation.internal.provisional.core.IMessage;
import org.eclipse.wst.validation.internal.provisional.core.IReporter;
/**
* Java persistent type:<ul>
* <li>name
* <li>access
* <li>mapping
* <li>attributes
* <li>super persistent type
* </ul>
*/
public abstract class AbstractJavaPersistentType
extends AbstractJavaManagedType<PersistentType.Parent>
implements JavaPersistentType {
protected AccessType specifiedAccess;
protected AccessType defaultAccess; // never null
protected JavaTypeMapping mapping; // never null
protected final Vector<JavaSpecifiedPersistentAttribute> attributes = new Vector<JavaSpecifiedPersistentAttribute>();
protected final Vector<JavaSpecifiedPersistentAttribute> structureChildren = new Vector<JavaSpecifiedPersistentAttribute>();
protected AbstractJavaPersistentType(PersistentType.Parent parent, JavaResourceType resourceType) {
super(parent, resourceType);
this.specifiedAccess = this.buildSpecifiedAccess();
// keep this non-null
this.defaultAccess = AccessType.FIELD;
this.mapping = this.buildMapping();
this.initializeAttributes();
this.initializeStructureChildren();
}
// ********** synchronize/update **********
@Override
public void synchronizeWithResourceModel() {
super.synchronizeWithResourceModel();
this.setSpecifiedAccess_(this.buildSpecifiedAccess());
this.syncMapping();
this.synchronizeModelsWithResourceModel(this.getAttributes());
}
@Override
public void update() {
super.update();
this.setDefaultAccess(this.buildDefaultAccess());
this.mapping.update();
this.updateAttributes();
this.updateStructureChildren();
}
// ***** inheritance *****
public PersistentType getSuperPersistentType() {
TypeMapping superTypeMapping = this.mapping.getSuperTypeMapping();
return (superTypeMapping == null) ? null : superTypeMapping.getPersistentType();
}
// ********** access annotation **********
protected AccessAnnotation2_0 getAccessAnnotation() {
return (AccessAnnotation2_0) this.resourceType.getNonNullAnnotation(this.getAccessAnnotationName());
}
protected void removeAccessAnnotationIfUnset() {
AccessAnnotation2_0 accessAnnotation = this.getAccessAnnotation();
if ((accessAnnotation != null) && accessAnnotation.isUnset()) {
this.removeAccessAnnotation();
}
}
protected void removeAccessAnnotation() {
this.resourceType.removeAnnotation(this.getAccessAnnotationName());
}
protected String getAccessAnnotationName() {
return AccessAnnotation2_0.ANNOTATION_NAME;
}
// ********** access **********
public AccessType getAccess() {
return (this.specifiedAccess != null) ? this.specifiedAccess : this.defaultAccess;
}
public AccessType getSpecifiedAccess() {
return this.specifiedAccess;
}
public void setSpecifiedAccess(AccessType access) {
if (ObjectTools.notEquals(this.specifiedAccess, access)) {
this.getAccessAnnotation().setValue(AccessType.toJavaResourceModel(access));
this.removeAccessAnnotationIfUnset();
this.setSpecifiedAccess_(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.fromJavaResourceModel(this.getAccessAnnotation().getValue(), 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);
}
/**
* Check the access "specified" by the Java resource model:<ul>
* <li>Check Java annotations first
* <li>If <code>null</code>, check XML mapping specified access
* <li>If still <code>null</code>, check {@link #superPersistentType} access
* <li>If still <code>null</code>, check <code>entity-mappings</code>
* specified access setting if the corresponding <code>persistent-type</code>
* is listed in a mapping (<code>orm.xml</code>) file
* <li>If still <code>null</code>, check the <code>persistence-unit</code>
* default Access
* <li>Default to {@link AccessType#FIELD FIELD} if all else fails.
* </ul>
*/
protected AccessType buildDefaultAccess() {
AccessType accessType = this.getResourceTypeAccess();
if (accessType != null) {
return accessType;
}
accessType = this.parent.getOverridePersistentTypeAccess();
if (accessType != null) {
return accessType;
}
if (getSuperPersistentType() != null) {
accessType = getSuperPersistentType().getAccess();
if (accessType != null) {
return accessType;
}
}
accessType = this.parent.getDefaultPersistentTypeAccess();
if (accessType != null) {
return accessType;
}
// last ditch attempt to allow the user to annotate *something*
return AccessType.FIELD;
}
/**
* Return the access type currently implied by the Java source
* code or class file:<ul>
* <li>if any fields are annotated =>
* {@link AccessType#FIELD FIELD}
* <li>if only properties are annotated =>
* {@link AccessType#PROPERTY PROPERTY}
* <li>if neither are annotated =>
* <code>null</code>
* </ul>
*/
protected AccessType getResourceTypeAccess() {
for (JavaResourceField field : this.resourceType.getFields()) {
if (field.isAnnotated()) {
// any field is annotated => FIELD
return AccessType.FIELD;
}
}
for (JavaResourceMethod method : this.resourceType.getMethods()) {
if (method.isAnnotated()) {
// none of the fields are annotated and any method is annotated => PROPERTY
return AccessType.PROPERTY;
}
}
// nothing is annotated
return null;
}
// ********** mapping **********
public JavaTypeMapping getMapping() {
return this.mapping;
}
public String getMappingKey() {
return this.mapping.getKey();
}
public void setMappingKey(String key) {
if (ObjectTools.notEquals(key, this.getMappingKey())) {
this.setMapping(this.buildMapping(key));
}
}
protected JavaTypeMapping buildMapping(String key) {
for (JavaTypeMappingDefinition definition : this.getMappingDefinitions()) {
if (ObjectTools.equals(definition.getKey(), key)) {
Annotation annotation = this.resourceType.setPrimaryAnnotation(definition.getAnnotationName(), definition.getSupportingAnnotationNames());
return definition.buildMapping(this, annotation, this.getJpaFactory());
}
}
this.resourceType.setPrimaryAnnotation(null, EmptyIterable.<String>instance());
return this.buildNullMapping();
}
/**
* Clients do not set the mapping directly.
* @see #setMappingKey(String)
*/
protected void setMapping(JavaTypeMapping mapping) {
JavaTypeMapping old = this.mapping;
this.mapping = mapping;
this.firePropertyChanged(MAPPING_PROPERTY, old, mapping);
}
protected JavaTypeMapping buildMapping() {
for (JavaTypeMappingDefinition definition : this.getMappingDefinitions()) {
Annotation annotation = this.resourceType.getAnnotation(definition.getAnnotationName());
if (annotation != null) {
return definition.buildMapping(this, annotation, this.getJpaFactory());
}
}
return this.buildNullMapping();
}
protected void syncMapping() {
JavaTypeMappingDefinition definition = null;
Annotation annotation = null;
for (Iterator<JavaTypeMappingDefinition> stream = this.mappingDefinitions(); stream.hasNext(); ) {
definition = stream.next();
annotation = this.resourceType.getAnnotation(definition.getAnnotationName());
if (annotation != null) {
break;
}
}
// 'annotation' can still be null when we get here
if (this.mapping.getMappingAnnotation() == annotation) {
this.mapping.synchronizeWithResourceModel();
} else {
this.setMapping(this.buildMapping(annotation, definition));
}
}
protected JavaTypeMapping buildMapping(Annotation annotation, JavaTypeMappingDefinition definition) {
return (annotation != null) ?
definition.buildMapping(this, annotation, this.getJpaFactory()) :
this.buildNullMapping();
}
protected Iterator<JavaTypeMappingDefinition> mappingDefinitions() {
return this.getMappingDefinitions().iterator();
}
protected Iterable<JavaTypeMappingDefinition> getMappingDefinitions() {
return this.getJpaPlatform().getJavaTypeMappingDefinitions();
}
protected JavaTypeMapping buildNullMapping() {
return this.getJpaFactory().buildJavaNullTypeMapping(this);
}
public boolean isMapped() {
return this.mapping.isMapped();
}
// ********** attributes **********
public ListIterable<JavaSpecifiedPersistentAttribute> getAttributes() {
return IterableTools.cloneLive(this.attributes);
}
public int getAttributesSize() {
return this.attributes.size();
}
public Iterable<String> getAttributeNames() {
return this.convertToNames(this.getAttributes());
}
public JavaSpecifiedPersistentAttribute getAttributeNamed(String attributeName) {
Iterator<JavaSpecifiedPersistentAttribute> stream = this.getAttributesNamed(attributeName).iterator();
return stream.hasNext() ? stream.next() : null;
}
public JavaSpecifiedPersistentAttribute getAttributeFor(JavaResourceAttribute javaResourceAttribute) {
for (JavaSpecifiedPersistentAttribute javaAttribute : this.getAttributes()) {
if (javaAttribute.getResourceAttribute() == javaResourceAttribute) {
return javaAttribute;
}
}
return null;
}
public Iterable<PersistentAttribute> getAllAttributes() {
return IterableTools.children(
this.getInheritanceHierarchy(),
PersistentType.ATTRIBUTES_TRANSFORMER
);
}
public Iterable<String> getAllAttributeNames() {
return this.convertToNames(this.getAllAttributes());
}
protected Iterable<JavaSpecifiedPersistentAttribute> getAttributesNamed(String attributeName) {
return IterableTools.filter(this.getAttributes(), new PersistentAttribute.NameEquals(attributeName));
}
public PersistentAttribute resolveAttribute(String attributeName) {
Iterator<JavaSpecifiedPersistentAttribute> stream = this.getAttributesNamed(attributeName).iterator();
if (stream.hasNext()) {
JavaSpecifiedPersistentAttribute attribute = stream.next();
// return null if we have more than one
return stream.hasNext() ? null : attribute;
}
// recurse
return (getSuperPersistentType() == null) ? null : getSuperPersistentType().resolveAttribute(attributeName);
}
protected Iterable<String> convertToNames(Iterable<? extends PersistentAttribute> attrs) {
return IterableTools.transform(attrs, PersistentAttribute.NAME_TRANSFORMER);
}
protected JavaSpecifiedPersistentAttribute buildField(JavaResourceField resourceField) {
return this.getJpaFactory().buildJavaPersistentField(this, resourceField);
}
protected JavaSpecifiedPersistentAttribute buildProperty(JavaResourceMethod resourceGetter, JavaResourceMethod resourceSetter) {
return this.getJpaFactory().buildJavaPersistentProperty(this, resourceGetter, resourceSetter);
}
public boolean hasAnyAnnotatedAttributes() {
return this.resourceType.hasAnyAnnotatedFields() || this.resourceType.hasAnyAnnotatedMethods();
}
protected void moveAttribute(int index, JavaSpecifiedPersistentAttribute attribute) {
this.moveItemInList(index, attribute, this.attributes, ATTRIBUTES_LIST);
}
protected void addAttribute(int index, JavaSpecifiedPersistentAttribute persistentAttribute) {
this.addItemToList(index, persistentAttribute, this.attributes, ATTRIBUTES_LIST);
}
protected void removeAttribute(JavaSpecifiedPersistentAttribute attribute) {
this.removeItemFromList(attribute, this.attributes, ATTRIBUTES_LIST);
}
protected void initializeAttributes() {
if (this.getAccess() == AccessType.FIELD) {
this.intializeFieldAccessAttributes();
}
else if (this.getAccess() == AccessType.PROPERTY) {
this.intializePropertyAccessAttributes();
}
}
/**
* Initialize the attributes for AccessType.FIELD
* 1. all non-transient, non-static fields + annotated fields
* 2. all annotated methods (getters/setters)
*/
private void intializeFieldAccessAttributes() {
this.initializeFieldAttributes(JavaResourceField.IS_RELEVANT_FOR_FIELD_ACCESS);
this.initializeAnnotatedPropertyAttributes();
}
private void initializeFieldAttributes(Predicate<? super JavaResourceField> filter) {
for (JavaResourceField resourceField : this.getResourceFields(filter)) {
this.attributes.add(this.buildField(resourceField));
}
}
/**
* 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 intializePropertyAccessAttributes() {
this.initializeFieldAttributes(JavaResourceAnnotatedElement.IS_ANNOTATED);
Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
//iterate through all resource methods searching for persistable getters
for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
if (this.includeProperty(getterMethod, setterMethod)) {
this.attributes.add(this.buildProperty(getterMethod, setterMethod));
}
resourceMethods.remove(getterMethod);
resourceMethods.remove(setterMethod);
}
this.initializeRemainingResourceMethodAttributes(resourceMethods);
}
private void initializeAnnotatedPropertyAttributes() {
Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
//iterate through all resource methods searching for persistable getters
for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
if (getterMethod.isAnnotated() || ((setterMethod != null) && setterMethod.isAnnotated())) {
this.attributes.add(this.buildProperty(getterMethod, setterMethod));
}
resourceMethods.remove(getterMethod);
resourceMethods.remove(setterMethod);
}
this.initializeRemainingResourceMethodAttributes(resourceMethods);
}
private void initializeRemainingResourceMethodAttributes(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()) {
//annotated setter(or other random method) with no corresponding getter, bring into context model for validation purposes
this.attributes.add(this.buildProperty(null, resourceMethod));
}
}
}
/**
* The attributes are synchronized during the <em>update</em> because
* the list of resource attributes is determined by the access type
* which can be controlled in a number of different places....
*/
protected void updateAttributes() {
if (this.getAccess() == AccessType.FIELD) {
this.syncFieldAccessAttributes();
}
else if (this.getAccess() == AccessType.PROPERTY) {
this.syncPropertyAccessAttributes();
}
}
/**
* Initialize the attributes for AccessType.FIELD
* 1. all non-transient, non-static fields + annotated fields
* 2. all annotated methods(getters/setters)
*/
private void syncFieldAccessAttributes() {
HashSet<JavaSpecifiedPersistentAttribute> contextAttributes = CollectionTools.hashSet(this.getAttributes());
this.syncFieldAttributes(contextAttributes, JavaResourceField.IS_RELEVANT_FOR_FIELD_ACCESS);
this.syncAnnotatedPropertyAttributes(contextAttributes);
}
/**
* 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 syncPropertyAccessAttributes() {
HashSet<JavaSpecifiedPersistentAttribute> contextAttributes = CollectionTools.hashSet(this.getAttributes());
this.syncFieldAttributes(contextAttributes, JavaResourceAnnotatedElement.IS_ANNOTATED);
Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
//iterate through all resource methods searching for persistable getters
for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
if (this.includeProperty(getterMethod, setterMethod)) {
boolean match = false;
for (Iterator<JavaSpecifiedPersistentAttribute> stream = contextAttributes.iterator(); stream.hasNext();) {
JavaSpecifiedPersistentAttribute contextAttribute = stream.next();
if (contextAttribute.isFor(getterMethod, setterMethod)) {
match = true;
contextAttribute.update();
stream.remove();
break;
}
}
if (!match) {
this.addAttribute(this.getAttributesSize(), this.buildProperty(getterMethod, setterMethod));
}
}
resourceMethods.remove(getterMethod);
resourceMethods.remove(setterMethod);
}
this.syncRemainingResourceMethods(contextAttributes, resourceMethods);
}
private void syncAnnotatedPropertyAttributes(HashSet<JavaSpecifiedPersistentAttribute> contextAttributes) {
Collection<JavaResourceMethod> resourceMethods = CollectionTools.hashBag(this.getResourceMethods());
//iterate through all resource methods searching for persistable getters
for (JavaResourceMethod getterMethod : this.getResourcePropertyGetters()) {
JavaResourceMethod setterMethod = JavaResourceMethod.SET_METHOD_TRANSFORMER.transform(getterMethod);
if (getterMethod.isAnnotated() || ((setterMethod != null) && setterMethod.isAnnotated())) {
boolean match = false;
for (Iterator<JavaSpecifiedPersistentAttribute> stream = contextAttributes.iterator(); stream.hasNext();) {
JavaSpecifiedPersistentAttribute contextAttribute = stream.next();
if (contextAttribute.isFor(getterMethod, setterMethod)) {
match = true;
contextAttribute.update();
stream.remove();
break;
}
}
if (!match) {
this.addAttribute(this.getAttributesSize(), this.buildProperty(getterMethod, setterMethod));
}
}
resourceMethods.remove(getterMethod);
resourceMethods.remove(setterMethod);
}
this.syncRemainingResourceMethods(contextAttributes, resourceMethods);
}
private void syncFieldAttributes(HashSet<JavaSpecifiedPersistentAttribute> contextAttributes, Predicate<? super JavaResourceField> filter) {
for (JavaResourceField resourceField : this.getResourceFields(filter)) {
boolean match = false;
for (Iterator<JavaSpecifiedPersistentAttribute> stream = contextAttributes.iterator(); stream.hasNext(); ) {
JavaSpecifiedPersistentAttribute 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.addAttribute(this.getAttributesSize(), this.buildField(resourceField));
}
}
}
private void syncRemainingResourceMethods(HashSet<JavaSpecifiedPersistentAttribute> 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<JavaSpecifiedPersistentAttribute> stream = contextAttributes.iterator(); stream.hasNext();) {
JavaSpecifiedPersistentAttribute contextAttribute = stream.next();
if (contextAttribute.isFor(null, resourceMethod)) {
match = true;
contextAttribute.update();
stream.remove();
break;
}
}
if (!match) {
this.addAttribute(this.getAttributesSize(), this.buildProperty(null, resourceMethod));
}
}
}
// remove any leftover context attributes
for (JavaSpecifiedPersistentAttribute contextAttribute : contextAttributes) {
this.removeAttribute(contextAttribute);
}
}
protected Iterable<JavaResourceField> getResourceFields() {
return this.resourceType.getFields();
}
protected Iterable<JavaResourceMethod> getResourceMethods() {
return this.resourceType.getMethods();
}
protected Iterable<JavaResourceField> getResourceFields(Predicate<? super JavaResourceField> filter) {
return IterableTools.filter(this.getResourceFields(), filter);
}
protected Iterable<JavaResourceMethod> getResourcePropertyGetters() {
return this.filterResourceMethods(JavaResourceMethod.IS_PROPERTY_GETTER);
}
protected Iterable<JavaResourceMethod> filterResourceMethods(Predicate<JavaResourceMethod> predicate) {
return IterableTools.filter(this.getResourceMethods(), predicate);
}
/**
* Return whether the pair of methods form a "property" (sorta).
* An annotated getter with no setter is still brought into the context
* model (for validation purposes)....
*/
protected boolean includeProperty(JavaResourceMethod getterMethod, JavaResourceMethod setterMethod) {
return (setterMethod != null) || getterMethod.isAnnotated();
}
// ********** inheritance **********
public Iterable<PersistentType> getInheritanceHierarchy() {
return IterableTools.insert(this, getAncestors());
}
public Iterable<PersistentType> getAncestors() {
return IterableTools.transform(getMapping().getAncestors(), TypeMapping.PERSISTENT_TYPE_TRANSFORMER);
}
protected Iterable<JavaResourceType> getResourceInheritanceHierarchy() {
return (this.resourceType == null) ?
IterableTools.<JavaResourceType>emptyIterable() :
ObjectTools.chain(this.resourceType, new SuperJavaResourceTypeTransformer());
}
/**
* Transform a Java resource type into its super Java resource type.
*/
protected class SuperJavaResourceTypeTransformer
extends TransformerAdapter<JavaResourceType, JavaResourceType> {
// keep track of visited resource types to prevent cyclical inheritance
private final HashSet<JavaResourceType> visitedResourceTypes = new HashSet<JavaResourceType>();
@Override
public JavaResourceType transform(JavaResourceType jrt) {
this.visitedResourceTypes.add(jrt);
String superclassName = jrt.getSuperclassQualifiedName();
if (superclassName == null) {
return null;
}
JavaResourceType superJRT = AbstractJavaPersistentType.this.getJavaResourceType(superclassName);
return ((superJRT == null) || this.visitedResourceTypes.contains(superJRT)) ?
null :
superJRT;
}
}
protected JavaResourceType getJavaResourceType(String jrtName) {
return (JavaResourceType) this.getJpaProject().getJavaResourceType(jrtName, JavaResourceAbstractType.AstNodeType.TYPE);
}
public TypeBinding getAttributeTypeBinding(PersistentAttribute attribute) {
JavaResourceAttribute resourceAttribute = attribute.getJavaPersistentAttribute().getResourceAttribute();
if (resourceAttribute == null) {
return null;
}
for (JavaResourceType jrt : this.getResourceInheritanceHierarchy()) {
TypeBinding attributeType = jrt.getAttributeTypeBinding(resourceAttribute);
if (attributeType != null) {
return attributeType;
}
}
// attribute was not found in this context
throw new IllegalArgumentException(attribute.toString());
}
// ********** JpaStructureNode implementation **********
public ContextType getContextType() {
return new ContextType(this);
}
public Class<PersistentType> getManagedTypeType() {
return PersistentType.class;
}
public Class<JavaPersistentType> getStructureType() {
return JavaPersistentType.class;
}
/**
* This method is called by <code>JpaTextEditorManager</code> only when the
* focus is <em>not</em> in the JPA Details view.
* See <code>JptJpaUiPlugin.focusIsNotInDaliView()</code>.
* <p>
* We are suppressing Java events when the focus is in the JPA Details view
* so we don't want to call
* {@link org.eclipse.jpt.common.core.resource.java.JavaResourceCompilationUnit#synchronizeWithJavaSourceIfNecessary()}
* in that case.
* When the user moves from the JPA Details view to the Java source editor
* we need to call
* {@link org.eclipse.jpt.common.core.resource.java.JavaResourceCompilationUnit#synchronizeWithJavaSourceIfNecessary()}
* in order for our cached text ranges to be updated appropriately.
* <p>
* We also need to call
* {@link org.eclipse.jpt.common.core.resource.java.JavaResourceCompilationUnit#synchronizeWithJavaSourceIfNecessary()}
* when directly editing the Java source, as our text ranges are
* updated after the Java delay, which is after we are notified of a selection change.
*/
public JpaStructureNode getStructureNode(int offset) {
this.resourceType.getJavaResourceCompilationUnit().synchronizeWithJavaSourceIfNecessary();
if (this.containsOffset(offset)) {
for (JpaStructureNode child : this.getStructureChildren()) {
if (child.containsOffset(offset)) {
return child;
}
}
return this;
}
return null;
}
public TextRange getFullTextRange() {
return this.resourceType.getTextRange();
}
public boolean containsOffset(int offset) {
TextRange fullTextRange = this.getFullTextRange();
// 'fullTextRange' will be null if the type no longer exists in the java;
// the context model can be out of sync with the resource model
// when a selection event occurs before the context model has a
// chance to sync with the resource model via the update thread
return (fullTextRange == null) ? false : fullTextRange.includes(offset);
}
public void addRootStructureNodesTo(JpaFile jpaFile, Collection<JpaStructureNode> rootStructureNodes) {
// the type's resource can be null if the resource type is "external"
if (ObjectTools.equals(this.getResource(), jpaFile.getFile())) {
for (JpaStructureNode root : rootStructureNodes) {
// the JPA file is a java file, so the already-added root nodes must be
// Java managed types
JavaManagedType jmt = (JavaManagedType) root;
if (jmt.getName().equals(this.name)) {
// no duplicates -
// the first one found is used as a root in the structure view,
// the others are ignored...
return;
}
}
rootStructureNodes.add(this);
}
}
protected void initializeStructureChildren() {
this.structureChildren.addAll(this.attributes);
}
protected void updateStructureChildren() {
this.synchronizeCollection(this.getAttributes(), this.structureChildren, STRUCTURE_CHILDREN_COLLECTION);
}
public Iterable<JavaSpecifiedPersistentAttribute> getStructureChildren() {
return IterableTools.cloneLive(this.structureChildren);
}
public int getStructureChildrenSize() {
return this.structureChildren.size();
}
// ********** Java completion proposals **********
@Override
public Iterable<String> getCompletionProposals(int pos) {
Iterable<String> result = super.getCompletionProposals(pos);
if (result != null) {
return result;
}
Iterable<String> values = this.mapping.getCompletionProposals(pos);
if (values != null) {
return values;
}
for (JavaSpecifiedPersistentAttribute attribute : this.getAttributes()) {
values = attribute.getCompletionProposals(pos);
if (values != null) {
return values;
}
}
return EmptyIterable.instance();
}
// ********** validation **********
@Override
public void validate(List<IMessage> messages, IReporter reporter) {
super.validate(messages, reporter);
if (MappingTools.modelIsInternalSource(this, this.resourceType)) {
this.validateMapping(messages, reporter);
this.validateAttributes(messages, reporter);
}
}
protected void validateMapping(List<IMessage> messages, IReporter reporter) {
try {
this.mapping.validate(messages, reporter);
} catch(Throwable t) {
JptJpaCorePlugin.instance().logError(t);
}
}
protected void validateAttributes(List<IMessage> messages, IReporter reporter) {
for (JavaSpecifiedPersistentAttribute attribute : this.getAttributes()) {
this.validateAttribute(attribute, reporter, messages);
}
}
protected void validateAttribute(JavaSpecifiedPersistentAttribute attribute, IReporter reporter, List<IMessage> messages) {
try {
attribute.validate(messages, reporter);
} catch(Throwable t) {
JptJpaCorePlugin.instance().logError(t);
}
}
// ********** misc **********
public PersistentType getOverriddenPersistentType() {
return null; // Java persistent types do not override anything
}
}