package org.dresdenocl.pivotmodel.impl;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
import org.eclipse.emf.ecore.util.EObjectEList;
import org.dresdenocl.pivotmodel.GenericElement;
import org.dresdenocl.pivotmodel.Type;
import org.dresdenocl.pivotmodel.TypeParameter;
/**
* A <code>Binding</code> contains all information about the binding of the
* {@link TypeParameter type parameters} of a {@link GenericElement}.
*
* @author Matthias Braeuer
* @version 1.0 02.08.2007
*/
public class Binding {
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(Binding.class);
/**
* The element that is going to be bound with the information provided to this
* binding.
*/
private GenericElement unboundElement;
/**
* The type parameters that were bound during the binding.
*/
private List<TypeParameter> typeParameters;
/**
* The types that were bound to the type parameters.
*/
private List<? extends Type> types;
/**
* Creates a new <code>Binding</code> instance. None of the parameters must be
* <code>null</code>. Also, the given lists must support comparison of
* elements via {@link Object#equals(Object) equality}, not identity (in EMF,
* the {@link EObjectEList} does not use <code>equals()</code> by default).
*
* @param unboundElement
* the element before the binding
* @param typeParameters
* the type parameters to be bound
* @param types
* the types to bind to the type parameters
*/
public Binding(GenericElement unboundElement,
List<TypeParameter> typeParameters, List<? extends Type> types) {
if (logger.isDebugEnabled()) {
logger.debug("Binding(unboundElement=" + unboundElement //$NON-NLS-1$
+ ", typeParameters=" + typeParameters + ", types=" + types //$NON-NLS-1$ //$NON-NLS-2$
+ ") - enter"); //$NON-NLS-1$
}
// initialize fields
this.unboundElement = unboundElement;
this.typeParameters = typeParameters;
this.types = types;
if (logger.isDebugEnabled()) {
logger.debug("Binding() - exit"); //$NON-NLS-1$
}
}
/**
* Returns the {@link Type} that has been bound to the given type parameter or
* <code>null</code> if the given type parameter was not part of the binding.
*
* @param typeParameter
* the type parameter bound during this binding
*
* @return the <code>Type</code> bound to the type parameter
*/
public Type getType(TypeParameter typeParameter) {
Type boundType = null;
int index;
// find the type parameter
index = typeParameters.indexOf(typeParameter);
if (index != -1) {
boundType = types.get(index);
}
return boundType;
}
/**
* @return
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result =
prime * result
+ ((typeParameters == null) ? 0 : typeParameters.hashCode());
result = prime * result + ((types == null) ? 0 : types.hashCode());
result =
prime * result
+ ((unboundElement == null) ? 0 : unboundElement.hashCode());
return result;
}
/**
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Binding))
return false;
final Binding other = (Binding) obj;
if (typeParameters == null) {
if (other.typeParameters != null)
return false;
}
else if (!typeParameters.equals(other.typeParameters))
return false;
if (types == null) {
if (other.types != null)
return false;
}
else if (!types.equals(other.types))
return false;
if (unboundElement == null) {
if (other.unboundElement != null)
return false;
}
else if (!unboundElement.equals(other.unboundElement))
return false;
return true;
}
/**
* Returns a string representation of this <code>Binding</code>. The string
* will contain the fully qualified name of the unbound element as well as the
* type parameters and corresponding types bound by this <code>Binding</code>.
*
* <p>
* Example: Binding both type parameters of {@code Map<K,V>} with the type
* named <code>Boolean</code> will result in the key
* <code>Map<K,V>:K->Boolean,V->Boolean</code>.
* </p>
*
* @return a <code>String</code> representing this binding
*/
@Override
public String toString() {
StringBuilder result;
// initialize with name of unbound element
result = new StringBuilder(unboundElement.getQualifiedName());
// add existing type parameters
if (!unboundElement.getOwnedTypeParameter().isEmpty()) {
result.append('<');
for (Iterator<TypeParameter> it =
unboundElement.getOwnedTypeParameter().iterator(); it.hasNext();) {
result.append(it.next().getName());
if (it.hasNext()) {
result.append(',');
}
}
result.append('>');
}
// add the type parameters and types bound to them
if (typeParameters.size() > 0) {
result.append(':');
for (int i = 0; i < typeParameters.size(); i++) {
result.append(typeParameters.get(i).getName()).append("->").append( //$NON-NLS-1$
types.get(i).getQualifiedName());
if (i < typeParameters.size() - 1) {
result.append(',');
}
}
}
return result.toString();
}
}