| /******************************************************************************* |
| * Copyright (c) 2006, 2009 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; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.Vector; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IResourceDelta; |
| import org.eclipse.core.resources.IResourceDeltaVisitor; |
| import org.eclipse.core.resources.IResourceProxy; |
| import org.eclipse.core.resources.IResourceProxyVisitor; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.content.IContentType; |
| 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.IJavaProject; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jpt.core.JpaDataSource; |
| import org.eclipse.jpt.core.JpaFile; |
| import org.eclipse.jpt.core.JpaPlatform; |
| import org.eclipse.jpt.core.JpaProject; |
| import org.eclipse.jpt.core.JpaResourceModel; |
| import org.eclipse.jpt.core.JpaResourceModelListener; |
| import org.eclipse.jpt.core.JptCorePlugin; |
| import org.eclipse.jpt.core.context.JpaRootContextNode; |
| import org.eclipse.jpt.core.internal.resource.java.binary.BinaryPersistentTypeCache; |
| import org.eclipse.jpt.core.internal.resource.java.source.SourceCompilationUnit; |
| import org.eclipse.jpt.core.internal.utility.PlatformTools; |
| import org.eclipse.jpt.core.internal.validation.DefaultJpaValidationMessages; |
| import org.eclipse.jpt.core.internal.validation.JpaValidationMessages; |
| import org.eclipse.jpt.core.resource.java.JavaResourceCompilationUnit; |
| import org.eclipse.jpt.core.resource.java.JavaResourceNode; |
| import org.eclipse.jpt.core.resource.java.JavaResourcePackageFragmentRoot; |
| import org.eclipse.jpt.core.resource.java.JavaResourcePersistentType; |
| import org.eclipse.jpt.core.resource.java.JavaResourcePersistentTypeCache; |
| import org.eclipse.jpt.core.resource.xml.JpaXmlResource; |
| import org.eclipse.jpt.db.Catalog; |
| import org.eclipse.jpt.db.ConnectionProfile; |
| import org.eclipse.jpt.db.Database; |
| import org.eclipse.jpt.db.Schema; |
| import org.eclipse.jpt.db.SchemaContainer; |
| import org.eclipse.jpt.utility.CommandExecutor; |
| import org.eclipse.jpt.utility.internal.BitTools; |
| import org.eclipse.jpt.utility.internal.StringTools; |
| import org.eclipse.jpt.utility.internal.ThreadLocalCommandExecutor; |
| import org.eclipse.jpt.utility.internal.iterables.LiveCloneIterable; |
| import org.eclipse.jpt.utility.internal.iterables.CompositeIterable; |
| import org.eclipse.jpt.utility.internal.iterables.FilteringIterable; |
| import org.eclipse.jpt.utility.internal.iterables.TransformationIterable; |
| import org.eclipse.jst.j2ee.model.internal.validation.ValidationCancelledException; |
| import org.eclipse.wst.validation.internal.provisional.core.IMessage; |
| import org.eclipse.wst.validation.internal.provisional.core.IReporter; |
| |
| /** |
| * JPA project. Holds all the JPA stuff. |
| * |
| * The JPA platform provides the hooks for vendor-specific stuff. |
| * |
| * The JPA files are the "resource" model (i.e. objects that correspond directly |
| * to Eclipse resources; e.g. Java source code files, XML files, JAR files). |
| * |
| * The root context node is the "context"model (i.e. objects that attempt to |
| * model the JPA spec, using the "resource" model as an adapter to the Eclipse |
| * resources). |
| * |
| * The data source is an adapter to the DTP meta-data model. |
| */ |
| public abstract class AbstractJpaProject |
| extends AbstractJpaNode |
| implements JpaProject |
| { |
| /** |
| * The Eclipse project corresponding to the JPA project. |
| */ |
| protected final IProject project; |
| |
| /** |
| * The vendor-specific JPA platform that builds the JPA project |
| * and all its contents. |
| */ |
| protected final JpaPlatform jpaPlatform; |
| |
| /** |
| * The JPA files associated with the JPA project: |
| * persistence.xml |
| * orm.xml |
| * java |
| */ |
| protected final Vector<JpaFile> jpaFiles = new Vector<JpaFile>(); |
| |
| /** |
| * The "external" Java resource compilation units (source). Populated upon demand. |
| */ |
| protected final Vector<JavaResourceCompilationUnit> externalJavaResourceCompilationUnits = new Vector<JavaResourceCompilationUnit>(); |
| |
| /** |
| * The "external" Java resource persistent types (binary). Populated upon demand. |
| */ |
| protected final JavaResourcePersistentTypeCache externalJavaResourcePersistentTypeCache; |
| |
| /** |
| * Resource models notify this listener when they change. A project update |
| * should occur any time a resource model changes. |
| */ |
| protected final JpaResourceModelListener resourceModelListener; |
| |
| /** |
| * The root of the model representing the collated resources associated with |
| * the JPA project. |
| */ |
| protected final JpaRootContextNode rootContextNode; |
| |
| /** |
| * A pluggable updater that can be used to "update" the JPA project either |
| * synchronously or asynchronously (or not at all). A synchronous updater |
| * is the default, allowing a newly-constructed JPA project to be "updated" |
| * upon return from the constructor. For performance reasons, a UI should |
| * immediately change this to an asynchronous updater. A synchronous |
| * updater can be used when the project is being manipulated by a "batch" |
| * (or non-UI) client (e.g. when testing the "update" behavior). A null |
| * updater can used during tests that do not care whether "updates" occur. |
| * Clients will need to explicitly configure the updater if they require |
| * something other than a synchronous updater. |
| */ |
| protected Updater updater; |
| |
| /** |
| * The data source that wraps the DTP model. |
| */ |
| protected final JpaDataSource dataSource; |
| |
| /** |
| * A catalog name used to override the connection's default catalog. |
| */ |
| protected String userOverrideDefaultCatalog; |
| |
| /** |
| * A schema name used to override the connection's default schema. |
| */ |
| protected String userOverrideDefaultSchema; |
| |
| /** |
| * Flag indicating whether the project should "discover" annotated |
| * classes automatically, as opposed to requiring the classes to be |
| * listed in persistence.xml. |
| */ |
| protected boolean discoversAnnotatedClasses; |
| |
| /** |
| * Support for modifying documents shared with the UI. |
| */ |
| protected final ThreadLocalCommandExecutor modifySharedDocumentCommandExecutor; |
| |
| |
| // ********** constructor/initialization ********** |
| |
| public AbstractJpaProject(JpaProject.Config config) throws CoreException { |
| super(null); // JPA project is the root of the containment tree |
| if ((config.getProject() == null) || (config.getJpaPlatform() == null)) { |
| throw new NullPointerException(); |
| } |
| this.project = config.getProject(); |
| this.jpaPlatform = config.getJpaPlatform(); |
| this.dataSource = this.getJpaFactory().buildJpaDataSource(this, config.getConnectionProfileName()); |
| this.userOverrideDefaultCatalog = config.getUserOverrideDefaultCatalog(); |
| this.userOverrideDefaultSchema = config.getUserOverrideDefaultSchema(); |
| this.discoversAnnotatedClasses = config.discoverAnnotatedClasses(); |
| |
| this.modifySharedDocumentCommandExecutor = this.buildModifySharedDocumentCommandExecutor(); |
| |
| this.resourceModelListener = this.buildResourceModelListener(); |
| // build the JPA files corresponding to the Eclipse project's files |
| this.project.accept(this.buildInitialResourceProxyVisitor(), IResource.NONE); |
| |
| this.externalJavaResourcePersistentTypeCache = this.buildExternalJavaResourcePersistentTypeCache(); |
| |
| this.rootContextNode = this.buildRootContextNode(); |
| |
| // "update" the project before returning |
| this.setUpdater_(new SynchronousJpaProjectUpdater(this)); |
| |
| // start listening to this cache once the context model has been built |
| // and all the external types are faulted in |
| this.externalJavaResourcePersistentTypeCache.addResourceModelListener(this.resourceModelListener); |
| } |
| |
| @Override |
| protected boolean requiresParent() { |
| return false; |
| } |
| |
| @Override |
| public IResource getResource() { |
| return this.project; |
| } |
| |
| protected ThreadLocalCommandExecutor buildModifySharedDocumentCommandExecutor() { |
| return new ThreadLocalCommandExecutor(); |
| } |
| |
| protected JpaResourceModelListener buildResourceModelListener() { |
| return new DefaultResourceModelListener(); |
| } |
| |
| protected IResourceProxyVisitor buildInitialResourceProxyVisitor() { |
| return new InitialResourceProxyVisitor(); |
| } |
| |
| protected JavaResourcePersistentTypeCache buildExternalJavaResourcePersistentTypeCache() { |
| return new BinaryPersistentTypeCache(this.jpaPlatform.getAnnotationProvider()); |
| } |
| |
| protected JpaRootContextNode buildRootContextNode() { |
| return this.getJpaFactory().buildRootContextNode(this); |
| } |
| |
| // ***** inner class |
| protected class InitialResourceProxyVisitor implements IResourceProxyVisitor { |
| protected InitialResourceProxyVisitor() { |
| super(); |
| } |
| // add a JPA file for every [appropriate] file encountered by the visitor |
| public boolean visit(IResourceProxy resource) throws CoreException { |
| switch (resource.getType()) { |
| case IResource.ROOT : // shouldn't happen |
| return true; // visit children |
| case IResource.PROJECT : |
| return true; // visit children |
| case IResource.FOLDER : |
| return true; // visit children |
| case IResource.FILE : |
| AbstractJpaProject.this.addJpaFile_((IFile) resource.requestResource()); |
| return false; // no children |
| default : |
| return false; // no children |
| } |
| } |
| } |
| |
| |
| // ********** miscellaneous ********** |
| |
| /** |
| * Ignore changes to this collection. Adds can be ignored since they are triggered |
| * by requests that will, themselves, trigger updates (typically during the |
| * update of an object that calls a setter with the newly-created resource |
| * type). Deletes will be accompanied by manual updates. |
| */ |
| @Override |
| protected void addNonUpdateAspectNamesTo(Set<String> nonUpdateAspectNames) { |
| super.addNonUpdateAspectNamesTo(nonUpdateAspectNames); |
| nonUpdateAspectNames.add(EXTERNAL_JAVA_RESOURCE_COMPILATION_UNITS_COLLECTION); |
| } |
| |
| |
| // ********** general queries ********** |
| |
| @Override |
| public JpaProject getJpaProject() { |
| return this; |
| } |
| |
| public String getName() { |
| return this.project.getName(); |
| } |
| |
| @Override |
| public void toString(StringBuilder sb) { |
| sb.append(this.getName()); |
| } |
| |
| public IProject getProject() { |
| return this.project; |
| } |
| |
| public IJavaProject getJavaProject() { |
| return JavaCore.create(this.project); |
| } |
| |
| @Override |
| public JpaPlatform getJpaPlatform() { |
| return this.jpaPlatform; |
| } |
| |
| @SuppressWarnings("unchecked") |
| protected Iterable<JavaResourceCompilationUnit> getCombinedJavaResourceCompilationUnits() { |
| return new CompositeIterable<JavaResourceCompilationUnit>( |
| this.getInternalJavaResourceCompilationUnits(), |
| this.getExternalJavaResourceCompilationUnits() |
| ); |
| } |
| |
| |
| // ********** database ********** |
| |
| @Override |
| public JpaDataSource getDataSource() { |
| return this.dataSource; |
| } |
| |
| public ConnectionProfile getConnectionProfile() { |
| return this.dataSource.getConnectionProfile(); |
| } |
| |
| public Catalog getDefaultDbCatalog() { |
| String catalog = this.getDefaultCatalog(); |
| return (catalog == null) ? null : this.getDbCatalog(catalog); |
| } |
| |
| public String getDefaultCatalog() { |
| String catalog = this.getUserOverrideDefaultCatalog(); |
| return (catalog != null) ? catalog : this.getDatabaseDefaultCatalog(); |
| } |
| |
| protected String getDatabaseDefaultCatalog() { |
| Database db = this.getDatabase(); |
| return (db == null ) ? null : db.getDefaultCatalogIdentifier(); |
| } |
| |
| /** |
| * If we don't have a catalog (i.e. we don't even have a *default* catalog), |
| * then the database probably does not support catalogs; and we need to |
| * get the schema directly from the database. |
| */ |
| public SchemaContainer getDefaultDbSchemaContainer() { |
| String catalog = this.getDefaultCatalog(); |
| return (catalog != null) ? this.getDbCatalog(catalog) : this.getDatabase(); |
| } |
| |
| public Schema getDefaultDbSchema() { |
| SchemaContainer sc = this.getDefaultDbSchemaContainer(); |
| return (sc == null) ? null : sc.getSchemaForIdentifier(this.getDefaultSchema()); |
| } |
| |
| public String getDefaultSchema() { |
| String schema = this.getUserOverrideDefaultSchema(); |
| if (schema != null) { |
| return schema; |
| } |
| |
| String catalog = this.getDefaultCatalog(); |
| if (catalog == null) { |
| // if there is no default catalog (either user-override or database-determined), |
| // the database probably does not support catalogs; |
| // return the database's default schema |
| return this.getDatabaseDefaultSchema(); |
| } |
| |
| Catalog dbCatalog = this.getDbCatalog(catalog); |
| if (dbCatalog != null) { |
| return dbCatalog.getDefaultSchemaIdentifier(); |
| } |
| |
| // if we could not find a catalog on the database that matches the default |
| // catalog name, return the database's default schema(?) - hmmm |
| return this.getDatabaseDefaultSchema(); |
| } |
| |
| protected String getDatabaseDefaultSchema() { |
| Database db = this.getDatabase(); |
| return (db == null ) ? null : db.getDefaultSchemaIdentifier(); |
| } |
| |
| |
| // ********** user override default catalog ********** |
| |
| public String getUserOverrideDefaultCatalog() { |
| return this.userOverrideDefaultCatalog; |
| } |
| |
| public void setUserOverrideDefaultCatalog(String catalog) { |
| String old = this.userOverrideDefaultCatalog; |
| this.userOverrideDefaultCatalog = catalog; |
| JptCorePlugin.setUserOverrideDefaultCatalog(this.project, catalog); |
| this.firePropertyChanged(USER_OVERRIDE_DEFAULT_CATALOG_PROPERTY, old, catalog); |
| } |
| |
| |
| // ********** user override default schema ********** |
| |
| public String getUserOverrideDefaultSchema() { |
| return this.userOverrideDefaultSchema; |
| } |
| |
| public void setUserOverrideDefaultSchema(String schema) { |
| String old = this.userOverrideDefaultSchema; |
| this.userOverrideDefaultSchema = schema; |
| JptCorePlugin.setUserOverrideDefaultSchema(this.project, schema); |
| this.firePropertyChanged(USER_OVERRIDE_DEFAULT_SCHEMA_PROPERTY, old, schema); |
| } |
| |
| |
| // ********** discover annotated classes ********** |
| |
| public boolean discoversAnnotatedClasses() { |
| return this.discoversAnnotatedClasses; |
| } |
| |
| public void setDiscoversAnnotatedClasses(boolean discoversAnnotatedClasses) { |
| boolean old = this.discoversAnnotatedClasses; |
| this.discoversAnnotatedClasses = discoversAnnotatedClasses; |
| JptCorePlugin.setDiscoverAnnotatedClasses(this.project, discoversAnnotatedClasses); |
| this.firePropertyChanged(DISCOVERS_ANNOTATED_CLASSES_PROPERTY, old, discoversAnnotatedClasses); |
| } |
| |
| |
| // ********** JPA files ********** |
| |
| public Iterator<JpaFile> jpaFiles() { |
| return this.getJpaFiles().iterator(); |
| } |
| |
| protected Iterable<JpaFile> getJpaFiles() { |
| return new LiveCloneIterable<JpaFile>(this.jpaFiles); // read-only |
| } |
| |
| public int jpaFilesSize() { |
| return this.jpaFiles.size(); |
| } |
| |
| protected Iterable<JpaFile> getJpaFiles(final IContentType contentType) { |
| return new FilteringIterable<JpaFile, JpaFile>(this.getJpaFiles()) { |
| @Override |
| protected boolean accept(JpaFile jpaFile) { |
| return jpaFile.getContentType().isKindOf(contentType); |
| } |
| }; |
| } |
| |
| @Override |
| public JpaFile getJpaFile(IFile file) { |
| for (JpaFile jpaFile : this.getJpaFiles()) { |
| if (jpaFile.getFile().equals(file)) { |
| return jpaFile; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Add a JPA file for the specified file, if appropriate. |
| * Return true if a JPA File was created and added, false otherwise |
| */ |
| protected boolean addJpaFile(IFile file) { |
| JpaFile jpaFile = this.addJpaFile_(file); |
| if (jpaFile != null) { |
| this.fireItemAdded(JPA_FILES_COLLECTION, jpaFile); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Add a JPA file for the specified file, if appropriate, without firing |
| * an event; useful during construction. |
| * Return the new JPA file, null if it was not created. |
| */ |
| protected JpaFile addJpaFile_(IFile file) { |
| if ( ! this.getJavaProject().isOnClasspath(file)) { |
| return null; // the file must be on the Java classpath |
| } |
| |
| JpaFile jpaFile = this.getJpaPlatform().buildJpaFile(this, file); |
| if (jpaFile == null) { |
| return null; |
| } |
| jpaFile.getResourceModel().addResourceModelListener(this.resourceModelListener); |
| this.jpaFiles.add(jpaFile); |
| return jpaFile; |
| } |
| |
| /** |
| * Remove the JPA file corresponding to the specified IFile, if it exists. |
| * Return true if a JPA File was removed, false otherwise |
| */ |
| protected boolean removeJpaFile(IFile file) { |
| JpaFile jpaFile = this.getJpaFile(file); |
| if (jpaFile != null) { // a JpaFile is not added for every IFile |
| this.removeJpaFile(jpaFile); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Stop listening to the JPA file and remove it. |
| */ |
| protected void removeJpaFile(JpaFile jpaFile) { |
| jpaFile.getResourceModel().removeResourceModelListener(this.resourceModelListener); |
| if ( ! this.removeItemFromCollection(jpaFile, this.jpaFiles, JPA_FILES_COLLECTION)) { |
| throw new IllegalArgumentException(jpaFile.toString()); |
| } |
| } |
| |
| |
| // ********** external Java resource persistent types (source or binary) ********** |
| |
| protected JavaResourcePersistentType buildPersistableExternalJavaResourcePersistentType(String typeName) { |
| IType jdtType = this.findType(typeName); |
| return (jdtType == null) ? null : this.buildPersistableExternalJavaResourcePersistentType(jdtType); |
| } |
| |
| protected IType findType(String typeName) { |
| try { |
| return this.getJavaProject().findType(typeName); |
| } catch (JavaModelException ex) { |
| return null; // ignore exception? |
| } |
| } |
| |
| protected JavaResourcePersistentType buildPersistableExternalJavaResourcePersistentType(IType jdtType) { |
| JavaResourcePersistentType jrpt = this.buildExternalJavaResourcePersistentType(jdtType); |
| return ((jrpt != null) && jrpt.isPersistable()) ? jrpt : null; |
| } |
| |
| protected JavaResourcePersistentType buildExternalJavaResourcePersistentType(IType jdtType) { |
| return jdtType.isBinary() ? |
| this.buildBinaryExternalJavaResourcePersistentType(jdtType) : |
| this.buildSourceExternalJavaResourcePersistentType(jdtType); |
| } |
| |
| protected JavaResourcePersistentType buildBinaryExternalJavaResourcePersistentType(IType jdtType) { |
| return this.externalJavaResourcePersistentTypeCache.addPersistentType(jdtType); |
| } |
| |
| protected JavaResourcePersistentType buildSourceExternalJavaResourcePersistentType(IType jdtType) { |
| JavaResourceCompilationUnit jrcu = this.getExternalJavaResourceCompilationUnit(jdtType.getCompilationUnit()); |
| String jdtTypeName = jdtType.getFullyQualifiedName('.'); // JDT member type names use '$' |
| for (Iterator<JavaResourcePersistentType> stream = jrcu.persistentTypes(); stream.hasNext(); ) { |
| JavaResourcePersistentType jrpt = stream.next(); |
| if (jrpt.getQualifiedName().equals(jdtTypeName)) { |
| return jrpt; |
| } |
| } |
| // we can get here if the project JRE is removed; |
| // see SourceCompilationUnit#getPrimaryType(CompilationUnit) |
| // bug 225332 |
| return null; |
| } |
| |
| |
| // ********** external Java resource persistent types (binary) ********** |
| |
| public JavaResourcePersistentTypeCache getExternalJavaResourcePersistentTypeCache() { |
| return this.externalJavaResourcePersistentTypeCache; |
| } |
| |
| |
| // ********** external Java resource compilation units (source) ********** |
| |
| public Iterator<JavaResourceCompilationUnit> externalJavaResourceCompilationUnits() { |
| return this.getExternalJavaResourceCompilationUnits().iterator(); |
| } |
| |
| protected Iterable<JavaResourceCompilationUnit> getExternalJavaResourceCompilationUnits() { |
| return new LiveCloneIterable<JavaResourceCompilationUnit>(this.externalJavaResourceCompilationUnits); // read-only |
| } |
| |
| public int externalJavaResourceCompilationUnitsSize() { |
| return this.externalJavaResourceCompilationUnits.size(); |
| } |
| |
| /** |
| * Return the resource model compilation unit corresponding to the specified |
| * JDT compilation unit. If it does not exist, build it. |
| */ |
| protected JavaResourceCompilationUnit getExternalJavaResourceCompilationUnit(ICompilationUnit jdtCompilationUnit) { |
| for (JavaResourceCompilationUnit jrcu : this.getExternalJavaResourceCompilationUnits()) { |
| if (jrcu.getCompilationUnit().equals(jdtCompilationUnit)) { |
| // we will get here if the JRCU could not build its persistent type... |
| return jrcu; |
| } |
| } |
| return this.addExternalJavaResourceCompilationUnit(jdtCompilationUnit); |
| } |
| |
| /** |
| * Add an external Java resource compilation unit. |
| */ |
| protected JavaResourceCompilationUnit addExternalJavaResourceCompilationUnit(ICompilationUnit jdtCompilationUnit) { |
| JavaResourceCompilationUnit jrcu = this.buildJavaResourceCompilationUnit(jdtCompilationUnit); |
| this.addItemToCollection(jrcu, this.externalJavaResourceCompilationUnits, EXTERNAL_JAVA_RESOURCE_COMPILATION_UNITS_COLLECTION); |
| jrcu.addResourceModelListener(this.resourceModelListener); |
| return jrcu; |
| } |
| |
| protected JavaResourceCompilationUnit buildJavaResourceCompilationUnit(ICompilationUnit jdtCompilationUnit) { |
| return new SourceCompilationUnit( |
| jdtCompilationUnit, |
| this.jpaPlatform.getAnnotationProvider(), |
| this.jpaPlatform.getAnnotationEditFormatter(), |
| this.modifySharedDocumentCommandExecutor |
| ); |
| } |
| |
| protected boolean removeExternalJavaResourceCompilationUnit(IFile file) { |
| for (JavaResourceCompilationUnit jrcu : this.getExternalJavaResourceCompilationUnits()) { |
| if (jrcu.getFile().equals(file)) { |
| this.removeExternalJavaResourceCompilationUnit(jrcu); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| protected void removeExternalJavaResourceCompilationUnit(JavaResourceCompilationUnit jrcu) { |
| jrcu.removeResourceModelListener(this.resourceModelListener); |
| this.removeItemFromCollection(jrcu, this.externalJavaResourceCompilationUnits, EXTERNAL_JAVA_RESOURCE_COMPILATION_UNITS_COLLECTION); |
| } |
| |
| |
| // ********** context model ********** |
| |
| public JpaRootContextNode getRootContextNode() { |
| return this.rootContextNode; |
| } |
| |
| |
| // ********** utility ********** |
| |
| public IFile convertToPlatformFile(String fileName) { |
| return JptCorePlugin.getPlatformFile(this.project, fileName); |
| } |
| |
| |
| // ********** XML files ********** |
| |
| public JpaXmlResource getPersistenceXmlResource() { |
| return (JpaXmlResource) this.getResourceModel( |
| JptCorePlugin.DEFAULT_PERSISTENCE_XML_FILE_PATH, |
| JptCorePlugin.PERSISTENCE_FILE_CONTENT_TYPE |
| ); |
| } |
| |
| public JpaXmlResource getDefaultOrmXmlResource() { |
| return this.getMappingFileXmlResource(JptCorePlugin.DEFAULT_ORM_XML_FILE_PATH); |
| } |
| |
| public JpaXmlResource getMappingFileXmlResource(String fileName) { |
| return (JpaXmlResource) this.getResourceModel(fileName, JptCorePlugin.MAPPING_FILE_CONTENT_TYPE); |
| } |
| |
| /** |
| * If the specified file exists, is significant to the JPA project, and its |
| * content is a "kind of" the specified content type, return the JPA |
| * resource model corresponding to the file; otherwise, return null. |
| */ |
| protected JpaResourceModel getResourceModel(String fileName, IContentType contentType) { |
| IFile file = this.convertToPlatformFile(fileName); |
| return file.exists() ? this.getResourceModel(file, contentType) : null; |
| } |
| |
| /** |
| * If the specified file is significant to the JPA project and its content |
| * is a "kind of" the specified content type, return the JPA resource model |
| * corresponding to the file; otherwise, return null. |
| */ |
| protected JpaResourceModel getResourceModel(IFile file, IContentType contentType) { |
| JpaFile jpaFile = this.getJpaFile(file); |
| return (jpaFile == null) ? null : jpaFile.getResourceModel(contentType); |
| } |
| |
| |
| // ********** annotated Java source classes ********** |
| |
| public Iterator<String> annotatedClassNames() { |
| return this.getAnnotatedClassNames().iterator(); |
| } |
| |
| protected Iterable<String> getAnnotatedClassNames() { |
| return new TransformationIterable<JavaResourcePersistentType, String>(this.getPersistedInternalSourceJavaResourcePersistentTypes()) { |
| @Override |
| protected String transform(JavaResourcePersistentType jrpType) { |
| return jrpType.getQualifiedName(); |
| } |
| }; |
| } |
| |
| /** |
| * return only those valid "persisted" Java resource persistent types that are |
| * part of the JPA project, ignoring those in JARs referenced in persistence.xml |
| * @see org.eclipse.jpt.core.internal.utility.jdt.JPTTools#typeIsPersistable(org.eclipse.jpt.core.internal.utility.jdt.JPTTools.TypeAdapter) |
| */ |
| protected Iterable<JavaResourcePersistentType> getPersistedInternalSourceJavaResourcePersistentTypes() { |
| return new FilteringIterable<JavaResourcePersistentType, JavaResourcePersistentType>(this.getInternalSourceJavaResourcePersistentTypes()) { |
| @Override |
| protected boolean accept(JavaResourcePersistentType jrpType) { |
| return jrpType.isPersistable() && jrpType.isPersisted(); // i.e. the type is valid and has a type mapping annotation |
| } |
| }; |
| } |
| |
| /** |
| * return only those Java resource persistent types that are |
| * part of the JPA project, ignoring those in JARs referenced in persistence.xml |
| */ |
| protected Iterable<JavaResourcePersistentType> getInternalSourceJavaResourcePersistentTypes() { |
| return new CompositeIterable<JavaResourcePersistentType>(this.getInternalSourceJavaResourcePersistentTypeSets()); |
| } |
| |
| /** |
| * return only those Java resource persistent types that are |
| * part of the JPA project, ignoring those in JARs referenced in persistence.xml |
| */ |
| protected Iterable<Iterable<JavaResourcePersistentType>> getInternalSourceJavaResourcePersistentTypeSets() { |
| return new TransformationIterable<JavaResourceCompilationUnit, Iterable<JavaResourcePersistentType>>(this.getInternalJavaResourceCompilationUnits()) { |
| @Override |
| protected Iterable<JavaResourcePersistentType> transform(final JavaResourceCompilationUnit compilationUnit) { |
| return new Iterable<JavaResourcePersistentType>() { |
| public Iterator<JavaResourcePersistentType> iterator() { |
| return compilationUnit.persistentTypes(); // *all* the types in the compilation unit |
| } |
| }; |
| } |
| }; |
| } |
| |
| protected Iterable<JavaResourceCompilationUnit> getInternalJavaResourceCompilationUnits() { |
| return new TransformationIterable<JpaFile, JavaResourceCompilationUnit>(this.getJavaSourceJpaFiles()) { |
| @Override |
| protected JavaResourceCompilationUnit transform(JpaFile jpaFile) { |
| return (JavaResourceCompilationUnit) jpaFile.getResourceModel(); |
| } |
| }; |
| } |
| |
| /** |
| * return JPA files with Java source "content" |
| */ |
| protected Iterable<JpaFile> getJavaSourceJpaFiles() { |
| return this.getJpaFiles(JptCorePlugin.JAVA_SOURCE_CONTENT_TYPE); |
| } |
| |
| |
| // ********** Java resource persistent type look-up ********** |
| |
| public JavaResourcePersistentType getJavaResourcePersistentType(String typeName) { |
| for (JavaResourcePersistentType jrpType : this.getPersistableJavaResourcePersistentTypes()) { |
| if (jrpType.getQualifiedName().equals(typeName)) { |
| return jrpType; |
| } |
| } |
| // if we don't have a type already, try to build new one from the project classpath |
| return this.buildPersistableExternalJavaResourcePersistentType(typeName); |
| } |
| |
| /** |
| * return *all* the "persistable" Java resource persistent types, including those in JARs referenced in |
| * persistence.xml |
| * @see org.eclipse.jpt.core.internal.utility.jdt.JPTTools#typeIsPersistable(org.eclipse.jpt.core.internal.utility.jdt.JPTTools.TypeAdapter) |
| */ |
| protected Iterable<JavaResourcePersistentType> getPersistableJavaResourcePersistentTypes() { |
| return new FilteringIterable<JavaResourcePersistentType, JavaResourcePersistentType>(this.getJavaResourcePersistentTypes()) { |
| @Override |
| protected boolean accept(JavaResourcePersistentType jrpType) { |
| return jrpType.isPersistable(); |
| } |
| }; |
| } |
| |
| /** |
| * return *all* the Java resource persistent types, including those in JARs referenced in |
| * persistence.xml |
| */ |
| protected Iterable<JavaResourcePersistentType> getJavaResourcePersistentTypes() { |
| return new CompositeIterable<JavaResourcePersistentType>(this.getJavaResourcePersistentTypeSets()); |
| } |
| |
| /** |
| * return *all* the Java resource persistent types, including those in JARs referenced in |
| * persistence.xml |
| */ |
| protected Iterable<Iterable<JavaResourcePersistentType>> getJavaResourcePersistentTypeSets() { |
| return new TransformationIterable<JavaResourceNode.Root, Iterable<JavaResourcePersistentType>>(this.getJavaResourceNodeRoots()) { |
| @Override |
| protected Iterable<JavaResourcePersistentType> transform(final JavaResourceNode.Root root) { |
| return new Iterable<JavaResourcePersistentType>() { |
| public Iterator<JavaResourcePersistentType> iterator() { |
| return root.persistentTypes(); // *all* the types held by the root |
| } |
| }; |
| } |
| }; |
| } |
| |
| @SuppressWarnings("unchecked") |
| protected Iterable<JavaResourceNode.Root> getJavaResourceNodeRoots() { |
| return new CompositeIterable<JavaResourceNode.Root>( |
| this.getInternalJavaResourceCompilationUnits(), |
| this.getInternalJavaResourcePackageFragmentRoots(), |
| this.getExternalJavaResourceCompilationUnits(), |
| Collections.singleton(this.externalJavaResourcePersistentTypeCache) |
| ); |
| } |
| |
| |
| // ********** JARs ********** |
| |
| // TODO |
| public JavaResourcePackageFragmentRoot getJavaResourcePackageFragmentRoot(String jarFileName) { |
| // return this.getJarResourcePackageFragmentRoot(this.convertToPlatformFile(jarFileName)); |
| return this.getJavaResourcePackageFragmentRoot(this.getProject().getFile(jarFileName)); |
| } |
| |
| protected JavaResourcePackageFragmentRoot getJavaResourcePackageFragmentRoot(IFile jarFile) { |
| for (JavaResourcePackageFragmentRoot pfr : this.getInternalJavaResourcePackageFragmentRoots()) { |
| if (pfr.getFile().equals(jarFile)) { |
| return pfr; |
| } |
| } |
| return null; |
| } |
| |
| protected Iterable<JavaResourcePackageFragmentRoot> getInternalJavaResourcePackageFragmentRoots() { |
| return new TransformationIterable<JpaFile, JavaResourcePackageFragmentRoot>(this.getJarJpaFiles()) { |
| @Override |
| protected JavaResourcePackageFragmentRoot transform(JpaFile jpaFile) { |
| return (JavaResourcePackageFragmentRoot) jpaFile.getResourceModel(); |
| } |
| }; |
| } |
| |
| /** |
| * return JPA files with JAR "content" |
| */ |
| protected Iterable<JpaFile> getJarJpaFiles() { |
| return this.getJpaFiles(JptCorePlugin.JAR_CONTENT_TYPE); |
| } |
| |
| |
| // ********** Java events ********** |
| |
| // TODO handle changes to external projects |
| public void javaElementChanged(ElementChangedEvent event) { |
| this.synchWithJavaDelta(event.getDelta()); |
| } |
| |
| /** |
| * We recurse back here when processing 'affectedChildren'. |
| */ |
| protected void synchWithJavaDelta(IJavaElementDelta delta) { |
| switch (delta.getElement().getElementType()) { |
| case IJavaElement.JAVA_MODEL : |
| this.javaModelChanged(delta); |
| break; |
| case IJavaElement.JAVA_PROJECT : |
| this.javaProjectChanged(delta); |
| break; |
| case IJavaElement.PACKAGE_FRAGMENT_ROOT : |
| this.javaPackageFragmentRootChanged(delta); |
| break; |
| case IJavaElement.PACKAGE_FRAGMENT : |
| this.javaPackageFragmentChanged(delta); |
| break; |
| case IJavaElement.COMPILATION_UNIT : |
| this.javaCompilationUnitChanged(delta); |
| break; |
| default : |
| break; // ignore the elements inside a compilation unit |
| } |
| } |
| |
| protected void synchWithJavaDeltaChildren(IJavaElementDelta delta) { |
| for (IJavaElementDelta child : delta.getAffectedChildren()) { |
| this.synchWithJavaDelta(child); // recurse |
| } |
| } |
| |
| // ***** model |
| protected void javaModelChanged(IJavaElementDelta delta) { |
| // process the java model's projects |
| this.synchWithJavaDeltaChildren(delta); |
| } |
| |
| // ***** project |
| protected void javaProjectChanged(IJavaElementDelta delta) { |
| // process the java project's package fragment roots |
| this.synchWithJavaDeltaChildren(delta); |
| |
| if (this.classpathHasChanged(delta)) { |
| if (delta.getElement().equals(this.getJavaProject())) { |
| this.update(this.getInternalJavaResourceCompilationUnits()); |
| } else { |
| // TODO see if changed project is on our classpath? |
| this.update(this.getExternalJavaResourceCompilationUnits()); |
| } |
| } |
| } |
| |
| protected boolean classpathHasChanged(IJavaElementDelta delta) { |
| return BitTools.flagIsSet(delta.getFlags(), IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED); |
| } |
| |
| protected void update(Iterable<JavaResourceCompilationUnit> javaResourceCompilationUnits) { |
| for (JavaResourceCompilationUnit javaResourceCompilationUnit : javaResourceCompilationUnits) { |
| javaResourceCompilationUnit.update(); |
| } |
| } |
| |
| // ***** package fragment root |
| protected void javaPackageFragmentRootChanged(IJavaElementDelta delta) { |
| // process the java package fragment root's package fragments |
| this.synchWithJavaDeltaChildren(delta); |
| |
| if (this.classpathEntryHasBeenAdded(delta)) { |
| // TODO |
| } else if (this.classpathEntryHasBeenRemoved(delta)) { // should be mutually-exclusive w/added (?) |
| // TODO |
| } |
| } |
| |
| protected boolean classpathEntryHasBeenAdded(IJavaElementDelta delta) { |
| return BitTools.flagIsSet(delta.getFlags(), IJavaElementDelta.F_ADDED_TO_CLASSPATH); |
| } |
| |
| protected boolean classpathEntryHasBeenRemoved(IJavaElementDelta delta) { |
| return BitTools.flagIsSet(delta.getFlags(), IJavaElementDelta.F_REMOVED_FROM_CLASSPATH); |
| } |
| |
| // ***** package fragment |
| protected void javaPackageFragmentChanged(IJavaElementDelta delta) { |
| // process the java package fragment's compilation units |
| this.synchWithJavaDeltaChildren(delta); |
| } |
| |
| // ***** compilation unit |
| protected void javaCompilationUnitChanged(IJavaElementDelta delta) { |
| if (this.javaCompilationUnitDeltaIsRelevant(delta)) { |
| ICompilationUnit compilationUnit = (ICompilationUnit) delta.getElement(); |
| for (JavaResourceCompilationUnit jrcu : this.getCombinedJavaResourceCompilationUnits()) { |
| if (jrcu.getCompilationUnit().equals(compilationUnit)) { |
| jrcu.update(); |
| // TODO ? this.resolveJavaTypes(); // might have new member types now... |
| break; // there *shouldn't* be any more... |
| } |
| } |
| } |
| // ignore the java compilation unit's children |
| } |
| |
| protected boolean javaCompilationUnitDeltaIsRelevant(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; |
| } |
| |
| // ignore java notification for ADDED or REMOVED; |
| // these are handled via resource notification |
| return delta.getKind() == IJavaElementDelta.CHANGED; |
| } |
| |
| |
| // ********** validation ********** |
| |
| public Iterator<IMessage> validationMessages(IReporter reporter) { |
| List<IMessage> messages = new ArrayList<IMessage>(); |
| this.validate(messages, reporter); |
| return messages.iterator(); |
| } |
| |
| protected void validate(List<IMessage> messages, IReporter reporter) { |
| if (reporter.isCancelled()) { |
| throw new ValidationCancelledException(); |
| } |
| this.validateConnection(messages); |
| this.rootContextNode.validate(messages, reporter); |
| } |
| |
| protected void validateConnection(List<IMessage> messages) { |
| String cpName = this.dataSource.getConnectionProfileName(); |
| if (StringTools.stringIsEmpty(cpName)) { |
| messages.add( |
| DefaultJpaValidationMessages.buildMessage( |
| IMessage.NORMAL_SEVERITY, |
| JpaValidationMessages.PROJECT_NO_CONNECTION, |
| this |
| ) |
| ); |
| return; |
| } |
| ConnectionProfile cp = this.dataSource.getConnectionProfile(); |
| if (cp == null) { |
| messages.add( |
| DefaultJpaValidationMessages.buildMessage( |
| IMessage.NORMAL_SEVERITY, |
| JpaValidationMessages.PROJECT_INVALID_CONNECTION, |
| new String[] {cpName}, |
| this |
| ) |
| ); |
| return; |
| } |
| if (cp.isInactive()) { |
| messages.add( |
| DefaultJpaValidationMessages.buildMessage( |
| IMessage.NORMAL_SEVERITY, |
| JpaValidationMessages.PROJECT_INACTIVE_CONNECTION, |
| new String[] {cpName}, |
| this |
| ) |
| ); |
| } |
| } |
| |
| |
| // ********** dispose ********** |
| |
| public void dispose() { |
| this.updater.stop(); |
| this.dataSource.dispose(); |
| } |
| |
| |
| // ********** resource model listener ********** |
| |
| protected class DefaultResourceModelListener implements JpaResourceModelListener { |
| protected DefaultResourceModelListener() { |
| super(); |
| } |
| public void resourceModelChanged() { |
| AbstractJpaProject.this.update(); |
| } |
| } |
| |
| |
| // ********** resource events ********** |
| |
| // TODO need to do the same thing for external projects and compilation units |
| public void projectChanged(IResourceDelta delta) throws CoreException { |
| if (delta.getResource().equals(this.getProject())) { |
| this.internalProjectChanged(delta); |
| } else { |
| this.externalProjectChanged(delta); |
| } |
| } |
| |
| protected void internalProjectChanged(IResourceDelta delta) throws CoreException { |
| ResourceDeltaVisitor resourceDeltaVisitor = this.buildInternalResourceDeltaVisitor(); |
| delta.accept(resourceDeltaVisitor); |
| // at this point, if we have added and/or removed JpaFiles, an "update" will have been triggered; |
| // any changes to the resource model during the "resolve" will trigger further "updates"; |
| // there should be no need to "resolve" external Java types (they can't have references to |
| // the internal Java types) |
| if (resourceDeltaVisitor.encounteredSignificantChange()) { |
| this.resolveInternalJavaTypes(); |
| } |
| } |
| |
| protected ResourceDeltaVisitor buildInternalResourceDeltaVisitor() { |
| return new ResourceDeltaVisitor() { |
| @Override |
| public boolean fileChangeIsSignificant(IFile file, int deltaKind) { |
| return AbstractJpaProject.this.synchronizeJpaFiles(file, deltaKind); |
| } |
| }; |
| } |
| |
| /** |
| * Internal resource delta visitor callback. |
| * Return true if a JpaFile was either added or removed. |
| */ |
| protected boolean synchronizeJpaFiles(IFile file, int deltaKind) { |
| switch (deltaKind) { |
| case IResourceDelta.ADDED : |
| return this.addJpaFile(file); |
| case IResourceDelta.REMOVED : |
| return this.removeJpaFile(file); |
| case IResourceDelta.CHANGED : |
| return this.checkForChangedFileContent(file); |
| case IResourceDelta.ADDED_PHANTOM : |
| break; // ignore |
| case IResourceDelta.REMOVED_PHANTOM : |
| break; // ignore |
| default : |
| break; // only worried about added/removed/changed files |
| } |
| |
| return false; |
| } |
| |
| protected boolean checkForChangedFileContent(IFile file) { |
| JpaFile jpaFile = this.getJpaFile(file); |
| if (jpaFile == null) { |
| // the file might have changed its content to something that we are interested in |
| return this.addJpaFile(file); |
| } |
| |
| if (jpaFile.getContentType().equals(PlatformTools.getContentType(file))) { |
| // content has not changed - ignore |
| return false; |
| } |
| |
| // the content type changed, we need to build a new JPA file |
| // (e.g. the schema of an orm.xml file changed from JPA to EclipseLink) |
| this.removeJpaFile(jpaFile); |
| this.addJpaFile(file); |
| return true; // at the least, we have removed a JPA file |
| } |
| |
| protected void resolveInternalJavaTypes() { |
| for (JavaResourceCompilationUnit jrcu : this.getInternalJavaResourceCompilationUnits()) { |
| jrcu.resolveTypes(); |
| } |
| } |
| |
| protected void externalProjectChanged(IResourceDelta delta) throws CoreException { |
| if (this.getJavaProject().isOnClasspath(delta.getResource())) { |
| ResourceDeltaVisitor resourceDeltaVisitor = this.buildExternalResourceDeltaVisitor(); |
| delta.accept(resourceDeltaVisitor); |
| // force an "update" here since adding and/or removing an external Java type |
| // will only trigger an "update" if the "resolve" causes something in the resource model to change |
| if (resourceDeltaVisitor.encounteredSignificantChange()) { |
| this.update(); |
| this.resolveExternalJavaTypes(); |
| this.resolveInternalJavaTypes(); |
| } |
| } |
| } |
| |
| protected ResourceDeltaVisitor buildExternalResourceDeltaVisitor() { |
| return new ResourceDeltaVisitor() { |
| @Override |
| public boolean fileChangeIsSignificant(IFile file, int deltaKind) { |
| return AbstractJpaProject.this.synchronizeExternalFiles(file, deltaKind); |
| } |
| }; |
| } |
| |
| /** |
| * external resource delta visitor callback |
| * Return true if an "external" Java resource compilation unit |
| * was added or removed. |
| */ |
| protected boolean synchronizeExternalFiles(IFile file, int deltaKind) { |
| switch (deltaKind) { |
| case IResourceDelta.ADDED : |
| return this.externalFileAdded(file); |
| case IResourceDelta.REMOVED : |
| return this.externalFileRemoved(file); |
| case IResourceDelta.CHANGED : |
| break; // ignore |
| case IResourceDelta.ADDED_PHANTOM : |
| break; // ignore |
| case IResourceDelta.REMOVED_PHANTOM : |
| break; // ignore |
| default : |
| break; // only worried about added/removed/changed files |
| } |
| |
| return false; |
| } |
| |
| protected boolean externalFileAdded(IFile file) { |
| IContentType contentType = PlatformTools.getContentType(file); |
| if (contentType == null) { |
| return false; |
| } |
| if (contentType.equals(JptCorePlugin.JAVA_SOURCE_CONTENT_TYPE)) { |
| return true; |
| } |
| if (contentType.equals(JptCorePlugin.JAR_CONTENT_TYPE)) { |
| return true; |
| } |
| return false; |
| } |
| |
| protected boolean externalFileRemoved(IFile file) { |
| IContentType contentType = PlatformTools.getContentType(file); |
| if (contentType == null) { |
| return false; |
| } |
| if (contentType.equals(JptCorePlugin.JAVA_SOURCE_CONTENT_TYPE)) { |
| return this.removeExternalJavaResourceCompilationUnit(file); |
| } |
| if (contentType.equals(JptCorePlugin.JAR_CONTENT_TYPE)) { |
| return this.externalJavaResourcePersistentTypeCache.removePersistentTypes(file); |
| } |
| return false; |
| } |
| |
| protected void resolveExternalJavaTypes() { |
| for (JavaResourceCompilationUnit jrcu : this.getExternalJavaResourceCompilationUnits()) { |
| jrcu.resolveTypes(); |
| } |
| } |
| |
| // ***** resource delta visitors |
| /** |
| * add or remove a JPA file for every [appropriate] file encountered by the visitor |
| */ |
| protected abstract class ResourceDeltaVisitor implements IResourceDeltaVisitor { |
| protected boolean encounteredSignificantChange = false; |
| |
| protected ResourceDeltaVisitor() { |
| super(); |
| } |
| |
| public boolean visit(IResourceDelta delta) throws CoreException { |
| IResource res = delta.getResource(); |
| switch (res.getType()) { |
| case IResource.ROOT : |
| return true; // visit children |
| case IResource.PROJECT : |
| return true; // visit children |
| case IResource.FOLDER : |
| return true; // visit children |
| case IResource.FILE : |
| this.fileChanged((IFile) res, delta.getKind()); |
| return false; // no children |
| default : |
| return false; // no children (probably shouldn't get here...) |
| } |
| } |
| |
| protected void fileChanged(IFile file, int deltaKind) { |
| if (this.fileChangeIsSignificant(file, deltaKind)) { |
| this.encounteredSignificantChange = true; |
| } |
| } |
| |
| protected abstract boolean fileChangeIsSignificant(IFile file, int deltaKind); |
| |
| /** |
| * Return whether the visitor encountered some sort of "significant" |
| * change while traversing the IResourceDelta |
| * (e.g. a JPA file was added or removed). |
| */ |
| protected boolean encounteredSignificantChange() { |
| return this.encounteredSignificantChange; |
| } |
| |
| } |
| |
| |
| // ********** support for modifying documents shared with the UI ********** |
| |
| public void setThreadLocalModifySharedDocumentCommandExecutor(CommandExecutor commandExecutor) { |
| this.modifySharedDocumentCommandExecutor.set(commandExecutor); |
| } |
| |
| public CommandExecutor getModifySharedDocumentCommandExecutor() { |
| return this.modifySharedDocumentCommandExecutor; |
| } |
| |
| |
| // ********** project "update" ********** |
| |
| public Updater getUpdater() { |
| return this.updater; |
| } |
| |
| public void setUpdater(Updater updater) { |
| if (updater == null) { |
| throw new NullPointerException(); |
| } |
| this.updater.stop(); |
| this.setUpdater_(updater); |
| } |
| |
| protected void setUpdater_(Updater updater) { |
| this.updater = updater; |
| this.updater.start(); |
| } |
| |
| /** |
| * Delegate to the updater so clients can configure how updates occur. |
| */ |
| public void update() { |
| this.updater.update(); |
| } |
| |
| /** |
| * Called by the updater. |
| */ |
| public IStatus update(IProgressMonitor monitor) { |
| try { |
| this.rootContextNode.update(monitor); |
| } catch (OperationCanceledException ex) { |
| return Status.CANCEL_STATUS; |
| } catch (Throwable ex) { |
| // Exceptions can occur when the update is running and changes are |
| // made concurrently to the Java source. When that happens, our |
| // model might be in an inconsistent state because it is not yet in |
| // sync with the changed Java source. |
| // Log these exceptions and assume they won't happen when the |
| // update runs again as a result of the concurrent Java source changes. |
| JptCorePlugin.log(ex); |
| } |
| this.rootContextNode.postUpdate(); |
| return Status.OK_STATUS; |
| } |
| |
| } |