* @author Erik Brakkee
*/
public class ParameterValues {
+ private String[] _names;
private Class[] _types;
private ValueProvider[] _values;
* @param aClass Class to construct.
*/
public ParameterValues(Class[] aTypes) {
+ _names = new String[aTypes.length];
+ for (int i = 0; i < aTypes.length; i++) {
+ _names[i] = "arg" + i;
+ }
_types = aTypes;
resetValues();
}
+ /**
+ * Constructs the configuration. By default no constructor is selected and
+ * one of {@link #select(Class...)} or
+ * {@link #greedy()} must be called.
+ * @param aNames Names of the arguments.
+ * @param aClass Class to construct.
+ */
+ public ParameterValues(String[] aNames, Class[] aTypes) {
+ assert aNames.length == aTypes.length;
+ _names = aNames;
+ _types = aTypes;
+ resetValues();
+ }
+
+ /**
+ * The types of the parameter values.
+ * @return Types.
+ */
public Class[] getTypes() {
return _types;
}
_values = new ValueProvider[_types.length];
for (int i = 0; i < _values.length; i++) {
_values[i] = new RequiredInterfaceProvider(new DefaultRequiredInterface(
- "arg" + i, _types[i]));
+ _names[i], _types[i]));
}
}
+ /**
+ * Gets the required interfaces to provide values that are not provided
+ * in another way.
+ * @return Required interfaces.
+ */
public List<RequiredInterface> getRequiredInterfaces() {
List<RequiredInterface> result = new ArrayList<RequiredInterface>();
for (ValueProvider provider: _values) {
return result;
}
+ /**
+ * Returns the values to use in the given scope.
+ * @param aScope Scope within which to retrieve the values.
+ * @return Values.
+ */
public Object[] values(Scope aScope) {
Object[] values = new Object[_values.length];
for (int i = 0; i < _values.length; i++) {
--- /dev/null
+/*
+ * 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.util.ArrayList;
+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 List<Pair<Method, ParameterValues>> _setters;
+
+ /**
+ * Constructs the setter configuration. By default all setters are added.
+ *
+ * @param aClass
+ * Class which is being configured.
+ */
+ public SetterConfiguration(Class aClass) {
+ _class = aClass;
+ _setters = getAllSetters();
+ }
+
+ /**
+ * 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<Pair<Method,ParameterValues>> setters =
+ new ArrayList<Pair<Method,ParameterValues>>();
+ CollectionFilter.filter(_setters, setters, new Condition<Pair<Method,ParameterValues>>() {
+ @Override
+ public boolean matches(Pair<Method,ParameterValues> 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(), _setters,
+ new Condition<Pair<Method,ParameterValues>>() {
+ @Override
+ public boolean matches(Pair<Method,ParameterValues> aObject) {
+ return aObject.getFirst().getName().equals(name);
+ }
+
+ });
+ if ( _setters.size() == oldlen) {
+ throw new IllegalArgumentException("No setter found for '" + aName + "'");
+ }
+ return this;
+ }
+
+ /**
+ * Gets all setters for the current class.
+ * @return List of all setters.
+ */
+ private List<Pair<Method, ParameterValues>> getAllSetters() {
+ List<Pair<Method,ParameterValues>> result =
+ new ArrayList<Pair<Method, ParameterValues>>();
+ for (Method method : _class.getMethods()) {
+ if (method.getName().startsWith("set")
+ && method.getParameterTypes().length == 1) {
+ String name = getSetterName(method);
+ result.add(new Pair<Method,ParameterValues>(method,
+ new ParameterValues(
+ new String[] { name }, new Class[] { method.getParameterTypes()[0] })));
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Gets the required interfaces based on the configured setteres.
+ * @return List of required interfaces.
+ */
+ public List<RequiredInterface> getRequiredInterfaces() {
+ List<RequiredInterface> result = new ArrayList<RequiredInterface>();
+ for (Pair<Method,ParameterValues> 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 invoke(Scope aScope, Object aObject) {
+ if ( !_class.isInstance(aObject)) {
+ throw new IllegalArgumentException("Object '" + aObject + "' is not an instance of "
+ + _class.getName());
+ }
+ for (Pair<Method,ParameterValues> 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,ParameterValues> 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 String getSetterName(Method aMethod) {
+ String result = aMethod.getName().substring(3);
+ return result.substring(0,1).toLowerCase() + result.substring(1);
+ }
+
+}
--- /dev/null
+/*
+ * 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.util.Collections;
+import java.util.List;
+
+import org.wamblee.system.core.DefaultProvidedInterface;
+import org.wamblee.system.core.ProvidedInterface;
+import org.wamblee.system.core.RequiredInterface;
+import org.wamblee.system.core.RequiredInterfaceComparator;
+import org.wamblee.test.AssertionUtils;
+
+public class SetterConfigurationTest extends AdapterTestCase {
+
+ public void testOneSetter() {
+ SetterConfiguration config = new SetterConfiguration(X5.class);
+ List<RequiredInterface> required = config.getRequiredInterfaces();
+ assertEquals(1, required.size());
+ assertEquals("value", required.get(0).getName());
+
+ ProvidedInterface provided = new DefaultProvidedInterface("janse", String.class);
+ required.get(0).setProvider(provided);
+ provided.publish("hello", _scope);
+
+ X5 obj = new X5();
+ assertNull(obj.getValue());
+ config.invoke(_scope, obj);
+ assertEquals("hello", obj.getValue());
+ }
+
+ public void testMultipleSetters() {
+ SetterConfiguration config = new SetterConfiguration(X6.class);
+ List<RequiredInterface> required = config.getRequiredInterfaces();
+ Collections.sort(required, new RequiredInterfaceComparator());
+ assertEquals(2, required.size());
+ assertEquals("host", required.get(0).getName());
+ assertEquals("port", required.get(1).getName());
+
+ ProvidedInterface provided0 = new DefaultProvidedInterface("janse", String.class);
+ required.get(0).setProvider(provided0);
+ provided0.publish("hello", _scope);
+
+ ProvidedInterface provided1 = new DefaultProvidedInterface("port", Integer.class);
+ required.get(1).setProvider(provided1);
+ provided1.publish(10, _scope);
+
+ X6 obj = new X6();
+ assertNull(obj.getHost());
+ assertNull(obj.getPort());
+
+ config.invoke(_scope, obj);
+ assertEquals("hello", obj.getHost());
+ assertEquals(10, obj.getPort().intValue());
+ }
+
+ public void testInvokeWrongType() {
+ final SetterConfiguration config = new SetterConfiguration(X5.class);
+ List<RequiredInterface> required = config.getRequiredInterfaces();
+ assertEquals(1, required.size());
+ assertEquals("value", required.get(0).getName());
+
+ ProvidedInterface provided = new DefaultProvidedInterface("janse", String.class);
+ required.get(0).setProvider(provided);
+ provided.publish("hello", _scope);
+
+ final X6 obj = new X6();
+ AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+ @Override
+ public void run() throws Exception {
+ config.invoke(_scope, obj);
+ }
+ }, IllegalArgumentException.class);
+ }
+
+ public void testSetExplicitValue() {
+ SetterConfiguration config = new SetterConfiguration(X5.class);
+ config.values("value").setValue(0, "bladibla");
+
+ List<RequiredInterface> required = config.getRequiredInterfaces();
+ assertEquals(0, required.size());
+
+ X5 obj = new X5();
+ assertNull(obj.getValue());
+ config.invoke(_scope, obj);
+ assertEquals("bladibla", obj.getValue());
+ }
+
+ public void testClear() {
+ SetterConfiguration config = new SetterConfiguration(X6.class);
+ config.clear();
+ List<RequiredInterface> required = config.getRequiredInterfaces();
+ Collections.sort(required, new RequiredInterfaceComparator());
+ assertEquals(0, required.size());
+
+ X6 obj = new X6();
+ assertNull(obj.getHost());
+ assertNull(obj.getPort());
+
+ config.invoke(_scope, obj);
+
+ assertNull(obj.getHost());
+ assertNull(obj.getPort());
+ }
+
+ public void testAdd() {
+ SetterConfiguration config = new SetterConfiguration(X6.class);
+ config.clear().add("host");
+ List<RequiredInterface> required = config.getRequiredInterfaces();
+ Collections.sort(required, new RequiredInterfaceComparator());
+ assertEquals(1, required.size());
+ assertEquals("host", required.get(0).getName());
+
+ ProvidedInterface provided0 = new DefaultProvidedInterface("janse", String.class);
+ required.get(0).setProvider(provided0);
+ provided0.publish("hello", _scope);
+
+ X6 obj = new X6();
+ assertNull(obj.getHost());
+ assertNull(obj.getPort());
+
+ config.invoke(_scope, obj);
+ assertEquals("hello", obj.getHost());
+ assertNull(obj.getPort());
+ }
+
+ public void testAddNonExisting() {
+ final SetterConfiguration config = new SetterConfiguration(X6.class);
+ config.clear();
+
+ AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+ @Override
+ public void run() throws Exception {
+ config.add("bladibla");
+ }
+ }, IllegalArgumentException.class);
+ }
+
+ public void testRemove() {
+ SetterConfiguration config = new SetterConfiguration(X6.class);
+ config.remove("port");
+ List<RequiredInterface> required = config.getRequiredInterfaces();
+ Collections.sort(required, new RequiredInterfaceComparator());
+ assertEquals(1, required.size());
+ assertEquals("host", required.get(0).getName());
+
+ ProvidedInterface provided0 = new DefaultProvidedInterface("janse", String.class);
+ required.get(0).setProvider(provided0);
+ provided0.publish("hello", _scope);
+
+ X6 obj = new X6();
+ assertNull(obj.getHost());
+ assertNull(obj.getPort());
+
+ config.invoke(_scope, obj);
+ assertEquals("hello", obj.getHost());
+ assertNull(obj.getPort());
+ }
+
+ public void testRemoveNonExisting() {
+ final SetterConfiguration config = new SetterConfiguration(X6.class);
+
+ AssertionUtils.assertException(new AssertionUtils.ErroneousCode() {
+ @Override
+ public void run() throws Exception {
+ config.remove("bladibla");
+ }
+ }, IllegalArgumentException.class);
+ }
+}
--- /dev/null
+/*
+ * 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;
+
+public class X5 {
+
+ private String _value;
+
+ public X5() {
+
+ }
+
+ public void setValue(String aValue) {
+ AdapterTestCase.EVENT_TRACKER.eventOccurred("x5.setValue(" + aValue + ")");
+ _value = aValue;
+ }
+
+ public String getValue() {
+ return _value;
+ }
+
+ public void doSomething() {
+ // Empty.
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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;
+
+public class X6 {
+
+ private String _host;
+ private Integer _port;
+
+ public X6() {
+
+ }
+
+ public Integer getPort() {
+ return _port;
+ }
+
+ public void setPort(Integer aPort) {
+ _port = aPort;
+ }
+
+ public String getHost() {
+ return _host;
+ }
+
+ public void setHost(String aHost) {
+ _host = aHost;
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * 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.core;
+
+import java.util.Comparator;
+
+public class RequiredInterfaceComparator implements
+ Comparator<RequiredInterface> {
+
+ @Override
+ public int compare(RequiredInterface aO1, RequiredInterface aO2) {
+ return aO1.getName().compareTo(aO2.getName());
+ }
+
+}