blob: 6dadcedb1f6a56a0cd20910a219395ad752d6b6f [file] [log] [blame]
/*
-----------------------------------------------------------------------
-- CHESS Live/Batch Validator plugin --
-- --
-- Copyright (C) 2011-2012 --
-- University of Padova, ITALY --
-- --
-- Author: Stefano Puri --
-- --
-- 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-v20.html --
-----------------------------------------------------------------------
*/
package org.polarsys.chess.validator.constraints;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.uml2.uml.Component;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.ParameterDirectionKind;
import org.eclipse.uml2.uml.Realization;
import org.eclipse.uml2.uml.Relationship;
import org.eclipse.uml2.uml.Stereotype;
import org.eclipse.emf.validation.AbstractModelConstraint;
import org.eclipse.emf.validation.IValidationContext;
import org.polarsys.chess.chessmlprofile.util.Constants;
/**
* The Class FV_03.
* This class implements the following constraint (invoked by the EMF validation framework):
* The ComponentImplementation must define the same operation as the ComponentType it realizes
*/
public class FV_03 extends AbstractModelConstraint {
/* (non-Javadoc)
* @see org.eclipse.emf.validation.AbstractModelConstraint#validate(org.eclipse.emf.validation.IValidationContext)
*/
@Override
public IStatus validate(IValidationContext ctx) {
EObject eObject = ctx.getTarget();
Component component = (Component)eObject;
IStatus success = ctx.createSuccessStatus();
Stereotype componentImplStereo = component.getAppliedStereotype(Constants.COMPONENT_IMPLEMENTATION);
if (componentImplStereo!=null) {
// This is a ComponentImplementation
int count=0;
Component realizedComponent = null;
for (Relationship rel : component.getRelationships()) {
// The component must realize exactly one <<ComponentType>>
if ((rel instanceof Realization)) {
//skip InterfaceRealizations ...
// Browse realization's clients
Boolean isClient=false;
for (NamedElement elem : ((Realization) rel).getClients()) {
if (elem.equals(component)) {
isClient=true;
}
}
if (isClient) {
//check if it realizes a component type
for (NamedElement elem : ((Realization) rel).getSuppliers()) {
Stereotype componentType = elem.getAppliedStereotype(Constants.COMPONENT_TYPE);
if (componentType!=null) {
realizedComponent=(Component) elem;
count++;
}
}
}
}
}
if (count!=1) {
String componentName = "";
componentName = component.getName();
String errorMsg = "The componentImplementation " + componentName + " must realize exactly one <<ComponentType>> (Currently : " + count +")";
IStatus failure = ctx.createFailureStatus(
component,
errorMsg
);
return failure;
}
else {
// Additional constraint.
// A ComponentImplementation has to define the same operations as the ComponentType it realizes
for (Operation ctOp : realizedComponent.getOperations()) {
// So for operation ctOp, the component has to define the same operation
Boolean opFound=false;
for (Operation op : component.getOperations()) {
if ( compareOperations(ctOp, op) ) {
opFound=true;
}
}
if (!opFound) {
String componentName = "";
componentName = component.getName();
String errorMsg = "The ComponentImplementation " + componentName + " must define the same operation " + ctOp.getName() + " as the ComponentType it realizes";
IStatus failure = ctx.createFailureStatus(
component,
errorMsg
);
return failure;
}
}
}
}
return success;
}
/**
* Compare operations.
*
* @param op1 the op1
* @param op2 the op2
* @return the boolean
*/
private Boolean compareOperations(Operation op1, Operation op2) {
Boolean result = true;
// Compare names
if (!op1.getName().equals(op2.getName())) {
result=false;
}
else {
// Compare return types
if (op1.getType() != op2.getType()) {
result=false;
}
else {
// Compare the number of parameters
Collection<Parameter> params1 = removeReturnParameter(op1.getOwnedParameters());
Collection<Parameter> params2 = removeReturnParameter(op2.getOwnedParameters());
if (params1.size() != params2.size() ) {
result=false;
}
else {
Iterator<Parameter> it1 = params1.iterator();
Iterator<Parameter> it2 = params2.iterator();
while (it1.hasNext()) {
Parameter p1 = it1.next();
Parameter p2 = it2.next();
if (p1.getType()!=p2.getType()) {
result=false;
break;
}
}
}
}
}
return result;
}
/**
* Removes the return parameter.
*
* @param ownedParameters the owned parameters
* @return the collection
*/
private Collection<Parameter> removeReturnParameter(
EList<Parameter> ownedParameters) {
Collection<Parameter> result = new ArrayList<Parameter>();
for (Parameter p : ownedParameters) {
if (!p.getDirection().equals(ParameterDirectionKind.get(ParameterDirectionKind.RETURN))) {
result.add(p);
}
}
return result;
}
}