| //------------------------------------------------------------------------------ |
| // Copyright (c) 2005, 2008 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 |
| // |
| // Contributors: |
| // IBM Corporation - initial implementation |
| //------------------------------------------------------------------------------ |
| package org.eclipse.epf.library.util; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IResourceStatus; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.epf.common.utils.RestartableJob; |
| import org.eclipse.epf.library.ILibraryManager; |
| import org.eclipse.epf.library.ILibraryService; |
| import org.eclipse.epf.library.LibraryPlugin; |
| import org.eclipse.epf.library.LibraryResources; |
| import org.eclipse.epf.library.LibraryService; |
| import org.eclipse.epf.library.LibraryServiceListener; |
| import org.eclipse.epf.library.LibraryServiceUtil; |
| import org.eclipse.epf.library.events.ILibraryChangeListener; |
| import org.eclipse.epf.services.ILibraryPersister; |
| import org.eclipse.epf.uma.MethodLibrary; |
| import org.eclipse.epf.uma.MethodPlugin; |
| |
| /** |
| * The class for monitor library problems. |
| * |
| * (1) Wake up regularly (say every 30 seconds) |
| * to schedule job if any change is registered during sleep |
| * |
| * (2) Goes to sleep again immediately after "waking up/do nothing" or |
| * "waking up/scheduling a job" |
| * |
| * (3) Job (finding library problems) runs to end only there is no change during run. |
| * |
| * (4) Job run is aborted (by throwing a RestartInterruptException) |
| * whenever a change is detected during run, and a new job scheduled |
| * with a delay time (say 1 second). |
| * |
| * (5) Make sure there is always at most one job running |
| * |
| * @author Weiping Lu |
| * @since 1.5 |
| */ |
| |
| public class LibraryProblemMonitor extends RestartableJob implements ILibraryChangeListener { |
| |
| public static final String UnresolvedBasedPluginMARKER_ID = LibraryPlugin.getDefault().getId() + ".unresolvedBasePlugins"; //$NON-NLS-1$ |
| |
| public static final String Name = "name"; //$NON-NLS-1$ |
| public static final String Guid = "guid"; //$NON-NLS-1$ |
| public static final String UnresolvedBaseGuids = "unresolvedBaseGuids"; //$NON-NLS-1$ |
| |
| private long delay = 30000L; |
| private long restartDelay = 1000L; |
| private boolean hasChange = false; |
| private Thread monitorThread; |
| private boolean stopMonitor = false; |
| private MethodLibrary library; |
| private Map<MethodPlugin, IMarker> pluginMarkerMap = new HashMap<MethodPlugin, IMarker>(); |
| |
| public LibraryProblemMonitor() { |
| super(LibraryResources.libraryProblemMonitor); |
| |
| LibraryServiceListener libServiceListener = new LibraryServiceListener() { |
| public void librarySet(MethodLibrary lib) { |
| ILibraryService libService = LibraryService.getInstance(); |
| if (library != null && library != lib) { |
| ILibraryManager libMgr = libService.getLibraryManager(library); |
| if (libMgr != null) { |
| libMgr.removeListener(LibraryProblemMonitor.this); |
| } |
| } |
| |
| if (lib != null && lib != library) { |
| ILibraryManager libMgr = libService.getLibraryManager(lib); |
| if (libMgr != null) { |
| libMgr.addListener(LibraryProblemMonitor.this); |
| } |
| kickToRun(); |
| } |
| |
| library = lib; |
| } |
| }; |
| LibraryService.getInstance().addListener(libServiceListener); |
| startMonitor(); |
| } |
| |
| public void startMonitor() { |
| Runnable runnable = new Runnable() { |
| public void run() { |
| while (! stopMonitor) { |
| try { |
| Thread.sleep(delay); |
| } catch (Exception e) { |
| LibraryPlugin.getDefault().getLogger().logError(e); |
| return; |
| } |
| if (hasChange) { |
| hasChange = false; |
| guardedSchedule(0L); |
| } |
| } |
| } |
| }; |
| |
| stopMonitor = false; |
| if (monitorThread == null) { |
| monitorThread = new Thread(runnable); |
| } |
| monitorThread.start(); |
| } |
| |
| public void stopMonitor() { |
| stopMonitor = true; |
| } |
| |
| |
| public void libraryChanged(int option, Collection<Object> changedItems) { |
| if (changedItems != null && changedItems.size() > 0) { |
| hasChange = true; |
| enableToRestart(); |
| } |
| } |
| |
| // Update will abort and re-schedule a job if new change detected |
| private void update() throws RestartInterruptException { |
| if (localDebug) { |
| System.out.println("LD> update"); //$NON-NLS-1$ |
| } |
| MethodLibrary lib = getLibrary(); |
| if (lib == null) { |
| return; |
| } |
| checkRestartInterruptException(restartDelay); |
| |
| cleanUp(); |
| |
| List<MethodPlugin> plugins = new ArrayList<MethodPlugin>(); |
| plugins.addAll(lib.getMethodPlugins()); |
| |
| Set<MethodPlugin> pluginSet = new HashSet<MethodPlugin>(plugins); |
| for (MethodPlugin plugin: plugins) { |
| checkRestartInterruptException(restartDelay); |
| List<MethodPlugin> baseList = plugin.getBases(); |
| boolean missing = false; |
| for (MethodPlugin base: baseList) { |
| checkRestartInterruptException(restartDelay); |
| if (! pluginSet.contains(base)) { |
| if (! missing) { |
| if (localDebug) { |
| System.out.println("LD> plugin: " + plugin); //$NON-NLS-1$ |
| System.out.println("LD> " + plugin.getName() + " references unresolved bases:"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| missing = true; |
| } |
| if (localDebug) { |
| System.out.println("LD> base: " + base); //$NON-NLS-1$ |
| } |
| addMissingBasePluginError(plugin, base); |
| } |
| } |
| if (missing) { |
| System.out.println(""); //$NON-NLS-1$ |
| } |
| } |
| |
| } |
| |
| private void addMissingBasePluginError(MethodPlugin plugin, MethodPlugin base) { |
| IMarker marker = pluginMarkerMap.get(plugin); |
| if (marker == null) { |
| Resource res = plugin.eResource(); |
| if (res == null) { |
| return; |
| } |
| |
| URI containerURI = res.getURI(); |
| IWorkspace workspace = ResourcesPlugin.getWorkspace(); |
| IPath path = new Path(containerURI.toFileString()); |
| IFile file = workspace.getRoot().getFileForLocation(path); |
| if (file == null) { |
| return; |
| } |
| String location = containerURI != null ? containerURI |
| .toFileString() : ""; //$NON-NLS-1$ |
| try { |
| marker = file.createMarker(UnresolvedBasedPluginMARKER_ID); |
| marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR); |
| marker.setAttribute(Name, plugin.getName()); |
| marker.setAttribute(Guid, plugin.getGuid()); |
| marker.setAttribute(IMarker.LOCATION, location); |
| marker.setAttribute(Guid, plugin.getGuid()); |
| |
| } catch (CoreException e) { |
| IStatus status = e.getStatus(); |
| if(status instanceof IResourceStatus && ((IResourceStatus) status).getCode() == IResourceStatus.RESOURCE_NOT_FOUND) { |
| // do nothing |
| } else { |
| LibraryPlugin.getDefault().getLogger().logError(e); |
| } |
| } catch(Exception e) { |
| LibraryPlugin.getDefault().getLogger().logError(e); |
| } |
| if (marker == null) { |
| return; |
| } |
| if (localDebug) { |
| System.out.println("LD> marker: " + marker); //$NON-NLS-1$ |
| } |
| pluginMarkerMap.put(plugin, marker); |
| |
| } |
| |
| String unresolvedBaseGuidsValue = null; |
| try { |
| |
| String errMsg = plugin.getName() + " " + LibraryResources.references_unresolved_base_txt; //$NON-NLS-1$ |
| unresolvedBaseGuidsValue = (String) marker.getAttribute(UnresolvedBaseGuids); |
| if (unresolvedBaseGuidsValue == null || unresolvedBaseGuidsValue.length() == 0) { |
| unresolvedBaseGuidsValue = base.getGuid(); |
| errMsg += ": "; //$NON-NLS-1$ |
| } else if (unresolvedBaseGuidsValue.indexOf(base.getGuid()) < 0) { |
| unresolvedBaseGuidsValue += ", " + base.getGuid(); //$NON-NLS-1$ |
| errMsg += "plugins: "; //$NON-NLS-1$ |
| } |
| errMsg += unresolvedBaseGuidsValue; |
| marker.setAttribute(IMarker.MESSAGE, errMsg); |
| marker.setAttribute(UnresolvedBaseGuids, unresolvedBaseGuidsValue); |
| } catch (Exception e) { |
| LibraryPlugin.getDefault().getLogger().logError(e); |
| } |
| |
| } |
| |
| protected IStatus restartableRun(IProgressMonitor monitor) throws RestartInterruptException { |
| update(); |
| return Status.OK_STATUS; |
| } |
| |
| protected void resetToRestart() { |
| if (localDebug) { |
| System.out.println("LD> resetToRestart"); //$NON-NLS-1$ |
| } |
| cleanUp(); |
| } |
| |
| private void cleanUp() { |
| if (pluginMarkerMap.isEmpty()) { |
| return; |
| } |
| for (IMarker marker: pluginMarkerMap.values()) { |
| try { |
| marker.delete(); |
| } catch (Exception e) { |
| LibraryPlugin.getDefault().getLogger().logError(e); |
| } |
| } |
| pluginMarkerMap = new HashMap<MethodPlugin, IMarker>(); |
| } |
| |
| public void kickToRun() { |
| if (localDebug) { |
| System.out.println("LD> kickToRun"); //$NON-NLS-1$ |
| } |
| enableToRestart(); |
| guardedSchedule(0L); |
| } |
| |
| //To do: allow a cached data to pased and return -> optimize fix of similar problems |
| public void fixProblem(IMarker marker) { |
| try { |
| if (marker.getType() != UnresolvedBasedPluginMARKER_ID) { |
| return; |
| } |
| MethodLibrary lib = getLibrary(); |
| if (lib == null) { |
| return; |
| } |
| |
| Map<String, MethodPlugin> guidToPluginMap = new HashMap<String, MethodPlugin>(); |
| for (MethodPlugin plugin : lib.getMethodPlugins()) { |
| guidToPluginMap.put(plugin.getGuid(), plugin); |
| } |
| String guid = (String) marker.getAttribute(Guid); //$NON-NLS-1$ |
| |
| MethodPlugin plugin = guidToPluginMap.get(guid); |
| if (plugin == null || plugin.eResource() == null) { |
| return; |
| } |
| |
| if (localDebug) { |
| System.out.println("LD> fixProblem, plugin: " + plugin); //$NON-NLS-1$ |
| } |
| |
| List<MethodPlugin> bases = new ArrayList<MethodPlugin>(); |
| bases.addAll(plugin.getBases()); |
| |
| boolean modified = false; |
| for (MethodPlugin base : bases) { |
| if (! guidToPluginMap.containsKey(base.getGuid())) { |
| modified = true; |
| plugin.getBases().remove(base); |
| } |
| } |
| if (! modified) { |
| return; |
| } |
| |
| Resource resource = plugin.eResource(); |
| ILibraryPersister.FailSafeMethodLibraryPersister persister = LibraryServiceUtil |
| .getPersisterFor(resource).getFailSafePersister(); |
| try { |
| persister.save(resource); |
| persister.commit(); |
| } |
| catch(Exception e) { |
| LibraryPlugin.getDefault().getLogger().logError(e); |
| persister.rollback(); |
| } |
| |
| kickToRun(); |
| } catch (Exception e) { |
| LibraryPlugin.getDefault().getLogger().logError(e); |
| } |
| } |
| |
| public void dispose() { |
| stopMonitor(); |
| cleanUp(); |
| } |
| |
| public MethodLibrary getLibrary() { |
| return library; |
| } |
| |
| public void setLibrary(MethodLibrary library) { |
| this.library = library; |
| } |
| |
| } |