/*******************************************************************************
* This file is protected by Copyright.
* Please refer to the COPYRIGHT file distributed with this source distribution.
*
* This file is part of REDHAWK IDE.
*
* 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
*******************************************************************************/
package gov.redhawk.ide.builders;
import java.util.HashMap;
import java.util.Map;
import mil.jpeojtrs.sca.validator.AdvancedEObjectValidator;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.notify.AdapterFactory;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EValidator;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.ecore.util.EObjectValidator;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.edit.provider.IItemLabelProvider;
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
/**
* Utility class for propagating EMF Validation errors to the Problems View.
* Heavily borrows from org.eclipse.emf.validation.marker.MarkerUtil class.
*/
public enum SCAMarkerUtil {
INSTANCE;
public static final String VALIDATION_MARKER_TYPE = "gov.redhawk.ide.emf.validation.problem"; //$NON-NLS-1$
public static final String RULE_ATTRIBUTE = "rule"; //$NON-NLS-1$
private static final String PLATFORM_SCHEME = "platform"; //$NON-NLS-1$
private static final String FILE_SCHEME = "file"; //$NON-NLS-1$
private static final String RESOURCE_SEGMENT = "resource"; //$NON-NLS-1$
private final Diagnostician diagnostician = new Diagnostician() {
@Override
public String getObjectLabel(final EObject eObject) {
if (!eObject.eIsProxy()) {
final IItemLabelProvider itemLabelProvider = (IItemLabelProvider) getAdapterFactory().adapt(eObject, IItemLabelProvider.class);
if (itemLabelProvider != null) {
return itemLabelProvider.getText(eObject);
}
}
return super.getObjectLabel(eObject);
}
};
private final ComposedAdapterFactory adapterFactory = new ComposedAdapterFactory(ComposedAdapterFactory.Descriptor.Registry.INSTANCE);
private final Map<URI, IFile> visitedResources = new HashMap<URI, IFile>();
/**
* Constructor.
*/
private SCAMarkerUtil() {
this.adapterFactory.addAdapterFactory(new ResourceItemProviderAdapterFactory());
this.adapterFactory.addAdapterFactory(new ReflectiveItemProviderAdapterFactory());
}
/**
* Returns an IFile for the specified resource.
*
* @param resource
* the resource to
* @return a cached IFile if it exists, otherwise gets file from workspace
* root based on uri
* @throws CoreException
*/
private IFile getFile(final Resource resource) throws CoreException {
URI uri = resource.getURI();
// Normalize the URI to something that we can deal with like file or
// platform scheme
uri = resource.getResourceSet().getURIConverter().normalize(uri);
IFile file = this.visitedResources.get(uri);
if (file == null) {
if (SCAMarkerUtil.PLATFORM_SCHEME.equals(uri.scheme()) && uri.segmentCount() > 1 && SCAMarkerUtil.RESOURCE_SEGMENT.equals(uri.segment(0))) {
final StringBuffer platformResourcePath = new StringBuffer();
for (int j = 1, size = uri.segmentCount(); j < size; ++j) {
platformResourcePath.append('/');
platformResourcePath.append(URI.decode(uri.segment(j)));
}
file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(platformResourcePath.toString()));
} else if (SCAMarkerUtil.FILE_SCHEME.equals(uri.scheme())) {
final StringBuffer fileResourcePath = new StringBuffer();
for (int j = 1, size = uri.segmentCount(); j < size; ++j) {
fileResourcePath.append('/');
fileResourcePath.append(URI.decode(uri.segment(j)));
}
file = ResourcesPlugin.getWorkspace().getRoot().getFileForLocation(new Path(fileResourcePath.toString()));
}
if (file != null) {
file.deleteMarkers(SCAMarkerUtil.VALIDATION_MARKER_TYPE, true, IResource.DEPTH_ZERO);
this.visitedResources.put(uri, file);
}
}
return file;
}
private AdapterFactory getAdapterFactory() {
return this.adapterFactory;
}
/**
* Creates the marker on the specified IFile from the provided Diagnostic.
*
* @param file
* @param resource
* @param diagnostic
* @throws CoreException
*/
private void createMarker(final IFile file, final Resource resource, final Diagnostic diagnostic) throws CoreException {
final IMarker marker = file.createMarker(SCAMarkerUtil.VALIDATION_MARKER_TYPE);
switch (diagnostic.getSeverity()) {
case IStatus.INFO:
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_INFO);
marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_LOW);
break;
case IStatus.WARNING:
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING);
marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_NORMAL);
break;
case IStatus.ERROR:
case IStatus.CANCEL:
marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH);
break;
default:
break;
}
marker.setAttribute(IMarker.SOURCE_ID, diagnostic.getSource());
marker.setAttribute(IMarker.PROBLEM, diagnostic.getCode());
marker.setAttribute(IMarker.MESSAGE, diagnostic.getMessage());
if (diagnostic.getData().size() > 0 && diagnostic.getData().get(0) instanceof EObject) {
marker.setAttribute(EValidator.URI_ATTRIBUTE, EcoreUtil.getURI((EObject) diagnostic.getData().get(0)).toString());
if (diagnostic.getData().size() > 1 && diagnostic.getData().get(1) instanceof EStructuralFeature) {
final EStructuralFeature feature = (EStructuralFeature) diagnostic.getData().get(1);
marker.setAttribute(AdvancedEObjectValidator.FEATURE_ID, feature.getFeatureID());
marker.setAttribute(IMarker.LOCATION, feature.getName());
}
} else {
marker.setAttribute(EValidator.URI_ATTRIBUTE, resource.getURI().toString());
}
if (marker.getAttribute(IMarker.LOCATION) == null) {
marker.setAttribute(IMarker.LOCATION, " ");
}
}
private void analyzeDiagnostic(final IFile file, final Resource resource, final Diagnostic diagnostic) throws CoreException {
if (EObjectValidator.DIAGNOSTIC_SOURCE.equals(diagnostic.getSource()) && diagnostic.getCode() == EObjectValidator.EOBJECT__EVERY_DATA_VALUE_CONFORMS) {
createMarker(file, resource, diagnostic);
} else if (diagnostic.getChildren().isEmpty()) {
if (diagnostic.getSeverity() == IStatus.WARNING || diagnostic.getSeverity() == IStatus.ERROR) {
createMarker(file, resource, diagnostic);
}
} else {
for (final Diagnostic child : diagnostic.getChildren()) {
analyzeDiagnostic(file, resource, child);
}
}
}
/**
* Creates markers for the specified diagnostic and resource.
*
* @param eResource
* the Resource to create markers for
* @param diagnostic
* the Diagnostic to process
* @throws CoreException
*/
public void createMarkers(final Resource eResource, final Diagnostic diagnostic) throws CoreException {
final IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
@Override
public void run(final IProgressMonitor m) throws CoreException {
final IFile file = getFile(eResource);
if (file != null) {
file.deleteMarkers(SCAMarkerUtil.VALIDATION_MARKER_TYPE, true, IResource.DEPTH_ZERO);
analyzeDiagnostic(file, eResource, diagnostic);
}
}
};
ResourcesPlugin.getWorkspace().run(runnable, null);
}
/**
* Returns the Diagnostician instance.
*
* @return
*/
public Diagnostician getDiagnostician() {
return this.diagnostician;
}
}