blob: 69a77f632a442e6379588757cc069137b981538f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 by SAP AG, Walldorf.
* 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:
* SAP AG - initial API and implementation
*******************************************************************************/
package org.eclipse.jst.ws.jaxws.dom.integration.navigator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.jdt.apt.core.internal.AptPlugin;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeParameter;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.ui.JavaElementImageDescriptor;
import org.eclipse.jdt.ui.ProblemsLabelDecorator;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.jst.ws.jaxws.dom.runtime.DomUtil;
import org.eclipse.jst.ws.jaxws.dom.runtime.api.DomPackage;
import org.eclipse.jst.ws.jaxws.dom.runtime.api.IServiceEndpointInterface;
import org.eclipse.jst.ws.jaxws.dom.runtime.api.IWebMethod;
import org.eclipse.jst.ws.jaxws.dom.runtime.api.IWebParam;
import org.eclipse.jst.ws.jaxws.dom.runtime.api.IWebService;
import org.eclipse.jst.ws.jaxws.dom.runtime.util.Dom2ResourceMapper;
import org.eclipse.jst.ws.jaxws.utils.annotations.AnnotationFactory;
import org.eclipse.jst.ws.jaxws.utils.annotations.IAnnotation;
import org.eclipse.jst.ws.jaxws.utils.annotations.IAnnotationInspector;
import org.eclipse.jst.ws.jaxws.utils.logging.Logger;
import org.eclipse.ui.PlatformUI;
@SuppressWarnings("restriction")
public class WebServiceProblemsDecorator extends ProblemsLabelDecorator
{
private static final String THIS_DECORATOR_ID = "org.eclipse.jst.ws.jaxws.dom.integration.navigator.WebServiceDecorator";
/**
* The APT marker IDs
*/
private static final String APT_MARKER_ID = AptPlugin.APT_COMPILATION_PROBLEM_MARKER;
private static final String APT_NONRECONCILE_MARKER_ID = AptPlugin.APT_NONRECONCILE_COMPILATION_PROBLEM_MARKER;
/** Enum to represent different marker types */
public enum Severity {OK, ERROR, WARNING};
private DomUtil domUtil = DomUtil.INSTANCE;
private final Dom2ResourceMapper dom2ResourceMapper = Dom2ResourceMapper.INSTANCE;
public WebServiceProblemsDecorator()
{
addListener(new ILabelProviderListener()
{
public void labelProviderChanged(LabelProviderChangedEvent event)
{
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable()
{
public void run()
{
PlatformUI.getWorkbench().getDecoratorManager().update(THIS_DECORATOR_ID);
}
});
}
});
}
@Override
protected int computeAdornmentFlags(Object obj)
{
final Severity severity = defineSeverity(obj);
if (severity == Severity.ERROR) {
return JavaElementImageDescriptor.ERROR;
}
if (severity == Severity.WARNING) {
return JavaElementImageDescriptor.WARNING;
}
return 0;
}
/**
* Checks the object's resource for markers and defines the severity of the
* problem if any.
* @param obj
* @return the severity calculated.
*/
protected Severity defineSeverity(final Object obj)
{
try
{
// process additional DOM objects needed for UI - IWebServiceChildList and ISEIChildList
if (obj instanceof IWebServiceChildList) {
return defineSeverityForEList(((IWebServiceChildList)obj).getWSChildList());
}
if (obj instanceof ISEIChildList) {
return defineSeverityForEList(((ISEIChildList)obj).getSEIChildList());
}
// do not process non DOM objects
if( !(obj instanceof EObject) ) {
return Severity.OK;
}
return defineSeverity((EObject) obj);
}
catch (CoreException e) {
(new Logger()).logError(e.getMessage(), e);
}
return Severity.OK;
}
protected Severity defineSeverityForEList(final List<? extends EObject> list) throws CoreException
{
Severity severity = Severity.OK;
for (EObject eObject : list)
{
Severity tempSeverity = defineSeverity(eObject);
if (tempSeverity == Severity.ERROR) {
return Severity.ERROR;
}
if (tempSeverity==Severity.WARNING) {
severity = Severity.WARNING;
}
}
return severity;
}
protected Severity defineSeverity(final EObject eObject) throws CoreException
{
final IResource resource = Dom2ResourceMapper.INSTANCE.findResource(eObject);
if (resource!=null) {
return defineSeverity(eObject, resource);
}
return Severity.OK;
}
protected Severity defineSeverity(final EObject eObject, final IResource resource) throws CoreException
{
if (!resource.isAccessible()) {
return Severity.OK;
}
final int depth = (resource.getType()==IResource.PROJECT) ? IResource.DEPTH_INFINITE : IResource.DEPTH_ZERO;
final Collection<IMarker> markers = findAptMarkers(resource, depth);
Severity severity = Severity.OK;
for (IMarker marker : markers)
{
if (!isRelevantFor(eObject, marker)) {
continue;
}
int tempSeverity = (Integer)marker.getAttribute(IMarker.SEVERITY);
if (tempSeverity==IMarker.SEVERITY_ERROR) {
return Severity.ERROR;
}
if(tempSeverity==IMarker.SEVERITY_WARNING) {
severity = Severity.WARNING;
}
}
if (severity == Severity.OK && (eObject instanceof IWebService))
{
// for bean with explicit interface we need to check the interface as well
// because it resides in another resource
final IServiceEndpointInterface sei = ((IWebService)eObject).getServiceEndpoint();
if (sei != null && !sei.isImplicit()) {
severity = defineSeverity(sei);
}
}
return severity;
}
/**
* Defines if <code>marker</code> is relevant for <code>eObject</code>.
* Only for web method and web parameter we need to define if the marker is relevant
* because they are not unique in the scope of the resource. For example if there is a
* marker set on the resource containing SEI, the SEI should be marked in any case
* while the method only in case when the error is specifically for this method or
* method parameter.
* @param eObject the object to be validated
* @param marker the resource marker
* @return <code>true</code> in case the marker is relevant for <code>eObject</code>
* @throws CoreException
*/
protected boolean isRelevantFor(final EObject eObject, final IMarker marker) throws CoreException
{
switch (eObject.eClass().getClassifierID())
{
case DomPackage.IWEB_METHOD:
return isRelevantForMethod((IWebMethod)eObject, marker);
case DomPackage.IWEB_PARAM:
return isRelevantForParameter((IWebParam)eObject, marker);
}
return true;
}
/**
* Defines if <code>marker</code> is relevant for <code>webMethod</code>.
* Checks if the marker is specifically for this method or some of it's parameters.
* @param webMethod the method to be checked
* @param marker the marker to be checked
* @return <code>true</code> in case marker is relevant
* @throws CoreException
*/
protected boolean isRelevantForMethod(final IWebMethod webMethod, final IMarker marker) throws CoreException
{
final IType type = dom2ResourceMapper.findType(webMethod);
final IMethod javaMethod = domUtil.findMethod(type, webMethod);
final IAnnotationInspector annotationInspector = AnnotationFactory.createAnnotationInspector(type);
boolean relevant = isMarkerRelevantFor(javaMethod, marker, annotationInspector);
if (!relevant)
{
for (String methodParameterName : javaMethod.getParameterNames())
{
final ITypeParameter param = javaMethod.getTypeParameter(methodParameterName);
relevant = relevant || isMarkerRelevantFor(param, marker, annotationInspector);
}
}
return relevant;
}
protected boolean isRelevantForParameter(final IWebParam webParam, final IMarker marker) throws CoreException
{
final IType type = dom2ResourceMapper.findType(webParam);
final ITypeParameter javaParameter = findJavaParameter(type, webParam);
return isMarkerRelevantFor(javaParameter, marker, AnnotationFactory.createAnnotationInspector(type));
}
/**
* Finds the {@link ITypeParameter} instance which corresponds to the web parameter specified
*/
private ITypeParameter findJavaParameter(final IType type, final IWebParam webParam) throws JavaModelException
{
final IMethod javaMethod = domUtil.findMethod(type, (IWebMethod) webParam.eContainer());
for (String paramName : javaMethod.getParameterNames())
{
final ITypeParameter javaParam = javaMethod.getTypeParameter(paramName);
if (webParam.getImplementation().equals(javaParam.getElementName()))
{
return javaParam;
}
}
throw new IllegalStateException("Parameter " + webParam.getImplementation() + " not found");
}
private boolean isMarkerRelevantFor(final IMethod javaMethod, final IMarker marker, final IAnnotationInspector inspector) throws CoreException
{
for (IAnnotation<IMethod> ann : inspector.inspectMethod(javaMethod))
{
if (isMarkerRelevantToAnnotation(marker, ann))
{
return true;
}
}
return false;
}
private boolean isMarkerRelevantFor(final ITypeParameter parameter, final IMarker marker, final IAnnotationInspector inspector) throws CoreException
{
for (IAnnotation<ITypeParameter> ann : inspector.inspectParam(parameter))
{
if (isMarkerRelevantToAnnotation(marker, ann))
{
return true;
}
}
return false;
}
/**
* Check whether the marker is relevant for the annotation specified<br>
* The implementation would read all the annotations relevant for the java element and check whether the marker start/end position is between annotation start/end
*/
private boolean isMarkerRelevantToAnnotation(final IMarker marker, final IAnnotation<? extends IJavaElement> ann) throws CoreException
{
final int annStartPos = ann.getLocator().getStartPosition();
final int annEndPos = annStartPos + ann.getLocator().getLength() - 1;
return (annStartPos <= (Integer) marker.getAttribute(IMarker.CHAR_START)) && (annEndPos >= (Integer) marker.getAttribute(IMarker.CHAR_END));
}
/**
* Finds all APT nonreconcile markers associated with the resource specified
*/
private Collection<IMarker> findAptMarkers(final IResource resource, final int depth) throws CoreException
{
final Collection<IMarker> result = new ArrayList<IMarker>();
// Search for both APT marker types. One of each IDs is used on Linux and Windows
for(final IMarker m : resource.findMarkers(APT_MARKER_ID, false, depth))
{
result.add(m);
}
for(final IMarker m : resource.findMarkers(APT_NONRECONCILE_MARKER_ID, false, depth))
{
result.add(m);
}
return result;
}
}