You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by gn...@apache.org on 2015/02/10 11:32:25 UTC
mina-sshd git commit: [SSHD-403] Lay down the groundwork for more
event listeners
Repository: mina-sshd
Updated Branches:
refs/heads/master 6af9457d3 -> 7f88d3a18
[SSHD-403] Lay down the groundwork for more event listeners
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/7f88d3a1
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/7f88d3a1
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/7f88d3a1
Branch: refs/heads/master
Commit: 7f88d3a18f9a4df77ae429ae724f4fd80b8685f5
Parents: 6af9457
Author: Guillaume Nodet <gn...@apache.org>
Authored: Tue Feb 10 11:32:10 2015 +0100
Committer: Guillaume Nodet <gn...@apache.org>
Committed: Tue Feb 10 11:32:18 2015 +0100
----------------------------------------------------------------------
.../org/apache/sshd/common/SessionListener.java | 4 +-
.../sshd/common/session/AbstractSession.java | 17 ++--
.../common/session/AbstractSessionFactory.java | 4 +
.../sshd/common/util/EventListenerUtils.java | 102 +++++++++++++++++++
.../common/util/EventListenerUtilsTest.java | 84 +++++++++++++++
.../java/org/apache/sshd/util/BaseTest.java | 13 ++-
6 files changed, 210 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/7f88d3a1/sshd-core/src/main/java/org/apache/sshd/common/SessionListener.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/SessionListener.java b/sshd-core/src/main/java/org/apache/sshd/common/SessionListener.java
index 32b69b3..6bbfecc 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/SessionListener.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/SessionListener.java
@@ -18,12 +18,14 @@
*/
package org.apache.sshd.common;
+import java.util.EventListener;
+
/**
* Represents an interface receiving Session events.
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public interface SessionListener {
+public interface SessionListener extends EventListener {
enum Event {
KeyEstablished, Authenticated, KexCompleted
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/7f88d3a1/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
index 13ce253..a0b16c1 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSession.java
@@ -54,6 +54,7 @@ import org.apache.sshd.common.io.IoWriteFuture;
import org.apache.sshd.common.util.Buffer;
import org.apache.sshd.common.util.BufferUtils;
import org.apache.sshd.common.util.CloseableUtils;
+import org.apache.sshd.common.util.EventListenerUtils;
import org.apache.sshd.common.util.Readable;
import static org.apache.sshd.common.SshConstants.SSH_MSG_DEBUG;
@@ -102,12 +103,12 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
protected final Random random;
/** Boolean indicating if this session has been authenticated or not */
protected boolean authed;
- /** The name of the authenticated useer */
+ /** The name of the authenticated user */
protected String username;
- /** Session listener */
+ /** Session listeners container */
protected final List<SessionListener> listeners = new CopyOnWriteArrayList<SessionListener>();
-
+ protected final SessionListener sessionListenerProxy;
//
// Key exchange support
//
@@ -177,6 +178,7 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
this.isServer = isServer;
this.factoryManager = factoryManager;
this.ioSession = ioSession;
+ sessionListenerProxy = EventListenerUtils.proxyWrapper(SessionListener.class, getClass().getClassLoader(), listeners);
random = factoryManager.getRandomFactory().create();
authTimeoutMs = getLongProperty(FactoryManager.AUTH_TIMEOUT, authTimeoutMs);
authTimeoutTimestamp = System.currentTimeMillis() + authTimeoutMs;
@@ -478,9 +480,7 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
protected void doCloseImmediately() {
super.doCloseImmediately();
// Fire 'close' event
- for (SessionListener sl : listeners) {
- sl.sessionClosed(this);
- }
+ sessionListenerProxy.sessionClosed(this);
}
protected Service[] getServices() {
@@ -1280,12 +1280,9 @@ public abstract class AbstractSession extends CloseableUtils.AbstractInnerClosea
}
protected void sendEvent(SessionListener.Event event) throws IOException {
- for (SessionListener sl : listeners) {
- sl.sessionEvent(this, event);
- }
+ sessionListenerProxy.sessionEvent(this, event);
}
-
/**
* {@inheritDoc}
*/
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/7f88d3a1/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSessionFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSessionFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSessionFactory.java
index 8c8429c..5127538 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSessionFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractSessionFactory.java
@@ -34,6 +34,10 @@ public abstract class AbstractSessionFactory extends AbstractSessionIoHandler {
protected final List<SessionListener> listeners = new CopyOnWriteArrayList<SessionListener>();
+ protected AbstractSessionFactory() {
+ super();
+ }
+
protected AbstractSession createSession(IoSession ioSession) throws Exception {
AbstractSession session = doCreateSession(ioSession);
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/7f88d3a1/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
new file mode 100644
index 0000000..f951a91
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/EventListenerUtils.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.sshd.common.util;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.EventListener;
+
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class EventListenerUtils {
+ /**
+ * Provides proxy wrapper around an {@link Iterable} container of listener
+ * interface implementation. <b>Note:</b> a listener interface is one whose
+ * invoked methods return <u>only</u> {@code void}.
+ *
+ * @param listenerType The expected listener <u>interface</u>
+ * @param listeners An {@link Iterable} container of listeners to be invoked.</P>
+ * <b>Note(s):</b>
+ * <ul>
+ * <li>The invocation order is same as the {@link Iterable} container</li>
+ * <p/>
+ * <li>If any of the invoked listener methods throws an exception, the
+ * rest of the listener are <u>not</u> invoked and the exception is
+ * propagated to the caller</li>
+ * <p/>
+ * <li>It is up to the <u>caller</u> to ensure that the container does
+ * not change while the proxy is invoked</li>
+ * </ul>
+ * @return A proxy wrapper implementing the same interface, but delegating
+ * the calls to the container
+ * @see #proxyWrapper(Class, ClassLoader, Iterable)
+ */
+ public static <T extends EventListener> T proxyWrapper(Class<T> listenerType, Iterable<? extends T> listeners) {
+ return proxyWrapper(listenerType, listenerType.getClassLoader(), listeners);
+ }
+
+ /**
+ * Provides proxy wrapper around an {@link Iterable} container of listener
+ * interface implementation. <b>Note:</b> a listener interface is one whose
+ * invoked methods return <u>only</u> {@code void}.
+ *
+ * @param listenerType The expected listener <u>interface</u>
+ * @param loader The {@link ClassLoader} to use for the proxy
+ * @param listeners An {@link Iterable} container of listeners to be invoked.</P>
+ * <b>Note(s):</b>
+ * <ul>
+ * <li>The invocation order is same as the {@link Iterable} container</li>
+ * <p/>
+ * <li>If any of the invoked listener methods throws an exception, the
+ * rest of the listener are <u>not</u> invoked and the exception is
+ * propagated to the caller</li>
+ * <p/>
+ * <li>It is up to the <u>caller</u> to ensure that the container does
+ * not change while the proxy is invoked</li>
+ * </ul>
+ * @return A proxy wrapper implementing the same interface, but delegating
+ * the calls to the container
+ * @throws IllegalArgumentException if <tt>listenerType</tt> is not an interface
+ * or a {@code null} container has been provided
+ * @see #proxyWrapper(Class, ClassLoader, Iterable)
+ */
+ public static <T extends EventListener> T proxyWrapper(Class<T> listenerType, ClassLoader loader, final Iterable<? extends T> listeners) {
+ if ((listenerType == null) || (!listenerType.isInterface())) {
+ throw new IllegalArgumentException("Target proxy is not an interface");
+ }
+
+ if (listeners == null) {
+ throw new IllegalArgumentException("No listeners container provided");
+ }
+
+ Object wrapper = Proxy.newProxyInstance(loader, new Class<?>[]{listenerType}, new InvocationHandler() {
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ for (T l : listeners) {
+ method.invoke(l, args);
+ }
+ return null; // we assume always void return value...
+ }
+ });
+ return listenerType.cast(wrapper);
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/7f88d3a1/sshd-core/src/test/java/org/apache/sshd/common/util/EventListenerUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/util/EventListenerUtilsTest.java b/sshd-core/src/test/java/org/apache/sshd/common/util/EventListenerUtilsTest.java
new file mode 100644
index 0000000..31dffaa
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/common/util/EventListenerUtilsTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.sshd.common.util;
+
+import java.util.ArrayList;
+import java.util.EventListener;
+import java.util.List;
+
+import org.apache.sshd.util.BaseTest;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public class EventListenerUtilsTest extends BaseTest {
+ public EventListenerUtilsTest() {
+ super();
+ }
+
+ @Test
+ public void testProxyWrapper() {
+ List<ProxyListenerImpl> impls = new ArrayList<ProxyListenerImpl>();
+ for (int index = 0; index < Byte.SIZE; index++) {
+ impls.add(new ProxyListenerImpl());
+ }
+
+ ProxyListener listener = EventListenerUtils.proxyWrapper(ProxyListener.class, impls);
+ String expStr = getCurrentTestName();
+ Number expNum = System.currentTimeMillis();
+ listener.callMeWithString(expStr);
+ listener.callMeWithNumber(expNum);
+
+ for (int index = 0; index < impls.size(); index++) {
+ ProxyListenerImpl l = impls.get(index);
+ Assert.assertSame("Mismatched string at listener #" + index, expStr, l.getStringValue());
+ Assert.assertSame("Mismatched number at listener #" + index, expNum, l.getNumberValue());
+ }
+ }
+
+ private static interface ProxyListener extends EventListener {
+ void callMeWithString(String s);
+
+ void callMeWithNumber(Number n);
+ }
+
+ private static class ProxyListenerImpl implements ProxyListener {
+ private String strValue;
+ private Number numValue;
+
+ public String getStringValue() {
+ return strValue;
+ }
+
+ public void callMeWithString(String s) {
+ strValue = s;
+ }
+
+ public Number getNumberValue() {
+ return numValue;
+ }
+
+ public void callMeWithNumber(Number n) {
+ numValue = n;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/7f88d3a1/sshd-core/src/test/java/org/apache/sshd/util/BaseTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/util/BaseTest.java b/sshd-core/src/test/java/org/apache/sshd/util/BaseTest.java
index d7b38c4..e81de2c 100644
--- a/sshd-core/src/test/java/org/apache/sshd/util/BaseTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/util/BaseTest.java
@@ -19,6 +19,7 @@
package org.apache.sshd.util;
import org.junit.Rule;
+import org.junit.rules.TestName;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
@@ -28,11 +29,17 @@ import org.junit.runner.Description;
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public abstract class BaseTest extends TestWatcher {
+ @Rule public TestWatcher rule = this;
+ @Rule public final TestName TEST_NAME_HOLDER = new TestName();
+ private long startTime;
- @Rule
- public TestWatcher rule = this;
+ protected BaseTest() {
+ super();
+ }
- private long startTime;
+ public final String getCurrentTestName() {
+ return TEST_NAME_HOLDER.getMethodName();
+ }
@Override
protected void starting(Description description) {