blob: 0803b4c5f7bcbf6283c7ec755558670635b7f07f [file] [log] [blame]
/**********************************************************************
* This file is part of the "Object Teams Runtime Environment"
*
* Copyright 2002-2009 Berlin Institute of Technology, Germany.
*
* 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
* $Id: CallinBindingManager.java 23408 2010-02-03 18:07:35Z stephan $
*
* Please visit http://www.objectteams.org for updates and contact.
*
* Contributors:
* Berlin Institute of Technology - Initial API and implementation
**********************************************************************/
package org.eclipse.objectteams.otre.util;
//import org.apache.bcel.generic.Type; // just for javadoc.
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ObjectType;
import org.eclipse.objectteams.otre.OTREInternalError;
import org.eclipse.objectteams.otre.ObjectTeamsTransformation;
import org.eclipse.objectteams.otre.RepositoryAccess;
import org.eclipse.objectteams.otre.ObjectTeamsTransformation.BaseMethodInfo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
/**
* @version $Id: CallinBindingManager.java 23408 2010-02-03 18:07:35Z stephan $
* @author Christine Hundt
*/
@SuppressWarnings("nls")
public class CallinBindingManager {
/** When asking for a bound super type, we may find a super class, a super interface or nothing. */
public static enum BoundSuperKind {
NONE, CLASS, INTERFACE;
}
// map of bindings for role classes: roleClassName -> RoleBaseBinding
private static HashMap<String, RoleBaseBinding> roleBindings = new HashMap<String, RoleBaseBinding>();
// map of bindings for base classes: baseClassName -> List[RoleBaseBinding]
private static ListValueHashMap<RoleBaseBinding> baseBindings = new ListValueHashMap<RoleBaseBinding>();
// maps a team to its handled bases: teamClassName -> List[BaseClassName]
private static ListValueHashMap<String> basesPerTeam = new ListValueHashMap<String>();
// maps a team to its contained roles: teamClassName -> List[RoleClassName]
private static ListValueHashMap<String> rolesPerTeam = new ListValueHashMap<String>();
/**
* Add super-link of the BoundRole object for the RoleBaseBinding of 'className' to 'superClassName'.
* @param className the name of the class for which to add the super-link
* @param superClassName the name of the super class to be linked
*/
public static void addSuperRoleLink(String className, String superClassName) {
if (!roleBindings.containsKey(superClassName))
return; // no super role class stored!
RoleBaseBinding rbbSuper = roleBindings.get(superClassName);
RoleBaseBinding rbb = roleBindings.get(className);
// establish link from the role to its super role class:
rbb.getRoleClass().setSuper(rbbSuper.getRoleClass());
}
/**
* @param baseClassName
*/
private static void addSuperBaseLink(String teamClassName, String baseClassName, RoleBaseBinding rbb)
{
BoundClass baseClass = rbb.getBaseClass();
ObjectType baseClassType = new ObjectType(baseClassName);
// clone the set for re-entrance:
Iterator<Entry<String, LinkedList<RoleBaseBinding>>> it = getBaseBindingsCloneIterator();
while (it.hasNext()) {
Entry<String, LinkedList<RoleBaseBinding>> entry = it.next();
String currentBaseClassName = entry.getKey();
if (currentBaseClassName.equals(baseClassName)) continue;
ObjectType currentType = new ObjectType(currentBaseClassName);
// BoundClass objects are unique per base object, so just take the first binding:
BoundClass currentBaseClass = entry.getValue().getFirst().getBaseClass();
if(RepositoryAccess.safeSubclassOf(baseClassType, currentType)) {
BoundClass rbbSuper = baseClass.getSuper();
if (rbbSuper != null) {
if (rbbSuper.getName().equals(currentBaseClassName))
continue; // no need for action: already set.
baseClass.updateSuper(currentBaseClass, currentType);
}
baseClass.setSuper(currentBaseClass);
}
else if (RepositoryAccess.safeSubclassOf(currentType, baseClassType)) {
BoundClass currentSuper = currentBaseClass.getSuper();
// if sub base classes may be registered before super base class,
// this case has to be considered too:
if (currentSuper != null) {
if (currentSuper.getName().equals(baseClassName))
continue; // no need for action: already set.
currentBaseClass.updateSuper(baseClass, baseClassType);
}
currentBaseClass.setSuper(baseClass);
}
}
}
/**
* Declare role playedBy base.
*
* @param roleClassName the name of the played role class
* @param baseClassName the name of the playing base class
* @param baseIsInterface whether the given base is an interface
*/
public static void addRoleBaseBinding(String roleClassName, String baseClassName, boolean baseIsInterface, String teamClassName) {
RoleBaseBinding rbb = roleBindings.get(roleClassName);
if (rbb == null) {
rbb = new RoleBaseBinding(roleClassName, baseClassName, baseIsInterface, teamClassName);
roleBindings.put(roleClassName, rbb);
}
addSuperBaseLink(teamClassName, baseClassName, rbb);
synchronized (baseBindings) {
baseBindings.put(baseClassName, rbb);
}
addTeamRoleRelation(teamClassName, roleClassName);
}
/**
* @param teamClassName
* @param baseClassName
*/
public static void addTeamBaseRelation(String teamClassName, String baseClassName) {
JavaClass baseClass = null;
try {
baseClass = RepositoryAccess.lookupClass(baseClassName);
} catch (ClassNotFoundException e) {
// FIXME(SH): where to log?
e.printStackTrace();
}
if (baseClass != null && baseClass.isInterface()) {
// TODO (SH): need to register with all implementing classes!
if (logging) {
ObjectTeamsTransformation.printLogMessage("*** Skipping base " + baseClassName + ": is an interface");
ObjectTeamsTransformation.printLogMessage("Classses implementing the interface " + baseClassName + " have to be transformed!");
}
addBoundBaseInterface(baseClassName);
} else {
List<String> bases = basesPerTeam.get(teamClassName);
if (bases==null || !bases.contains(baseClassName))
basesPerTeam.put(teamClassName, baseClassName);
}
}
/**
* @param teamClassName
* @return
*/
public static List<String> getBasesPerTeam(String teamClassName) {
// (PH): return empty list instead of null when team has no bases?
return basesPerTeam.get(teamClassName);
}
/**
* @param teamClassName
* @param roleClassName
*/
public static void addTeamRoleRelation(String teamClassName, String roleClassName) {
List<String> roles = rolesPerTeam.get(teamClassName);
if (roles == null || !roles.contains(roleClassName))
rolesPerTeam.put(teamClassName, roleClassName);
}
/**
* @param teamClassName
* @return
*/
public static List<String> getRolePerTeam(String teamClassName) {
return rolesPerTeam.get(teamClassName);
}
private static LinkedList<String> allRoles = new LinkedList<String>();
/**
* @param roleName
*/
public static void addRole(String roleName) {
allRoles.add(roleName);
}
/**
* @param roleName
* @return
*/
public static boolean isRole(String roleName) {
return allRoles.contains(roleName);
}
/**
* Declare binding of a pair of methods.
* @param roleClassName
* @param bindingFileName TODO
* @param bindingLineNumber TODO
* @param bindingLineOffset TODO
* @param roleMethodName
* @param roleMethodSignature signature ready for interpretation by
* {@link Type org.apache.bcel.generic.Type}
* @param isStaticRoleMethod TODO
* @param modifier "before", "after" or "replace"
* @param baseMethodName
* @param baseMethodSignature
* @param isStaticBaseMethod is the base method static?
* @param baseIsCallin is the base method a callin method?
* @param translationFlags one bit for the result and for each argument indicating whether lifting/lowering is needed
* @param liftMethodName
* @param liftMethodSignature
*/
public static void addMethodBinding(
String roleClassName, String baseClassName,
String bindingFileName, int bindingLineNumber, int bindingLineOffset,
String bindingLabel, String roleMethodName, String roleMethodSignature, boolean isStaticRoleMethod,
String wrapperName, String wrapperSignature, String modifier,
String baseMethodName, String baseMethodSignature,
boolean isStaticBaseMethod, boolean baseIsCallin, boolean covariantBaseReturn,
int translationFlags, String liftMethodName, String liftMethodSignature)
{
RoleBaseBinding rbb = roleBindings.get(roleClassName);
if (rbb == null) {
// no binding found, create it now:
if (baseClassName == null)
throw new OTREInternalError("PlayedBy attribute must be read before method bindings.");
int lastDollar = roleClassName.lastIndexOf('$');
String teamClassName = roleClassName.substring(0, lastDollar);
rbb = new RoleBaseBinding(roleClassName, baseClassName, false, teamClassName);
roleBindings.put(roleClassName, rbb);
}
//System.err.println(rbb.getRoleClass().getName()+"<-*->"+rbb.getBaseClass().getName());
rbb.addMethodBinding(bindingFileName, bindingLineNumber, bindingLineOffset,
bindingLabel, roleMethodName, roleMethodSignature, isStaticRoleMethod,
wrapperName, wrapperSignature, modifier,
baseMethodName, baseMethodSignature,
isStaticBaseMethod, baseIsCallin, covariantBaseReturn,
translationFlags,
liftMethodName, liftMethodSignature);
if (modifier.equals("replace"))
assignBaseCallTag(rbb.getBaseClassName(), baseMethodName, baseMethodSignature);
}
/**
* Get all callin bindings for a given base method.
* @param className the base class
* @param methodName the base method
* @return Collection of <pre>MethodBinding</pre>
*/
public static Collection<MethodBinding> getBindingForBaseMethod(String baseClassName, String baseMethodName, String baseMethodSignature)
{
LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
LinkedList<MethodBinding> resultList = new LinkedList<MethodBinding>();
if (rbbList != null) {
Iterator<RoleBaseBinding> it = rbbList.iterator();
while (it.hasNext()) {
RoleBaseBinding rbb = it.next();
List<MethodBinding> mbs = rbb.getBaseMethodBindings(baseMethodName, baseMethodSignature);
if (mbs != null)
addFiltered(resultList, mbs, baseMethodName, baseMethodSignature);
}
}
// IMPLICIT_INHERITANCE
addFiltered(resultList,
getImplicitlyInheritedBaseMethodBindings(baseClassName, baseMethodName, baseMethodSignature),
baseMethodName,
baseMethodSignature);
if (resultList.isEmpty())
return null;
return resultList;
}
/** variant of the above, optimized for computing only a boolean result instead of a complete list. */
public static boolean isBoundBaseMethod(String baseClassName, String baseMethodName, String baseMethodSignature)
{
LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
if (rbbList != null) {
for (RoleBaseBinding rbb : rbbList) {
List<MethodBinding> mbs = rbb.getBaseMethodBindings(baseMethodName, baseMethodSignature);
if (mbs != null)
for (MethodBinding mb : mbs)
if (mb.matchesMethod(baseMethodName, baseMethodSignature, /* strict */ true))
return true;
}
}
// IMPLICIT_INHERITANCE
for (MethodBinding mb : getImplicitlyInheritedBaseMethodBindings(baseClassName, baseMethodName, baseMethodSignature))
if (mb.matchesMethod(baseMethodName, baseMethodSignature, /* strict */ true))
return true;
return false;
}
// add bindings from candidates to resultList, perhaps checking
// full signatures (i.e., if not covariantBaseReturn).
private static void addFiltered(Collection<MethodBinding> resultList,
Collection<MethodBinding> candidates,
String name,
String fullSignature)
{
for (MethodBinding methodBinding : candidates)
if (methodBinding.matchesMethod(name, fullSignature, /*strict*/false))
resultList.add(methodBinding);
}
/**
* Gets all implicitly inherited method bindings for the given base method.
* Note: the result can only contain elements for base classes which are
* roles at the same time!
* @param baseClassName the name of the base class
* @param baseMethodName the name of the base mehtod
* @param baseMethodSignature the descriptor or the base method signature
* @return a Collection with all implicitly inherited method bindings
*/
private static Collection<MethodBinding> getImplicitlyInheritedBaseMethodBindings(String baseClassName, String baseMethodName, String baseMethodSignature) {
List<MethodBinding> resultList = new LinkedList<MethodBinding>();
if (!isRole(baseClassName))
return resultList; // only roles can have implicit super types
Iterator<Entry<String, LinkedList<RoleBaseBinding>>> it = getBaseBindingsCloneIterator();
while (it.hasNext()) {
Entry<String, LinkedList<RoleBaseBinding>> entry = it.next();
String have = entry.getKey();
// look for true superClass (not same):
if (have.equals(baseClassName))
continue;
if (isImplicitSubtype(baseClassName, have)) {
// now we have an implicit superClass:
if (logging)
ObjectTeamsTransformation.printLogMessage(baseClassName
+ " implicitly inherits callin bindings from " + have);
// collect the signatures of all bound base methods:
List<RoleBaseBinding> rbbList = entry.getValue();
if (rbbList != null) {
Iterator<RoleBaseBinding> rbb_it = rbbList.iterator();
while (rbb_it.hasNext()) {
RoleBaseBinding rbb = rbb_it.next();
List<MethodBinding> mbs = rbb.getBaseMethodBindings(baseMethodName, baseMethodSignature);
if (mbs != null)
resultList.addAll(mbs);
}
}
}
}
//if (!resultList.isEmpty())
// System.err.println(resultList);
return resultList;
}
/**
* Get all callin bindings that a given base class may inherit from its superclass.
* @param className
* @result list of MethodBinding
*/
public static Collection<MethodBinding> getInheritedCallinBindings (String className) {
/*
List classBindings = baseBindings.get(className);
if (classBindings!=null) {
// any RoleBaseBinding contains the corresponding BoundClass object for the super base:
RoleBaseBinding anyRBB = (RoleBaseBinding)classBindings.get(0);
// problem: if a sub base class is not explicitly bound to a role class no corresponding
// BoundClass object exists. How can we access the super bindings via the
// super-link??
BoundClass bc = anyRBB.getBaseClass();
//System.out.println("-----------");
while (bc.getSuper()!=null) {
System.out.println(bc.getName());
bc = bc.getSuper();
}
//System.out.println("-----------");
}
*/
List<MethodBinding> result = new LinkedList<MethodBinding>();
ObjectType current = new ObjectType(className);
// clone for re-entrance:
Iterator<Entry<String, LinkedList<RoleBaseBinding>>> it= getBaseBindingsCloneIterator();
while (it.hasNext()) {
Entry<String, LinkedList<RoleBaseBinding>> entry = it.next();
String have = entry.getKey();
// look for true superClass (not same):
if (have.equals(className)) continue;
ObjectType haveType = new ObjectType(have);
if (RepositoryAccess.safeSubclassOf(current, haveType)) {
// now we have a true superClass:
if (logging)
ObjectTeamsTransformation.printLogMessage(className
+ " inherits callin bindings from " + have);
// collect the signatures of all bound base methods:
List<RoleBaseBinding> rbbList = entry.getValue();
if (rbbList != null) {
Iterator<RoleBaseBinding> rbb_it = rbbList.iterator();
while (rbb_it.hasNext()) {
RoleBaseBinding rbb = rbb_it.next();
result.addAll(rbb.getBaseMethodBindings());
}
}
}
}
return result;
}
/**
* Get all super classes defining callin bindings that a given static base
* method may inherit.
*
* @author juerwid
* @param className
* @param methodName
* @param methodSignaturte
* @result list of <String[] {class_name}>
*/
public static Collection<String> getInheritedCallinBindingsForStaticMethods(
String className, String methodName, String methodSignature)
{
List<String> result = new LinkedList<String>();
ObjectType current = new ObjectType(className);
// clone for re-entrance:
Iterator<Entry<String, LinkedList<RoleBaseBinding>>> it = getBaseBindingsCloneIterator();
boolean getNextClass = false;
while (it.hasNext()) {
Entry<String,LinkedList<RoleBaseBinding>> entry = it.next();
String have = entry.getKey();
// look for true superClass (not same):
if (have.equals(className)) continue;
ObjectType haveType = new ObjectType(have);
if (RepositoryAccess.safeSubclassOf(current, haveType)) {
// now we have a true superClass:
if (logging)
ObjectTeamsTransformation.printLogMessage(className
+ " inherits callin bindings from " + have);
// collect the signatures of all bound base methods:
LinkedList<RoleBaseBinding> rbbList = entry.getValue();
if (rbbList != null) {
Iterator<RoleBaseBinding> rbb_it = rbbList.iterator();
while (rbb_it.hasNext() && !getNextClass) {
RoleBaseBinding rbb = rbb_it.next();
List<String[]> methods = rbb.getBaseSignatures();
Iterator<String[]> methodsIter = methods.iterator();
while(methodsIter.hasNext() && !getNextClass){
String[] aMethod = methodsIter.next();
if(methodName.equals(aMethod[0]) && methodSignature.equals(aMethod[1])){
result.add(have);
getNextClass = true;
}
}
}
if(getNextClass){
getNextClass = false;
continue;
}
}
}
}
return result;
}
/**
* Checks if 'subType' is an implicit subtype of 'superType'.
* To be true the role name parts have to be equal and the
* team name parts have to be in a 'real' subtype relationship.
*
* @param subType the name of the potential subtype.
* @param superType the name of the potential supertype.
* @return true, if subType implicitly inherits from superType.
*/
private static boolean isImplicitSubtype(String subType, String superType) {
//System.err.println(subType +" -?-> " + superType);
int dollarIdxSub = subType.lastIndexOf('$');
int dollarIdxSuper = superType.lastIndexOf('$');
if (dollarIdxSub==-1 || dollarIdxSuper==-1)
return false; // no roles
String pureSubType = subType.substring(dollarIdxSub+1, subType.length());
String pureSuperType = superType.substring(dollarIdxSuper+1, superType.length());
if (!pureSubType.equals(pureSuperType))
return false;// no identical role names
String subTeamName = subType.substring(0, dollarIdxSub);
String superTeamName = superType.substring(0,dollarIdxSuper);
ObjectType subTeamType = new ObjectType(subTeamName);
ObjectType superTeamType = new ObjectType(superTeamName);
if (RepositoryAccess.safeSubclassOf(subTeamType, superTeamType)) {
if (logging)
ObjectTeamsTransformation.printLogMessage(subType
+ " implicitly inherits method bindings from " + superType);
//System.err.println(subType + " implicitly inherits method bindings from " + superType);
return true;
}
return false; // no inheritance relation between teams
}
/**
* Get all inherited method bindings for a given base method, which are
* bindings declared for a super base class.
*
* the actual base class has additional bindings for this method!
* @param baseClassName the name of the role class
* @param baseMethodName the name of the role method
* @param baseMethodSignature the signature of the role method
* @result a List containing all inherited bindings for the role method
*/
public static List<MethodBinding> getInheritedBaseMethodBindings(String baseClassName, String baseMethodName, String baseMethodSignature) {
List<MethodBinding> inheritedMethodBindings = new LinkedList<MethodBinding>();
if (!isBoundBaseClass(baseClassName)) {
return inheritedMethodBindings;
}
LinkedList<RoleBaseBinding> baseBindingsForBase = baseBindings.get(baseClassName);
if (baseBindingsForBase == null)
return inheritedMethodBindings;
Iterator<RoleBaseBinding> it = baseBindingsForBase.iterator();
while (it.hasNext()) {
RoleBaseBinding rbb = it.next();
BoundClass bc = rbb.getBaseClass();
while (bc.getSuper() != null) {
bc = bc.getSuper();
String superRoleName = bc.getName();
Collection<MethodBinding> superRoleMethodBindings = CallinBindingManager.getBindingForBaseMethod(
superRoleName,
baseMethodName,
baseMethodSignature);
if (superRoleMethodBindings!=null)
inheritedMethodBindings.addAll(superRoleMethodBindings);
}
}
return inheritedMethodBindings;
}
/**
* Get all inherited method bindings for a given role method, which are
* bindings declared in a super role class. The actual role class has
* additional bindings for this method!
*
* @param roleClassName the name of the role class
* @param roleMethodName the name of the role method
* @param roleMethodSignature the signature of the role method
* @result a List containing all inherited bindings for the role method
*/
public static List<MethodBinding> getInheritedRoleMethodBindings(String roleClassName, String roleMethodName, String roleMethodSignature) {
List<MethodBinding> inheritedMethodBindings = new LinkedList<MethodBinding>();
if (!isBoundRoleClass(roleClassName)) {
return inheritedMethodBindings;
}
RoleBaseBinding rbb = roleBindings.get(roleClassName);
BoundClass bc = rbb.getRoleClass();
while (bc.getSuper() != null) {
bc = bc.getSuper();
String superRoleName = bc.getName();
List<MethodBinding> superRoleMethodBindings = CallinBindingManager.getBindingsForRoleMethod(
superRoleName,
roleMethodName,
roleMethodSignature);
inheritedMethodBindings.addAll(superRoleMethodBindings);
}
return inheritedMethodBindings;
}
/**
* All bindings for a given role method concerning its base class.
*
* @return List of MethodBinding
*/
public static List<MethodBinding> getBindingsForRoleMethod(String roleClassName,
String roleMethodName, String roleMethodSignature)
{
RoleBaseBinding rbb = roleBindings.get(roleClassName);
if (rbb==null) {
return new LinkedList<MethodBinding>();
}
List<MethodBinding> roleMethodBindings = rbb.getRoleMethodBindings(roleMethodName, roleMethodSignature);
if (roleMethodBindings == null) {
return new LinkedList<MethodBinding>();
}
return roleMethodBindings;
}
/**
* @param className
* @return
*/
public static boolean isBoundBaseClass(String className) {
// and has at least one method binding?
boolean result = baseBindings.containsKey(className);
if (result || !isRole(className)) {
return result;
}
else {// bound implicit super class?
Iterator<String> it = getBaseBindingsKeyIterator();
while (it.hasNext()) {
String have = it.next();
// look for true superClass (not same):
if (have.equals(className))
continue;
if (isImplicitSubtype(className, have))
return true;
}
return result;
}
}
/**
* @param className
* @return
*/
public static boolean isBoundBaseAndRoleClass(String className) {
// and has at least one method binding?
if (baseBindings.containsKey(className))
return true;
// bound implicit super class?
Iterator<String> it = getBaseBindingsKeyIterator();
while (it.hasNext()) {
String have = it.next();
// look for true superClass (not same):
if (have.equals(className))
continue;
if (isImplicitSubtype(className, have))
return true;
}
return false;
}
/**
* @param baseClassName
* @return
*/
public static BoundSuperKind hasBoundBaseParent(String baseClassName) {
LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
if (rbbList != null) {
Iterator<RoleBaseBinding> it = rbbList.iterator();
while (it.hasNext()) {
RoleBaseBinding rbb = it.next();
BoundClass baseSuper = rbb.getBaseClass().getSuper();
if (baseSuper!=null)
return baseSuper.isInterface ? BoundSuperKind.INTERFACE : BoundSuperKind.CLASS;
}
}
// IMPLICIT_INHERITANCE
//if (isUnboundSubBase(baseClassName))
// return true;
return BoundSuperKind.NONE;
}
/**
* Returns the name of the topmost bound base class.
*
* @param baseClassName
* @return
*/
public static String getTopmostBoundBaseClass(String baseClassName) {
LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
if (rbbList != null) {
// assumption: EVERY BoundClass object has been connected to its bound super classes.
RoleBaseBinding anyRBB = rbbList.get(0);
BoundClass bc = anyRBB.getBaseClass();
while (bc.getSuper() != null) {
if (bc.getSuper().isInterface)
break; // use bc instead of travelling up to super interfaces
bc = bc.getSuper();
}
return bc.getName();
}
return baseClassName;
}
/**
* @param teamClassName
* @param baseClassName
* @return
*/
public static boolean teamAdaptsSuperBaseClass(String teamClassName, String baseClassName) {
LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
if (rbbList != null && !rbbList.isEmpty()) {
RoleBaseBinding rbb = rbbList.getFirst(); // all entries refer to the same base class.
BoundClass bc = rbb.getBaseClass().getSuper();
while (bc!=null && !bc.isInterface) {
if (bc.isAdaptedByTeam(teamClassName))
return true;
bc = bc.getSuper();
}
}
return false;
}
/**
* @param baseClassName
* @return
*/
// private static boolean isUnboundSubBase(String baseClassName) {
// ObjectType current = new ObjectType(baseClassName);
// if (!checkLookup(current.getClassName())) // TODO: workaround for classes loaded from special locations
// return false;
// Iterator /* String */ it = baseBindings.keySet().iterator();
// while (it.hasNext()) {
// String have = (String)it.next();
// // look for true superClass (not same):
// if (have.equals(baseClassName)) continue;
// ObjectType haveType = new ObjectType(have);
// //System.err.println(current + " : "+haveType);
// //System.err.println(org.apache.bcel.Repository.lookupClass(have));
// if (!checkLookup(haveType.getClassName())) // TODO: workaround for classes loaded from special locations
// continue;
// if (current.subclassOf(haveType)) {
// return true;
// }
// }
// return false;
// }
/**
* @param className
* @return
*/
public static boolean isBoundRoleClass(String className) {
return roleBindings.containsKey(className);
}
/**
* @param className
* @return
*/
public static RoleBaseBinding getRoleBaseBinding(String roleClassName) {
return roleBindings.get(roleClassName);
}
/**
* @param roleClassName
* @return
*/
public static List<MethodBinding> getMethodBindingsForRoleClass(String roleClassName)
{
RoleBaseBinding rbb = roleBindings.get(roleClassName);
return rbb.getRoleMethodBindings();
}
/**
* @param roleClassName
* @return
*/
public static Set<String> getBoundRoleMethods(String roleClassName) {
Set<String> roleMethodKeySet = new HashSet<String>();
if (roleBindings.get(roleClassName) != null) {
RoleBaseBinding rbb = roleBindings.get(roleClassName);
roleMethodKeySet = rbb.getRoleMethodSignatures();
}
return roleMethodKeySet;
}
/**
* @param baseClassName
* @return
*/
public static List<MethodBinding> getMethodBindingsForBaseClass(String baseClassName)
{
LinkedList<RoleBaseBinding> rbbList = baseBindings.get(baseClassName);
LinkedList<MethodBinding> resultList = new LinkedList<MethodBinding>();
if (rbbList != null) {
Iterator<RoleBaseBinding> it = rbbList.iterator();
while (it.hasNext()) {
RoleBaseBinding rbb = it.next();
resultList.addAll(rbb.getRoleMethodBindings());
}
}
return resultList;
}
// --------------------------------------------------
// discriminate base methods by tag per callin
// --------------------------------------------------
// baseClass.baseMeth.baseMethodSignature -> tag
private static HashMap<String, Integer> baseCallTags = new HashMap<String, Integer>();
// -- follow access methods for baseCallTags:
/**
* @param baseClass
* @param baseMeth
* @param baseMethodSignature
*/
public static void assignBaseCallTag (String baseClass, String baseMeth,
String baseMethodSignature)
{
// every base method bound by a replace callin gets an unique tag:
String key = baseClass+"."+baseMeth+"."+baseMethodSignature;
int tag = baseCallTags.size();
if (!baseCallTags.containsKey(key))
baseCallTags.put(key, Integer.valueOf(tag));
}
public static int getBaseCallTag (String base_class_name,
String base_method_name,
String base_method_signature) {
String key = base_class_name + "." + base_method_name
+ "." + base_method_signature;
return baseCallTags.get(key).intValue();
}
// ----------------------------------------------
// Map argument positions:
// ----------------------------------------------
// teamName -> callinWrapperName -> int[]
private static HashMap<String, HashMap<String, int[]>> paramMappings = new HashMap<String, HashMap<String, int[]>>();
// -- follow access methods for paramMappings:
/**
* @param teamName
* @param methodWrapper
* @param positions
*/
public static void addParameterBinding (String teamName,
String methodWrapper,
int[] positions) {
HashMap<String, int[]> teamMap = paramMappings.get(teamName);
if (teamMap == null) {
teamMap = new HashMap<String, int[]>();
paramMappings.put(teamName, teamMap);
}
teamMap.put(methodWrapper, positions);
}
public static boolean hasParamMappings (String teamName, String methodWrapper)
{
HashMap<String,int[]> teamMap = paramMappings.get(teamName);
if (teamMap == null) return false;
return teamMap.containsKey(methodWrapper);
}
/** Get parameter positions for the given team or any super team. */
public static int[] getParamPositions (String teamName, String methodWrapper)
{
int[] positions = getExactParamPositions(teamName, methodWrapper);
if (positions != null)
return positions;
// inherit parameter mappings from super teams: -- >>
Iterator<String> superTeams = getSuperTeamsWithParamMappigs(teamName).iterator();
while (superTeams.hasNext()) {
positions = getExactParamPositions(superTeams.next(), methodWrapper);
if (positions != null) // found (the!) parameter mapping
return positions;
}
return null;
}
/** Get parameter positions for exactly the given team (no super teams). */
private static int[] getExactParamPositions(String teamName, String methodWrapper) {
HashMap<String,int[]>teamMap = paramMappings.get(teamName);
if (teamMap == null)
return null;
return teamMap.get(methodWrapper);
}
private static List<String> getSuperTeamsWithParamMappigs(String teamName) {
LinkedList<String> result = new LinkedList<String>();
try {
for (JavaClass superTeam : RepositoryAccess.getSuperClasses(teamName))
if (paramMappings.get(superTeam.getClassName()) != null)
result.add(superTeam.getClassName());
} catch (ClassNotFoundException e) {
// FIXME(SH): where to log to?
e.printStackTrace();
// continue, just nothing added to result
}
return result;
}
// -----------------------------------------------
// callout bindings that require adjustment:
// -----------------------------------------------
// baseClass -> HashSet (method_name+signature)
private static HashMap<String, HashSet<String>> calloutBindings = new HashMap<String, HashSet<String>>();
/**
* @param clazz
* @param meth
* @param sign
*/
public static void addCalloutBinding(String clazz, String meth, String sign) {
HashSet<String> bindings = calloutBindings.get(clazz);
if (bindings == null) {
bindings = new HashSet<String>();
calloutBindings.put(clazz, bindings);
}
bindings.add(meth + sign);
}
/**
* @param clazz
* @return
*/
public static HashSet<String> getCalloutBindings (String clazz) {
return calloutBindings.get(clazz);
}
/**
* @param bindings
* @param method_name
* @param signature
* @return
*/
public static boolean requiresCalloutAdjustment(HashSet<String> bindings,
String method_name,
String signature)
{
return bindings.contains(method_name+signature);
}
// -----------------------------------------------
// callouts to base class fields are stored here for furher reading and get/set method generation:
// -----------------------------------------------
private static ListValueHashMap<FieldDescriptor> calloutSetFields = new ListValueHashMap<FieldDescriptor>();
private static ListValueHashMap<FieldDescriptor> calloutGetFields = new ListValueHashMap<FieldDescriptor>();
/**
* @param roleClassName
* @param fieldName
* @param fieldSignature
* @param accessMode
* @param isStaticField
*/
public static void addCalloutBoundFileds(String baseClassName, String fieldName,
String fieldSignature, String accessMode, boolean isStaticField)
{
FieldDescriptor fd = new FieldDescriptor(fieldName, fieldSignature, isStaticField);
if (accessMode.equals("get")) {
calloutGetFields.put(baseClassName, fd);
} else if (accessMode.equals("set")) {
calloutSetFields.put(baseClassName, fd);
} else {
throw new OTREInternalError("CalloutFieldAccess attribute contains wrong access mode: "+accessMode);
}
}
/**
* @param baseClassName
* @return
*/
public static List<FieldDescriptor> getCalloutGetFields(String baseClassName) {
return calloutGetFields.get(baseClassName);
}
/**
* @param baseClassName
* @return
*/
public static List<FieldDescriptor> getCalloutSetFields(String baseClassName) {
return calloutSetFields.get(baseClassName);
}
// -----------------------------------------------
// base calls to super methods via special accessor
// -----------------------------------------------
private static ListValueHashMap<SuperMethodDescriptor> superMethods = new ListValueHashMap<SuperMethodDescriptor>();
public static void addSuperAccess(String baseClassName, String superClassName, String methodName, String signature) {
SuperMethodDescriptor superMethod = new SuperMethodDescriptor(methodName, baseClassName, superClassName, signature);
superMethods.put(baseClassName, superMethod);
}
public static List<SuperMethodDescriptor> getSuperAccesses(String class_name) {
return superMethods.get(class_name);
}
// -----------------------------------------------
// bound interfaces have to be registered, for implementing classes to inherit callin bindings:
// -----------------------------------------------
private static List<String> boundBaseInterfaces = new LinkedList<String>();
/**
* @param baseInterfaceName The name of the bound base interface.
*/
public static void addBoundBaseInterface(String baseInterfaceName) {
if (!boundBaseInterfaces.contains(baseInterfaceName))
boundBaseInterfaces.add(baseInterfaceName);
}
/**
* @param interfaceName
* @return
*/
public static Collection<String[]> getInterfaceInheritedCallinBindings(String interfaceName) {
List<String[]> result = new LinkedList<String[]>();
//System.err.println(interfaceName);
//System.err.println(boundBaseInterfaces);
if (boundBaseInterfaces.contains(interfaceName)) {
if (logging)
ObjectTeamsTransformation.printLogMessage(interfaceName
+ " bequests callin bindings to implementing class");
// collect the signatures of all bound base methods:
LinkedList<RoleBaseBinding> rbbList = baseBindings.get(interfaceName);
if (rbbList != null) {
Iterator<RoleBaseBinding> rbb_it = rbbList.iterator();
while (rbb_it.hasNext()) {
RoleBaseBinding rbb = rbb_it.next();
result.addAll(rbb.getBaseSignatures());
// System.err.println("inheriting binding: "+rbb);
}
}
}
return result;
}
/**
* @param methodName
* @param methodSignature
* @param interfaceName
* @return
*/
public static Collection<MethodBinding> getInterfaceInheritedMethodBindings(
String methodName, String methodSignature, String interfaceName) {
List<MethodBinding> result = new LinkedList<MethodBinding>();
if (boundBaseInterfaces.contains(interfaceName)) {
LinkedList<RoleBaseBinding> rbbList = baseBindings.get(interfaceName);
if (rbbList != null) {
Iterator<RoleBaseBinding> rbb_it = rbbList.iterator();
while (rbb_it.hasNext()) {
RoleBaseBinding rbb = rbb_it.next();
List<MethodBinding> mbs = rbb.getBaseMethodBindings(methodName, methodSignature);
if (mbs != null)
result.addAll(mbs);
}
}
}
return result;
}
/**
* @param interfaceNames
* @return
*/
public static boolean containsBoundBaseInterface(String[] interfaceNames) {
for (int i = 0; i < interfaceNames.length; i++) {
if (boundBaseInterfaces.contains(interfaceNames[i]))
return true;
}
return false;
}
// -----------------------------------------------
// precedence can be set for a list of method bindings:
// -----------------------------------------------
private static ListValueHashMap<List<String>> precedencePerTeam = new ListValueHashMap<List<String>>();
/**
* Add a precedence list for the given team.
* @param precedenceList the list of binding labels defining their precedence
* @param teamName the name of the team for which the precedence list was defined
*/
public static void addPrecedenceList(List<String> precedenceList, String teamName) {
precedencePerTeam.put(teamName, precedenceList);
}
/**
* Sorts the method binding list according to the given precedence for the team
* @param mbList the list of 'MethodBinding's to be sorted
* @param teamName the name of the corresponding team
* @return the sorted 'MethodBindig' list
*/
public static List<MethodBinding> sortMethodBindings(List<MethodBinding> mbList, String teamName) {
if (mbList.size() < 2)
return mbList; // nothing to sort
String outermostTeamName;
int dollarIdx = teamName.indexOf('$');
if (dollarIdx > 0)
outermostTeamName = teamName.substring(0, dollarIdx);
else outermostTeamName = teamName;
List<List<String>> precedenceList = precedencePerTeam.get(outermostTeamName);
if (precedenceList==null) {
// mbList has to be reduced by removing overridden bindings:
return removeOverridden(mbList);
}
LinkedList<MethodBinding> sortedMethodBindings = new LinkedList<MethodBinding>();
Iterator<List<String>> predIt = precedenceList.iterator();
while (predIt.hasNext()) {
List<String> plainList = predIt.next();
Iterator<String> plainIt = plainList.iterator();
while (plainIt.hasNext()) {
boolean foundOne = false;
String label = plainIt.next();
Iterator<MethodBinding> mbIter = mbList.iterator();
List<MethodBinding> alreadySorted = new LinkedList<MethodBinding>();
while (mbIter.hasNext()) {
MethodBinding mb = mbIter.next();
if (mb.getQualifiedBindingLabel().equals(label)) { // mb exactly fits binding label:
alreadySorted.add(mb);
if (!foundOne) {
sortedMethodBindings.add(mb);
foundOne = true;
} else checkInheritance(sortedMethodBindings.getLast(), mb);
} else if (mb.inheritsBindingLabel(label, teamName)) { // mb inherits binding label:
alreadySorted.add(mb);
if (!foundOne) {
sortedMethodBindings.add(mb);
foundOne = true;
} else {// maybe it is a subtype of the already added?
MethodBinding lastAdded = sortedMethodBindings.getLast();
if (mb.overridesMethodBinding(lastAdded)) {
sortedMethodBindings.set(sortedMethodBindings.size()-1, mb);
foundOne = true;
} else checkInheritance(sortedMethodBindings.getLast(), mb);
}
}
}
if (foundOne) {
Iterator<MethodBinding> sortedIter = alreadySorted.iterator();
while (sortedIter.hasNext()) {
MethodBinding mb = sortedIter.next();
mbList.remove(mb);
}
}
}
}
// if (mbList.size() > 0) {
// System.err.println("ERROR: Unsortable method bindings: " + mbList +"!");
// // assumption: all remaining method bindings are overridden! TODO: check assumption!
// }
return sortedMethodBindings;
}
/**
* Removes overridden method bindings from the given list. Assumes that
* all bindings in the list are in a sub/super type relationship.
* @param mbList the method binding list
* @return the most specific method binding overriding all others
*/
private static List<MethodBinding> removeOverridden(List<MethodBinding> mbList) {
MethodBinding mostSpecificMB = mbList.get(0);
Iterator<MethodBinding> mbIter = mbList.iterator();
while (mbIter.hasNext()) {
MethodBinding mb = mbIter.next();
if (mb.overridesMethodBinding(mostSpecificMB)) {
mostSpecificMB = mb;
} else checkInheritance(mostSpecificMB, mb);
}
List<MethodBinding> resultList = new LinkedList<MethodBinding>();
resultList.add(mostSpecificMB);
return resultList;
}
/**
* Checks if 'subMB' 'inherits' from 'superMB'. Used to check if assumptions
* about the precedence lists are fulfilled.
*
* @param subMB the overriding method binding
* @param superMB the overridden method binding
*/
private static void checkInheritance(MethodBinding subMB, MethodBinding superMB) {
if (! (subMB.equals(superMB) || subMB.overridesMethodBinding(superMB))) {
//System.err.println("sub: " + subMB + "\n super: " + superMB);
throw new OTREInternalError("Wrong assumption! Broken precedence list possible.");
}
}
// ------------------------------------------
// ---------- Logging: ----------------------
// ------------------------------------------
/** Initialized from property <tt>ot.log</tt>. */
static boolean logging = false;
/** Initialized from property <tt>otequinox.debug</tt> */
static boolean OTEQUINOX_WARN = false;
static {
if(System.getProperty("ot.log") != null)
logging = true;
String warnlevel = System.getProperty("otequinox.debug");
if (warnlevel != null) {
warnlevel = warnlevel.toUpperCase();
if (warnlevel.startsWith("INFO") || warnlevel.equals("OK"))
OTEQUINOX_WARN = true;
}
}
// -----------------------------------------------
// static replace callin bindings have to be stored in the team, special treatment:
// -----------------------------------------------
// maps an implemented role method to its base methods: roleMethod -> List[baseMethod] // added by JU
private static ListValueHashMap<BaseMethodInfo> staticReplaceBindings = new ListValueHashMap<BaseMethodInfo>();
/**
* Adds a base method to its implemented role method (static replace bindings).
*
* @param roleMethodKey a string structured according team_class_ name.role_class_name.role_method_name.role_method_signature
* @param baseMethodInfo an Object contained base class name, base method name and base method signature
*/
public static void addStaticReplaceBindingForRoleMethod(String roleMethodKey, BaseMethodInfo baseMethodInfo) {
staticReplaceBindings.put(roleMethodKey, baseMethodInfo);
}
/**
* Returns static method bindings for the given role method
* @param roleMethodKey
* @return
*/
public static LinkedList<BaseMethodInfo> getStaticReplaceBindingsForRoleMethod(String roleMethodKey) {
return staticReplaceBindings.get(roleMethodKey);
}
/**
* @param roleClassName
* @param roleMethodName
* @param roleMethodSignature
* @return
*/
public static boolean roleMethodHasBinding(String roleClassName, String roleMethodName, String roleMethodSignature) {
RoleBaseBinding rbb = roleBindings.get(roleClassName);
if (rbb == null) {
return false;
}
return rbb.hasRoleMethodBinding(roleMethodName, roleMethodSignature);
}
// -----------------------------------------------
// access modifiers of some base classes have to be changed to 'public' (decapsulation)
// the names of these classes are stored in baseClassesForModifierChange
// -----------------------------------------------
private static LinkedList<String> baseClassesForModifierChange = new LinkedList<String>();
/**
* Adds the given class name to the list of class names intended for decapsulation
* @param className
*/
public static void addBaseClassForModifierChange(String className){
baseClassesForModifierChange.add(className);
}
/**
* Checks whether a class name is contained in the list of classes intended for decapsulation
* @param className
* @return
*/
public static boolean checkBaseClassModifierChange(String className) {
Iterator<String> iter = baseClassesForModifierChange.iterator();
while(iter.hasNext()) {
if(className.equals(iter.next())){
return true;
}
}
return false;
}
public static void addBoundSuperclassLink(String sub_name, String super_name) {
synchronized (baseBindings) {
bases:
for (RoleBaseBinding subBinding : baseBindings.getFlattenValues()) {
if (subBinding.getBaseClassName().equals(sub_name)) {
for (RoleBaseBinding superBinding : baseBindings.getFlattenValues()) {
if (subBinding == superBinding) continue;
if (superBinding.getBaseClassName().equals(super_name)) {
subBinding.getBaseClass().setSuper(superBinding.getBaseClass());
break bases;
}
}
}
}
}
}
/** Either retrieve an existing BoundClass for `className' are create a new one.
* If an existing one is used it is updated for the new adapting team.
*/
public static BoundClass getBoundBaseClass(String className, String teamClassName) {
for (RoleBaseBinding subBinding : baseBindings.getFlattenValues()) {
if (subBinding.getBaseClassName().equals(className)) {
BoundClass baseClass = subBinding.getBaseClass();
baseClass.addAdaptingTeam(teamClassName);
return baseClass;
}
}
return new BoundClass(className, teamClassName);
}
// ==== HELPERS FOR RE-ENTRANCE SAFETY: ====
private static Iterator<String> getBaseBindingsKeyIterator() {
synchronized (baseBindings) {
ArrayList<String> list = new ArrayList<String>();
list.addAll(baseBindings.keySet());
Iterator<String> it = list.iterator();
return it;
}
}
private static Iterator<Entry<String, LinkedList<RoleBaseBinding>>> getBaseBindingsCloneIterator() {
synchronized (baseBindings) {
ArrayList<Entry<String, LinkedList<RoleBaseBinding>>> list = new ArrayList<Entry<String,LinkedList<RoleBaseBinding>>>();
list.addAll(baseBindings.entrySet());
Iterator<Entry<String, LinkedList<RoleBaseBinding>>> it = list.iterator();
return it;
}
}
}