| /******************************************************************************* |
| * Copyright (c) 2010, 2011 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.jaxb.core.internal; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| 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.NullProgressMonitor; |
| 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.IPackageDeclaration; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jpt.common.core.JptCommonCorePlugin; |
| import org.eclipse.jpt.common.core.JptResourceModel; |
| import org.eclipse.jpt.common.core.JptResourceModelListener; |
| import org.eclipse.jpt.common.core.internal.utility.PlatformTools; |
| import org.eclipse.jpt.common.core.resource.ResourceLocator; |
| import org.eclipse.jpt.common.core.resource.java.JavaResourceAbstractType; |
| import org.eclipse.jpt.common.core.resource.java.JavaResourceCompilationUnit; |
| import org.eclipse.jpt.common.core.resource.java.JavaResourceNode; |
| import org.eclipse.jpt.common.core.resource.java.JavaResourcePackage; |
| import org.eclipse.jpt.common.core.resource.java.JavaResourcePackageInfoCompilationUnit; |
| import org.eclipse.jpt.common.utility.Command; |
| import org.eclipse.jpt.common.utility.CommandExecutor; |
| import org.eclipse.jpt.common.utility.internal.BitTools; |
| import org.eclipse.jpt.common.utility.internal.NotNullFilter; |
| import org.eclipse.jpt.common.utility.internal.ThreadLocalCommandExecutor; |
| import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.CompositeIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.EmptyIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.FilteringIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.LiveCloneIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.SnapshotCloneIterable; |
| import org.eclipse.jpt.common.utility.internal.iterables.TransformationIterable; |
| import org.eclipse.jpt.common.utility.internal.synchronizers.CallbackSynchronousSynchronizer; |
| import org.eclipse.jpt.common.utility.internal.synchronizers.SynchronousSynchronizer; |
| import org.eclipse.jpt.common.utility.synchronizers.CallbackSynchronizer; |
| import org.eclipse.jpt.common.utility.synchronizers.Synchronizer; |
| import org.eclipse.jpt.jaxb.core.JaxbFacet; |
| import org.eclipse.jpt.jaxb.core.JaxbFile; |
| import org.eclipse.jpt.jaxb.core.JaxbProject; |
| import org.eclipse.jpt.jaxb.core.JptJaxbCorePlugin; |
| import org.eclipse.jpt.jaxb.core.SchemaLibrary; |
| import org.eclipse.jpt.jaxb.core.context.JaxbContextRoot; |
| import org.eclipse.jpt.jaxb.core.context.JaxbPackage; |
| import org.eclipse.jpt.jaxb.core.context.JaxbPackageInfo; |
| import org.eclipse.jpt.jaxb.core.context.JaxbType; |
| import org.eclipse.jpt.jaxb.core.context.java.JavaContextNode; |
| import org.eclipse.jpt.jaxb.core.internal.platform.JaxbPlatformImpl; |
| import org.eclipse.jpt.jaxb.core.internal.validation.DefaultValidationMessages; |
| import org.eclipse.jpt.jaxb.core.internal.validation.JaxbValidationMessages; |
| import org.eclipse.jpt.jaxb.core.libprov.JaxbLibraryProviderInstallOperationConfig; |
| import org.eclipse.jpt.jaxb.core.platform.JaxbPlatform; |
| import org.eclipse.jpt.jaxb.core.resource.jaxbindex.JaxbIndexResource; |
| import org.eclipse.jpt.jaxb.core.resource.jaxbprops.JaxbPropertiesResource; |
| import org.eclipse.jst.common.project.facet.core.libprov.ILibraryProvider; |
| import org.eclipse.jst.common.project.facet.core.libprov.LibraryInstallDelegate; |
| import org.eclipse.jst.j2ee.model.internal.validation.ValidationCancelledException; |
| import org.eclipse.wst.common.project.facet.core.IFacetedProject; |
| import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion; |
| import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager; |
| import org.eclipse.wst.validation.internal.provisional.core.IMessage; |
| import org.eclipse.wst.validation.internal.provisional.core.IReporter; |
| |
| /** |
| * JAXB project. Holds all the JAXB stuff. |
| * |
| * The JAXB platform provides the hooks for vendor-specific stuff. |
| * |
| * The JAXB 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 JAXB spec, using the "resource" model as an adapter to the Eclipse |
| * resources). |
| */ |
| public abstract class AbstractJaxbProject |
| extends AbstractJaxbNode |
| implements JaxbProject { |
| |
| /** |
| * The Eclipse project corresponding to the JAXB project. |
| */ |
| protected final IProject project; |
| |
| /** |
| * The vendor-specific JAXB platform that builds the JAXB project |
| * and all its contents. |
| */ |
| protected final JaxbPlatform jaxbPlatform; |
| |
| /** |
| * The library of schemas associated with this project |
| */ |
| protected final SchemaLibraryImpl schemaLibrary; |
| |
| /** |
| * The JAXB files associated with the JAXB project: |
| * java |
| * jaxb.index |
| * platform-specific files |
| */ |
| protected final Vector<JaxbFile> jaxbFiles = new Vector<JaxbFile>(); |
| |
| // /** |
| // * 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 JptResourceModelListener resourceModelListener; |
| |
| /** |
| * The root of the model representing the collated resources associated with |
| * the JAXB project. |
| */ |
| protected final JaxbContextRoot contextRoot; |
| |
| /** |
| * A pluggable synchronizer that keeps the JAXB |
| * project's context model synchronized with its resource model, either |
| * synchronously or asynchronously (or not at all). A synchronous synchronizer |
| * is the default. For performance reasons, a UI should |
| * immediately change this to an asynchronous synchronizer. A synchronous |
| * synchronizer can be used when the project is being manipulated by a "batch" |
| * (or non-UI) client (e.g. when testing "synchronization"). A null updater |
| * can used during tests that do not care whether "synchronization" occur. |
| * Clients will need to explicitly configure the synchronizer if they require |
| * an asynchronous synchronizer. |
| */ |
| protected volatile Synchronizer contextModelSynchronizer; |
| protected volatile boolean synchronizingContextModel = false; |
| |
| /** |
| * A pluggable synchronizer that "updates" the JAXB project, either |
| * synchronously or asynchronously (or not at all). A synchronous updater |
| * is the default, allowing a newly-constructed JAXB 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 "synchronization" |
| * occur. |
| * Clients will need to explicitly configure the updater if they require |
| * an asynchronous updater. |
| */ |
| protected volatile CallbackSynchronizer updateSynchronizer; |
| protected final CallbackSynchronizer.Listener updateSynchronizerListener; |
| |
| /** |
| * Support for modifying documents shared with the UI. |
| */ |
| protected final ThreadLocalCommandExecutor modifySharedDocumentCommandExecutor; |
| |
| |
| // ********** constructor/initialization ********** |
| |
| protected AbstractJaxbProject(JaxbProject.Config config) { |
| super(null); // JPA project is the root of the containment tree |
| if ((config.getProject() == null) || (config.getPlatformDefinition() == null)) { |
| throw new NullPointerException(); |
| } |
| this.project = config.getProject(); |
| this.jaxbPlatform = new JaxbPlatformImpl(config.getPlatformDefinition()); |
| |
| this.schemaLibrary = new SchemaLibraryImpl(this); |
| |
| this.modifySharedDocumentCommandExecutor = this.buildModifySharedDocumentCommandExecutor(); |
| |
| this.resourceModelListener = this.buildResourceModelListener(); |
| // build the JPA files corresponding to the Eclipse project's files |
| InitialResourceProxyVisitor visitor = this.buildInitialResourceProxyVisitor(); |
| visitor.visitProject(this.project); |
| |
| // this.externalJavaResourcePersistentTypeCache = this.buildExternalJavaResourcePersistentTypeCache(); |
| |
| this.contextRoot = this.buildContextRoot(); |
| |
| // there *shouldn't* be any changes to the resource model... |
| this.setContextModelSynchronizer_(this.buildSynchronousContextModelSynchronizer()); |
| |
| this.updateSynchronizerListener = this.buildUpdateSynchronizerListener(); |
| // "update" the project before returning |
| this.setUpdateSynchronizer_(this.buildSynchronousUpdateSynchronizer()); |
| |
| // // 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 InitialResourceProxyVisitor buildInitialResourceProxyVisitor() { |
| return new InitialResourceProxyVisitor(); |
| } |
| // |
| // protected JavaResourcePersistentTypeCache buildExternalJavaResourcePersistentTypeCache() { |
| // return new BinaryPersistentTypeCache(this.jpaPlatform.getAnnotationProvider()); |
| // } |
| |
| protected JaxbContextRoot buildContextRoot() { |
| return this.getFactory().buildContextRoot(this); |
| } |
| |
| // ***** inner class |
| protected class InitialResourceProxyVisitor implements IResourceProxyVisitor { |
| protected InitialResourceProxyVisitor() { |
| super(); |
| } |
| protected void visitProject(IProject p) { |
| try { |
| p.accept(this, IResource.NONE); |
| } catch (CoreException ex) { |
| // shouldn't happen - we don't throw any CoreExceptions |
| throw new RuntimeException(ex); |
| } |
| } |
| // add a JPA file for every [appropriate] file encountered by the visitor |
| public boolean visit(IResourceProxy resource) { |
| 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 : |
| AbstractJaxbProject.this.addJaxbFile_((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 JaxbProject getJaxbProject() { |
| 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 JaxbPlatform getPlatform() { |
| return this.jaxbPlatform; |
| } |
| |
| public SchemaLibrary getSchemaLibrary() { |
| return this.schemaLibrary; |
| } |
| |
| @SuppressWarnings("unchecked") |
| protected Iterable<JavaResourceCompilationUnit> getCombinedJavaResourceCompilationUnits() { |
| return this.getInternalJavaResourceCompilationUnits(); |
| // return new CompositeIterable<JavaResourceCompilationUnit>( |
| // this.getInternalJavaResourceCompilationUnits(), |
| // this.getExternalJavaResourceCompilationUnits() |
| // ); |
| } |
| |
| |
| // ********** JAXB files ********** |
| |
| public Iterable<JaxbFile> getJaxbFiles() { |
| return new LiveCloneIterable<JaxbFile>(this.jaxbFiles); // read-only |
| } |
| |
| public int getJaxbFilesSize() { |
| return this.jaxbFiles.size(); |
| } |
| |
| protected Iterable<JaxbFile> getJaxbFiles(final IContentType contentType) { |
| return new FilteringIterable<JaxbFile>(this.getJaxbFiles()) { |
| @Override |
| protected boolean accept(JaxbFile jaxbFile) { |
| return jaxbFile.getContentType().isKindOf(contentType); |
| } |
| }; |
| } |
| |
| @Override |
| public JaxbFile getJaxbFile(IFile file) { |
| for (JaxbFile jaxbFile : this.getJaxbFiles()) { |
| if (jaxbFile.getFile().equals(file)) { |
| return jaxbFile; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Add a JAXB file for the specified file, if appropriate. |
| * Return true if a JAXB File was created and added, false otherwise |
| */ |
| protected boolean addJaxbFile(IFile file) { |
| JaxbFile jaxbFile = this.addJaxbFile_(file); |
| if (jaxbFile != null) { |
| this.fireItemAdded(JAXB_FILES_COLLECTION, jaxbFile); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Add a JAXB file for the specified file, if appropriate, without firing |
| * an event; useful during construction. |
| * Return the new JAXB file, null if it was not created. |
| */ |
| protected JaxbFile addJaxbFile_(IFile file) { |
| if (isJavaFile(file)) { |
| if (! getJavaProject().isOnClasspath(file)) { |
| // a java (.jar or .java) file must be on the Java classpath |
| return null; |
| } |
| } |
| else if (! isInAcceptableResourceLocation(file)) { |
| return null; |
| } |
| |
| JaxbFile jaxbFile = null; |
| try { |
| jaxbFile = this.getPlatform().buildJaxbFile(this, file); |
| } |
| catch (Exception e) { |
| //log any developer exceptions and don't build a JaxbFile rather |
| //than completely failing to build the JaxbProject |
| JptJaxbCorePlugin.log(e); |
| } |
| if (jaxbFile == null) { |
| return null; |
| } |
| jaxbFile.getResourceModel().addResourceModelListener(this.resourceModelListener); |
| this.jaxbFiles.add(jaxbFile); |
| return jaxbFile; |
| } |
| |
| /* file is .java or .jar */ |
| protected boolean isJavaFile(IFile file) { |
| IContentType contentType = PlatformTools.getContentType(file); |
| return contentType != null |
| && (contentType.isKindOf(JptCommonCorePlugin.JAVA_SOURCE_CONTENT_TYPE) |
| || contentType.isKindOf(JptCommonCorePlugin.JAR_CONTENT_TYPE)); |
| } |
| |
| /* (non-java resource) file is in acceptable resource location */ |
| protected boolean isInAcceptableResourceLocation(IFile file) { |
| ResourceLocator resourceLocator = JptCommonCorePlugin.getResourceLocator(getProject()); |
| return resourceLocator.acceptResourceLocation(getProject(), file.getParent()); |
| } |
| |
| /** |
| * Remove the JAXB file corresponding to the specified IFile, if it exists. |
| * Return true if a JAXB File was removed, false otherwise |
| */ |
| protected boolean removeJaxbFile(IFile file) { |
| JaxbFile jaxbFile = this.getJaxbFile(file); |
| if (jaxbFile != null) { // a JpaFile is not added for every IFile |
| this.removeJaxbFile(jaxbFile); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Stop listening to the JAXB file and remove it. |
| */ |
| protected void removeJaxbFile(JaxbFile jaxbFile) { |
| jaxbFile.getResourceModel().removeResourceModelListener(this.resourceModelListener); |
| if ( ! this.removeItemFromCollection(jaxbFile, this.jaxbFiles, JAXB_FILES_COLLECTION)) { |
| throw new IllegalArgumentException(jaxbFile.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 SourceTypeCompilationUnit( |
| // 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 JaxbContextRoot getContextRoot() { |
| return this.contextRoot; |
| } |
| |
| public Iterable<? extends JavaContextNode> getPrimaryJavaNodes(ICompilationUnit cu) { |
| IFile file = getCorrespondingResource(cu); |
| if (file == null) { |
| return EmptyIterable.instance(); |
| } |
| |
| IContentType contentType = PlatformTools.getContentType(file); |
| if (contentType == null) { |
| return EmptyIterable.instance(); |
| } |
| |
| if (contentType.isKindOf(JptCommonCorePlugin.JAVA_SOURCE_PACKAGE_INFO_CONTENT_TYPE)) { |
| try { |
| return new FilteringIterable<JaxbPackageInfo>( |
| new TransformationIterable<IPackageDeclaration, JaxbPackageInfo>( |
| new ArrayIterable<IPackageDeclaration>(cu.getPackageDeclarations())) { |
| @Override |
| protected JaxbPackageInfo transform(IPackageDeclaration o) { |
| JaxbPackage jaxbPackage = getContextRoot().getPackage(o.getElementName()); |
| return (jaxbPackage != null) ? jaxbPackage.getPackageInfo() : null; |
| } |
| }, |
| NotNullFilter.<JaxbPackageInfo>instance()); |
| } |
| catch (JavaModelException jme) { |
| return EmptyIterable.instance(); |
| } |
| } |
| else if (contentType.isKindOf(JptCommonCorePlugin.JAVA_SOURCE_CONTENT_TYPE)) { |
| try { |
| return new FilteringIterable<JaxbType>( |
| new TransformationIterable<IType, JaxbType>( |
| new ArrayIterable<IType>(cu.getAllTypes())) { |
| @Override |
| protected JaxbType transform(IType o) { |
| JaxbType jaxbType = getContextRoot().getType(o.getFullyQualifiedName('.')); |
| return jaxbType; |
| } |
| }, |
| NotNullFilter.<JaxbType>instance()); |
| } |
| catch (JavaModelException jme) { |
| return EmptyIterable.instance(); |
| } |
| } |
| |
| return EmptyIterable.instance(); |
| } |
| |
| private IFile getCorrespondingResource(ICompilationUnit cu) { |
| try { |
| return (IFile) cu.getCorrespondingResource(); |
| } |
| catch (JavaModelException ex) { |
| JptJaxbCorePlugin.log(ex); |
| return null; |
| } |
| } |
| |
| |
| // // ********** utility ********** |
| // |
| // public IFile getPlatformFile(IPath runtimePath) { |
| // return JptCorePlugin.getPlatformFile(this.project, runtimePath); |
| // } |
| |
| |
| // |
| // /** |
| // * 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(IPath runtimePath, IContentType contentType) { |
| // IFile file = this.getPlatformFile(runtimePath); |
| // 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 Iterable<JavaResourceAbstractType> getJavaSourceResourceTypes() { |
| return new CompositeIterable<JavaResourceAbstractType>(this.getInternalJavaSourceResourceTypeSets()); |
| } |
| |
| public Iterable<JavaResourceAbstractType> getAnnotatedJavaSourceResourceTypes() { |
| return new FilteringIterable<JavaResourceAbstractType>(getJavaSourceResourceTypes()) { |
| @Override |
| protected boolean accept(JavaResourceAbstractType type) { |
| return type.isAnnotated(); |
| } |
| }; |
| } |
| |
| // public Iterable<String> getAnnotatedJavaSourceClassNames() { |
| // return new TransformationIterable<JavaResourceType, String>(this.getInternalAnnotatedSourceJavaResourceTypes()) { |
| // @Override |
| // protected String transform(JavaResourceType type) { |
| // return type.getQualifiedName(); |
| // } |
| // }; |
| // } |
| |
| /* |
| * Return the sets of {@link JavaResourceType}s that are represented by java source within this project |
| */ |
| protected Iterable<Iterable<JavaResourceAbstractType>> getInternalJavaSourceResourceTypeSets() { |
| return new TransformationIterable<JavaResourceCompilationUnit, Iterable<JavaResourceAbstractType>>( |
| this.getInternalJavaResourceCompilationUnits()) { |
| @Override |
| protected Iterable<JavaResourceAbstractType> transform(JavaResourceCompilationUnit compilationUnit) { |
| return compilationUnit.getTypes(); |
| } |
| }; |
| } |
| |
| protected Iterable<JavaResourceCompilationUnit> getInternalJavaResourceCompilationUnits() { |
| return new TransformationIterable<JaxbFile, JavaResourceCompilationUnit>(this.getJavaSourceJaxbFiles()) { |
| @Override |
| protected JavaResourceCompilationUnit transform(JaxbFile jaxbFile) { |
| return (JavaResourceCompilationUnit) jaxbFile.getResourceModel(); |
| } |
| }; |
| } |
| |
| /** |
| * return JAXB files with Java source "content" |
| */ |
| protected Iterable<JaxbFile> getJavaSourceJaxbFiles() { |
| return this.getJaxbFiles(JptCommonCorePlugin.JAVA_SOURCE_CONTENT_TYPE); |
| } |
| |
| |
| // ********** Java resource package look-up ********** |
| |
| public Iterable<JavaResourcePackage> getJavaResourcePackages(){ |
| return new FilteringIterable<JavaResourcePackage>( |
| new TransformationIterable<JaxbFile, JavaResourcePackage>(this.getPackageInfoSourceJaxbFiles()) { |
| @Override |
| protected JavaResourcePackage transform(JaxbFile jaxbFile) { |
| return ((JavaResourcePackageInfoCompilationUnit) jaxbFile.getResourceModel()).getPackage(); |
| } |
| }) { |
| |
| @Override |
| protected boolean accept(JavaResourcePackage resourcePackage) { |
| return resourcePackage != null; |
| } |
| }; |
| } |
| |
| public JavaResourcePackage getJavaResourcePackage(String packageName) { |
| for (JavaResourcePackage jrp : this.getJavaResourcePackages()) { |
| if (jrp.getName().equals(packageName)) { |
| return jrp; |
| } |
| } |
| return null; |
| } |
| |
| public Iterable<JavaResourcePackage> getAnnotatedJavaResourcePackages() { |
| return new FilteringIterable<JavaResourcePackage>(this.getJavaResourcePackages()) { |
| @Override |
| protected boolean accept(JavaResourcePackage resourcePackage) { |
| return resourcePackage.isAnnotated(); // i.e. the package has a valid package annotation |
| } |
| }; |
| } |
| |
| public JavaResourcePackage getAnnotatedJavaResourcePackage(String packageName) { |
| JavaResourcePackage jrp = getJavaResourcePackage(packageName); |
| return (jrp != null && jrp.isAnnotated()) ? jrp : null; |
| } |
| |
| /** |
| * return JPA files with package-info source "content" |
| */ |
| protected Iterable<JaxbFile> getPackageInfoSourceJaxbFiles() { |
| return this.getJaxbFiles(JptCommonCorePlugin.JAVA_SOURCE_PACKAGE_INFO_CONTENT_TYPE); |
| } |
| |
| |
| // ********** Java resource type look-up ********** |
| |
| |
| public JavaResourceAbstractType getJavaResourceType(String typeName) { |
| for (JavaResourceAbstractType type : this.getJavaResourceTypes()) { |
| if (type.getQualifiedName().equals(typeName)) { |
| return type; |
| } |
| } |
| return null; |
| // // if we don't have a type already, try to build new one from the project classpath |
| // return this.buildPersistableExternalJavaResourcePersistentType(typeName); |
| } |
| |
| public JavaResourceAbstractType getJavaResourceType(String typeName, JavaResourceAbstractType.Kind kind) { |
| JavaResourceAbstractType resourceType = getJavaResourceType(typeName); |
| if (resourceType == null || resourceType.getKind() != kind) { |
| return null; |
| } |
| return resourceType; |
| } |
| |
| protected Iterable<JavaResourceAbstractType> getJavaResourceTypes() { |
| return new CompositeIterable<JavaResourceAbstractType>(this.getJavaResourceTypeSets()); |
| } |
| |
| protected Iterable<Iterable<JavaResourceAbstractType>> getJavaResourceTypeSets() { |
| return new TransformationIterable<JavaResourceNode.Root, Iterable<JavaResourceAbstractType>>( |
| this.getJavaResourceNodeRoots()) { |
| @Override |
| protected Iterable<JavaResourceAbstractType> transform(JavaResourceNode.Root root) { |
| return root.getTypes(); |
| } |
| }; |
| } |
| |
| @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 source folder names ********** |
| // |
| // public Iterable<String> getJavaSourceFolderNames() { |
| // try { |
| // return this.getJavaSourceFolderNames_(); |
| // } catch (JavaModelException ex) { |
| // JptCorePlugin.log(ex); |
| // return EmptyIterable.instance(); |
| // } |
| // } |
| // |
| // protected Iterable<String> getJavaSourceFolderNames_() throws JavaModelException { |
| // return new TransformationIterable<IPackageFragmentRoot, String>(this.getJavaSourceFolders()) { |
| // @Override |
| // protected String transform(IPackageFragmentRoot pfr) { |
| // try { |
| // return this.transform_(pfr); |
| // } catch (JavaModelException ex) { |
| // return "Error: " + pfr.getPath(); //$NON-NLS-1$ |
| // } |
| // } |
| // private String transform_(IPackageFragmentRoot pfr) throws JavaModelException { |
| // return pfr.getUnderlyingResource().getProjectRelativePath().toString(); |
| // } |
| // }; |
| // } |
| // |
| // protected Iterable<IPackageFragmentRoot> getJavaSourceFolders() throws JavaModelException { |
| // return new FilteringIterable<IPackageFragmentRoot>( |
| // this.getPackageFragmentRoots(), |
| // SOURCE_PACKAGE_FRAGMENT_ROOT_FILTER |
| // ); |
| // } |
| // |
| // protected static final Filter<IPackageFragmentRoot> SOURCE_PACKAGE_FRAGMENT_ROOT_FILTER = |
| // new Filter<IPackageFragmentRoot>() { |
| // public boolean accept(IPackageFragmentRoot pfr) { |
| // try { |
| // return this.accept_(pfr); |
| // } catch (JavaModelException ex) { |
| // return false; |
| // } |
| // } |
| // private boolean accept_(IPackageFragmentRoot pfr) throws JavaModelException { |
| // return pfr.exists() && (pfr.getKind() == IPackageFragmentRoot.K_SOURCE); |
| // } |
| // }; |
| // |
| // protected Iterable<IPackageFragmentRoot> getPackageFragmentRoots() throws JavaModelException { |
| // return new ArrayIterable<IPackageFragmentRoot>(this.getJavaProject().getPackageFragmentRoots()); |
| // } |
| |
| |
| // **************** jaxb.index resources ********************************** |
| |
| public Iterable<JaxbIndexResource> getJaxbIndexResources() { |
| return new TransformationIterable<JaxbFile, JaxbIndexResource>(getJaxbFiles(JptJaxbCorePlugin.JAXB_INDEX_CONTENT_TYPE)) { |
| @Override |
| protected JaxbIndexResource transform(JaxbFile o) { |
| return (JaxbIndexResource) o.getResourceModel(); |
| } |
| }; |
| } |
| |
| public JaxbIndexResource getJaxbIndexResource(String packageName) { |
| for (JaxbIndexResource jir : getJaxbIndexResources()) { |
| if (packageName.equals(jir.getPackageName())) { |
| return jir; |
| } |
| } |
| return null; |
| } |
| |
| |
| // **************** jaxb.properties resources ***************************** |
| |
| public Iterable<JaxbPropertiesResource> getJaxbPropertiesResources() { |
| return new TransformationIterable<JaxbFile, JaxbPropertiesResource>(getJaxbFiles(JptJaxbCorePlugin.JAXB_PROPERTIES_CONTENT_TYPE)) { |
| @Override |
| protected JaxbPropertiesResource transform(JaxbFile o) { |
| return (JaxbPropertiesResource) o.getResourceModel(); |
| } |
| }; |
| } |
| |
| public JaxbPropertiesResource getJaxbPropertiesResource(String packageName) { |
| for (JaxbPropertiesResource jpr : getJaxbPropertiesResources()) { |
| if (packageName.equals(jpr.getPackageName())) { |
| return jpr; |
| } |
| } |
| return null; |
| } |
| |
| |
| // ********** Java events ********** |
| |
| // TODO handle changes to external projects |
| public void javaElementChanged(ElementChangedEvent event) { |
| this.processJavaDelta(event.getDelta()); |
| } |
| |
| /** |
| * We recurse back here from {@link #processJavaDeltaChildren(IJavaElementDelta)}. |
| */ |
| protected void processJavaDelta(IJavaElementDelta delta) { |
| switch (delta.getElement().getElementType()) { |
| case IJavaElement.JAVA_MODEL : |
| this.processJavaModelDelta(delta); |
| break; |
| case IJavaElement.JAVA_PROJECT : |
| this.processJavaProjectDelta(delta); |
| break; |
| case IJavaElement.PACKAGE_FRAGMENT_ROOT : |
| this.processJavaPackageFragmentRootDelta(delta); |
| break; |
| case IJavaElement.PACKAGE_FRAGMENT : |
| this.processJavaPackageFragmentDelta(delta); |
| break; |
| case IJavaElement.COMPILATION_UNIT : |
| this.processJavaCompilationUnitDelta(delta); |
| break; |
| default : |
| break; // ignore the elements inside a compilation unit |
| } |
| } |
| |
| protected void processJavaDeltaChildren(IJavaElementDelta delta) { |
| for (IJavaElementDelta child : delta.getAffectedChildren()) { |
| this.processJavaDelta(child); // recurse |
| } |
| } |
| |
| /** |
| * Return whether the specified Java element delta is for a |
| * {@link IJavaElementDelta#CHANGED CHANGED} |
| * (as opposed to {@link IJavaElementDelta#ADDED ADDED} or |
| * {@link IJavaElementDelta#REMOVED REMOVED}) Java element |
| * and the specified flag is set. |
| * (The delta flags are only significant if the delta |
| * {@link IJavaElementDelta#getKind() kind} is |
| * {@link IJavaElementDelta#CHANGED CHANGED}.) |
| */ |
| protected boolean deltaFlagIsSet(IJavaElementDelta delta, int flag) { |
| return (delta.getKind() == IJavaElementDelta.CHANGED) && |
| BitTools.flagIsSet(delta.getFlags(), flag); |
| } |
| |
| // ***** model |
| protected void processJavaModelDelta(IJavaElementDelta delta) { |
| // process the Java model's projects |
| this.processJavaDeltaChildren(delta); |
| } |
| |
| // ***** project |
| protected void processJavaProjectDelta(IJavaElementDelta delta) { |
| // process the Java project's package fragment roots |
| this.processJavaDeltaChildren(delta); |
| |
| // a classpath change can have pretty far-reaching effects... |
| if (this.classpathHasChanged(delta)) { |
| this.rebuild((IJavaProject) delta.getElement()); |
| } |
| } |
| |
| /** |
| * The specified Java project's classpath changed. Rebuild the JPA project |
| * as appropriate. |
| */ |
| protected void rebuild(IJavaProject javaProject) { |
| // if the classpath has changed, we need to update everything since |
| // class references could now be resolved (or not) etc. |
| if (javaProject.equals(this.getJavaProject())) { |
| this.removeDeadJpaFiles(); |
| this.synchronizeWithJavaSource(this.getInternalJavaResourceCompilationUnits()); |
| } else { |
| // TODO see if changed project is on our classpath? |
| //this.synchronizeWithJavaSource(this.getExternalJavaResourceCompilationUnits()); |
| } |
| } |
| |
| /** |
| * Loop through all our JPA files, remove any that are no longer on the |
| * classpath. |
| */ |
| protected void removeDeadJpaFiles() { |
| for (JaxbFile jaxbFile : this.getJaxbFiles()) { |
| if (this.jaxbFileIsDead(jaxbFile)) { |
| this.removeJaxbFile(jaxbFile); |
| } |
| } |
| } |
| |
| protected boolean jaxbFileIsDead(JaxbFile jaxbFile) { |
| return ! this.jaxbFileIsAlive(jaxbFile); |
| } |
| |
| /** |
| * Sometimes (e.g. during tests), when a project has been deleted, we get a |
| * Java change event that indicates the Java project is CHANGED (as |
| * opposed to REMOVED, which is what typically happens). The event's delta |
| * indicates that everything in the Java project has been deleted and the |
| * classpath has changed. All entries in the classpath have been removed; |
| * but single entry for the Java project's root folder has been added. (!) |
| * This means any file in the project is on the Java project's classpath. |
| * This classpath change is what triggers us to rebuild the JPA project; so |
| * we put an extra check here to make sure the JPA file's resource file is |
| * still present. |
| * <p> |
| * This would not be a problem if Dali received the resource change event |
| * <em>before</em> JDT and simply removed the JPA project; but JDT receives |
| * the resource change event first and converts it into the problematic |
| * Java change event.... |
| */ |
| protected boolean jaxbFileIsAlive(JaxbFile jaxbFile) { |
| IFile file = jaxbFile.getFile(); |
| return this.getJavaProject().isOnClasspath(file) && |
| file.exists(); |
| } |
| |
| /** |
| * pre-condition: |
| * delta.getElement().getElementType() == IJavaElement.JAVA_PROJECT |
| */ |
| protected boolean classpathHasChanged(IJavaElementDelta delta) { |
| return this.deltaFlagIsSet(delta, IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED); |
| } |
| |
| protected void synchronizeWithJavaSource(Iterable<JavaResourceCompilationUnit> javaResourceCompilationUnits) { |
| for (JavaResourceCompilationUnit javaResourceCompilationUnit : javaResourceCompilationUnits) { |
| javaResourceCompilationUnit.synchronizeWithJavaSource(); |
| } |
| } |
| |
| |
| // ***** package fragment root |
| protected void processJavaPackageFragmentRootDelta(IJavaElementDelta delta) { |
| // process the Java package fragment root's package fragments |
| this.processJavaDeltaChildren(delta); |
| |
| if (this.classpathEntryHasBeenAdded(delta)) { |
| // TODO bug 277218 |
| } else if (this.classpathEntryHasBeenRemoved(delta)) { // should be mutually-exclusive w/added (?) |
| // TODO bug 277218 |
| } |
| } |
| |
| /** |
| * pre-condition: |
| * delta.getElement().getElementType() == IJavaElement.PACKAGE_FRAGMENT_ROOT |
| */ |
| protected boolean classpathEntryHasBeenAdded(IJavaElementDelta delta) { |
| return this.deltaFlagIsSet(delta, IJavaElementDelta.F_ADDED_TO_CLASSPATH); |
| } |
| |
| /** |
| * pre-condition: |
| * delta.getElement().getElementType() == IJavaElement.PACKAGE_FRAGMENT_ROOT |
| */ |
| protected boolean classpathEntryHasBeenRemoved(IJavaElementDelta delta) { |
| return this.deltaFlagIsSet(delta, IJavaElementDelta.F_REMOVED_FROM_CLASSPATH); |
| } |
| |
| // ***** package fragment |
| protected void processJavaPackageFragmentDelta(IJavaElementDelta delta) { |
| // process the java package fragment's compilation units |
| this.processJavaDeltaChildren(delta); |
| } |
| |
| // ***** compilation unit |
| protected void processJavaCompilationUnitDelta(IJavaElementDelta delta) { |
| if (this.javaCompilationUnitDeltaIsRelevant(delta)) { |
| ICompilationUnit compilationUnit = (ICompilationUnit) delta.getElement(); |
| for (JavaResourceCompilationUnit jrcu : this.getCombinedJavaResourceCompilationUnits()) { |
| if (jrcu.getCompilationUnit().equals(compilationUnit)) { |
| jrcu.synchronizeWithJavaSource(); |
| // 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 Iterable<IMessage> getValidationMessages(IReporter reporter) { |
| List<IMessage> messages = new ArrayList<IMessage>(); |
| this.validate(messages, reporter); |
| return new SnapshotCloneIterable<IMessage>(messages); |
| } |
| |
| protected void validate(List<IMessage> messages, IReporter reporter) { |
| if (reporter.isCancelled()) { |
| throw new ValidationCancelledException(); |
| } |
| |
| getSchemaLibrary().refreshAllSchemas(); |
| |
| validateLibraryProvider(messages); |
| validateSchemaLibrary(messages); |
| this.contextRoot.validate(messages, reporter); |
| } |
| |
| protected void validateLibraryProvider(List<IMessage> messages) { |
| try { |
| IFacetedProject facetedProject = ProjectFacetsManager.create(getProject()); |
| IProjectFacetVersion facetVersion = facetedProject.getInstalledVersion(JaxbFacet.FACET); |
| LibraryInstallDelegate lid = new LibraryInstallDelegate(facetedProject, facetVersion); |
| ILibraryProvider lp = lid.getLibraryProvider(); |
| if (lid.getLibraryProviderOperationConfig() instanceof JaxbLibraryProviderInstallOperationConfig) { |
| ((JaxbLibraryProviderInstallOperationConfig) lid.getLibraryProviderOperationConfig()).setJaxbPlatform(getPlatform().getDescription()); |
| } |
| if (! lp.isEnabledFor(facetedProject, facetVersion) || ! lid.validate().isOK()) { |
| messages.add( |
| DefaultValidationMessages.buildMessage( |
| IMessage.HIGH_SEVERITY, |
| JaxbValidationMessages.PROJECT_INVALID_LIBRARY_PROVIDER, |
| this)); |
| } |
| } |
| catch (CoreException ce) { |
| // fall through |
| JptJaxbCorePlugin.log(ce); |
| } |
| } |
| |
| protected void validateSchemaLibrary(List<IMessage> messages) { |
| this.schemaLibrary.validate(messages); |
| } |
| |
| |
| // ********** dispose ********** |
| |
| public void dispose() { |
| this.contextModelSynchronizer.stop(); |
| this.updateSynchronizer.stop(); |
| this.updateSynchronizer.removeListener(this.updateSynchronizerListener); |
| this.schemaLibrary.dispose(); |
| // the XML resources are held indefinitely by the WTP translator framework, |
| // so we better remove our listener or the JAXB project will not be GCed |
| for (JaxbFile jaxbFile : this.getJaxbFiles()) { |
| jaxbFile.getResourceModel().removeResourceModelListener(this.resourceModelListener); |
| } |
| } |
| |
| |
| |
| // ********** resource model listener ********** |
| |
| protected JptResourceModelListener buildResourceModelListener() { |
| return new DefaultResourceModelListener(); |
| } |
| |
| protected class DefaultResourceModelListener |
| implements JptResourceModelListener |
| { |
| protected DefaultResourceModelListener() { |
| super(); |
| } |
| |
| public void resourceModelChanged(JptResourceModel jpaResourceModel) { |
| // String msg = Thread.currentThread() + " resource model change: " + jpaResourceModel; |
| // System.out.println(msg); |
| // new Exception(msg).printStackTrace(System.out); |
| AbstractJaxbProject.this.synchronizeContextModel(jpaResourceModel); |
| } |
| |
| public void resourceModelReverted(JptResourceModel jpaResourceModel) { |
| // IFile file = WorkbenchResourceHelper.getFile((JpaXmlResource)jpaResourceModel); |
| // AbstractJaxbProject.this.removeJaxbFile(file); |
| // AbstractJaxbProject.this.addJaxbFile(file); |
| } |
| |
| public void resourceModelUnloaded(JptResourceModel jpaResourceModel) { |
| // IFile file = WorkbenchResourceHelper.getFile((JpaXmlResource)jpaResourceModel); |
| // AbstractJaxbProject.this.removeJaxbFile(file); |
| } |
| } |
| |
| protected void synchronizeContextModel(@SuppressWarnings("unused") JptResourceModel jpaResourceModel) { |
| this.synchronizeContextModel(); |
| } |
| |
| |
| // ********** resource events ********** |
| |
| // TODO need to do the same thing for external projects and compilation units |
| public void projectChanged(IResourceDelta delta) { |
| if (delta.getResource().equals(this.getProject())) { |
| this.internalProjectChanged(delta); |
| } else { |
| // this.externalProjectChanged(delta); |
| } |
| } |
| |
| protected void internalProjectChanged(IResourceDelta delta) { |
| ResourceDeltaVisitor resourceDeltaVisitor = this.buildInternalResourceDeltaVisitor(); |
| resourceDeltaVisitor.visitDelta(delta); |
| // 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 AbstractJaxbProject.this.synchronizeJaxbFiles(file, deltaKind); |
| } |
| }; |
| } |
| |
| /** |
| * Internal resource delta visitor callback. |
| * Return true if a JaxbFile was either added or removed. |
| */ |
| protected boolean synchronizeJaxbFiles(IFile file, int deltaKind) { |
| switch (deltaKind) { |
| case IResourceDelta.ADDED : |
| return this.addJaxbFile(file); |
| case IResourceDelta.REMOVED : |
| return this.removeJaxbFile(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) { |
| JaxbFile jaxbFile = this.getJaxbFile(file); |
| if (jaxbFile == null) { |
| // the file might have changed its content to something that we are interested in |
| return this.addJaxbFile(file); |
| } |
| |
| if (jaxbFile.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.removeJaxbFile(jaxbFile); |
| this.addJaxbFile(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) { |
| // if (this.getJavaProject().isOnClasspath(delta.getResource())) { |
| // ResourceDeltaVisitor resourceDeltaVisitor = this.buildExternalResourceDeltaVisitor(); |
| // resourceDeltaVisitor.visitDelta(delta); |
| // // 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 AbstractJaxbProject.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(); |
| } |
| |
| protected void visitDelta(IResourceDelta delta) { |
| try { |
| delta.accept(this); |
| } catch (CoreException ex) { |
| // shouldn't happen - we don't throw any CoreExceptions |
| throw new RuntimeException(ex); |
| } |
| } |
| |
| public boolean visit(IResourceDelta delta) { |
| 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; |
| } |
| |
| |
| // ********** synchronize context model with resource model ********** |
| |
| public Synchronizer getContextModelSynchronizer() { |
| return this.contextModelSynchronizer; |
| } |
| |
| public void setContextModelSynchronizer(Synchronizer synchronizer) { |
| if (synchronizer == null) { |
| throw new NullPointerException(); |
| } |
| this.contextModelSynchronizer.stop(); |
| this.setContextModelSynchronizer_(synchronizer); |
| } |
| |
| protected void setContextModelSynchronizer_(Synchronizer synchronizer) { |
| this.contextModelSynchronizer = synchronizer; |
| this.contextModelSynchronizer.start(); |
| } |
| |
| /** |
| * Delegate to the context model synchronizer so clients can configure how |
| * synchronizations occur. |
| */ |
| public void synchronizeContextModel() { |
| this.synchronizingContextModel = true; |
| this.contextModelSynchronizer.synchronize(); |
| this.synchronizingContextModel = false; |
| |
| // There are some changes to the resource model that will not change |
| // the existing context model and trigger an update (e.g. adding an |
| // @Entity annotation when the the JPA project is automatically |
| // discovering annotated classes); so we explicitly execute an update |
| // here to discover those changes. |
| this.update(); |
| } |
| |
| /** |
| * Called by the context model synchronizer. |
| */ |
| public IStatus synchronizeContextModel(IProgressMonitor monitor) { |
| this.contextRoot.synchronizeWithResourceModel(); |
| return Status.OK_STATUS; |
| } |
| |
| public void synchronizeContextModelAndWait() { |
| Synchronizer temp = this.contextModelSynchronizer; |
| this.setContextModelSynchronizer(this.buildSynchronousContextModelSynchronizer()); |
| this.synchronizeContextModel(); |
| this.setContextModelSynchronizer(temp); |
| } |
| |
| |
| // ********** default context model synchronizer (synchronous) ********** |
| |
| protected Synchronizer buildSynchronousContextModelSynchronizer() { |
| return new SynchronousSynchronizer(this.buildSynchronousContextModelSynchronizerCommand()); |
| } |
| |
| protected Command buildSynchronousContextModelSynchronizerCommand() { |
| return new SynchronousContextModelSynchronizerCommand(); |
| } |
| |
| protected class SynchronousContextModelSynchronizerCommand |
| implements Command |
| { |
| public void execute() { |
| AbstractJaxbProject.this.synchronizeContextModel(new NullProgressMonitor()); |
| } |
| } |
| |
| |
| // ********** project "update" ********** |
| |
| public CallbackSynchronizer getUpdateSynchronizer() { |
| return this.updateSynchronizer; |
| } |
| |
| public void setUpdateSynchronizer(CallbackSynchronizer synchronizer) { |
| if (synchronizer == null) { |
| throw new NullPointerException(); |
| } |
| this.updateSynchronizer.stop(); |
| this.updateSynchronizer.removeListener(this.updateSynchronizerListener); |
| this.setUpdateSynchronizer_(synchronizer); |
| } |
| |
| protected void setUpdateSynchronizer_(CallbackSynchronizer synchronizer) { |
| this.updateSynchronizer = synchronizer; |
| this.updateSynchronizer.addListener(this.updateSynchronizerListener); |
| this.updateSynchronizer.start(); |
| } |
| |
| @Override |
| public void stateChanged() { |
| super.stateChanged(); |
| this.update(); |
| } |
| |
| /** |
| * The JAXB project's state has changed, "update" those parts of the |
| * JAXB project that are dependent on other parts of the JAXB project. |
| * <p> |
| * Delegate to the update synchronizer so clients can configure how |
| * updates occur. |
| * <p> |
| * Ignore any <em>updates</em> that occur while we are synchronizing |
| * the context model with the resource model because we will <em>update</em> |
| * the context model at the completion of the <em>sync</em>. This is really |
| * only useful for synchronous <em>syncs</em> and <em>updates</em>; since |
| * the job scheduling rules will prevent the <em>sync</em> and |
| * <em>update</em> jobs from running concurrently. |
| * |
| * @see #updateAndWait() |
| */ |
| protected void update() { |
| if ( ! this.synchronizingContextModel) { |
| this.updateSynchronizer.synchronize(); |
| } |
| } |
| |
| /** |
| * Called by the update synchronizer. |
| */ |
| public IStatus update(IProgressMonitor monitor) { |
| this.contextRoot.update(); |
| return Status.OK_STATUS; |
| } |
| |
| /** |
| * This is the callback used by the update synchronizer to notify the JAXB |
| * project that the "update" has quiesced (i.e. the "update" has completed |
| * and there are no outstanding requests for further "updates"). |
| */ |
| public void updateQuiesced() { |
| //nothing yet |
| } |
| |
| public void updateAndWait() { |
| CallbackSynchronizer temp = this.updateSynchronizer; |
| this.setUpdateSynchronizer(this.buildSynchronousUpdateSynchronizer()); |
| this.update(); |
| this.setUpdateSynchronizer(temp); |
| } |
| |
| |
| // ********** default update synchronizer (synchronous) ********** |
| |
| protected CallbackSynchronizer buildSynchronousUpdateSynchronizer() { |
| return new CallbackSynchronousSynchronizer(this.buildSynchronousUpdateSynchronizerCommand()); |
| } |
| |
| protected Command buildSynchronousUpdateSynchronizerCommand() { |
| return new SynchronousUpdateSynchronizerCommand(); |
| } |
| |
| protected class SynchronousUpdateSynchronizerCommand |
| implements Command |
| { |
| public void execute() { |
| AbstractJaxbProject.this.update(new NullProgressMonitor()); |
| } |
| } |
| |
| |
| // ********** update synchronizer listener ********** |
| |
| protected CallbackSynchronizer.Listener buildUpdateSynchronizerListener() { |
| return new UpdateSynchronizerListener(); |
| } |
| |
| protected class UpdateSynchronizerListener |
| implements CallbackSynchronizer.Listener |
| { |
| public void synchronizationQuiesced(CallbackSynchronizer synchronizer) { |
| AbstractJaxbProject.this.updateQuiesced(); |
| } |
| } |
| } |