Skip to content

Commit

Permalink
Unify listeners on the server side
Browse files Browse the repository at this point in the history
This patch updates server side add*Listener methods to return
a registration object and deprecates their corresponding
remove*Listener methods.

Additionally this patch removes add/removeListener methods which were
deprecated in 7.0.

Change-Id: I26ac5f11882512288fbbf601c7cb2aaff653ec76
  • Loading branch information
ahie authored and Denis Anisimov committed Sep 29, 2016
1 parent 599b61b commit 2bee988
Show file tree
Hide file tree
Showing 156 changed files with 1,084 additions and 981 deletions.
Expand Up @@ -20,6 +20,9 @@
import java.lang.reflect.Method;

import com.vaadin.event.ConnectorEventListener;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.ui.Component;
import com.vaadin.util.ReflectTools;
import com.vaadin.v7.ui.Field;
Expand All @@ -32,6 +35,68 @@
@Deprecated
public interface FieldEvents {

/**
* The interface for adding and removing <code>FocusEvent</code> listeners.
* By implementing this interface a class explicitly announces that it will
* generate a <code>FocusEvent</code> when it receives keyboard focus.
*
* @since 6.2
* @see FocusListener
* @see FocusEvent
*/
@Deprecated
public interface FocusNotifier extends Serializable {
/**
* Adds a <code>FocusListener</code> to the Component which gets fired
* when a <code>Field</code> receives keyboard focus.
*
* @param listener
* @see FocusListener
* @since 6.2
*/
public void addFocusListener(FocusListener listener);

/**
* Removes a <code>FocusListener</code> from the Component.
*
* @param listener
* @see FocusListener
* @since 6.2
*/
public void removeFocusListener(FocusListener listener);
}

/**
* The interface for adding and removing <code>BlurEvent</code> listeners.
* By implementing this interface a class explicitly announces that it will
* generate a <code>BlurEvent</code> when it loses keyboard focus.
*
* @since 6.2
* @see BlurListener
* @see BlurEvent
*/
@Deprecated
public interface BlurNotifier extends Serializable {
/**
* Adds a <code>BlurListener</code> to the Component which gets fired
* when a <code>Field</code> loses keyboard focus.
*
* @param listener
* @see BlurListener
* @since 6.2
*/
public void addBlurListener(BlurListener listener);

/**
* Removes a <code>BlurListener</code> from the Component.
*
* @param listener
* @see BlurListener
* @since 6.2
*/
public void removeBlurListener(BlurListener listener);
}

/**
* TextChangeEvents are fired when the user is editing the text content of a
* field. Most commonly text change events are triggered by typing text with
Expand Down
Expand Up @@ -24,15 +24,15 @@

import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.BlurNotifier;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.event.FieldEvents.FocusNotifier;
import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.ui.LegacyComponent;
import com.vaadin.ui.declarative.DesignAttributeHandler;
import com.vaadin.ui.declarative.DesignContext;
import com.vaadin.v7.event.FieldEvents.BlurNotifier;
import com.vaadin.v7.event.FieldEvents.FocusNotifier;
import com.vaadin.v7.event.FieldEvents.TextChangeEvent;
import com.vaadin.v7.event.FieldEvents.TextChangeListener;
import com.vaadin.v7.event.FieldEvents.TextChangeNotifier;
Expand Down
Expand Up @@ -24,7 +24,6 @@
import java.util.List;
import java.util.Map;

import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.FocusEvent;
Expand All @@ -34,6 +33,7 @@
import com.vaadin.server.Resource;
import com.vaadin.v7.data.Container;
import com.vaadin.v7.data.util.filter.SimpleStringFilter;
import com.vaadin.v7.event.FieldEvents;
import com.vaadin.v7.shared.ui.combobox.ComboBoxConstants;
import com.vaadin.v7.shared.ui.combobox.ComboBoxState;
import com.vaadin.v7.shared.ui.combobox.FilteringMode;
Expand Down
Expand Up @@ -28,7 +28,6 @@

import org.jsoup.nodes.Element;

import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.FocusEvent;
Expand All @@ -45,6 +44,7 @@
import com.vaadin.v7.data.Validator.InvalidValueException;
import com.vaadin.v7.data.util.converter.Converter;
import com.vaadin.v7.data.validator.DateRangeValidator;
import com.vaadin.v7.event.FieldEvents;
import com.vaadin.v7.shared.ui.datefield.DateFieldConstants;
import com.vaadin.v7.shared.ui.datefield.TextualDateFieldState;

Expand Down Expand Up @@ -73,7 +73,7 @@ public class DateField extends AbstractField<Date> implements

/**
* Resolution identifier: seconds.
*
*
* @deprecated As of 7.0, use {@link Resolution#SECOND}
*/
@Deprecated
Expand Down
Expand Up @@ -18,13 +18,13 @@

import java.util.Collection;

import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.v7.data.Container;
import com.vaadin.v7.event.FieldEvents;

/**
* This is a simple drop-down select without, for instance, support for
Expand Down
Expand Up @@ -23,7 +23,6 @@

import org.jsoup.nodes.Element;

import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
import com.vaadin.event.FieldEvents.FocusEvent;
Expand All @@ -33,6 +32,7 @@
import com.vaadin.ui.declarative.DesignContext;
import com.vaadin.ui.declarative.DesignFormatter;
import com.vaadin.v7.data.Container;
import com.vaadin.v7.event.FieldEvents;
import com.vaadin.v7.shared.ui.optiongroup.OptionGroupConstants;
import com.vaadin.v7.shared.ui.optiongroup.OptionGroupState;

Expand Down
@@ -0,0 +1,181 @@
package com.vaadin.tests.server.component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

import org.easymock.EasyMock;
import org.junit.Assert;

import com.vaadin.tests.VaadinClasses;
import com.vaadin.ui.Component;

public abstract class AbstractListenerMethodsTestBase {

public static void main(String[] args) {
findAllListenerMethods();
}

private static void findAllListenerMethods() {
Set<Class<?>> classes = new HashSet<>();
for (Class<?> c : VaadinClasses.getAllServerSideClasses()) {
while (c != null && c.getName().startsWith("com.vaadin.")) {
classes.add(c);
c = c.getSuperclass();
}
}

for (Class<?> c : classes) {
boolean found = false;
for (Method m : c.getDeclaredMethods()) {
String methodName = m.getName();
if (methodName.startsWith("add")
&& methodName.endsWith("Listener")
&& !"addListener".equals(methodName)) {
if (m.getParameterTypes().length != 1) {
continue;
}
String packageName = "com.vaadin.tests.server";
if (Component.class.isAssignableFrom(c)) {
packageName += ".component."
+ c.getSimpleName().toLowerCase();
continue;
}

if (!found) {
found = true;
System.out.println("package " + packageName + ";");

System.out.println("import "
+ AbstractListenerMethodsTestBase.class
.getName()
+ ";");
System.out.println("import " + c.getName() + ";");
System.out
.println(
"public class " + c.getSimpleName()
+ "Listeners extends "
+ AbstractListenerMethodsTestBase.class
.getSimpleName()
+ " {");
}

String listenerClassName = m.getParameterTypes()[0]
.getSimpleName();
String eventClassName = listenerClassName
.replaceFirst("Listener$", "Event");
System.out.println("public void test" + listenerClassName
+ "() throws Exception {");
System.out.println(" testListener(" + c.getSimpleName()
+ ".class, " + eventClassName + ".class, "
+ listenerClassName + ".class);");
System.out.println("}");
}
}
if (found) {
System.out.println("}");
System.out.println();
}
}
}

protected void testListenerAddGetRemove(Class<?> testClass,
Class<?> eventClass, Class<?> listenerClass) throws Exception {
// Create a component for testing
Object c = testClass.newInstance();
testListenerAddGetRemove(testClass, eventClass, listenerClass, c);

}

protected void testListenerAddGetRemove(Class<?> cls, Class<?> eventClass,
Class<?> listenerClass, Object c) throws Exception {

Object mockListener1 = EasyMock.createMock(listenerClass);
Object mockListener2 = EasyMock.createMock(listenerClass);

// Verify we start from no listeners
verifyListeners(c, eventClass);

// Add one listener and verify
addListener(c, mockListener1, listenerClass);
verifyListeners(c, eventClass, mockListener1);

// Add another listener and verify
addListener(c, mockListener2, listenerClass);
verifyListeners(c, eventClass, mockListener1, mockListener2);

// Ensure we can fetch using parent class also
if (eventClass.getSuperclass() != null) {
verifyListeners(c, eventClass.getSuperclass(), mockListener1,
mockListener2);
}

// Remove the first and verify
removeListener(c, mockListener1, listenerClass);
verifyListeners(c, eventClass, mockListener2);

// Remove the remaining and verify
removeListener(c, mockListener2, listenerClass);
verifyListeners(c, eventClass);

}

private void removeListener(Object c, Object listener,
Class<?> listenerClass) throws IllegalArgumentException,
IllegalAccessException, InvocationTargetException,
SecurityException, NoSuchMethodException {
Method method = getRemoveListenerMethod(c.getClass(), listenerClass);
method.invoke(c, listener);

}

private void addListener(Object c, Object listener1, Class<?> listenerClass)
throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, SecurityException,
NoSuchMethodException {
Method method = getAddListenerMethod(c.getClass(), listenerClass);
method.invoke(c, listener1);
}

private Collection<?> getListeners(Object c, Class<?> eventType)
throws IllegalArgumentException, IllegalAccessException,
InvocationTargetException, SecurityException,
NoSuchMethodException {
Method method = getGetListenersMethod(c.getClass());
return (Collection<?>) method.invoke(c, eventType);
}

private Method getGetListenersMethod(Class<? extends Object> cls)
throws SecurityException, NoSuchMethodException {
return cls.getMethod("getListeners", Class.class);
}

private Method getAddListenerMethod(Class<?> cls, Class<?> listenerClass)
throws SecurityException, NoSuchMethodException {
return cls.getMethod("add" + listenerClass.getSimpleName(),
listenerClass);

}

private Method getRemoveListenerMethod(Class<?> cls, Class<?> listenerClass)
throws SecurityException, NoSuchMethodException {
return cls.getMethod("remove" + listenerClass.getSimpleName(),
listenerClass);

}

private void verifyListeners(Object c, Class<?> eventClass,
Object... expectedListeners) throws IllegalArgumentException,
SecurityException, IllegalAccessException,
InvocationTargetException, NoSuchMethodException {
Collection<?> registeredListeners = getListeners(c, eventClass);
Assert.assertEquals("Number of listeners", expectedListeners.length,
registeredListeners.size());

Assert.assertArrayEquals(expectedListeners,
registeredListeners.toArray());

}
}
9 changes: 8 additions & 1 deletion server/src/main/java/com/vaadin/event/Action.java
Expand Up @@ -19,6 +19,7 @@
import java.io.Serializable;

import com.vaadin.server.Resource;
import com.vaadin.shared.Registration;

/**
* Implements the action framework. This class contains subinterfaces for action
Expand Down Expand Up @@ -106,8 +107,14 @@ public interface Notifier extends Container {
}

public interface ShortcutNotifier extends Serializable {
public void addShortcutListener(ShortcutListener shortcut);
public Registration addShortcutListener(ShortcutListener shortcut);

/**
* @deprecated As of 8.0, replaced by {@link Registration#remove()} in
* the registration object returned from
* {@link #addShortcutListener(ShortcutListener)}.
*/
@Deprecated
public void removeShortcutListener(ShortcutListener shortcut);
}

Expand Down

0 comments on commit 2bee988

Please sign in to comment.