blob: 1780f00bc1c11e3d9fda163758b746f30eab591e [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2011 E.D.Willink 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 - initial API and implementation
*
* </copyright>
*
* $Id$
*/
package org.eclipse.ocl.examples.pivot.manager;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.ocl.examples.domain.elements.DomainTypedElement;
import org.eclipse.ocl.examples.pivot.ParameterableElement;
import org.eclipse.ocl.examples.pivot.PivotFactory;
import org.eclipse.ocl.examples.pivot.Property;
import org.eclipse.ocl.examples.pivot.TemplateParameter;
import org.eclipse.ocl.examples.pivot.TupleType;
import org.eclipse.ocl.examples.pivot.Type;
import org.eclipse.ocl.examples.pivot.TypedElement;
import org.eclipse.ocl.examples.pivot.internal.impl.TypedElementImpl;
import org.eclipse.ocl.examples.pivot.utilities.PivotUtil;
/**
* TupleTypeManager encapsulates the knowledge about known tuple types.
*/
public class TupleTypeManager
{
/**
* TuplePart provides a convenient descriptor for a tuple part complying with the full EMF model protocols.
*/
public static class TuplePart extends TypedElementImpl implements Comparable<TuplePart>
{
public TuplePart(String name, Type type) {
setName(name);
setType(type);
}
public int compareTo(TuplePart o) {
String n1 = getName();
String n2 = o.getName();
if (n1 == n2) {
return 0;
}
if (n1 == null) {
return -1;
}
if (n2 == null) {
return +1;
}
return n1.compareTo(n2);
}
}
protected final MetaModelManager metaModelManager;
/**
* Map from the sum of the part name hashes to the tuple types with the same hash.
*/
private Map<Integer, List<TupleType>> hash2tuple = null;
protected TupleTypeManager(MetaModelManager metaModelManager) {
this.metaModelManager = metaModelManager;
}
public void dispose() {
hash2tuple = null;
}
public Type getCommonType(TupleType leftType, TupleType rightType, Map<TemplateParameter, ParameterableElement> bindings) {
List<Property> leftProperties = leftType.getOwnedAttribute();
List<Property> rightProperties = rightType.getOwnedAttribute();
if (leftProperties.size() != rightProperties.size()) {
return null;
}
boolean isLeft = true;
boolean isRight = true;
List<TypedElement> commonProperties = new ArrayList<TypedElement>(leftProperties.size());
for (Property leftProperty : leftProperties) {
Property rightProperty = PivotUtil.getNamedElement(rightProperties, leftProperty.getName());
Type leftPropertyType = leftProperty.getType();
Type rightPropertyType = rightProperty.getType();
TypedElement commonProperty = null;
Type commonType = metaModelManager.getCommonType(leftPropertyType, rightPropertyType, bindings);
if (commonType == null) {
return null;
}
if (commonType != leftPropertyType) {
isLeft = false;
}
else {
commonProperty = leftProperty;
}
if (commonType != rightPropertyType) {
isRight = false;
}
else {
commonProperty = rightProperty;
}
if (commonProperty == null) {
commonProperty = new TuplePart(leftProperty.getName(), commonType);
}
commonProperties.add(commonProperty);
}
if (isLeft) {
return leftType;
}
else if (isRight) {
return rightType;
}
else {
return getTupleType(leftType.getName(), commonProperties, bindings);
}
}
/**
* Return the named tuple type with the defined alphabetically ordered parts.
*/
protected TupleType getOrderedTupleType(String name, List<TuplePart> orderedParts) {
if (hash2tuple == null) {
hash2tuple = new HashMap<Integer, List<TupleType>>();
}
int hash = name.hashCode();
for (TypedElement part : orderedParts) {
hash = 101 * hash + part.getName().hashCode();
}
List<TupleType> tupleList = hash2tuple.get(hash);
if (tupleList == null) {
tupleList = new ArrayList<TupleType>();
hash2tuple.put(hash, tupleList);
}
int iMax = orderedParts.size();
for (TupleType candidateTupleType : tupleList) {
List<Property> candidateParts = candidateTupleType.getOwnedAttribute();
if (candidateParts.size() == iMax) {
int i = 0;
for (TuplePart orderedPart : orderedParts) {
Property candidatePart = candidateParts.get(i);
if (orderedPart.getType() != candidatePart.getType()) {
break;
}
if (!orderedPart.getName().equals(candidatePart.getName())) {
break;
}
i++;
}
if (i >= iMax) {
return candidateTupleType;
}
}
}
TupleType tupleType = PivotFactory.eINSTANCE.createTupleType();
tupleType.setName(name);
List<Property> tupleParts = tupleType.getOwnedAttribute();
for (TuplePart part : orderedParts) {
Property tuplePart = PivotFactory.eINSTANCE.createProperty();
tuplePart.setName(part.getName());
tuplePart.setType(part.getType());
tupleParts.add(tuplePart);
}
tupleType.getSuperClass().add(metaModelManager.getOclTupleType());
tupleList.add(tupleType);
metaModelManager.addOrphanClass(tupleType);
return tupleType;
}
public TupleType getTupleType(String typeName, Collection<? extends DomainTypedElement> parts,
Map<TemplateParameter, ParameterableElement> bindings) {
List<TuplePart> orderedParts = new ArrayList<TuplePart>(parts.size());
for (DomainTypedElement part : parts) {
Type type = metaModelManager.getType(part.getType());
Type specializedType = metaModelManager.getSpecializedType(type, bindings);
orderedParts.add(new TuplePart(part.getName(), specializedType));
}
Collections.sort(orderedParts);
return getOrderedTupleType(typeName, orderedParts);
}
public TupleType getTupleType(TupleType type, Map<TemplateParameter, ParameterableElement> usageBindings) { // FIXME Remove duplication, unify type/multiplicity
TupleType specializedTupleType = type;
Map<String, Type> resolutions = null;
for (Property property : specializedTupleType.getOwnedAttribute()) {
Type propertyType = metaModelManager.getTypeWithMultiplicity(property);
Type resolvedPropertyType = metaModelManager.getSpecializedType(propertyType, usageBindings);
if (resolvedPropertyType != propertyType) {
if (resolutions == null) {
resolutions = new HashMap<String, Type>();
}
resolutions.put(property.getName(), resolvedPropertyType);
}
}
if (resolutions != null) {
List<TypedElement> parts = new ArrayList<TypedElement>();
for (Property property : specializedTupleType.getOwnedAttribute()) {
TypedElement part = property;
Type resolvedPropertyType = resolutions.get(property.getName());
if (resolvedPropertyType != null) {
part = new TuplePart(property.getName(), resolvedPropertyType);
}
parts.add(part);
}
specializedTupleType = getTupleType(type.getName(), parts, usageBindings);
}
return specializedTupleType;
}
}