All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fitlibrary.closure.LookupClosureStandard Maven / Gradle / Ivy

Go to download

FitLibrary provides general-purpose fixtures (and runners) for storytests with Fit and FitNesse.

The newest version!
/*
 * Copyright (c) 2009 Rick Mugridge, www.RimuResearch.com
 * Released under the terms of the GNU General Public License version 2 or later.
*/
package fitlibrary.closure;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import fitlibrary.exception.method.AmbiguousNameException;
import fitlibrary.traverse.workflow.DoEvaluator;
import fitlibrary.typed.TypedObject;
import fitlibrary.utility.ClassUtility;

public class LookupClosureStandard implements LookupClosure{
	private Map mapMethodSignatureToMethod = new ConcurrentHashMap(5000);
	private final Object NOT_FOUND = "";

	public void mustBeThreadSafe() {
		//
	}
	public Closure findMethodClosure(TypedObject typedObject, String methodName, int argCount) {
		Method chosenMethod = findMethod(typedObject.getSubject().getClass(), methodName, argCount, typedObject.getSubject());
		if (chosenMethod == null && aGetter(methodName, argCount))
			return findField(typedObject,extractFieldName(methodName));
		if (chosenMethod == null)
			return null;
		return new MethodClosure(typedObject,chosenMethod);
	}
	public Closure findPublicMethodClosure(TypedObject typedObject, String name, Class[] argTypes) {
		Object subject = typedObject.getSubject();
		if (subject == null)
			return null;
		try {
			return new MethodClosure(typedObject,subject.getClass().getMethod(name,argTypes));
        } catch (Exception e) {
            return null;
        }
	}
	public boolean fitLibrarySystemMethod(Method method, int argCount, Object subject) {
		if (!ClassUtility.fitLibrarySystemMethod(method))
			return false;
		if (subject instanceof DoEvaluator)
			return !((DoEvaluator)subject).methodsThatAreVisible().contains(method.getName()+"/"+argCount);
		return true;
	}
	protected Closure findField(TypedObject typedObject, String fieldName) {
		try {
			Class type = typedObject.getSubject().getClass();
			return new FieldClosure(typedObject,type.getField(fieldName));
		} catch (Exception e) {
			return findPrivateField(typedObject,fieldName);
		}
	}
	protected Closure findPrivateField(TypedObject typedObject, String fieldName) {
		Class type = typedObject.getSubject().getClass();
		Field[] declaredFields = type.getDeclaredFields();
		for (int i = 0; i < declaredFields.length; i++) {
			Field field = declaredFields[i];
			if (fieldName.equals(field.getName())) {
				field.setAccessible(true);
				return new FieldClosure(typedObject,field);
			}
		}
		return null;
	}
	protected Method findMethod(Class type, String name, int argCount, Object subject) {
		MethodSignature methodSignature = new MethodSignature(type,name,argCount);
		Object result = mapMethodSignatureToMethod.get(methodSignature);
		if (result != null) {
			if (result == NOT_FOUND)
				return null;
			return (Method) result;
		}
		Method chosenMethod = findSpecificMethod(type, name, argCount, subject);
		if (chosenMethod == null && (aGetter(name, argCount) || aSetter(name, argCount)))
			chosenMethod = findPrivateMethod(type,name,argCount,subject);
		if (chosenMethod == null)
			mapMethodSignatureToMethod.put(methodSignature, NOT_FOUND);
		else
			mapMethodSignatureToMethod.put(methodSignature, chosenMethod);
		return chosenMethod;
	}
	protected Method findSpecificMethod(Class type, String name, int argCount, Object subject) {
		Method[] methods = type.getMethods();
		Method chosenMethod = null;
		for (int i = 0; i < methods.length; i++) {
			Method method = methods[i];
			if (name.equals(method.getName()) && method.getParameterTypes().length == argCount && 
		            !fitLibrarySystemMethod(method,argCount,subject))
				if (chosenMethod == null)
					chosenMethod = method;
				else
					throw new AmbiguousNameException(name);
		}
		return chosenMethod;
	}
	protected String extractFieldName(String methodName) {
		String fieldName = "";
		if (methodName.startsWith("is"))
			fieldName = methodName.substring(2);
		else
			fieldName = methodName.substring(3);
		fieldName = Character.toLowerCase(fieldName.charAt(0))+fieldName.substring(1);
		return fieldName;
	}
	protected boolean aGetter(String name, int argCount) {
		boolean getter = name.startsWith("get") && name.length() > 3 && isUpper(name.charAt(3));
		boolean isa = name.startsWith("is") && name.length() > 2 && isUpper(name.charAt(2));
		return argCount == 0 && (getter || isa);
	}
	protected boolean isUpper(char ch) {
		return Character.isUpperCase(ch);
	}
	protected boolean aSetter(String name, int argCount) {
		return argCount == 1 && name.startsWith("set");
	}
	protected Method findPrivateMethod(Class type, String name, int args, Object subject) {
		Method chosenMethod = findMethod(type.getDeclaredMethods(), name, args,subject);
		if (chosenMethod != null) {
			chosenMethod.setAccessible(true);
			return chosenMethod;
		}
		if (type.getSuperclass() != null)
			return findPrivateMethod(type.getSuperclass(), name, args,subject);
		return null;
	}
	protected Method findMethod(Method[] methods, String name, int args, Object subject) {
		Method chosenMethod = null;
		for (int i = 0; i < methods.length; i++) {
			Method method = methods[i];
			if (name.equals(method.getName()) &&
		            method.getParameterTypes().length == args && 
		            !fitLibrarySystemMethod(method,args,subject))
				if (chosenMethod == null)
					chosenMethod = method;
				else
					throw new AmbiguousNameException(name);
		}
		return chosenMethod;
	}
	protected static class MethodSignature {
		private Class type;
		private String name;
		private int args;

		public MethodSignature(Class type, String name, int args) {
			this.type = type;
			this.name = name;
			this.args = args;
		}
		@Override
		public boolean equals(Object object) {
			if (!(object instanceof MethodSignature))
				return false;
			MethodSignature signature = (MethodSignature) object;
			return type == signature.type && name.equals(signature.name)
				&& args == signature.args;
		}
		@Override
		public int hashCode() {
			return type.hashCode()+name.hashCode()+args;
		}
		@Override
		public String toString() {
			return type+"."+name+"("+args+")";
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy