/*******************************************************************************
* Copyright (c) 2013, 2015 CEA LIST 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:
* E.D.Willink (CEA LIST) - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.pivot.uml.internal.validation;
import org.apache.log4j.Logger;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.notify.Notification;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.validation.IValidationContext;
import org.eclipse.emf.validation.model.ConstraintSeverity;
import org.eclipse.emf.validation.model.EvaluationMode;
import org.eclipse.emf.validation.model.IModelConstraint;
import org.eclipse.emf.validation.service.AbstractConstraintDescriptor;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.pivot.Constraint;
import org.eclipse.ocl.pivot.ExpressionInOCL;
import org.eclipse.ocl.pivot.LanguageExpression;
import org.eclipse.ocl.pivot.NamedElement;
import org.eclipse.ocl.pivot.internal.prettyprint.PrettyPrinter;
import org.eclipse.ocl.pivot.util.PivotPlugin;
import org.eclipse.ocl.pivot.utilities.MetamodelManager;
import org.eclipse.ocl.pivot.utilities.OCL;
import org.eclipse.ocl.pivot.utilities.ParserException;
import org.eclipse.uml2.uml.Stereotype;
/**
* A LoadableConstraintDescriptor realizes both an IConstraintDescriptor and IModelConstraint
* to support a Constraint derived from loading some model source. The resulting desciptor
* is suitable for use with the EMF.Valitation framework.
*/
public abstract class LoadableConstraintDescriptor<T> extends AbstractConstraintDescriptor implements IModelConstraint
{
public static class Ecore extends LoadableConstraintDescriptor<EClassifier>
{
public Ecore(@NonNull EClassifier targetType, @NonNull Constraint constraint, int code) {
super(targetType, constraint, targetType.getEPackage().getNsURI(), targetType.getName(), code);
}
@Override
public boolean targetsTypeOf(EObject eObject) {
return targetType.isInstance(eObject);
}
}
public static class UML extends LoadableConstraintDescriptor<Stereotype>
{
public UML(@NonNull Stereotype targetType, @NonNull Constraint constraint, int code) {
super(targetType, constraint, targetType.getNearestPackage().getURI(), targetType.getName(), code);
}
protected boolean isKindOf(@NonNull String nsURI, @NonNull String name, EClass eClass) {
if (name.equals(eClass.getName())) {
EPackage ePackage = eClass.getEPackage();
if (nsURI.equals(ePackage.getNsURI())) {
return true;
}
}
for (EClass eSuperClass : eClass.getESuperTypes()) {
if (isKindOf(nsURI, name, eSuperClass)) {
return true;
}
}
return false;
}
@Override
public boolean targetsTypeOf(EObject eObject) {
EClass eClass = eObject.eClass();
String nsURI = targetType.getProfile().getURI();
if (nsURI == null) {
return false;
}
String name = targetType.getName();
if (name == null) {
return false;
}
return isKindOf(nsURI, name, eClass);
}
}
private static final Logger logger = Logger.getLogger(LoadableConstraintDescriptor.class);
private final @NonNull Constraint constraint;
protected final @NonNull T targetType;
private final @NonNull String id;
private final @NonNull String name;
private final int code;
private ExpressionInOCL query = null;
public LoadableConstraintDescriptor(@NonNull T targetType, @NonNull Constraint constraint,
String targetNamespace, String targetName, int code) {
this.constraint = constraint;
this.targetType = targetType;
String name = constraint.getName();
if (name == null) {
name = Long.toHexString(System.identityHashCode(constraint));
}
id = "'" + targetNamespace + "'::" + targetName + "::" + name;
this.name = targetName + "::" + name;
this.code = code;
}
final Constraint getConstraint() {
return constraint;
}
@Override
public String getBody() {
return PrettyPrinter.print(constraint);
}
@Override
public String getDescription() {
return getBody();
}
@Override
public EvaluationMode<?> getEvaluationMode() {
return EvaluationMode.BATCH;
}
@Override
public String getId() {
return id;
}
@Override
public String getMessagePattern() {
return String.format("Constraint %s violated on {0}", getName()); //$NON-NLS-1$
}
@Override
public String getName() {
return name;
}
@Override
public String getPluginId() {
return PivotPlugin.PLUGIN_ID;
}
@Override
public ConstraintSeverity getSeverity() {
return ConstraintSeverity.WARNING;
}
@Override
public int getStatusCode() {
return code;
}
@Override
public boolean targetsEvent(Notification notification) {
return false;
}
@Override
public IStatus validate(IValidationContext ctx) {
EObject target = ctx.getTarget();
if (target == null) {
return ctx.createFailureStatus(target);
}
OCL ocl = LoadableConstraintProvider.getOCL();
ExpressionInOCL query2 = query;
if (query2 == null) {
MetamodelManager metamodelManager = ocl.getMetamodelManager();
EClass eClass = target.eClass();
NamedElement contextElement = null;
try {
contextElement = metamodelManager.getASOf(NamedElement.class, eClass);
} catch (ParserException e) {
logger.error("Failed to convert " + eClass, e);
}
if (contextElement == null) {
return ctx.createFailureStatus(target);
}
LanguageExpression specification = constraint.getOwnedSpecification();
if (specification == null) {
return ctx.createFailureStatus(target);
}
try {
query = query2 = metamodelManager.parseSpecification(specification);
} catch (ParserException e) {
return ctx.createFailureStatus(e.getLocalizedMessage());
}
}
Object result = ocl.evaluate(target, query2);
if (result != Boolean.TRUE) {
return ctx.createFailureStatus(target);
}
return ctx.createSuccessStatus();
}
}