Author: mes
Date: 2012-03-16 14:43:48 -0700 (Fri, 16 Mar 2012)
New Revision: 28569
Added:
core3/api/trunk/work-api/src/main/java/org/cytoscape/work/ContainsTunables.java
core3/support/trunk/task-testing-impl/src/main/java/org/cytoscape/internal/test/tunables/JustTunables.java
Modified:
core3/api/trunk/work-api/src/main/java/org/cytoscape/work/AbstractTunableInterceptor.java
core3/api/trunk/work-api/src/test/java/org/cytoscape/work/AbstractTunableInterceptorTest.java
core3/impl/trunk/command-executor-impl/src/main/java/org/cytoscape/command/internal/tunables/CommandTunableInterceptorImpl.java
core3/impl/trunk/swing-application-impl/src/main/java/org/cytoscape/internal/commands/ArgRecorder.java
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/submenu/SubmenuTunableMutator.java
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/sync/SyncTunableMutator.java
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/tunables/JPanelTunableMutator.java
core3/support/trunk/task-testing-impl/src/main/java/org/cytoscape/internal/test/tunables/ScootersTunableTask.java
Log:
Added support for ContainsTunable annotation which allows tunables to be
composed from multiple objects.
Modified:
core3/api/trunk/work-api/src/main/java/org/cytoscape/work/AbstractTunableInterceptor.java
===================================================================
---
core3/api/trunk/work-api/src/main/java/org/cytoscape/work/AbstractTunableInterceptor.java
2012-03-16 21:37:08 UTC (rev 28568)
+++
core3/api/trunk/work-api/src/main/java/org/cytoscape/work/AbstractTunableInterceptor.java
2012-03-16 21:43:48 UTC (rev 28569)
@@ -53,14 +53,9 @@
/**
* Store the Handlers.
*/
- protected final Map<Object, LinkedHashMap<String, T>> handlerMap;
+ protected final Map<Object, List<T>> handlerMap;
/**
- * Store the JPanel-returning methods.
- */
- protected final Map<Object, Method> guiProviderMap;
-
- /**
* Store the title-returning methods.
*/
protected final Map<Object, Method> titleProviderMap;
@@ -77,8 +72,7 @@
*/
public AbstractTunableInterceptor() {
throwException = false;
- handlerMap = new HashMap<Object, LinkedHashMap<String, T>>();
- guiProviderMap = new HashMap<Object, Method>();
+ handlerMap = new HashMap<Object, List<T>>();
titleProviderMap = new HashMap<Object, Method>();
tunableHandlerFactories = new
ArrayList<TunableHandlerFactory<T>>();
}
@@ -88,7 +82,6 @@
this.throwException = throwException;
}
- // TODO make this private!!!
/**
* To detect fields and methods annotated with {@link Tunable}, create
* a {@link TunableHandler} for each from the factory, and store it in
handlerMap.
@@ -96,9 +89,11 @@
* @param obj A class that contains fields or methods annotated with
{@link Tunable}
* whose value needs to be set or recorded.
*/
- protected void loadTunables(final Object obj) {
- if (!handlerMap.containsKey(obj)) {
- final LinkedHashMap<String, T> handlerList = new
LinkedHashMap<String, T>();
+ private List<T> loadTunables(final Object obj) {
+ List<T> handlerList = handlerMap.get(obj);
+ if (handlerList == null) {
+ handlerList = new ArrayList<T>();
+ handlerMap.put(obj, handlerList);
// Find each public field in the class.
for (final Field field : obj.getClass().getFields()) {
@@ -113,18 +108,27 @@
// ...add it to the list of
Handlers
if (handler != null)
-
handlerList.put(field.getName(), handler);
+
handlerList.add(handler);
else
logOrThrowException("No
handler for type: " + field.getType().getName(), null);
} catch (final Throwable ex) {
- logOrThrowException("tunable
field intercept failed for "
- + field.toString(),
ex);
+ logOrThrowException("tunable
field intercept failed for " + field.toString(), ex);
}
+
+ // Evaluate fields for ContainsTunables
annotation. If the field
+ // is annotated, then get the object from the
field and evaluate
+ // *it* for tunables.
+ } else if
(field.isAnnotationPresent(ContainsTunables.class)) {
+ try {
+ Object tunableContainer =
field.get(obj);
+ if (
!handlerMap.containsKey(tunableContainer) )
+ handlerList.addAll(
loadTunables(tunableContainer) );
+ } catch (final Throwable ex) {
+
logOrThrowException("ContainsTunables field intercept failed for " +
field.toString(), ex);
+ }
}
}
- guiProviderMap.clear();
-
// Find each public method in the class.
for (final Method method : obj.getClass().getMethods())
{
// See if the method is annotated as a Tunable.
@@ -139,43 +143,30 @@
if (handler == null) {
logOrThrowException("Failed to create a handler for " + setter.getName() +
"()!",null);
} else {
-
handlerList.put("getset" + rootName, handler);
+
handlerList.add(handler);
}
} catch (Throwable t) {
logOrThrowException("tunable
method intercept failed for " + method.toString(), t);
}
- }else if
(method.isAnnotationPresent(ProvidesTitle.class)) {
+ } else if
(method.isAnnotationPresent(ProvidesTitle.class)) {
if
(!String.class.isAssignableFrom(method.getReturnType())) {
throw new
IllegalArgumentException(method.getName() + " annotated with @ProvidesTitle
must return String!");
} else if
(method.getParameterTypes().length != 0) {
throw new
IllegalArgumentException(method.getName() + " annotated with @ProvidesTitle
must take 0 arguments!");
} else {
if
(titleProviderMap.containsKey(obj)) {
- throw new
IllegalArgumentException("Classes must have at most a single @ProvidesTitle
annotated method but + "
- +
method.getDeclaringClass().getName() + " has more than one!");
+ throw new
IllegalArgumentException("Classes must have at most one @ProvidesTitle
annotated method but " + method.getDeclaringClass().getName() + " has more than
one!");
}
titleProviderMap.put(obj,
method);
}
}
}
-
- handlerMap.put(obj, handlerList);
}
+
+ return handlerList;
}
- private boolean isJPanelOrJPanelDescendent(final Class c) {
- Class c0 = c;
- while (c0 != null && c0 != Object.class) {
- // hack so that we don't need to import swing
- if (c0.getName().equals( "javax.swing.JPanel" ))
- return true;
- c0 = c0.getSuperclass();
- }
-
- return false;
- }
-
private boolean isValidGetter(final Method getterCandidate) {
// Make sure we're not returning "void":
try {
@@ -216,14 +207,11 @@
* @return The map that contains all the {@link TunableHandler} objects
that have been
* found to process the fields and methods annotated with {@link
Tunable}.
*/
- public final Map<String, T> getHandlers(final Object o) {
+ public final List<T> getHandlers(final Object o) {
if (o == null)
return null;
- // this is a no-op if tunables have already been loaded
- loadTunables(o);
-
- return handlerMap.get(o);
+ return loadTunables(o);
}
/**
@@ -234,8 +222,17 @@
*/
public boolean hasTunables(final Object o) {
for (final Field field : o.getClass().getFields()) {
- if (field.isAnnotationPresent(Tunable.class))
+ if (field.isAnnotationPresent(Tunable.class)) {
return true;
+ } else if
(field.isAnnotationPresent(ContainsTunables.class)) {
+ try {
+ Object tunableContainer = field.get(o);
+ return hasTunables(tunableContainer);
+ } catch (final Throwable ex) {
+ logger.debug("ContainsTunables field
intercept failed for " + field.toString(), ex);
+ return false;
+ }
+ }
}
for (final Method method : o.getClass().getMethods()) {
if (method.isAnnotationPresent(Tunable.class))
Added:
core3/api/trunk/work-api/src/main/java/org/cytoscape/work/ContainsTunables.java
===================================================================
---
core3/api/trunk/work-api/src/main/java/org/cytoscape/work/ContainsTunables.java
(rev 0)
+++
core3/api/trunk/work-api/src/main/java/org/cytoscape/work/ContainsTunables.java
2012-03-16 21:43:48 UTC (rev 28569)
@@ -0,0 +1,38 @@
+package org.cytoscape.work;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * An annotation designed to signal that the annotated field contains
+ * fields and methods that are annotated with the Tunable annotation.
+ * The goal is to allow rich tunable collections to be created by
+ * combining the tunables found in fields annotated with ContainsTunables.
+ * <br/>
+ * For example, given classes A and B:
+ * <p><pre><code>
+ *
+ * public class A {
+ * @Tunable
+ * public int value = 5;
+ * }
+ *
+ * public class B {
+ * @ContainsTunable
+ * public A a = new A();
+ * @Tunable
+ * public String name = "homer";
+ * }
+ *
+ * </code></pre></p>
+ * When class B is evaluated for Tunables, it should display a tunable
+ * for both the "name" and "value" fields.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD})
+public @interface ContainsTunables {
+}
Modified:
core3/api/trunk/work-api/src/test/java/org/cytoscape/work/AbstractTunableInterceptorTest.java
===================================================================
---
core3/api/trunk/work-api/src/test/java/org/cytoscape/work/AbstractTunableInterceptorTest.java
2012-03-16 21:37:08 UTC (rev 28568)
+++
core3/api/trunk/work-api/src/test/java/org/cytoscape/work/AbstractTunableInterceptorTest.java
2012-03-16 21:43:48 UTC (rev 28569)
@@ -58,8 +58,8 @@
@Test
public final void testLoadTunables() {
- interceptor.loadTunables(hasAnnotatedField);
- interceptor.loadTunables(hasAnnotatedSetterAndGetterMethods);
+ interceptor.getHandlers(hasAnnotatedField);
+ interceptor.getHandlers(hasAnnotatedSetterAndGetterMethods);
}
@Test
@@ -70,44 +70,74 @@
@Test(expected=IllegalArgumentException.class)
public final void testInvalidGetter() {
- interceptor.loadTunables(new HasInvalidGetter());
+ interceptor.getHandlers(new HasInvalidGetter());
}
@Test(expected=IllegalArgumentException.class)
public final void testInvalidGetterReturnType() {
- interceptor.loadTunables(new HasInvalidGetterReturnType());
+ interceptor.getHandlers(new HasInvalidGetterReturnType());
}
@Test(expected=IllegalArgumentException.class)
public final void testMisnamedGetter() {
- interceptor.loadTunables(new HasMisnamedGetter());
+ interceptor.getHandlers(new HasMisnamedGetter());
}
@Test(expected=IllegalArgumentException.class)
public final void testInvalidSetter() {
- interceptor.loadTunables(new HasInvalidSetter());
+ interceptor.getHandlers(new HasInvalidSetter());
}
@Test(expected=IllegalArgumentException.class)
public final void testInvalidAnnotatedType() {
- interceptor.loadTunables(new HasInvalidAnotatedType());
+ interceptor.getHandlers(new HasInvalidAnotatedType());
}
@Test(expected=IllegalArgumentException.class)
public final void testSetterAnnotatedInsteadOfGetter() {
- interceptor.loadTunables(new SetterAnnotatedInsteadOfGetter());
+ interceptor.getHandlers(new SetterAnnotatedInsteadOfGetter());
}
@Test
public final void testInheritedField() {
assertTrue( interceptor.hasTunables( new ExtendedFieldClass() )
);
+ assertTrue( interceptor.getHandlers( new ExtendedFieldClass()
).size() > 0 );
}
@Test
public final void testInheritedMethod() {
assertTrue( interceptor.hasTunables( new ExtendedMethodClass()
) );
+ assertTrue( interceptor.getHandlers( new ExtendedMethodClass()
).size() > 0 );
}
+
+ @Test
+ public final void testJustContainsTunables() {
+ Object o = new ContainsTunablesClass();
+ assertTrue( interceptor.hasTunables( o ) );
+ assertTrue( interceptor.getHandlers(o).size() > 0 );
+ }
+
+ @Test
+ public final void testContainsTunablesAndTunables() {
+ Object o = new ContainsTunablesAndTunablesClass();
+ assertTrue( interceptor.hasTunables( o ) );
+ assertTrue( interceptor.getHandlers(o).size() > 1 );
+ }
+
+ @Test
+ public final void testContainsTunablesRecusion() {
+ Object o = new ContainsTunablesClass2();
+ assertTrue( interceptor.hasTunables( o ) );
+ assertTrue( interceptor.getHandlers(o).size() > 0 );
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public final void testContainsTunablesUninitialized() {
+ Object o = new UninitializedContainsTunablesClass();
+ interceptor.getHandlers(o);
+ }
+
}
class FakeTunableHandler extends AbstractTunableHandler {
@@ -120,27 +150,11 @@
public void handle() {}
}
-
-//class SimpleHandlerFactory implements
TunableHandlerFactory<AbstractTunableHandler> {
-// public AbstractTunableHandler getHandler(final Field field, final
Object instance, final Tunable tunable) {
-// return new FakeTunableHandler(field, instance, tunable);
-// }
-//
-// public AbstractTunableHandler getHandler(final Method setter, final
Method getter, final Object instance, final Tunable tunable) {
-// return new FakeTunableHandler(setter, getter, instance,
tunable);
-// }
-//}
-
-
class ConcreteTunableInterceptor extends AbstractTunableInterceptor {
public boolean validateAndWriteBackTunables(Object... objs) {
return true;
}
-
- public boolean execUI(Object... obs) {
- return true;
- }
}
@@ -202,3 +216,33 @@
class ExtendedMethodClass extends BaseMethodClass {
}
+
+class ContainsTunablesClass {
+ @ContainsTunables
+ public BaseMethodClass bmc = new BaseMethodClass();
+}
+
+
+class ContainsTunablesClass2 {
+ @ContainsTunables
+ public ContainsTunablesClass ctc = new ContainsTunablesClass();
+}
+
+class ContainsTunablesAndTunablesClass {
+
+ @ContainsTunables
+ public BaseMethodClass bmc = new BaseMethodClass();
+
+ @Tunable
+ public int getXValue() { return 0; }
+
+ public void setXValue(int a) { };
+
+ @Tunable
+ public int yValue;
+}
+
+class UninitializedContainsTunablesClass {
+ @ContainsTunables
+ public BaseMethodClass bmc;
+}
Modified:
core3/impl/trunk/command-executor-impl/src/main/java/org/cytoscape/command/internal/tunables/CommandTunableInterceptorImpl.java
===================================================================
---
core3/impl/trunk/command-executor-impl/src/main/java/org/cytoscape/command/internal/tunables/CommandTunableInterceptorImpl.java
2012-03-16 21:37:08 UTC (rev 28568)
+++
core3/impl/trunk/command-executor-impl/src/main/java/org/cytoscape/command/internal/tunables/CommandTunableInterceptorImpl.java
2012-03-16 21:43:48 UTC (rev 28569)
@@ -1,6 +1,5 @@
package org.cytoscape.command.internal.tunables;
-
import java.util.Map;
import org.cytoscape.work.AbstractTunableInterceptor;
@@ -23,8 +22,7 @@
// Get the handlers for the tunables in the Task. The
// key is the name of the tunable and the value is the
handler
// for that tunable.
- Map<String,StringTunableHandler> handlers =
getHandlers(o);
- for ( StringTunableHandler h : handlers.values() ) {
+ for ( StringTunableHandler h : getHandlers(o) ) {
// Give the handler the arg string and let it
do its thing,
// which will hopefully be: set the tunable
value based on
Modified:
core3/impl/trunk/swing-application-impl/src/main/java/org/cytoscape/internal/commands/ArgRecorder.java
===================================================================
---
core3/impl/trunk/swing-application-impl/src/main/java/org/cytoscape/internal/commands/ArgRecorder.java
2012-03-16 21:37:08 UTC (rev 28568)
+++
core3/impl/trunk/swing-application-impl/src/main/java/org/cytoscape/internal/commands/ArgRecorder.java
2012-03-16 21:43:48 UTC (rev 28569)
@@ -15,8 +15,7 @@
public List<String> findArgs(Object o) {
List<String> desc = new ArrayList<String>();
- Map<String,ArgHandler> handlers = getHandlers(o);
- for (final ArgHandler p : handlers.values())
+ for (final ArgHandler p : getHandlers(o))
desc.add( p.getDesc() );
return desc;
}
Modified:
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/submenu/SubmenuTunableMutator.java
===================================================================
---
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/submenu/SubmenuTunableMutator.java
2012-03-16 21:37:08 UTC (rev 28568)
+++
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/submenu/SubmenuTunableMutator.java
2012-03-16 21:43:48 UTC (rev 28569)
@@ -31,8 +31,7 @@
else
return null;
- Map<String,SubmenuTunableHandler> handlers = getHandlers(tf);
- for ( SubmenuTunableHandler handler : handlers.values() ) {
+ for ( SubmenuTunableHandler handler : getHandlers(tf) ) {
handler.setExecutionParams(dtm,tf);
handler.handle();
return handler.getSubmenuItem();
Modified:
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/sync/SyncTunableMutator.java
===================================================================
---
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/sync/SyncTunableMutator.java
2012-03-16 21:37:08 UTC (rev 28568)
+++
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/sync/SyncTunableMutator.java
2012-03-16 21:43:48 UTC (rev 28569)
@@ -27,9 +27,8 @@
@Override
public boolean validateAndWriteBack(Object o) {
- final Map<String, SyncTunableHandler> handlers = getHandlers(o);
- for (SyncTunableHandler handler : handlers.values()) {
+ for (SyncTunableHandler handler : getHandlers(o)) {
handler.setValueMap(map);
handler.handle();
}
Modified:
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/tunables/JPanelTunableMutator.java
===================================================================
---
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/tunables/JPanelTunableMutator.java
2012-03-16 21:37:08 UTC (rev 28568)
+++
core3/impl/trunk/work-swing-impl/impl/src/main/java/org/cytoscape/work/internal/tunables/JPanelTunableMutator.java
2012-03-16 21:43:48 UTC (rev 28569)
@@ -87,7 +87,7 @@
/** {@inheritDoc} */
public boolean validateAndWriteBack(Object objectWithTunables) {
- List<GUITunableHandler> handlers =
findHandlers(objectWithTunables);
+ List<GUITunableHandler> handlers =
getHandlers(objectWithTunables);
for (final GUITunableHandler h : handlers)
h.handle();
@@ -114,7 +114,7 @@
else
++otherCount;
- List<GUITunableHandler> handlers =
findHandlers(objectWithTunables);
+ List<GUITunableHandler> handlers =
getHandlers(objectWithTunables);
// Sanity check:
if (factoryCount > 0) {
@@ -330,20 +330,6 @@
return true;
}
- private List<GUITunableHandler> findHandlers(Object objectWithTunables)
{
- List<GUITunableHandler> handlers = new
ArrayList<GUITunableHandler>();
-
- // the call to getHandlers will populate guiProviderMap
- // note that map may be empty!
- Map<String, GUITunableHandler> tunableHandlerMap =
getHandlers(objectWithTunables);
-
-
- if ( tunableHandlerMap != null && !tunableHandlerMap.isEmpty() )
- handlers.addAll(tunableHandlerMap.values());
-
- return handlers;
- }
-
protected String getTitle(Object objectWithTunables) {
Method method = titleProviderMap.get(objectWithTunables);
if (method != null) {
Added:
core3/support/trunk/task-testing-impl/src/main/java/org/cytoscape/internal/test/tunables/JustTunables.java
===================================================================
---
core3/support/trunk/task-testing-impl/src/main/java/org/cytoscape/internal/test/tunables/JustTunables.java
(rev 0)
+++
core3/support/trunk/task-testing-impl/src/main/java/org/cytoscape/internal/test/tunables/JustTunables.java
2012-03-16 21:43:48 UTC (rev 28569)
@@ -0,0 +1,15 @@
+
+package org.cytoscape.internal.test.tunables;
+
+
+import org.cytoscape.work.Tunable;
+
+
+public class JustTunables {
+
+ @Tunable(description="Enter a value:",groups="Examples of Tunables From
Other Object")
+ public int value = 5;
+
+ @Tunable(description="Enter a name",groups="Examples of Tunables From
Other Object")
+ public String name = "Scooter";
+}
Modified:
core3/support/trunk/task-testing-impl/src/main/java/org/cytoscape/internal/test/tunables/ScootersTunableTask.java
===================================================================
---
core3/support/trunk/task-testing-impl/src/main/java/org/cytoscape/internal/test/tunables/ScootersTunableTask.java
2012-03-16 21:37:08 UTC (rev 28568)
+++
core3/support/trunk/task-testing-impl/src/main/java/org/cytoscape/internal/test/tunables/ScootersTunableTask.java
2012-03-16 21:43:48 UTC (rev 28569)
@@ -5,6 +5,7 @@
import org.cytoscape.work.AbstractTask;
import org.cytoscape.work.TaskMonitor;
import org.cytoscape.work.Tunable;
+import org.cytoscape.work.ContainsTunables;
import org.cytoscape.work.util.ListSingleSelection;
@@ -53,6 +54,9 @@
return aggregationType;
}
+ @ContainsTunables
+ public JustTunables someSortOfConfigObject = new JustTunables();
+
public void setAggregationType(ListSingleSelection<String> input) {
// Ignore because ListSingleSelection is set in the handler and
not here.
}
--
You received this message because you are subscribed to the Google Groups
"cytoscape-cvs" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/cytoscape-cvs?hl=en.