/* * Copyright 2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.wamblee.system.adapters; import java.awt.CompositeContext; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.wamblee.collections.CollectionFilter; import org.wamblee.conditions.Condition; import org.wamblee.conditions.FixedCondition; import org.wamblee.general.Pair; import org.wamblee.system.core.DefaultProvidedInterface; import org.wamblee.system.core.DefaultRequiredInterface; import org.wamblee.system.core.ProvidedInterface; import org.wamblee.system.core.RequiredInterface; import org.wamblee.system.core.Scope; import org.wamblee.system.core.SystemAssemblyException; /** * Represents the configuration for exposing the setters of a class as required * interfaces. * * @author Erik Brakkee */ public class SetterConfiguration { private Class _class; private boolean _publicOnly; private List> _setters; /** * Constructs the setter configuration. By default all setters are added. * * @param aClass * Class which is being configured. */ public SetterConfiguration(Class aClass) { _class = aClass; _publicOnly = true; _setters = getAllSetters(_class, _publicOnly); } /** * Called to set whether non-public setters are also used. By default only * public setters are used. * * @param aIsNonPublic * Non public flag. */ public void setNonPublic(boolean aIsNonPublic) { _publicOnly = !aIsNonPublic; _setters = getAllSetters(_class, _publicOnly); } /** * Removes all setters. * * @return Reference to the current object to allow call chaining. */ public SetterConfiguration clear() { _setters.clear(); return this; } /** * Removes a setter from the set of methods. * * @param aName * Name of the setter to remove (without the "set" prefix). * @return Reference to the current object to allow call chaining. */ public SetterConfiguration remove(String aName) { final String name = createSetterName(aName); List> setters = new ArrayList>(); CollectionFilter.filter(_setters, setters, new Condition>() { @Override public boolean matches(Pair aObject) { return !aObject.getFirst().getName().equals(name); } }); if (_setters.size() == setters.size()) { throw new IllegalArgumentException( "No setter configured by the name of '" + aName + "'"); } _setters = setters; return this; } /** * Creates the name of a setter based on the name of the setter without the * "set" prefix. * * @param aName * Setter name. * @return Setter name. */ private String createSetterName(String aName) { return "set" + aName.substring(0, 1).toUpperCase() + aName.substring(1); } /** * Adds a given setter name to the setters. * * @param aName * @return Reference to the current object to allow call chaining. */ public SetterConfiguration add(String aName) { final String name = createSetterName(aName); int oldlen = _setters.size(); CollectionFilter.filter(getAllSetters(_class, false), _setters, new Condition>() { @Override public boolean matches(Pair aObject) { return aObject.getFirst().getName().equals(name); } }); if (_setters.size() == oldlen) { throw new IllegalArgumentException("No setter found for '" + aName + "' in " + _class.getName()); } return this; } /** * Gets all setters for the current class. * * @return List of all setters. */ private static List> getAllSetters( Class aClass, boolean aPublicOnly) { List> result = new ArrayList>(); for (Method method : getAllMethods(aClass)) { if (!aPublicOnly || Modifier.isPublic(method.getModifiers())) { if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) { method.setAccessible(true); String name = getSetterName(method); result .add(new Pair(method, new ParameterValues(new String[] { name }, new Class[] { method .getParameterTypes()[0] }))); } } } return result; } private static final List getAllMethods(Class aClass) { List result = new ArrayList(); result.addAll(Arrays.asList(aClass.getDeclaredMethods())); Class superClass = aClass.getSuperclass(); if ( superClass != null ) { result.addAll(getAllMethods(superClass)); } return result; } /** * Gets the required interfaces based on the configured setteres. * * @return List of required interfaces. */ public List getRequiredInterfaces() { List result = new ArrayList(); for (Pair method : _setters) { result.addAll(method.getSecond().getRequiredInterfaces()); } return result; } /** * Invokes all configured setters with the appropriate values. * * @param aScope * Scope within which invocation takes place. * @param aObject * Object on which the invocation takes place. */ public void inject(Scope aScope, Object aObject) { if (!_class.isInstance(aObject)) { throw new IllegalArgumentException("Object '" + aObject + "' is not an instance of " + _class.getName()); } for (Pair setter : _setters) { Method method = setter.getFirst(); ParameterValues values = setter.getSecond(); try { method.invoke(aObject, values.values(aScope)); } catch (IllegalAccessException e) { throw new SystemAssemblyException("Problem invoking " + method + " with " + values, e); } catch (InvocationTargetException e) { throw new SystemAssemblyException("Problem invoking " + method + " with " + values, e); } } } /** * Returns the parameter values for allowing detailed configuration of how * parameter values are set. * * @param aSetter * Setter name without the "set" prefix with the first character * converted to lower case. * @return Parameter values. */ public ParameterValues values(String aMethod) { String name = createSetterName(aMethod); for (Pair method : _setters) { if (method.getFirst().getName().equals(name)) { return method.getSecond(); } } throw new IllegalArgumentException("No setter method '" + name + "' found"); } /** * Gets the setter name for a given setter method. This is the name of the * setter without the "set" prefix and with the first character converted to * lowercase. * * @param aMethod * Method. * @return Setter name. */ private static String getSetterName(Method aMethod) { String result = aMethod.getName().substring(3); return result.substring(0, 1).toLowerCase() + result.substring(1); } }