| /******************************************************************************* |
| * Copyright (c) 2007, 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.resource.java; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.ListIterator; |
| import org.eclipse.jdt.core.IField; |
| import org.eclipse.jdt.core.IMember; |
| import org.eclipse.jdt.core.IMethod; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| import org.eclipse.jpt.core.internal.jdtutility.AnnotationEditFormatter; |
| import org.eclipse.jpt.core.internal.jdtutility.Attribute; |
| import org.eclipse.jpt.core.internal.jdtutility.FieldAttribute; |
| import org.eclipse.jpt.core.internal.jdtutility.JPTTools; |
| import org.eclipse.jpt.core.internal.jdtutility.MethodAttribute; |
| import org.eclipse.jpt.core.internal.jdtutility.Type; |
| import org.eclipse.jpt.utility.internal.CollectionTools; |
| import org.eclipse.jpt.utility.internal.CommandExecutorProvider; |
| import org.eclipse.jpt.utility.internal.iterators.CloneIterator; |
| import org.eclipse.jpt.utility.internal.iterators.FilteringIterator; |
| |
| public class JavaPersistentTypeResourceImpl extends AbstractJavaPersistentResource<Type> implements JavaPersistentTypeResource |
| { |
| /** |
| * store all member types including those that aren't persistable so we can include validation errors. |
| */ |
| private final Collection<JavaPersistentTypeResource> nestedTypes; |
| |
| private final Collection<JavaPersistentAttributeResource> attributes; |
| |
| private AccessType accessType; |
| |
| private String superClassQualifiedName; |
| |
| private String qualifiedName; |
| |
| private String name; |
| |
| private boolean isAbstract; |
| |
| public JavaPersistentTypeResourceImpl(JavaResource parent, Type type){ |
| super(parent, type); |
| this.nestedTypes = new ArrayList<JavaPersistentTypeResource>(); |
| this.attributes = new ArrayList<JavaPersistentAttributeResource>(); |
| } |
| |
| @Override |
| public void initialize(CompilationUnit astRoot) { |
| super.initialize(astRoot); |
| this.qualifiedName = this.qualifiedName(astRoot); |
| this.name = this.name(astRoot); |
| this.initializeNestedTypes(astRoot); |
| this.initializeAttributes(astRoot); |
| this.accessType = this.calculateAccessType(); |
| this.superClassQualifiedName = this.superClassQualifiedName(astRoot); |
| this.isAbstract = this.isAbstract(astRoot); |
| } |
| |
| protected void initializeNestedTypes(CompilationUnit astRoot) { |
| for (IType declaredType : getMember().declaredTypes()) { |
| this.nestedTypes.add(createJavaPersistentType(declaredType, astRoot)); |
| } |
| } |
| |
| protected void initializeAttributes(CompilationUnit astRoot) { |
| for (IField field : getMember().fields()) { |
| this.attributes.add(createJavaPersistentAttribute(field, astRoot)); |
| } |
| for (IMethod method : getMember().methods()) { |
| this.attributes.add(createJavaPersistentAttribute(method, astRoot)); |
| } |
| } |
| |
| // ******** AbstractJavaPersistentResource implementation ******** |
| |
| @Override |
| protected Annotation buildMappingAnnotation(String mappingAnnotationName) { |
| return annotationProvider().buildTypeMappingAnnotation(this, getMember(), mappingAnnotationName); |
| } |
| |
| @Override |
| protected Annotation buildNullMappingAnnotation(String annotationName) { |
| return annotationProvider().buildNullTypeMappingAnnotation(this, getMember(), annotationName); |
| } |
| |
| @Override |
| protected Annotation buildAnnotation(String annotationName) { |
| return annotationProvider().buildTypeAnnotation(this, getMember(), annotationName); |
| } |
| |
| @Override |
| protected Annotation buildNullAnnotation(String annotationName) { |
| return annotationProvider().buildNullTypeAnnotation(this, getMember(), annotationName); |
| } |
| |
| @Override |
| protected ListIterator<String> possibleMappingAnnotationNames() { |
| return annotationProvider().typeMappingAnnotationNames(); |
| } |
| |
| @Override |
| protected boolean isPossibleAnnotation(String annotationName) { |
| return CollectionTools.contains(annotationProvider().typeAnnotationNames(), annotationName); |
| } |
| |
| @Override |
| protected boolean isPossibleMappingAnnotation(String annotationName) { |
| return CollectionTools.contains(annotationProvider().typeMappingAnnotationNames(), annotationName); |
| } |
| |
| @Override |
| protected boolean calculatePersistability(CompilationUnit astRoot) { |
| return JPTTools.typeIsPersistable(getMember().binding(astRoot)); |
| } |
| |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| //overriding purely to suppress the warning you get at the class level |
| public ListIterator<NestableAnnotation> annotations(String nestableAnnotationName, String containerAnnotationName) { |
| return super.annotations(nestableAnnotationName, containerAnnotationName); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| //overriding purely to suppress the warning you get at the class level |
| public Iterator<Annotation> mappingAnnotations() { |
| return super.mappingAnnotations(); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| //overriding purely to suppress the warning you get at the class level |
| public Iterator<Annotation> annotations() { |
| return super.annotations(); |
| } |
| |
| |
| // ******** JavaPersistentTypeResource implementation ******** |
| public JavaPersistentTypeResource javaPersistentTypeResource(String fullyQualifiedTypeName) { |
| if (getQualifiedName().equals(fullyQualifiedTypeName)) { |
| return this; |
| } |
| for (JavaPersistentTypeResource jptr : CollectionTools.iterable(nestedTypes())) { |
| if (jptr.getQualifiedName().equals(fullyQualifiedTypeName)) { |
| return jptr; |
| } |
| } |
| return null; |
| } |
| |
| public Iterator<JavaPersistentTypeResource> nestedTypes() { |
| //TODO since we are filtering how do we handle the case where a type becomes persistable? |
| //what kind of change notificiation for that case? |
| return new FilteringIterator<JavaPersistentTypeResource, JavaPersistentTypeResource>(new CloneIterator<JavaPersistentTypeResource>(this.nestedTypes)) { |
| @Override |
| protected boolean accept(JavaPersistentTypeResource o) { |
| return o.isPersistable(); |
| } |
| }; |
| } |
| |
| protected JavaPersistentTypeResource nestedTypeFor(IType type) { |
| for (JavaPersistentTypeResource nestedType : this.nestedTypes) { |
| if (nestedType.isFor(type)) { |
| return nestedType; |
| } |
| } |
| return null; |
| } |
| |
| protected JavaPersistentTypeResource addNestedType(IType nestedType, CompilationUnit astRoot) { |
| JavaPersistentTypeResource persistentType = createJavaPersistentType(nestedType, astRoot); |
| addNestedType(persistentType); |
| return persistentType; |
| } |
| |
| protected void addNestedType(JavaPersistentTypeResource nestedType) { |
| addItemToCollection(nestedType, this.nestedTypes, NESTED_TYPES_COLLECTION); |
| } |
| |
| protected void removeNestedType(JavaPersistentTypeResource nestedType) { |
| removeItemFromCollection(nestedType, this.nestedTypes, NESTED_TYPES_COLLECTION); |
| } |
| |
| protected JavaPersistentTypeResource createJavaPersistentType(IType nestedType, CompilationUnit astRoot) { |
| return createJavaPersistentType(this, nestedType, modifySharedDocumentCommandExecutorProvider(), annotationEditFormatter(), astRoot); |
| } |
| |
| public static JavaPersistentTypeResource createJavaPersistentType( |
| JavaResource parent, |
| IType nestedType, |
| CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, |
| AnnotationEditFormatter annotationEditFormatter, |
| CompilationUnit astRoot) { |
| |
| Type type = new Type(nestedType, modifySharedDocumentCommandExecutorProvider, annotationEditFormatter); |
| JavaPersistentTypeResourceImpl javaPersistentType = new JavaPersistentTypeResourceImpl(parent, type); |
| javaPersistentType.initialize(astRoot); |
| return javaPersistentType; |
| } |
| |
| public Iterator<JavaPersistentAttributeResource> attributes() { |
| //TODO since we are filtering how do we handle the case where an attribute becomes persistable? |
| //what kind of change notificiation for that case? |
| return new FilteringIterator<JavaPersistentAttributeResource, JavaPersistentAttributeResource>(new CloneIterator<JavaPersistentAttributeResource>(this.attributes)) { |
| @Override |
| protected boolean accept(JavaPersistentAttributeResource o) { |
| return o.isPersistable(); |
| } |
| }; |
| } |
| |
| public Iterator<JavaPersistentAttributeResource> fields() { |
| return new FilteringIterator<JavaPersistentAttributeResource, JavaPersistentAttributeResource>(attributes()) { |
| @Override |
| protected boolean accept(JavaPersistentAttributeResource o) { |
| return o.isForField(); |
| } |
| }; |
| } |
| |
| public Iterator<JavaPersistentAttributeResource> properties() { |
| return new FilteringIterator<JavaPersistentAttributeResource, JavaPersistentAttributeResource>(attributes()) { |
| @Override |
| protected boolean accept(JavaPersistentAttributeResource o) { |
| return o.isForProperty(); |
| } |
| }; |
| } |
| |
| protected JavaPersistentAttributeResource addAttribute(IMember jdtMember, CompilationUnit astRoot) { |
| JavaPersistentAttributeResource persistentAttribute = createJavaPersistentAttribute(jdtMember, astRoot); |
| addAttribute(persistentAttribute); |
| return persistentAttribute; |
| } |
| |
| protected void addAttribute(JavaPersistentAttributeResource attribute) { |
| addItemToCollection(attribute, this.attributes, ATTRIBUTES_COLLECTION); |
| } |
| |
| protected JavaPersistentAttributeResource createJavaPersistentAttribute(IMember member, CompilationUnit astRoot) { |
| Attribute attribute = null; |
| if (member instanceof IField) { |
| attribute = new FieldAttribute((IField) member, this.modifySharedDocumentCommandExecutorProvider(), this.annotationEditFormatter()); |
| } |
| else if (member instanceof IMethod) { |
| attribute = new MethodAttribute((IMethod) member, this.modifySharedDocumentCommandExecutorProvider(), this.annotationEditFormatter()); |
| } |
| else { |
| throw new IllegalArgumentException(); |
| } |
| JavaPersistentAttributeResource javaPersistentAttribute = new JavaPersistentAttributeResourceImpl(this, attribute); |
| javaPersistentAttribute.initialize(astRoot); |
| return javaPersistentAttribute; |
| } |
| |
| protected void removeAttribute(JavaPersistentAttributeResource attribute) { |
| removeItemFromCollection(attribute, this.attributes, ATTRIBUTES_COLLECTION); |
| } |
| |
| protected JavaPersistentAttributeResource attributeFor(IMember member) { |
| for (JavaPersistentAttributeResource persistentAttribute : this.attributes) { |
| if (persistentAttribute.isFor(member)) { |
| return persistentAttribute; |
| } |
| } |
| return null; |
| } |
| |
| public AccessType getAccess() { |
| return this.accessType; |
| } |
| |
| //seems we could have a public changeAccess() api which would |
| //move all annotations from fields to their corresponding methods or vice versa |
| //though of course it's more complicated than that since what if the |
| //corresponding field/method does not exist? |
| //making this internal since it should only be set based on changes in the source, the |
| //context model should not need to set this |
| protected void setAccess(AccessType newAccess) { |
| AccessType oldAccess = this.accessType; |
| this.accessType = newAccess; |
| firePropertyChanged(ACCESS_PROPERTY, oldAccess, newAccess); |
| } |
| |
| public String getSuperClassQualifiedName() { |
| return this.superClassQualifiedName; |
| } |
| |
| private void setSuperClassQualifiedName(String newSuperClassQualifiedName) { |
| String oldSuperClassQualifiedName = this.superClassQualifiedName; |
| this.superClassQualifiedName = newSuperClassQualifiedName; |
| firePropertyChanged(SUPER_CLASS_QUALIFIED_NAME_PROPERTY, oldSuperClassQualifiedName, newSuperClassQualifiedName); |
| } |
| |
| public String getQualifiedName() { |
| return this.qualifiedName; |
| } |
| |
| protected void setQualifiedName(String newQualifiedName) { |
| String oldQualifiedName = this.qualifiedName; |
| this.qualifiedName = newQualifiedName; |
| firePropertyChanged(QUALIFIED_NAME_PROPERTY, oldQualifiedName, newQualifiedName); |
| } |
| |
| public String getName() { |
| return this.name; |
| } |
| |
| protected void setName(String newName) { |
| String oldName = this.name; |
| this.name = newName; |
| firePropertyChanged(NAME_PROPERTY, oldName, newName); |
| } |
| |
| public boolean isAbstract() { |
| return this.isAbstract; |
| } |
| |
| protected void setAbstract(boolean newAbstract) { |
| boolean oldAbstract = this.isAbstract; |
| this.isAbstract = newAbstract; |
| firePropertyChanged(ABSTRACT_PROPERTY, oldAbstract, newAbstract); |
| } |
| |
| @Override |
| public void updateFromJava(CompilationUnit astRoot) { |
| super.updateFromJava(astRoot); |
| this.setQualifiedName(this.qualifiedName(astRoot)); |
| this.setName(this.name(astRoot)); |
| this.updateNestedTypes(astRoot); |
| this.updatePersistentAttributes(astRoot); |
| this.setAccess(this.calculateAccessType()); |
| this.setSuperClassQualifiedName(this.superClassQualifiedName(astRoot)); |
| this.setAbstract(isAbstract(astRoot)); |
| } |
| |
| @Override |
| public void resolveTypes(CompilationUnit astRoot) { |
| super.resolveTypes(astRoot); |
| for (JavaPersistentAttributeResource attribute : this.attributes) { |
| attribute.resolveTypes(astRoot); |
| } |
| for (JavaPersistentTypeResource persistentType : this.nestedTypes) { |
| persistentType.resolveTypes(astRoot); |
| } |
| } |
| |
| protected boolean isAbstract(CompilationUnit astRoot) { |
| return JPTTools.typeIsAbstract(getMember().binding(astRoot)); |
| } |
| |
| protected String qualifiedName(CompilationUnit astRoot) { |
| return getMember().binding(astRoot).getQualifiedName(); |
| } |
| |
| protected String name(CompilationUnit astRoot) { |
| return getMember().binding(astRoot).getName(); |
| } |
| |
| protected void updateNestedTypes(CompilationUnit astRoot) { |
| IType[] declaredTypes = getMember().declaredTypes(); |
| |
| List<JavaPersistentTypeResource> nestedTypesToRemove = new ArrayList<JavaPersistentTypeResource>(this.nestedTypes); |
| for (IType declaredType : declaredTypes) { |
| JavaPersistentTypeResource nestedType = nestedTypeFor(declaredType); |
| if (nestedType == null) { |
| nestedType = addNestedType(declaredType, astRoot); |
| } |
| else { |
| nestedTypesToRemove.remove(nestedType); |
| } |
| nestedType.updateFromJava(astRoot); |
| } |
| for (JavaPersistentTypeResource nestedType : nestedTypesToRemove) { |
| removeNestedType(nestedType); |
| } |
| } |
| |
| protected void updatePersistentAttributes(CompilationUnit astRoot) { |
| List<JavaPersistentAttributeResource> persistentAttributesToRemove = new ArrayList<JavaPersistentAttributeResource>(this.attributes); |
| updatePersistentFields(astRoot, persistentAttributesToRemove); |
| updatePersistentProperties(astRoot, persistentAttributesToRemove); |
| for (JavaPersistentAttributeResource persistentAttribute : persistentAttributesToRemove) { |
| removeAttribute(persistentAttribute); |
| } |
| } |
| |
| protected void updatePersistentFields(CompilationUnit astRoot, List<JavaPersistentAttributeResource> persistentAttributesToRemove) { |
| updatePersistentAttributes(astRoot, persistentAttributesToRemove, getMember().fields()); |
| } |
| |
| protected void updatePersistentProperties(CompilationUnit astRoot, List<JavaPersistentAttributeResource> persistentAttributesToRemove) { |
| updatePersistentAttributes(astRoot, persistentAttributesToRemove, getMember().methods()); |
| } |
| |
| protected void updatePersistentAttributes(CompilationUnit astRoot, List<JavaPersistentAttributeResource> persistentAttributesToRemove, IMember[] members) { |
| for (IMember member : members) { |
| JavaPersistentAttributeResource persistentAttribute = attributeFor(member); |
| if (persistentAttribute == null) { |
| persistentAttribute = addAttribute(member, astRoot); |
| } |
| else { |
| persistentAttributesToRemove.remove(persistentAttribute); |
| } |
| persistentAttribute.updateFromJava(astRoot); |
| } |
| } |
| |
| public boolean hasAnyAttributeAnnotations() { |
| for (JavaPersistentAttributeResource attribute : CollectionTools.iterable(attributes())) { |
| if (attribute.hasAnyAnnotation()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Return the AccessType currently implied by the Java source code: |
| * - if only Fields are annotated => FIELD |
| * - if only Properties are annotated => PROPERTY |
| * - if both Fields and Properties are annotated => FIELD |
| * - if nothing is annotated |
| * - and fields exist => FIELD |
| * - and properties exist, but no fields exist => PROPERTY |
| * - and neither fields nor properties exist => null at this level (FIELD in the context model) |
| */ |
| private AccessType calculateAccessType() { |
| boolean hasPersistableFields = false; |
| boolean hasPersistableProperties = false; |
| for (JavaPersistentAttributeResource field : CollectionTools.iterable(fields())) { |
| hasPersistableFields = true; |
| if (field.hasAnyAnnotation()) { |
| // any field is annotated => FIELD |
| return AccessType.FIELD; |
| } |
| } |
| for (JavaPersistentAttributeResource property : CollectionTools.iterable(properties())) { |
| hasPersistableProperties = true; |
| if (property.hasAnyAnnotation()) { |
| // none of the fields are annotated and a getter is annotated => PROPERTY |
| return AccessType.PROPERTY; |
| } |
| } |
| |
| if (hasPersistableProperties && !hasPersistableFields) { |
| return AccessType.PROPERTY; |
| } |
| //no annotations exist, access is null at the resource model level |
| return null; |
| } |
| |
| private String superClassQualifiedName(CompilationUnit astRoot) { |
| ITypeBinding typeBinding = getMember().binding(astRoot); |
| if (typeBinding == null) { |
| return null; |
| } |
| ITypeBinding superClassTypeBinding = typeBinding.getSuperclass(); |
| if (superClassTypeBinding == null) { |
| return null; |
| } |
| return superClassTypeBinding.getQualifiedName(); |
| } |
| |
| @Override |
| public void toString(StringBuilder sb) { |
| sb.append(getName()); |
| } |
| |
| } |