blob: be7d41ee68596a3edd5f92924095d1699e6ab454 [file] [log] [blame]
//------------------------------------------------------------------------------
// Copyright (c) 2005, 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
//
// Contributors:
// IBM Corporation - initial implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.persistence.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
import org.eclipse.core.filebuffers.ITextFileBufferManager;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.resources.WorkspaceJob;
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.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.epf.persistence.FileManager;
import org.eclipse.epf.persistence.MultiFileResourceSetImpl;
import org.eclipse.epf.persistence.MultiFileSaveUtil;
import org.eclipse.epf.persistence.PersistencePlugin;
import org.eclipse.epf.uma.ecore.IProxyResolutionListener;
import org.eclipse.epf.uma.ecore.ResolveException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.osgi.util.NLS;
/**
* Background job that manage markers for unresolved proxies
*
* @author Phong Nguyen Le
* @since 1.0
*/
public class UnresolvedProxyMarkerManager extends WorkspaceJob implements IProxyResolutionListener {
private static final long DELAY = 0;
public static final String PROXY_URI = "proxyURI"; //$NON-NLS-1$
public static final String OWNER_GUID = "ownerGUID"; //$NON-NLS-1$
private static class ValidObject {
boolean valid;
Object object;
/**
* @param valid
* @param object
*/
public ValidObject(Object object) {
super();
this.object = object;
valid = true;
}
}
private Map uriToExceptionsMap;
private List exceptions;
private Map resourceGUIToMarkersMap;
private Map elementGUIToMarkersMap;
private ResourceSet resourceSet;
private boolean enabled;
private List resourcesToValidateMarkers;
public UnresolvedProxyMarkerManager(ResourceSet resourceSet) {
super("EPF Unresolved Proxy Logger"); //$NON-NLS-1$
this.resourceSet = resourceSet;
// unresolvedResourceGUIDToMarkersMap = new HashMap();
uriToExceptionsMap = new HashMap();
exceptions = new ArrayList();
resourceGUIToMarkersMap = new HashMap();
elementGUIToMarkersMap = new HashMap();
resourcesToValidateMarkers = new UniqueEList();
}
public IMarker findMarker(IFile file, String proxyURI, int start, int end) throws CoreException {
IMarker[] markers = file.findMarkers(IMarker.PROBLEM, false, IResource.DEPTH_ZERO);
for (int i = 0; i < markers.length; i++) {
IMarker marker = markers[i];
if(proxyURI.equals(marker.getAttribute(PROXY_URI))
&& marker.getAttribute(IMarker.CHAR_START, -1) == start
&& marker.getAttribute(IMarker.CHAR_END, -1) == end)
{
return marker;
}
}
return null;
}
private boolean addException(ResolveException re) {
synchronized(exceptions) {
URI uri = ((InternalEObject)re.getProxy()).eProxyURI();
Set exceptions = (Set) uriToExceptionsMap.get(uri);
if(exceptions == null) {
exceptions = new HashSet();
uriToExceptionsMap.put(uri, exceptions);
}
if(exceptions.add(re)) {
this.exceptions.add(re);
return true;
}
return false;
}
}
/**
* Document based character sequence.
*/
private static class DocumentCharSequence implements CharSequence {
/** Document */
private IDocument fDocument;
/**
* Initialize with the sequence of characters in the given
* document.
*
* @param document the document
*/
public DocumentCharSequence(IDocument document) {
fDocument= document;
}
/*
* @see java.lang.CharSequence#length()
*/
public int length() {
return fDocument.getLength();
}
/*
* @see java.lang.CharSequence#charAt(int)
*/
public char charAt(int index) {
try {
return fDocument.getChar(index);
} catch (BadLocationException x) {
throw new IndexOutOfBoundsException(x.getLocalizedMessage());
}
}
/*
* @see java.lang.CharSequence#subSequence(int, int)
*/
public CharSequence subSequence(int start, int end) {
try {
return fDocument.get(start, end - start);
} catch (BadLocationException x) {
throw new IndexOutOfBoundsException(x.getLocalizedMessage());
}
}
}
private void addMarker(Resource resource, URI proxyURI, String errMsg, String ownerGUID, IProgressMonitor monitor) {
URI containerURI = resource.getURI();
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IPath path = new Path(containerURI.toFileString());
IFile file = workspace.getRoot().getFileForLocation(path);
if (file != null) {
String location = containerURI != null ? containerURI
.toFileString() : ""; //$NON-NLS-1$
try {
file.refreshLocal(IResource.DEPTH_ZERO, null);
// locate the text of unresolved URI in file
//
ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager();
try {
manager.connect(path, monitor);
ITextFileBuffer fileBuffer= manager.getTextFileBuffer(path);
fileBuffer.requestSynchronizationContext();
fileBuffer.getDocument();
IDocument doc = fileBuffer.getDocument();
if(doc != null) {
String proxyURIStr = proxyURI.toString();
Pattern pattern = PatternConstructor.createPattern(proxyURIStr, true, false);
Matcher matcher = pattern.matcher(new DocumentCharSequence(doc));
while(matcher.find()) {
int start = matcher.start();
int end = matcher.end();
if(start != end) {
// make sure that resolver is still in the open library by checking whether its resource
// still belongs to a resource set
//
if(resource != null && resource.getResourceSet() != null) {
// create problem marker for file
IMarker marker = findMarker(file, proxyURIStr, start, end);
if(marker == null) {
marker = file.createMarker(IMarker.PROBLEM);
marker.setAttribute(IMarker.SEVERITY,
IMarker.SEVERITY_ERROR);
marker.setAttribute(IMarker.MESSAGE, errMsg);
marker.setAttribute(IMarker.LOCATION, location);
marker.setAttribute(IMarker.TRANSIENT, true);
marker.setAttribute(IMarker.CHAR_START, start);
marker.setAttribute(IMarker.CHAR_END, end);
marker.setAttribute(PROXY_URI, proxyURIStr);
marker.setAttribute(OWNER_GUID, ownerGUID);
// cache marker to it can be found easily and deleted
//
cacheMarker(marker, proxyURI);
}
else {
// update owner GUID
//
marker.setAttribute(OWNER_GUID, ownerGUID);
}
}
}
}
}
fileBuffer.releaseSynchronizationContext();
}
finally {
manager.disconnect(path, monitor);
}
} catch (CoreException ex) {
CommonPlugin.INSTANCE.log(ex);
if (MultiFileSaveUtil.DEBUG) {
ex.printStackTrace();
}
}
}
}
private void addMarker(ResolveException re, IProgressMonitor monitor) {
InternalEObject proxy = (InternalEObject) re.getProxy();
URI containerURI = null;
Resource resource = null;
if(re.getResolver() != null) {
resource = re.getResolver().eResource();
// make sure that resolver is still in the open library by checking whether its resource
// still belongs to a resource set
//
// System.out.println("UnresolvedProxyMarkerManager.addMarker(): resourceSet=" + resource.getResourceSet().hashCode());
if(resource != null && resource.getResourceSet() != null) {
containerURI = resource.getURI();
}
}
if (containerURI != null) {
IWorkspace workspace = ResourcesPlugin.getWorkspace();
IPath path = new Path(containerURI.toFileString());
IFile file = workspace.getRoot().getFileForLocation(path);
if (file != null) {
String errMsg;
if (re.exception() != null && re.exception().getLocalizedMessage() != null &&
re.exception().getLocalizedMessage().trim().length() > 0) {
errMsg = re.exception().getLocalizedMessage();
}
else {
errMsg = re.getMessage() == null ? NLS.bind(PersistenceResources.UnresolvedProxyMarkerManager_couldNotResolveProxy, proxy.eProxyURI()) : re
.getMessage();
}
addMarker(resource, proxy.eProxyURI(), errMsg, MultiFileSaveUtil.getGuid(re.getResolver()), monitor);
}
}
}
/**
* @param marker
* @param uri proxy uri
*/
private void cacheMarker(IMarker marker, URI uri) {
synchronized(elementGUIToMarkersMap) {
String resourceGUID = uri.authority();
if(resourceGUID != null) {
ValidObject vo = (ValidObject) resourceGUIToMarkersMap.get(resourceGUID);
if(vo == null) {
vo = new ValidObject(new HashSet());
resourceGUIToMarkersMap.put(resourceGUID, vo);
}
Collection markers = (Collection) vo.object;
markers.add(marker);
}
String elementGUID = uri.fragment();
Collection markers = (Collection) elementGUIToMarkersMap.get(elementGUID);
if(markers == null) {
markers = new HashSet();
elementGUIToMarkersMap.put(elementGUID, markers);
}
markers.add(new ValidObject(marker));
}
}
public void clearAll() {
boolean oldEnabled = enabled;
try {
enabled = false;
cancel();
synchronized (exceptions) {
uriToExceptionsMap.clear();
exceptions.clear();
}
synchronized(elementGUIToMarkersMap) {
if(!elementGUIToMarkersMap.isEmpty()) {
for (Iterator iter = elementGUIToMarkersMap.values().iterator(); iter.hasNext();) {
Collection markers = (Collection) iter.next();
for (Iterator iter1 = markers.iterator(); iter1.hasNext();) {
ValidObject vo = (ValidObject) iter1.next();
IMarker marker = (IMarker) vo.object;
try {
if(marker.exists()) {
marker.delete();
}
}
catch(Exception e) {
CommonPlugin.INSTANCE.log(e);
}
}
markers.clear();
}
elementGUIToMarkersMap.clear();
resourceGUIToMarkersMap.clear();
}
}
synchronized(resourcesToValidateMarkers) {
resourcesToValidateMarkers.clear();
}
}
finally {
enabled = oldEnabled;
// System.out.println("UnresolvedProxyMarkerManager.clearAll(): end");
}
}
public boolean hasUnresolvedProxy() {
return !elementGUIToMarkersMap.isEmpty();
}
private ResolveException nextException() {
synchronized(exceptions) {
// synchronized: in order to atomically obtain and clear requests
if(exceptions.isEmpty()) {
return null;
}
else {
ResolveException e = (ResolveException) this.exceptions.remove(0);
URI uri = ((InternalEObject)e.getProxy()).eProxyURI();
Collection exceptions = (Collection) uriToExceptionsMap.get(uri);
if(exceptions != null) {
exceptions.remove(e);
if(exceptions.isEmpty()) {
uriToExceptionsMap.remove(uri);
}
}
return e;
}
}
}
private Resource nextResourceToValidateMarkers() {
synchronized(resourcesToValidateMarkers) {
if(resourcesToValidateMarkers.isEmpty()) {
return null;
}
else {
return (Resource) resourcesToValidateMarkers.remove(0);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.core.resources.WorkspaceJob#runInWorkspace(org.eclipse.core.runtime.IProgressMonitor)
*/
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
// System.out.println("UnresolvedProxyMarkerManager.runInWorkspace(): begin");
try {
if(!enabled) return Status.OK_STATUS;
try {
// add markers
//
ResolveException re;
while((re = nextException()) != null) {
try {
addMarker(re, monitor);
}
catch(Exception e) {
CommonPlugin.INSTANCE.log(e);
}
}
// remove invalid markers
//
removeMarkers(monitor);
// validate resource markers
//
Resource resource;
while((resource = nextResourceToValidateMarkers()) != null) {
doValidateMarkers(resource);
}
}
catch(Exception e) {
CommonPlugin.INSTANCE.log(e);
}
return Status.OK_STATUS;
}
finally {
// System.out.println("UnresolvedProxyMarkerManager.runInWorkspace(): end");
}
}
private boolean removeFromResourceGUIDToMarkersMap(String proxyURI, IMarker marker) {
URI uri = URI.createURI(proxyURI);
String resourceGUID = uri.authority();
if(resourceGUID != null) {
ValidObject vo = (ValidObject) resourceGUIToMarkersMap.get(resourceGUID);
if(vo != null) {
Collection markers = ((Collection)vo.object);
boolean ret = markers.remove(marker);
if(markers.isEmpty()) {
resourceGUIToMarkersMap.remove(resourceGUID);
}
return ret;
}
}
return false;
}
private void removeFromElementGUIDToMarkersMap(String proxyURI, IMarker marker) {
URI uri = URI.createURI(proxyURI);
String elementGUID = uri.fragment();
if(elementGUID != null) {
Collection validObjects = (Collection) elementGUIToMarkersMap.get(elementGUID);
if(validObjects != null) {
for (Iterator iterator1 = validObjects.iterator(); iterator1
.hasNext();) {
ValidObject vo1 = (ValidObject) iterator1.next();
if(vo1.object == marker) {
iterator1.remove();
}
}
if(validObjects.isEmpty()) {
elementGUIToMarkersMap.remove(elementGUID);
}
}
}
}
private void removeMarkers(IProgressMonitor monitor) {
synchronized(elementGUIToMarkersMap) {
for (Iterator iter = elementGUIToMarkersMap.values().iterator(); iter.hasNext();) {
Collection markers = (Collection) iter.next();
for (Iterator iterator = markers.iterator(); iterator.hasNext();) {
ValidObject vo = (ValidObject) iterator.next();
if(!vo.valid) {
try {
IMarker marker = (IMarker) vo.object;
if(marker.exists()) {
String proxyURI = (String) marker.getAttribute(PROXY_URI);
marker.delete();
// remove this marker from resourceGUIToMarkersMap
//
removeFromResourceGUIDToMarkersMap(proxyURI, marker);
}
iterator.remove();
} catch (Exception e) {
CommonPlugin.INSTANCE.log(e);
}
}
}
}
for (Iterator iter = resourceGUIToMarkersMap.values().iterator(); iter.hasNext();) {
ValidObject vo = (ValidObject) iter.next();
if(!vo.valid) {
vo.valid = true;
Collection markers = (Collection) vo.object;
for (Iterator iterator = markers.iterator(); iterator.hasNext();) {
IMarker marker;
try {
marker = (IMarker) iterator.next();
if(marker.exists()) {
String proxyURIStr = (String) marker.getAttribute(PROXY_URI);
URI proxyURI = URI.createURI(proxyURIStr);
// proxy is in the same resource that is just loaded
// try to get the object with this proxy URI without loading new resource
//
// EObject o = resourceSet.getEObject(proxyURI, false);
String elementGUID = proxyURI.fragment();
EObject o = (EObject) ((MultiFileResourceSetImpl)resourceSet).getGuidToMethodElementMap().get(elementGUID);
if(o != null && !o.eIsProxy()) {
marker.delete();
iterator.remove();
// remove this marker from elementGUIToMarkersMap
//
removeFromElementGUIDToMarkersMap(proxyURIStr, marker);
}
}
else {
iterator.remove();
}
}
catch(Exception e) {
CommonPlugin.INSTANCE.log(e);
}
}
if(markers.isEmpty()) {
iter.remove();
}
}
}
}
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/* (non-Javadoc)
* @see org.eclipse.epf.uma.ecore.IProxyResolutionListener#notifyException(java.lang.Exception)
*/
public void notifyException(Exception e) {
if(!enabled) return;
if(e instanceof ResolveException) {
ResolveException re = (ResolveException) e;
// URI uri = ((InternalEObject)re.getProxy()).eProxyURI();
// if("_2J4YoPTDEdmkpYARNN468A".equals(uri.fragment())) {
// System.out.println();
// }
if(addException(re)) {
schedule(DELAY);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.epf.uma.ecore.IProxyResolutionListener#proxyResolved(java.lang.Object, java.lang.Object)
*/
public void proxyResolved(Object proxy, Object resolved) {
if(!enabled) return;
if(proxy instanceof InternalEObject) {
URI uri = ((InternalEObject)proxy).eProxyURI();
// if("_2J4YoPTDEdmkpYARNN468A".equals(uri.fragment())) {
// System.out.println();
// }
// remove all exceptions for this URI
//
removeExceptions(uri);
// invalidate all markers for this URI
//
if(invalidateMarkers(uri)) {
schedule(DELAY);
}
}
}
/**
* @param uri
*/
private boolean invalidateMarkers(URI uri) {
synchronized(elementGUIToMarkersMap) {
boolean ret = false;
String resourceGUID = uri.authority();
if(resourceGUID != null) {
ValidObject vo = (ValidObject) resourceGUIToMarkersMap.get(resourceGUID);
if(vo != null) {
vo.valid = false;
ret = true;
}
}
String elementGUID = uri.fragment();
if(elementGUID != null) {
Collection markers = (Collection) elementGUIToMarkersMap.get(elementGUID);
if(markers != null && !markers.isEmpty()) {
ret = true;
for (Iterator iter = markers.iterator(); iter.hasNext();) {
ValidObject vo = (ValidObject) iter.next();
vo.valid = false;
}
}
}
return ret;
}
}
/**
* @param uri
*/
private void removeExceptions(URI uri) {
synchronized (exceptions) {
Collection exceptions = (Collection) uriToExceptionsMap.get(uri);
if(exceptions == null || exceptions.isEmpty()) return;
this.exceptions.removeAll(exceptions);
uriToExceptionsMap.remove(uri);
}
}
/**
* Clears markers for unresolved proxies of the given resource
*
* @param resource
*/
public void clearMarkers(Resource resource) {
try {
IResource file = FileManager.getResourceForLocation(resource.getURI().toFileString());
if(file instanceof IFile) {
IMarker[] markers = file.findMarkers(IMarker.PROBLEM, false, IResource.DEPTH_ZERO);
for (int i = 0; i < markers.length; i++) {
IMarker marker = markers[i];
removeMarker(marker);
}
}
}
catch(Exception e) {
PersistencePlugin.getDefault().getLogger().logError(e);
}
}
public void removeMarker(IMarker marker) {
String proxyURI = null;
try {
if(marker.exists()) {
proxyURI = (String) marker.getAttribute(PROXY_URI);
marker.delete();
}
} catch (Exception e) {
PersistencePlugin.getDefault().getLogger().logError(e);
}
if(proxyURI != null) {
synchronized(elementGUIToMarkersMap) {
removeFromElementGUIDToMarkersMap(proxyURI, marker);
removeFromResourceGUIDToMarkersMap(proxyURI, marker);
}
}
}
private static class MarkerInfo {
String proxyURI;
String ownerGUID;
String message;
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
public boolean equals(Object obj) {
if(obj instanceof MarkerInfo) {
MarkerInfo info = (MarkerInfo) obj;
if(proxyURI != null && ownerGUID != null && proxyURI.equals(info.proxyURI) && ownerGUID.equals(info.ownerGUID)) {
return true;
}
}
return super.equals(obj);
}
}
/**
* Validates markers for unresolved proxies of the given resource
*
* @param resource
*/
public void validateMarkers(Resource resource) {
boolean newlyAdded = false;
synchronized(resourcesToValidateMarkers) {
newlyAdded = resourcesToValidateMarkers.add(resource);
}
if(newlyAdded) {
schedule(DELAY);
}
}
private void doValidateMarkers(Resource resource) {
try {
IResource file = FileManager.getResourceForLocation(resource.getURI().toFileString());
if(file instanceof IFile) {
IMarker[] markers = file.findMarkers(IMarker.PROBLEM, false, IResource.DEPTH_ZERO);
HashSet markerInfos = new HashSet();
for (int i = 0; i < markers.length; i++) {
IMarker marker = markers[i];
String proxyURI = (String) marker.getAttribute(PROXY_URI);
if(proxyURI != null) {
URI uri = URI.createURI(proxyURI);
// try to get the object with this proxy URI without loading new resource
//
String elementGUID = uri.fragment();
EObject o = (EObject) ((MultiFileResourceSetImpl)resourceSet).getGuidToMethodElementMap().get(elementGUID);
if(o == null || o.eIsProxy()) {
MarkerInfo info = new MarkerInfo();
info.message = (String) marker.getAttribute(IMarker.MESSAGE);
info.ownerGUID = (String) marker.getAttribute(OWNER_GUID);
info.proxyURI = proxyURI;
markerInfos.add(info);
}
if(marker.exists()) {
try {
marker.delete();
}
catch(Exception e) {
PersistencePlugin.getDefault().getLogger().logError(e);
}
}
synchronized(elementGUIToMarkersMap) {
removeFromElementGUIDToMarkersMap(proxyURI, marker);
removeFromResourceGUIDToMarkersMap(proxyURI, marker);
}
}
}
if(!markerInfos.isEmpty()) {
for (Iterator iter = markerInfos.iterator(); iter.hasNext();) {
MarkerInfo info = (MarkerInfo) iter.next();
addMarker(resource, URI.createURI(info.proxyURI), info.message, info.ownerGUID, new NullProgressMonitor());
}
}
}
}
catch(Exception e) {
PersistencePlugin.getDefault().getLogger().logError(e);
}
}
}