/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.core.workspace; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IMarkerDelta; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceChangeEvent; import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.designer.core.ModelerCore; /** This class provides an efficient mechanism to track marker changes for IResources and maps markers to their corresponding * or associated EObjects. This was prompted by use of eclipse's decorator scheduler framework. Our content providers * were resolving EObjects for UUID's on ALL markers for a given resource. This was very inefficient. This class keeps track * of markers for existing resources and refreshes a map of marker-to-eObject for each resource. * @since 8.0 */ public class ModelMarkerManager implements IResourceChangeListener { private HashMap resourceMap = new HashMap(); /** * * @since 5.0 */ public ModelMarkerManager() { super(); if (ResourcesPlugin.getPlugin() != null) { ModelerCore.getWorkspace().addResourceChangeListener(this); } } /** * Responds to resource change events, looks to see if resource/marker/eobject maps need to get refreshed. * @see org.eclipse.core.resources.IResourceChangeListener#resourceChanged(org.eclipse.core.resources.IResourceChangeEvent) * @since 5.0 */ @Override public void resourceChanged(IResourceChangeEvent event) { boolean refreshNeeded = false; IMarkerDelta[] markerDeltas = event.findMarkerDeltas(IMarker.PROBLEM, true); List changes = new ArrayList(markerDeltas.length); examineDelta(markerDeltas, changes); if (markerDeltas.length != changes.size()) { refreshNeeded = true; } if ( refreshNeeded ) { List visitedResources = new ArrayList(); // boolean which will break this method out of it's loop // We only need to refresh the diagram once here List changedResources = new ArrayList(); for( int i=0; i<markerDeltas.length; i++ ) { IResource eventResource = markerDeltas[i].getResource(); // Need to only look at a delta's resource if we haven't looked at it before. if( !visitedResources.contains(eventResource) ) { if( ModelUtil.isModelFile(eventResource)) { ModelResource mr = null; try { mr = ModelUtil.getModelResource((IFile)eventResource, false); } catch (ModelWorkspaceException e) { ModelerCore.Util.log(e); } if( mr != null ) { if( !changedResources.contains(eventResource) ) { changedResources.add(eventResource); } } } visitedResources.add(eventResource); } } refreshMarkers(changedResources); } } protected String[] getMarkerTypes() { return new String[] { IMarker.PROBLEM }; } /* * looks for changed markers */ private static void examineDelta(IMarkerDelta[] deltas, List changes) { for (int idx = 0; idx < deltas.length; idx++) { IMarkerDelta delta = deltas[idx]; int kind = delta.getKind(); if (kind == IResourceDelta.CHANGED) { changes.add(deltas[idx].getMarker()); } } } /* * refreshes marker maps for changed resources */ private void refreshMarkers(List changedResources) { clearStaleResources(); // walk through the changed resoures for( Iterator iter = changedResources.iterator(); iter.hasNext(); ) { IResource theIResource = (IResource)iter.next(); if( theIResource.exists() ) { Object obj = resourceMap.get(theIResource); HashMap theMarkerMap = null; // Check resourceMap, if exists, get markerMap, clear it and re-populate with resource markers if( obj != null && obj instanceof HashMap ) { theMarkerMap = (HashMap)obj; theMarkerMap.clear(); } // If resourceMap doesn't contain markerMap for a resource, create one, add it to the resourceMap and re-populate with // resource markers. if( theMarkerMap == null ) { theMarkerMap = new HashMap(); resourceMap.put(theIResource, theMarkerMap); } populateMarkerMap(theMarkerMap, theIResource); } else { resourceMap.remove(theIResource); } } } /* * Clears the marker maps for stale/non-existing resources */ private void clearStaleResources() { List staleKeys = new ArrayList(); for( Iterator iter = resourceMap.keySet().iterator(); iter.hasNext(); ) { Object nextKey = iter.next(); if( nextKey instanceof IResource ) { if( !((IResource)nextKey).exists() ) { staleKeys.add(nextKey); } } } for( Iterator iter = staleKeys.iterator(); iter.hasNext(); ) { resourceMap.remove(iter.next()); } } /* * re-populates the marker-to-eobject map for a given resource */ private void populateMarkerMap(HashMap markerMap, IResource theResource) { IMarker[] markers = null; boolean errorOccurred = false; try { markers = theResource.findMarkers(IMarker.PROBLEM, false, IResource.DEPTH_INFINITE); } catch (CoreException ex) { ModelerCore.Util.log(ex); errorOccurred = true; } if (!errorOccurred) { // We have the markers, let's create a MAP of EObjects to for (int ndx = markers.length; --ndx >= 0;) { IMarker marker = markers[ndx]; EObject targetEObject = getMarkedEObject(marker); if( targetEObject != null ) { markerMap.put(marker, targetEObject); } } } } /** * For a given iMarker, this method resolves the eObject from the UUID reference on the marker. * @param resrc * @param iMarker * @return * @since 5.0 */ public EObject getMarkedEObject(IResource resrc, IMarker iMarker) { CoreArgCheck.isNotNull(resrc); EObject theMarkedEObject = null; if( resrc.exists() ) { Object obj = resourceMap.get(resrc); HashMap theMarkerMap = null; // Check resourceMap, if exists, then get the value for the iMarker key if( obj != null && obj instanceof HashMap ) { theMarkerMap = (HashMap)obj; Object value = theMarkerMap.get(iMarker); if( value != null && value instanceof EObject ) { theMarkedEObject = (EObject)value; } } } return theMarkedEObject; } /* * Private method which does the actual EObject resolution */ private EObject getMarkedEObject(IMarker iMarker) { EObject target = null; String uri = (String)getMarkerAttribute(iMarker, ModelerCore.MARKER_URI_PROPERTY); if( uri != null ) { URI theURI = URI.createURI(uri); if( theURI != null ) { try { target = ModelerCore.getModelContainer().getEObject(theURI, true); // Need to } catch (CoreException e1) { ModelerCore.Util.log(e1); } } } return target; } /* * Private method for obtaining an attribute property from an IMarker */ private Object getMarkerAttribute(IMarker iMarker, String attributeName) { Object attribute = null; if( iMarker != null ) { try { attribute = iMarker.getAttribute(attributeName); } catch (CoreException e) { //Do nothing. } } return attribute; } /** * Public method used by the owner of an instance of this class. This method provides a mechanism to clear out the marker maps. * * @since 5.0 */ public void dispose() { ModelerCore.getWorkspace().removeResourceChangeListener(this); this.resourceMap.clear(); } }