| /* |
| * Copyright (c) 2012, 2016 CEA 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: |
| * Christian W. Damus (CEA) - initial API and implementation |
| * Kenn Hussey (CEA) - 509329 |
| */ |
| package org.eclipse.uml2.uml.validation; |
| |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.emf.common.util.BasicDiagnostic; |
| import org.eclipse.emf.common.util.Diagnostic; |
| import org.eclipse.emf.common.util.DiagnosticChain; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.EValidator; |
| import org.eclipse.emf.validation.IValidationContext; |
| import org.eclipse.emf.validation.model.ConstraintStatus; |
| import org.eclipse.emf.validation.model.IConstraintStatus; |
| import org.eclipse.emf.validation.model.IModelConstraint; |
| import org.eclipse.emf.validation.service.IConstraintDescriptor; |
| import org.eclipse.uml2.uml.UMLPlugin; |
| |
| /** |
| * Implementation of a constraint that delegates to an {@link EPackage}'s |
| * constraints via its generated {@link EValidator}. |
| */ |
| class DelegatingModelConstraint |
| implements IModelConstraint { |
| |
| private final IConstraintDescriptor descriptor; |
| |
| private final EValidator delegate; |
| |
| private final EValidator.SubstitutionLabelProvider labelProvider; |
| |
| private final Method constraintMethod; |
| |
| /** |
| * Initializes me. |
| */ |
| DelegatingModelConstraint(String namespace, EValidator delegate, |
| EValidator.SubstitutionLabelProvider labelProvider, EClass target, |
| Method constraintMethod) { |
| // strip the type-qualifying part off of the validator method name |
| String name = constraintMethod.getName(); |
| String expectedPrefix = String.format("validate%s_validate", //$NON-NLS-1$ |
| target.getName()); |
| if (name.startsWith(expectedPrefix)) { |
| name = name.substring(expectedPrefix.length()); |
| } |
| |
| this.descriptor = new DelegatingConstraintDescriptor(namespace, target, |
| name); |
| this.delegate = delegate; |
| this.labelProvider = labelProvider; |
| this.constraintMethod = constraintMethod; |
| } |
| |
| public final IConstraintDescriptor getDescriptor() { |
| return descriptor; |
| } |
| |
| public IStatus validate(IValidationContext ctx) { |
| IStatus result; |
| |
| final ContextAdapter ctxAdapter = ContextAdapter.getInstance(ctx); |
| final BasicDiagnostic diagnostics = ctxAdapter.getDiagnostics(); |
| final Map<Object, Object> contextMap = ctxAdapter.getContextMap(); |
| |
| try { |
| // pass the label provider (if any) to the validator |
| contextMap.put(EValidator.SubstitutionLabelProvider.class, |
| labelProvider); |
| |
| boolean isOK = (Boolean) constraintMethod.invoke(delegate, |
| ctx.getTarget(), diagnostics, contextMap); |
| |
| if (isOK) { |
| result = ctx.createSuccessStatus(); |
| } else { |
| final int count = diagnostics.getChildren().size(); |
| |
| switch (count) { |
| case 0 : |
| result = ctx.createFailureStatus(getDescriptor() |
| .getName()); |
| break; |
| case 1 : |
| result = toConstraintStatus(ctx, diagnostics |
| .getChildren().get(0)); |
| break; |
| default : |
| List<IStatus> statuses = new java.util.ArrayList<IStatus>( |
| diagnostics.getChildren().size()); |
| for (Diagnostic next : diagnostics.getChildren()) { |
| statuses.add(toConstraintStatus(ctx, next)); |
| } |
| result = ConstraintStatus.createMultiStatus(ctx, |
| statuses); |
| break; |
| } |
| } |
| } catch (InvocationTargetException e) { |
| // disable this constraint in future validation operations |
| ctx.disableCurrentConstraint(e.getTargetException()); |
| |
| result = ConstraintStatus.createStatus(ctx, ctx.getTarget(), ctx |
| .getResultLocus(), IStatus.WARNING, getDescriptor() |
| .getStatusCode(), UMLPlugin.INSTANCE |
| .getString("_UI_Validation_runtimeError"), //$NON-NLS-1$ |
| getDescriptor().getException().getMessage()); |
| } catch (Exception e) { |
| // disable this constraint in future validation operations |
| ctx.disableCurrentConstraint(e); |
| |
| result = ConstraintStatus.createStatus(ctx, ctx.getTarget(), ctx |
| .getResultLocus(), IStatus.WARNING, getDescriptor() |
| .getStatusCode(), UMLPlugin.INSTANCE |
| .getString("_UI_Validation_linkageError"), //$NON-NLS-1$ |
| e.getMessage()); |
| } |
| |
| return result; |
| } |
| |
| private static IConstraintStatus toConstraintStatus(IValidationContext ctx, |
| Diagnostic diagnostic) { |
| final EObject target = ctx.getTarget(); |
| |
| // collect the "result locus" on which to create problem markers, or |
| // whatever |
| List<EObject> resultLocus = new java.util.ArrayList<EObject>(3); |
| for (Object next : diagnostic.getData()) { |
| if ((next != target) && (next instanceof EObject)) { |
| resultLocus.add((EObject) next); |
| } |
| } |
| |
| return ConstraintStatus.createStatus(ctx, target, resultLocus, |
| diagnostic.getSeverity(), diagnostic.getCode(), "{0}", //$NON-NLS-1$ |
| diagnostic.getMessage()); |
| } |
| |
| // |
| // Nested types |
| // |
| |
| /** |
| * A translation from the EMF Validation Framework's |
| * {@link IValidationContext}-based API to EMF's {@link DiagnosticChain}- |
| * and map-based API. A weak mapping ensures that the same adapters are |
| * reused as appropriate for any given instance of the validation context. |
| */ |
| private static final class ContextAdapter { |
| |
| private static final Map<IValidationContext, ContextAdapter> contextAdapters = new java.util.WeakHashMap<IValidationContext, ContextAdapter>(); |
| |
| private Map<Object, Object> contextMap = new java.util.HashMap<Object, Object>(); |
| |
| private BasicDiagnostic diagnostics; |
| |
| ContextAdapter() { |
| super(); |
| } |
| |
| static ContextAdapter getInstance(IValidationContext ctx) { |
| ContextAdapter result = contextAdapters.get(ctx); |
| |
| if (result == null) { |
| result = new ContextAdapter(); |
| contextAdapters.put(ctx, result); |
| } |
| |
| return result; |
| } |
| |
| Map<Object, Object> getContextMap() { |
| return contextMap; |
| } |
| |
| BasicDiagnostic getDiagnostics() { |
| if ((diagnostics != null) && !diagnostics.getChildren().isEmpty()) { |
| // self-destruct a diagnostic that previously had problems added |
| // to it |
| diagnostics = null; |
| } |
| |
| if (diagnostics == null) { |
| diagnostics = new BasicDiagnostic(); |
| } |
| |
| return diagnostics; |
| } |
| } |
| } |