Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 52041 Details for
Bug 157089
org.eclipse.hyades.ui.internal.provider.ResourceChangeUpdateProvider$UIUpdaterProvider maxes out CPU, blocks UI
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read
this important communication.
[patch]
Fix.
patch_157089.txt (text/plain), 112.75 KB, created by
Julien Canches
on 2006-10-16 12:42:33 EDT
(
hide
)
Description:
Fix.
Filename:
MIME Type:
Creator:
Julien Canches
Created:
2006-10-16 12:42:33 EDT
Size:
112.75 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.hyades.test.ui >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/DefaultTypeProvider.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/proxy/DefaultTypeProvider.java,v >retrieving revision 1.12 >diff -u -r1.12 DefaultTypeProvider.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/proxy/DefaultTypeProvider.java 1 Sep 2006 14:03:55 -0000 1.12 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/DefaultTypeProvider.java 16 Oct 2006 16:45:23 -0000 >@@ -11,6 +11,7 @@ > **********************************************************************/ > package org.eclipse.hyades.test.ui.internal.navigator.proxy; > >+import java.util.Collections; > import java.util.HashMap; > import java.util.Map; > >@@ -18,9 +19,7 @@ > import org.eclipse.core.resources.IResourceChangeEvent; > import org.eclipse.core.resources.IResourceChangeListener; > import org.eclipse.core.resources.IResourceDelta; >-import org.eclipse.core.resources.ResourcesPlugin; > import org.eclipse.hyades.test.ui.navigator.IFileProxyManager; >-import org.eclipse.hyades.test.ui.navigator.IProxyNode; > import org.eclipse.hyades.test.ui.navigator.IProxyNodeListener; > import org.eclipse.hyades.test.ui.navigator.ITypeProvider; > import org.eclipse.hyades.test.ui.navigator.ITypeProviderContext; >@@ -43,7 +42,7 @@ > private IFileProxyManager fileProxyManager; > > public DefaultTypeProvider() { >- cache = new HashMap(); >+ cache = Collections.synchronizedMap(new HashMap()); > //- register this class as a resource change listener to the proxy node cache > FileProxyNodeCache.getInstance().addResourceListener(this); > } >@@ -70,53 +69,35 @@ > } > > public void resourceChanged(IResourceChangeEvent event) { >- Object lowestChanged = null; > IResourceDelta resDelta = event.getDelta(); > //- get all projects affected by the current change > IResourceDelta[] affectedProjects = resDelta.getAffectedChildren(); >- boolean oneProjectAlreadyChanged = false; > for (int i = 0; i < affectedProjects.length; i++) { >+ Object lowestChanged = null; > IResourceDelta delta = affectedProjects[i]; > IProject project = (IProject) delta.getResource(); > DefaultTypeProviderProxyNode proxy = (DefaultTypeProviderProxyNode) cache.get(project); > // proxy may be null if we receive a resource change event before get() is invoked: > // in this case, there are no proxies to update. >- if (proxy == null) return; >- boolean wasEmpty = proxy.getChildren().length == 0; >- IProxyNode lowestTP = proxy.resourceChanged(delta); >- if (proxy.getChildren().length == 0 && !wasEmpty) { >- //- after update the type provider does no longer contain children, we need to remove it as well. >- cache.remove(project); >- lowestChanged = project; >- lowestTP = null; >- } else if (proxy.getChildren().length != 0 && wasEmpty) { >- //- after update the type provider is no longer empty, we need to show its content. >- lowestChanged = project; >- lowestTP = null; >+ if (delta.getKind() == IResourceDelta.REMOVED) { >+ cache.remove(project); >+ } else if (delta.getKind() == IResourceDelta.CHANGED) { >+ if (proxy == null) { >+ //lowestChanged = project; >+ } else { >+ int previousChildrenCount = proxy.getChildren().length; >+ lowestChanged = proxy.resourceChanged(delta); >+ if (lowestChanged == proxy) { >+ int newChildrenCount = proxy.getChildren().length; >+ if ((previousChildrenCount == 0 || newChildrenCount == 0) && previousChildrenCount != newChildrenCount) { >+ lowestChanged = project; >+ } >+ } >+ } >+ if(lowestChanged != null) { >+ refresher.nodeChanged(lowestChanged); >+ } > } >- if (lowestTP != null) { >- //- a change is found is it the first one or not ? >- if (lowestChanged == null) { >- //- that is the first one, save it >- lowestChanged = lowestTP; >- } else { >- //- not the first one, so lowest is the parent -> current project >- if (!oneProjectAlreadyChanged) { >- lowestChanged = project; >- oneProjectAlreadyChanged = true; >- } else { >- //- this is the second time that a project is changed, lowest is now the root workspace >- lowestChanged = ResourcesPlugin.getWorkspace().getRoot(); >- } >- } >- } >- if(delta.getKind() == IResourceDelta.REMOVED) { >- cache.remove(project); >- } >- } >- //- refresh only the lowest node >- if(lowestChanged != null) { >- refresher.nodeChanged(lowestChanged); > } > } > >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TestAssetGroupProxyManager.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TestAssetGroupProxyManager.java,v >retrieving revision 1.8 >diff -u -r1.8 TestAssetGroupProxyManager.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TestAssetGroupProxyManager.java 19 May 2006 17:16:10 -0000 1.8 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TestAssetGroupProxyManager.java 16 Oct 2006 16:45:24 -0000 >@@ -11,12 +11,10 @@ > *******************************************************************************/ > package org.eclipse.hyades.test.ui.internal.navigator.proxy; > >+import java.util.Collection; > import java.util.HashMap; > import java.util.Iterator; >-import java.util.LinkedList; >-import java.util.List; > import java.util.Map; >-import java.util.Set; > > import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IResourceChangeEvent; >@@ -26,8 +24,10 @@ > import org.eclipse.core.runtime.IExtensionPoint; > import org.eclipse.core.runtime.Platform; > import org.eclipse.hyades.test.ui.UiPlugin; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.async.SynchronizedAccess; > import org.eclipse.hyades.test.ui.navigator.IProxyNode; > import org.eclipse.hyades.test.ui.navigator.IProxyNodeListener; >+import org.eclipse.hyades.test.ui.navigator.ITypeProviderContext; > > /** This class manage the extensions of org.eclipse.hyades.test.ui.testNavigatorTestAssetGroupProxy > * This class manage all test asset groups created using a cache. >@@ -36,7 +36,7 @@ > */ > public class TestAssetGroupProxyManager implements IResourceChangeListener { > >- static class TestAssetInfo { >+ static class TestAssetInfo extends SynchronizedAccess { > private String name; > private boolean isFlat; > private String imageKey; >@@ -67,22 +67,20 @@ > } > } > >- private Map extensions; > /** >- * project -> List(ITestAssetGroupProxyNode) >+ * string -> TestAssetInfo > */ >- private Map cache; >+ private Map extensions; > /** > * project -> List(ITestAssetGroupProxyNode) > */ >- private Map removedElements; >+ private Map cache; > private IProxyNodeListener refresher; > >- public TestAssetGroupProxyManager() { >+ public TestAssetGroupProxyManager(ITypeProviderContext context) { > extensions = new HashMap(); > cache = new HashMap(); >- removedElements = new HashMap(); >- refresher = new TestNavigatorRefresher(); >+ refresher = context.getProxyNodeListener(); > IExtensionPoint extPoint = Platform.getExtensionRegistry().getExtensionPoint(UiPlugin.getID() + ".testNavigatorTestAssetGroupProxy"); //$NON-NLS-1$ > if (extPoint != null) { > IConfigurationElement[] members = extPoint.getConfigurationElements(); >@@ -113,57 +111,56 @@ > UiPlugin.logInfo("extension: "+extension+" already registered"); //$NON-NLS-1$ //$NON-NLS-2$ > } > } >- >- /** Returns all test asset groups for a given project >- * >- * @param project the project in which the test asset groups are required >- * @return a list of ITestAssetGroupProxyNode. >- */ >- public List getTestAssetGroups(IProject project) { >- if(project != null) { >- List groups = new LinkedList(); >- if(cache.containsKey(project)) { >- return (List)cache.get(project); >- } else { >- //- not yet built >- Set keys = extensions.keySet(); >- for (Iterator it = keys.iterator(); it.hasNext();) { >- ITestAssetGroupProxyNode proxy = getTestAssetGroup(project,(String) it.next()); >- if(proxy != null) { >- groups.add(proxy); >- } >- } >- } >- return groups; >- } else { >- //- return empty list >- return new LinkedList(); >- } >- } >+ >+ public Collection getExtensions() { >+ return extensions.keySet(); >+ } > >- private ITestAssetGroupProxyNode getTestAssetGroup(IProject project, String extension) { >- if(extensions.containsKey(extension)) { >- //- this extension has a test asset group registered to display those files >- TestAssetInfo info = (TestAssetInfo)extensions.get(extension); >- //- build the proxy node with the right parameters >- ITestAssetGroupProxyNode proxy = new TestAssetGroupProxyNode(project, extension, info.getName(), info.getImageKey(), info.isFlat, project); >- if(proxy.getChildren().length > 0) { >- cachePut(project, proxy); >- return proxy; >- } >- } >+ public ITestAssetGroupProxyNode getTestAssetGroup(IProject project, String extension) { >+ ITestAssetGroupProxyNode group = cacheGet(project, extension); >+ if (group == null) { >+ if(extensions.containsKey(extension)) { >+ //- this extension has a test asset group registered to display those files >+ TestAssetInfo info = (TestAssetInfo)extensions.get(extension); >+ //- build the proxy node with the right parameters >+ try { >+ if (info.acquireLock(project)) { >+ // the group may be have been computed in another thread while we >+ // were acquiring the lock. >+ group = cacheGet(project, extension); >+ if (group == null) { >+ group = new TestAssetGroupProxyNode(project, extension, info.getName(), info.getImageKey(), info.isFlat, project); >+ cachePut(project, extension, group); >+ } >+ } >+ } finally { >+ info.releaseLock(project); >+ } >+ } >+ } >+ >+ if(group != null && group.getChildren().length > 0) { >+ return group; >+ } > return null; > } > >- private void cachePut(IProject project, ITestAssetGroupProxyNode testAsset) { >- List list; >- if (cache.containsKey(project)) { >- list = (List) cache.get(project); >- } else { >- list = new LinkedList(); >- cache.put(project, list); >- } >- list.add(testAsset); >+ private void cachePut(IProject project, String extension, ITestAssetGroupProxyNode testAsset) { >+ Map map = (Map) cache.get(project); >+ if (map == null) { >+ map = new HashMap(); >+ cache.put(project, map); >+ } >+ map.put(extension, testAsset); >+ } >+ >+ private ITestAssetGroupProxyNode cacheGet(IProject project, String extension) { >+ Map map = (Map) cache.get(project); >+ if (map != null) { >+ ITestAssetGroupProxyNode group = (ITestAssetGroupProxyNode) map.get(extension); >+ if (group != null) return group; >+ } >+ return null; > } > > /* (non-Javadoc) >@@ -178,111 +175,38 @@ > IResourceDelta delta = affectedProjects[i]; > IProject project = (IProject)delta.getResource(); > //- given a project we need to update all test asset group proxy nodes created in this project >- List groups = (List)cache.get(project); >+ Map groups = (Map)cache.get(project); > if(groups != null) { >- for (Iterator it = groups.iterator(); it.hasNext();) { >- TestAssetGroupProxyNode proxy = (TestAssetGroupProxyNode) it.next(); >- IProxyNode lowestProxy = proxy.resourceChanged(delta); >- if(proxy.getChildren().length == 0) { >- //- this means that the group no longer contains children >- prepareCacheRemove(project, proxy); >- lowestChanged = project; >- lowestProxy = null; >- } >- if(lowestProxy != null) { >- //- there was a change in this test asset group proxy node tree >- if(lowestChanged == null) { >- //- this was the first change >- lowestChanged = lowestProxy; >- } else { >- //- the second one ... we need to refresh the owner of those nodes (the project) >- lowestChanged = project; >- } >+ for (Iterator it = extensions.keySet().iterator(); it.hasNext();) { >+ String ext = (String)it.next(); >+ TestAssetGroupProxyNode proxy = (TestAssetGroupProxyNode) groups.get(ext); >+ if (proxy != null) { >+ IProxyNode lowestProxy = proxy.resourceChanged(delta); >+ if(proxy.getChildren().length == 0) { >+ //- this means that the group no longer contains children >+ lowestChanged = project; >+ lowestProxy = null; >+ } >+ if(lowestProxy != null) { >+ //- there was a change in this test asset group proxy node tree >+ if(lowestChanged == null) { >+ //- this was the first change >+ lowestChanged = lowestProxy; >+ } else { >+ //- the second one ... we need to refresh the owner of those nodes (the project) >+ lowestChanged = project; >+ } >+ } > } > } > } >- //- we need to handle test asset creation in empty group >- boolean newTAG = getAddedTestAssetGroups(project, delta); >- if(!(lowestChanged instanceof IProject) && newTAG) { >- lowestChanged = project; >- } > } >- //- after the for loop, we can update the cache for removes >- completeCacheRemoves(); > //- refresh only the lowest node > if(lowestChanged != null) { > refresher.nodeChanged(lowestChanged); > } > } > >- /** Return whether the given project has changed by addition of new test asset group found in the resource delta. >- * @param project the project affected by the resource change >- * @param delta the resource change delta used to know what the change is. >- * @return <code>true</code> if the project has at least one new test asset group proxy node and <code>false</code> otherwise. >- */ >- private boolean getAddedTestAssetGroups(IProject project, IResourceDelta delta) { >- List groups = (List)cache.get(project); >- List notExistingExt = new LinkedList(); >- //- initializing with all extensions >- for (Iterator it = extensions.keySet().iterator(); it.hasNext();) { >- notExistingExt.add(it.next()); >- } >- //- remove from all those that already been handled by a test asset group proxy node >- if(groups != null) { >- for (Iterator it = groups.iterator(); it.hasNext();) { >- TestAssetGroupProxyNode tagpn = (TestAssetGroupProxyNode) it.next(); >- notExistingExt.remove(tagpn.getExtension()); >- } >- } >- boolean projectChanged = false; >- //- then try to create a test asset group from this list of not yet handled extension >- for (Iterator it = notExistingExt.iterator(); it.hasNext();) { >- String ext = (String) it.next(); >- ITestAssetGroupProxyNode proxy = getTestAssetGroup(project, ext); >- //- if the proxy has been created, that means that the project need to be refreshed >- if(proxy != null) { >- projectChanged = true; >- } >- } >- return projectChanged; >- } >- >- private void prepareCacheRemove(IProject project, TestAssetGroupProxyNode proxy) { >- List proxies; >- if(removedElements.containsKey(project)) { >- //- a test asset group of this project has already been added to removals >- proxies = (List)removedElements.get(project); >- } else { >- proxies = new LinkedList(); >- removedElements.put(project, proxies); >- } >- proxies.add(proxy); >- } >- >- private void completeCacheRemoves() { >- Set removed = removedElements.entrySet(); >- for (Iterator it = removed.iterator(); it.hasNext();) { >- Map.Entry element = (Map.Entry) it.next(); >- IProject project = (IProject)element.getKey(); >- //- remove saved test asset groups of this project >- removeCacheElements(project, (List)element.getValue()); >- } >- //- clear removal cache. >- removedElements.clear(); >- } >- >- /** >- * Removes all element given by the list argument from the project cached elements >- * @param project the project from which the elements are removed >- * @param list elments to remove. (those elements should be ITestAssetGroupProxyNode) >- */ >- private void removeCacheElements(IProject project, List list) { >- List groups = (List)cache.get(project); >- for(Iterator it = list.iterator(); it.hasNext(); ) { >- groups.remove(it.next()); >- } >- } >- > public void dispose() { > FileProxyNodeCache.getInstance().removeResourceListener(this); > } >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/FileProxyNodeCache.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/proxy/FileProxyNodeCache.java,v >retrieving revision 1.10 >diff -u -r1.10 FileProxyNodeCache.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/proxy/FileProxyNodeCache.java 28 Sep 2006 15:14:48 -0000 1.10 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/FileProxyNodeCache.java 16 Oct 2006 16:45:24 -0000 >@@ -12,6 +12,7 @@ > package org.eclipse.hyades.test.ui.internal.navigator.proxy; > > import java.util.ArrayList; >+import java.util.Collection; > import java.util.Collections; > import java.util.HashMap; > import java.util.HashSet; >@@ -20,6 +21,7 @@ > import java.util.Set; > > 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; >@@ -30,6 +32,7 @@ > import org.eclipse.hyades.test.ui.UiPlugin; > import org.eclipse.hyades.test.ui.internal.navigator.TestNavigator; > import org.eclipse.hyades.test.ui.internal.navigator.TestNavigatorMessages; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.async.SynchronizedAccess; > import org.eclipse.hyades.test.ui.navigator.FileProxyNode; > import org.eclipse.hyades.test.ui.navigator.IFileProxyFactory; > import org.eclipse.hyades.test.ui.navigator.IPersistableProxyNode; >@@ -45,7 +48,7 @@ > * @author jgout > * @since 4.2 > */ >-public class FileProxyNodeCache { >+public class FileProxyNodeCache extends SynchronizedAccess { > > /** > * Internal class associated to files that do not have a proxy. It is used as a marker >@@ -112,6 +115,12 @@ > private IFileProxyPersister defaultPersister = new FileProxyMarkerPersister(); > > /** >+ * The set of locked files. A file is locked when a proxy is being computed for this >+ * file. Only one thread is allowed to access a file at one time. >+ */ >+ private Collection locks = Collections.synchronizedList(new ArrayList(TestNavigator.BACKGROUND_JOB_POOL_SIZE + 1)); >+ >+ /** > * Singleton instance. > */ > private static FileProxyNodeCache instance; >@@ -196,14 +205,23 @@ > IProxyNode proxy = (IProxyNode) proxies.get(file); > if (proxy == null && file.exists()) { > try { >- //- not yet in the cache, try to load it. >- proxy = loadProxy(file); >- if(proxy == null) { >- //- load failed, create the proxy using a proxy factory. >- proxy = createProxy(file); >- } >+ if (acquireLock(file)) { >+ // Test again if file is in the map. It may have been added while we were >+ // acquiring the lock. >+ proxy = (IProxyNode) proxies.get(file); >+ if (proxy == null) { >+ //- not yet in the cache, try to load it. >+ proxy = loadProxy(file); >+ if(proxy == null) { >+ //- load failed, create the proxy using a proxy factory. >+ proxy = internalCreateProxy(file); >+ } >+ } >+ } > } catch (Throwable t) { > proxy = createErrorProxy(file, t); >+ } finally { >+ releaseLock(file); > } > } > if (proxy == nullProxy) return null; >@@ -245,6 +263,19 @@ > * @return the new proxy node ot <code>null</code> if there is no factory that is able to create proxies from this kind of file. > */ > public IProxyNode createProxy(IFile file) { >+ try { >+ if (acquireLock(file)) { >+ proxies.remove(file); >+ return internalCreateProxy(file); >+ } else { >+ return null; >+ } >+ } finally { >+ releaseLock(file); >+ } >+ } >+ >+ private IProxyNode internalCreateProxy(IFile file) { > IProxyNode proxy = null; > //- get all factories (FileProxyFactory) for this file element > ArrayList factories = TestNavigator.getFileFactoryManager().getFactories(file.getFileExtension()); >@@ -292,6 +323,20 @@ > resourceListeners.remove(listener); > } > >+ /** >+ * Invoked when a project is closed. This method cleans up the map and removes any >+ * cached files that belong the closed project. >+ * @param project >+ */ >+ protected void projectClosed(IProject project) { >+ for (Iterator it = proxies.keySet().iterator(); it.hasNext();) { >+ IFile file = (IFile) it.next(); >+ if (project.equals(file.getProject())) { >+ it.remove(); >+ } >+ } >+ } >+ > private class ResourceChangeListener implements IResourceChangeListener, IResourceDeltaVisitor { > > public ResourceChangeListener() { >@@ -306,15 +351,16 @@ > IResourceDelta delta = event.getDelta(); > if(delta == null) return; > //- first delegates to other listeners registered in the cache. >+ IResourceChangeListener[] copy; > synchronized(resourceListeners) { >- for (Iterator it = resourceListeners.iterator(); it.hasNext();) { >- IResourceChangeListener listener = (IResourceChangeListener) it.next(); >- try { >- listener.resourceChanged(event); >- } catch (Throwable e) { >- UiPlugin.logError(e); >- } >- } >+ copy = (IResourceChangeListener[]) resourceListeners.toArray(new IResourceChangeListener[resourceListeners.size()]); >+ } >+ for (int i = 0; i < copy.length; i++) { >+ try { >+ copy[i].resourceChanged(event); >+ } catch (Throwable e) { >+ UiPlugin.logError(e); >+ } > } > //- then cache can handle proxies removal properly. > try { >@@ -328,6 +374,15 @@ > > public boolean visit(IResourceDelta delta) throws CoreException { > if (delta.getKind() == IResourceDelta.CHANGED) { >+ if (delta.getResource().getType() == IResource.PROJECT) { >+ if ((delta.getFlags() & IResourceDelta.OPEN) != 0) { >+ IProject project = (IProject)delta.getResource(); >+ if (!project.isOpen()) { >+ // Project has been closed. >+ projectClosed(project); >+ } >+ } >+ } > return delta.getResource().getType() != IResource.FILE; > } > if (delta.getKind() == IResourceDelta.REMOVED) { >@@ -341,4 +396,5 @@ > return false; > } > } >+ > } >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TypeProviderManager.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TypeProviderManager.java,v >retrieving revision 1.8 >diff -u -r1.8 TypeProviderManager.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TypeProviderManager.java 1 Sep 2006 14:03:55 -0000 1.8 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TypeProviderManager.java 16 Oct 2006 16:45:24 -0000 >@@ -11,6 +11,7 @@ > *******************************************************************************/ > package org.eclipse.hyades.test.ui.internal.navigator.proxy; > >+import java.util.Collections; > import java.util.HashMap; > import java.util.Iterator; > import java.util.Map; >@@ -22,6 +23,8 @@ > import org.eclipse.core.runtime.Platform; > import org.eclipse.hyades.test.ui.UiPlugin; > import org.eclipse.hyades.test.ui.internal.navigator.TestNavigator; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.async.ISynchronizedAccess; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.async.JobSynchronizedAccess; > import org.eclipse.hyades.test.ui.navigator.ITypeProvider; > import org.eclipse.hyades.test.ui.navigator.ITypeProviderContext; > import org.eclipse.hyades.test.ui.navigator.ITypeProviderProxyNode; >@@ -37,7 +40,7 @@ > */ > public class TypeProviderManager { > >- static interface ITypeProviderInfo { >+ static interface ITypeProviderInfo extends ISynchronizedAccess { > > /** > * @return Returns the imageKey. >@@ -56,7 +59,7 @@ > > } > >- class ExtensionTypeProviderInfo implements ITypeProviderInfo { >+ class ExtensionTypeProviderInfo extends JobSynchronizedAccess implements ITypeProviderInfo { > private String name; > private String imageKey; > /** >@@ -103,7 +106,7 @@ > } > } > >- class DefaultTypeProviderInfo implements ITypeProviderInfo { >+ class DefaultTypeProviderInfo extends JobSynchronizedAccess implements ITypeProviderInfo { > private DefaultTypeProvider defaultTypeProvider; > private String name; > >@@ -137,7 +140,7 @@ > private ITypeProviderContext context; > > public TypeProviderManager(ITypeProviderContext context) { >- providers = new HashMap(); >+ providers = Collections.synchronizedMap(new HashMap()); > this.context = context; > IExtensionPoint extPoint = Platform.getExtensionRegistry().getExtensionPoint(UiPlugin.getID() + ".testNavigatorTypeProvider"); //$NON-NLS-1$ > if (extPoint != null) { >@@ -178,14 +181,24 @@ > * @return a type provider proxy node. > */ > public ITypeProviderProxyNode getTypeProviderProxyNode(IProject project, String type) { >- if(!providers.containsKey(type)) { >- //- since no provider registered for the given type, add the default one for the given type in the map >- addProvider(type, new DefaultTypeProviderInfo(type)); >- } >+ synchronized(providers) { >+ if(!providers.containsKey(type)) { >+ //- since no provider registered for the given type, add the default one for the given type in the map >+ addProvider(type, new DefaultTypeProviderInfo(type)); >+ } >+ } > //- By construction, the internal map of providers has a provider for the given type. > ITypeProviderInfo info = (ITypeProviderInfo)providers.get(type); > //- deleguate to client >- return info.getProvider().get(project, type); >+ ITypeProvider provider = info.getProvider(); >+ try { >+ if (info.acquireLock(project)) { >+ return provider.get(project, type); >+ } >+ return null; >+ } finally { >+ info.releaseLock(project); >+ } > } > > /** Returns the name registered in the extension for the given type of element. >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/FileProxyManager.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/proxy/FileProxyManager.java,v >retrieving revision 1.23 >diff -u -r1.23 FileProxyManager.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/proxy/FileProxyManager.java 11 Apr 2006 11:27:10 -0000 1.23 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/FileProxyManager.java 16 Oct 2006 16:45:23 -0000 >@@ -11,6 +11,7 @@ > *******************************************************************************/ > package org.eclipse.hyades.test.ui.internal.navigator.proxy; > >+import java.util.Collections; > import java.util.HashMap; > import java.util.Iterator; > import java.util.Map; >@@ -43,8 +44,8 @@ > private FileProxyNodeCache fileProxyNodeCache; > > public FileProxyManager() { >- parents = new HashMap(); >- parentsToCache = new HashMap(); >+ parents = Collections.synchronizedMap(new HashMap()); >+ parentsToCache = Collections.synchronizedMap(new HashMap()); > fileProxyNodeCache = FileProxyNodeCache.getInstance(); > } > >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TestNavigatorRefresher.java >=================================================================== >RCS file: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TestNavigatorRefresher.java >diff -N src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TestNavigatorRefresher.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/proxy/TestNavigatorRefresher.java 26 Apr 2005 15:55:53 -0000 1.2 >+++ /dev/null 1 Jan 1970 00:00:00 -0000 >@@ -1,31 +0,0 @@ >-/******************************************************************************* >- * Copyright (c) 2005 IBM Corporation and others. >- * 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 >- * $Id: TestNavigatorRefresher.java,v 1.2 2005/04/26 15:55:53 jcanches Exp $ >- * >- * Contributors: >- * IBM Corporation - initial API and implementation >- *******************************************************************************/ >-package org.eclipse.hyades.test.ui.internal.navigator.proxy; >- >-import java.util.Iterator; >- >-import org.eclipse.hyades.test.ui.internal.navigator.TestNavigator; >-import org.eclipse.hyades.test.ui.navigator.IProxyNodeListener; >- >-/** >- * @author jgout >- * >- */ >-public class TestNavigatorRefresher implements IProxyNodeListener { >- >- public void nodeChanged(Object node) { >- for(Iterator it = TestNavigator.getAllInstancesIterator(); it.hasNext();) { >- ((TestNavigator)it.next()).nodeChanged(node); >- } >- } >- >-} >Index: src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigatorProvider.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigatorProvider.java,v >retrieving revision 1.4 >diff -u -r1.4 TestNavigatorProvider.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigatorProvider.java 30 Jan 2006 09:19:56 -0000 1.4 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigatorProvider.java 16 Oct 2006 16:45:23 -0000 >@@ -15,16 +15,32 @@ > > import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IWorkspaceRoot; >+import org.eclipse.core.runtime.jobs.Job; > import org.eclipse.hyades.test.ui.internal.navigator.proxy.FileProxyManager; > import org.eclipse.hyades.test.ui.navigator.IProxyNode; >+import org.eclipse.hyades.test.ui.navigator.IProxyNodeListener; > import org.eclipse.jface.viewers.ITreeContentProvider; > import org.eclipse.jface.viewers.Viewer; > > /** > * @author jgout >+ * @author jcanches > */ > public abstract class TestNavigatorProvider extends TestNavigatorLabelProvider implements ITreeContentProvider { > >+ public static final int CONTEXT_LOADING = 0; >+ public static final int CONTEXT_INTERACTIVE = 1; >+ >+ protected TestNavigator testNavigator; >+ private int context; >+ >+ public TestNavigatorProvider(TestNavigator testNavigator) { >+ this.testNavigator = testNavigator; >+ this.context = CONTEXT_LOADING; >+ } >+ >+ protected abstract IProxyNodeListener getProxyNodeListener(); >+ > public Object getParent(Object element) { > if (element instanceof IProxyNode) { > Object parent = ((IProxyNode) element).getParent(); >@@ -71,4 +87,45 @@ > public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { > } > >+ /** >+ * Sets the context in which the provider is used. There are two available values: >+ * INTERACTIVE and LOADING. The context has an effect on two parameters: >+ * 1) responsiveness: time that getChildren() is allowed to spent before returning >+ * control. High responsiveness means that the provider will return incomplete nodes, >+ * compute the remaining in a background task, and update the navigator when computation >+ * is complete. Low responsiveness means that the UI will be blocked for a longer period of >+ * time but the returned node are more likely to be complete. >+ * 2) computation job priority: the priority allocated to the computation job, if the provider >+ * does not manage to compute nodes in the allocated time (responsiveness parameter). This does >+ * not affect the thread priority, but helps eclipse decide which job should be launched first. >+ * In LOADING mode, responsiveness is high (100ms) and priority is low (NORMAL). >+ * In INTERACTIVE mode, responsiveness is lower (800ms) and priority is high (INTERACTIVE). >+ */ >+ public void setContext(int context) { >+ this.context = context; >+ } >+ >+ protected int getContext() { >+ return context; >+ } >+ >+ protected int getResponseTime() { >+ switch (context) { >+ case CONTEXT_INTERACTIVE: >+ return 800; >+ case CONTEXT_LOADING: >+ return 100; >+ } >+ return 100; >+ } >+ >+ protected int getJobPriority() { >+ switch(context) { >+ case CONTEXT_INTERACTIVE: >+ return Job.INTERACTIVE; >+ case CONTEXT_LOADING: >+ return Job.LONG; >+ } >+ return Job.LONG; >+ } > } >Index: src/org/eclipse/hyades/test/ui/internal/navigator/messages.properties >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/messages.properties,v >retrieving revision 1.8 >diff -u -r1.8 messages.properties >--- src/org/eclipse/hyades/test/ui/internal/navigator/messages.properties 10 Aug 2006 15:19:23 -0000 1.8 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/messages.properties 16 Oct 2006 16:45:23 -0000 >@@ -15,6 +15,7 @@ > > TEST_NAVIGATOR_UNNAMED_ELEMENT=unnamed > PROXY_LOADING_ERROR=loading error >+NODE_PENDING=Pending... > OpenWithActionGroup_ActionLabel=Open Wit&h > FileFolderInContainerPaste_NameTwoArg=Copy ({0}) of {1} > FileFolderInContainerPaste_NameOneArg=Copy of {0} >@@ -24,3 +25,8 @@ > FileFolderInContainerPaste_MessageLabel=Enter a new name for ''{0}'' > TestNavigatorActionGroup_ToggleAction_Text=Link with Editor > RenameAction_ActionName=Rena&me >+PM_INDEXING_TYPE=Indexing type {0} >+PM_INDEXING_ASSET_GROUP=Indexing .{0} assets >+PM_EXPLORING_PROJECT=Exploring project {0} >+PM_EXPLORING_FOLDER=Exploring {0} >+PM_INDEXING_FILE=Indexing {0} >\ No newline at end of file >Index: src/org/eclipse/hyades/test/ui/internal/navigator/ResourceTestNavigatorProvider.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/ResourceTestNavigatorProvider.java,v >retrieving revision 1.6 >diff -u -r1.6 ResourceTestNavigatorProvider.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/ResourceTestNavigatorProvider.java 1 Sep 2006 14:03:54 -0000 1.6 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/ResourceTestNavigatorProvider.java 16 Oct 2006 16:45:23 -0000 >@@ -11,17 +11,26 @@ > *******************************************************************************/ > package org.eclipse.hyades.test.ui.internal.navigator; > >+import java.util.ArrayList; >+import java.util.Collections; >+import java.util.HashMap; >+import java.util.Iterator; > import java.util.List; >+import java.util.Map; > > import org.eclipse.core.resources.IContainer; > import org.eclipse.core.resources.IFile; > import org.eclipse.core.resources.IProject; > import org.eclipse.core.resources.IResource; > import org.eclipse.core.runtime.CoreException; >-import org.eclipse.emf.common.util.UniqueEList; > import org.eclipse.hyades.test.ui.UiPlugin; > import org.eclipse.hyades.test.ui.internal.navigator.proxy.FileProxyManager; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.async.FileProxiesRequest; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.async.IProxiesRequestListener; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.async.ProxiesRequest; > import org.eclipse.hyades.test.ui.navigator.IProxyNode; >+import org.eclipse.hyades.test.ui.navigator.IProxyNodeListener; >+import org.eclipse.hyades.ui.util.IDisposable; > > /** This the resource oriented provider for the test navigator view. > * @author jgout >@@ -39,6 +48,12 @@ > return fileProxyManager; > } > >+ public ResourceTestNavigatorProvider(TestNavigator testNavigator) { >+ super(testNavigator); >+ } >+ >+ private FileProxyRequests requests = new FileProxyRequests(); >+ > public Object getParent(Object element) { > if (element instanceof IResource) { > return ((IResource) element).getParent(); >@@ -101,7 +116,6 @@ > * @return an array of Object which cn be empty but not null > */ > private Object[] getContainerChildren(Object parentElement) { >- List children = new UniqueEList(); > IResource[] resources = null; > IContainer container = ((IContainer) parentElement); > if (container.isAccessible()) { >@@ -111,23 +125,116 @@ > UiPlugin.logError(e); > return new Object[0]; > } >+ List children = new ArrayList(resources.length); >+ FileProxiesRequest request = requests.getRequest(container, resources); > for (int i = 0, maxi = resources.length; i < maxi; i++) { > if (!TestNavigator.getFiltersManager().filter(resources[i])) { >- if (resources[i].getType() != IResource.FILE) { >- //- folders are displayed as they are >- children.add(resources[i]); >- } else { >+ if (resources[i].getType() != IResource.FILE) { >+ children.add(resources[i]); >+ } else { > //- convert the file in something else (proxy) >- IProxyNode node = fileProxyManager.getProxy((IFile) resources[i], resources[i].getParent()); >+ IFile file = (IFile)resources[i]; >+ IProxyNode node = request.getProxy(file); > if (!TestNavigator.getFiltersManager().filter(node)) { > children.add(node); >- fileProxyManager.cacheProxy((IFile) resources[i], node); >+ fileProxyManager.cacheProxy(file, node); > } > } > } > } >- } >- return children.toArray(); >+ return children.toArray(); >+ } >+ return new Object[0]; >+ } >+ >+ public IProxyNodeListener getProxyNodeListener() { >+ return requests; >+ } >+ >+ private class FileProxyRequests implements IProxiesRequestListener, IDisposable, IProxyNodeListener { >+ >+ private Map containerToRequestMap = Collections.synchronizedMap(new HashMap()); >+ >+ public FileProxiesRequest getRequest(IContainer container, IResource[] members) { >+ FileProxiesRequest request = (FileProxiesRequest)containerToRequestMap.get(container); >+ //if (request != null && !request.isPending()) containerToRequestMap.remove(container); >+ if (request == null) { >+ request = newRequest(container, members); >+ } >+ return request; >+ } >+ >+ public FileProxiesRequest newRequest(IContainer container, IResource[] members) { >+ ArrayList filesToRequest = new ArrayList(members.length); >+ for (int i = 0, maxi = members.length; i < maxi; i++) { >+ if (members[i].getType() == IResource.FILE) { >+ if (!TestNavigator.getFiltersManager().filter(members[i])) { >+ filesToRequest.add(members[i]); >+ } >+ } >+ } >+ if (filesToRequest.isEmpty()) return null; >+ FileProxiesRequest req = new FileProxiesRequest(filesToRequest, fileProxyManager, container, testNavigator); >+ req.setPriority(getJobPriority()); >+ testNavigator.getJobPool().scheduleJob(req); >+ if (!req.wait(getResponseTime(), this, 2000)) { >+ containerToRequestMap.put(container, req); >+ } >+ return req; >+ } >+ >+ public void proxyComputed(final ProxiesRequest request, Object key) { >+ } >+ >+ public void computationCompleted(ProxiesRequest request) { >+ IContainer parent = ((FileProxiesRequest)request).getParent(); >+ if (containerToRequestMap.containsKey(parent)) { >+ // A last refresh is necessary to remove the request from the map. >+ testNavigator.refresh(parent); >+ } >+ } >+ >+ public void dispose() { >+ // Cancel all running requests. As the atomic action of FileProxiesRequest is >+ // the computation of a single file proxy, all requests should honor the cancel >+ // request quite quickly. However we don't wait them to complete (i.e. they may >+ // be still running while this instance has been disposed). >+ for (Iterator it = containerToRequestMap.values().iterator(); it.hasNext();) { >+ FileProxiesRequest request = (FileProxiesRequest) it.next(); >+ request.dispose(); >+ it.remove(); >+ } >+ } >+ >+ public void proxiesComputed(ProxiesRequest request) { >+ testNavigator.refresh(((FileProxiesRequest)request).getParent()); >+ } >+ >+ public void nodeChanged(Object node) { >+ if (node instanceof IContainer) { >+ FileProxiesRequest req = (FileProxiesRequest) containerToRequestMap.remove(node); >+ if (req != null) { >+ // Then we need to cancel the current request. A new one will be spawned >+ // when getChildren() is invoked on this project. >+ if (req.cancel(1000)) { >+ containerToRequestMap.remove(node); >+ testNavigator.refresh(node); >+ } >+ } >+ } >+ } >+ >+ public void computationCancelled(ProxiesRequest request) { >+ IContainer parent = ((FileProxiesRequest)request).getParent(); >+ containerToRequestMap.remove(parent); >+ testNavigator.refresh(parent); >+ } >+ >+ } >+ >+ public void dispose() { >+ requests.dispose(); >+ super.dispose(); > } > > } >Index: src/org/eclipse/hyades/test/ui/internal/navigator/TestResourceChangeUpdater.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/TestResourceChangeUpdater.java,v >retrieving revision 1.12 >diff -u -r1.12 TestResourceChangeUpdater.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/TestResourceChangeUpdater.java 1 Sep 2006 14:03:54 -0000 1.12 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/TestResourceChangeUpdater.java 16 Oct 2006 16:45:23 -0000 >@@ -15,6 +15,7 @@ > import java.util.Iterator; > import java.util.List; > >+import org.eclipse.core.resources.IContainer; > import org.eclipse.core.resources.IFile; > import org.eclipse.core.resources.IResource; > import org.eclipse.emf.common.util.UniqueEList; >@@ -23,6 +24,7 @@ > import org.eclipse.hyades.models.common.common.CMNNamedElement; > import org.eclipse.hyades.test.core.util.EMFUtil; > import org.eclipse.hyades.test.ui.internal.navigator.proxy.FileProxyManager; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.FileProxyNodeCache; > import org.eclipse.hyades.test.ui.navigator.IProxyNode; > import org.eclipse.hyades.ui.internal.provider.IResourceChangeUpdater; > import org.eclipse.jface.viewers.IStructuredSelection; >@@ -167,14 +169,12 @@ > addedObjects.add(affectedResources[i]); > } > } else { >- //- ask to the file proxy manager the proxy corresponding to this file >- IProxyNode convertedObject = TestNavigator.getFileProxyManager().getProxy((IFile)affectedResources[i], parent); >- if(convertedObject != null) { >- //- file has been converted into another object, insert ojbect instead of the file >- addedObjects.add(convertedObject); >- //- since we succeed to create a proxy from that file, we need to cache it. >- TestNavigator.getFileProxyManager().cacheProxy((IFile)affectedResources[i], convertedObject); >- } >+ // Don't bother computing the proxy here, since this may be long. >+ // Refresh the container so its children are re-computed and the added >+ // file gets discovered (the discovery will happen in a background job, >+ // which is much better). >+ IContainer container = affectedResources[i].getParent(); >+ changedObjects.add(container); > } > } > } else { >@@ -205,7 +205,7 @@ > //- in case of file removed, we need to find the right corresponding element in the test navigator > //- try to retrieve a proxy from this file > //- the object to remove from the navigator is the proxy >- IProxyNode proxy = TestNavigator.getFileProxyManager().getProxy((IFile)affectedResources[i], null); >+ IProxyNode proxy = FileProxyNodeCache.getInstance().getCachedProxy((IFile)affectedResources[i]); > if(proxy != null) { > removedObjects.add(proxy); > } >Index: src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigator.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigator.java,v >retrieving revision 1.26 >diff -u -r1.26 TestNavigator.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigator.java 1 Sep 2006 14:03:54 -0000 1.26 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigator.java 16 Oct 2006 16:45:23 -0000 >@@ -23,6 +23,7 @@ > import org.eclipse.core.resources.ResourcesPlugin; > import org.eclipse.core.runtime.IAdaptable; > import org.eclipse.core.runtime.Path; >+import org.eclipse.core.runtime.Platform; > import org.eclipse.emf.common.util.URI; > import org.eclipse.emf.ecore.EObject; > import org.eclipse.emf.ecore.resource.Resource; >@@ -40,9 +41,9 @@ > import org.eclipse.hyades.test.ui.internal.navigator.proxy.FileProxyManager; > import org.eclipse.hyades.test.ui.internal.navigator.proxy.FileProxyNodeCache; > import org.eclipse.hyades.test.ui.internal.navigator.proxy.TestAssetGroupProxyManager; >-import org.eclipse.hyades.test.ui.internal.navigator.proxy.TestNavigatorRefresher; > import org.eclipse.hyades.test.ui.internal.navigator.proxy.TypeProviderManager; > import org.eclipse.hyades.test.ui.internal.util.ContextIds; >+import org.eclipse.hyades.test.ui.internal.util.FixedSizeJobPool; > import org.eclipse.hyades.test.ui.navigator.CMNNamedElementProxyNode; > import org.eclipse.hyades.test.ui.navigator.EObjectProxyNode; > import org.eclipse.hyades.test.ui.navigator.FileProxyNode; >@@ -110,6 +111,12 @@ > > public static final int VIEW_ID_LOGICAL = 1; > >+ /** >+ * The size of the background job pool. This is the maximal number of background >+ * jobs that can run at the same time. >+ */ >+ public static final int BACKGROUND_JOB_POOL_SIZE = 3; >+ > private int currentViewIndex; > > /** >@@ -149,8 +156,8 @@ > /** actions to switch between both logical and resource views. */ > private ToggleViewAction[] viewActions; > >- /** Label and content provider for both logical and resource views. */ >- private TestNavigatorProvider[] providers; >+ /** Current content and label provider. */ >+ private TestNavigatorProvider currentProvider; > > // - constants are used in the IDialogSettings > protected final static String SET_SHOW_FOLDERS = "SHOW_FOLDERS"; //$NON-NLS-1$ >@@ -164,7 +171,7 @@ > protected final static int CP_FOLDER = 0; > > protected final static int CP_LOGICAL = 1; >- >+ > private List rootLogicalFolders; > > private boolean showingFolders = true; >@@ -172,7 +179,9 @@ > private boolean showingEObjectChildren = true; > > private ResourceChangeUpdaterProvider resourceChangeUpdaterProvider; >- >+ >+ private FixedSizeJobPool jobPool; >+ > /** > * Constructor for TestNavigator > */ >@@ -180,7 +189,6 @@ > super(ITestNavigator.ID); > > viewActions = new ToggleViewAction[] { new ToggleViewAction(this, VIEW_ID_RESOURCE), new ToggleViewAction(this, VIEW_ID_LOGICAL) }; >- providers = new TestNavigatorProvider[] { new ResourceTestNavigatorProvider(), new LogicalTestNavigatorProvider() }; > } > > /** >@@ -263,13 +271,21 @@ > /** > * @return Returns the typeProviderProxyManager. > */ >- public static TypeProviderManager getTypeProviderManager() { >+ public synchronized static TypeProviderManager getTypeProviderManager() { > if (typeProviderManager == null) { > typeProviderManager = new TypeProviderManager(getTypeProviderContext()); > } > return typeProviderManager; > } > >+ private static class AllInstancesRefresher implements IProxyNodeListener { >+ public void nodeChanged(Object node) { >+ for(Iterator it = TestNavigator.getAllInstancesIterator(); it.hasNext();) { >+ ((TestNavigator)it.next()).nodeChanged(node); >+ } >+ } >+ } >+ > /** > * This class is responsible to give the correct context to the used ITypeProvider (DefaultTypeProvider). > * It stores the file proxy manager of the logical view to be used by the ITypeProvider, >@@ -283,7 +299,7 @@ > } > public IProxyNodeListener getProxyNodeListener() { > if (refresher == null) { >- refresher = new TestNavigatorRefresher(); >+ refresher = new AllInstancesRefresher(); > } > return refresher; > } >@@ -299,9 +315,9 @@ > return typeProviderContext; > } > >- public static TestAssetGroupProxyManager getTestAssetGroupProxyManager() { >+ public synchronized static TestAssetGroupProxyManager getTestAssetGroupProxyManager() { > if (testAssetGroupProxyManager == null) { >- testAssetGroupProxyManager = new TestAssetGroupProxyManager(); >+ testAssetGroupProxyManager = new TestAssetGroupProxyManager(getTypeProviderContext()); > } > return testAssetGroupProxyManager; > } >@@ -310,6 +326,15 @@ > * @see org.eclipse.ui.IWorkbenchPart#dispose() > */ > public void dispose() { >+ if (jobPool != null) { >+ // Disposing the job pool cancels all pending jobs that have net been yet >+ // scheduled. >+ jobPool.dispose(); >+ } >+ // Cancel all "TestNavigatorJob"s, i.e. jobs that belongs the "family" represented by >+ // this instance. This cancels all jobs that have already been scheduled. >+ Platform.getJobManager().cancel(this); >+ > if (rootLogicalFolders != null) > rootLogicalFolders.clear(); > removeTestNavigator(this); >@@ -319,13 +344,6 @@ > resourceChangeUpdaterProvider.dispose(); > resourceChangeUpdaterProvider = null; > >- for (int i = 0; i < providers.length; i++) { >- if(providers[i] != null){ >- providers[i].dispose(); >- providers[i] = null; >- } >- } >- > if(testAssetGroupProxyManager != null){ > testAssetGroupProxyManager.dispose(); > testAssetGroupProxyManager=null; >@@ -362,7 +380,17 @@ > addTestNavigator(this); > } > >- /** >+ private void adjustCurrentProviderContext(boolean isLoading) { >+ if (currentProvider != null) { >+ if (isLoading) { >+ currentProvider.setContext(TestNavigatorProvider.CONTEXT_LOADING); >+ } else { >+ currentProvider.setContext(TestNavigatorProvider.CONTEXT_INTERACTIVE); >+ } >+ } >+ } >+ >+ /** > * Returns the file associated to a given object that is located in this > * navigator. > * >@@ -496,7 +524,7 @@ > }; > treeViewer.addFilter(viewerFilter); > >- resourceChangeUpdaterProvider = new ResourceChangeUpdaterProvider.UIUpdaterProvider(); >+ resourceChangeUpdaterProvider = new ResourceChangeUpdaterProvider.UIUpdaterProvider(false); > FileProxyNodeCache.getInstance().addResourceListener(resourceChangeUpdaterProvider); > IResourceChangeUpdater resourceChangeUpdater = new TestResourceChangeUpdater(this); > resourceChangeUpdaterProvider.setResourceChangeUpdater(resourceChangeUpdater); >@@ -508,9 +536,17 @@ > * @param treeViewer > */ > private void updateTestNavigatorProvider(TreeViewer treeViewer) { >- treeViewer.setContentProvider(providers[currentViewIndex]); >+ if (currentViewIndex == VIEW_ID_RESOURCE) { >+ currentProvider = new ResourceTestNavigatorProvider(this); >+ } else { >+ currentProvider = new LogicalTestNavigatorProvider(this); >+ } >+ adjustCurrentProviderContext(true); >+ treeViewer.setContentProvider(currentProvider); > ILabelDecorator decorator = PlatformUI.getWorkbench().getDecoratorManager().getLabelDecorator(); >- treeViewer.setLabelProvider(new TestDecoratingLabelProvider(providers[currentViewIndex], decorator, this)); >+ ILabelProvider labelProvider = new TestDecoratingLabelProvider(currentProvider, decorator, this); >+ treeViewer.setLabelProvider(labelProvider); >+ adjustCurrentProviderContext(false); > } > > /** >@@ -524,21 +560,8 @@ > if (input instanceof IFileEditorInput) { > IFileEditorInput fileInput = (IFileEditorInput) input; > IFile file = fileInput.getFile(); >- >- Resource resource = EMFUtil.getResource(null, file); >- if ((resource != null) && (!resource.getContents().isEmpty())) { >- IStructuredSelection structuredSelection = getStructuredSelection(); >- if (structuredSelection.size() == 1) { >- Object currentSelection = structuredSelection.getFirstElement(); >- if (currentSelection instanceof EObject) { >- if (((EObject) currentSelection).eResource() == resource) >- return true; >- } >- } >- >- selectReveal(new StructuredSelection(resource.getContents().get(0))); >- return true; >- } >+ selectReveal(new StructuredSelection(file)); >+ return true; > } > > return false; >@@ -962,10 +985,23 @@ > } > } > >+ /** >+ * Invoked by test providers to notify that a node and its children should be refreshed. >+ */ > public void nodeChanged(Object node) { >- Display.getDefault().asyncExec(new Refresher(node)); >+ currentProvider.getProxyNodeListener().nodeChanged(node); >+ refresh(node); > } >- >+ >+ /** >+ * Internal method used by the provider to refresh a node and its sub-nodes. The difference >+ * with nodeChanged(Object) is that this method does not notify the provider with the change. >+ * @param node >+ */ >+ /*package*/void refresh(Object node) { >+ Display.getDefault().asyncExec(new Refresher(node)); >+ } >+ > /** > * @return > */ >@@ -1008,4 +1044,11 @@ > return "[Invalid Descriptor]"; //$NON-NLS-1$ > } > } >+ >+ public FixedSizeJobPool getJobPool() { >+ if (jobPool == null) { >+ jobPool = new FixedSizeJobPool(BACKGROUND_JOB_POOL_SIZE); >+ } >+ return jobPool; >+ } > } >\ No newline at end of file >Index: src/org/eclipse/hyades/test/ui/internal/navigator/LogicalTestNavigatorProvider.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/LogicalTestNavigatorProvider.java,v >retrieving revision 1.7 >diff -u -r1.7 LogicalTestNavigatorProvider.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/LogicalTestNavigatorProvider.java 1 Sep 2006 14:03:54 -0000 1.7 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/LogicalTestNavigatorProvider.java 16 Oct 2006 16:45:23 -0000 >@@ -11,20 +11,29 @@ > *******************************************************************************/ > package org.eclipse.hyades.test.ui.internal.navigator; > >+import java.util.ArrayList; >+import java.util.Collection; >+import java.util.HashMap; > import java.util.Iterator; >-import java.util.LinkedList; > import java.util.List; >+import java.util.Map; > > import org.eclipse.core.resources.IProject; >+import org.eclipse.core.resources.IResource; > import org.eclipse.hyades.test.ui.TestUIExtension; > import org.eclipse.hyades.test.ui.internal.navigator.proxy.FileProxyManager; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.async.IProxiesRequestListener; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.async.LogicalProjectProxiesRequest; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.async.ProxiesRequest; > import org.eclipse.hyades.test.ui.navigator.IFileProxyManager; > import org.eclipse.hyades.test.ui.navigator.IProxyNode; >-import org.eclipse.hyades.test.ui.navigator.ITypeProviderProxyNode; >+import org.eclipse.hyades.test.ui.navigator.IProxyNodeListener; > import org.eclipse.hyades.ui.extension.IAssociationConstants; > import org.eclipse.hyades.ui.extension.IAssociationDescriptor; > import org.eclipse.hyades.ui.extension.IAssociationMapping; > import org.eclipse.hyades.ui.internal.extension.AssociationMappingRegistry; >+import org.eclipse.hyades.ui.util.IDisposable; >+import org.eclipse.swt.graphics.Image; > > /** This is the provider of the logical test navigator. > * @author jgout >@@ -35,6 +44,8 @@ > /** The file proxy manager to acces to proxies from files */ > private static FileProxyManager fileProxyManager = new FileProxyManager(); > >+ private ProxiesRequests requests = new ProxiesRequests(); >+ > /** > * @return Returns the fileProxyManager. > */ >@@ -42,6 +53,10 @@ > return fileProxyManager; > } > >+ public LogicalTestNavigatorProvider(TestNavigator testNavigator) { >+ super(testNavigator); >+ } >+ > public Object getParent(Object element) { > Object parent = super.getParent(element); > if (parent instanceof FileProxyManager.IUnboundedParent) { >@@ -63,34 +78,55 @@ > } > > public Object[] getChildren(Object parentElement) { >- if(parentElement instanceof IProject && ((IProject)parentElement).isOpen()) { >- //- for the given project we need to build all the type provider proxy node trees. >- List providers = getTypeProviders((IProject)parentElement); >- //- append all test asset groups found in this project >- List groups = TestNavigator.getTestAssetGroupProxyManager().getTestAssetGroups((IProject)parentElement); >- return mergeChildren(providers, groups); >+ if(parentElement instanceof IProject) { >+ IProject project = (IProject)parentElement; >+ if (project.isAccessible()) { >+ Collection types = getTypes(); >+ Collection extensions = getExtensions(); >+ ArrayList ret = new ArrayList(types.size() + extensions.size()); >+ LogicalProjectProxiesRequest request = requests.getRequest(project, types, extensions); >+ for (Iterator it = types.iterator(); it.hasNext();) { >+ String type = (String) it.next(); >+ IProxyNode proxy = request.getProxy(LogicalProjectProxiesRequest.TYPE_PROVIDER_PREFIX + type); >+ if (proxy != null) { >+ ret.add(proxy); >+ } >+ } >+ for (Iterator it = extensions.iterator(); it.hasNext();) { >+ String ext = (String) it.next(); >+ IProxyNode proxy = request.getProxy(LogicalProjectProxiesRequest.TEST_ASSET_EXTENSION_PREFIX + ext); >+ if (proxy != null) { >+ ret.add(proxy); >+ } >+ } >+ if (request.isPending()) { >+ ret.add(0, new PendingProxy(project)); >+ } >+ return ret.toArray(); >+ } >+ return new Object[0]; > } > return super.getChildren(parentElement); > } > >- private List getTypeProviders(IProject project) { >- List typeProviders = new LinkedList(); >- //- for all defined test suite types, call the type provider factory >+ private Collection getTypes() { > AssociationMappingRegistry registry = (AssociationMappingRegistry)TestUIExtension.getTestSuiteMappingRegistry(); > IAssociationMapping associationMapping = registry.getAssociationMapping(IAssociationConstants.EP_TYPE_DESCRIPTIONS); > String[] types = associationMapping.getTypes(); >+ List typeProviders = new ArrayList(types.length); > for (int i = 0; i < types.length; i++) { > IAssociationDescriptor descriptor = associationMapping.getDefaultAssociationDescriptor(types[i]); > if (descriptor != null) { >- ITypeProviderProxyNode proxy = TestNavigator.getTypeProviderManager().getTypeProviderProxyNode(project, types[i]); >- if(proxy != null) { >- typeProviders.add(proxy); >- } >+ typeProviders.add(types[i]); > } > } > return typeProviders; > } >- >+ >+ private Collection getExtensions() { >+ return TestNavigator.getTestAssetGroupProxyManager().getExtensions(); >+ } >+ > private Object[] mergeChildren(List providers, List groups) { > Object[] children = new Object[providers.size()+groups.size()]; > int i = 0; >@@ -102,6 +138,126 @@ > } > return children; > } >+ >+ public IProxyNodeListener getProxyNodeListener() { >+ return requests; >+ } >+ >+ public void dispose() { >+ requests.dispose(); >+ super.dispose(); >+ } >+ >+ class ProxiesRequests implements IProxiesRequestListener, IProxyNodeListener, IDisposable { >+ >+ private Map projectToRequestMap = new HashMap(); >+ >+ public LogicalProjectProxiesRequest getRequest(IProject project, Collection types, Collection extensions) { >+ LogicalProjectProxiesRequest req = (LogicalProjectProxiesRequest)projectToRequestMap.get(project); >+ if (req == null) { >+ ArrayList requests = new ArrayList(types.size() + extensions.size()); >+ for(Iterator it = types.iterator(); it.hasNext(); ) { >+ requests.add(LogicalProjectProxiesRequest.TYPE_PROVIDER_PREFIX + (String)it.next()); >+ } >+ for(Iterator it = extensions.iterator(); it.hasNext(); ) { >+ requests.add(LogicalProjectProxiesRequest.TEST_ASSET_EXTENSION_PREFIX + (String)it.next()); >+ } >+ req = new LogicalProjectProxiesRequest(requests, TestNavigator.getTypeProviderManager(), TestNavigator.getTestAssetGroupProxyManager(), project, testNavigator); >+ req.setPriority(getJobPriority()); >+ testNavigator.getJobPool().scheduleJob(req); >+ if (!req.wait(getResponseTime(), this, 2000)) { >+ projectToRequestMap.put(project, req); >+ } >+ } >+ return req; >+ } >+ >+ public void computationCompleted(ProxiesRequest request) { >+ IProject project = ((LogicalProjectProxiesRequest)request).getProject(); >+ if (projectToRequestMap.containsKey(project)) { >+ // A last refresh is necessary to remove the "Pending..." node. >+ testNavigator.refresh(project); >+ } >+ } >+ >+ public void proxiesComputed(ProxiesRequest request) { >+ IProject project = ((LogicalProjectProxiesRequest)request).getProject(); >+ testNavigator.refresh(project); >+ } > >+ public void proxyComputed(ProxiesRequest request, Object key) { >+ } >+ >+ public void nodeChanged(Object node) { >+ if (node instanceof IProject) { >+ LogicalProjectProxiesRequest req = (LogicalProjectProxiesRequest) projectToRequestMap.get(node); >+ if (req != null) { >+ // Then we need to cancel the current request. A new one will be spawned >+ // when getChildren() is invoked on this project. >+ if (req.cancel(1000)) { >+ projectToRequestMap.remove(node); >+ testNavigator.refresh(node); >+ } >+ } >+ } >+ } >+ >+ public void computationCancelled(ProxiesRequest request) { >+ IProject project = ((LogicalProjectProxiesRequest)request).getProject(); >+ projectToRequestMap.remove(project); >+ testNavigator.refresh(project); >+ } >+ >+ public void dispose() { >+ // Cancel all running requests. Note that a LogicalProjectProxiesRequest may take >+ // considerable time before it can honor the cancel request. So in general the >+ // request may be still running for a long time after this instance has been >+ // disposed. >+ // If the user switches from the logical view to the resource view, and then back >+ // to the logical view, this provider is disposed, and then another instance gets >+ // created. As a result, two requests for the same project may be running: the old >+ // one, which has been cancelled but has not stopped yet, and the new one. This >+ // will look as if two jobs are doing the same thing at the same time. However what >+ // really happens is that the new job is blocked on a wait until the old request >+ // completes, and then the new job automatically leverages the computation performed >+ // by the old one, so there is no CPU waste. The only drawback is that the new job >+ // occupies a slot in the Test navigator job pool. >+ for (Iterator it = projectToRequestMap.values().iterator(); it.hasNext();) { >+ ProxiesRequest request = (ProxiesRequest) it.next(); >+ request.dispose(); >+ it.remove(); >+ } >+ } >+ >+ } >+ >+ private static class PendingProxy implements IProxyNode { >+ public PendingProxy(Object parent) { >+ this.parent = parent; >+ } >+ private Object parent; >+ private static IProxyNode[] NO_CHILDREN = new IProxyNode[0]; >+ public IProxyNode[] getChildren() { >+ return NO_CHILDREN; >+ } >+ public Image getImage() { >+ return null; >+ } >+ public Object getParent() { >+ return parent; >+ } >+ public String getText() { >+ return TestNavigatorMessages.NODE_PENDING; >+ } >+ public Object getAdapter(Class adapter) { >+ return null; >+ } >+ public String getIdentifier() { >+ return "~"; //$NON-NLS-1$ >+ } >+ public IResource getUnderlyingResource() { >+ return null; >+ } >+ } > > } >Index: src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigatorMessages.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigatorMessages.java,v >retrieving revision 1.7 >diff -u -r1.7 TestNavigatorMessages.java >--- src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigatorMessages.java 10 Aug 2006 15:19:23 -0000 1.7 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/TestNavigatorMessages.java 16 Oct 2006 16:45:23 -0000 >@@ -26,6 +26,7 @@ > > public static String TEST_NAVIGATOR_UNNAMED_ELEMENT; > public static String PROXY_LOADING_ERROR; >+ public static String NODE_PENDING; > public static String OpenWithActionGroup_ActionLabel; > public static String FileFolderInContainerPaste_NameTwoArg; > public static String FileFolderInContainerPaste_NameOneArg; >@@ -35,4 +36,9 @@ > public static String FileFolderInContainerPaste_MessageLabel; > public static String TestNavigatorActionGroup_ToggleAction_Text; > public static String RenameAction_ActionName; >+ public static String PM_INDEXING_TYPE; >+ public static String PM_INDEXING_ASSET_GROUP; >+ public static String PM_EXPLORING_PROJECT; >+ public static String PM_EXPLORING_FOLDER; >+ public static String PM_INDEXING_FILE; > } >Index: src/org/eclipse/hyades/test/ui/navigator/ITypeProvider.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.ui/src/org/eclipse/hyades/test/ui/navigator/ITypeProvider.java,v >retrieving revision 1.4 >diff -u -r1.4 ITypeProvider.java >--- src/org/eclipse/hyades/test/ui/navigator/ITypeProvider.java 19 May 2006 17:16:12 -0000 1.4 >+++ src/org/eclipse/hyades/test/ui/navigator/ITypeProvider.java 16 Oct 2006 16:45:24 -0000 >@@ -12,12 +12,18 @@ > package org.eclipse.hyades.test.ui.navigator; > > import org.eclipse.core.resources.IProject; >+import org.eclipse.hyades.ui.util.IDisposable; > > /** >- * Type providers are responsible to collect and organize all elements of a given type >- * located in a project. The returned node is shown in the logical view of the test navigator. >- * Implementors are responsible to manage the proxy nodes produced as they want >- * (default implementation uses a cache to increase performance). >+ * Type providers are responsible to collect and organize all elements of a given type >+ * located in a project. The returned node is shown in the logical view of the test navigator. >+ * The returned proxy nodes lifecyle is under the type provider responsibility. If the type provider >+ * implements the {@link IDisposable} interface, the {@link IDisposable#dispose()} will >+ * be invoked when the provider is no longer necessary. >+ * From a performance perspective, it is better for a type provider implementation to cache >+ * its returned values, unless their computing is trivial. >+ * Type providers also have the responsibility of providing updates of their content by >+ * using the provided context's {@link IProxyNodeListener}. > * > * @author jgout > * @since 4.0 >@@ -25,17 +31,21 @@ > public interface ITypeProvider /*extends IDisposable*/ { > > /** >- * Make some initialization for the type provider. >- * @param context this parameter contains all inputs necessary to initialize the type provider. >- * For instance, a file proxy manager is set. >+ * Initializes the type provider with a context. >+ * @param context The context in which the type provider will be used. The context >+ * provides various tools and information for the provider to interact with its >+ * context. > */ > public void init(ITypeProviderContext context); > >- /** Returns a proxy node hierarchy based of the given type from elements located in the given project. >+ /** >+ * Returns a proxy node hierarchy based of the given type from elements located in the given project. > * The returned hierarchy will appear as a special type provider node directly under the project. >+ * The implementation should not assume anything about the thread it will run in. This method >+ * may be invoked from any thread, and concurrent calls to this method may happen. However >+ * there will never be two concurrent calls for the same project. > * @param project the owner of the returned hierarchy. > * @param type the type of elements that type provider is interested in. >- * > * @return a proxy node tree that represents all elements of the given type contained by the given project. > */ > public ITypeProviderProxyNode get(IProject project, String type); >Index: src/org/eclipse/hyades/test/ui/internal/util/FixedSizeJobPool.java >=================================================================== >RCS file: src/org/eclipse/hyades/test/ui/internal/util/FixedSizeJobPool.java >diff -N src/org/eclipse/hyades/test/ui/internal/util/FixedSizeJobPool.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/hyades/test/ui/internal/util/FixedSizeJobPool.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,73 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 IBM Corporation and others. >+ * 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 >+ * $Id: $ >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+ >+package org.eclipse.hyades.test.ui.internal.util; >+ >+import java.util.Collections; >+import java.util.LinkedList; >+import java.util.List; >+ >+import org.eclipse.core.runtime.jobs.IJobChangeEvent; >+import org.eclipse.core.runtime.jobs.IJobChangeListener; >+import org.eclipse.core.runtime.jobs.Job; >+import org.eclipse.core.runtime.jobs.JobChangeAdapter; >+import org.eclipse.hyades.ui.util.IDisposable; >+ >+public class FixedSizeJobPool implements IDisposable { >+ >+ private int maxJobs; >+ private int runningJobs = 0; >+ private List queue = Collections.synchronizedList(new LinkedList()); >+ private Object lock = new Object(); >+ private boolean disposed; >+ >+ public FixedSizeJobPool(int maxJobs) { >+ this.maxJobs = maxJobs; >+ } >+ >+ public void scheduleJob(Job job) { >+ queue.add(job); >+ synchronized(lock) { >+ if (runningJobs < maxJobs) { >+ doScheduleJob(); >+ } >+ } >+ } >+ >+ private void doScheduleJob() { >+ if (disposed) return; >+ if (!queue.isEmpty()) { >+ Job job = (Job)queue.remove(0); >+ job.addJobChangeListener(jobListener); >+ runningJobs++; >+ job.schedule(); >+ } >+ } >+ >+ private IJobChangeListener jobListener = new JobChangeAdapter() { >+ >+ public void done(IJobChangeEvent event) { >+ if (event.getResult() != null) { >+ synchronized(lock) { >+ runningJobs--; >+ doScheduleJob(); >+ } >+ } >+ } >+ >+ }; >+ >+ public void dispose() { >+ disposed = true; >+ } >+ >+} >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/SynchronizedAccess.java >=================================================================== >RCS file: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/SynchronizedAccess.java >diff -N src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/SynchronizedAccess.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/SynchronizedAccess.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,58 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 IBM Corporation and others. >+ * 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 >+ * $Id: $ >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+ >+package org.eclipse.hyades.test.ui.internal.navigator.proxy.async; >+ >+import java.util.ArrayList; >+import java.util.Collection; >+import java.util.Collections; >+ >+import org.eclipse.hyades.test.ui.internal.navigator.TestNavigator; >+ >+/** >+ * A general purpose synchronizer that allows only one instance to access a given resource. >+ * This synchronizer is mainly useful in multi-threaded contexts where one thread needs >+ * exclusive access to a resource. >+ * @author jcanches >+ * @since 4.3 >+ */ >+public class SynchronizedAccess implements ISynchronizedAccess { >+ >+ private Collection locks = Collections.synchronizedList(new ArrayList(TestNavigator.BACKGROUND_JOB_POOL_SIZE + 1)); >+ >+ /* (non-Javadoc) >+ * @see org.eclipse.hyades.test.ui.internal.navigator.proxy.async.ISynchronizedAccess#acquireLock(java.lang.Object) >+ */ >+ public boolean acquireLock(Object resource) { >+ synchronized(locks) { >+ while (locks.contains(resource)) { >+ try { >+ locks.wait(); >+ } catch (InterruptedException e) { >+ return false; >+ } >+ } >+ locks.add(resource); >+ return true; >+ } >+ } >+ /* (non-Javadoc) >+ * @see org.eclipse.hyades.test.ui.internal.navigator.proxy.async.ISynchronizedAccess#releaseLock(java.lang.Object) >+ */ >+ public void releaseLock(Object resource) { >+ synchronized(locks) { >+ locks.remove(resource); >+ locks.notify(); >+ } >+ } >+ >+} >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/IProxiesRequestListener.java >=================================================================== >RCS file: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/IProxiesRequestListener.java >diff -N src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/IProxiesRequestListener.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/IProxiesRequestListener.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,52 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 IBM Corporation and others. >+ * 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 >+ * $Id: $ >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+ >+package org.eclipse.hyades.test.ui.internal.navigator.proxy.async; >+ >+/** >+ * Listener of ProxiesRequest. This listener is notified of various events that occur in >+ * the lifecycle of ProxiesRequest instances. >+ * @author jcanches >+ * @since 4.3 >+ */ >+public interface IProxiesRequestListener { >+ >+ /** >+ * Indicates that a proxy has been computed. >+ * @param request The request that was emitted and from which this event is sent. >+ * @param key The key whose proxy was computed. >+ */ >+ void proxyComputed(ProxiesRequest request, Object key); >+ >+ /** >+ * Indicates that at least one proxy has been computed since the last call to this method, >+ * or since {@link ProxiesRequest#wait(int, IProxyRequestListener, int)} has been called if >+ * this method has never been called before. This kind of notification is guaranted not to >+ * occur more often than the specified notification interval specified in the wait method, >+ * unless there are no more proxies to compute, in this case the notification occurs as soon >+ * as the last proxy is computed. >+ */ >+ void proxiesComputed(ProxiesRequest request); >+ >+ /** >+ * Indicates that the request has been completed. >+ * @param request The request that was emitted and which is now complete. >+ */ >+ void computationCompleted(ProxiesRequest request); >+ >+ /** >+ * Indicates that the request has been cancelled. >+ * @param request The request that was emitted and then cancelled. >+ */ >+ void computationCancelled(ProxiesRequest request); >+ >+} >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/TestNavigatorJob.java >=================================================================== >RCS file: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/TestNavigatorJob.java >diff -N src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/TestNavigatorJob.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/TestNavigatorJob.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,43 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 IBM Corporation and others. >+ * 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 >+ * $Id: $ >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+ >+package org.eclipse.hyades.test.ui.internal.navigator.proxy.async; >+ >+import org.eclipse.core.runtime.jobs.Job; >+import org.eclipse.hyades.test.ui.internal.navigator.TestNavigator; >+ >+/** >+ * Abstract job that belongs to a {@link TestNavigator} instance family. When disposed, >+ * a test navigator cancels all jobs that belongs to its family. >+ * @author jcanches >+ * @since 4.3 >+ */ >+public abstract class TestNavigatorJob extends Job { >+ >+ private TestNavigator testNavigator; >+ >+ /** >+ * Constructs a job that belongs to the specified testNavigator. >+ * @param name Name of the job. >+ * @param testNavigator Instance of the test navigator that this job is a member of. >+ */ >+ protected TestNavigatorJob(String name, TestNavigator testNavigator) { >+ super(name); >+ this.testNavigator = testNavigator; >+ } >+ >+ public boolean belongsTo(Object family) { >+ if (testNavigator.equals(family)) return true; >+ return super.belongsTo(family); >+ } >+ >+} >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/ISynchronizedAccess.java >=================================================================== >RCS file: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/ISynchronizedAccess.java >diff -N src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/ISynchronizedAccess.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/ISynchronizedAccess.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,37 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 IBM Corporation and others. >+ * 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 >+ * $Id: $ >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+ >+package org.eclipse.hyades.test.ui.internal.navigator.proxy.async; >+ >+/** >+ * A synchronized access allows only one instance to access a given resource. >+ * The typical use is: >+ * <pre> >+ * try { >+ * if (access.acquireLock(resource)) { >+ * // Do something with the resource >+ * } >+ * } finally { >+ * access.releaseLock(resource); >+ * } >+ * </pre> >+ * Note that releaseLock must be called EVEN IF acquireLock failed. >+ * @author jcanches >+ * @since 4.3 >+ */ >+public interface ISynchronizedAccess { >+ >+ boolean acquireLock(Object resource); >+ >+ void releaseLock(Object resource); >+ >+} >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/JobSynchronizedAccess.java >=================================================================== >RCS file: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/JobSynchronizedAccess.java >diff -N src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/JobSynchronizedAccess.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/JobSynchronizedAccess.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,99 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 IBM Corporation and others. >+ * 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 >+ * $Id: $ >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+ >+package org.eclipse.hyades.test.ui.internal.navigator.proxy.async; >+ >+import java.util.ArrayList; >+import java.util.Collection; >+import java.util.Collections; >+import java.util.Iterator; >+ >+import org.eclipse.core.resources.ResourcesPlugin; >+import org.eclipse.core.runtime.NullProgressMonitor; >+import org.eclipse.core.runtime.Platform; >+import org.eclipse.core.runtime.jobs.ISchedulingRule; >+import org.eclipse.hyades.test.ui.internal.navigator.TestNavigator; >+ >+/** >+ * An implementation of ISynchronizedAccess specially optimized for running in jobs. >+ * The platform job manager is used to acquire and release locks, and a job waiting >+ * for lock acquisition may let another non-blocked job meanwhile. >+ * @author jcanches >+ */ >+public class JobSynchronizedAccess implements ISynchronizedAccess { >+ >+ /** >+ * The list of rules that this instance currently owns. Must be protected against concurrent >+ * access because two jobs may acquire/release a lock for two different resources at the >+ * same time. Use an array list as small as the maximum number of background jobs the >+ * test navigator may launch, plus one (the UI thread), since there should be not more >+ * than this number of threads acquiring a lock at any time. >+ */ >+ private Collection rules = Collections.synchronizedList(new ArrayList(TestNavigator.BACKGROUND_JOB_POOL_SIZE + 1)); >+ >+ /** >+ * A rule that ensures exclusive access to a given resource, when it has the same owner. >+ * In other words: a given owner can only have one job running within a ResourceRule >+ * block for a given resource. >+ * @author jcanches >+ */ >+ private static class ResourceRule implements ISchedulingRule { >+ >+ private JobSynchronizedAccess owner; >+ private Object resource; >+ >+ public ResourceRule(JobSynchronizedAccess owner, Object resource) { >+ this.owner = owner; >+ this.resource = resource; >+ } >+ >+ public boolean contains(ISchedulingRule rule) { >+ if (rule == this) return true; >+ // Any rule than can be contained in the workspace rule is also accepted >+ return ResourcesPlugin.getWorkspace().getRoot().contains(rule); >+ } >+ >+ public boolean isConflicting(ISchedulingRule rule) { >+ if (rule instanceof ResourceRule) { >+ ResourceRule oRule = (ResourceRule) rule; >+ return this.owner == oRule.owner && this.resource.equals(oRule.resource); >+ } >+ return false; >+ } >+ } >+ >+ public boolean acquireLock(Object resource) { >+ ResourceRule rule = new ResourceRule(this, resource); >+ Platform.getJobManager().beginRule(rule, new NullProgressMonitor()); >+ rules.add(rule); >+ return true; >+ } >+ >+ private ResourceRule removeRule(Object resource) { >+ for (Iterator it = rules.iterator(); it.hasNext();) { >+ ResourceRule rule = (ResourceRule) it.next(); >+ if (rule.resource.equals(resource)) { >+ it.remove(); >+ return rule; >+ } >+ } >+ return null; >+ } >+ >+ public void releaseLock(Object resource) { >+ ResourceRule rule = removeRule(resource); >+ if (rule != null) { >+ Platform.getJobManager().endRule(rule); >+ } >+ } >+ >+} >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/FileProxiesRequest.java >=================================================================== >RCS file: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/FileProxiesRequest.java >diff -N src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/FileProxiesRequest.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/FileProxiesRequest.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,119 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 IBM Corporation and others. >+ * 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 >+ * $Id: $ >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+ >+package org.eclipse.hyades.test.ui.internal.navigator.proxy.async; >+ >+import java.util.Collection; >+ >+import org.eclipse.core.resources.IContainer; >+import org.eclipse.core.resources.IFile; >+import org.eclipse.core.resources.IResource; >+import org.eclipse.hyades.test.ui.internal.navigator.TestNavigator; >+import org.eclipse.hyades.test.ui.internal.navigator.TestNavigatorMessages; >+import org.eclipse.hyades.test.ui.navigator.IFileProxyManager; >+import org.eclipse.hyades.test.ui.navigator.IProxyNode; >+import org.eclipse.osgi.util.NLS; >+import org.eclipse.swt.graphics.Image; >+ >+/** >+ * A ProxiesRequest that performs the long-running computation of proxy nodes for a >+ * collection of files, using a FileProxyManager. >+ * @author jcanches >+ * @since 4.3 >+ */ >+public class FileProxiesRequest extends ProxiesRequest { >+ >+ private IFileProxyManager fileProxyManager; >+ private IContainer parent; >+ >+ /** >+ * Constructs a new request. >+ * @param files The list of files for which proxy nodes must be computed. >+ * @param fileProxyManager The FileProxyManager used to compute the proxies. >+ * @param parent The common parent of all returned proxies. >+ */ >+ public FileProxiesRequest(Collection files, IFileProxyManager fileProxyManager, IContainer parent, TestNavigator testNavigator) { >+ super(NLS.bind(TestNavigatorMessages.PM_EXPLORING_FOLDER, parent.getFullPath().toString()), files, testNavigator); >+ this.fileProxyManager = fileProxyManager; >+ this.parent = parent; >+ //this.setRule(parent); >+ } >+ >+ /** >+ * Returns the common parent of all computed proxies. >+ * @return the common parent of all computed proxies. >+ */ >+ public IContainer getParent() { >+ return parent; >+ } >+ >+ protected IProxyNode computeProxy(Object key) { >+ return fileProxyManager.getProxy((IFile)key, parent); >+ } >+ >+ protected IProxyNode getPlaceHolder(Object key) { >+ return new TemporaryProxy((IFile)key, parent); >+ } >+ >+ protected String getTaskName() { >+ return NLS.bind(TestNavigatorMessages.PM_EXPLORING_FOLDER, parent.getFullPath().toString()); >+ } >+ >+ protected String getSubTaskName(Object key) { >+ return NLS.bind(TestNavigatorMessages.PM_INDEXING_FILE, ((IFile)key).getName()); >+ } >+ >+ private static class TemporaryProxy implements IProxyNode { >+ >+ private IFile file; >+ private Object parent; >+ >+ public TemporaryProxy(IFile file, Object parent) { >+ this.file = file; >+ this.parent = parent; >+ } >+ >+ public IProxyNode[] getChildren() { >+ return new IProxyNode[0]; >+ } >+ >+ public Image getImage() { >+ // TODO Auto-generated method stub >+ return null; >+ } >+ >+ public Object getParent() { >+ return parent; >+ } >+ >+ public String getText() { >+ return file.getName(); >+ } >+ >+ public Object getAdapter(Class adapter) { >+ if (adapter.isAssignableFrom(IFile.class)) { >+ return file; >+ } >+ return null; >+ } >+ >+ public String getIdentifier() { >+ return "#"; //$NON-NLS-1$ >+ } >+ >+ public IResource getUnderlyingResource() { >+ return file; >+ } >+ >+ } >+ >+} >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/ProxiesRequest.java >=================================================================== >RCS file: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/ProxiesRequest.java >diff -N src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/ProxiesRequest.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/ProxiesRequest.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,237 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 IBM Corporation and others. >+ * 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 >+ * $Id: $ >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+ >+package org.eclipse.hyades.test.ui.internal.navigator.proxy.async; >+ >+import java.util.ArrayList; >+import java.util.Collection; >+import java.util.Collections; >+import java.util.HashMap; >+import java.util.Iterator; >+import java.util.List; >+import java.util.Map; >+ >+import org.eclipse.core.runtime.IProgressMonitor; >+import org.eclipse.core.runtime.IStatus; >+import org.eclipse.core.runtime.OperationCanceledException; >+import org.eclipse.core.runtime.Status; >+import org.eclipse.hyades.test.ui.UiPlugin; >+import org.eclipse.hyades.test.ui.internal.navigator.TestNavigator; >+import org.eclipse.hyades.test.ui.navigator.IProxyNode; >+import org.eclipse.hyades.ui.util.IDisposable; >+ >+/** >+ * A proxies request is a job that performs the computation, for a list >+ * of keys, of a list of matching proxy nodes. Assuming that the proxies computation is >+ * a long-running operation, the request can be queried for results at any time, even if >+ * the result for the given key has not been computed yet. In this case, the request >+ * returns a placeholder proxy. >+ * The caller has the choice of waiting until the computation is completed, or not waiting >+ * and being notified when the computation progresses, or a mix of the two (i.e. wait for a >+ * limited time, then switch to a notification method). >+ * @author jcanches >+ * @since 4.3 >+ */ >+public abstract class ProxiesRequest extends TestNavigatorJob implements IDisposable { >+ >+ private IProxiesRequestListener listener; >+ private List requests; >+ private Map results = Collections.synchronizedMap(new HashMap()); >+ private boolean cancelled; >+ private long lastNotificationTime; >+ private long notificationInterval; >+ private boolean notificationNeeded; >+ private State state = new State(); >+ private boolean issueCancelNotification = false; >+ >+ protected ProxiesRequest(String name, Collection keys, TestNavigator testNavigator) { >+ super(name, testNavigator); >+ this.requests = new ArrayList(keys); >+ for (Iterator it = keys.iterator(); it.hasNext();) { >+ Object key = it.next(); >+ IProxyNode proxy = getPlaceHolder(key); >+ results.put(key, proxy); >+ } >+ } >+ >+ public IProxyNode getProxy(Object key) { >+ return (IProxyNode)results.get(key); >+ } >+ >+ /** >+ * Waits until this request is executed, or until the specified time-out is reached. >+ * @param timeOut A time, in milliseconds, that this method should not exceed. >+ * @param listener A listener that will be notified, if the request exceeds the time. >+ * @param notificationInterval The pace, in milliseconds, at which the method >+ * {@link IProxiesRequestListener#proxiesComputed(ProxiesRequest)} should be >+ * invoked. Only used if the request exceeds the time allocated. >+ * @return Whether the request could be completed in time or not. If not, the listener will >+ * be used to get asynchronous update of the state of the request. >+ * @throws OperationCanceledException If the method dispose() has already been called. >+ */ >+ public boolean wait(int timeOut, IProxiesRequestListener listener, int notificationInterval) throws OperationCanceledException { >+ if (cancelled) throw new OperationCanceledException(); >+ synchronized(state) { >+ if (state.getState() != State.COMPLETED) { >+ try { >+ state.wait(timeOut); >+ } catch (InterruptedException e) { >+ // OK >+ } >+ } >+ } >+ switch(state.getState()) { >+ case State.RUNNING: >+ case State.INITIALIZED: { >+ this.notificationInterval = notificationInterval; >+ this.listener = listener; >+ this.lastNotificationTime = System.currentTimeMillis(); >+ return false; >+ } >+ case State.COMPLETED: { >+ this.listener = listener; >+ fireNotification(state); >+ return true; >+ } >+ case State.CANCELLED: { >+ throw new OperationCanceledException(); >+ } >+ default: { >+ throw new RuntimeException("Illegal internal state"); //$NON-NLS-1$ >+ } >+ } >+ } >+ >+ public boolean isPending() { >+ int s = state.getState(); >+ return s == State.INITIALIZED || s == State.RUNNING; >+ } >+ >+ /** >+ * Performs the computation. This method will trigger notification once a listener >+ * is registered. This method should be run in a separate thread. >+ */ >+ public IStatus run(IProgressMonitor monitor) { >+ monitor.beginTask(getTaskName(), requests.size()); >+ synchronized(state) { >+ state.set(State.RUNNING); >+ } >+ Thread.currentThread().setPriority(Thread.MIN_PRIORITY + 2); >+ try { >+ for (Iterator it = requests.iterator(); !cancelled && it.hasNext();) { >+ Object key = it.next(); >+ monitor.subTask(getSubTaskName(key)); >+ _computeProxy(key); >+ if (monitor.isCanceled()) { >+ cancelled = true; >+ } else { >+ monitor.worked(1); >+ } >+ } >+ } finally { >+ synchronized(state) { >+ state.set(cancelled ? State.CANCELLED : State.COMPLETED); >+ fireNotification(state); >+ state.notifyAll(); >+ } >+ monitor.done(); >+ } >+ return new Status(IStatus.OK, UiPlugin.PLUGIN_ID, 0, "", null); //$NON-NLS-1$ >+ } >+ >+ private void _computeProxy(Object key) { >+ IProxyNode proxy = computeProxy(key); >+ results.put(key, proxy); >+ fireNotification(key); >+ } >+ >+ abstract protected IProxyNode getPlaceHolder(Object key); >+ >+ abstract protected IProxyNode computeProxy(Object key); >+ >+ abstract protected String getTaskName(); >+ >+ abstract protected String getSubTaskName(Object key); >+ >+ private void fireNotification(Object key) { >+ if (listener == null) return; >+ try { >+ if (key instanceof State) { >+ if (state.getState() == State.CANCELLED) { >+ if (issueCancelNotification) { >+ listener.computationCancelled(this); >+ } >+ } else { >+ if (notificationNeeded) { >+ listener.proxiesComputed(this); >+ } >+ listener.computationCompleted(this); >+ } >+ } else if (!cancelled) { >+ listener.proxyComputed(this, key); >+ long now = System.currentTimeMillis(); >+ if (lastNotificationTime + notificationInterval < now) { >+ listener.proxiesComputed(this); >+ notificationNeeded = false; >+ lastNotificationTime = now; >+ } else { >+ notificationNeeded = true; >+ } >+ } >+ } catch (Throwable t) { >+ UiPlugin.logError(t); >+ } >+ } >+ >+ public boolean cancel(int timeOut) { >+ cancelled = true; >+ // Wait a few seconds for the running thread to complete >+ synchronized(state) { >+ if (state.getState() == State.RUNNING) { >+ try { >+ state.wait(timeOut); >+ } catch (InterruptedException e) { >+ // OK >+ } >+ if (state.getState() == State.RUNNING) { >+ issueCancelNotification = true; >+ return false; >+ } >+ } >+ return true; >+ } >+ } >+ >+ public void dispose() { >+ cancel(1); >+ } >+ >+ private static class State { >+ >+ public final static int INITIALIZED = 0; >+ public final static int RUNNING = 1; >+ public final static int CANCELLED = 2; >+ public final static int COMPLETED = 3; >+ >+ private int state = INITIALIZED; >+ >+ public void set(int state) { >+ this.state = state; >+ } >+ >+ public int getState() { >+ return state; >+ } >+ >+ } >+ >+} >Index: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/LogicalProjectProxiesRequest.java >=================================================================== >RCS file: src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/LogicalProjectProxiesRequest.java >diff -N src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/LogicalProjectProxiesRequest.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/hyades/test/ui/internal/navigator/proxy/async/LogicalProjectProxiesRequest.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,83 @@ >+/******************************************************************************* >+ * Copyright (c) 2006 IBM Corporation and others. >+ * 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 >+ * $Id: $ >+ * >+ * Contributors: >+ * IBM Corporation - initial API and implementation >+ *******************************************************************************/ >+ >+package org.eclipse.hyades.test.ui.internal.navigator.proxy.async; >+ >+import java.util.Collection; >+ >+import org.eclipse.core.resources.IProject; >+import org.eclipse.hyades.test.ui.internal.navigator.TestNavigator; >+import org.eclipse.hyades.test.ui.internal.navigator.TestNavigatorMessages; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.ITestAssetGroupProxyNode; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.TestAssetGroupProxyManager; >+import org.eclipse.hyades.test.ui.internal.navigator.proxy.TypeProviderManager; >+import org.eclipse.hyades.test.ui.navigator.IProxyNode; >+import org.eclipse.hyades.test.ui.navigator.ITypeProviderProxyNode; >+import org.eclipse.osgi.util.NLS; >+ >+/** >+ * Request that computes the {@link ITypeProviderProxyNode}s and the {@link ITestAssetGroupProxyNode} >+ * of a project. A request is a job that can be run as a background job, and that provides >+ * additional events to the requester. >+ * @author jcanches >+ * @since 4.3 >+ */ >+public class LogicalProjectProxiesRequest extends ProxiesRequest { >+ >+ public static final String TYPE_PROVIDER_PREFIX = "#"; //$NON-NLS-1$ >+ public static final String TEST_ASSET_EXTENSION_PREFIX = "~"; //$NON-NLS-1$ >+ >+ private IProject project; >+ private TypeProviderManager typeProviderManager; >+ private TestAssetGroupProxyManager testAssetGroupProxyManager; >+ >+ public LogicalProjectProxiesRequest(Collection requests, TypeProviderManager typeProviderManager, TestAssetGroupProxyManager testAssetGroupProxyManager, IProject project, TestNavigator testNavigator) { >+ super(NLS.bind(TestNavigatorMessages.PM_EXPLORING_PROJECT, project.getName()), requests, testNavigator); >+ this.project = project; >+ this.typeProviderManager = typeProviderManager; >+ this.testAssetGroupProxyManager = testAssetGroupProxyManager; >+ //this.setRule(project); >+ } >+ >+ public IProject getProject() { >+ return project; >+ } >+ >+ protected IProxyNode computeProxy(Object key) { >+ String req = (String)key; >+ if (req.startsWith(TYPE_PROVIDER_PREFIX)) { >+ return typeProviderManager.getTypeProviderProxyNode(project, req.substring(1)); >+ } else if (req.startsWith(TEST_ASSET_EXTENSION_PREFIX)) { >+ return testAssetGroupProxyManager.getTestAssetGroup(project, req.substring(1)); >+ } >+ return null; >+ } >+ >+ protected IProxyNode getPlaceHolder(Object key) { >+ return null; >+ } >+ >+ protected String getTaskName() { >+ return NLS.bind(TestNavigatorMessages.PM_EXPLORING_PROJECT, project.getName()); >+ } >+ >+ protected String getSubTaskName(Object key) { >+ String req = (String)key; >+ if (req.startsWith(TYPE_PROVIDER_PREFIX)) { >+ return NLS.bind(TestNavigatorMessages.PM_INDEXING_TYPE, req.substring(1)); >+ } else if (req.startsWith(TEST_ASSET_EXTENSION_PREFIX)) { >+ return NLS.bind(TestNavigatorMessages.PM_INDEXING_ASSET_GROUP, req.substring(1)); >+ } >+ return ""; //$NON-NLS-1$ >+ } >+ >+} >#P org.eclipse.hyades.test.tools.ui >Index: src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/RegularJUnitProviderProxyNode.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.tools.ui/src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/RegularJUnitProviderProxyNode.java,v >retrieving revision 1.2 >diff -u -r1.2 RegularJUnitProviderProxyNode.java >--- src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/RegularJUnitProviderProxyNode.java 1 Sep 2006 15:42:16 -0000 1.2 >+++ src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/RegularJUnitProviderProxyNode.java 16 Oct 2006 16:45:26 -0000 >@@ -12,9 +12,6 @@ > > package org.eclipse.hyades.test.tools.ui.java.internal.junit.navigator; > >-import java.util.Collections; >-import java.util.List; >- > import org.eclipse.hyades.test.ui.TestUIExtension; > import org.eclipse.hyades.test.ui.internal.navigator.TestNavigator; > import org.eclipse.hyades.test.ui.navigator.IProxyNode; >@@ -59,20 +56,6 @@ > setChildren(computeChildren()); > } > >- protected List computeChildren() { >- RegularJUnitProvider provider = getProvider(); >- if (provider.refresher == null) { >- return super.computeChildren(); >- } else { >- provider.scheduleComputeChildren(this); >- return Collections.EMPTY_LIST; >- } >- } >- >- protected void computeActualChildren() { >- setChildren(RegularJUnitProviderProxyNode.super.computeChildren()); >- } >- > protected JavaElementProxyNode createChildProxy(IJavaElement childElement, IJavaElementDelta delta) { > if (childElement instanceof IPackageFragmentRoot) { > return RegularJUnitSourceFolderProxyNode.create((IPackageFragmentRoot)childElement, this, delta); >Index: src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/RegularJUnitProvider.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.tools.ui/src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/RegularJUnitProvider.java,v >retrieving revision 1.1 >diff -u -r1.1 RegularJUnitProvider.java >--- src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/RegularJUnitProvider.java 1 Sep 2006 14:14:37 -0000 1.1 >+++ src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/RegularJUnitProvider.java 16 Oct 2006 16:45:26 -0000 >@@ -13,27 +13,16 @@ > package org.eclipse.hyades.test.tools.ui.java.internal.junit.navigator; > > import java.util.HashMap; >-import java.util.HashSet; > import java.util.Iterator; > import java.util.Map; >-import java.util.Set; > > import org.eclipse.core.resources.IProject; >-import org.eclipse.core.resources.IResource; > import org.eclipse.core.resources.IResourceDelta; >-import org.eclipse.core.runtime.Assert; >-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.jobs.Job; > import org.eclipse.hyades.test.tools.core.internal.java.modelsync.event.IJUnitTestSuiteFactoryEvent; > import org.eclipse.hyades.test.tools.core.internal.java.modelsync.event.IJUnitTestSuiteFactoryListener; > import org.eclipse.hyades.test.tools.core.internal.java.modelsync.event.JUnitTestSuiteCreatedEvent; > import org.eclipse.hyades.test.tools.core.internal.java.modelsync.event.JUnitTestSuiteDetachedEvent; > import org.eclipse.hyades.test.tools.core.internal.java.modelsync.event.JUnitTestSuiteFactoryEventManager; >-import org.eclipse.hyades.test.tools.ui.ToolsUiPlugin; >-import org.eclipse.hyades.test.tools.ui.java.internal.JavaMessages; > import org.eclipse.hyades.test.ui.navigator.IFileProxyManager; > import org.eclipse.hyades.test.ui.navigator.IProxyNodeListener; > import org.eclipse.hyades.test.ui.navigator.ITypeProvider; >@@ -103,7 +92,6 @@ > disposed = true; > // disposed must be set to true before cancelling the current job, otherwise another > // job may be triggered while we cancel this one. >- if (computeJob != null) computeJob.cancel(); > if (refresher != null) { > JUnitTestSuiteFactoryEventManager.getInstance().removeListener(this); > JavaCore.removeElementChangedListener(this); >@@ -143,87 +131,6 @@ > } > } > >- protected void proxyComputed(RegularJUnitProviderProxyNode proxy) { >- if (proxy.getChildren().length != 0) { >- IJavaProject project = proxy.getJavaProject(); >- refresher.nodeChanged(project.getProject()); >- } >- } >- >- protected ISchedulingRule mutualExlusionRule = new ISchedulingRule() { >- public boolean contains(ISchedulingRule rule) { >- if (rule == this) return true; >- if (rule instanceof IResource) return true; >- return false; >- } >- public boolean isConflicting(ISchedulingRule rule) { >- return rule == this; >- } >- }; >- >- protected class ComputeJob extends Job { >- private Set proxies = new HashSet(); >- public ComputeJob() { >- super(JavaMessages.REGULAR_JUNIT_EXPLORING_TESTS); >- setRule(mutualExlusionRule); >- } >- public void addProxy(RegularJUnitProviderProxyNode proxy) { >- proxies.add(proxy); >- } >- protected IStatus run(IProgressMonitor monitor) { >- monitor.beginTask(JavaMessages.REGULAR_JUNIT_EXPLORING_PROJECT, proxies.size()); >- try { >- Iterator it = proxies.iterator(); >- while (it.hasNext()) { >- RegularJUnitProviderProxyNode proxy = (RegularJUnitProviderProxyNode) it.next(); >- try { >- monitor.subTask(proxy.getJavaElement().getElementName()); >- proxy.computeActualChildren(); >- proxyComputed(proxy); >- } catch (Throwable t) { >- ToolsUiPlugin.logError(t); >- } finally { >- it.remove(); >- monitor.done(); >- } >- } >- return new Status(IStatus.OK, ToolsUiPlugin.getID(), 0, "", null); //$NON-NLS-1$ >- } finally { >- monitor.done(); >- } >- } >- } >- >- private ComputeJob computeJob = null; >- >- /** >- * Returns an ComputeJob in NONE state (ie. ready to be scheduled). >- * @return >- */ >- private synchronized ComputeJob getComputeJob() { >- if (computeJob != null) { >- if (computeJob.getState() != Job.RUNNING && computeJob.cancel()) { >- // The job is back to NONE state now >- return computeJob; >- } else { >- // Too late, our job is already running. Forget this one. >- computeJob = null; >- } >- } >- if (computeJob == null) { >- computeJob = new ComputeJob(); >- } >- return computeJob; >- } >- >- /*package*/ void scheduleComputeChildren(RegularJUnitProviderProxyNode proxy) { >- Assert.isLegal(refresher != null, "Cannot delay children computation in static view mode"); //$NON-NLS-1$ >- if (disposed) return; >- ComputeJob job = getComputeJob(); >- job.addProxy(proxy); >- job.schedule(500); >- } >- > /** > * Convenience method to get the proxy node associated to an arbitrary java element. > * @param element An opened java element. >Index: src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/JUnitTypeProvider.java >=================================================================== >RCS file: /home/tptp/test/org.eclipse.hyades.test.tools.ui/src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/JUnitTypeProvider.java,v >retrieving revision 1.8 >diff -u -r1.8 JUnitTypeProvider.java >--- src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/JUnitTypeProvider.java 1 Sep 2006 14:14:37 -0000 1.8 >+++ src/org/eclipse/hyades/test/tools/ui/java/internal/junit/navigator/JUnitTypeProvider.java 16 Oct 2006 16:45:26 -0000 >@@ -11,6 +11,7 @@ > **********************************************************************/ > package org.eclipse.hyades.test.tools.ui.java.internal.junit.navigator; > >+import java.util.Collections; > import java.util.HashMap; > import java.util.Map; > >@@ -39,7 +40,7 @@ > protected IFileProxyManager fileProxyManager; > protected IProxyNodeListener refresher; > >- private Map projectToProxyMap = new HashMap(); >+ private Map projectToProxyMap = Collections.synchronizedMap(new HashMap()); > > public JUnitTypeProvider() { > FileProxyNodeCache.getInstance().addResourceListener(this); >@@ -96,7 +97,7 @@ > if (lowestChange != null) { > refresher.nodeChanged(lowestChange); > } >- } else if (event.getType() == IResourceDelta.ADDED) { >+ } else if (affectedChildren[i].getKind() == IResourceDelta.ADDED) { > //- if there is something added to this project, refresh it this can lead to type provider appearance > refresher.nodeChanged(project); > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 157089
:
50014
| 52041