Browse Source

WIP: prototype of SimpleEventRouter

fix_event_router_prototype
Henri Sara 7 years ago
parent
commit
5e09b462cc

+ 9
- 11
server/src/main/java/com/vaadin/data/Binder.java View File

@@ -34,7 +34,7 @@ import com.vaadin.data.HasValue.ValueChangeEvent;
import com.vaadin.data.util.converter.Converter;
import com.vaadin.data.util.converter.StringToIntegerConverter;
import com.vaadin.data.util.converter.ValueContext;
import com.vaadin.event.EventRouter;
import com.vaadin.event.SimpleEventRouter;
import com.vaadin.server.ErrorMessage;
import com.vaadin.server.SerializableBiConsumer;
import com.vaadin.server.SerializableFunction;
@@ -957,7 +957,7 @@ public class Binder<BEAN> implements Serializable {

private final Map<HasValue<?>, ConverterDelegate<?>> initialConverters = new IdentityHashMap<>();

private EventRouter eventRouter;
private SimpleEventRouter<StatusChangeEvent> eventRouter;

private Label statusLabel;

@@ -1373,11 +1373,10 @@ public class Binder<BEAN> implements Serializable {
*/
private List<ValidationResult> validateBean(BEAN bean) {
Objects.requireNonNull(bean, "bean cannot be null");
List<ValidationResult> results = Collections
.unmodifiableList(validators.stream()
.map(validator -> validator.apply(bean,
new ValueContext()))
.collect(Collectors.toList()));
List<ValidationResult> results = Collections.unmodifiableList(validators
.stream()
.map(validator -> validator.apply(bean, new ValueContext()))
.collect(Collectors.toList()));
return results;
}

@@ -1494,8 +1493,7 @@ public class Binder<BEAN> implements Serializable {
* @return a registration for the listener
*/
public Registration addStatusChangeListener(StatusChangeListener listener) {
return getEventRouter().addListener(StatusChangeEvent.class, listener,
StatusChangeListener.class.getDeclaredMethods()[0]);
return getEventRouter().addListener(listener);
}

/**
@@ -1663,9 +1661,9 @@ public class Binder<BEAN> implements Serializable {
*
* @return the event router, not null
*/
protected EventRouter getEventRouter() {
private SimpleEventRouter getEventRouter() {
if (eventRouter == null) {
eventRouter = new EventRouter();
eventRouter = new SimpleEventRouter();
}
return eventRouter;
}

+ 6
- 5
server/src/main/java/com/vaadin/data/StatusChangeListener.java View File

@@ -15,23 +15,24 @@
*/
package com.vaadin.data;

import java.io.Serializable;
import com.vaadin.event.Listener;

/**
* Listener interface for {@link StatusChangeEvent}s.
*
*
* @see StatusChangeEvent
* @author Vaadin Ltd
*
*/
@FunctionalInterface
public interface StatusChangeListener extends Serializable {
public interface StatusChangeListener extends Listener<StatusChangeEvent> {

/**
* Notifies the listener about status change {@code event}.
*
*
* @param event
* a status change event, not null
*/
void statusChange(StatusChangeEvent event);
@Override
void onEvent(StatusChangeEvent event);
}

+ 65
- 74
server/src/main/java/com/vaadin/event/EventRouter.java View File

@@ -24,7 +24,6 @@ import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.logging.Logger;

import com.vaadin.server.ErrorEvent;
import com.vaadin.server.ErrorHandler;
@@ -39,19 +38,40 @@ import com.vaadin.shared.Registration;
* @since 3.0
*/
@SuppressWarnings("serial")
public class EventRouter implements MethodEventSource {
public class EventRouter {

/**
* List of registered listeners.
*/
private LinkedHashSet<ListenerMethod> listenerList = null;

/*
* Registers a new listener with the specified activation method to listen
* events generated by this component. Don't add a JavaDoc comment here, we
* use the default documentation from implemented interface.
/**
* <p>
* Registers a new event listener with the specified activation method to
* listen events generated by this component. If the activation method does
* not have any arguments the event object will not be passed to it when
* it's called.
* </p>
*
* <p>
* For more information on the inheritable event mechanism see the
* {@link com.vaadin.event com.vaadin.event package documentation}.
* </p>
*
* @param eventType
* the type of the listened event. Events of this type or its
* subclasses activate the listener.
* @param object
* the object instance who owns the activation method.
* @param method
* the activation method.
* @return a registration object for removing the listener
* @throws java.lang.IllegalArgumentException
* unless <code>method</code> has exactly one match in
* <code>object</code>
* @throws NullPointerException
* if {@code object} is {@code null}
*/
@Override
public Registration addListener(Class<?> eventType, Object object,
Method method) {
Objects.requireNonNull(object, "Listener must not be null.");
@@ -64,30 +84,24 @@ public class EventRouter implements MethodEventSource {
return () -> listenerList.remove(listenerMethod);
}

/*
* Registers a new listener with the specified named activation method to
* listen events generated by this component. Don't add a JavaDoc comment
* here, we use the default documentation from implemented interface.
*/
@Override
public Registration addListener(Class<?> eventType, Object object,
String methodName) {
Objects.requireNonNull(object, "Listener must not be null.");
if (listenerList == null) {
listenerList = new LinkedHashSet<>();
}
ListenerMethod listenerMethod = new ListenerMethod(eventType, object,
methodName);
listenerList.add(listenerMethod);
return () -> listenerList.remove(listenerMethod);
}

/*
* Removes all registered listeners matching the given parameters. Don't add
* a JavaDoc comment here, we use the default documentation from implemented
* interface.
/**
* Removes all registered listeners matching the given parameters. Since
* this method receives the event type and the listener object as
* parameters, it will unregister all <code>object</code>'s methods that are
* registered to listen to events of type <code>eventType</code> generated
* by this component.
*
* <p>
* For more information on the inheritable event mechanism see the
* {@link com.vaadin.event com.vaadin.event package documentation}.
* </p>
*
* @param eventType
* the exact event type the <code>object</code> listens to.
* @param target
* the target object that has registered to listen to events of
* type <code>eventType</code> with one or more methods.
*/
@Override
public void removeListener(Class<?> eventType, Object target) {
if (listenerList != null) {
final Iterator<ListenerMethod> i = listenerList.iterator();
@@ -101,12 +115,28 @@ public class EventRouter implements MethodEventSource {
}
}

/*
* Removes the event listener methods matching the given given paramaters.
* Don't add a JavaDoc comment here, we use the default documentation from
* implemented interface.
/**
* Removes one registered listener method. The given method owned by the
* given object will no longer be called when the specified events are
* generated by this component.
*
* <p>
* For more information on the inheritable event mechanism see the
* {@link com.vaadin.event com.vaadin.event package documentation}.
* </p>
*
* @param eventType
* the exact event type the <code>object</code> listens to.
* @param target
* the target object that has registered to listen to events of
* type eventType with one or more methods.
* @param method
* the method owned by the target that's registered to listen to
* events of type eventType.
* @deprecated use a {@link Registration} returned by
* {@link #addListener(Class, Object, Method)}
*/
@Override
@Deprecated
public void removeListener(Class<?> eventType, Object target,
Method method) {
if (listenerList != null) {
@@ -121,41 +151,6 @@ public class EventRouter implements MethodEventSource {
}
}

/*
* Removes the event listener method matching the given given parameters.
* Don't add a JavaDoc comment here, we use the default documentation from
* implemented interface.
*/
@Override
public void removeListener(Class<?> eventType, Object target,
String methodName) {

// Find the correct method
final Method[] methods = target.getClass().getMethods();
Method method = null;
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName)) {
method = methods[i];
}
}
if (method == null) {
throw new IllegalArgumentException();
}

// Remove the listeners
if (listenerList != null) {
final Iterator<ListenerMethod> i = listenerList.iterator();
while (i.hasNext()) {
final ListenerMethod lm = i.next();
if (lm.matches(eventType, target, method)) {
i.remove();
return;
}
}
}

}

/**
* Removes all listeners from event router.
*/
@@ -254,8 +249,4 @@ public class EventRouter implements MethodEventSource {
return listeners;
}

private Logger getLogger() {
return Logger.getLogger(EventRouter.class.getName());
}

}

+ 29
- 0
server/src/main/java/com/vaadin/event/Listener.java View File

@@ -0,0 +1,29 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* 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 com.vaadin.event;

import java.io.Serializable;

/**
* Generic Listener interface.
*
* @author Vaadin Ltd.
* @since 8.0
*/
@FunctionalInterface
public interface Listener<E extends Serializable> extends Serializable {
public void onEvent(E event);
}

+ 0
- 184
server/src/main/java/com/vaadin/event/MethodEventSource.java View File

@@ -1,184 +0,0 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* 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 com.vaadin.event;

import java.io.Serializable;
import java.lang.reflect.Method;

import com.vaadin.shared.Registration;

/**
* <p>
* Interface for classes supporting registration of methods as event receivers.
* </p>
*
* <p>
* For more information on the inheritable event mechanism see the
* {@link com.vaadin.event com.vaadin.event package documentation}.
* </p>
*
* @author Vaadin Ltd.
* @since 3.0
*/
public interface MethodEventSource extends Serializable {

/**
* <p>
* Registers a new event listener with the specified activation method to
* listen events generated by this component. If the activation method does
* not have any arguments the event object will not be passed to it when
* it's called.
* </p>
*
* <p>
* For more information on the inheritable event mechanism see the
* {@link com.vaadin.event com.vaadin.event package documentation}.
* </p>
*
* @param eventType
* the type of the listened event. Events of this type or its
* subclasses activate the listener.
* @param object
* the object instance who owns the activation method.
* @param method
* the activation method.
* @return a registration object for removing the listener
* @throws java.lang.IllegalArgumentException
* unless <code>method</code> has exactly one match in
* <code>object</code>
* @throws NullPointerException
* if {@code object} is {@code null}
*/
public Registration addListener(Class<?> eventType, Object object,
Method method);

/**
* <p>
* Registers a new listener with the specified activation method to listen
* events generated by this component. If the activation method does not
* have any arguments the event object will not be passed to it when it's
* called.
* </p>
*
* <p>
* This version of <code>addListener</code> gets the name of the activation
* method as a parameter. The actual method is reflected from
* <code>object</code>, and unless exactly one match is found,
* <code>java.lang.IllegalArgumentException</code> is thrown.
* </p>
*
* <p>
* For more information on the inheritable event mechanism see the
* {@link com.vaadin.event com.vaadin.event package documentation}.
* </p>
*
* @param eventType
* the type of the listened event. Events of this type or its
* subclasses activate the listener.
* @param object
* the object instance who owns the activation method.
* @param methodName
* the name of the activation method.
* @return a registration object for removing the listener
* @throws java.lang.IllegalArgumentException
* unless <code>method</code> has exactly one match in
* <code>object</code>
* @throws NullPointerException
* if {@code object} is {@code null}
*/
public Registration addListener(Class<?> eventType, Object object,
String methodName);

/**
* Removes all registered listeners matching the given parameters. Since
* this method receives the event type and the listener object as
* parameters, it will unregister all <code>object</code>'s methods that are
* registered to listen to events of type <code>eventType</code> generated
* by this component.
*
* <p>
* For more information on the inheritable event mechanism see the
* {@link com.vaadin.event com.vaadin.event package documentation}.
* </p>
*
* @param eventType
* the exact event type the <code>object</code> listens to.
* @param target
* the target object that has registered to listen to events of
* type <code>eventType</code> with one or more methods.
*/
public void removeListener(Class<?> eventType, Object target);

/**
* Removes one registered listener method. The given method owned by the
* given object will no longer be called when the specified events are
* generated by this component.
*
* <p>
* For more information on the inheritable event mechanism see the
* {@link com.vaadin.event com.vaadin.event package documentation}.
* </p>
*
* @param eventType
* the exact event type the <code>object</code> listens to.
* @param target
* the target object that has registered to listen to events of
* type eventType with one or more methods.
* @param method
* the method owned by the target that's registered to listen to
* events of type eventType.
* @deprecated use a {@link Registration} returned by
* {@link #addListener(Class, Object, Method)}
*/
@Deprecated
public void removeListener(Class<?> eventType, Object target,
Method method);

/**
* <p>
* Removes one registered listener method. The given method owned by the
* given object will no longer be called when the specified events are
* generated by this component.
* </p>
*
* <p>
* This version of <code>removeListener</code> gets the name of the
* activation method as a parameter. The actual method is reflected from the
* target, and unless exactly one match is found,
* <code>java.lang.IllegalArgumentException</code> is thrown.
* </p>
*
* <p>
* For more information on the inheritable event mechanism see the
* {@link com.vaadin.event com.vaadin.event package documentation}.
* </p>
*
* @param eventType
* the exact event type the <code>object</code> listens to.
* @param target
* the target object that has registered to listen to events of
* type <code>eventType</code> with one or more methods.
* @param methodName
* the name of the method owned by <code>target</code> that's
* registered to listen to events of type <code>eventType</code>.
* @deprecated use a {@link Registration} returned by
* {@link #addListener(Class, Object, String)}
*/
@Deprecated
public void removeListener(Class<?> eventType, Object target,
String methodName);
}

+ 52
- 0
server/src/main/java/com/vaadin/event/SimpleEventRouter.java View File

@@ -0,0 +1,52 @@
/*
* Copyright 2000-2016 Vaadin Ltd.
*
* 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 com.vaadin.event;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;

import com.vaadin.shared.Registration;

public class SimpleEventRouter<E extends Serializable> {

private Collection<Listener<E>> listeners = null;

public Registration addListener(Listener<E> listener) {
if (listeners == null) {
listeners = new LinkedHashSet<>();
}
listeners.add(listener);
return () -> listeners.remove(listener);
}

public void fireEvent(E event) {
if (listeners == null) {
return;
}
for (Listener<E> listener : new ArrayList<>(listeners)) {
// very few callers have been doing error handling here, so not
// complicating the basic event list with it
listener.onEvent(event);
}
}

public boolean hasListeners() {
return listeners != null && !listeners.isEmpty();
}
}

+ 1
- 93
server/src/main/java/com/vaadin/server/AbstractClientConnector.java View File

@@ -34,7 +34,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Logger;

import com.vaadin.event.EventRouter;
import com.vaadin.event.MethodEventSource;
import com.vaadin.shared.Registration;
import com.vaadin.shared.communication.ClientRpc;
import com.vaadin.shared.communication.ServerRpc;
@@ -56,8 +55,7 @@ import elemental.json.JsonValue;
* @author Vaadin Ltd
* @since 7.0.0
*/
public abstract class AbstractClientConnector
implements ClientConnector, MethodEventSource {
public abstract class AbstractClientConnector implements ClientConnector {
/**
* A map from client to server RPC interface class name to the RPC call
* manager that handles incoming RPC calls for that interface.
@@ -842,7 +840,6 @@ public abstract class AbstractClientConnector
* the activation method.
* @return a registration object for removing the listener
*/
@Override
public Registration addListener(Class<?> eventType, Object target,
Method method) {
if (eventRouter == null) {
@@ -851,54 +848,6 @@ public abstract class AbstractClientConnector
return eventRouter.addListener(eventType, target, method);
}

/**
* <p>
* Convenience method for registering a new listener with the specified
* activation method to listen events generated by this component. If the
* activation method does not have any arguments the event object will not
* be passed to it when it's called.
* </p>
*
* <p>
* This version of <code>addListener</code> gets the name of the activation
* method as a parameter. The actual method is reflected from
* <code>object</code>, and unless exactly one match is found,
* <code>java.lang.IllegalArgumentException</code> is thrown.
* </p>
*
* <p>
* For more information on the inheritable event mechanism see the
* {@link com.vaadin.event com.vaadin.event package documentation}.
* </p>
*
* <p>
* Note: Using this method is discouraged because it cannot be checked
* during compilation. Use {@link #addListener(Class, Object, Method)} or
* {@link #addListener(com.vaadin.ui.Component.Listener)} instead.
* </p>
*
* @param eventType
* the type of the listened event. Events of this type or its
* subclasses activate the listener.
* @param target
* the object instance who owns the activation method.
* @param methodName
* the name of the activation method.
* @return a registration object for removing the listener
* @deprecated As of 7.0. This method should be avoided. Use
* {@link #addListener(Class, Object, Method)} or
* {@link #addListener(String, Class, Object, Method)} instead.
*/
@Override
@Deprecated
public Registration addListener(Class<?> eventType, Object target,
String methodName) {
if (eventRouter == null) {
eventRouter = new EventRouter();
}
return eventRouter.addListener(eventType, target, methodName);
}

/**
* Removes all registered listeners matching the given parameters. Since
* this method receives the event type and the listener object as
@@ -917,7 +866,6 @@ public abstract class AbstractClientConnector
* the target object that has registered to listen to events of
* type <code>eventType</code> with one or more methods.
*/
@Override
public void removeListener(Class<?> eventType, Object target) {
if (eventRouter != null) {
eventRouter.removeListener(eventType, target);
@@ -946,7 +894,6 @@ public abstract class AbstractClientConnector
* {@link #addListener(Class, Object, Method)} to remove a
* listener
*/
@Override
@Deprecated
public void removeListener(Class<?> eventType, Object target,
Method method) {
@@ -955,45 +902,6 @@ public abstract class AbstractClientConnector
}
}

/**
* <p>
* Removes one registered listener method. The given method owned by the
* given object will no longer be called when the specified events are
* generated by this component.
* </p>
*
* <p>
* This version of <code>removeListener</code> gets the name of the
* activation method as a parameter. The actual method is reflected from
* <code>target</code>, and unless exactly one match is found,
* <code>java.lang.IllegalArgumentException</code> is thrown.
* </p>
*
* <p>
* For more information on the inheritable event mechanism see the
* {@link com.vaadin.event com.vaadin.event package documentation}.
* </p>
*
* @param eventType
* the exact event type the <code>object</code> listens to.
* @param target
* the target object that has registered to listen to events of
* type <code>eventType</code> with one or more methods.
* @param methodName
* the name of the method owned by <code>target</code> that's
* registered to listen to events of type <code>eventType</code>.
* @deprecated As of 7.0. This method should be avoided. Use
* {@link #removeListener(Class, Object, Method)} instead.
*/
@Deprecated
@Override
public void removeListener(Class<?> eventType, Object target,
String methodName) {
if (eventRouter != null) {
eventRouter.removeListener(eventType, target, methodName);
}
}

/**
* Returns all listeners that are registered for the given event type or one
* of its subclasses.

+ 6
- 35
server/src/main/java/com/vaadin/server/data/AbstractDataProvider.java View File

@@ -15,10 +15,7 @@
*/
package com.vaadin.server.data;

import java.lang.reflect.Method;
import java.util.EventObject;

import com.vaadin.event.EventRouter;
import com.vaadin.event.SimpleEventRouter;
import com.vaadin.shared.Registration;

/**
@@ -36,12 +33,11 @@ import com.vaadin.shared.Registration;
*/
public abstract class AbstractDataProvider<T, F> implements DataProvider<T, F> {

private EventRouter eventRouter;
private SimpleEventRouter<DataChangeEvent> eventRouter = new SimpleEventRouter<>();

@Override
public Registration addDataProviderListener(DataProviderListener listener) {
return addListener(DataChangeEvent.class, listener,
DataProviderListener.class.getMethods()[0]);
return eventRouter.addListener(listener);
}

@Override
@@ -49,38 +45,13 @@ public abstract class AbstractDataProvider<T, F> implements DataProvider<T, F> {
fireEvent(new DataChangeEvent(this));
}

/**
* Registers a new listener with the specified activation method to listen
* events generated by this component. If the activation method does not
* have any arguments the event object will not be passed to it when it's
* called.
*
* @param eventType
* the type of the listened event. Events of this type or its
* subclasses activate the listener.
* @param listener
* the object instance who owns the activation method.
* @param method
* the activation method.
* @return a registration for the listener
*/
protected Registration addListener(Class<?> eventType,
DataProviderListener listener, Method method) {
if (eventRouter == null) {
eventRouter = new EventRouter();
}
return eventRouter.addListener(eventType, listener, method);
}

/**
* Sends the event to all listeners.
*
* @param event
* the Event to be sent to all listeners.
* the event to be sent to all listeners.
*/
protected void fireEvent(EventObject event) {
if (eventRouter != null) {
eventRouter.fireEvent(event);
}
protected void fireEvent(DataChangeEvent event) {
eventRouter.fireEvent(event);
}
}

+ 5
- 4
server/src/main/java/com/vaadin/server/data/DataProviderListener.java View File

@@ -15,17 +15,17 @@
*/
package com.vaadin.server.data;

import java.io.Serializable;
import com.vaadin.event.Listener;

/**
* Interface for listening for a data change events fired by a
* {@link DataProvider}.
*
*
* @author Vaadin Ltd
* @since 8.0
*/
@FunctionalInterface
public interface DataProviderListener extends Serializable {
public interface DataProviderListener extends Listener<DataChangeEvent> {

/**
* Invoked when this listener receives a data change event from a data
@@ -39,5 +39,6 @@ public interface DataProviderListener extends Serializable {
* @param event
* the received event, not null
*/
void onDataChange(DataChangeEvent event);
@Override
void onEvent(DataChangeEvent event);
}

+ 3
- 4
server/src/test/java/com/vaadin/server/RemoveListenersDeprecatedTest.java View File

@@ -11,7 +11,6 @@ import org.junit.Assert;
import org.junit.Test;

import com.vaadin.event.EventRouter;
import com.vaadin.event.MethodEventSource;
import com.vaadin.server.data.AbstractDataProvider;
import com.vaadin.shared.Registration;
import com.vaadin.tests.VaadinClasses;
@@ -26,7 +25,7 @@ public class RemoveListenersDeprecatedTest {
ALLOW_REMOVE_LISTENER
.add(RemoveListenersDeprecatedTest::acceptAbstractDataProvider);
ALLOW_REMOVE_LISTENER
.add(RemoveListenersDeprecatedTest::acceptMethodEventSource);
.add(RemoveListenersDeprecatedTest::acceptEventRouter);
}

@Test
@@ -71,8 +70,8 @@ public class RemoveListenersDeprecatedTest {
Assert.assertTrue(count > 0);
}

private static boolean acceptMethodEventSource(Method method) {
return method.getDeclaringClass().equals(MethodEventSource.class)
private static boolean acceptEventRouter(Method method) {
return method.getDeclaringClass().equals(EventRouter.class)
&& method.getParameterCount() == 2;
}


+ 1
- 1
server/src/test/java/com/vaadin/server/data/provider/DataProviderTestBase.java View File

@@ -27,7 +27,7 @@ public abstract class DataProviderTestBase<D extends DataProvider<StrBean, Seria
private int counter = 0;

@Override
public void onDataChange(DataChangeEvent event) {
public void onEvent(DataChangeEvent event) {
++counter;
}


Loading…
Cancel
Save