| /******************************************************************************* |
| * Copyright (c) 2016 ALL4TEC & CEA LIST. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * ALL4TEC & CEA LIST - initial API and implementation |
| ******************************************************************************/ |
| package org.polarsys.esf.core.common.adapter; |
| |
| import java.util.HashSet; |
| import java.util.LinkedHashMap; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.util.BasicDiagnostic; |
| import org.eclipse.emf.common.util.Diagnostic; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.util.EContentAdapter; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.polarsys.esf.core.common.CommonActivator; |
| import org.polarsys.esf.core.common.listener.IProblemIndicationListener; |
| |
| |
| /** |
| * Content adapter used to analyse resources content and build the problem indication. |
| * It maintains a set of listeners to warn when a new diagnostic is built. |
| * |
| * NB : It extends {@link EContentAdapter} to listen to all the changes on a resource and its content. |
| * |
| * @author $Author: jdumont $ |
| * @version $Revision: 83 $ |
| */ |
| public class ProblemIndicationAdapter extends EContentAdapter { |
| |
| /** Map to store the diagnostic associated with a resource. */ |
| private Map<Resource, Diagnostic> mResourceToDiagnosticMap = new LinkedHashMap<Resource, Diagnostic>(); |
| |
| /** Set of listening objects, waiting for the diagnostics results. */ |
| private Set<IProblemIndicationListener> mListenersSet = new HashSet<IProblemIndicationListener>(); |
| |
| |
| /** |
| * Default constructor. |
| */ |
| public ProblemIndicationAdapter() { |
| // Nothing to do |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public void notifyChanged(final Notification pNotification) { |
| |
| // Check if the notification come from a Resource |
| if (pNotification.getNotifier() instanceof Resource) { |
| // Switch according to the properties modified, the resource can |
| // be loading, or errors/warning can be identified |
| switch (pNotification.getFeatureID(Resource.class)) { |
| case Resource.RESOURCE__IS_LOADED: |
| case Resource.RESOURCE__ERRORS: |
| case Resource.RESOURCE__WARNINGS: |
| // Get the resource underlying the notification |
| Resource vResource = (Resource) pNotification.getNotifier(); |
| |
| // Analyse the resource and get its diagnostic |
| Diagnostic vDiagnostic = analyzeResourceProblems(vResource, null); |
| |
| // If any error found, store it in the diagnostic map |
| // otherwise clean the potential existing diagnostic associated |
| // to this resource |
| if (vDiagnostic.getSeverity() != Diagnostic.OK) { |
| mResourceToDiagnosticMap.put(vResource, vDiagnostic); |
| } else { |
| mResourceToDiagnosticMap.remove(vResource); |
| } |
| |
| // Warn all the listeners that the diagnostics has changed |
| fireProblemIndication(); |
| |
| break; |
| |
| default: |
| // By default, nothing to do |
| break; |
| } |
| |
| } else { |
| // Call the parent method for all the others type of notifiers |
| super.notifyChanged(pNotification); |
| } |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected void setTarget(final Resource pTargetResource) { |
| // Set the resource to listen |
| basicSetTarget(pTargetResource); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| protected void unsetTarget(final Resource pTargetResource) { |
| // Unset the resource to listen |
| basicUnsetTarget(pTargetResource); |
| |
| // Clean all the diagnostics linked to the previously listened resource |
| mResourceToDiagnosticMap.remove(pTargetResource); |
| |
| // Warn all the listeners that the diagnostics has changed |
| fireProblemIndication(); |
| } |
| |
| /** |
| * Returns a diagnostic describing the errors and warnings listed in the resource |
| * and the specified exception (if any). |
| * |
| * @param pResource The resource to analyse |
| * @param pException The potential exception thrown during the resource creation or load. May be null |
| * @return The resulting diagnostic |
| */ |
| private Diagnostic analyzeResourceProblems(final Resource pResource, final Exception pException) { |
| // Create the default diagnostic to return |
| Diagnostic vDiagnostic = Diagnostic.OK_INSTANCE; |
| |
| if (pResource == null) { |
| // The resource is null, create a basic error diagnostic |
| vDiagnostic = new BasicDiagnostic( |
| Diagnostic.ERROR, |
| CommonActivator.getPlugin().getSymbolicName(), |
| 0, |
| CommonActivator.getMessages().getString( |
| "ProblemIndicationAdapter.diagnostics.error.null"), //$NON-NLS-1$ |
| new Object[] {pException }); |
| |
| } else if (!pResource.getErrors().isEmpty() || !pResource.getWarnings().isEmpty()) { |
| // Build the diagnostic data with the given exception, or the resource directly |
| Object[] vDataArray = null; |
| if (pException == null) { |
| vDataArray = new Object[] {pException }; |
| } else { |
| vDataArray = new Object[] {pResource }; |
| } |
| |
| // The resource is invalid, create a basic error diagnostic |
| vDiagnostic = new BasicDiagnostic( |
| Diagnostic.ERROR, |
| CommonActivator.getPlugin().getSymbolicName(), |
| 0, |
| CommonActivator.getMessages().getString( |
| "ProblemIndicationAdapter.diagnostics.error.creation", //$NON-NLS-1$ |
| new Object[] {pResource.getURI()}), |
| vDataArray); |
| |
| // Add the details in the root diagnostic |
| ((BasicDiagnostic) vDiagnostic).merge(EcoreUtil.computeDiagnostic(pResource, true)); |
| |
| } else if (pException != null) { |
| // An exception is given, create a basic diagnostic for it |
| vDiagnostic = new BasicDiagnostic( |
| Diagnostic.ERROR, |
| CommonActivator.getPlugin().getSymbolicName(), |
| 0, |
| CommonActivator.getMessages().getString( |
| "ProblemIndicationAdapter.diagnostics.error.exception", //$NON-NLS-1$ |
| new Object[] {pResource.getURI()}), |
| new Object[] {pException }); |
| } |
| |
| return vDiagnostic; |
| } |
| |
| |
| /** |
| * Analyse a resource, given in parameter, to identify its potential problems. |
| * All the errors or warnings found are saved to be able to build a global diagnostic |
| * and transfer it to the listeners at the end of this method execution. |
| * |
| * An exception can be given, to be integrated to the diagnostics, for example if it has |
| * been thrown during the resource load or save. |
| * |
| * @param pResource The resource to analyse |
| * @param pException The potential exception thrown during the resource creation or load. May be null |
| */ |
| public void analyzeResource(final Resource pResource, final Exception pException) { |
| |
| boolean vDiagnosticsChanged = false; |
| |
| // If the resource is not already registered with a problem, |
| // do its analyse, potentially with the given exception, and |
| // remember of the resulting diagnostic |
| if (!mResourceToDiagnosticMap.containsKey(pResource)) { |
| |
| // Analyse the resource and get the resulting diagnostic |
| Diagnostic vDiagnostic = analyzeResourceProblems(pResource, pException); |
| |
| // If an error is identified, register it in the map of diagnostic, for this resource |
| if (vDiagnostic.getSeverity() != Diagnostic.OK) { |
| mResourceToDiagnosticMap.put(pResource, vDiagnostic); |
| |
| // Remember that the diagnostics have changed |
| vDiagnosticsChanged = true; |
| } |
| } |
| |
| // Once the analysis is done, warn the listener if the diagnostics changed |
| if (vDiagnosticsChanged) { |
| fireProblemIndication(); |
| } |
| } |
| |
| /** |
| * Return a root diagnostic containing as children all the diagnostics |
| * for each analysed resource. |
| * |
| * The diagnostics are taken from the current state, resulting of the analysis |
| * previously done by this adapter. |
| * |
| * @return The current diagnostic |
| */ |
| public Diagnostic getDiagnostic() { |
| // Create the root diagnostic to enrich with the identified diagnostics |
| BasicDiagnostic vRootDiagnostic = new BasicDiagnostic( |
| Diagnostic.OK, |
| CommonActivator.getPlugin().getSymbolicName(), |
| 0, |
| null, |
| null); |
| |
| // Loop on the diagnostics identified, and add them to the root |
| // if they correspond to an error or a warning |
| for (Diagnostic vChildDiagnostic : mResourceToDiagnosticMap.values()) { |
| if (vChildDiagnostic.getSeverity() != Diagnostic.OK) { |
| vRootDiagnostic.add(vChildDiagnostic); |
| } |
| } |
| |
| return vRootDiagnostic; |
| } |
| |
| /** |
| * Add a listener for the diagnostics results. |
| * This has no effect if an identical listener is already registered. |
| * |
| * @param pListener The new listener to add |
| */ |
| public void addProblemIndicationListener(final IProblemIndicationListener pListener) { |
| mListenersSet.add(pListener); |
| } |
| |
| /** |
| * Remove the given listener. |
| * This has no affect if the listener is not registered. |
| * |
| * @param pListener The listener to remove |
| */ |
| public void removeProblemIndicationListener(final IProblemIndicationListener pListener) { |
| mListenersSet.remove(pListener); |
| } |
| |
| /** |
| * Warn all the listeners that a new diagnostic has been built. |
| */ |
| private void fireProblemIndication() { |
| // Get the new root diagnostic |
| Diagnostic vDiagnostic = getDiagnostic(); |
| |
| // Warn all the listeners |
| for (IProblemIndicationListener vListener : mListenersSet) { |
| vListener.updateProblemIndication(vDiagnostic); |
| } |
| |
| } |
| |
| } |