/*******************************************************************************
* Copyright (c) 2008, 2014 Obeo 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:
* Stephane Begaudeau (Obeo) - initial API and implementation
*******************************************************************************/
package org.eclipse.umlgen.gen.java.services;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Generalization;
import org.eclipse.uml2.uml.Interface;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.VisibilityKind;
/**
* Various services for the classifiers.
*
* @author <a href="mailto:stephane.begaudeau@obeo.fr">Stephane Begaudeau</a>
* @since 2.0
*/
public class ClassifierServices {
/**
* get all inherited operations from the given UML class.
*
* @param aClass
* The UML class.
* @return The list of operations.
*/
public List<Operation> getAllInheritedOperations(org.eclipse.uml2.uml.Class aClass) {
LinkedHashSet<Operation> inheritedOperations = new LinkedHashSet<Operation>();
// Everything inherited from the classes
List<Class> allGeneralizedClasses = this.getAllGeneralizedClasses(aClass);
for (Class aGeneralizedClass : allGeneralizedClasses) {
List<Operation> operations = aGeneralizedClass.getOperations();
for (Operation operation : operations) {
if (operation.isAbstract()) {
inheritedOperations.add(operation);
}
}
}
List<Interface> implementedInterfaces = aClass.getImplementedInterfaces();
for (Interface anInterface : implementedInterfaces) {
inheritedOperations.addAll(anInterface.getAllOperations());
}
List<Operation> operationsToRemove = new ArrayList<Operation>();
for (Operation inheritedOperation : inheritedOperations) {
boolean shouldRemoveOperation = false;
// See if it's not implemented
List<Operation> ownedOperations = aClass.getOwnedOperations();
for (Operation ownedOperation : ownedOperations) {
if (this.areEqual(ownedOperation, inheritedOperation)) {
shouldRemoveOperation = true;
break;
}
}
// See if a parent is not implementing it
if (!shouldRemoveOperation) {
for (Class aGeneralizedClass : allGeneralizedClasses) {
List<Operation> generalizedClassOperations = aGeneralizedClass.getOwnedOperations();
for (Operation generalizedClassOperation : generalizedClassOperations) {
if (generalizedClassOperation != inheritedOperation
&& this.canOverride(generalizedClassOperation, inheritedOperation)
&& this.areEqual(generalizedClassOperation, inheritedOperation)) {
shouldRemoveOperation = true;
break;
}
}
}
}
// See if we don't have the same operation to implement with a stronger visibility
// public > package > protected > private
if (!shouldRemoveOperation) {
for (Operation otherInheritedOperation : inheritedOperations) {
if (this.areEqual(inheritedOperation, otherInheritedOperation)) {
if (VisibilityKind.PUBLIC_LITERAL.equals(otherInheritedOperation.getVisibility())
&& !VisibilityKind.PUBLIC_LITERAL.equals(inheritedOperation.getVisibility())) {
// Public > everything
shouldRemoveOperation = true;
break;
} else if (VisibilityKind.PACKAGE_LITERAL.equals(otherInheritedOperation
.getVisibility())
&& !VisibilityKind.PUBLIC_LITERAL.equals(inheritedOperation.getVisibility())) {
// Package > protected and private only
shouldRemoveOperation = true;
break;
} else if (VisibilityKind.PROTECTED_LITERAL.equals(otherInheritedOperation
.getVisibility())
&& VisibilityKind.PRIVATE_LITERAL.equals(inheritedOperation.getVisibility())) {
// Protected > private only
shouldRemoveOperation = true;
break;
}
}
}
}
if (shouldRemoveOperation) {
operationsToRemove.add(inheritedOperation);
}
}
inheritedOperations.removeAll(operationsToRemove);
List<Operation> operations = new ArrayList<Operation>();
operations.addAll(inheritedOperations);
return operations;
}
/**
* Check if the given generalized UML operation can be overridden.
*
* @param generalizedClassOperation
* the generalized UML operation.
* @param inheritedOperation
* a inherited operation.
* @return True if it can be overridden.
*/
private boolean canOverride(Operation generalizedClassOperation, Operation inheritedOperation) {
return !generalizedClassOperation.isAbstract()
&& !VisibilityKind.PRIVATE_LITERAL.equals(generalizedClassOperation.getVisibility());
}
/**
* Check if the two given UML operation seems to be equal.
*
* @param generalizedClassOperation
* The first operation.
* @param inheritedOperation
* The second one.
* @return True if equal.
*/
// CHECKSTYLE:OFF
private boolean areEqual(Operation generalizedClassOperation, Operation inheritedOperation) {
// CHECKSTYLE:ON
if (generalizedClassOperation.getName() != null
&& generalizedClassOperation.getName().equals(inheritedOperation.getName())) {
EList<Parameter> generalizedClassOperationParameters = generalizedClassOperation
.getOwnedParameters();
int generalizedClassOperationParametersSize = generalizedClassOperationParameters.size();
EList<Parameter> inheritedOperationParameters = inheritedOperation.getOwnedParameters();
EList<Parameter> returnResult = generalizedClassOperation.returnResult();
int returnResultSize = returnResult.size();
EList<Parameter> inheritedOperationReturnResult = inheritedOperation.returnResult();
if (generalizedClassOperationParametersSize == inheritedOperationParameters.size()
&& returnResultSize == inheritedOperationReturnResult.size()) {
for (int i = 0; i < generalizedClassOperationParametersSize; i++) {
Type inheritedOperationParameterType = inheritedOperationParameters.get(i).getType();
Type generalizedClassOperationParameterType = generalizedClassOperationParameters.get(i)
.getType();
// CHECKSTYLE:OFF
if (inheritedOperationParameterType == null) {
if (generalizedClassOperationParameterType != null) {
return false;
}
} else {
if (!inheritedOperationParameterType
.conformsTo(generalizedClassOperationParameterType)) {
return false;
}
}
// CHECKSTYLE:ON
}
for (int i = 0; i < returnResultSize; i++) {
Type inheritedOperationReturnResultType = inheritedOperationReturnResult.get(i).getType();
Type returnResultType = returnResult.get(i).getType();
// CHECKSTYLE:OFF
if (inheritedOperationReturnResultType == null) {
if (returnResultType != null) {
return false;
}
} else {
if (!inheritedOperationReturnResultType.conformsTo(returnResultType)) {
return false;
}
}
// CHECKSTYLE:ON
}
return true;
}
}
return false;
}
/**
* get all generalized UML classes from the given UML class.
*
* @param aClass
* The UML class.
* @return The list of classes.
*/
private List<org.eclipse.uml2.uml.Class> getAllGeneralizedClasses(org.eclipse.uml2.uml.Class aClass) {
List<org.eclipse.uml2.uml.Class> generalizedClass = new ArrayList<org.eclipse.uml2.uml.Class>();
List<Generalization> generalizations = aClass.getGeneralizations();
for (Generalization generalization : generalizations) {
Classifier aClassifier = generalization.getGeneral();
if (aClassifier instanceof org.eclipse.uml2.uml.Class) {
org.eclipse.uml2.uml.Class anInheritedClass = (org.eclipse.uml2.uml.Class)aClassifier;
generalizedClass.add(anInheritedClass);
generalizedClass.addAll(this.getAllGeneralizedClasses(anInheritedClass));
}
}
return generalizedClass;
}
}