Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbvosburgh2009-10-28 17:46:10 +0000
committerbvosburgh2009-10-28 17:46:10 +0000
commit267dda422e19750a8746f265dc0d6469e3aac014 (patch)
tree0afb6f533e2c7fed4907a5d2eeeb479661fdbce1
parentb9beac12764ad3ce59b39a98fc7a0665e8af36f4 (diff)
downloadwebtools.dali-267dda422e19750a8746f265dc0d6469e3aac014.tar.gz
webtools.dali-267dda422e19750a8746f265dc0d6469e3aac014.tar.xz
webtools.dali-267dda422e19750a8746f265dc0d6469e3aac014.zip
rework JPA project locking
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/property_files/jpa_core.properties1
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/GenericJpaModel.java1076
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaFactory.java5
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaModel.java47
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaProject.java4
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JptCorePlugin.java117
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractJpaFactory.java3
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractJpaProject.java38
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaModel.java528
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/JpaModelManager.java590
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/JptCoreMessages.java1
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jpa1/GenericJpaProject.java3
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/operations/AbstractJpaFileCreationDataModelProvider.java5
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/operations/AbstractJpaFileCreationOperation.java25
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/SimpleSchedulingRule.java22
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/validation/JpaValidator.java4
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/AbstractXmlResourceProvider.java2
-rw-r--r--jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/xml/JpaXmlResource.java21
-rw-r--r--jpa/plugins/org.eclipse.jpt.eclipselink.core/src/org/eclipse/jpt/eclipselink/core/internal/EclipseLinkJpaFactory.java3
-rw-r--r--jpa/plugins/org.eclipse.jpt.eclipselink.core/src/org/eclipse/jpt/eclipselink/core/internal/EclipseLinkJpaProjectImpl.java3
-rw-r--r--jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/JptUiPlugin.java6
-rw-r--r--jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/properties/JpaProjectPropertiesPage.java17
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AsynchronousCommandExecutor.java164
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CallbackStatefulCommandExecutor.java51
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CompositeCommand.java39
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ConsumerThreadCoordinator.java225
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Queue.java75
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleCommandExecutor.java65
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleQueue.java90
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java15
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java11
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StatefulCommandExecutor.java33
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedQueue.java348
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java142
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/QueueIterable.java51
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/StackIterable.java51
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/QueueIterator.java58
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/StackIterator.java58
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/AsynchronousSynchronizer.java149
-rw-r--r--jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/CallbackAsynchronousSynchronizer.java29
-rw-r--r--jpa/tests/org.eclipse.jpt.core.tests/META-INF/MANIFEST.MF7
-rw-r--r--jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/JptCoreTestsPlugin.java56
-rw-r--r--jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/MiscTests.java65
-rw-r--r--jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/internal/context/ContextModelTestCase.java13
-rw-r--r--jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/internal/model/JpaModelTests.java26
-rw-r--r--jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SimpleQueueTests.java149
-rw-r--r--jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SimpleStackTests.java23
-rw-r--r--jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SynchronizedQueueTests.java285
-rw-r--r--jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SynchronizedStackTests.java20
-rw-r--r--jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/synchronizers/AsynchronousSynchronizerTests.java7
50 files changed, 3350 insertions, 1476 deletions
diff --git a/jpa/plugins/org.eclipse.jpt.core/property_files/jpa_core.properties b/jpa/plugins/org.eclipse.jpt.core/property_files/jpa_core.properties
index cf03e9e32c..be5a0dc0f6 100644
--- a/jpa/plugins/org.eclipse.jpt.core/property_files/jpa_core.properties
+++ b/jpa/plugins/org.eclipse.jpt.core/property_files/jpa_core.properties
@@ -45,3 +45,4 @@ REGISTRY_FAILED_INSTANTIATION=Unable to instantiate the class ''{0}'' for the ex
UPDATE_JOB_NAME=Update JPA project: ''{0}''
SYNCHRONIZE_METAMODEL_JOB_NAME=Synchronize JPA Canonical Metamodel: ''{0}''
PLATFORM_ID_DOES_NOT_EXIST=No JPA platform exists for the id: ''{0}''. The JPA project was not created for project ''{1}''. Ensure that the platform''s plugin has been added to this Eclipse installation.
+DALI_EVENT_HANDLER_THREAD_NAME=Dali Event Handler
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/GenericJpaModel.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/GenericJpaModel.java
new file mode 100644
index 0000000000..913b48d54d
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/GenericJpaModel.java
@@ -0,0 +1,1076 @@
+/*******************************************************************************
+ * 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;
+
+import java.util.Vector;
+
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceChangeEvent;
+import org.eclipse.core.resources.IResourceChangeListener;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceProxy;
+import org.eclipse.core.resources.IResourceProxyVisitor;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.jobs.IJobManager;
+import org.eclipse.core.runtime.jobs.ILock;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.jdt.core.ElementChangedEvent;
+import org.eclipse.jdt.core.IElementChangedListener;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jpt.core.internal.AsynchronousJpaProjectUpdater;
+import org.eclipse.jpt.core.internal.JptCoreMessages;
+import org.eclipse.jpt.core.internal.SimpleJpaProjectConfig;
+import org.eclipse.jpt.core.internal.facet.JpaFacetInstallDataModelProperties;
+import org.eclipse.jpt.core.internal.operations.JpaFileCreationDataModelProperties;
+import org.eclipse.jpt.core.internal.operations.OrmFileCreationDataModelProvider;
+import org.eclipse.jpt.core.internal.operations.PersistenceFileCreationDataModelProvider;
+import org.eclipse.jpt.utility.internal.AsynchronousCommandExecutor;
+import org.eclipse.jpt.utility.internal.BitTools;
+import org.eclipse.jpt.utility.internal.CallbackStatefulCommandExecutor;
+import org.eclipse.jpt.utility.internal.SimpleCommandExecutor;
+import org.eclipse.jpt.utility.internal.StringTools;
+import org.eclipse.jpt.utility.internal.SynchronizedBoolean;
+import org.eclipse.jpt.utility.internal.iterables.LiveCloneIterable;
+import org.eclipse.jpt.utility.internal.model.AbstractModel;
+import org.eclipse.wst.common.frameworks.datamodel.DataModelFactory;
+import org.eclipse.wst.common.frameworks.datamodel.IDataModel;
+import org.eclipse.wst.common.project.facet.core.FacetedProjectFramework;
+import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectEvent;
+import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectListener;
+import org.eclipse.wst.common.project.facet.core.events.IProjectFacetActionEvent;
+
+/**
+ * The JPA model maintains a list of all JPA projects in the workspace.
+ * It keeps the list (and the state of the JPA projects themselves)
+ * synchronized with the workspace by listening for various
+ * changes:<ul>
+ * <li>Resource
+ * <li>Java
+ * <li>Faceted Project
+ * </ul>
+ * We use an Eclipse {@link ILock lock} to synchronize access to the JPA
+ * projects when dealing with these events. In an effort to reduce deadlocks,
+ * the simple Resource and Java change events are dispatched to a background
+ * thread, allowing us to handle the events outside of the workspace lock held
+ * during resource and Java change notifications.
+ * <p>
+ * Events that trigger either the adding or removing of a JPA project (e.g.
+ * {@link IFacetedProjectEvent.Type#POST_INSTALL}) are handled "synchronously"
+ * by allowing the background thread to handle any outstanding events before
+ * updating the list of JPA projects and returning execution to the event
+ * source.
+ * <p>
+ * Various things that cause us to add or remove a JPA project:<ul>
+ * <li>Startup of the Dali plug-in will trigger all the pre-existing JPA
+ * projects to be added
+ *
+ * <li>Project created and facet installed<p>
+ * {@link IFacetedProjectEvent.Type#POST_INSTALL}
+ * <li>Project facet uninstalled<p>
+ * {@link IFacetedProjectEvent.Type#PRE_UNINSTALL}
+ *
+ * <li>Project opened<p>
+ * {@link IFacetedProjectEvent.Type#PROJECT_MODIFIED}
+ * <li>Project closed<p>
+ * {@link IFacetedProjectEvent.Type#PROJECT_MODIFIED}
+ *
+ * <li>Pre-existing project imported from directory or archive (created and opened)<p>
+ * {@link IResourceChangeEvent#POST_CHANGE}
+ * -> {@link IResource#PROJECT}
+ * -> {@link IResourceDelta#ADDED}
+ * -> {@link IResourceDelta#OPEN}
+ * <li>Project renamed<p>
+ * {@link IResourceChangeEvent#POST_CHANGE}
+ * -> {@link IResource#PROJECT}
+ * -> {@link IResourceDelta#ADDED}
+ * -> {@link IResourceDelta#MOVED_FROM}
+ * <li>Project deleted<p>
+ * {@link IResourceChangeEvent#PRE_DELETE}
+ *
+ * <li>Project facet installed by editing the facets settings file directly<p>
+ * {@link IFacetedProjectEvent.Type#PROJECT_MODIFIED}
+ * <li>Project facet uninstalled by editing the facets settings file directly<p>
+ * {@link IFacetedProjectEvent.Type#PROJECT_MODIFIED}
+ * </ul>
+ */
+class GenericJpaModel
+ extends AbstractModel
+ implements JpaModel
+{
+ /**
+ * All the JPA projects in the workspace.
+ */
+ private final Vector<JpaProject> jpaProjects = new Vector<JpaProject>();
+
+ /**
+ * Synchronize access to the JPA projects.
+ */
+ /* private */ final ILock lock = this.getJobManager().newLock();
+
+ /**
+ * Determine how Resource and Java change events are
+ * handled (i.e. synchronously or asynchronously).
+ */
+ private volatile CallbackStatefulCommandExecutor eventHandler = new AsynchronousCommandExecutor(JptCoreMessages.DALI_EVENT_HANDLER_THREAD_NAME);
+
+ /**
+ * Listen for<ul>
+ * <li>changes to projects and files
+ * <li>deleted projects
+ * <li>clean builds
+ * </ul>
+ */
+ private final IResourceChangeListener resourceChangeListener = new ResourceChangeListener();
+
+ /**
+ * The types of resource change events that interest
+ * {@link #resourceChangeListener}.
+ */
+ private static final int RESOURCE_CHANGE_EVENT_TYPES =
+ IResourceChangeEvent.PRE_DELETE |
+ IResourceChangeEvent.POST_CHANGE |
+ IResourceChangeEvent.POST_BUILD;
+
+ /**
+ * Listen for the JPA facet being added to or removed from a "faceted" project.
+ */
+ private final IFacetedProjectListener facetedProjectListener = new FacetedProjectListener();
+
+ /**
+ * Listen for Java changes (unless the Dali UI is active).
+ * @see #javaElementChangeListenerIsActive
+ */
+ private final JavaElementChangeListener javaElementChangeListener = new JavaElementChangeListener();
+
+
+ // ********** constructor **********
+
+ /**
+ * internal - called by the Dali plug-in
+ */
+ GenericJpaModel() {
+ super();
+ }
+
+
+ // ********** plug-in controlled life-cycle **********
+
+ /**
+ * internal - called by the Dali plug-in
+ */
+ void start() {
+ try {
+ this.lock.acquire();
+ this.start_();
+ } finally {
+ this.lock.release();
+ }
+ }
+
+ private void start_() {
+ debug("*** JPA model START ***"); //$NON-NLS-1$
+ try {
+ this.buildJpaProjects();
+ this.eventHandler.start();
+ this.getWorkspace().addResourceChangeListener(this.resourceChangeListener, RESOURCE_CHANGE_EVENT_TYPES);
+ FacetedProjectFramework.addListener(this.facetedProjectListener, IFacetedProjectEvent.Type.values());
+ JavaCore.addElementChangedListener(this.javaElementChangeListener);
+ } catch (RuntimeException ex) {
+ JptCorePlugin.log(ex);
+ this.stop_();
+ }
+ }
+
+ private void buildJpaProjects() {
+ try {
+ this.buildJpaProjects_();
+ } catch (CoreException ex) {
+ // our visitor does not throw any exceptions
+ throw new RuntimeException(ex);
+ }
+ }
+
+ private void buildJpaProjects_() throws CoreException {
+ this.getWorkspace().getRoot().accept(new ResourceProxyVisitor(), IResource.NONE);
+ }
+
+ /**
+ * internal - called by the Dali plug-in
+ */
+ void stop() throws Exception {
+ try {
+ this.lock.acquire();
+ this.stop_();
+ } finally {
+ this.lock.release();
+ }
+ }
+
+ private void stop_() {
+ debug("*** JPA model STOP ***"); //$NON-NLS-1$
+ JavaCore.removeElementChangedListener(this.javaElementChangeListener);
+ FacetedProjectFramework.removeListener(this.facetedProjectListener);
+ this.getWorkspace().removeResourceChangeListener(this.resourceChangeListener);
+ this.eventHandler.stop();
+ this.clearJpaProjects();
+ }
+
+ private void clearJpaProjects() {
+ // clone to prevent concurrent modification exceptions
+ for (JpaProject jpaProject : this.getJpaProjects_()) {
+ this.removeJpaProject(jpaProject);
+ }
+ }
+
+
+ // ********** JpaModel implementation **********
+
+ public Iterable<JpaProject> getJpaProjects() {
+ try {
+ this.lock.acquire();
+ return this.getJpaProjects_();
+ } finally {
+ this.lock.release();
+ }
+ }
+
+ private Iterable<JpaProject> getJpaProjects_() {
+ return new LiveCloneIterable<JpaProject>(this.jpaProjects);
+ }
+
+ public int getJpaProjectsSize() {
+ return this.jpaProjects.size();
+ }
+
+ public JpaProject getJpaProject(IProject project) {
+ try {
+ this.lock.acquire();
+ return this.getJpaProject_(project);
+ } finally {
+ this.lock.release();
+ }
+ }
+
+ private JpaProject getJpaProject_(IProject project) {
+ for (JpaProject jpaProject : this.jpaProjects) {
+ if (jpaProject.getProject().equals(project)) {
+ return jpaProject;
+ }
+ }
+ return null;
+ }
+
+ public JpaFile getJpaFile(IFile file) {
+ JpaProject jpaProject = this.getJpaProject(file.getProject());
+ return (jpaProject == null) ? null : jpaProject.getJpaFile(file);
+ }
+
+ public void rebuildJpaProject(IProject project) {
+ try {
+ this.lock.acquire();
+ this.rebuildJpaProject_(project);
+ } finally {
+ this.lock.release();
+ }
+ }
+
+ /**
+ * assumption: the JPA project holder exists
+ */
+ private void rebuildJpaProject_(IProject project) {
+ this.removeJpaProject(this.getJpaProject_(project));
+ this.addJpaProject(project);
+ }
+
+ public boolean javaElementChangeListenerIsActive() {
+ return this.javaElementChangeListener.isActive();
+ }
+
+ public void setJavaElementChangeListenerIsActive(boolean javaElementChangeListenerIsActive) {
+ this.javaElementChangeListener.setActive(javaElementChangeListenerIsActive);
+ }
+
+ public IWorkspace getWorkspace() {
+ return ResourcesPlugin.getWorkspace();
+ }
+
+ public IJobManager getJobManager() {
+ return Job.getJobManager();
+ }
+
+
+ // ********** adding/removing JPA projects **********
+
+ /* private */ void addJpaProject(IProject project) {
+ this.addJpaProject(this.buildJpaProject(project));
+ }
+
+ private void addJpaProject(JpaProject jpaProject) {
+ // figure out exactly when JPA projects are added
+ dumpStackTrace("add: ", jpaProject); //$NON-NLS-1$
+ // the jpa project can be null if we have problems getting the jpa platform
+ if (jpaProject != null) {
+ this.addItemToCollection(jpaProject, this.jpaProjects, JPA_PROJECTS_COLLECTION);
+ }
+ }
+
+ private JpaProject buildJpaProject(IProject project) {
+ return this.buildJpaProject(this.buildJpaProjectConfig(project));
+ }
+
+ private JpaProject buildJpaProject(JpaProject.Config config) {
+ JpaPlatform jpaPlatform = config.getJpaPlatform();
+ if (jpaPlatform == null) {
+ return null;
+ }
+ JpaProject result = jpaPlatform.getJpaFactory().buildJpaProject(config);
+ result.setUpdater(new AsynchronousJpaProjectUpdater(result));
+ return result;
+ }
+
+ private JpaProject.Config buildJpaProjectConfig(IProject project) {
+ SimpleJpaProjectConfig config = new SimpleJpaProjectConfig();
+ config.setProject(project);
+ config.setJpaPlatform(JptCorePlugin.getJpaPlatform(project));
+ config.setConnectionProfileName(JptCorePlugin.getConnectionProfileName(project));
+ config.setUserOverrideDefaultCatalog(JptCorePlugin.getUserOverrideDefaultCatalog(project));
+ config.setUserOverrideDefaultSchema(JptCorePlugin.getUserOverrideDefaultSchema(project));
+ config.setDiscoverAnnotatedClasses(JptCorePlugin.discoverAnnotatedClasses(project));
+ config.setMetamodelSourceFolderName(JptCorePlugin.getMetamodelSourceFolderName(project));
+ return config;
+ }
+
+ private void removeJpaProject(JpaProject jpaProject) {
+ // figure out exactly when JPA projects are removed
+ dumpStackTrace("remove: ", jpaProject); //$NON-NLS-1$
+ this.removeItemFromCollection(jpaProject, this.jpaProjects, JPA_PROJECTS_COLLECTION);
+ jpaProject.dispose();
+ }
+
+
+ // ********** Project POST_CHANGE **********
+
+ /**
+ * Forward the specified resource delta to all our JPA projects;
+ * they will each determine whether the event is significant.
+ */
+ /* private */ void projectChanged(IResourceDelta delta) {
+ this.eventHandler.execute(this.buildProjectChangedCommand(delta));
+ }
+
+ private Command buildProjectChangedCommand(final IResourceDelta delta) {
+ return new Command() {
+ @Override
+ void execute_() {
+ GenericJpaModel.this.projectChanged_(delta);
+ }
+ };
+ }
+
+ /* private */ void projectChanged_(IResourceDelta delta) {
+ for (JpaProject jpaProject : this.jpaProjects) {
+ jpaProject.projectChanged(delta);
+ }
+ }
+
+
+ // ********** Project POST_BUILD (CLEAN_BUILD) **********
+
+ /* private */ void projectPostCleanBuild(IProject project) {
+ this.waitForExecution(this.buildProjectPostCleanBuildCommand(project));
+ }
+
+ private Command buildProjectPostCleanBuildCommand(final IProject project) {
+ return new Command() {
+ @Override
+ void execute_() {
+ GenericJpaModel.this.projectPostCleanBuild_(project);
+ }
+ };
+ }
+
+ /* private */ void projectPostCleanBuild_(IProject project) {
+ JpaProject jpaProject = this.getJpaProject_(project);
+ if (jpaProject != null) {
+ this.removeJpaProject(jpaProject);
+ this.addJpaProject(project);
+ }
+ }
+
+
+ // ********** Project PRE_DELETE **********
+
+ /**
+ * A project is being deleted. Remove its corresponding
+ * JPA project if appropriate.
+ */
+ /* private */ void projectPreDelete(IProject project) {
+ this.waitForExecution(this.buildProjectPreDeleteCommand(project));
+ }
+
+ private Command buildProjectPreDeleteCommand(final IProject project) {
+ return new Command() {
+ @Override
+ void execute_() {
+ GenericJpaModel.this.projectPreDelete_(project);
+ }
+ };
+ }
+
+ /* private */ void projectPreDelete_(IProject project) {
+ JpaProject jpaProject = this.getJpaProject(project);
+ if (jpaProject != null) {
+ this.removeJpaProject(jpaProject);
+ }
+ }
+
+
+ // ********** Resource and/or Facet events **********
+
+ /**
+ * Check whether the JPA facet has been added or removed.
+ */
+ /* private */ void checkForJpaFacetTransition(IProject project) {
+ this.waitForExecution(this.buildCheckForJpaFacetTransitionCommand(project));
+ }
+
+ private Command buildCheckForJpaFacetTransitionCommand(final IProject project) {
+ return new Command() {
+ @Override
+ void execute_() {
+ GenericJpaModel.this.checkForJpaFacetTransition_(project);
+ }
+ };
+ }
+
+ /* private */ void checkForJpaFacetTransition_(IProject project) {
+ JpaProject jpaProject = this.getJpaProject_(project);
+
+ if (JptCorePlugin.projectHasJpaFacet(project)) {
+ if (jpaProject == null) { // JPA facet added
+ this.addJpaProject(project);
+ }
+ } else {
+ if (jpaProject != null) { // JPA facet removed
+ this.removeJpaProject(jpaProject);
+ }
+ }
+ }
+
+
+ // ********** FacetedProject POST_INSTALL **********
+
+ /* private */ void jpaFacetedProjectPostInstall(IProjectFacetActionEvent event) {
+ this.waitForExecution(this.buildJpaFacetedProjectPostInstallCommand(event));
+ }
+
+ private Command buildJpaFacetedProjectPostInstallCommand(final IProjectFacetActionEvent event) {
+ return new Command() {
+ @Override
+ void execute_() {
+ GenericJpaModel.this.jpaFacetedProjectPostInstall_(event);
+ }
+ };
+ }
+
+ /* private */ void jpaFacetedProjectPostInstall_(IProjectFacetActionEvent event) {
+ IProject project = event.getProject().getProject();
+ IDataModel dataModel = (IDataModel) event.getActionConfig();
+
+ // assume(?) this is the first event to indicate we need to add the JPA project to the JPA model
+ this.addJpaProject(project);
+
+ boolean buildOrmXml = dataModel.getBooleanProperty(JpaFacetInstallDataModelProperties.CREATE_ORM_XML);
+ this.createProjectXml(project, buildOrmXml);
+ }
+
+ private void createProjectXml(IProject project, boolean buildOrmXml) {
+ this.createPersistenceXml(project);
+
+ if (buildOrmXml) {
+ this.createOrmXml(project);
+ }
+ }
+
+ private void createPersistenceXml(IProject project) {
+ IDataModel config = DataModelFactory.createDataModel(new PersistenceFileCreationDataModelProvider());
+ config.setProperty(JpaFileCreationDataModelProperties.PROJECT_NAME, project.getName());
+ // default values for all other properties should suffice
+ try {
+ config.getDefaultOperation().execute(null, null);
+ } catch (ExecutionException ex) {
+ JptCorePlugin.log(ex);
+ }
+ }
+
+ private void createOrmXml(IProject project) {
+ IDataModel config = DataModelFactory.createDataModel(new OrmFileCreationDataModelProvider());
+ config.setProperty(JpaFileCreationDataModelProperties.PROJECT_NAME, project.getName());
+ // default values for all other properties should suffice
+ try {
+ config.getDefaultOperation().execute(null, null);
+ } catch (ExecutionException ex) {
+ JptCorePlugin.log(ex);
+ }
+ }
+
+
+ // ********** FacetedProject PRE_UNINSTALL **********
+
+ /* private */ void jpaFacetedProjectPreUninstall(IProjectFacetActionEvent event) {
+ IProject project = event.getProject().getProject();
+ this.waitForExecution(this.buildJpaFacetedProjectPreUninstallCommand(project));
+ }
+
+ private Command buildJpaFacetedProjectPreUninstallCommand(final IProject project) {
+ return new Command() {
+ @Override
+ void execute_() {
+ GenericJpaModel.this.jpaFacetedProjectPreUninstall_(project);
+ }
+ };
+ }
+
+ /* private */ void jpaFacetedProjectPreUninstall_(IProject project) {
+ // assume(?) this is the first event to indicate we need to remove the JPA project to the JPA model
+ this.removeJpaProject(this.getJpaProject_(project));
+ }
+
+
+ // ********** Java element changed **********
+
+ /**
+ * Forward the Java element changed event to all the JPA projects
+ * because the event could affect multiple projects.
+ */
+ /* private */ void javaElementChanged(ElementChangedEvent event) {
+ this.eventHandler.execute(this.buildJavaElementChangedCommand(event));
+ }
+
+ private Command buildJavaElementChangedCommand(final ElementChangedEvent event) {
+ return new Command() {
+ @Override
+ void execute_() {
+ GenericJpaModel.this.javaElementChanged_(event);
+ }
+ };
+ }
+
+ /* private */ void javaElementChanged_(ElementChangedEvent event) {
+ for (JpaProject jpaProject : this.jpaProjects) {
+ jpaProject.javaElementChanged(event);
+ }
+ }
+
+
+ // ********** miscellaneous **********
+
+ @Override
+ public void toString(StringBuilder sb) {
+ sb.append(this.jpaProjects);
+ }
+
+
+ // ********** event handler **********
+
+ private void waitForExecution(Command command) {
+ SynchronizedBoolean flag = new SynchronizedBoolean(false);
+ org.eclipse.jpt.utility.Command markerCommand = this.buildMarkerCommand();
+ EventHandlerListener listener = new EventHandlerListener(markerCommand, flag);
+ this.eventHandler.addListener(listener);
+ this.eventHandler.execute(markerCommand);
+ try {
+ flag.waitUntilTrue();
+ } catch (InterruptedException ex) {
+ // ignore - not sure why this thread would be interrupted
+ }
+ this.eventHandler.removeListener(listener);
+ command.execute();
+ }
+
+ private org.eclipse.jpt.utility.Command buildMarkerCommand() {
+ return new org.eclipse.jpt.utility.Command() {
+ public void execute() {
+ // do nothing
+ }
+ };
+ }
+
+ private static class EventHandlerListener implements CallbackStatefulCommandExecutor.Listener {
+ private final org.eclipse.jpt.utility.Command command;
+ private final SynchronizedBoolean flag;
+
+ EventHandlerListener(org.eclipse.jpt.utility.Command command, SynchronizedBoolean flag) {
+ super();
+ this.command = command;
+ this.flag = flag;
+ }
+
+ public void commandExecuted(org.eclipse.jpt.utility.Command c) {
+ if (c == this.command) {
+ this.flag.setTrue();
+ }
+ }
+ }
+
+ public void handleEventsSynchronously() {
+ try {
+ this.lock.acquire();
+ this.handleEventsSynchronously_();
+ } finally {
+ this.lock.release();
+ }
+ }
+
+ private void handleEventsSynchronously_() {
+ this.eventHandler.stop();
+ this.eventHandler = new SimpleCommandExecutor();
+ this.eventHandler.start();
+ }
+
+
+ // ********** resource proxy visitor **********
+
+ /**
+ * Visit the workspace resource tree, adding a JPA project to the
+ * JPA model for each open Eclipse project that has a JPA facet.
+ */
+ private class ResourceProxyVisitor implements IResourceProxyVisitor {
+ ResourceProxyVisitor() {
+ super();
+ }
+
+ public boolean visit(IResourceProxy resourceProxy) {
+ switch (resourceProxy.getType()) {
+ case IResource.ROOT :
+ return true; // all projects are in the "root"
+ case IResource.PROJECT :
+ this.checkProject(resourceProxy);
+ return false; // no nested projects
+ case IResource.FOLDER :
+ return false; // ignore
+ case IResource.FILE :
+ return false; // ignore
+ default :
+ return false;
+ }
+ }
+
+ private void checkProject(IResourceProxy resourceProxy) {
+ if (resourceProxy.isAccessible()) { // the project exists and is open
+ IProject project = (IProject) resourceProxy.requestResource();
+ if (JptCorePlugin.projectHasJpaFacet(project)) {
+ GenericJpaModel.this.addJpaProject(project);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this);
+ }
+
+ }
+
+
+ // ********** command **********
+
+ /**
+ * Abstract class that holds the JPA model lock while
+ * executing.
+ */
+ private abstract class Command
+ implements org.eclipse.jpt.utility.Command
+ {
+ Command() {
+ super();
+ }
+
+ public final void execute() {
+ try {
+ GenericJpaModel.this.lock.acquire();
+ this.execute_();
+ } finally {
+ GenericJpaModel.this.lock.release();
+ }
+ }
+
+ abstract void execute_();
+
+ }
+
+
+ // ********** resource change listener **********
+
+ private class ResourceChangeListener implements IResourceChangeListener {
+
+ ResourceChangeListener() {
+ super();
+ }
+
+ /**
+ * Check for:<ul>
+ * <li>project close/delete
+ * <li>file add/remove
+ * <li>project open/rename
+ * </ul>
+ */
+ public void resourceChanged(IResourceChangeEvent event) {
+ switch (event.getType()) {
+ case IResourceChangeEvent.POST_CHANGE :
+ this.resourcePostChange(event);
+ break;
+
+ // workspace or project events
+ case IResourceChangeEvent.PRE_REFRESH :
+ break; // ignore
+ case IResourceChangeEvent.PRE_BUILD :
+ break; // ignore
+ case IResourceChangeEvent.POST_BUILD :
+ this.resourcePostBuild(event);
+ break;
+
+ // project-only events
+ case IResourceChangeEvent.PRE_CLOSE :
+ break; // ignore
+ case IResourceChangeEvent.PRE_DELETE :
+ this.resourcePreDelete(event);
+ break;
+ default :
+ break;
+ }
+ }
+
+ /**
+ * A resource has changed somehow.
+ * Check for files being added or removed.
+ * (The JPA project only handles added and removed files here
+ * File changes are handled via the Java Element Changed event.)
+ * Also check for opened projects.
+ */
+ private void resourcePostChange(IResourceChangeEvent event) {
+ debug("Resource POST_CHANGE"); //$NON-NLS-1$
+ this.resourceChanged(event.getDelta());
+ }
+
+ private void resourceChanged(IResourceDelta delta) {
+ IResource resource = delta.getResource();
+ switch (resource.getType()) {
+ case IResource.ROOT :
+ this.resourceChangedChildren(delta);
+ break;
+ case IResource.PROJECT :
+ this.projectChanged((IProject) resource, delta);
+ break;
+ case IResource.FOLDER :
+ break; // ignore
+ case IResource.FILE :
+ break; // ignore
+ default :
+ break;
+ }
+ }
+
+ private void resourceChangedChildren(IResourceDelta delta) {
+ for (IResourceDelta child : delta.getAffectedChildren()) {
+ this.resourceChanged(child); // recurse
+ }
+ }
+
+ private void projectChanged(IProject project, IResourceDelta delta) {
+ GenericJpaModel.this.projectChanged(delta);
+ this.checkForOpenedProject(project, delta);
+ }
+
+
+ /**
+ * Crawl the specified delta, looking for projects being opened.
+ * Projects being deleted are handled in {@link IResourceChangeEvent#PRE_DELETE}.
+ * Projects being closed are handled in {@link IFacetedProjectEvent.Type#PROJECT_MODIFIED}.
+ */
+ private void checkForOpenedProject(IProject project, IResourceDelta delta) {
+ switch (delta.getKind()) {
+ case IResourceDelta.ADDED : // all but project import and rename handled with the facet POST_INSTALL event
+ this.checkDeltaFlagsForOpenedProject(project, delta);
+ this.checkDeltaFlagsForRenamedProject(project, delta);
+ break;
+ case IResourceDelta.REMOVED : // already handled with the PRE_DELETE event
+ break;
+ case IResourceDelta.CHANGED :
+ this.checkDeltaFlagsForOpenedProject(project, delta);
+ break;
+ case IResourceDelta.ADDED_PHANTOM :
+ break; // ignore
+ case IResourceDelta.REMOVED_PHANTOM :
+ break; // ignore
+ default :
+ break;
+ }
+ }
+
+ /**
+ * We don't get any events from the Facets Framework when a pre-existing
+ * project is imported, so we need to check for the newly imported project here.
+ * <p>
+ * This event also occurs when a project is simply opened. Project opening
+ * also triggers a {@link IFacetedProjectEvent.Type#PROJECT_MODIFIED} event
+ * and that is where we add the JPA project, not here.
+ */
+ private void checkDeltaFlagsForOpenedProject(IProject project, IResourceDelta delta) {
+ if (BitTools.flagIsSet(delta.getFlags(), IResourceDelta.OPEN) && project.isOpen()) {
+ debug("\tProject CHANGED - OPEN: ", project.getName()); //$NON-NLS-1$
+ GenericJpaModel.this.checkForJpaFacetTransition(project);
+ }
+ }
+
+ /**
+ * We don't get any events from the Facets Framework when a project is renamed,
+ * so we need to check for the renamed projects here.
+ */
+ private void checkDeltaFlagsForRenamedProject(IProject project, IResourceDelta delta) {
+ if (BitTools.flagIsSet(delta.getFlags(), IResourceDelta.MOVED_FROM) && project.isOpen()) {
+ debug("\tProject ADDED - MOVED_FROM: ", delta.getMovedFromPath()); //$NON-NLS-1$
+ GenericJpaModel.this.checkForJpaFacetTransition(project);
+ }
+ }
+
+ /**
+ * A post build event has occurred.
+ * Check for whether the build was a "clean" build and trigger project update.
+ */
+ private void resourcePostBuild(IResourceChangeEvent event) {
+ debug("Resource POST_BUILD: ", event.getResource()); //$NON-NLS-1$
+ if (event.getBuildKind() == IncrementalProjectBuilder.CLEAN_BUILD) {
+ this.resourcePostCleanBuild(event.getDelta());
+ }
+ }
+
+ private void resourcePostCleanBuild(IResourceDelta delta) {
+ IResource resource = delta.getResource();
+ switch (resource.getType()) {
+ case IResource.ROOT :
+ this.resourcePostCleanBuildChildren(delta);
+ break;
+ case IResource.PROJECT :
+ this.projectPostCleanBuild((IProject) resource);
+ break;
+ case IResource.FOLDER :
+ break; // ignore
+ case IResource.FILE :
+ break; // ignore
+ default :
+ break;
+ }
+ }
+
+ private void resourcePostCleanBuildChildren(IResourceDelta delta) {
+ for (IResourceDelta child : delta.getAffectedChildren()) {
+ this.resourcePostCleanBuild(child); // recurse
+ }
+ }
+
+ private void projectPostCleanBuild(IProject project) {
+ debug("\tProject CLEAN: ", project.getName()); //$NON-NLS-1$
+ GenericJpaModel.this.projectPostCleanBuild(project);
+ }
+
+ /**
+ * A project is being deleted. Remove its corresponding
+ * JPA project if appropriate.
+ */
+ private void resourcePreDelete(IResourceChangeEvent event) {
+ IProject project = (IProject) event.getResource();
+ debug("Resource (Project) PRE_DELETE: ", project); //$NON-NLS-1$
+ GenericJpaModel.this.projectPreDelete(project);
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this);
+ }
+
+ }
+
+
+ // ********** faceted project listener **********
+
+ /**
+ * Forward the Faceted project change event back to the JPA model.
+ */
+ private class FacetedProjectListener implements IFacetedProjectListener {
+
+ FacetedProjectListener() {
+ super();
+ }
+
+ /**
+ * Check for:<ul>
+ * <li>install of JPA facet
+ * <li>un-install of JPA facet
+ * <li>any other appearance or disappearance of the JPA facet
+ * </ul>
+ */
+ public void handleEvent(IFacetedProjectEvent event) {
+ switch (event.getType()) {
+ case POST_INSTALL :
+ this.facetedProjectPostInstall((IProjectFacetActionEvent) event);
+ break;
+ case PRE_UNINSTALL :
+ this.facetedProjectPreUninstall((IProjectFacetActionEvent) event);
+ break;
+ case PROJECT_MODIFIED :
+ this.facetedProjectModified(event.getProject().getProject());
+ break;
+ default :
+ break;
+ }
+ }
+
+ private void facetedProjectPostInstall(IProjectFacetActionEvent event) {
+ debug("Facet POST_INSTALL: ", event.getProjectFacet()); //$NON-NLS-1$
+ if (event.getProjectFacet().getId().equals(JptCorePlugin.FACET_ID)) {
+ GenericJpaModel.this.jpaFacetedProjectPostInstall(event);
+ }
+ }
+
+ private void facetedProjectPreUninstall(IProjectFacetActionEvent event) {
+ debug("Facet PRE_UNINSTALL: ", event.getProjectFacet()); //$NON-NLS-1$
+ if (event.getProjectFacet().getId().equals(JptCorePlugin.FACET_ID)) {
+ GenericJpaModel.this.jpaFacetedProjectPreUninstall(event);
+ }
+ }
+
+ /**
+ * This event is triggered for any change to a faceted project.
+ * We use the event to watch for the following:<ul>
+ * <li>an open project is closed
+ * <li>a closed project is opened
+ * <li>one of a project's (facet) metadata files is edited directly
+ * </ul>
+ */
+ private void facetedProjectModified(IProject project) {
+ debug("Facet PROJECT_MODIFIED: ", project.getName()); //$NON-NLS-1$
+ GenericJpaModel.this.checkForJpaFacetTransition(project);
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this);
+ }
+
+ }
+
+
+ // ********** Java element change listener **********
+
+ /**
+ * Forward the Java element change event back to the JPA model.
+ */
+ private class JavaElementChangeListener implements IElementChangedListener {
+ /**
+ * A flag to activate/deactivate the listener
+ * so we can ignore Java events whenever Dali is manipulating the Java
+ * source code via the Dali model. We do this because the 0.5 sec delay
+ * between the Java source being changed and the corresponding event
+ * being fired causes us no end of pain.
+ */
+ private volatile boolean active = true;
+
+ JavaElementChangeListener() {
+ super();
+ }
+
+ public void elementChanged(ElementChangedEvent event) {
+ if (this.active) {
+ GenericJpaModel.this.javaElementChanged(event);
+ }
+ }
+
+ void setActive(boolean active) {
+ this.active = active;
+ }
+
+ boolean isActive() {
+ return this.active;
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this);
+ }
+
+ }
+
+
+ // ********** DEBUG **********
+
+ // @see JpaModelTests#testDEBUG()
+ private static final boolean DEBUG = false;
+
+ /**
+ * trigger #toString() call and string concatenation only if DEBUG is true
+ */
+ /* private */ static void debug(String message, Object object) {
+ if (DEBUG) {
+ debug_(message + object);
+ }
+ }
+
+ /* private */ static void debug(String message) {
+ if (DEBUG) {
+ debug_(message);
+ }
+ }
+
+ private static void debug_(String message) {
+ System.out.println(Thread.currentThread().getName() + ": " + message); //$NON-NLS-1$
+ }
+
+ /* private */ static void dumpStackTrace() {
+ dumpStackTrace(null);
+ }
+
+ /* private */ static void dumpStackTrace(String message, Object object) {
+ if (DEBUG) {
+ dumpStackTrace_(message + object);
+ }
+ }
+
+ /* private */ static void dumpStackTrace(String message) {
+ if (DEBUG) {
+ dumpStackTrace_(message);
+ }
+ }
+
+ private static void dumpStackTrace_(String message) {
+ // lock System.out so the stack elements are printed out contiguously
+ synchronized (System.out) {
+ if (message != null) {
+ debug_(message);
+ }
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ // skip the first 3 elements - those are this method and 2 methods in Thread
+ for (int i = 3; i < stackTrace.length; i++) {
+ StackTraceElement element = stackTrace[i];
+ if (element.getMethodName().equals("invoke0")) { //$NON-NLS-1$
+ break; // skip all elements outside of the JUnit test
+ }
+ System.out.println("\t" + element); //$NON-NLS-1$
+ }
+ }
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaFactory.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaFactory.java
index 63133feab0..ed3693e965 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaFactory.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaFactory.java
@@ -10,7 +10,6 @@
package org.eclipse.jpt.core;
import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jpt.core.context.AssociationOverride;
import org.eclipse.jpt.core.context.AssociationOverrideContainer;
@@ -68,8 +67,6 @@ import org.eclipse.jpt.core.context.java.JavaTransientMapping;
import org.eclipse.jpt.core.context.java.JavaTypeMapping;
import org.eclipse.jpt.core.context.java.JavaUniqueConstraint;
import org.eclipse.jpt.core.context.java.JavaVersionMapping;
-import org.eclipse.jpt.core.context.orm.EntityMappings;
-import org.eclipse.jpt.core.context.persistence.PersistenceUnit;
import org.eclipse.jpt.core.resource.java.AssociationOverrideAnnotation;
import org.eclipse.jpt.core.resource.java.JavaResourcePersistentAttribute;
import org.eclipse.jpt.core.resource.java.JavaResourcePersistentMember;
@@ -111,7 +108,7 @@ public interface JpaFactory
* added to the specified JPA project. Return null if unable to create
* the JPA file (e.g. the content type is unrecognized).
*/
- JpaProject buildJpaProject(JpaProject.Config config) throws CoreException;
+ JpaProject buildJpaProject(JpaProject.Config config);
JpaDataSource buildJpaDataSource(JpaProject jpaProject, String connectionProfileName);
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaModel.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaModel.java
index 97d817d02c..09518e5a70 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaModel.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaModel.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2008 Oracle. All rights reserved.
+ * 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.
@@ -9,15 +9,13 @@
******************************************************************************/
package org.eclipse.jpt.core;
-import java.util.Iterator;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.jpt.utility.model.Model;
/**
- * The JPA model holds all the JPA projects.
- *
+ * The JPA model holds all the JPA projects in the workspace.
+ * <p>
* Provisional API: This interface is part of an interim API that is still
* under development and expected to change significantly before reaching
* stability. It is available at this early stage to solicit feedback from
@@ -27,34 +25,45 @@ import org.eclipse.jpt.utility.model.Model;
public interface JpaModel extends Model {
/**
+ * Return the JPA model's JPA projects.
+ */
+ Iterable<JpaProject> getJpaProjects();
+ public static final String JPA_PROJECTS_COLLECTION = "jpaProjects"; //$NON-NLS-1$
+
+ /**
+ * Return the size of the JPA model's list of JPA projects.
+ */
+ int getJpaProjectsSize();
+
+ /**
* Return the JPA project corresponding to the specified Eclipse project.
* Return null if unable to associate the specified Eclipse project
* with a JPA project.
*/
- JpaProject getJpaProject(IProject project) throws CoreException;
+ JpaProject getJpaProject(IProject project);
/**
- * Return whether the JPA model contains a JPA project corresponding
- * to the specified Eclipse project.
+ * Return the JPA file corresponding to the specified Eclipse file,
+ * or null if unable to associate the specified file with a JPA file.
*/
- boolean containsJpaProject(IProject project);
+ JpaFile getJpaFile(IFile file);
/**
- * Return the JPA model's JPA projects. This has performance implications,
- * it will build all the JPA projects.
+ * The JPA settings associated with the specified Eclipse project
+ * have changed in such a way as to require the associated
+ * JPA project to be completely rebuilt
+ * (e.g. when the user changes a project's JPA platform).
*/
- Iterator<JpaProject> jpaProjects() throws CoreException;
- public static final String JPA_PROJECTS_COLLECTION = "jpaProjects"; //$NON-NLS-1$
+ void rebuildJpaProject(IProject project);
/**
- * Return the size of the JPA model's list of JPA projects.
+ * Return whether the model's Java change listener is active.
*/
- int jpaProjectsSize();
-
+ boolean javaElementChangeListenerIsActive();
+
/**
- * Return the JPA file corresponding to the specified Eclipse file,
- * or null if unable to associate the specified file with a JPA file.
+ * Set whether the model's Java change listener is active.
*/
- JpaFile getJpaFile(IFile file) throws CoreException;
+ void setJavaElementChangeListenerIsActive(boolean javaElementChangeListenerIsActive);
}
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaProject.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaProject.java
index 55a7ca4bf5..4f63da8621 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaProject.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JpaProject.java
@@ -10,10 +10,10 @@
package org.eclipse.jpt.core;
import java.util.Iterator;
+
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceDelta;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.ElementChangedEvent;
@@ -202,7 +202,7 @@ public interface JpaProject
* Synchronize the JPA project with the specified project resource
* delta, watching for added and removed files in particular.
*/
- void projectChanged(IResourceDelta delta) throws CoreException;
+ void projectChanged(IResourceDelta delta);
/**
* Synchronize the JPA project with the specified Java change.
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JptCorePlugin.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JptCorePlugin.java
index cc92e43820..98260f81f8 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JptCorePlugin.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/JptCorePlugin.java
@@ -10,6 +10,7 @@
package org.eclipse.jpt.core;
import javax.xml.parsers.SAXParserFactory;
+
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
@@ -28,10 +29,8 @@ import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jpt.core.internal.GenericJpaPlatformProvider;
-import org.eclipse.jpt.core.internal.JpaModelManager;
import org.eclipse.jpt.core.internal.JpaPlatformRegistry;
import org.eclipse.jpt.core.internal.jpa2.Generic2_0JpaPlatformProvider;
-import org.eclipse.jpt.core.internal.prefs.JpaPreferenceInitializer;
import org.eclipse.jpt.utility.internal.StringTools;
import org.eclipse.jst.j2ee.internal.J2EEConstants;
import org.eclipse.wst.common.componentcore.ComponentCore;
@@ -44,20 +43,21 @@ import org.osgi.service.prefs.Preferences;
import org.osgi.util.tracker.ServiceTracker;
/**
- * The JPT plug-in lifecycle implementation.
+ * The Dali core plug-in lifecycle implementation.
* A number of globally-available constants and methods.
- *
+ * <p>
* Provisional API: This class is part of an interim API that is still
* under development and expected to change significantly before reaching
* stability. It is available at this early stage to solicit feedback from
* pioneering adopters on the understanding that any code that uses this API
* will almost certainly be broken (repeatedly) as the API evolves.
*/
-// TODO keep preferences in synch with the JPA project
-// (connection profile name, "discover" flag)
-// use listeners?
public class JptCorePlugin extends Plugin {
+ private volatile GenericJpaModel jpaModel;
+ private volatile ServiceTracker parserTracker;
+
+
// ********** public constants **********
/**
@@ -145,18 +145,18 @@ public class JptCorePlugin extends Plugin {
public static final JpaResourceType JAVA_SOURCE_RESOURCE_TYPE = new JpaResourceType(JAVA_SOURCE_CONTENT_TYPE);
/**
- * The content type for persistence.xml files.
+ * The content type for <code>persistence.xml</code> files.
*/
public static final IContentType PERSISTENCE_XML_CONTENT_TYPE = getJpaContentType("persistence"); //$NON-NLS-1$
/**
- * The resource type for persistence.xml version 1.0 files
+ * The resource type for <code>persistence.xml</code> version 1.0 files
*/
public static final JpaResourceType PERSISTENCE_XML_1_0_RESOURCE_TYPE =
new JpaResourceType(PERSISTENCE_XML_CONTENT_TYPE, org.eclipse.jpt.core.resource.persistence.JPA.SCHEMA_VERSION);
/**
- * The resource type for persistence.xml version 2.0 files
+ * The resource type for <code>persistence.xml</code> version 2.0 files
*/
public static final JpaResourceType PERSISTENCE_XML_2_0_RESOURCE_TYPE =
new JpaResourceType(PERSISTENCE_XML_CONTENT_TYPE, org.eclipse.jpt.core.resource.persistence.v2_0.JPA2_0.SCHEMA_VERSION);
@@ -167,18 +167,18 @@ public class JptCorePlugin extends Plugin {
public static final IContentType MAPPING_FILE_CONTENT_TYPE = getJpaContentType("mappingFile"); //$NON-NLS-1$
/**
- * The content type for orm.xml mapping files.
+ * The content type for <code>orm.xml</code> mapping files.
*/
public static final IContentType ORM_XML_CONTENT_TYPE = getJpaContentType("orm"); //$NON-NLS-1$
/**
- * The resource type for orm.xml version 1.0 mapping files
+ * The resource type for <code>orm.xml</code> version 1.0 mapping files
*/
public static final JpaResourceType ORM_XML_1_0_RESOURCE_TYPE =
new JpaResourceType(ORM_XML_CONTENT_TYPE, org.eclipse.jpt.core.resource.orm.JPA.SCHEMA_VERSION);
/**
- * The resource type for orm.xml version 2.0 mapping files
+ * The resource type for <code>orm.xml</code> version 2.0 mapping files
*/
public static final JpaResourceType ORM_XML_2_0_RESOURCE_TYPE =
new JpaResourceType(ORM_XML_CONTENT_TYPE, org.eclipse.jpt.core.resource.orm.v2_0.JPA2_0.SCHEMA_VERSION);
@@ -189,7 +189,7 @@ public class JptCorePlugin extends Plugin {
public static final IContentType JAR_CONTENT_TYPE = getJpaContentType("jar"); //$NON-NLS-1$
/**
- * The resource type for Java archives (JARs)
+ * The resource type for Java archives (JARs).
*/
public static final JpaResourceType JAR_RESOURCE_TYPE = new JpaResourceType(JAR_CONTENT_TYPE);
@@ -220,14 +220,12 @@ public class JptCorePlugin extends Plugin {
}
- private ServiceTracker parserTracker;
-
// ********** singleton **********
private static JptCorePlugin INSTANCE;
/**
- * Return the singleton JPT plug-in.
+ * Return the singleton Dali core plug-in.
*/
public static JptCorePlugin instance() {
return INSTANCE;
@@ -240,34 +238,34 @@ public class JptCorePlugin extends Plugin {
* Return the singular JPA model corresponding to the current workspace.
*/
public static JpaModel getJpaModel() {
- return JpaModelManager.instance().getJpaModel();
+ return INSTANCE.getJpaModel_();
}
/**
* Return the JPA project corresponding to the specified Eclipse project,
- * or null if unable to associate the specified project with a
+ * or <code>null</code> if unable to associate the specified project with a
* JPA project.
*/
public static JpaProject getJpaProject(IProject project) {
- try {
- return JpaModelManager.instance().getJpaProject(project);
- } catch (CoreException ex) {
- log(ex);
- return null;
- }
+ return getJpaModel().getJpaProject(project);
}
/**
* Return the JPA file corresponding to the specified Eclipse file,
- * or null if unable to associate the specified file with a JPA file.
+ * or <code>null</code> if unable to associate the specified file with a JPA file.
*/
public static JpaFile getJpaFile(IFile file) {
- try {
- return JpaModelManager.instance().getJpaFile(file);
- } catch (CoreException ex) {
- log(ex);
- return null;
- }
+ return getJpaModel().getJpaFile(file);
+ }
+
+ /**
+ * The JPA settings associated with the specified Eclipse project
+ * have changed in such a way as to require the associated
+ * JPA project to be completely rebuilt
+ * (e.g. when the user changes a project's JPA platform).
+ */
+ public static void rebuildJpaProject(IProject project) {
+ getJpaModel().rebuildJpaProject(project);
}
/**
@@ -278,7 +276,7 @@ public class JptCorePlugin extends Plugin {
}
/**
- * Return whether the specified Eclipse project has a JPA facet.
+ * Return whether the specified Eclipse project has a Web facet.
*/
public static boolean projectHasWebFacet(IProject project) {
return projectHasFacet(project, WEB_PROJECT_FACET_ID);
@@ -297,7 +295,7 @@ public class JptCorePlugin extends Plugin {
}
/**
- * Return the persistence.xml (specified as "META-INF/persistence.xml")
+ * Return the <code>persistence.xml</code> (specified as <code>"META-INF/persistence.xml"</code>)
* deployment URI for the specified project.
*/
public static String getPersistenceXmlDeploymentURI(IProject project) {
@@ -305,7 +303,7 @@ public class JptCorePlugin extends Plugin {
}
/**
- * Return the default mapping file (specified as "META-INF/orm.xml")
+ * Return the default mapping file (specified as <code>"META-INF/orm.xml"</code>)
* deployment URI for the specified project.
*/
public static String getDefaultOrmXmlDeploymentURI(IProject project) {
@@ -313,7 +311,7 @@ public class JptCorePlugin extends Plugin {
}
/**
- * Return the mapping file (specified as "META-INF/<mappingFileName>")
+ * Return the mapping file (specified as {@code"META-INF/<mappingFileName>"})
* deployment URI for the specified project.
*/
public static String getOrmXmlDeploymentURI(IProject project, String mappingFileName) {
@@ -322,7 +320,7 @@ public class JptCorePlugin extends Plugin {
/**
* Tweak the specified deployment URI if the specified project
- * has a web facet.
+ * has a Web facet.
*/
public static String getDeploymentURI(IProject project, String defaultURI) {
return projectHasWebFacet(project) ?
@@ -332,9 +330,9 @@ public class JptCorePlugin extends Plugin {
}
/**
- * Return the deployment path to which jars are relatively specified for
- * the given project
- * (Web projects have a different deployment structure than non-web projects)
+ * Return the deployment path to which JARs are relatively specified for
+ * the given project.
+ * (Web projects have a different deployment structure than non-web projects.)
*/
public static IPath getJarDeploymentRootPath(IProject project) {
return new Path(getJarDeploymentRootPathName(project));
@@ -415,12 +413,10 @@ public class JptCorePlugin extends Plugin {
if (jpaFacetVersion.equals(JPA_FACET_VERSION_1_0)) {
return GenericJpaPlatformProvider.ID;
}
- else if (jpaFacetVersion.equals(JPA_FACET_VERSION_2_0)) {
+ if (jpaFacetVersion.equals(JPA_FACET_VERSION_2_0)) {
return Generic2_0JpaPlatformProvider.ID;
}
- else {
- throw new IllegalArgumentException("Illegal JPA facet version: " + jpaFacetVersion);
- }
+ throw new IllegalArgumentException("Illegal JPA facet version: " + jpaFacetVersion); //$NON-NLS-1$
}
private static String getDefaultJpaPlatformId(Preferences... nodes) {
@@ -602,6 +598,20 @@ public class JptCorePlugin extends Plugin {
}
/**
+ * Return whether the model manager's Java change listener is active.
+ */
+ public static boolean javaElementChangeListenerIsActive() {
+ return getJpaModel().javaElementChangeListenerIsActive();
+ }
+
+ /**
+ * Set whether the model manager's Java change listener is active.
+ */
+ public static void setJavaElementChangeListenerIsActive(boolean javaElementChangeListenerIsActive) {
+ getJpaModel().setJavaElementChangeListenerIsActive(javaElementChangeListenerIsActive);
+ }
+
+ /**
* Log the specified status.
*/
public static void log(IStatus status) {
@@ -638,13 +648,16 @@ public class JptCorePlugin extends Plugin {
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
- JpaModelManager.instance().start();
+ // nothing yet...
}
@Override
public void stop(BundleContext context) throws Exception {
try {
- JpaModelManager.instance().stop();
+ if (this.jpaModel != null) {
+ this.jpaModel.stop();
+ this.jpaModel = null;
+ }
if (this.parserTracker != null) {
this.parserTracker.close();
this.parserTracker = null;
@@ -654,6 +667,18 @@ public class JptCorePlugin extends Plugin {
}
}
+ private synchronized GenericJpaModel getJpaModel_() {
+ if (this.jpaModel == null) {
+ this.jpaModel = this.buildJpaModel();
+ this.jpaModel.start();
+ }
+ return this.jpaModel;
+ }
+
+ private GenericJpaModel buildJpaModel() {
+ return new GenericJpaModel();
+ }
+
public synchronized SAXParserFactory getSAXParserFactory() {
SAXParserFactory factory = (SAXParserFactory) this.getParserTracker().getService();
if (factory != null) {
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractJpaFactory.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractJpaFactory.java
index efacae6803..4ce3c05476 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractJpaFactory.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractJpaFactory.java
@@ -10,7 +10,6 @@
package org.eclipse.jpt.core.internal;
import org.eclipse.core.resources.IFile;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jpt.core.JpaDataSource;
import org.eclipse.jpt.core.JpaFile;
@@ -155,7 +154,7 @@ public abstract class AbstractJpaFactory
// ********** Core Model **********
- public JpaProject buildJpaProject(JpaProject.Config config) throws CoreException {
+ public JpaProject buildJpaProject(JpaProject.Config config) {
return new GenericJpaProject((JpaProject2_0.Config) config);
}
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractJpaProject.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractJpaProject.java
index ca0ed219c7..0058ec7e0d 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractJpaProject.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/AbstractJpaProject.java
@@ -191,7 +191,7 @@ public abstract class AbstractJpaProject
// ********** constructor/initialization **********
- protected AbstractJpaProject(JpaProject2_0.Config config) throws CoreException {
+ protected AbstractJpaProject(JpaProject2_0.Config config) {
super(null); // JPA project is the root of the containment tree
if ((config.getProject() == null) || (config.getJpaPlatform() == null)) {
throw new NullPointerException();
@@ -207,7 +207,8 @@ public abstract class AbstractJpaProject
this.resourceModelListener = this.buildResourceModelListener();
// build the JPA files corresponding to the Eclipse project's files
- this.project.accept(this.buildInitialResourceProxyVisitor(), IResource.NONE);
+ InitialResourceProxyVisitor visitor = this.buildInitialResourceProxyVisitor();
+ visitor.visitProject(this.project);
this.externalJavaResourcePersistentTypeCache = this.buildExternalJavaResourcePersistentTypeCache();
@@ -243,7 +244,7 @@ public abstract class AbstractJpaProject
return new DefaultResourceModelListener();
}
- protected IResourceProxyVisitor buildInitialResourceProxyVisitor() {
+ protected InitialResourceProxyVisitor buildInitialResourceProxyVisitor() {
return new InitialResourceProxyVisitor();
}
@@ -286,8 +287,16 @@ public abstract class AbstractJpaProject
protected InitialResourceProxyVisitor() {
super();
}
+ protected void visitProject(IProject p) {
+ try {
+ p.accept(this, IResource.NONE);
+ } catch (CoreException ex) {
+ // 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) throws CoreException {
+ public boolean visit(IResourceProxy resource) {
switch (resource.getType()) {
case IResource.ROOT : // shouldn't happen
return true; // visit children
@@ -1227,7 +1236,7 @@ public abstract class AbstractJpaProject
// ********** resource events **********
// TODO need to do the same thing for external projects and compilation units
- public void projectChanged(IResourceDelta delta) throws CoreException {
+ public void projectChanged(IResourceDelta delta) {
if (delta.getResource().equals(this.getProject())) {
this.internalProjectChanged(delta);
} else {
@@ -1235,9 +1244,9 @@ public abstract class AbstractJpaProject
}
}
- protected void internalProjectChanged(IResourceDelta delta) throws CoreException {
+ protected void internalProjectChanged(IResourceDelta delta) {
ResourceDeltaVisitor resourceDeltaVisitor = this.buildInternalResourceDeltaVisitor();
- delta.accept(resourceDeltaVisitor);
+ 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
@@ -1304,10 +1313,10 @@ public abstract class AbstractJpaProject
}
}
- protected void externalProjectChanged(IResourceDelta delta) throws CoreException {
+ protected void externalProjectChanged(IResourceDelta delta) {
if (this.getJavaProject().isOnClasspath(delta.getResource())) {
ResourceDeltaVisitor resourceDeltaVisitor = this.buildExternalResourceDeltaVisitor();
- delta.accept(resourceDeltaVisitor);
+ 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()) {
@@ -1396,7 +1405,16 @@ public abstract class AbstractJpaProject
super();
}
- public boolean visit(IResourceDelta delta) throws CoreException {
+ protected void visitDelta(IResourceDelta delta) {
+ try {
+ delta.accept(this);
+ } catch (CoreException ex) {
+ // 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 :
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaModel.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaModel.java
deleted file mode 100644
index 9bdaceb461..0000000000
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/GenericJpaModel.java
+++ /dev/null
@@ -1,528 +0,0 @@
-/*******************************************************************************
- * 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.Iterator;
-import org.eclipse.core.commands.ExecutionException;
-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.IResourceProxy;
-import org.eclipse.core.resources.IResourceProxyVisitor;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.jdt.core.ElementChangedEvent;
-import org.eclipse.jpt.core.JpaFile;
-import org.eclipse.jpt.core.JpaModel;
-import org.eclipse.jpt.core.JpaPlatform;
-import org.eclipse.jpt.core.JpaProject;
-import org.eclipse.jpt.core.JptCorePlugin;
-import org.eclipse.jpt.core.JpaProject.Config;
-import org.eclipse.jpt.core.internal.facet.JpaFacetInstallDataModelProperties;
-import org.eclipse.jpt.core.internal.operations.OrmFileCreationDataModelProperties;
-import org.eclipse.jpt.core.internal.operations.OrmFileCreationDataModelProvider;
-import org.eclipse.jpt.core.internal.operations.PersistenceFileCreationDataModelProperties;
-import org.eclipse.jpt.core.internal.operations.PersistenceFileCreationDataModelProvider;
-import org.eclipse.jpt.utility.internal.ClassTools;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.jpt.utility.internal.model.AbstractModel;
-import org.eclipse.wst.common.frameworks.datamodel.DataModelFactory;
-import org.eclipse.wst.common.frameworks.datamodel.IDataModel;
-import org.eclipse.wst.common.project.facet.core.events.IProjectFacetActionEvent;
-
-/**
- * The JPA model is synchronized so all changes to the list of JPA projects
- * are thread-safe.
- *
- * The JPA model holds on to a list of JPA project configs and only instantiates
- * their associated JPA projects when necessary. Other than performance,
- * this should be transparent to clients.
- */
-public class GenericJpaModel
- extends AbstractModel
- implements JpaModel
-{
-
- /** maintain a list of all the current JPA projects */
- private final ArrayList<JpaProjectHolder> jpaProjectHolders = new ArrayList<JpaProjectHolder>();
-
-
- // ********** constructor **********
-
- /**
- * Construct a JPA model and populate it with JPA projects for all the
- * current Eclipse projects with JPA facets.
- * The JPA model can only be instantiated by the JPA model manager.
- */
- GenericJpaModel() throws CoreException {
- super();
- ResourcesPlugin.getWorkspace().getRoot().accept(new ResourceProxyVisitor(), IResource.NONE);
- }
-
-
- // ********** IJpaModel implementation **********
-
- /**
- * This will trigger the instantiation of the JPA project associated with the
- * specified Eclipse project.
- */
- public synchronized JpaProject getJpaProject(IProject project) throws CoreException {
- return this.getJpaProjectHolder(project).jpaProject();
- }
-
- /**
- * We can answer this question without instantiating the
- * associated JPA project.
- */
- public synchronized boolean containsJpaProject(IProject project) {
- return this.getJpaProjectHolder(project).holdsJpaProjectFor(project);
- }
-
- /**
- * This will trigger the instantiation of all the JPA projects.
- */
- public synchronized Iterator<JpaProject> jpaProjects() throws CoreException {
- // force the CoreException to occur here (instead of later, in Iterator#next())
- ArrayList<JpaProject> jpaProjects = new ArrayList<JpaProject>(this.jpaProjectHolders.size());
- for (JpaProjectHolder holder : this.jpaProjectHolders) {
- jpaProjects.add(holder.jpaProject());
- }
- return jpaProjects.iterator();
- }
-
- /**
- * We can answer this question without instantiating any JPA projects.
- */
- public synchronized int jpaProjectsSize() {
- return this.jpaProjectHolders.size();
- }
-
- /**
- * This will trigger the instantiation of the JPA project associated with the
- * specified file.
- */
- public synchronized JpaFile getJpaFile(IFile file) throws CoreException {
- JpaProject jpaProject = this.getJpaProject(file.getProject());
- return (jpaProject == null) ? null : jpaProject.getJpaFile(file);
- }
-
-
- // ********** internal methods **********
-
- /**
- * never return null
- */
- private JpaProjectHolder getJpaProjectHolder(IProject project) {
- for (JpaProjectHolder holder : this.jpaProjectHolders) {
- if (holder.holdsJpaProjectFor(project)) {
- return holder;
- }
- }
- return NullJpaProjectHolder.instance();
- }
-
- private JpaProject.Config buildJpaProjectConfig(IProject project) {
- SimpleJpaProjectConfig config = new SimpleJpaProjectConfig();
- config.setProject(project);
- config.setJpaPlatform(JptCorePlugin.getJpaPlatform(project));
- config.setConnectionProfileName(JptCorePlugin.getConnectionProfileName(project));
- config.setUserOverrideDefaultCatalog(JptCorePlugin.getUserOverrideDefaultCatalog(project));
- config.setUserOverrideDefaultSchema(JptCorePlugin.getUserOverrideDefaultSchema(project));
- config.setDiscoverAnnotatedClasses(JptCorePlugin.discoverAnnotatedClasses(project));
- config.setMetamodelSourceFolderName(JptCorePlugin.getMetamodelSourceFolderName(project));
- return config;
- }
-
- /* private */ void addJpaProject(IProject project) {
- this.addJpaProject(this.buildJpaProjectConfig(project));
- }
-
- /**
- * Add a JPA project to the JPA model for the specified Eclipse project.
- * JPA projects can only be added by the JPA model manager.
- * The JPA project will only be instantiated later, on demand.
- */
- private void addJpaProject(JpaProject.Config config) {
- dumpStackTrace(); // figure out exactly when JPA projects are added
- this.jpaProjectHolders.add(this.getJpaProjectHolder(config.getProject()).buildJpaProjectHolder(this, config));
- }
-
- /**
- * Remove the JPA project corresponding to the specified Eclipse project
- * from the JPA model. Return whether the removal actually happened.
- * JPA projects can only be removed by the JPA model manager.
- */
- private void removeJpaProject(IProject project) {
- dumpStackTrace(); // figure out exactly when JPA projects are removed
- this.getJpaProjectHolder(project).remove();
- }
-
-
- // ********** Resource events **********
-
- /**
- * A project is being deleted. Remove its corresponding
- * JPA project if appropriate.
- */
- synchronized void projectPreDelete(IProject project) {
- this.removeJpaProject(project);
- }
-
- /**
- * Forward the specified resource delta to all our JPA projects;
- * they will each determine whether the event is significant.
- */
- synchronized void projectChanged(IResourceDelta delta) throws CoreException {
- for (JpaProjectHolder holder : this.jpaProjectHolders) {
- holder.projectChanged(delta);
- }
- }
-
-
- // ********** Resource and/or Facet events **********
-
- /**
- * Check whether the JPA facet has been added or removed.
- */
- synchronized void checkForTransition(IProject project) {
- boolean jpaFacet = JptCorePlugin.projectHasJpaFacet(project);
- boolean jpaProject = this.containsJpaProject(project);
-
- if (jpaFacet) {
- if ( ! jpaProject) { // JPA facet added
- this.addJpaProject(project);
- }
- } else {
- if (jpaProject) { // JPA facet removed
- this.removeJpaProject(project);
- }
- }
- }
-
-
- // ********** Facet events **********
-
- synchronized void jpaFacetedProjectPostInstall(IProjectFacetActionEvent event) {
- IProject project = event.getProject().getProject();
- IDataModel dataModel = (IDataModel) event.getActionConfig();
-
- boolean buildOrmXml = dataModel.getBooleanProperty(JpaFacetInstallDataModelProperties.CREATE_ORM_XML);
- this.createProjectXml(project, buildOrmXml);
-
- // assume(?) this is the first event to indicate we need to add the JPA project to the JPA model
- this.addJpaProject(project);
- }
-
- private void createProjectXml(IProject project, boolean buildOrmXml) {
- this.createPersistenceXml(project);
-
- if (buildOrmXml) {
- this.createOrmXml(project);
- }
- }
-
- private void createPersistenceXml(IProject project) {
- IDataModel config =
- DataModelFactory.createDataModel(new PersistenceFileCreationDataModelProvider());
- config.setProperty(PersistenceFileCreationDataModelProperties.PROJECT_NAME, project.getName());
- // default values for all other properties should suffice
- try {
- config.getDefaultOperation().execute(null, null);
- }
- catch (ExecutionException e) {
- JptCorePlugin.log(e);
- }
- }
-
- private void createOrmXml(IProject project) {
- IDataModel config =
- DataModelFactory.createDataModel(new OrmFileCreationDataModelProvider());
- config.setProperty(OrmFileCreationDataModelProperties.PROJECT_NAME, project.getName());
- // default values for all other properties should suffice
- try {
- config.getDefaultOperation().execute(null, null);
- }
- catch (ExecutionException e) {
- JptCorePlugin.log(e);
- }
- }
-
- // TODO remove classpath items? persistence.xml? orm.xml?
- synchronized void jpaFacetedProjectPreUninstall(IProjectFacetActionEvent event) {
- // assume(?) this is the first event to indicate we need to remove the JPA project to the JPA model
- this.removeJpaProject(event.getProject().getProject());
- }
-
-
- // ********** Java events **********
-
- /**
- * Forward the Java element changed event to all the JPA projects
- * because the event could affect multiple projects.
- */
- synchronized void javaElementChanged(ElementChangedEvent event) {
- for (JpaProjectHolder jpaProjectHolder : this.jpaProjectHolders) {
- jpaProjectHolder.javaElementChanged(event);
- }
- }
-
-
- // ********** miscellaneous **********
-
- /**
- * The JPA settings associated with the specified Eclipse project
- * have changed in such a way as to require the associated
- * JPA project to be completely rebuilt
- * (e.g. when the user changes a project's JPA platform).
- */
- synchronized void rebuildJpaProject(IProject project) {
- this.removeJpaProject(project);
- this.addJpaProject(project);
- }
-
- /**
- * Dispose the JPA model by disposing and removing all its JPA projects.
- * The JPA model can only be disposed by the JPA model manager.
- */
- synchronized void dispose() {
- // clone the list to prevent concurrent modification exceptions
- JpaProjectHolder[] holders = this.jpaProjectHolders.toArray(new JpaProjectHolder[this.jpaProjectHolders.size()]);
- for (JpaProjectHolder holder : holders) {
- holder.remove();
- }
- }
-
- @Override
- public void toString(StringBuilder sb) {
- sb.append("JPA projects size: " + this.jpaProjectsSize()); //$NON-NLS-1$
- }
-
-
- // ********** holder callbacks **********
-
- /**
- * called by the JPA project holder when the JPA project is actually
- * instantiated
- */
- /* private */ void jpaProjectBuilt(JpaProject jpaProject) {
- this.fireItemAdded(JPA_PROJECTS_COLLECTION, jpaProject);
- }
-
- /**
- * called by the JPA project holder if the JPA project has been
- * instantiated and we need to remove it
- */
- /* private */ void jpaProjectRemoved(JpaProject jpaProject) {
- this.fireItemRemoved(JPA_PROJECTS_COLLECTION, jpaProject);
- }
-
- /**
- * called by the JPA project holder
- */
- /* private */ void removeJpaProjectHolder(JpaProjectHolder jpaProjectHolder) {
- this.jpaProjectHolders.remove(jpaProjectHolder);
- }
-
-
- // ********** JPA project holders **********
-
- private interface JpaProjectHolder {
-
- boolean holdsJpaProjectFor(IProject project);
-
- JpaProject jpaProject() throws CoreException;
-
- void projectChanged(IResourceDelta delta) throws CoreException;
-
- void javaElementChanged(ElementChangedEvent event);
-
- JpaProjectHolder buildJpaProjectHolder(GenericJpaModel jpaModel, JpaProject.Config config);
-
- void remove();
-
- }
-
- private static class NullJpaProjectHolder implements JpaProjectHolder {
- private static final JpaProjectHolder INSTANCE = new NullJpaProjectHolder();
-
- static JpaProjectHolder instance() {
- return INSTANCE;
- }
-
- // ensure single instance
- private NullJpaProjectHolder() {
- super();
- }
-
- public boolean holdsJpaProjectFor(IProject project) {
- return false;
- }
-
- public JpaProject jpaProject() throws CoreException {
- return null;
- }
-
- public void projectChanged(IResourceDelta delta) throws CoreException {
- // do nothing
- }
-
- public void javaElementChanged(ElementChangedEvent event) {
- // do nothing
- }
-
- public JpaProjectHolder buildJpaProjectHolder(GenericJpaModel jpaModel, Config config) {
- return new DefaultJpaProjectHolder(jpaModel, config);
- }
-
- public void remove() {
- // do nothing
- }
-
- @Override
- public String toString() {
- return ClassTools.shortClassNameForObject(this);
- }
- }
-
- /**
- * Pair a JPA project config with its lazily-initialized JPA project.
- */
- private static class DefaultJpaProjectHolder implements JpaProjectHolder {
- private final GenericJpaModel jpaModel;
- private final JpaProject.Config config;
- private JpaProject jpaProject;
-
- DefaultJpaProjectHolder(GenericJpaModel jpaModel, JpaProject.Config config) {
- super();
- this.jpaModel = jpaModel;
- this.config = config;
- }
-
- public boolean holdsJpaProjectFor(IProject project) {
- return this.config.getProject().equals(project);
- }
-
- public JpaProject jpaProject() throws CoreException {
- if (this.jpaProject == null) {
- this.jpaProject = this.buildJpaProject();
- // notify listeners of the JPA model
- this.jpaModel.jpaProjectBuilt(this.jpaProject);
- }
- return this.jpaProject;
- }
-
- private JpaProject buildJpaProject() throws CoreException {
- JpaPlatform jpaPlatform = this.config.getJpaPlatform();
- if (jpaPlatform == null) {
- return null;
- }
- JpaProject result = jpaPlatform.getJpaFactory().buildJpaProject(this.config);
- result.setUpdater(new AsynchronousJpaProjectUpdater(result));
- return result;
- }
-
- public void projectChanged(IResourceDelta delta) throws CoreException {
- if (this.jpaProject != null) {
- this.jpaProject.projectChanged(delta);
- }
- }
-
- public void javaElementChanged(ElementChangedEvent event) {
- if (this.jpaProject != null) {
- this.jpaProject.javaElementChanged(event);
- }
- }
-
- public JpaProjectHolder buildJpaProjectHolder(GenericJpaModel jm, Config c) {
- throw new IllegalArgumentException(c.getProject().getName());
- }
-
- public void remove() {
- this.jpaModel.removeJpaProjectHolder(this);
- if (this.jpaProject != null) {
- this.jpaModel.jpaProjectRemoved(this.jpaProject);
- this.jpaProject.dispose();
- }
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.config.getProject().getName());
- }
-
- }
-
-
- // ********** resource proxy visitor **********
-
- /**
- * Visit the workspace resource tree, adding a JPA project to the
- * JPA model for each open Eclipse project that has a JPA facet.
- */
- private class ResourceProxyVisitor implements IResourceProxyVisitor {
-
- ResourceProxyVisitor() {
- super();
- }
-
- public boolean visit(IResourceProxy resourceProxy) throws CoreException {
- switch (resourceProxy.getType()) {
- case IResource.ROOT :
- return true; // all projects are in the "root"
- case IResource.PROJECT :
- this.checkProject(resourceProxy);
- return false; // no nested projects
- default :
- return false;
- }
- }
-
- private void checkProject(IResourceProxy resourceProxy) {
- if (resourceProxy.isAccessible()) { // the project exists and is open
- IProject project = (IProject) resourceProxy.requestResource();
- if (JptCorePlugin.projectHasJpaFacet(project)) {
- GenericJpaModel.this.addJpaProject(project);
- }
- }
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this);
- }
-
- }
-
-
- // ********** DEBUG **********
-
- // @see JpaModelTests#testDEBUG()
- private static final boolean DEBUG = false;
-
- private static void dumpStackTrace() {
- if (DEBUG) {
- // lock System.out so the stack elements are printed out contiguously
- synchronized (System.out) {
- StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
- // skip the first 3 elements - those are this method and 2 methods in Thread
- for (int i = 3; i < stackTrace.length; i++) {
- StackTraceElement element = stackTrace[i];
- if (element.getMethodName().equals("invoke0")) { //$NON-NLS-1$
- break; // skip all elements outside of the JUnit test
- }
- System.out.println("\t" + element); //$NON-NLS-1$
- }
- }
- }
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/JpaModelManager.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/JpaModelManager.java
deleted file mode 100644
index b4ec22bef0..0000000000
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/JpaModelManager.java
+++ /dev/null
@@ -1,590 +0,0 @@
-/*******************************************************************************
- * Copyright (c) 2006, 2008 Oracle. All rights reserved.
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0, which accompanies this distribution
- * and is available at http://www.eclipse.org/legal/epl-v10.html.
- *
- * Contributors:
- * Oracle - initial API and implementation
- ******************************************************************************/
-package org.eclipse.jpt.core.internal;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.resources.IResourceChangeEvent;
-import org.eclipse.core.resources.IResourceChangeListener;
-import org.eclipse.core.resources.IResourceDelta;
-import org.eclipse.core.resources.IWorkspace;
-import org.eclipse.core.resources.IncrementalProjectBuilder;
-import org.eclipse.core.resources.ResourcesPlugin;
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.core.runtime.IStatus;
-import org.eclipse.jdt.core.ElementChangedEvent;
-import org.eclipse.jdt.core.IElementChangedListener;
-import org.eclipse.jdt.core.IJavaElement;
-import org.eclipse.jdt.core.IJavaElementDelta;
-import org.eclipse.jdt.core.IOpenable;
-import org.eclipse.jdt.core.JavaCore;
-import org.eclipse.jpt.core.JpaFile;
-import org.eclipse.jpt.core.JpaModel;
-import org.eclipse.jpt.core.JpaProject;
-import org.eclipse.jpt.core.JptCorePlugin;
-import org.eclipse.jpt.utility.internal.BitTools;
-import org.eclipse.jpt.utility.internal.StringTools;
-import org.eclipse.wst.common.project.facet.core.FacetedProjectFramework;
-import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectEvent;
-import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectListener;
-import org.eclipse.wst.common.project.facet.core.events.IProjectFacetActionEvent;
-
-/**
- * "Internal" global stuff.
- * Provide access via a singleton.
- * Hold and manage the JPA model (which holds all the JPA projects)
- * and the various global listeners. We attempt to determine whether events
- * are relevant before forwarding them to the JPA model.
- *
- * Various things that cause us to add or remove a JPA project:
- * - Startup of the Dali plug-in will trigger all the JPA projects to be added
- *
- * - Project created and facet installed
- * facet POST_INSTALL
- * - Project facet uninstalled
- * facet PRE_UNINSTALL
- *
- * - Project opened
- * facet PROJECT_MODIFIED
- * - Project closed
- * facet PROJECT_MODIFIED
- *
- * - Pre-existing project imported from directory or archive (created and opened)
- * resource POST_CHANGE -> PROJECT -> ADDED -> OPEN
- * - Project deleted
- * resource PRE_DELETE
- *
- * - Project facet installed by editing the facets settings file directly
- * facet PROJECT_MODIFIED
- * - Project facet uninstalled by editing the facets settings file directly
- * facet PROJECT_MODIFIED
- */
-public class JpaModelManager {
-
- /**
- * The JPA model - null until the plug-in is started.
- */
- private GenericJpaModel jpaModel;
-
- /**
- * Listen for changes to projects and files.
- */
- private final IResourceChangeListener resourceChangeListener;
-
- /**
- * Listen for the JPA facet being added or removed from a project.
- */
- private final IFacetedProjectListener facetedProjectListener;
-
- /**
- * Listen for Java changes and forward them to the JPA model,
- * which will forward them to the JPA projects.
- */
- private final IElementChangedListener javaElementChangeListener;
- private boolean javaElementChangeListenerIsActive;
-
-
- // ********** singleton **********
-
- private static final JpaModelManager INSTANCE = new JpaModelManager();
-
- /**
- * Return the singleton JPA model manager.
- */
- public static JpaModelManager instance() {
- return INSTANCE;
- }
-
-
- // ********** constructor **********
-
- /**
- * Private - ensure single instance.
- */
- private JpaModelManager() {
- super();
- this.resourceChangeListener = new ResourceChangeListener();
- this.facetedProjectListener = new FacetedProjectListener();
- this.javaElementChangeListener = new JavaElementChangeListener();
- this.javaElementChangeListenerIsActive = true;
- }
-
-
- // ********** plug-in controlled life-cycle **********
-
- /**
- * internal - called by JptCorePlugin
- */
- public synchronized void start() throws Exception {
- debug("*** START JPA model manager ***"); //$NON-NLS-1$
- try {
- this.jpaModel = new GenericJpaModel();
- ResourcesPlugin.getWorkspace().addResourceChangeListener(
- this.resourceChangeListener,
- IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.POST_BUILD);
- FacetedProjectFramework.addListener(this.facetedProjectListener, IFacetedProjectEvent.Type.values());
- JavaCore.addElementChangedListener(this.javaElementChangeListener);
- } catch (RuntimeException ex) {
- this.log(ex);
- this.stop();
- }
- }
-
- /**
- * internal - called by JptCorePlugin
- */
- public synchronized void stop() throws Exception {
- debug("*** STOP JPA model manager ***"); //$NON-NLS-1$
- JavaCore.removeElementChangedListener(this.javaElementChangeListener);
- FacetedProjectFramework.removeListener(this.facetedProjectListener);
- ResourcesPlugin.getWorkspace().removeResourceChangeListener(this.resourceChangeListener);
- this.jpaModel.dispose();
- this.jpaModel = null;
- }
-
-
- // ********** API **********
-
- /**
- * Return the workspace-wide JPA model.
- */
- public JpaModel getJpaModel() {
- return this.jpaModel;
- }
-
- /**
- * Return the JPA project corresponding to the specified Eclipse project,
- * or null if unable to associate the specified project with a
- * JPA project.
- */
- public JpaProject getJpaProject(IProject project) throws CoreException {
- return this.jpaModel.getJpaProject(project);
- }
-
- /**
- * Return the JPA file corresponding to the specified Eclipse file,
- * or null if unable to associate the specified file with a JPA file.
- */
- public JpaFile getJpaFile(IFile file) throws CoreException {
- return this.jpaModel.getJpaFile(file);
- }
-
- /**
- * The JPA settings associated with the specified Eclipse project
- * have changed in such a way as to require the associated
- * JPA project to be completely rebuilt
- * (e.g. when the user changes a project's JPA platform).
- */
- public void rebuildJpaProject(IProject project) {
- this.jpaModel.rebuildJpaProject(project);
- }
-
- /**
- * Return whether the model manager's Java change listener is active.
- */
- public boolean javaElementChangeListenerIsActive() {
- return this.javaElementChangeListenerIsActive;
- }
-
- /**
- * Set whether the model manager's Java change listener is active.
- */
- public void setJavaElementChangeListenerIsActive(boolean javaElementChangeListenerIsActive) {
- this.javaElementChangeListenerIsActive = javaElementChangeListenerIsActive;
- }
-
- /**
- * Log the specified status.
- */
- public void log(IStatus status) {
- JptCorePlugin.log(status);
- }
-
- /**
- * Log the specified message.
- */
- public void log(String msg) {
- JptCorePlugin.log(msg);
- }
-
- /**
- * Log the specified exception or error.
- */
- public void log(Throwable throwable) {
- JptCorePlugin.log(throwable);
- }
-
-
- // ********** resource changed **********
-
- /**
- * Check for:
- * - project close/delete
- * - file add/remove
- * - project open/rename
- */
- /* private */ void resourceChanged(IResourceChangeEvent event) {
- // build events can have the workspace or project as source
- if (event.getType() == IResourceChangeEvent.POST_BUILD) {
- this.resourcePostBuild(event);
- return;
- }
-
- if (! (event.getSource() instanceof IWorkspace)) {
- return; // this probably shouldn't happen...
- }
-
- switch (event.getType()) {
- case IResourceChangeEvent.PRE_DELETE : // project-only event
- this.resourcePreDelete(event);
- break;
- case IResourceChangeEvent.POST_CHANGE :
- this.resourcePostChange(event);
- break;
- default :
- break;
- }
- }
-
- /**
- * A project is being deleted. Remove its corresponding
- * JPA project if appropriate.
- */
- private void resourcePreDelete(IResourceChangeEvent event) {
- IProject project = (IProject) event.getResource();
- debug("Resource (Project) PRE_DELETE: ", project); //$NON-NLS-1$
- this.jpaModel.projectPreDelete(project);
- }
-
- /**
- * A resource has changed somehow.
- * Check for files being added or removed.
- * (The JPA project only handles added and removed files here
- * Changed files are handlded via the Java Element Changed event.)
- * Also check for opened projects.
- */
- private void resourcePostChange(IResourceChangeEvent event) {
- debug("Resource POST_CHANGE"); //$NON-NLS-1$
- this.resourceChanged(event.getDelta());
- }
-
- private void resourceChanged(IResourceDelta delta) {
- IResource resource = delta.getResource();
- switch (resource.getType()) {
- case IResource.ROOT :
- this.resourceChangedChildren(delta);
- break;
- case IResource.PROJECT :
- this.projectChanged((IProject) resource, delta);
- break;
- case IResource.FILE :
- case IResource.FOLDER :
- default :
- break;
- }
- }
-
- private void resourceChangedChildren(IResourceDelta delta) {
- for (IResourceDelta child : delta.getAffectedChildren()) {
- this.resourceChanged(child); // recurse
- }
- }
-
- private void projectChanged(IProject project, IResourceDelta delta) {
- this.projectChanged_(delta);
- this.checkForOpenedProject(project, delta);
- }
-
-
- /**
- * Checked exceptions bite.
- */
- private void projectChanged_(IResourceDelta delta) {
- try {
- this.jpaModel.projectChanged(delta);
- } catch (CoreException ex) {
- this.log(ex); // problem traversing the project's resources - not much we can do
- }
- }
-
- /**
- * Crawl the specified delta, looking for projects being opened.
- * Projects being deleted are handled in IResourceChangeEvent.PRE_DELETE.
- * Projects being closed are handled in IFacetedProjectEvent.Type.PROJECT_MODIFIED.
- */
- private void checkForOpenedProject(IProject project, IResourceDelta delta) {
- switch (delta.getKind()) {
- case IResourceDelta.ADDED : // all but project import and rename handled with the facet POST_INSTALL event
- this.checkDeltaFlagsForOpenedProject(project, delta);
- this.checkDeltaFlagsForRenamedProject(project, delta);
- break;
- case IResourceDelta.REMOVED : // already handled with the PRE_DELETE event
- break;
- case IResourceDelta.CHANGED :
- this.checkDeltaFlagsForOpenedProject(project, delta);
- break;
- case IResourceDelta.ADDED_PHANTOM : // ignore
- break;
- case IResourceDelta.REMOVED_PHANTOM : // ignore
- break;
- default :
- break;
- }
- }
-
- /**
- * We don't get any events from the Facets Framework when a pre-existing
- * project is imported, so we need to check for the newly imported project here.
- *
- * This event also occurs when a project is simply opened. Project opening
- * also triggers a Facet PROJECT_MODIFIED event and that is where we add
- * the JPA project, not here
- */
- private void checkDeltaFlagsForOpenedProject(IProject project, IResourceDelta delta) {
- if (BitTools.flagIsSet(delta.getFlags(), IResourceDelta.OPEN) && project.isOpen()) {
- debug("\tProject CHANGED - OPEN: ", project.getName()); //$NON-NLS-1$
- this.jpaModel.checkForTransition(project);
- }
- }
-
- /**
- * We don't get any events from the Facets Framework when a project is renamed,
- * so we need to check for the renamed projects here.
- */
- private void checkDeltaFlagsForRenamedProject(IProject project, IResourceDelta delta) {
- if (BitTools.flagIsSet(delta.getFlags(), IResourceDelta.MOVED_FROM) && project.isOpen()) {
- debug("\tProject ADDED - MOVED_FROM: ", delta.getMovedFromPath()); //$NON-NLS-1$
- this.jpaModel.checkForTransition(project);
- }
- }
-
- /**
- * A post build event has occurred.
- * Check for whether the build was a "clean" build and trigger project update.
- */
- private void resourcePostBuild(IResourceChangeEvent event) {
- debug("Resource POST_BUILD"); //$NON-NLS-1$
- if (event.getBuildKind() == IncrementalProjectBuilder.CLEAN_BUILD) {
- this.resourcePostClean(event.getDelta());
- }
- }
-
- private void resourcePostClean(IResourceDelta delta) {
- IResource resource = delta.getResource();
- switch (resource.getType()) {
- case IResource.ROOT :
- this.resourcePostCleanChildren(delta);
- break;
- case IResource.PROJECT :
- this.projectPostClean((IProject) resource);
- break;
- case IResource.FILE :
- case IResource.FOLDER :
- default :
- break;
- }
- }
-
- private void resourcePostCleanChildren(IResourceDelta delta) {
- for (IResourceDelta child : delta.getAffectedChildren()) {
- this.resourcePostClean(child); // recurse
- }
- }
-
- private void projectPostClean(IProject project) {
- JpaProject jpaProject = null;
- try {
- jpaProject = getJpaProject(project);
- }
- catch (CoreException ce) {
- // nothing to do, we won't be able to update anyway
- }
- if (jpaProject != null) {
- rebuildJpaProject(project);
- }
- }
-
-
- // ********** faceted project changed **********
-
- /**
- * Check for:
- * - install of JPA facet
- * - un-install of JPA facet
- * - any other appearance or disappearance of the JPA facet
- */
- /* private */ void facetedProjectChanged(IFacetedProjectEvent event) {
- switch (event.getType()) {
- case POST_INSTALL :
- this.facetedProjectPostInstall((IProjectFacetActionEvent) event);
- break;
- case PRE_UNINSTALL :
- this.facetedProjectPreUninstall((IProjectFacetActionEvent) event);
- break;
- case PROJECT_MODIFIED :
- this.facetedProjectModified(event.getProject().getProject());
- break;
- default :
- break;
- }
- }
-
- private void facetedProjectPostInstall(IProjectFacetActionEvent event) {
- debug("Facet POST_INSTALL: ", event.getProjectFacet()); //$NON-NLS-1$
- if (event.getProjectFacet().getId().equals(JptCorePlugin.FACET_ID)) {
- this.jpaModel.jpaFacetedProjectPostInstall(event);
- }
- }
-
- private void facetedProjectPreUninstall(IProjectFacetActionEvent event) {
- debug("Facet PRE_UNINSTALL: ", event.getProjectFacet()); //$NON-NLS-1$
- if (event.getProjectFacet().getId().equals(JptCorePlugin.FACET_ID)) {
- this.jpaModel.jpaFacetedProjectPreUninstall(event);
- }
- }
-
- /**
- * This event is triggered for any change to a faceted project.
- * We use the event to watch for the following:
- * - an open project is closed
- * - a closed project is opened
- * - one of a project's (facet) metadata files is edited directly
- */
- private void facetedProjectModified(IProject project) {
- debug("Facet PROJECT_MODIFIED: ", project.getName()); //$NON-NLS-1$
- this.jpaModel.checkForTransition(project);
- }
-
-
- // ********** Java element changed **********
-
- /**
- * Forward the event to the JPA model.
- */
- /* private */ void javaElementChanged(ElementChangedEvent event) {
- if ( ! this.javaElementChangeListenerIsActive) {
- return; // ignore Java events
- }
- if (this.eventIndicatesProjectAddedButNotOpen(event)) {
- return;
- }
- this.jpaModel.javaElementChanged(event);
- }
-
- //209275 - This particular event only causes problems in a clean workspace the first time a JPA project
- //is created through the JPA wizard. The second time a JPA project is created, this event occurs, but
- //it occurs as the wizard is closing so it does not cause a deadlock.
- private boolean eventIndicatesProjectAddedButNotOpen(ElementChangedEvent event) {
- IJavaElementDelta delta = event.getDelta();
- if (delta.getKind() == IJavaElementDelta.CHANGED) {
- if (delta.getElement().getElementType() == IJavaElement.JAVA_MODEL) {
- IJavaElementDelta[] children = delta.getAffectedChildren();
- if (children.length == 1) {
- IJavaElementDelta childDelta = children[0];
- if (childDelta.getKind() == IJavaElementDelta.ADDED) {
- IJavaElement childElement = childDelta.getElement();
- if (childElement.getElementType() == IJavaElement.JAVA_PROJECT) {
- if (childDelta.getAffectedChildren().length == 0) {
- if (!((IOpenable) childElement).isOpen()) {
- return true;
- }
- }
- }
- }
- }
- }
- }
- return false;
- }
-
-
- // ********** resource change listener **********
-
- /**
- * Forward the Resource change event back to the JPA model manager.
- */
- private class ResourceChangeListener implements IResourceChangeListener {
- ResourceChangeListener() {
- super();
- }
- public void resourceChanged(IResourceChangeEvent event) {
- JpaModelManager.this.resourceChanged(event);
- }
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this);
- }
- }
-
-
- // ********** faceted project listener **********
-
- /**
- * Forward the Faceted project change event back to the JPA model manager.
- */
- private class FacetedProjectListener implements IFacetedProjectListener {
- FacetedProjectListener() {
- super();
- }
- public void handleEvent(IFacetedProjectEvent event) {
- JpaModelManager.this.facetedProjectChanged(event);
- }
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this);
- }
- }
-
-
- // ********** Java element change listener **********
-
- /**
- * Forward the Java element change event back to the JPA model manager.
- */
- private class JavaElementChangeListener implements IElementChangedListener {
- JavaElementChangeListener() {
- super();
- }
- public void elementChanged(ElementChangedEvent event) {
- JpaModelManager.this.javaElementChanged(event);
- }
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this);
- }
- }
-
-
- // ********** debug **********
-
- // @see JpaModelTests#testDEBUG()
- private static final boolean DEBUG = false;
-
- /**
- * trigger #toString() call and string concatenation only if DEBUG is true
- */
- private static void debug(String message, Object object) {
- if (DEBUG) {
- debug_(message + object);
- }
- }
-
- private static void debug(String message) {
- if (DEBUG) {
- debug_(message);
- }
- }
-
- private static void debug_(String message) {
- System.out.println(Thread.currentThread().getName() + ": " + message); //$NON-NLS-1$
- }
-
-}
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/JptCoreMessages.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/JptCoreMessages.java
index 9e64af61ba..df58bc8729 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/JptCoreMessages.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/JptCoreMessages.java
@@ -53,6 +53,7 @@ public class JptCoreMessages {
public static String UPDATE_JOB_NAME;
public static String SYNCHRONIZE_METAMODEL_JOB_NAME;
public static String PLATFORM_ID_DOES_NOT_EXIST;
+ public static String DALI_EVENT_HANDLER_THREAD_NAME;
private static final String BUNDLE_NAME = "jpa_core"; //$NON-NLS-1$
private static final Class<?> BUNDLE_CLASS = JptCoreMessages.class;
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jpa1/GenericJpaProject.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jpa1/GenericJpaProject.java
index afa4628b0b..5fdd73fc23 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jpa1/GenericJpaProject.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/jpa1/GenericJpaProject.java
@@ -9,7 +9,6 @@
******************************************************************************/
package org.eclipse.jpt.core.internal.jpa1;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.jpt.core.internal.AbstractJpaProject;
import org.eclipse.jpt.core.jpa2.JpaProject2_0;
@@ -22,7 +21,7 @@ public class GenericJpaProject
// ********** constructor/initialization **********
- public GenericJpaProject(JpaProject2_0.Config config) throws CoreException {
+ public GenericJpaProject(JpaProject2_0.Config config) {
super(config);
}
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/operations/AbstractJpaFileCreationDataModelProvider.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/operations/AbstractJpaFileCreationDataModelProvider.java
index bfb0b96642..db52d48cf4 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/operations/AbstractJpaFileCreationDataModelProvider.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/operations/AbstractJpaFileCreationDataModelProvider.java
@@ -232,10 +232,7 @@ public abstract class AbstractJpaFileCreationDataModelProvider
protected JpaProject getJpaProject() {
IProject project = getProject();
- if (project == null) {
- return null;
- }
- return JptCorePlugin.getJpaProject(project);
+ return (project == null) ? null : JptCorePlugin.getJpaProject(project);
}
/**
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/operations/AbstractJpaFileCreationOperation.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/operations/AbstractJpaFileCreationOperation.java
index 1510d8ed9c..806bc48a52 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/operations/AbstractJpaFileCreationOperation.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/operations/AbstractJpaFileCreationOperation.java
@@ -1,12 +1,11 @@
/*******************************************************************************
- * Copyright (c) 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
+ * Copyright (c) 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.operations;
@@ -19,6 +18,7 @@ import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.jem.util.emf.workbench.ProjectUtilities;
import org.eclipse.jpt.core.JpaProject;
import org.eclipse.jpt.core.JptCorePlugin;
@@ -111,5 +111,14 @@ public abstract class AbstractJpaFileCreationOperation
this.createdFile = newFile;
}
+ @Override
+ public ISchedulingRule getSchedulingRule() {
+ try {
+ return this.getProject();
+ } catch (ExecutionException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
protected abstract AbstractXmlResourceProvider getXmlResourceProvider(IFile file);
}
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/SimpleSchedulingRule.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/SimpleSchedulingRule.java
index a77b0c03aa..b51b33c87e 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/SimpleSchedulingRule.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/utility/SimpleSchedulingRule.java
@@ -10,6 +10,7 @@
package org.eclipse.jpt.core.internal.utility;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.jpt.utility.internal.StringTools;
/**
* A job scheduling rule that conflicts only with itself.
@@ -17,21 +18,7 @@ import org.eclipse.core.runtime.jobs.ISchedulingRule;
public final class SimpleSchedulingRule
implements ISchedulingRule
{
-
- // singleton
- private static final SimpleSchedulingRule INSTANCE = new SimpleSchedulingRule();
-
- /**
- * Return the singleton.
- */
- public static ISchedulingRule instance() {
- return INSTANCE;
- }
-
- /**
- * Ensure single instance.
- */
- private SimpleSchedulingRule() {
+ public SimpleSchedulingRule() {
super();
}
@@ -43,4 +30,9 @@ public final class SimpleSchedulingRule
return rule == this;
}
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this);
+ }
+
}
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/validation/JpaValidator.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/validation/JpaValidator.java
index 68f3fac1c4..f5d7ac64e8 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/validation/JpaValidator.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/internal/validation/JpaValidator.java
@@ -37,6 +37,10 @@ import org.eclipse.wst.validation.internal.provisional.core.IValidator;
*/
public class JpaValidator extends AbstractValidator implements IValidator {
+ public JpaValidator() {
+ super();
+ }
+
// ********** IValidator implementation **********
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/AbstractXmlResourceProvider.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/AbstractXmlResourceProvider.java
index 9b532bdc7c..48be5bd41c 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/AbstractXmlResourceProvider.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/AbstractXmlResourceProvider.java
@@ -173,7 +173,7 @@ public abstract class AbstractXmlResourceProvider
createResourceAndUnderlyingFile(config);
}
};
- workspace.run(runnable, workspace.getRoot(), IWorkspace.AVOID_UPDATE, new NullProgressMonitor());
+ workspace.run(runnable, this.project, IWorkspace.AVOID_UPDATE, null);
return this.resource;
}
diff --git a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/xml/JpaXmlResource.java b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/xml/JpaXmlResource.java
index 232f8f80ff..8f4a2c9a2f 100644
--- a/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/xml/JpaXmlResource.java
+++ b/jpa/plugins/org.eclipse.jpt.core/src/org/eclipse/jpt/core/resource/xml/JpaXmlResource.java
@@ -21,6 +21,7 @@ import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.jem.util.emf.workbench.WorkbenchResourceHelperBase;
import org.eclipse.jem.util.plugin.JEMUtilPlugin;
import org.eclipse.jpt.core.JpaResourceModel;
@@ -75,16 +76,30 @@ public class JpaXmlResource
// ********** BasicNotifierImpl override **********
/**
- * override to prevent notification when the resource's state is unchanged
- * or the resource is not loaded
+ * override to fire notification only when
+ * - the resource's state has actually changed; and
+ * - the resource is loaded; and
+ * - the resource's resource set is still present (EMF will fire an
+ * notification when the resource set is set to 'null', just before
+ * the resource is "unloaded" - we want to swallow this notification)
*/
@Override
public void eNotify(Notification notification) {
- if ( ! notification.isTouch() && this.isLoaded()) {
+ if ( ! notification.isTouch() && this.isLoaded() && (this.resourceSet != null)) {
super.eNotify(notification);
this.resourceModelChanged();
}
}
+
+ /**
+ * we could use this method to suppress some notifications; or we could just
+ * check whether 'resourceSet' is 'null' (which is what we do)
+ */
+ protected boolean resultSetCleared(Notification notification) {
+ return (notification.getNotifier() == this) &&
+ (notification.getFeatureID(Resource.class) == RESOURCE__RESOURCE_SET) &&
+ (notification.getNewValue() == null);
+ }
// ********** TranslatorResource implementation **********
diff --git a/jpa/plugins/org.eclipse.jpt.eclipselink.core/src/org/eclipse/jpt/eclipselink/core/internal/EclipseLinkJpaFactory.java b/jpa/plugins/org.eclipse.jpt.eclipselink.core/src/org/eclipse/jpt/eclipselink/core/internal/EclipseLinkJpaFactory.java
index 5f886a6fad..20ebe2df93 100644
--- a/jpa/plugins/org.eclipse.jpt.eclipselink.core/src/org/eclipse/jpt/eclipselink/core/internal/EclipseLinkJpaFactory.java
+++ b/jpa/plugins/org.eclipse.jpt.eclipselink.core/src/org/eclipse/jpt/eclipselink/core/internal/EclipseLinkJpaFactory.java
@@ -9,7 +9,6 @@
*******************************************************************************/
package org.eclipse.jpt.eclipselink.core.internal;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.jpt.core.JpaProject;
import org.eclipse.jpt.core.context.PersistentType;
import org.eclipse.jpt.core.context.java.JavaBasicMapping;
@@ -54,7 +53,7 @@ public class EclipseLinkJpaFactory
// ********** Core Model **********
@Override
- public EclipseLinkJpaProject buildJpaProject(JpaProject.Config config) throws CoreException {
+ public EclipseLinkJpaProject buildJpaProject(JpaProject.Config config) {
return new EclipseLinkJpaProjectImpl((JpaProject2_0.Config) config);
}
diff --git a/jpa/plugins/org.eclipse.jpt.eclipselink.core/src/org/eclipse/jpt/eclipselink/core/internal/EclipseLinkJpaProjectImpl.java b/jpa/plugins/org.eclipse.jpt.eclipselink.core/src/org/eclipse/jpt/eclipselink/core/internal/EclipseLinkJpaProjectImpl.java
index 9f5647f316..edac78a5e1 100644
--- a/jpa/plugins/org.eclipse.jpt.eclipselink.core/src/org/eclipse/jpt/eclipselink/core/internal/EclipseLinkJpaProjectImpl.java
+++ b/jpa/plugins/org.eclipse.jpt.eclipselink.core/src/org/eclipse/jpt/eclipselink/core/internal/EclipseLinkJpaProjectImpl.java
@@ -9,7 +9,6 @@
******************************************************************************/
package org.eclipse.jpt.eclipselink.core.internal;
-import org.eclipse.core.runtime.CoreException;
import org.eclipse.jpt.core.internal.AbstractJpaProject;
import org.eclipse.jpt.core.jpa2.JpaProject2_0;
import org.eclipse.jpt.core.resource.xml.JpaXmlResource;
@@ -22,7 +21,7 @@ public class EclipseLinkJpaProjectImpl
extends AbstractJpaProject
implements EclipseLinkJpaProject
{
- public EclipseLinkJpaProjectImpl(JpaProject2_0.Config config) throws CoreException {
+ public EclipseLinkJpaProjectImpl(JpaProject2_0.Config config) {
super(config);
}
diff --git a/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/JptUiPlugin.java b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/JptUiPlugin.java
index 2b07f4a8a1..c7225e72ec 100644
--- a/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/JptUiPlugin.java
+++ b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/JptUiPlugin.java
@@ -13,7 +13,7 @@ import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jpt.core.JpaPlatform;
-import org.eclipse.jpt.core.internal.JpaModelManager;
+import org.eclipse.jpt.core.JptCorePlugin;
import org.eclipse.jpt.ui.internal.platform.JpaPlatformUiRegistry;
import org.eclipse.jpt.ui.navigator.JpaNavigatorProvider;
import org.eclipse.swt.SWT;
@@ -156,7 +156,7 @@ public class JptUiPlugin
* @see #focusOut()
*/
private void focusIn() {
- JpaModelManager.instance().setJavaElementChangeListenerIsActive(false);
+ JptCorePlugin.setJavaElementChangeListenerIsActive(false);
}
/**
@@ -166,7 +166,7 @@ public class JptUiPlugin
* @see #focusIn()
*/
private void focusOut() {
- JpaModelManager.instance().setJavaElementChangeListenerIsActive(true);
+ JptCorePlugin.setJavaElementChangeListenerIsActive(true);
}
/**
diff --git a/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/properties/JpaProjectPropertiesPage.java b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/properties/JpaProjectPropertiesPage.java
index b2ee041467..5183b59dbd 100644
--- a/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/properties/JpaProjectPropertiesPage.java
+++ b/jpa/plugins/org.eclipse.jpt.ui/src/org/eclipse/jpt/ui/internal/properties/JpaProjectPropertiesPage.java
@@ -25,6 +25,7 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener;
import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent;
@@ -35,7 +36,6 @@ import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jpt.core.JpaDataSource;
import org.eclipse.jpt.core.JpaProject;
import org.eclipse.jpt.core.JptCorePlugin;
-import org.eclipse.jpt.core.internal.JpaModelManager;
import org.eclipse.jpt.core.internal.JpaPlatformRegistry;
import org.eclipse.jpt.core.internal.JptCoreMessages;
import org.eclipse.jpt.core.internal.facet.JpaLibraryProviderConstants;
@@ -666,9 +666,12 @@ public class JpaProjectPropertiesPage
return new IRunnableWithProgress() {
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
- IWorkspace ws = ResourcesPlugin.getWorkspace();
- IWorkspaceRunnable wr = JpaProjectPropertiesPage.this.buildOkWorkspaceRunnable();
- ws.run(wr, ws.getRoot(), IWorkspace.AVOID_UPDATE, monitor);
+ ResourcesPlugin.getWorkspace().run(
+ JpaProjectPropertiesPage.this.buildOkWorkspaceRunnable(),
+ JpaProjectPropertiesPage.this.getOkSchedulingRule(),
+ IWorkspace.AVOID_UPDATE,
+ monitor
+ );
}
catch (CoreException ex) {
throw new InvocationTargetException(ex);
@@ -685,13 +688,17 @@ public class JpaProjectPropertiesPage
};
}
+ ISchedulingRule getOkSchedulingRule() {
+ return this.getProject();
+ }
+
void performOk_(IProgressMonitor monitor) throws CoreException {
if (this.isBuffering()) {
boolean platformChanged = this.platformIdModel.isBuffering();
this.trigger.accept();
if (platformChanged) {
// if the JPA platform is changed, we need to completely rebuild the JPA project
- JpaModelManager.instance().rebuildJpaProject(this.getProject());
+ JptCorePlugin.rebuildJpaProject(this.getProject());
}
this.getProject().build(IncrementalProjectBuilder.FULL_BUILD, monitor);
}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AsynchronousCommandExecutor.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AsynchronousCommandExecutor.java
new file mode 100644
index 0000000000..00baa2efd0
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/AsynchronousCommandExecutor.java
@@ -0,0 +1,164 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal;
+
+import org.eclipse.jpt.utility.Command;
+
+/**
+ * This command executor will dispatch commands to be executed in a separate
+ * thread, allowing calls to {@link CommandExecutor#execute(Command)} to return
+ * immediately.
+ * <p>
+ * <strong>NB:</strong> The client-supplied commands should handle any
+ * exception appropriately (e.g. log the exception and return gracefully) so
+ * the command execution thread can continue executing.
+ */
+public class AsynchronousCommandExecutor
+ implements CallbackStatefulCommandExecutor
+{
+ /**
+ * This command queue is shared with the command execution/consumer thread.
+ * Adding a command to it will trigger the command to be executed by the
+ * command execution thread or, if another command is currently executing,
+ * to execute the new command once the currently executing command has
+ * finished executing.
+ */
+ final SynchronizedQueue<Command> commands = new SynchronizedQueue<Command>();
+
+ /**
+ * Most of the thread-related behavior is delegated to this coordinator.
+ */
+ private final ConsumerThreadCoordinator consumerThreadCoordinator;
+
+ private final ListenerList<Listener> listenerList = new ListenerList<Listener>(Listener.class);
+
+
+ // ********** construction **********
+
+ /**
+ * Construct an asynchronous command executor.
+ * Allow the command execution thread(s) to be assigned JDK-generated names.
+ */
+ public AsynchronousCommandExecutor() {
+ this(null);
+ }
+
+ /**
+ * Construct an asynchronous command executor.
+ * Assign the command execution thread(s) the specified name.
+ */
+ public AsynchronousCommandExecutor(String threadName) {
+ super();
+ this.consumerThreadCoordinator = new ConsumerThreadCoordinator(this.buildConsumer(), threadName);
+ }
+
+ private ConsumerThreadCoordinator.Consumer buildConsumer() {
+ return new Consumer();
+ }
+
+
+ // ********** CallbackStatefulCommandExecutor implementation **********
+
+ /**
+ * Build and start the command execution/consumer thread.
+ * <p>
+ * Note: We don't clear the command queue here; so if a command has been
+ * added to the queue <em>before</em> getting here, the first command will
+ * be executed promptly (albeit, asynchronously).
+ * The command queue will be non-empty if:<ul>
+ * <li>{@link #execute(Command)} was called after the command executor was
+ * constructed but before {@link #start()} was called; or
+ * <li>{@link #execute(Command)} was called after {@link #stop()} was called
+ * but before {@link #start()} was called (to restart the command executor); or
+ * <li>{@link #stop()} was called when there were still outstanding commands
+ * remaining in the command queue
+ * </ul>
+ */
+ public void start() {
+ this.consumerThreadCoordinator.start();
+ }
+
+ /**
+ * Put the specified command on the command queue, to be consumed by the
+ * command execution thread.
+ */
+ public void execute(Command command) {
+ this.commands.enqueue(command);
+ }
+
+ /**
+ * Interrupt the command execution thread so that it stops executing at the
+ * end of the current command. Suspend the current thread until
+ * the command execution thread is finished executing. If any uncaught
+ * exceptions were thrown while the execution thread was executing,
+ * wrap them in a composite exception and throw the composite exception.
+ */
+ public void stop() {
+ this.consumerThreadCoordinator.stop();
+ }
+
+ public void addListener(Listener listener) {
+ this.listenerList.add(listener);
+ }
+
+ public void removeListener(Listener listener) {
+ this.listenerList.remove(listener);
+ }
+
+ /**
+ * Notify our listeners.
+ */
+ /* private */ void commandExecuted(Command command) {
+ for (Listener listener : this.listenerList.getListeners()) {
+ listener.commandExecuted(command);
+ }
+ }
+
+
+ // ********** consumer **********
+
+ /**
+ * This implementation of {@link ConsumerThreadCoordinator.Consumer}
+ * will execute the commands enqueued by the asynchronous command executor.
+ * It will wait until the shared command queue is non-empty to begin executing the
+ * commands in the queue. Once a comand is executed, the thread will quiesce until
+ * another command is placed in the command queue. If a new command is
+ * enqueued during the execution of another command (either recursively by
+ * the command itself or by another thread),
+ * the new command will be executed immediately after the currently
+ * executing command is finished.
+ * Stop the thread by calling {@link Thread#interrupt()}.
+ */
+ class Consumer
+ implements ConsumerThreadCoordinator.Consumer
+ {
+ Consumer() {
+ super();
+ }
+
+ /**
+ * Wait until a command has been placed in the queue.
+ */
+ public void waitForProducer() throws InterruptedException {
+ AsynchronousCommandExecutor.this.commands.waitUntilNotEmpty();
+ }
+
+ /**
+ * Execute the first command in the queue and notify our listeners.
+ */
+ public void execute() {
+ Command command = AsynchronousCommandExecutor.this.commands.dequeue();
+ command.execute();
+ AsynchronousCommandExecutor.this.commandExecuted(command);
+ }
+
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CallbackStatefulCommandExecutor.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CallbackStatefulCommandExecutor.java
new file mode 100644
index 0000000000..d9fb9a1c6b
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CallbackStatefulCommandExecutor.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal;
+
+import java.util.EventListener;
+
+import org.eclipse.jpt.utility.Command;
+
+/**
+ * This command executor notifies clients commands are executed.
+ */
+public interface CallbackStatefulCommandExecutor
+ extends StatefulCommandExecutor
+{
+ /**
+ * Add the specified listener to be notified whenever a command has been
+ * executed.
+ * @see #removeListener(Listener)
+ */
+ void addListener(Listener listener);
+
+ /**
+ * Remove the specified listener.
+ * @see #addListener(Listener)
+ */
+ void removeListener(Listener listener);
+
+
+ // ********** listener **********
+
+ /**
+ * Interface implemented by listeners to be notified whenever a
+ * command is executed.
+ */
+ public interface Listener
+ extends EventListener
+ {
+ /**
+ * The specified command was executed.
+ */
+ void commandExecuted(Command command);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CompositeCommand.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CompositeCommand.java
new file mode 100644
index 0000000000..ff603eb0b7
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/CompositeCommand.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal;
+
+import org.eclipse.jpt.utility.Command;
+
+/**
+ * <code>CompositeCommand</code> provides support for treating a collection of
+ * {@link Command}s as a single command.
+ */
+public class CompositeCommand
+ implements Command
+{
+ private final Iterable<Command> commands;
+
+ public CompositeCommand(Iterable<Command> commands) {
+ super();
+ this.commands = commands;
+ }
+
+ public void execute() {
+ for (Command command : this.commands) {
+ command.execute();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.commands);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ConsumerThreadCoordinator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ConsumerThreadCoordinator.java
new file mode 100644
index 0000000000..abc9e71456
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/ConsumerThreadCoordinator.java
@@ -0,0 +1,225 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal;
+
+import java.util.Vector;
+
+/**
+ * A <code>ConsumerThreadCoordinator</code> controls the creation,
+ * starting, and stopping of a general purpose "consumer" thread. Construct
+ * the coordinator with a {@link Consumer} that both waits for the producer
+ * to "produce" something to "consume" and, once the wait is over,
+ * "consumes" whatever is available.
+ * <p>
+ * <strong>NB:</strong> The client-supplied consumer should handle any
+ * exception appropriately (e.g. log the exception and return gracefully) so
+ * the thread can continue executing.
+ */
+public class ConsumerThreadCoordinator {
+ /**
+ * The runnable passed to the consumer thread each time it is built.
+ */
+ private final Runnable runnable;
+
+ /**
+ * Optional, client-supplied name for the consumer thread.
+ * If null, the JDK assigns a name.
+ */
+ private final String threadName;
+
+ /**
+ * The consumer is executed on this thread. A new thread is built
+ * for every start/stop cycle (since a thread cannot be started more than
+ * once).
+ */
+ private volatile Thread thread;
+
+ /**
+ * A list of the uncaught exceptions thrown by the consumer
+ * during the current start/stop cycle.
+ */
+ final Vector<Throwable> exceptions = new Vector<Throwable>();
+
+
+ // ********** construction **********
+
+ /**
+ * Construct a consumer thread coordinator for the specified consumer.
+ * Allow the consumer thread(s) to be assigned JDK-generated names.
+ */
+ public ConsumerThreadCoordinator(Consumer consumer) {
+ this(consumer, null);
+ }
+
+ /**
+ * Construct a consumer thread coordinator for the specified consumer.
+ * Assign the consumer thread(s) the specified name.
+ */
+ public ConsumerThreadCoordinator(Consumer consumer, String threadName) {
+ super();
+ this.runnable = this.buildRunnable(consumer);
+ this.threadName = threadName;
+ }
+
+ private Runnable buildRunnable(Consumer consumer) {
+ return new RunnableConsumer(consumer);
+ }
+
+
+ // ********** Lifecycle support **********
+
+ /**
+ * Build and start the consumer thread.
+ */
+ public synchronized void start() {
+ if (this.thread != null) {
+ throw new IllegalStateException("Not stopped."); //$NON-NLS-1$
+ }
+ this.thread = this.buildThread();
+ this.thread.start();
+ }
+
+ private Thread buildThread() {
+ Thread t = new Thread(this.runnable);
+ if (this.threadName != null) {
+ t.setName(this.threadName);
+ }
+ return t;
+ }
+
+ /**
+ * Interrupt the consumer thread so that it stops executing at the
+ * end of its current iteration. Suspend the current thread until
+ * the consumer thread is finished executing. If any uncaught
+ * exceptions were thrown while the consumer thread was executing,
+ * wrap them in a composite exception and throw the composite exception.
+ */
+ public synchronized void stop() {
+ if (this.thread == null) {
+ throw new IllegalStateException("Not started."); //$NON-NLS-1$
+ }
+ this.thread.interrupt();
+ try {
+ this.thread.join();
+ } catch (InterruptedException ex) {
+ // the thread that called #stop() was interrupted while waiting to
+ // join the consumer thread - ignore;
+ // 'thread' is still "interrupted", so its #run() loop will still stop
+ // after its current execution - we just won't wait around for it...
+ }
+ this.thread = null;
+
+ if (this.exceptions.size() > 0) {
+ Throwable[] temp = this.exceptions.toArray(new Throwable[this.exceptions.size()]);
+ this.exceptions.clear();
+ throw new CompositeException(temp);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.thread);
+ }
+
+
+ // ********** consumer thread runnable **********
+
+ /**
+ * This implementation of {@link Runnable} is a long-running consumer that
+ * will repeatedly execute the consumer {@link Consumer#execute()} method.
+ * With each iteration, the consumer thread will wait
+ * until the other consumer method, {@link Consumer#waitForProducer()}, allows the
+ * consumer thread to proceed (i.e. there is something for the consumer to
+ * consume). Once {@link Consumer#execute()} is finished, the thread will quiesce
+ * until {@link Consumer#waitForProducer()} returns again.
+ * Stop the thread by calling {@link Thread#interrupt()}.
+ */
+ private class RunnableConsumer
+ implements Runnable
+ {
+ /**
+ * Client-supplied consumer that controls waiting for something to consume
+ * and the consuming itself.
+ */
+ private final Consumer consumer;
+
+ RunnableConsumer(Consumer consumer) {
+ super();
+ this.consumer = consumer;
+ }
+
+ /**
+ * Loop while this thread has not been interrupted by another thread.
+ * In each loop: Pause execution until {@link Consumer#waitForProducer()}
+ * allows us to proceed.
+ * <p>
+ * If this thread is interrupted <em>during</em> {@link Consumer#execute()},
+ * the call to {@link Thread#interrupted()} will stop the loop. If this thread is
+ * interrupted during the call to {@link Consumer#waitForProducer()},
+ * we will catch the {@link InterruptedException} and stop the loop also.
+ */
+ public void run() {
+ while ( ! Thread.interrupted()) {
+ try {
+ this.consumer.waitForProducer();
+ } catch (InterruptedException ex) {
+ // we were interrupted while waiting, must be Quittin' Time
+ return;
+ }
+ this.execute();
+ }
+ }
+
+ /**
+ * Execute the consumer {@link Consumer#execute()} method.
+ * Do not allow any unhandled exceptions to kill the thread.
+ * Store them up for later pain.
+ * @see ConsumerThreadCoordinator#stop()
+ */
+ private void execute() {
+ try {
+ this.execute_();
+ } catch (Throwable ex) {
+ ConsumerThreadCoordinator.this.exceptions.add(ex);
+ }
+ }
+
+ /**
+ * Subclass-implemented behavior: consume stuff.
+ */
+ private void execute_() {
+ this.consumer.execute();
+ }
+
+ }
+
+
+ // ********** consumer interface **********
+
+ /**
+ * Interface implemented by clients that controls:<ul>
+ * <li>when the consumer thread suspends, waiting for something to consume
+ * <li>the consuming of whatever is being produced
+ * </ul>
+ */
+ public interface Consumer {
+ /**
+ * Wait for something to consume.
+ * Throw an {@link InterruptedException} if the thread is interrupted.
+ */
+ void waitForProducer() throws InterruptedException;
+
+ /**
+ * Consume whatever is currently available.
+ */
+ void execute();
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Queue.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Queue.java
new file mode 100644
index 0000000000..cf9b1f8b25
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Queue.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal;
+
+import java.io.Serializable;
+import java.util.NoSuchElementException;
+
+/**
+ * Interface defining the classic queue behavior,
+ * without the backdoors allowed by {@link java.util.Queue}.
+ *
+ * @param <E> the type of elements contained by the queue
+ */
+public interface Queue<E> {
+
+ /**
+ * "Enqueue" the specified item to the tail of the queue.
+ */
+ void enqueue(E o);
+
+ /**
+ * "Dequeue" an item from the head of the queue.
+ */
+ E dequeue();
+
+ /**
+ * Return the item on the head of the queue
+ * without removing it from the queue.
+ */
+ E peek();
+
+ /**
+ * Return whether the queue is empty.
+ */
+ boolean isEmpty();
+
+
+ final class Empty<E> implements Queue<E>, Serializable {
+ @SuppressWarnings("unchecked")
+ public static final Queue INSTANCE = new Empty();
+ @SuppressWarnings("unchecked")
+ public static <T> Queue<T> instance() {
+ return INSTANCE;
+ }
+ // ensure single instance
+ private Empty() {
+ super();
+ }
+ public void enqueue(E o) {
+ throw new UnsupportedOperationException();
+ }
+ public E dequeue() {
+ throw new NoSuchElementException();
+ }
+ public E peek() {
+ throw new NoSuchElementException();
+ }
+ public boolean isEmpty() {
+ return true;
+ }
+ private static final long serialVersionUID = 1L;
+ private Object readResolve() {
+ // replace this object with the singleton
+ return INSTANCE;
+ }
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleCommandExecutor.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleCommandExecutor.java
new file mode 100644
index 0000000000..de883b3e8b
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleCommandExecutor.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal;
+
+import org.eclipse.jpt.utility.Command;
+
+/**
+ * Straightforward implementation of {@link CallbackStatefulCommandExecutor}.
+ */
+public class SimpleCommandExecutor
+ implements CallbackStatefulCommandExecutor
+{
+ private boolean active = false;
+ private final ListenerList<Listener> listenerList = new ListenerList<Listener>(Listener.class);
+
+ public SimpleCommandExecutor() {
+ super();
+ }
+
+ public void start() {
+ if (this.active) {
+ throw new IllegalStateException("Not stopped."); //$NON-NLS-1$
+ }
+ this.active = true;
+ }
+
+ public void execute(Command command) {
+ if (this.active) {
+ command.execute();
+ this.commandExecuted(command);
+ }
+ }
+
+ public void stop() {
+ if ( ! this.active) {
+ throw new IllegalStateException("Not started."); //$NON-NLS-1$
+ }
+ this.active = false;
+ }
+
+ public void addListener(Listener listener) {
+ this.listenerList.add(listener);
+ }
+
+ public void removeListener(Listener listener) {
+ this.listenerList.remove(listener);
+ }
+
+ /**
+ * Notify our listeners.
+ */
+ private void commandExecuted(Command command) {
+ for (Listener listener : this.listenerList.getListeners()) {
+ listener.commandExecuted(command);
+ }
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleQueue.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleQueue.java
new file mode 100644
index 0000000000..89a73e1454
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleQueue.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.LinkedList;
+
+/**
+ * Straightforward implementation of the {@link Queue} interface.
+ */
+public class SimpleQueue<E>
+ implements Queue<E>, Cloneable, Serializable
+{
+ private LinkedList<E> elements;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Construct an empty queue.
+ */
+ public SimpleQueue() {
+ super();
+ this.elements = new LinkedList<E>();
+ }
+
+ /**
+ * Construct a queue containing the elements of the specified
+ * collection. The queue will dequeue its elements in the same
+ * order they are returned by the collection's iterator (i.e. the
+ * first element returned by the collection's iterator will be the
+ * first element returned by {@link #dequeue()}).
+ */
+ public SimpleQueue(Collection<? extends E> c) {
+ super();
+ this.elements = new LinkedList<E>(c);
+ }
+
+
+ // ********** Queue implementation **********
+
+ public void enqueue(E o) {
+ this.elements.addLast(o);
+ }
+
+ public E dequeue() {
+ return this.elements.removeFirst();
+ }
+
+ public E peek() {
+ return this.elements.getFirst();
+ }
+
+ public boolean isEmpty() {
+ return this.elements.isEmpty();
+ }
+
+
+ // ********** Cloneable implementation **********
+
+ @Override
+ public SimpleQueue<E> clone() {
+ try {
+ @SuppressWarnings("unchecked")
+ SimpleQueue<E> clone = (SimpleQueue<E>) super.clone();
+ @SuppressWarnings("unchecked")
+ LinkedList<E> ll = (LinkedList<E>) this.elements.clone();
+ clone.elements = ll;
+ return clone;
+ } catch (CloneNotSupportedException ex) {
+ throw new InternalError();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.peek());
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java
index 5df2f99e40..ffdea0c519 100644
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SimpleStack.java
@@ -43,16 +43,16 @@ public class SimpleStack<E>
* last element returned by the collection's iterator will be the
* first element returned by {@link #pop()}).
*/
- public SimpleStack(Collection<? extends E> c) {
+ public SimpleStack(Collection<? extends E> collection) {
super();
- this.elements = new LinkedList<E>(c);
+ this.elements = new LinkedList<E>(collection);
}
// ********** Stack implementation **********
- public void push(E o) {
- this.elements.addLast(o);
+ public void push(E element) {
+ this.elements.addLast(element);
}
public E pop() {
@@ -76,7 +76,7 @@ public class SimpleStack<E>
}
- // ********** Cloneable implementation **********
+ // ********** standard methods **********
@Override
public SimpleStack<E> clone() {
@@ -92,4 +92,9 @@ public class SimpleStack<E>
}
}
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.peek());
+ }
+
}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java
index 4c3ac1bca6..50ba19877a 100644
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/Stack.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2008 Oracle. All rights reserved.
+ * Copyright (c) 2007, 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.
@@ -14,15 +14,16 @@ import java.util.EmptyStackException;
/**
* Interface defining the classic stack behavior,
- * without the backdoors allowed by java.util.Stack.
- * E is the type of elements contained by the Stack.
+ * without the backdoors allowed by {@link java.util.Stack}.
+ *
+ * @param <E> the type of elements contained by the stack
*/
public interface Stack<E> {
/**
* "Push" the specified item on to the top of the stack.
*/
- void push(E o);
+ void push(E element);
/**
* "Pop" an item from the top of the stack.
@@ -52,7 +53,7 @@ public interface Stack<E> {
private Empty() {
super();
}
- public void push(E o) {
+ public void push(E element) {
throw new UnsupportedOperationException();
}
public E pop() {
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StatefulCommandExecutor.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StatefulCommandExecutor.java
new file mode 100644
index 0000000000..d4fd37a110
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/StatefulCommandExecutor.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal;
+
+import org.eclipse.jpt.utility.CommandExecutor;
+
+/**
+ * This interface allows clients to control how a command is executed.
+ * This is useful when the server provides the command but the client provides
+ * the context (e.g. the client would like to dispatch the command to the UI
+ * thread).
+ */
+public interface StatefulCommandExecutor
+ extends CommandExecutor
+{
+ /**
+ * Start the command executor.
+ */
+ void start();
+
+ /**
+ * Stop the command executor.
+ */
+ void stop();
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedQueue.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedQueue.java
new file mode 100644
index 0000000000..c35a4aa133
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedQueue.java
@@ -0,0 +1,348 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal;
+
+import java.io.Serializable;
+import java.util.NoSuchElementException;
+
+import org.eclipse.jpt.utility.Command;
+
+/**
+ * Thread-safe implementation of the {@link Queue} interface.
+ * This also provides protocol for suspending a thread until the
+ * queue is empty or not empty, with optional time-outs.
+ */
+public class SynchronizedQueue<E>
+ implements Queue<E>, Serializable
+{
+ /** Backing queue. */
+ private final Queue<E> queue;
+
+ /** Object to synchronize on. */
+ private final Object mutex;
+
+ private static final long serialVersionUID = 1L;
+
+
+ // ********** constructors **********
+
+ /**
+ * Construct a synchronized queue that wraps the
+ * specified queue and locks on the specified mutex.
+ */
+ public SynchronizedQueue(Queue<E> queue, Object mutex) {
+ super();
+ if (queue == null) {
+ throw new NullPointerException();
+ }
+ this.queue = queue;
+ this.mutex = mutex;
+ }
+
+ /**
+ * Construct a synchronized queue that wraps the
+ * specified queue and locks on itself.
+ */
+ public SynchronizedQueue(Queue<E> queue) {
+ super();
+ if (queue == null) {
+ throw new NullPointerException();
+ }
+ this.queue = queue;
+ this.mutex = this;
+ }
+
+ /**
+ * Construct an empty synchronized queue that locks on the specified mutex.
+ */
+ public SynchronizedQueue(Object mutex) {
+ this(new SimpleQueue<E>(), mutex);
+ }
+
+ /**
+ * Construct an empty synchronized queue that locks on itself.
+ */
+ public SynchronizedQueue() {
+ this(new SimpleQueue<E>());
+ }
+
+
+ // ********** Queue implementation **********
+
+ public void enqueue(E element) {
+ synchronized (this.mutex) {
+ this.enqueue_(element);
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private void enqueue_(E element) {
+ this.queue.enqueue(element);
+ this.mutex.notifyAll();
+ }
+
+ public E dequeue() {
+ synchronized (this.mutex) {
+ return this.dequeue_();
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private E dequeue_() {
+ E element = this.queue.dequeue();
+ this.mutex.notifyAll();
+ return element;
+ }
+
+ public E peek() {
+ synchronized (this.mutex) {
+ return this.queue.peek();
+ }
+ }
+
+ public boolean isEmpty() {
+ synchronized (this.mutex) {
+ return this.queue.isEmpty();
+ }
+ }
+
+
+ // ********** indefinite waits **********
+
+ /**
+ * Suspend the current thread until the queue's empty status changes
+ * to the specified value.
+ */
+ public void waitUntilEmptyIs(boolean empty) throws InterruptedException {
+ synchronized (this.mutex) {
+ this.waitUntilEmptyIs_(empty);
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private void waitUntilEmptyIs_(boolean empty) throws InterruptedException {
+ while (this.queue.isEmpty() != empty) {
+ this.mutex.wait();
+ }
+ }
+
+ /**
+ * Suspend the current thread until the queue is empty.
+ */
+ public void waitUntilEmpty() throws InterruptedException {
+ this.waitUntilEmptyIs(true);
+ }
+
+ /**
+ * Suspend the current thread until the queue has something on it.
+ */
+ public void waitUntilNotEmpty() throws InterruptedException {
+ this.waitUntilEmptyIs(false);
+ }
+
+ /**
+ * Suspend the current thread until the queue is empty,
+ * then "enqueue" the specified item to the tail of the queue
+ * and continue executing.
+ */
+ public void waitToEnqueue(E element) throws InterruptedException {
+ synchronized (this.mutex) {
+ this.waitUntilEmptyIs_(true);
+ this.enqueue_(element);
+ }
+ }
+
+ /**
+ * Suspend the current thread until the queue has something on it,
+ * then "dequeue" an item from the head of the queue and return it.
+ */
+ public Object waitToDequeue() throws InterruptedException {
+ synchronized (this.mutex) {
+ this.waitUntilEmptyIs_(false);
+ return this.dequeue_();
+ }
+ }
+
+
+ // ********** timed waits **********
+
+ /**
+ * Suspend the current thread until the queue's empty status changes
+ * to the specified value or the specified time-out occurs.
+ * The time-out is specified in milliseconds. Return <code>true</code> if the specified
+ * empty status was achieved; return <code>false</code> if a time-out occurred.
+ * If the queue's empty status is already the specified value,
+ * return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
+ */
+ public boolean waitUntilEmptyIs(boolean empty, long timeout) throws InterruptedException {
+ synchronized (this.mutex) {
+ return this.waitUntilEmptyIs_(empty, timeout);
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private boolean waitUntilEmptyIs_(boolean empty, long timeout) throws InterruptedException {
+ if (timeout == 0L) {
+ this.waitUntilEmptyIs_(empty); // wait indefinitely until notified
+ return true; // if it ever comes back, the condition was met
+ }
+
+ long stop = System.currentTimeMillis() + timeout;
+ long remaining = timeout;
+ while ((this.queue.isEmpty() != empty) && (remaining > 0L)) {
+ this.mutex.wait(remaining);
+ remaining = stop - System.currentTimeMillis();
+ }
+ return (this.queue.isEmpty() == empty);
+ }
+
+ /**
+ * Suspend the current thread until the queue is empty
+ * or the specified time-out occurs.
+ * The time-out is specified in milliseconds. Return <code>true</code> if
+ * the queue is empty; return <code>false</code> if a time-out occurred.
+ * If the queue is already empty, return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
+ */
+ public boolean waitUntilEmpty(long timeout) throws InterruptedException {
+ return this.waitUntilEmptyIs(true, timeout);
+ }
+
+ /**
+ * Suspend the current thread until the queue has something on it.
+ * or the specified time-out occurs.
+ * The time-out is specified in milliseconds. Return <code>true</code> if
+ * the queue is not empty; return <code>false</code> if a time-out occurred.
+ * If the queue already has something on it, return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
+ */
+ public boolean waitUntilNotEmpty(long timeout) throws InterruptedException {
+ return this.waitUntilEmptyIs(false, timeout);
+ }
+
+ /**
+ * Suspend the current thread until the queue is empty,
+ * then "enqueue" the specified item to the tail of the queue
+ * and continue executing. If the queue is not emptied out
+ * before the time-out, simply continue executing without
+ * "enqueueing" the item.
+ * The time-out is specified in milliseconds. Return <code>true</code> if the
+ * item was enqueued; return <code>false</code> if a time-out occurred.
+ * If the queue is already empty, "enqueue" the specified item and
+ * return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
+ */
+ public boolean waitToEnqueue(E element, long timeout) throws InterruptedException {
+ synchronized (this.mutex) {
+ boolean success = this.waitUntilEmptyIs_(true, timeout);
+ if (success) {
+ this.enqueue_(element);
+ }
+ return success;
+ }
+ }
+
+ /**
+ * Suspend the current thread until the queue has something on it,
+ * then "dequeue" an item from the head of the queue and return it.
+ * If the queue is empty and nothing is "enqueued" on to it before the
+ * time-out, throw a no such element exception.
+ * The time-out is specified in milliseconds.
+ * If the queue is not empty, "dequeue" an item and
+ * return it immediately.
+ * If the time-out is zero, wait indefinitely.
+ */
+ public Object waitToDequeue(long timeout) throws InterruptedException {
+ synchronized (this.mutex) {
+ boolean success = this.waitUntilEmptyIs_(false, timeout);
+ if (success) {
+ return this.dequeue_();
+ }
+ throw new NoSuchElementException();
+ }
+ }
+
+
+ // ********** synchronized behavior **********
+
+ /**
+ * If the current thread is not interrupted, execute the specified command
+ * with the mutex locked. This is useful for initializing the queue in another
+ * thread.
+ */
+ public void execute(Command command) throws InterruptedException {
+ if (Thread.interrupted()) {
+ throw new InterruptedException();
+ }
+ synchronized (this.mutex) {
+ command.execute();
+ }
+ }
+
+
+ // ********** additional public protocol **********
+
+ /**
+ * "Drain" all the current items from the queue into specified queue.
+ */
+ public void drainTo(Queue<E> q) {
+ synchronized (this.mutex) {
+ this.drainTo_(q);
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private void drainTo_(Queue<E> q) {
+ boolean changed = false;
+ while ( ! this.queue.isEmpty()) {
+ q.enqueue(this.queue.dequeue());
+ changed = true;
+ }
+ if (changed) {
+ this.mutex.notifyAll();
+ }
+ }
+
+ /**
+ * Return the object the queue locks on while performing
+ * its operations.
+ */
+ public Object getMutex() {
+ return this.mutex;
+ }
+
+
+ // ********** standard methods **********
+
+ @Override
+ public String toString() {
+ synchronized (this.mutex) {
+ return '[' + this.queue.toString() + ']';
+ }
+ }
+
+ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException {
+ synchronized (this.mutex) {
+ s.defaultWriteObject();
+ }
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java
index 1b0b9f33d9..dc0a4dce1b 100644
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/SynchronizedStack.java
@@ -11,6 +11,7 @@ package org.eclipse.jpt.utility.internal;
import java.io.Serializable;
import java.util.EmptyStackException;
+
import org.eclipse.jpt.utility.Command;
/**
@@ -59,14 +60,14 @@ public class SynchronizedStack<E>
}
/**
- * Construct a synchronized stack that locks on the specified mutex.
+ * Construct an empty synchronized stack that locks on the specified mutex.
*/
public SynchronizedStack(Object mutex) {
this(new SimpleStack<E>(), mutex);
}
/**
- * Construct a synchronized stack that locks on itself.
+ * Construct an empty synchronized stack that locks on itself.
*/
public SynchronizedStack() {
this(new SimpleStack<E>());
@@ -75,21 +76,35 @@ public class SynchronizedStack<E>
// ********** Stack implementation **********
- public void push(E o) {
+ public void push(E element) {
synchronized (this.mutex) {
- this.stack.push(o);
- this.mutex.notifyAll();
+ this.push_(element);
}
}
+ /**
+ * Pre-condition: synchronized
+ */
+ private void push_(E element) {
+ this.stack.push(element);
+ this.mutex.notifyAll();
+ }
+
public E pop() {
synchronized (this.mutex) {
- E o = this.stack.pop();
- this.mutex.notifyAll();
- return o;
+ return this.pop_();
}
}
+ /**
+ * Pre-condition: synchronized
+ */
+ private E pop_() {
+ E o = this.stack.pop();
+ this.mutex.notifyAll();
+ return o;
+ }
+
public E peek() {
synchronized (this.mutex) {
return this.stack.peek();
@@ -111,9 +126,16 @@ public class SynchronizedStack<E>
*/
public void waitUntilEmptyIs(boolean empty) throws InterruptedException {
synchronized (this.mutex) {
- while (this.isEmpty() != empty) {
- this.mutex.wait();
- }
+ this.waitUntilEmptyIs_(empty);
+ }
+ }
+
+ /**
+ * Pre-condition: synchronized
+ */
+ private void waitUntilEmptyIs_(boolean empty) throws InterruptedException {
+ while (this.stack.isEmpty() != empty) {
+ this.mutex.wait();
}
}
@@ -121,18 +143,14 @@ public class SynchronizedStack<E>
* Suspend the current thread until the stack is empty.
*/
public void waitUntilEmpty() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilEmptyIs(true);
- }
+ this.waitUntilEmptyIs(true);
}
/**
* Suspend the current thread until the stack has something on it.
*/
public void waitUntilNotEmpty() throws InterruptedException {
- synchronized (this.mutex) {
- this.waitUntilEmptyIs(false);
- }
+ this.waitUntilEmptyIs(false);
}
/**
@@ -140,10 +158,10 @@ public class SynchronizedStack<E>
* then "push" the specified item on to the top of the stack
* and continue executing.
*/
- public void waitToPush(E o) throws InterruptedException {
+ public void waitToPush(E element) throws InterruptedException {
synchronized (this.mutex) {
- this.waitUntilEmpty();
- this.push(o);
+ this.waitUntilEmptyIs_(true);
+ this.push_(element);
}
}
@@ -153,8 +171,8 @@ public class SynchronizedStack<E>
*/
public Object waitToPop() throws InterruptedException {
synchronized (this.mutex) {
- this.waitUntilNotEmpty();
- return this.pop();
+ this.waitUntilEmptyIs_(false);
+ return this.pop_();
}
}
@@ -164,48 +182,58 @@ public class SynchronizedStack<E>
/**
* Suspend the current thread until the stack's empty status changes
* to the specified value or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if the specified
- * value was achieved; return false if a time-out occurred.
+ * The time-out is specified in milliseconds. Return <code>true</code> if the specified
+ * empty status was achieved; return <code>false</code> if a time-out occurred.
+ * If the stack's empty status is already the specified value,
+ * return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
*/
public boolean waitUntilEmptyIs(boolean empty, long timeout) throws InterruptedException {
synchronized (this.mutex) {
- if (timeout == 0L) {
- this.waitUntilEmptyIs(empty); // wait indefinitely until notified
- return true; // if it ever comes back, the condition was met
- }
+ return this.waitUntilEmptyIs_(empty, timeout);
+ }
+ }
- long stop = System.currentTimeMillis() + timeout;
- long remaining = timeout;
- while ((this.isEmpty() != empty) && (remaining > 0L)) {
- this.mutex.wait(remaining);
- remaining = stop - System.currentTimeMillis();
- }
- return (this.isEmpty() == empty);
+ /**
+ * Pre-condition: synchronized
+ */
+ private boolean waitUntilEmptyIs_(boolean empty, long timeout) throws InterruptedException {
+ if (timeout == 0L) {
+ this.waitUntilEmptyIs_(empty); // wait indefinitely until notified
+ return true; // if it ever comes back, the condition was met
+ }
+
+ long stop = System.currentTimeMillis() + timeout;
+ long remaining = timeout;
+ while ((this.stack.isEmpty() != empty) && (remaining > 0L)) {
+ this.mutex.wait(remaining);
+ remaining = stop - System.currentTimeMillis();
}
+ return (this.stack.isEmpty() == empty);
}
/**
* Suspend the current thread until the stack is empty
* or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if
- * the stack is empty; return false if a time-out occurred.
+ * The time-out is specified in milliseconds. Return <code>true</code> if
+ * the stack is empty; return <code>false</code> if a time-out occurred.
+ * If the stack is already empty, return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
*/
public boolean waitUntilEmpty(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitUntilEmptyIs(true, timeout);
- }
+ return this.waitUntilEmptyIs(true, timeout);
}
/**
* Suspend the current thread until the stack has something on it.
* or the specified time-out occurs.
- * The time-out is specified in milliseconds. Return true if
- * the stack has something on it; return false if a time-out occurred.
+ * The time-out is specified in milliseconds. Return <code>true</code> if
+ * the stack is not empty; return <code>false</code> if a time-out occurred.
+ * If the stack already has something on it, return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
*/
public boolean waitUntilNotEmpty(long timeout) throws InterruptedException {
- synchronized (this.mutex) {
- return this.waitUntilEmptyIs(false, timeout);
- }
+ return this.waitUntilEmptyIs(false, timeout);
}
/**
@@ -214,14 +242,17 @@ public class SynchronizedStack<E>
* and continue executing. If the stack is not emptied out
* before the time-out, simply continue executing without
* "pushing" the item.
- * The time-out is specified in milliseconds. Return true if the
- * item was pushed; return false if a time-out occurred.
+ * The time-out is specified in milliseconds. Return <code>true</code> if the
+ * item was pushed; return <code>false</code> if a time-out occurred.
+ * If the stack is already empty, "push" the specified item and
+ * return <code>true</code> immediately.
+ * If the time-out is zero, wait indefinitely.
*/
- public boolean waitToPush(E o, long timeout) throws InterruptedException {
+ public boolean waitToPush(E element, long timeout) throws InterruptedException {
synchronized (this.mutex) {
- boolean success = this.waitUntilEmpty(timeout);
+ boolean success = this.waitUntilEmptyIs_(true, timeout);
if (success) {
- this.push(o);
+ this.push_(element);
}
return success;
}
@@ -233,12 +264,15 @@ public class SynchronizedStack<E>
* If the stack is empty and nothing is "pushed" on to it before the
* time-out, throw an empty stack exception.
* The time-out is specified in milliseconds.
+ * If the stack is not empty, "pop" an item and
+ * return it immediately.
+ * If the time-out is zero, wait indefinitely.
*/
public Object waitToPop(long timeout) throws InterruptedException {
synchronized (this.mutex) {
- boolean success = this.waitUntilNotEmpty(timeout);
+ boolean success = this.waitUntilEmptyIs_(false, timeout);
if (success) {
- return this.pop();
+ return this.pop_();
}
throw new EmptyStackException();
}
@@ -273,12 +307,12 @@ public class SynchronizedStack<E>
}
- // ********** Object overrides **********
+ // ********** standard methods **********
@Override
public String toString() {
synchronized (this.mutex) {
- return this.stack.toString();
+ return '[' + this.stack.toString() + ']';
}
}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/QueueIterable.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/QueueIterable.java
new file mode 100644
index 0000000000..50819f3f9c
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/QueueIterable.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal.iterables;
+
+import java.util.Iterator;
+
+import org.eclipse.jpt.utility.internal.Queue;
+import org.eclipse.jpt.utility.internal.StringTools;
+import org.eclipse.jpt.utility.internal.iterators.QueueIterator;
+
+/**
+ * A <code>QueueIterable</code> provides an {@link Iterable}
+ * for a {@link Queue} of objects of type <code>E</code>. The queue's elements
+ * are {@link Queue#dequeue() dequeue}d" as the iterable's iterator returns
+ * them with calls to {@link Iterator#next()}.
+ *
+ * @param <E> the type of elements returned by the iterable's iterator
+ *
+ * @see Queue
+ * @see QueueIterator
+ */
+public class QueueIterable<E>
+ implements Iterable<E>
+{
+ private final Queue<E> queue;
+
+ /**
+ * Construct an iterable for the specified queue.
+ */
+ public QueueIterable(Queue<E> queue) {
+ super();
+ this.queue = queue;
+ }
+
+ public Iterator<E> iterator() {
+ return new QueueIterator<E>(this.queue);
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.queue);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/StackIterable.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/StackIterable.java
new file mode 100644
index 0000000000..a1e18318ed
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterables/StackIterable.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal.iterables;
+
+import java.util.Iterator;
+
+import org.eclipse.jpt.utility.internal.Stack;
+import org.eclipse.jpt.utility.internal.StringTools;
+import org.eclipse.jpt.utility.internal.iterators.StackIterator;
+
+/**
+ * A <code>StackIterable</code> provides an {@link Iterable}
+ * for a {@link Stack} of objects of type <code>E</code>. The stack's elements
+ * are {@link Stack#pop() pop}ped" as the iterable's iterator returns
+ * them with calls to {@link Iterator#next()}.
+ *
+ * @param <E> the type of elements returned by the iterable's iterator
+ *
+ * @see Stack
+ * @see StackIterator
+ */
+public class StackIterable<E>
+ implements Iterable<E>
+{
+ private final Stack<E> stack;
+
+ /**
+ * Construct an iterable for the specified stack.
+ */
+ public StackIterable(Stack<E> stack) {
+ super();
+ this.stack = stack;
+ }
+
+ public Iterator<E> iterator() {
+ return new StackIterator<E>(this.stack);
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.stack);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/QueueIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/QueueIterator.java
new file mode 100644
index 0000000000..d7a1ff5cec
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/QueueIterator.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal.iterators;
+
+import java.util.Iterator;
+
+import org.eclipse.jpt.utility.internal.Queue;
+import org.eclipse.jpt.utility.internal.StringTools;
+
+/**
+ * A <code>QueueIterator</code> provides an {@link Iterator}
+ * for a {@link Queue} of objects of type <code>E</code>. The queue's elements
+ * are {@link Queue#dequeue() dequeue}d" as the iterator returns them with
+ * calls to {@link #next()}.
+ *
+ * @param <E> the type of elements returned by the iterator
+ *
+ * @see Queue
+ */
+public class QueueIterator<E>
+ implements Iterator<E>
+{
+ private final Queue<E> queue;
+
+
+ /**
+ * Construct an iterator for the specified queue.
+ */
+ public QueueIterator(Queue<E> queue) {
+ super();
+ this.queue = queue;
+ }
+
+ public boolean hasNext() {
+ return ! this.queue.isEmpty();
+ }
+
+ public E next() {
+ return this.queue.dequeue();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.queue);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/StackIterator.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/StackIterator.java
new file mode 100644
index 0000000000..af510c8232
--- /dev/null
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/iterators/StackIterator.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.internal.iterators;
+
+import java.util.Iterator;
+
+import org.eclipse.jpt.utility.internal.Stack;
+import org.eclipse.jpt.utility.internal.StringTools;
+
+/**
+ * A <code>StackIterator</code> provides an {@link Iterator}
+ * for a {@link Stack} of objects of type <code>E</code>. The stack's elements
+ * are {@link Stack#pop() pop}ped" as the iterator returns them with
+ * calls to {@link #next()}.
+ *
+ * @param <E> the type of elements returned by the iterator
+ *
+ * @see Stack
+ */
+public class StackIterator<E>
+ implements Iterator<E>
+{
+ private final Stack<E> stack;
+
+
+ /**
+ * Construct an iterator for the specified stack.
+ */
+ public StackIterator(Stack<E> stack) {
+ super();
+ this.stack = stack;
+ }
+
+ public boolean hasNext() {
+ return ! this.stack.isEmpty();
+ }
+
+ public E next() {
+ return this.stack.pop();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return StringTools.buildToStringFor(this, this.stack);
+ }
+
+}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/AsynchronousSynchronizer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/AsynchronousSynchronizer.java
index 75d6fea7fa..970e94c738 100644
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/AsynchronousSynchronizer.java
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/AsynchronousSynchronizer.java
@@ -9,11 +9,8 @@
******************************************************************************/
package org.eclipse.jpt.utility.internal.synchronizers;
-import java.util.Vector;
-
import org.eclipse.jpt.utility.Command;
-import org.eclipse.jpt.utility.internal.CompositeException;
-import org.eclipse.jpt.utility.internal.StringTools;
+import org.eclipse.jpt.utility.internal.ConsumerThreadCoordinator;
import org.eclipse.jpt.utility.internal.SynchronizedBoolean;
/**
@@ -28,7 +25,7 @@ public class AsynchronousSynchronizer
implements Synchronizer
{
/**
- * This flag is shared with the synchronization thread. Setting it to true
+ * This flag is shared with the synchronization/consumer thread. Setting it to true
* will trigger the synchronization to begin or, if the synchronization is
* currently executing, to execute again, once the current execution is
* complete.
@@ -36,34 +33,16 @@ public class AsynchronousSynchronizer
final SynchronizedBoolean synchronizeFlag = new SynchronizedBoolean(false);
/**
- * The runnable passed to the synchronization thread each time it is built.
- */
- private final Runnable runnable;
-
- /**
- * Optional, client-supplied name for the synchronization thread.
- * If null, allow the JDK to assign a name.
- */
- private final String threadName;
-
- /**
- * The synchronization is performed on this thread. A new thread is built
- * for every start/stop cycle (since a thread cannot be started more than
- * once).
+ * Most of the thread-related behavior is delegated to this coordinator.
*/
- private Thread thread;
-
- /**
- * A list of the uncaught exceptions thrown by the command.
- */
- final Vector<Throwable> exceptions = new Vector<Throwable>();
+ private final ConsumerThreadCoordinator consumerThreadCoordinator;
// ********** construction **********
/**
* Construct an asynchronous synchronizer that uses the specified command to
- * perform the synchronization. Allow the generated thread(s) to be assigned
+ * perform the synchronization. Allow the synchronization thread(s) to be assigned
* JDK-generated names.
*/
public AsynchronousSynchronizer(Command command) {
@@ -72,17 +51,19 @@ public class AsynchronousSynchronizer
/**
* Construct an asynchronous synchronizer that uses the specified command to
- * perform the synchronization. Assign the generated thread(s) the specified
+ * perform the synchronization. Assign the synchronization thread(s) the specified
* name.
*/
public AsynchronousSynchronizer(Command command, String threadName) {
super();
- this.runnable = this.buildRunnable(command);
- this.threadName = threadName;
+ if (command == null) {
+ throw new NullPointerException();
+ }
+ this.consumerThreadCoordinator = new ConsumerThreadCoordinator(this.buildConsumer(command), threadName);
}
- Runnable buildRunnable(Command command) {
- return new RunnableSynchronization(command);
+ ConsumerThreadCoordinator.Consumer buildConsumer(Command command) {
+ return new Consumer(command);
}
@@ -106,20 +87,8 @@ public class AsynchronousSynchronizer
* the time {@link #stop()} was called)
* </ul>
*/
- public synchronized void start() {
- if (this.thread != null) {
- throw new IllegalStateException("The Synchronizer was not stopped."); //$NON-NLS-1$
- }
- this.thread = this.buildThread();
- this.thread.start();
- }
-
- private Thread buildThread() {
- Thread t = new Thread(this.runnable);
- if (this.threadName != null) {
- t.setName(this.threadName);
- }
- return t;
+ public void start() {
+ this.consumerThreadCoordinator.start();
}
/**
@@ -140,101 +109,49 @@ public class AsynchronousSynchronizer
* exceptions were thrown while the synchronization thread was executing,
* wrap them in a composite exception and throw the composite exception.
*/
- public synchronized void stop() {
- if (this.thread == null) {
- throw new IllegalStateException("The Synchronizer was not started."); //$NON-NLS-1$
- }
- this.thread.interrupt();
- try {
- this.thread.join();
- } catch (InterruptedException ex) {
- // the thread that called #stop() was interrupted while waiting to
- // join the synchronization thread - ignore;
- // 'thread' is still "interrupted", so its #run() loop will still stop
- // after its current execution - we just won't wait around for it...
- }
- this.thread = null;
-
- if (this.exceptions.size() > 0) {
- Throwable[] temp = this.exceptions.toArray(new Throwable[this.exceptions.size()]);
- this.exceptions.clear();
- throw new CompositeException(temp);
- }
- }
-
- @Override
- public String toString() {
- return StringTools.buildToStringFor(this, this.thread);
+ public void stop() {
+ this.consumerThreadCoordinator.stop();
}
- // ********** synchronization thread runnable **********
+ // ********** consumer **********
/**
- * This implementation of {@link Runnable} will execute a client-supplied command.
- * It will wait until a shared "synchronize" flag is set to execute the
- * command. Once the the comand is executed, the thread will quiesce until
+ * This implementation of {@link ConsumerThreadCoordinator.Consumer}
+ * will execute the client-supplied "synchronize" command.
+ * It will wait until the shared "synchronize" flag is set to execute the
+ * command. Once the comand is executed, the thread will quiesce until
* the flag is set again. If the flag was set during the execution of the
* command (either recursively by the command itself or by another thread),
* the command will be re-executed immediately. Stop the thread by calling
* {@link Thread#interrupt()}.
*/
- class RunnableSynchronization
- implements Runnable
+ class Consumer
+ implements ConsumerThreadCoordinator.Consumer
{
- /** The client-supplied command that executes on this thread. */
+ /**
+ * The client-supplied command that executes on the
+ * synchronization/consumer thread.
+ */
private final Command command;
-
- RunnableSynchronization(Command command) {
+ Consumer(Command command) {
super();
- if (command == null) {
- throw new NullPointerException();
- }
this.command = command;
}
/**
- * Loop while this thread has not been interrupted by another thread.
- * In each loop: Wait until the "synchronize" flag is set,
- * then clear it and execute the command. If the
- * "synchronize" flag was set <em>during</em> the synchronization,
- * there will be no "wait" before beginning the next synchronization
- * (thus the call to {@link Thread#isInterrupted()} before each cycle).
- * <p>
- * If this thread is interrupted <em>during</em> the synchronization, the
- * call to {@link Thread#interrupted()} will stop the loop. If this thread is
- * interrupted during the call to {@link SynchronizedBoolean#waitToSetFalse()},
- * we will catch the {@link InterruptedException} and stop the loop.
- */
- public void run() {
- while ( ! Thread.interrupted()) {
- try {
- AsynchronousSynchronizer.this.synchronizeFlag.waitToSetFalse();
- } catch (InterruptedException ex) {
- // we were interrupted while waiting, must be Quittin' Time
- return;
- }
- this.execute();
- }
- }
-
- /**
- * Execute the client-supplied command. Do not allow any unhandled
- * exceptions to kill the thread. Store them up for later pain.
+ * Wait until the "synchronize" flag is set,
+ * then clear it and allow the "synchronize" command to execute.
*/
- private void execute() {
- try {
- this.execute_();
- } catch (Throwable ex) {
- AsynchronousSynchronizer.this.exceptions.add(ex);
- }
+ public void waitForProducer() throws InterruptedException {
+ AsynchronousSynchronizer.this.synchronizeFlag.waitToSetFalse();
}
/**
* Execute the client-supplied command.
*/
- void execute_() {
+ public void execute() {
this.command.execute();
}
diff --git a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/CallbackAsynchronousSynchronizer.java b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/CallbackAsynchronousSynchronizer.java
index 28c610d642..2c30a3241f 100644
--- a/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/CallbackAsynchronousSynchronizer.java
+++ b/jpa/plugins/org.eclipse.jpt.utility/src/org/eclipse/jpt/utility/internal/synchronizers/CallbackAsynchronousSynchronizer.java
@@ -10,15 +10,16 @@
package org.eclipse.jpt.utility.internal.synchronizers;
import org.eclipse.jpt.utility.Command;
+import org.eclipse.jpt.utility.internal.ConsumerThreadCoordinator;
import org.eclipse.jpt.utility.internal.ListenerList;
/**
* Extend the asynchronous synchronizer to notify listeners
* when a synchronization "cycle" is complete; i.e. the synchronization has,
- * for the moment, handled every "synchronize" request and quiesced.
+ * for the moment, handled every outstanding "synchronize" request and quiesced.
* This notification is <em>not</em> guaranteed to occur with <em>every</em>
- * synchronization "cycle";
- * since other, unrelated, synchronizations can be triggered concurrently.
+ * synchronization "cycle"; since other, unrelated, synchronizations can be
+ * triggered concurrently.
* <p>
* <strong>NB:</strong> Listeners should handle any exceptions
* appropriately (e.g. log the exception and return gracefully so the thread
@@ -35,7 +36,7 @@ public class CallbackAsynchronousSynchronizer
/**
* Construct a callback asynchronous synchronizer that uses the specified
- * command to perform the synchronization. Allow the generated thread(s)
+ * command to perform the synchronization. Allow the synchronization thread(s)
* to be assigned JDK-generated names.
*/
public CallbackAsynchronousSynchronizer(Command command) {
@@ -44,7 +45,7 @@ public class CallbackAsynchronousSynchronizer
/**
* Construct a callback asynchronous synchronizer that uses the specified
- * command to perform the synchronization. Assign the generated thread(s)
+ * command to perform the synchronization. Assign the synchronization thread(s)
* the specified name.
*/
public CallbackAsynchronousSynchronizer(Command command, String threadName) {
@@ -52,12 +53,12 @@ public class CallbackAsynchronousSynchronizer
}
/**
- * Build a runnable that will let us know when the synchronization has
+ * Build a consumer that will let us know when the synchronization has
* quiesced.
*/
@Override
- Runnable buildRunnable(Command command) {
- return new RunnableCallbackSynchronization(command);
+ ConsumerThreadCoordinator.Consumer buildConsumer(Command command) {
+ return new CallbackConsumer(command);
}
@@ -84,7 +85,7 @@ public class CallbackAsynchronousSynchronizer
// ********** synchronization thread runnable **********
/**
- * Extend {@link AsynchronousSynchronizer.RunnableSynchronization}
+ * Extend {@link AsynchronousSynchronizer.Consumer}
* to notify the synchronizer when the synchronization has quiesced
* (i.e. the command has finished executing and there are no further
* requests for synchronization).
@@ -96,16 +97,16 @@ public class CallbackAsynchronousSynchronizer
* but this synchronization will not occur until <em>after</em> all the
* listeners have been notified.
*/
- class RunnableCallbackSynchronization
- extends RunnableSynchronization
+ class CallbackConsumer
+ extends Consumer
{
- RunnableCallbackSynchronization(Command command) {
+ CallbackConsumer(Command command) {
super(command);
}
@Override
- void execute_() {
- super.execute_();
+ public void execute() {
+ super.execute();
// hmmm - we will notify listeners even when we our thread is "interrupted";
// that seems ok... ~bjv
if (CallbackAsynchronousSynchronizer.this.synchronizeFlag.isFalse()) {
diff --git a/jpa/tests/org.eclipse.jpt.core.tests/META-INF/MANIFEST.MF b/jpa/tests/org.eclipse.jpt.core.tests/META-INF/MANIFEST.MF
index 3a5123b641..6696ad1f40 100644
--- a/jpa/tests/org.eclipse.jpt.core.tests/META-INF/MANIFEST.MF
+++ b/jpa/tests/org.eclipse.jpt.core.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %pluginName
Bundle-Vendor: %providerName
-Bundle-SymbolicName: org.eclipse.jpt.core.tests
+Bundle-SymbolicName: org.eclipse.jpt.core.tests;singleton:=true
Bundle-Version: 2.3.0.qualifier
Bundle-Localization: plugin
Require-Bundle: org.eclipse.core.commands;bundle-version="[3.4.0,4.0.0)",
@@ -23,7 +23,8 @@ Require-Bundle: org.eclipse.core.commands;bundle-version="[3.4.0,4.0.0)",
org.eclipse.wst.common.project.facet.core;bundle-version="[1.3.0,2.0.0)",
org.junit;bundle-version="[3.8.2,4.0.0)"
Bundle-RequiredExecutionEnvironment: J2SE-1.5
-Export-Package: org.eclipse.jpt.core.tests.internal;x-friends:="org.eclipse.jpt.ui.tests",
+Export-Package: org.eclipse.jpt.core.tests,
+ org.eclipse.jpt.core.tests.internal;x-friends:="org.eclipse.jpt.ui.tests",
org.eclipse.jpt.core.tests.internal.context;x-internal:=true,
org.eclipse.jpt.core.tests.internal.context.java;x-internal:=true,
org.eclipse.jpt.core.tests.internal.context.orm;x-internal:=true,
@@ -38,3 +39,5 @@ Export-Package: org.eclipse.jpt.core.tests.internal;x-friends:="org.eclipse.jpt.
org.eclipse.jpt.core.tests.internal.resource;x-internal:=true,
org.eclipse.jpt.core.tests.internal.resource.java;x-internal:=true,
org.eclipse.jpt.core.tests.internal.utility.jdt;x-internal:=true
+Bundle-Activator: org.eclipse.jpt.core.tests.JptCoreTestsPlugin
+Bundle-ActivationPolicy: lazy
diff --git a/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/JptCoreTestsPlugin.java b/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/JptCoreTestsPlugin.java
new file mode 100644
index 0000000000..2e3978e5bb
--- /dev/null
+++ b/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/JptCoreTestsPlugin.java
@@ -0,0 +1,56 @@
+/*******************************************************************************
+ * Copyright (c) 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.tests;
+
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.jpt.core.JpaModel;
+import org.eclipse.jpt.core.JptCorePlugin;
+import org.eclipse.jpt.utility.internal.ClassTools;
+import org.osgi.framework.BundleContext;
+
+/**
+ * configure the core to handle events synchronously when we are
+ * running tests
+ */
+@SuppressWarnings("nls")
+public class JptCoreTestsPlugin extends Plugin {
+
+ private static JptCoreTestsPlugin INSTANCE;
+
+ public static JptCoreTestsPlugin instance() {
+ return INSTANCE;
+ }
+
+
+ // ********** plug-in implementation **********
+
+ public JptCoreTestsPlugin() {
+ super();
+ if (INSTANCE != null) {
+ throw new IllegalStateException();
+ }
+ // this convention is *wack*... ~bjv
+ INSTANCE = this;
+ }
+
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ JpaModel jpaModel = JptCorePlugin.getJpaModel();
+ ClassTools.executeMethod(jpaModel, "handleEventsSynchronously");
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ super.stop(context);
+ }
+
+}
diff --git a/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/MiscTests.java b/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/MiscTests.java
new file mode 100644
index 0000000000..72c9ad75ac
--- /dev/null
+++ b/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/MiscTests.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 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.tests;
+
+import junit.framework.TestCase;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ILock;
+import org.eclipse.core.runtime.jobs.Job;
+
+@SuppressWarnings("nls")
+public class MiscTests extends TestCase {
+
+ public MiscTests(String name) {
+ super(name);
+ }
+
+ /*
+ *
+ */
+ public void testJobsAndLocks() throws Exception {
+ ILock lock = Job.getJobManager().newLock();
+ Job testJob = new TestJob(lock);
+ testJob.schedule();
+ }
+
+ class TestJob extends Job {
+ private final ILock lock;
+ TestJob(ILock lock) {
+ super("test job");
+ this.lock = lock;
+ }
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ this.run();
+ return Status.OK_STATUS;
+ }
+ private void run() {
+ try {
+ this.lock.acquire();
+ MiscTests.sleep(100);
+ } finally {
+ this.lock.release();
+ }
+ }
+ }
+
+ static void sleep(long millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+}
diff --git a/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/internal/context/ContextModelTestCase.java b/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/internal/context/ContextModelTestCase.java
index 1f08b71499..0c72eb0ff3 100644
--- a/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/internal/context/ContextModelTestCase.java
+++ b/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/internal/context/ContextModelTestCase.java
@@ -63,7 +63,7 @@ public abstract class ContextModelTestCase extends AnnotationTestCase
super.setUp();
this.persistenceXmlResource = getJpaProject().getPersistenceXmlResource();
this.ormXmlResource = getJpaProject().getDefaultOrmXmlResource();
- waitForWorkspaceJobs();
+ this.waitForWorkspaceJobsToFinish();
}
@Override
@@ -71,6 +71,7 @@ public abstract class ContextModelTestCase extends AnnotationTestCase
this.persistenceXmlResource = null;
this.ormXmlResource = null;
JptCorePlugin.getWorkspacePreferences().clear();
+ this.waitForWorkspaceJobsToFinish();
super.tearDown();
}
@@ -99,8 +100,8 @@ public abstract class ContextModelTestCase extends AnnotationTestCase
return getJavaProject().getJpaProject();
}
- protected void waitForWorkspaceJobs() {
- // This job will not finish running until the workspace jobs are done
+ protected void waitForWorkspaceJobsToFinish() throws InterruptedException {
+ // This job will not start running until all the other workspace jobs are done
Job waitJob = new Job("Wait job") {
@Override
protected IStatus run(IProgressMonitor monitor) {
@@ -109,11 +110,7 @@ public abstract class ContextModelTestCase extends AnnotationTestCase
};
waitJob.setRule(ResourcesPlugin.getWorkspace().getRoot());
waitJob.schedule();
- try {
- waitJob.join();
- } catch (InterruptedException ex) {
- // the job thread was interrupted during a wait - ignore
- }
+ waitJob.join();
}
protected JpaXmlResource getPersistenceXmlResource() {
diff --git a/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/internal/model/JpaModelTests.java b/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/internal/model/JpaModelTests.java
index b47fb0b549..8145ff2f7a 100644
--- a/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/internal/model/JpaModelTests.java
+++ b/jpa/tests/org.eclipse.jpt.core.tests/src/org/eclipse/jpt/core/tests/internal/model/JpaModelTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2006, 2008 Oracle. All rights reserved.
+ * 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.
@@ -9,18 +9,14 @@
******************************************************************************/
package org.eclipse.jpt.core.tests.internal.model;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
import junit.framework.TestCase;
+
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Path;
import org.eclipse.jpt.core.JpaProject;
import org.eclipse.jpt.core.JptCorePlugin;
-import org.eclipse.jpt.core.internal.GenericJpaModel;
-import org.eclipse.jpt.core.internal.JpaModelManager;
import org.eclipse.jpt.core.tests.internal.projects.TestFacetedProject;
import org.eclipse.jpt.core.tests.internal.projects.TestJavaProject;
import org.eclipse.jpt.core.tests.internal.projects.TestPlatformProject;
@@ -47,10 +43,15 @@ public class JpaModelTests extends TestCase {
}
private boolean debug() {
- Boolean debug = (Boolean) ClassTools.staticFieldValue(JpaModelManager.class, "DEBUG");
+ Boolean debug = (Boolean) ClassTools.staticFieldValue(this.getGenericJpaModelClass(), "DEBUG");
return debug.booleanValue();
}
+ // GenericJpaModel is package-private
+ private Class<?> getGenericJpaModelClass() {
+ return JptCorePlugin.getJpaModel().getClass();
+ }
+
private void printName() {
String name = this.getName();
System.out.println();
@@ -94,8 +95,7 @@ public class JpaModelTests extends TestCase {
* make sure the DEBUG constants are 'false' before checking in the code
*/
public void testDEBUG() {
- this.verifyDEBUG(JpaModelManager.class);
- this.verifyDEBUG(GenericJpaModel.class);
+ this.verifyDEBUG(this.getGenericJpaModelClass());
}
private void verifyDEBUG(Class<?> clazz) {
@@ -131,12 +131,12 @@ public class JpaModelTests extends TestCase {
this.testProject.installFacet(JptCorePlugin.FACET_ID, "1.0");
JpaProject jpaProject = JptCorePlugin.getJpaProject(this.testProject.getProject());
assertNotNull(jpaProject);
- assertEquals(1, JptCorePlugin.getJpaModel().jpaProjectsSize());
+ assertEquals(1, JptCorePlugin.getJpaModel().getJpaProjectsSize());
this.testProject.getProject().delete(false, true, null);
jpaProject = JptCorePlugin.getJpaProject(this.testProject.getProject());
assertNull(jpaProject);
- assertEquals(0, JptCorePlugin.getJpaModel().jpaProjectsSize());
+ assertEquals(0, JptCorePlugin.getJpaModel().getJpaProjectsSize());
assertEquals(0, ResourcesPlugin.getWorkspace().getRoot().getProjects().length);
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(this.testProject.getProject().getName());
@@ -159,7 +159,7 @@ public class JpaModelTests extends TestCase {
assertNull(JptCorePlugin.getJpaProject(this.testProject.getProject()));
this.testProject.installFacet(JptCorePlugin.FACET_ID, "1.0");
- assertEquals(1, JptCorePlugin.getJpaModel().jpaProjectsSize());
+ assertEquals(1, JptCorePlugin.getJpaModel().getJpaProjectsSize());
JpaProject jpaProject = JptCorePlugin.getJpaProject(this.testProject.getProject());
assertNotNull(jpaProject);
assertEquals(4, jpaProject.jpaFilesSize());
@@ -170,7 +170,7 @@ public class JpaModelTests extends TestCase {
assertNotNull(jpaProject.getJpaFile(this.getFile(this.testProject, "src/META-INF/orm.xml")));
this.testProject.uninstallFacet(JptCorePlugin.FACET_ID, "1.0");
- assertEquals(0, JptCorePlugin.getJpaModel().jpaProjectsSize());
+ assertEquals(0, JptCorePlugin.getJpaModel().getJpaProjectsSize());
jpaProject = JptCorePlugin.getJpaProject(this.testProject.getProject());
assertNull(jpaProject);
}
diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SimpleQueueTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SimpleQueueTests.java
new file mode 100644
index 0000000000..8ac603921f
--- /dev/null
+++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SimpleQueueTests.java
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.tests.internal;
+
+import java.util.NoSuchElementException;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jpt.utility.internal.Queue;
+import org.eclipse.jpt.utility.internal.SimpleQueue;
+
+@SuppressWarnings("nls")
+public class SimpleQueueTests extends TestCase {
+
+ public SimpleQueueTests(String name) {
+ super(name);
+ }
+
+ Queue<String> buildQueue() {
+ return new SimpleQueue<String>();
+ }
+
+ public void testIsEmpty() {
+ Queue<String> queue = this.buildQueue();
+ assertTrue(queue.isEmpty());
+ queue.enqueue("first");
+ assertFalse(queue.isEmpty());
+ queue.enqueue("second");
+ assertFalse(queue.isEmpty());
+ queue.dequeue();
+ assertFalse(queue.isEmpty());
+ queue.dequeue();
+ assertTrue(queue.isEmpty());
+ }
+
+ public void testEnqueueAndDequeue() {
+ Queue<String> queue = this.buildQueue();
+ String first = "first";
+ String second = "second";
+
+ queue.enqueue(first);
+ queue.enqueue(second);
+ assertEquals(first, queue.dequeue());
+ assertEquals(second, queue.dequeue());
+ }
+
+ public void testEnqueueAndPeek() {
+ Queue<String> queue = this.buildQueue();
+ String first = "first";
+ String second = "second";
+
+ queue.enqueue(first);
+ queue.enqueue(second);
+ assertEquals(first, queue.peek());
+ assertEquals(first, queue.peek());
+ assertEquals(first, queue.dequeue());
+ assertEquals(second, queue.peek());
+ assertEquals(second, queue.peek());
+ assertEquals(second, queue.dequeue());
+ }
+
+ public void testEmptyQueueExceptionPeek() {
+ Queue<String> queue = this.buildQueue();
+ String first = "first";
+ String second = "second";
+
+ queue.enqueue(first);
+ queue.enqueue(second);
+ assertEquals(first, queue.peek());
+ assertEquals(first, queue.dequeue());
+ assertEquals(second, queue.peek());
+ assertEquals(second, queue.dequeue());
+
+ boolean exCaught = false;
+ try {
+ queue.peek();
+ fail();
+ } catch (NoSuchElementException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testEmptyQueueExceptionDequeue() {
+ Queue<String> queue = this.buildQueue();
+ String first = "first";
+ String second = "second";
+
+ queue.enqueue(first);
+ queue.enqueue(second);
+ assertEquals(first, queue.peek());
+ assertEquals(first, queue.dequeue());
+ assertEquals(second, queue.peek());
+ assertEquals(second, queue.dequeue());
+
+ boolean exCaught = false;
+ try {
+ queue.dequeue();
+ fail();
+ } catch (NoSuchElementException ex) {
+ exCaught = true;
+ }
+ assertTrue(exCaught);
+ }
+
+ public void testClone() {
+ SimpleQueue<String> queue = (SimpleQueue<String>) this.buildQueue();
+ queue.enqueue("first");
+ queue.enqueue("second");
+ queue.enqueue("third");
+
+ this.verifyClone(queue, queue.clone());
+ }
+
+ public void testSerialization() throws Exception {
+ Queue<String> queue = this.buildQueue();
+ queue.enqueue("first");
+ queue.enqueue("second");
+ queue.enqueue("third");
+
+ this.verifyClone(queue, TestTools.serialize(queue));
+ }
+
+ private void verifyClone(Queue<String> original, Queue<String> clone) {
+ assertNotSame(original, clone);
+ assertEquals(original.peek(), clone.peek());
+ assertEquals(original.dequeue(), clone.dequeue());
+ assertEquals(original.peek(), clone.peek());
+ assertEquals(original.dequeue(), clone.dequeue());
+ assertEquals(original.isEmpty(), clone.isEmpty());
+ assertEquals(original.peek(), clone.peek());
+ assertEquals(original.dequeue(), clone.dequeue());
+ assertTrue(original.isEmpty());
+ assertEquals(original.isEmpty(), clone.isEmpty());
+
+ original.enqueue("fourth");
+ assertFalse(original.isEmpty());
+ // clone should still be empty
+ assertTrue(clone.isEmpty());
+ }
+
+}
diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SimpleStackTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SimpleStackTests.java
index f1e97895c4..4d3de7b5bf 100644
--- a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SimpleStackTests.java
+++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SimpleStackTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
+ * Copyright (c) 2007, 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.
@@ -14,14 +14,19 @@ import junit.framework.TestCase;
import org.eclipse.jpt.utility.internal.SimpleStack;
import org.eclipse.jpt.utility.internal.Stack;
+@SuppressWarnings("nls")
public class SimpleStackTests extends TestCase {
public SimpleStackTests(String name) {
super(name);
}
+ Stack<String> buildStack() {
+ return new SimpleStack<String>();
+ }
+
public void testIsEmpty() {
- Stack<String> stack = new SimpleStack<String>();
+ Stack<String> stack = this.buildStack();
assertTrue(stack.isEmpty());
stack.push("first");
assertFalse(stack.isEmpty());
@@ -34,7 +39,7 @@ public class SimpleStackTests extends TestCase {
}
public void testPushAndPop() {
- Stack<String> stack = new SimpleStack<String>();
+ Stack<String> stack = this.buildStack();
String first = "first";
String second = "second";
@@ -45,7 +50,7 @@ public class SimpleStackTests extends TestCase {
}
public void testPushAndPeek() {
- Stack<String> stack = new SimpleStack<String>();
+ Stack<String> stack = this.buildStack();
String first = "first";
String second = "second";
@@ -60,7 +65,7 @@ public class SimpleStackTests extends TestCase {
}
public void testEmptyStackExceptionPeek() {
- Stack<String> stack = new SimpleStack<String>();
+ Stack<String> stack = this.buildStack();
String first = "first";
String second = "second";
@@ -74,6 +79,7 @@ public class SimpleStackTests extends TestCase {
boolean exCaught = false;
try {
stack.peek();
+ fail();
} catch (EmptyStackException ex) {
exCaught = true;
}
@@ -81,7 +87,7 @@ public class SimpleStackTests extends TestCase {
}
public void testEmptyStackExceptionPop() {
- Stack<String> stack = new SimpleStack<String>();
+ Stack<String> stack = this.buildStack();
String first = "first";
String second = "second";
@@ -95,6 +101,7 @@ public class SimpleStackTests extends TestCase {
boolean exCaught = false;
try {
stack.pop();
+ fail();
} catch (EmptyStackException ex) {
exCaught = true;
}
@@ -102,7 +109,7 @@ public class SimpleStackTests extends TestCase {
}
public void testClone() {
- SimpleStack<String> stack = new SimpleStack<String>();
+ SimpleStack<String> stack = (SimpleStack<String>) this.buildStack();
stack.push("first");
stack.push("second");
stack.push("third");
@@ -111,7 +118,7 @@ public class SimpleStackTests extends TestCase {
}
public void testSerialization() throws Exception {
- SimpleStack<String> stack = new SimpleStack<String>();
+ Stack<String> stack = this.buildStack();
stack.push("first");
stack.push("second");
stack.push("third");
diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SynchronizedQueueTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SynchronizedQueueTests.java
new file mode 100644
index 0000000000..c95262682d
--- /dev/null
+++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SynchronizedQueueTests.java
@@ -0,0 +1,285 @@
+/*******************************************************************************
+ * Copyright (c) 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.utility.tests.internal;
+
+import java.util.NoSuchElementException;
+
+import org.eclipse.jpt.utility.internal.Queue;
+import org.eclipse.jpt.utility.internal.SimpleQueue;
+import org.eclipse.jpt.utility.internal.SynchronizedQueue;
+
+@SuppressWarnings("nls")
+public class SynchronizedQueueTests extends SimpleQueueTests {
+ private volatile SynchronizedQueue<String> sq;
+ private volatile boolean exCaught;
+ private volatile boolean timeoutOccurred;
+ private volatile long startTime;
+ private volatile long endTime;
+ private volatile Object dequeuedObject;
+
+ static final String ITEM_1 = new String();
+ static final String ITEM_2 = new String();
+
+ public SynchronizedQueueTests(String name) {
+ super(name);
+ }
+
+ @Override
+ Queue<String> buildQueue() {
+ return new SynchronizedQueue<String>();
+ }
+
+ @Override
+ public void testClone() {
+ // synchronized queue is not cloneable
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.sq = new SynchronizedQueue<String>();
+ this.exCaught = false;
+ this.timeoutOccurred = false;
+ this.startTime = 0;
+ this.endTime = 0;
+ this.dequeuedObject = null;
+ }
+
+ /**
+ * test first with an unsynchronized queue,
+ * then with a synchronized queue
+ */
+ public void testConcurrentAccess() throws Exception {
+ this.verifyConcurrentAccess(new SlowSimpleQueue<String>(), "first");
+ this.verifyConcurrentAccess(new SlowSynchronizedQueue<String>(), "second");
+ }
+
+ private void verifyConcurrentAccess(SlowQueue<String> slowQueue, String expected) throws Exception {
+ slowQueue.enqueue("first");
+ slowQueue.enqueue("second");
+
+ Thread thread = new Thread(this.buildRunnable(slowQueue));
+ thread.start();
+ Thread.sleep(200);
+
+ assertEquals(expected, slowQueue.dequeue());
+ thread.join();
+ assertTrue(slowQueue.isEmpty());
+ }
+
+ private Runnable buildRunnable(final SlowQueue<String> slowQueue) {
+ return new Runnable() {
+ public void run() {
+ slowQueue.slowDequeue();
+ }
+ };
+ }
+
+
+ private interface SlowQueue<E> extends Queue<E> {
+ Object slowDequeue();
+ }
+
+ private class SlowSimpleQueue<E> extends SimpleQueue<E> implements SlowQueue<E> {
+ SlowSimpleQueue() {
+ super();
+ }
+ public Object slowDequeue() {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ex) {
+ throw new RuntimeException(ex);
+ }
+ return this.dequeue();
+ }
+
+ }
+
+ private class SlowSynchronizedQueue<E> extends SynchronizedQueue<E> implements SlowQueue<E> {
+ SlowSynchronizedQueue() {
+ super();
+ }
+ public synchronized Object slowDequeue() {
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException ex) {
+ throw new RuntimeException(ex);
+ }
+ return this.dequeue();
+ }
+
+ }
+
+
+ // ********** waits **********
+
+ public void testWaitToDequeue() throws Exception {
+ this.verifyWaitToDequeue(0);
+ // no timeout occurs...
+ assertFalse(this.timeoutOccurred);
+ // ...and an item should have been dequeued by t2...
+ assertSame(ITEM_1, this.dequeuedObject);
+ // ...and the queue should be empty
+ assertTrue(this.sq.isEmpty());
+ // make a reasonable guess about how long t2 took
+ assertTrue(this.elapsedTime() > 150);
+ }
+
+ public void testWaitToDequeueTimeout() throws Exception {
+ this.verifyWaitToDequeue(20);
+ // timeout occurs...
+ assertTrue(this.timeoutOccurred);
+ // ...and the queue was never dequeued...
+ assertNull(this.dequeuedObject);
+ // ...and it still holds the item
+ assertSame(ITEM_1, this.sq.peek());
+ // make a reasonable guess about how long t2 took
+ assertTrue(this.elapsedTime() < 150);
+ }
+
+ private void verifyWaitToDequeue(long timeout) throws Exception {
+ Runnable r1 = this.buildRunnable(this.buildEnqueueCommand(), this.sq, 200);
+ Runnable r2 = this.buildRunnable(this.buildWaitToDequeueCommand(timeout), this.sq, 0);
+ Thread t1 = new Thread(r1);
+ Thread t2 = new Thread(r2);
+ t1.start();
+ t2.start();
+ while (t1.isAlive() || t2.isAlive()) {
+ Thread.sleep(50);
+ }
+ assertFalse(this.exCaught);
+ }
+
+ public void testWaitToEnqueue() throws Exception {
+ this.verifyWaitToEnqueue(0);
+ // no timeout occurs...
+ assertFalse(this.timeoutOccurred);
+ // ...and the queue gets dequeued by t1...
+ assertSame(ITEM_1, this.dequeuedObject);
+ // ...and an item is enqueued on to the queue by t2
+ assertFalse(this.sq.isEmpty());
+ assertSame(ITEM_2, this.sq.peek());
+ // make a reasonable guess about how long t2 took
+ assertTrue(this.elapsedTime() > 150);
+ }
+
+ public void testWaitToEnqueueTimeout() throws Exception {
+ this.verifyWaitToEnqueue(20);
+ // timeout occurs...
+ assertTrue(this.timeoutOccurred);
+ // ...and the queue is eventually dequeued by t1...
+ assertSame(ITEM_1, this.dequeuedObject);
+ // ...but nothing is enqueued on to the queue by t2
+ assertTrue(this.sq.isEmpty());
+ // make a reasonable guess about how long t2 took
+ assertTrue(this.elapsedTime() < 150);
+ }
+
+ private void verifyWaitToEnqueue(long timeout) throws Exception {
+ this.sq.enqueue(ITEM_1);
+ Runnable r1 = this.buildRunnable(this.buildDequeueCommand(), this.sq, 200);
+ Runnable r2 = this.buildRunnable(this.buildWaitToEnqueueCommand(timeout), this.sq, 0);
+ Thread t1 = new Thread(r1);
+ Thread t2 = new Thread(r2);
+ t1.start();
+ t2.start();
+ while (t1.isAlive() || t2.isAlive()) {
+ Thread.sleep(50);
+ }
+ assertFalse(this.exCaught);
+ }
+
+ private Command buildEnqueueCommand() {
+ return new Command() {
+ public void execute(SynchronizedQueue<String> synchronizedQueue) {
+ synchronizedQueue.enqueue(ITEM_1);
+ }
+ };
+ }
+
+ private Command buildWaitToDequeueCommand(final long timeout) {
+ return new Command() {
+ public void execute(SynchronizedQueue<String> synchronizedQueue) throws Exception {
+ SynchronizedQueueTests.this.setStartTime(System.currentTimeMillis());
+ try {
+ SynchronizedQueueTests.this.setDequeuedObject(synchronizedQueue.waitToDequeue(timeout));
+ } catch (NoSuchElementException ex) {
+ SynchronizedQueueTests.this.setTimeoutOccurred(true);
+ }
+ SynchronizedQueueTests.this.setEndTime(System.currentTimeMillis());
+ }
+ };
+ }
+
+ private Command buildDequeueCommand() {
+ return new Command() {
+ public void execute(SynchronizedQueue<String> synchronizedQueue) {
+ SynchronizedQueueTests.this.setDequeuedObject(synchronizedQueue.dequeue());
+ }
+ };
+ }
+
+ private Command buildWaitToEnqueueCommand(final long timeout) {
+ return new Command() {
+ public void execute(SynchronizedQueue<String> synchronizedQueue) throws Exception {
+ SynchronizedQueueTests.this.setStartTime(System.currentTimeMillis());
+ SynchronizedQueueTests.this.setTimeoutOccurred( ! synchronizedQueue.waitToEnqueue(ITEM_2, timeout));
+ SynchronizedQueueTests.this.setEndTime(System.currentTimeMillis());
+ }
+ };
+ }
+
+ private Runnable buildRunnable(final Command command, final SynchronizedQueue<String> synchronizedQueue, final long sleep) {
+ return new Runnable() {
+ public void run() {
+ try {
+ if (sleep != 0) {
+ Thread.sleep(sleep);
+ }
+ command.execute(synchronizedQueue);
+ } catch (Exception ex) {
+ SynchronizedQueueTests.this.setExCaught(true);
+ }
+ }
+ };
+ }
+
+ void setExCaught(boolean exCaught) {
+ this.exCaught = exCaught;
+ }
+
+ void setTimeoutOccurred(boolean timeoutOccurred) {
+ this.timeoutOccurred = timeoutOccurred;
+ }
+
+ void setStartTime(long startTime) {
+ this.startTime = startTime;
+ }
+
+ void setEndTime(long endTime) {
+ this.endTime = endTime;
+ }
+
+ void setDequeuedObject(Object dequeuedObject) {
+ this.dequeuedObject = dequeuedObject;
+ }
+
+ long elapsedTime() {
+ return this.endTime - this.startTime;
+ }
+
+
+ // ********** Command interface **********
+
+ private interface Command {
+ void execute(SynchronizedQueue<String> synchronizedQueue) throws Exception;
+ }
+
+}
diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SynchronizedStackTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SynchronizedStackTests.java
index 50c353c2de..ca187b5cb3 100644
--- a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SynchronizedStackTests.java
+++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/SynchronizedStackTests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007 Oracle. All rights reserved.
+ * Copyright (c) 2007, 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.
@@ -14,6 +14,7 @@ import org.eclipse.jpt.utility.internal.SimpleStack;
import org.eclipse.jpt.utility.internal.Stack;
import org.eclipse.jpt.utility.internal.SynchronizedStack;
+@SuppressWarnings("nls")
public class SynchronizedStackTests extends SimpleStackTests {
private volatile SynchronizedStack<String> ss;
private volatile boolean exCaught;
@@ -30,6 +31,16 @@ public class SynchronizedStackTests extends SimpleStackTests {
}
@Override
+ Stack<String> buildStack() {
+ return new SynchronizedStack<String>();
+ }
+
+ @Override
+ public void testClone() {
+ // synchronized stack is not cloneable
+ }
+
+ @Override
protected void setUp() throws Exception {
super.setUp();
this.ss = new SynchronizedStack<String>();
@@ -53,10 +64,13 @@ public class SynchronizedStackTests extends SimpleStackTests {
slowStack.push("first");
slowStack.push("second");
- new Thread(this.buildRunnable(slowStack)).start();
+ Thread thread = new Thread(this.buildRunnable(slowStack));
+ thread.start();
Thread.sleep(200);
assertEquals(expected, slowStack.pop());
+ thread.join();
+ assertTrue(slowStack.isEmpty());
}
private Runnable buildRunnable(final SlowStack<String> slowStack) {
@@ -93,7 +107,7 @@ public class SynchronizedStackTests extends SimpleStackTests {
}
public synchronized Object slowPop() {
try {
- Thread.sleep(100);
+ Thread.sleep(500);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
diff --git a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/synchronizers/AsynchronousSynchronizerTests.java b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/synchronizers/AsynchronousSynchronizerTests.java
index 9c16348a64..7a6a82f517 100644
--- a/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/synchronizers/AsynchronousSynchronizerTests.java
+++ b/jpa/tests/org.eclipse.jpt.utility.tests/src/org/eclipse/jpt/utility/tests/internal/synchronizers/AsynchronousSynchronizerTests.java
@@ -14,6 +14,7 @@ import junit.framework.TestCase;
import org.eclipse.jpt.utility.Command;
import org.eclipse.jpt.utility.internal.ClassTools;
import org.eclipse.jpt.utility.internal.CompositeException;
+import org.eclipse.jpt.utility.internal.ConsumerThreadCoordinator;
import org.eclipse.jpt.utility.internal.synchronizers.AsynchronousSynchronizer;
import org.eclipse.jpt.utility.internal.synchronizers.Synchronizer;
@@ -57,7 +58,8 @@ public class AsynchronousSynchronizerTests extends TestCase {
}
protected static void stop(Synchronizer synchronizer) {
- if (ClassTools.fieldValue(synchronizer, "thread") != null) {
+ ConsumerThreadCoordinator ctc = (ConsumerThreadCoordinator) ClassTools.fieldValue(synchronizer, "consumerThreadCoordinator");
+ if (ClassTools.fieldValue(ctc, "thread") != null) {
synchronizer.stop();
}
}
@@ -166,7 +168,8 @@ public class AsynchronousSynchronizerTests extends TestCase {
public void testThreadName() {
Synchronizer s = new AsynchronousSynchronizer(this.command1, "sync");
s.start();
- Thread t = (Thread) ClassTools.fieldValue(s, "thread");
+ ConsumerThreadCoordinator ctc = (ConsumerThreadCoordinator) ClassTools.fieldValue(s, "consumerThreadCoordinator");
+ Thread t = (Thread) ClassTools.fieldValue(ctc, "thread");
assertEquals("sync", t.getName());
s.stop();
}

Back to the top