| /******************************************************************************* |
| * 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.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.jdt.core.ElementChangedEvent; |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaElementDelta; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jdt.core.dom.TypeDeclaration; |
| import org.eclipse.jpt.core.JpaAnnotationProvider; |
| import org.eclipse.jpt.core.ResourceModelListener; |
| import org.eclipse.jpt.core.internal.utility.jdt.JDTTools; |
| import org.eclipse.jpt.core.resource.java.JavaResourcePersistentType; |
| import org.eclipse.jpt.core.resource.java.JpaCompilationUnit; |
| import org.eclipse.jpt.core.utility.TextRange; |
| import org.eclipse.jpt.core.utility.jdt.AnnotationEditFormatter; |
| import org.eclipse.jpt.utility.CommandExecutorProvider; |
| import org.eclipse.jpt.utility.internal.BitTools; |
| import org.eclipse.jpt.utility.internal.iterators.EmptyIterator; |
| |
| /** |
| * |
| */ |
| public class JpaCompilationUnitImpl |
| extends AbstractJavaResourceNode |
| implements JpaCompilationUnit |
| { |
| private final ICompilationUnit compilationUnit; |
| |
| private final JpaAnnotationProvider annotationProvider; |
| |
| private final CommandExecutorProvider modifySharedDocumentCommandExecutorProvider; |
| |
| private final AnnotationEditFormatter annotationEditFormatter; |
| |
| private final ResourceModelListener resourceModelListener; |
| |
| /** |
| * The primary type of the AST compilation unit. We are not going to handle |
| * multiple types defined in a single compilation unit. Entities must have |
| * a public/protected no-arg constructor, and there is no way to access |
| * the constructor in a package class (which is what all top-level, |
| * non-primary classes must be). |
| */ |
| protected JavaResourcePersistentType persistentType; |
| |
| |
| // ********** construction ********** |
| |
| public JpaCompilationUnitImpl( |
| ICompilationUnit compilationUnit, |
| JpaAnnotationProvider annotationProvider, |
| CommandExecutorProvider modifySharedDocumentCommandExecutorProvider, |
| AnnotationEditFormatter annotationEditFormatter, |
| ResourceModelListener resourceModelListener) { |
| super(null); // the JPA compilation unit is the root of its sub-tree |
| this.compilationUnit = compilationUnit; |
| this.annotationProvider = annotationProvider; |
| this.modifySharedDocumentCommandExecutorProvider = modifySharedDocumentCommandExecutorProvider; |
| this.annotationEditFormatter = annotationEditFormatter; |
| this.resourceModelListener = resourceModelListener; |
| this.persistentType = this.buildPersistentType(); |
| } |
| |
| protected JavaResourcePersistentType buildPersistentType() { |
| this.openCompilationUnit(); |
| CompilationUnit astRoot = this.buildASTRoot(); |
| this.closeCompilationUnit(); |
| return this.buildPersistentType(astRoot); |
| } |
| |
| protected void openCompilationUnit() { |
| try { |
| this.compilationUnit.open(null); |
| } catch (JavaModelException ex) { |
| // do nothing - we just won't have a primary type in this case |
| } |
| } |
| |
| protected void closeCompilationUnit() { |
| try { |
| this.compilationUnit.close(); |
| } catch (JavaModelException ex) { |
| // hmmm |
| } |
| } |
| |
| protected JavaResourcePersistentType buildPersistentType(CompilationUnit astRoot) { |
| TypeDeclaration td = this.getPrimaryType(astRoot); |
| return (td == null) ? null : this.buildPersistentType(astRoot, td); |
| } |
| |
| public void initialize(CompilationUnit astRoot) { |
| // never called? |
| } |
| |
| |
| // ********** AbstractJavaResourceNode overrides ********** |
| |
| @Override |
| protected boolean requiresParent() { |
| return false; |
| } |
| |
| @Override |
| public JpaCompilationUnit getJpaCompilationUnit() { |
| return this; |
| } |
| |
| @Override |
| public JpaAnnotationProvider getAnnotationProvider() { |
| return this.annotationProvider; |
| } |
| |
| |
| // ********** JavaResourceNode implementation ********** |
| |
| public void update(CompilationUnit astRoot) { |
| TypeDeclaration td = this.getPrimaryType(astRoot); |
| if (td == null) { |
| this.persistentType = null; |
| } else { |
| if (this.persistentType == null) { |
| this.persistentType = this.buildPersistentType(astRoot, td); |
| } else { |
| this.persistentType.update(astRoot); |
| } |
| } |
| } |
| |
| public TextRange getTextRange(CompilationUnit astRoot) { |
| return null; |
| } |
| |
| |
| // ********** JpaCompilationUnit implementation ********** |
| |
| public ICompilationUnit getCompilationUnit() { |
| return this.compilationUnit; |
| } |
| |
| public Iterator<JavaResourcePersistentType> persistableTypes() { |
| return (this.persistentType == null) ? |
| EmptyIterator.<JavaResourcePersistentType>instance() : |
| this.persistentType.allPersistableTypes(); |
| } |
| |
| public void resourceModelChanged() { |
| this.resourceModelListener.resourceModelChanged(); |
| } |
| |
| public void resolveTypes() { |
| if (this.persistentType != null) { |
| this.persistentType.resolveTypes(this.buildASTRoot()); |
| } |
| } |
| |
| public CommandExecutorProvider getModifySharedDocumentCommandExecutorProvider() { |
| return this.modifySharedDocumentCommandExecutorProvider; |
| } |
| |
| public AnnotationEditFormatter getAnnotationEditFormatter() { |
| return this.annotationEditFormatter; |
| } |
| |
| |
| // ********** Java changes ********** |
| |
| public void javaElementChanged(ElementChangedEvent event) { |
| this.synchWithJavaDelta(event.getDelta()); |
| } |
| |
| protected void synchWithJavaDelta(IJavaElementDelta delta) { |
| switch (delta.getElement().getElementType()) { |
| case IJavaElement.JAVA_PROJECT : |
| if (this.classpathHasChanged(delta)) { |
| this.updateFromJava(); |
| break; // no need to check further |
| } |
| case IJavaElement.JAVA_MODEL : |
| case IJavaElement.PACKAGE_FRAGMENT_ROOT : |
| case IJavaElement.PACKAGE_FRAGMENT : |
| this.synchChildrenWithJavaDelta(delta); |
| break; |
| case IJavaElement.COMPILATION_UNIT : |
| if (this.deltaIsRelevant(delta)) { |
| this.updateFromJava(); |
| } |
| break; |
| default : |
| break; // the element type is somehow held by a compilation unit (i.e. probably doesn't happen) |
| } |
| } |
| |
| protected void synchChildrenWithJavaDelta(IJavaElementDelta delta) { |
| for (IJavaElementDelta child : delta.getAffectedChildren()) { |
| this.synchWithJavaDelta(child); // recurse |
| } |
| } |
| |
| // 235384 - We need to update all compilation units when a classpath change occurs. |
| // The persistence.jar could have been added to or removed from the |
| // classpath which affects whether we know about the JPA annotations. |
| protected boolean classpathHasChanged(IJavaElementDelta delta) { |
| return BitTools.anyFlagsAreSet(delta.getFlags(), this.getClasspathChangedFlags()); |
| } |
| |
| protected int getClasspathChangedFlags() { |
| return CLASSPATH_CHANGED_FLAGS; |
| } |
| |
| protected static final int CLASSPATH_CHANGED_FLAGS = |
| IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED | |
| IJavaElementDelta.F_CLASSPATH_CHANGED; |
| |
| protected boolean deltaIsRelevant(IJavaElementDelta delta) { |
| // ignore changes to/from primary working copy - no content has changed; |
| // and make sure there are no other flags set that indicate *both* a |
| // change to/from primary working copy *and* content has changed |
| if (BitTools.onlyFlagIsSet(delta.getFlags(), IJavaElementDelta.F_PRIMARY_WORKING_COPY)) { |
| return false; |
| } |
| |
| // we get the java notification for removal before we get the resource notification; |
| // we do not need to handle this event and will get exceptions building an astRoot if we try |
| if (delta.getKind() == IJavaElementDelta.REMOVED) { |
| return false; |
| } |
| |
| return delta.getElement().equals(this.compilationUnit); |
| } |
| |
| protected void updateFromJava() { |
| this.update(this.buildASTRoot()); |
| } |
| |
| |
| // ********** internal ********** |
| |
| protected CompilationUnit buildASTRoot() { |
| return JDTTools.buildASTRoot(this.compilationUnit); |
| } |
| |
| protected JavaResourcePersistentType buildPersistentType(CompilationUnit astRoot, TypeDeclaration typeDeclaration) { |
| return JavaResourcePersistentTypeImpl.newInstance(this, typeDeclaration, astRoot); |
| } |
| |
| /** |
| * i.e. the type with the same name as the compilation unit; |
| * return the first class or interface (ignore annotations and enums) with |
| * the same name as the compilation unit (file); |
| * NB: this type could be in error if there is an annotation or enum |
| * with the same name preceding it in the compilation unit |
| * |
| * Return null if resolveBinding() on the TypeDeclaration returns null |
| * This can occur if the project JRE is removed (bug 225332) |
| */ |
| protected TypeDeclaration getPrimaryType(CompilationUnit astRoot) { |
| String primaryTypeName = this.getPrimaryTypeName(); |
| for (AbstractTypeDeclaration atd : types(astRoot)) { |
| if ((atd.getNodeType() == ASTNode.TYPE_DECLARATION) |
| && atd.getName().getFullyQualifiedName().equals(primaryTypeName)) { |
| return (atd.resolveBinding()) != null ? (TypeDeclaration) atd : null; |
| } |
| } |
| return null; |
| } |
| |
| // minimize scope of suppressed warnings |
| @SuppressWarnings("unchecked") |
| protected static List<AbstractTypeDeclaration> types(CompilationUnit astRoot) { |
| return astRoot.types(); |
| } |
| |
| /** |
| * i.e. the name of the compilation unit |
| */ |
| protected String getPrimaryTypeName() { |
| return removeJavaExtension(this.compilationUnit.getElementName()); |
| } |
| |
| protected static String removeJavaExtension(String fileName) { |
| int index = fileName.lastIndexOf(".java"); //$NON-NLS-1$ |
| return (index == -1) ? fileName : fileName.substring(0, index); |
| } |
| |
| @Override |
| public void toString(StringBuilder sb) { |
| sb.append(this.persistentType.getName()); |
| } |
| |
| } |