You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/10/06 07:23:00 UTC

[3/4] mina-sshd git commit: [SSHD-566] Allow specific properties overrides per session and channel

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
new file mode 100644
index 0000000..4760a48
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
@@ -0,0 +1,375 @@
+/*
+ * 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;
+
+import java.util.Map;
+import java.util.Objects;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public final class PropertyResolverUtils {
+
+    private PropertyResolverUtils() {
+        throw new UnsupportedOperationException("No instance allowed");
+    }
+
+    /**
+     * @param resolver     The {@link PropertyResolver} instance - ignored if {@code null}
+     * @param name         The property name
+     * @param defaultValue The default value to return if the specified property
+     *                     does not exist in the properties map
+     * @return The resolved property
+     * @throws NumberFormatException if malformed value
+     * @see #toLong(Object, long)
+     */
+    public static long getLongProperty(PropertyResolver resolver, String name, long defaultValue) {
+        return toLong(resolvePropertyValue(resolver, name), defaultValue);
+    }
+
+    public static long getLongProperty(Map<String, ?> props, String name, long defaultValue) {
+        return toLong(resolvePropertyValue(props, name), defaultValue);
+    }
+
+    /**
+     * Converts a generic object value to a {@code long} if possible:
+     * <UL>
+     *      <LI>
+     *      If value is {@code null} the default is returned
+     *      </LI>
+     *
+     *      <LI>
+     *      If value is a {@link Number} then its {@link Number#longValue()} is returned
+     *      </LI>
+     *
+     *      <LI>
+     *      Otherwise, the value's {@link #toString()} is parsed as a {@code long}
+     *      </LI>
+     * </UL>
+     *
+     * @param value         The resolved value - may be {@code null}
+     * @param defaultValue  The default to use if {@code null} resolved value
+     * @return The resolved value
+     * @throws NumberFormatException if malformed value
+     * @see Long#parseLong(String)
+     */
+    public static long toLong(Object value, long defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        } else if (value instanceof Number) {
+            return ((Number) value).longValue();
+        } else {    // we parse the string in case it is not a valid long value
+            return Long.parseLong(value.toString());
+        }
+    }
+
+    /**
+     * @param resolver The {@link PropertyResolver} instance - ignored if {@code null}
+     * @param name     The property name
+     * @return The {@link Long} value or {@code null} if property not found
+     * @throws NumberFormatException if malformed value
+     * @see #toLong(Object)
+     */
+    public static Long getLong(PropertyResolver resolver, String name) {
+        return toLong(resolvePropertyValue(resolver, name));
+    }
+
+    public static Long getLong(Map<String, ?> props, String name) {
+        return toLong(resolvePropertyValue(props, name));
+    }
+
+    /**
+     * Converts a generic object into a {@link Long}:
+     * <UL>
+     *      <LI>
+     *      If the value is {@code null} then returns {@code null}.
+     *      </LI>
+     *
+     *      <LI>
+     *      If the value is already a {@link Long} then it is returned as such.
+     *      </LI>
+
+     *      <LI>
+     *      If value is a {@link Number} then its {@link Number#longValue()} is
+     *      wrapped as a {@link Long}
+     *      </LI>
+     *
+     *      <LI>
+     *      Otherwise, the value's {@link #toString()} is parsed as a {@link Long}
+     *      </LI>
+     * </UL>
+     *
+     * @param value The resolved value - may be {@code null}
+     * @return The {@link Long} value or {@code null} if property not found
+     * @throws NumberFormatException if malformed value
+     * @see Long#valueOf(long)
+     * @see Long#valueOf(String)
+     */
+    public static Long toLong(Object value) {
+        if (value == null) {
+            return null;
+        } else if (value instanceof Long) {
+            return (Long) value;
+        } else if (value instanceof Number) {
+            return Long.valueOf(((Number) value).longValue());
+        } else {    // we parse the string in case it is not a valid long value
+            return Long.valueOf(value.toString());
+        }
+    }
+
+    public static Object updateProperty(PropertyResolver resolver, String name, long value) {
+        return updateProperty(resolver.getProperties(), name, value);
+    }
+
+    public static Object updateProperty(Map<String, Object> props, String name, long value) {
+        return updateProperty(props, name, Long.valueOf(value));
+    }
+
+    public static int getIntProperty(PropertyResolver resolver, String name, int defaultValue) {
+        return toInteger(resolvePropertyValue(resolver, name), defaultValue);
+    }
+
+    public static int getIntProperty(Map<String, ?> props, String name, int defaultValue) {
+        return toInteger(resolvePropertyValue(props, name), defaultValue);
+    }
+
+    public static int toInteger(Object value, int defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        } else if (value instanceof Number) {
+            return ((Number) value).intValue();
+        } else {    // we parse the string in case this is NOT an integer
+            return Integer.parseInt(value.toString());
+        }
+    }
+
+    public static Integer getInteger(PropertyResolver resolver, String name) {
+        return toInteger(resolvePropertyValue(resolver, name));
+    }
+
+    public static Integer getInteger(Map<String, ?> props, String name) {
+        return toInteger(resolvePropertyValue(props, name));
+    }
+
+    public static Integer toInteger(Object value) {
+        if (value == null) {
+            return null;
+        } else if (value instanceof Integer) {
+            return (Integer) value;
+        } else if (value instanceof Number) {
+            return Integer.valueOf(((Number) value).intValue());
+        } else {    // we parse the string in case this is NOT an integer
+            return Integer.valueOf(value.toString());
+        }
+    }
+
+    public static Object updateProperty(PropertyResolver resolver, String name, int value) {
+        return updateProperty(resolver.getProperties(), name, value);
+    }
+
+    public static Object updateProperty(Map<String, Object> props, String name, int value) {
+        return updateProperty(props, name, Integer.valueOf(value));
+    }
+
+    public static boolean getBooleanProperty(PropertyResolver resolver, String name, boolean defaultValue) {
+        return toBoolean(getObject(resolver, name), defaultValue);
+    }
+
+    public static boolean getBooleanProperty(Map<String, ?> props, String name, boolean defaultValue) {
+        return toBoolean(getObject(props, name), defaultValue);
+    }
+
+    public static boolean toBoolean(Object value, boolean defaultValue) {
+        if (value == null) {
+            return defaultValue;
+        } else {
+            return toBoolean(value).booleanValue();
+        }
+    }
+
+    public static Boolean getBoolean(PropertyResolver resolver, String name) {
+        return toBoolean(resolvePropertyValue(resolver, name));
+    }
+
+    public static Boolean getBoolean(Map<String, ?> props, String name) {
+        return toBoolean(resolvePropertyValue(props, name));
+    }
+
+    public static Boolean toBoolean(Object value) {
+        if (value == null) {
+            return null;
+        } else if (value instanceof Boolean) {
+            return (Boolean) value;
+        } else {
+            return Boolean.valueOf(value.toString());
+        }
+    }
+
+    public static Object updateProperty(PropertyResolver resolver, String name, boolean value) {
+        return updateProperty(resolver.getProperties(), name, value);
+    }
+
+    public static Object updateProperty(Map<String, Object> props, String name, boolean value) {
+        return updateProperty(props, name, Boolean.valueOf(value));
+    }
+
+    /**
+     * @param resolver     The {@link PropertyResolver} to use - ignored if {@code null}
+     * @param name         The property name
+     * @param defaultValue The default value to return if property not set or empty
+     * @return The set value (if not {@code null}/empty) or default one
+     */
+    public static String getStringProperty(PropertyResolver resolver, String name, String defaultValue) {
+        String value = getString(resolver, name);
+        if (GenericUtils.isEmpty(value)) {
+            return defaultValue;
+        } else {
+            return value;
+        }
+    }
+    public static String getStringProperty(Map<String, ?> props, String name, String defaultValue) {
+        Object value = resolvePropertyValue(props, name);
+        if (value == null) {
+            return defaultValue;
+        } else {
+            return Objects.toString(value);
+        }
+    }
+
+    public static String getString(PropertyResolver resolver, String name) {
+        Object value = getObject(resolver, name);
+        return Objects.toString(value, null);
+    }
+
+    public static String getString(Map<String, ?> props, String name) {
+        Object value = getObject(props, name);
+        return Objects.toString(value, null);
+    }
+
+    public static Object getObject(PropertyResolver resolver, String name) {
+        return resolvePropertyValue(resolver, name);
+    }
+
+
+    // for symmetrical reasons...
+    public static Object getObject(Map<String, ?> props, String name) {
+        return resolvePropertyValue(props, name);
+    }
+
+    public static Object resolvePropertyValue(Map<String, ?> props, String name) {
+        String key = ValidateUtils.checkNotNullAndNotEmpty(name, "No property name");
+        return GenericUtils.isEmpty(props) ? null : props.get(key);
+    }
+
+    /**
+     * @param resolver The {@link PropertyResolver} instance
+     * @param name     The property name
+     * @param value    The new value - if {@code null} or an empty {@link CharSequence}
+     *                 the property is <U>removed</U>
+     * @return The previous value - {@code null} if none
+     */
+    public static Object updateProperty(PropertyResolver resolver, String name, Object value) {
+        return updateProperty(resolver.getProperties(), name, value);
+    }
+
+    public static Object updateProperty(Map<String, Object> props, String name, Object value) {
+        String key = ValidateUtils.checkNotNullAndNotEmpty(name, "No property name");
+        if ((value == null) || ((value instanceof CharSequence) && GenericUtils.isEmpty((CharSequence) value))) {
+            return props.remove(key);
+        } else {
+            return props.put(key, value);
+        }
+    }
+
+    /**
+     * Unwinds the resolvers hierarchy until found one with a non-{@code null} value
+     * for the requested property or reached top.
+     *
+     * @param resolver The {@link PropertyResolver} to start from - ignored if {@code null}
+     * @param name     The requested property name
+     * @return The found value or {@code null}
+     */
+    public static Object resolvePropertyValue(PropertyResolver resolver, String name) {
+        String key = ValidateUtils.checkNotNullAndNotEmpty(name, "No property name");
+        for (PropertyResolver r = resolver; r != null; r = r.getParentPropertyResolver()) {
+            Map<String, ?> props = r.getProperties();
+            Object value = GenericUtils.isEmpty(props) ? null : props.get(key);
+            if (value != null) {
+                return value;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Unwinds the resolvers hierarchy until found one with a non-{@code null} value
+     * for the requested property or reached top.
+     *
+     * @param resolver The {@link PropertyResolver} to start from - ignored if {@code null}
+     * @param name     The requested property name
+     * @return The found properties {@link Map} or {@code null}
+     */
+    public static Map<String, Object> resolvePropertiesSource(PropertyResolver resolver, String name) {
+        String key = ValidateUtils.checkNotNullAndNotEmpty(name, "No property name");
+        for (PropertyResolver r = resolver; r != null; r = r.getParentPropertyResolver()) {
+            Map<String, Object> props = r.getProperties();
+            Object value = GenericUtils.isEmpty(props) ? null : props.get(key);
+            if (value != null) {
+                return props;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Wraps a {@link Map} into a {@link PropertyResolver} so it can be used
+     * with these utilities
+     *
+     * @param props The properties map - may be {@code null}/empty if no properties
+     *              are updated
+     * @return The resolver wrapper
+     */
+    public static PropertyResolver toPropertyResolver(final Map<String, Object> props) {
+        return toPropertyResolver(props, null);
+    }
+
+    public static PropertyResolver toPropertyResolver(final Map<String, Object> props, final PropertyResolver parent) {
+        return new PropertyResolver() {
+            @Override
+            public PropertyResolver getParentPropertyResolver() {
+                return parent;
+            }
+
+            @Override
+            public Map<String, Object> getProperties() {
+                return props;
+            }
+
+            @Override
+            public String toString() {
+                return Objects.toString(props);
+            }
+        };
+    }
+}

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
index 2e70c49..ea579e1 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/AbstractChannel.java
@@ -22,6 +22,8 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArraySet;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -30,7 +32,8 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.PropertyResolver;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.future.DefaultCloseFuture;
@@ -59,11 +62,6 @@ public abstract class AbstractChannel
         extends AbstractInnerCloseable
         implements Channel, ExecutorServiceConfigurer {
 
-    public static final int DEFAULT_WINDOW_SIZE = 0x200000;
-    public static final int DEFAULT_PACKET_SIZE = 0x8000;
-
-    public static final long DEFAULT_CHANNEL_CLOSE_TIMEOUT = TimeUnit.SECONDS.toMillis(5L);
-
     /**
      * Default growth factor function used to resize response buffers
      */
@@ -78,7 +76,6 @@ public abstract class AbstractChannel
     protected final Window localWindow;
     protected final Window remoteWindow;
     protected ConnectionService service;
-    protected Session session;
     protected int id;
     protected int recipient;
     protected final AtomicBoolean eof = new AtomicBoolean(false);
@@ -91,6 +88,9 @@ public abstract class AbstractChannel
     protected final Collection<ChannelListener> channelListeners = new CopyOnWriteArraySet<>();
     protected final ChannelListener channelListenerProxy;
 
+    private Session session;
+    private final Map<String, Object> properties = new ConcurrentHashMap<>();
+
     protected AbstractChannel(boolean client) {
         this("", client);
     }
@@ -132,6 +132,11 @@ public abstract class AbstractChannel
     }
 
     @Override
+    public PropertyResolver getParentPropertyResolver() {
+        return getSession();
+    }
+
+    @Override
     public ExecutorService getExecutorService() {
         return executor;
     }
@@ -304,32 +309,35 @@ public abstract class AbstractChannel
             if (immediately) {
                 gracefulFuture.setClosed();
             } else if (!gracefulFuture.isClosed()) {
-                log.debug("Send SSH_MSG_CHANNEL_CLOSE on channel {}", AbstractChannel.this);
+                final Channel channel = AbstractChannel.this;
+                log.debug("Send SSH_MSG_CHANNEL_CLOSE on channel {}", channel);
+
                 Session s = getSession();
                 Buffer buffer = s.createBuffer(SshConstants.SSH_MSG_CHANNEL_CLOSE, Short.SIZE);
                 buffer.putInt(getRecipient());
+
                 try {
-                    long timeout = FactoryManagerUtils.getLongProperty(getSession(), FactoryManager.CHANNEL_CLOSE_TIMEOUT, DEFAULT_CHANNEL_CLOSE_TIMEOUT);
-                    session.writePacket(buffer, timeout, TimeUnit.MILLISECONDS).addListener(new SshFutureListener<IoWriteFuture>() {
+                    long timeout = PropertyResolverUtils.getLongProperty(channel, FactoryManager.CHANNEL_CLOSE_TIMEOUT, FactoryManager.DEFAULT_CHANNEL_CLOSE_TIMEOUT);
+                    s.writePacket(buffer, timeout, TimeUnit.MILLISECONDS).addListener(new SshFutureListener<IoWriteFuture>() {
                         @SuppressWarnings("synthetic-access")
                         @Override
                         public void operationComplete(IoWriteFuture future) {
                             if (future.isWritten()) {
-                                log.debug("Message SSH_MSG_CHANNEL_CLOSE written on channel {}", AbstractChannel.this);
+                                log.debug("Message SSH_MSG_CHANNEL_CLOSE written on channel {}", channel);
                                 if (gracefulState.compareAndSet(GracefulState.Opened, GracefulState.CloseSent)) {
                                     // Waiting for CLOSE message to come back from the remote side
                                 } else if (gracefulState.compareAndSet(GracefulState.CloseReceived, GracefulState.Closed)) {
                                     gracefulFuture.setClosed();
                                 }
                             } else {
-                                log.debug("Failed to write SSH_MSG_CHANNEL_CLOSE on channel {}", AbstractChannel.this);
-                                AbstractChannel.this.close(true);
+                                log.debug("Failed to write SSH_MSG_CHANNEL_CLOSE on channel {}", channel);
+                                channel.close(true);
                             }
                         }
                     });
                 } catch (IOException e) {
-                    log.debug("Exception caught while writing SSH_MSG_CHANNEL_CLOSE packet on channel " + AbstractChannel.this, e);
-                    AbstractChannel.this.close(true);
+                    log.debug("Exception caught while writing SSH_MSG_CHANNEL_CLOSE packet on channel " + channel, e);
+                    channel.close(true);
                 }
             }
 
@@ -471,8 +479,13 @@ public abstract class AbstractChannel
         writePacket(buffer);
     }
 
+    @Override
+    public Map<String, Object> getProperties() {
+        return properties;
+    }
+
     protected void configureWindow() {
-        localWindow.init(getSession());
+        localWindow.init(this);
     }
 
     protected void sendWindowAdjust(int len) throws IOException {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/channel/Channel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/Channel.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/Channel.java
index dc93b96..20436c8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/Channel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/Channel.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.common.Closeable;
+import org.apache.sshd.common.PropertyResolver;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.session.ConnectionService;
 import org.apache.sshd.common.session.Session;
@@ -33,7 +34,7 @@ import org.apache.sshd.common.util.buffer.Buffer;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public interface Channel extends ChannelListenerManager, Closeable {
+public interface Channel extends ChannelListenerManager, PropertyResolver, Closeable {
 
     /**
      * @return Local channel identifier

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java
index a2c4ace..0ba9c39 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelOutputStream.java
@@ -23,7 +23,7 @@ import java.io.InterruptedIOException;
 import java.io.OutputStream;
 import java.nio.channels.Channel;
 import java.util.concurrent.TimeUnit;
-import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.util.ValidateUtils;
@@ -55,7 +55,7 @@ public class ChannelOutputStream extends OutputStream implements Channel {
     private boolean noDelay;
 
     public ChannelOutputStream(AbstractChannel channel, Window remoteWindow, Logger log, byte cmd) {
-        this(channel, remoteWindow, FactoryManagerUtils.getLongProperty(channel, WAIT_FOR_SPACE_TIMEOUT, DEFAULT_WAIT_FOR_SPACE_TIMEOUT), log, cmd);
+        this(channel, remoteWindow, PropertyResolverUtils.getLongProperty(channel, WAIT_FOR_SPACE_TIMEOUT, DEFAULT_WAIT_FOR_SPACE_TIMEOUT), log, cmd);
     }
 
     public ChannelOutputStream(AbstractChannel channel, Window remoteWindow, long maxWaitTimeout, Logger log, byte cmd) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelPipedInputStream.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelPipedInputStream.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelPipedInputStream.java
index a01b955..61c5ec9 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelPipedInputStream.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/ChannelPipedInputStream.java
@@ -29,7 +29,8 @@ import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.PropertyResolver;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
@@ -40,8 +41,6 @@ import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
 public class ChannelPipedInputStream extends InputStream implements ChannelPipedSink {
-    public static final long DEFAULT_TIMEOUT = 0L;
-
     private final Window localWindow;
     private final Buffer buffer = new ByteArrayBuffer();
     private final byte[] b = new byte[1];
@@ -60,9 +59,13 @@ public class ChannelPipedInputStream extends InputStream implements ChannelPiped
 
     private long timeout;
 
-    public ChannelPipedInputStream(Window localWindow) {
+    public ChannelPipedInputStream(PropertyResolver resolver, Window localWindow) {
+        this(localWindow, PropertyResolverUtils.getLongProperty(resolver, FactoryManager.WINDOW_TIMEOUT, FactoryManager.DEFAULT_WINDOW_TIMEOUT));
+    }
+
+    public ChannelPipedInputStream(Window localWindow, long windowTimeout) {
         this.localWindow = ValidateUtils.checkNotNull(localWindow, "No local window provided");
-        this.timeout = FactoryManagerUtils.getLongProperty(localWindow.getProperties(), FactoryManager.WINDOW_TIMEOUT, DEFAULT_TIMEOUT);
+        this.timeout = windowTimeout;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java b/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
index 0094b9d..08d8ed7 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/channel/Window.java
@@ -28,8 +28,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
-import org.apache.sshd.common.session.Session;
+import org.apache.sshd.common.PropertyResolver;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.util.Predicate;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.logging.AbstractLoggingBean;
@@ -43,7 +43,7 @@ import org.apache.sshd.common.util.logging.AbstractLoggingBean;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public class Window extends AbstractLoggingBean implements java.nio.channels.Channel {
+public class Window extends AbstractLoggingBean implements java.nio.channels.Channel, PropertyResolver {
     /**
      * Default {@link Predicate} used to test if space became available
      */
@@ -65,7 +65,7 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha
 
     private int maxSize;
     private int packetSize;
-    private Map<String, ?> props = Collections.<String, Object>emptyMap();
+    private Map<String, Object> props = Collections.<String, Object>emptyMap();
 
     public Window(AbstractChannel channel, Object lock, boolean client, boolean local) {
         this.channel = ValidateUtils.checkNotNull(channel, "No channel provided");
@@ -73,10 +73,16 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha
         this.suffix = ": " + (client ? "client" : "server") + " " + (local ? "local " : "remote") + " window";
     }
 
-    public Map<String, ?> getProperties() {
+    @Override
+    public Map<String, Object> getProperties() {
         return props;
     }
 
+    @Override
+    public PropertyResolver getParentPropertyResolver() {
+        return channel;
+    }
+
     public int getSize() {
         synchronized (lock) {
             return sizeHolder.get();
@@ -91,21 +97,13 @@ public class Window extends AbstractLoggingBean implements java.nio.channels.Cha
         return packetSize;
     }
 
-    public void init(Session session) {
-        init(session.getFactoryManager());
-    }
-
-    public void init(FactoryManager manager) {
-        init(manager.getProperties());
-    }
-
-    public void init(Map<String, ?> props) {
-        init(FactoryManagerUtils.getIntProperty(props, FactoryManager.WINDOW_SIZE, AbstractChannel.DEFAULT_WINDOW_SIZE),
-             FactoryManagerUtils.getIntProperty(props, FactoryManager.MAX_PACKET_SIZE, AbstractChannel.DEFAULT_PACKET_SIZE),
-             props);
+    public void init(PropertyResolver resolver) {
+        init(PropertyResolverUtils.getIntProperty(resolver, FactoryManager.WINDOW_SIZE, FactoryManager.DEFAULT_WINDOW_SIZE),
+             PropertyResolverUtils.getIntProperty(resolver, FactoryManager.MAX_PACKET_SIZE, FactoryManager.DEFAULT_MAX_PACKET_SIZE),
+             resolver.getProperties());
     }
 
-    public void init(int size, int packetSize, Map<String, ?> props) {
+    public void init(int size, int packetSize, Map<String, Object> props) {
         ValidateUtils.checkTrue(size >= 0, "Illegal initial size: %d", size);
         ValidateUtils.checkTrue(packetSize > 0, "Illegal packet size: %d", packetSize);
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java b/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java
index 07b1d90..6fbe333 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/forward/TcpipClientChannel.java
@@ -30,6 +30,7 @@ import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.SshdSocketAddress;
 import org.apache.sshd.common.channel.ChannelOutputStream;
 import org.apache.sshd.common.io.IoSession;
+import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 
@@ -86,6 +87,7 @@ public class TcpipClientChannel extends AbstractClientChannel {
         openFuture = new DefaultOpenFuture(lock);
         log.debug("Send SSH_MSG_CHANNEL_OPEN on channel {}", this);
 
+        Session session = getSession();
         Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_OPEN);
         buffer.putString(type);
         buffer.putInt(id);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactory.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactory.java b/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactory.java
index bb1742e..73a91ca 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactory.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/io/AbstractIoServiceFactory.java
@@ -23,7 +23,7 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.util.closeable.AbstractCloseable;
 import org.apache.sshd.common.util.threads.ExecutorServiceCarrier;
 
@@ -77,7 +77,7 @@ public abstract class AbstractIoServiceFactory extends AbstractCloseable impleme
     }
 
     public static int getNioWorkers(FactoryManager manager) {
-        int nb = FactoryManagerUtils.getIntProperty(manager, FactoryManager.NIO_WORKERS, FactoryManager.DEFAULT_NIO_WORKERS);
+        int nb = PropertyResolverUtils.getIntProperty(manager, FactoryManager.NIO_WORKERS, FactoryManager.DEFAULT_NIO_WORKERS);
         if (nb > 0) {
             return nb;
         } else {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaAcceptor.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaAcceptor.java b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaAcceptor.java
index f25d8ee..bfd87f6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaAcceptor.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaAcceptor.java
@@ -31,7 +31,7 @@ import org.apache.mina.core.service.IoService;
 import org.apache.mina.transport.socket.nio.NioSession;
 import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.PropertyResolverUtils;
 
 /**
  */
@@ -48,8 +48,8 @@ public class MinaAcceptor extends MinaService implements org.apache.sshd.common.
     public MinaAcceptor(FactoryManager manager, org.apache.sshd.common.io.IoHandler handler, IoProcessor<NioSession> ioProcessor) {
         super(manager, handler, ioProcessor);
 
-        backlog = FactoryManagerUtils.getIntProperty(manager, FactoryManager.SOCKET_BACKLOG, DEFAULT_BACKLOG);
-        reuseAddress = FactoryManagerUtils.getBooleanProperty(manager, FactoryManager.SOCKET_REUSEADDR, DEFAULT_REUSE_ADDRESS);
+        backlog = PropertyResolverUtils.getIntProperty(manager, FactoryManager.SOCKET_BACKLOG, DEFAULT_BACKLOG);
+        reuseAddress = PropertyResolverUtils.getBooleanProperty(manager, FactoryManager.SOCKET_REUSEADDR, DEFAULT_REUSE_ADDRESS);
     }
 
     protected IoAcceptor createAcceptor() {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java
index 1455518..654c0b0 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/io/mina/MinaService.java
@@ -32,7 +32,7 @@ import org.apache.mina.transport.socket.SocketSessionConfig;
 import org.apache.mina.transport.socket.nio.NioSession;
 import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.util.closeable.AbstractCloseable;
 
 /**
@@ -151,11 +151,11 @@ public abstract class MinaService extends AbstractCloseable implements org.apach
     }
 
     protected Integer getInteger(String property) {
-        return FactoryManagerUtils.getInteger(manager, property);
+        return PropertyResolverUtils.getInteger(manager, property);
     }
 
     protected Boolean getBoolean(String property) {
-        return FactoryManagerUtils.getBoolean(manager, property);
+        return PropertyResolverUtils.getBoolean(manager, property);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Acceptor.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Acceptor.java b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Acceptor.java
index f12bc4a..836f41d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Acceptor.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Acceptor.java
@@ -32,7 +32,7 @@ import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.io.IoAcceptor;
 import org.apache.sshd.common.io.IoHandler;
@@ -48,7 +48,7 @@ public class Nio2Acceptor extends Nio2Service implements IoAcceptor {
     public Nio2Acceptor(FactoryManager manager, IoHandler handler, AsynchronousChannelGroup group) {
         super(manager, handler, group);
         channels = new ConcurrentHashMap<SocketAddress, AsynchronousServerSocketChannel>();
-        backlog = FactoryManagerUtils.getIntProperty(manager, FactoryManager.SOCKET_BACKLOG, DEFAULT_BACKLOG);
+        backlog = PropertyResolverUtils.getIntProperty(manager, FactoryManager.SOCKET_BACKLOG, DEFAULT_BACKLOG);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Service.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Service.java b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Service.java
index 7d4f1db..ba1494c 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Service.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Service.java
@@ -30,7 +30,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.io.IoHandler;
 import org.apache.sshd.common.io.IoService;
 import org.apache.sshd.common.io.IoSession;
@@ -78,7 +78,7 @@ public abstract class Nio2Service extends AbstractInnerCloseable implements IoSe
     }
 
     protected <T> void setOption(NetworkChannel socket, String property, SocketOption<T> option, T defaultValue) throws IOException {
-        String valStr = FactoryManagerUtils.getString(manager, property);
+        String valStr = PropertyResolverUtils.getString(manager, property);
         T val = defaultValue;
         if (!GenericUtils.isEmpty(valStr)) {
             Class<T> type = option.type();

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Session.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Session.java b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Session.java
index 9f5f09c..d37403d 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Session.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2Session.java
@@ -31,7 +31,7 @@ import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.io.IoHandler;
 import org.apache.sshd.common.io.IoService;
@@ -179,7 +179,7 @@ public class Nio2Session extends AbstractCloseable implements IoSession {
     }
 
     public void startReading() {
-        startReading(FactoryManagerUtils.getIntProperty(manager, FactoryManager.NIO2_READ_BUFFER_SIZE, DEFAULT_READBUF_SIZE));
+        startReading(PropertyResolverUtils.getIntProperty(manager, FactoryManager.NIO2_READ_BUFFER_SIZE, DEFAULT_READBUF_SIZE));
     }
 
     public void startReading(int bufSize) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java b/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
index 584d3b1..6cbb376 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/kex/dh/AbstractDHKeyExchange.java
@@ -30,7 +30,6 @@ import org.apache.sshd.common.util.logging.AbstractLoggingBean;
  */
 public abstract class AbstractDHKeyExchange extends AbstractLoggingBean implements KeyExchange {
 
-    protected AbstractSession session;
     protected byte[] v_s;
     protected byte[] v_c;
     protected byte[] i_s;
@@ -41,6 +40,8 @@ public abstract class AbstractDHKeyExchange extends AbstractLoggingBean implemen
     protected byte[] k;
     protected byte[] h;
 
+    private AbstractSession session;
+
     protected AbstractDHKeyExchange() {
         super();
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
index 8f00b8d..65d7e64 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/AbstractConnectionService.java
@@ -30,8 +30,8 @@ import org.apache.sshd.client.channel.AbstractClientChannel;
 import org.apache.sshd.client.future.OpenFuture;
 import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.channel.Channel;
@@ -48,20 +48,6 @@ import org.apache.sshd.common.util.closeable.AbstractInnerCloseable;
 import org.apache.sshd.server.channel.OpenChannelException;
 import org.apache.sshd.server.x11.X11ForwardSupport;
 
-import static org.apache.sshd.common.SshConstants.SSH_MSG_CHANNEL_CLOSE;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_CHANNEL_DATA;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_CHANNEL_EOF;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_CHANNEL_EXTENDED_DATA;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_CHANNEL_FAILURE;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_CHANNEL_OPEN;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_CHANNEL_OPEN_FAILURE;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_CHANNEL_REQUEST;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_CHANNEL_WINDOW_ADJUST;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_GLOBAL_REQUEST;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_REQUEST_FAILURE;
-import static org.apache.sshd.common.SshConstants.SSH_MSG_REQUEST_SUCCESS;
-
 /**
  * Base implementation of ConnectionService.
  *
@@ -147,7 +133,7 @@ public abstract class AbstractConnectionService extends AbstractInnerCloseable i
 
     @Override
     public int registerChannel(Channel channel) throws IOException {
-        int maxChannels = FactoryManagerUtils.getIntProperty(session, MAX_CONCURRENT_CHANNELS_PROP, DEFAULT_MAX_CHANNELS);
+        int maxChannels = PropertyResolverUtils.getIntProperty(session, MAX_CONCURRENT_CHANNELS_PROP, DEFAULT_MAX_CHANNELS);
         int curSize = channels.size();
         if (curSize > maxChannels) {
             throw new IllegalStateException("Currently active channels (" + curSize + ") at max.: " + maxChannels);
@@ -182,43 +168,43 @@ public abstract class AbstractConnectionService extends AbstractInnerCloseable i
     @Override
     public void process(int cmd, Buffer buffer) throws Exception {
         switch (cmd) {
-            case SSH_MSG_CHANNEL_OPEN:
+            case SshConstants.SSH_MSG_CHANNEL_OPEN:
                 channelOpen(buffer);
                 break;
-            case SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
+            case SshConstants.SSH_MSG_CHANNEL_OPEN_CONFIRMATION:
                 channelOpenConfirmation(buffer);
                 break;
-            case SSH_MSG_CHANNEL_OPEN_FAILURE:
+            case SshConstants.SSH_MSG_CHANNEL_OPEN_FAILURE:
                 channelOpenFailure(buffer);
                 break;
-            case SSH_MSG_CHANNEL_REQUEST:
+            case SshConstants.SSH_MSG_CHANNEL_REQUEST:
                 channelRequest(buffer);
                 break;
-            case SSH_MSG_CHANNEL_DATA:
+            case SshConstants.SSH_MSG_CHANNEL_DATA:
                 channelData(buffer);
                 break;
-            case SSH_MSG_CHANNEL_EXTENDED_DATA:
+            case SshConstants.SSH_MSG_CHANNEL_EXTENDED_DATA:
                 channelExtendedData(buffer);
                 break;
-            case SSH_MSG_CHANNEL_FAILURE:
+            case SshConstants.SSH_MSG_CHANNEL_FAILURE:
                 channelFailure(buffer);
                 break;
-            case SSH_MSG_CHANNEL_WINDOW_ADJUST:
+            case SshConstants.SSH_MSG_CHANNEL_WINDOW_ADJUST:
                 channelWindowAdjust(buffer);
                 break;
-            case SSH_MSG_CHANNEL_EOF:
+            case SshConstants.SSH_MSG_CHANNEL_EOF:
                 channelEof(buffer);
                 break;
-            case SSH_MSG_CHANNEL_CLOSE:
+            case SshConstants.SSH_MSG_CHANNEL_CLOSE:
                 channelClose(buffer);
                 break;
-            case SSH_MSG_GLOBAL_REQUEST:
+            case SshConstants.SSH_MSG_GLOBAL_REQUEST:
                 globalRequest(buffer);
                 break;
-            case SSH_MSG_REQUEST_SUCCESS:
+            case SshConstants.SSH_MSG_REQUEST_SUCCESS:
                 requestSuccess(buffer);
                 break;
-            case SSH_MSG_REQUEST_FAILURE:
+            case SshConstants.SSH_MSG_REQUEST_FAILURE:
                 requestFailure(buffer);
                 break;
             default:

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/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 4108949..11ca6f8 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
@@ -37,9 +37,10 @@ import java.util.concurrent.atomic.AtomicReference;
 
 import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
 import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.PropertyResolver;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.Service;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
@@ -60,6 +61,7 @@ import org.apache.sshd.common.mac.Mac;
 import org.apache.sshd.common.random.Random;
 import org.apache.sshd.common.util.EventListenerUtils;
 import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Pair;
 import org.apache.sshd.common.util.Readable;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.Buffer;
@@ -166,12 +168,9 @@ public abstract class AbstractSession extends AbstractInnerCloseable implements
     protected final AtomicReference<Buffer> requestResult = new AtomicReference<>();
     protected final Map<AttributeKey<?>, Object> attributes = new ConcurrentHashMap<>();
 
-    // Session timeout
-    protected long authTimeoutTimestamp;
-    protected long idleTimeoutTimestamp;
-    protected long authTimeoutMs = TimeUnit.MINUTES.toMillis(2);          // 2 minutes in milliseconds
-    protected long idleTimeoutMs = TimeUnit.MINUTES.toMillis(10);         // 10 minutes in milliseconds
-    protected long disconnectTimeoutMs = TimeUnit.SECONDS.toMillis(10);   // 10 seconds in milliseconds
+    // Session timeout measurements
+    protected long authTimeoutStart = System.currentTimeMillis();
+    protected long idleTimeoutStart = System.currentTimeMillis();
     protected final AtomicReference<TimeoutStatus> timeoutStatus = new AtomicReference<>(TimeoutStatus.NoTimeout);
 
     //
@@ -190,6 +189,7 @@ public abstract class AbstractSession extends AbstractInnerCloseable implements
      * The factory manager used to retrieve factories of Ciphers, Macs and other objects
      */
     private final FactoryManager factoryManager;
+    private final Map<String, Object> properties = new ConcurrentHashMap<>();
 
     /**
      * Create a new session.
@@ -198,7 +198,7 @@ public abstract class AbstractSession extends AbstractInnerCloseable implements
      * @param factoryManager the factory manager
      * @param ioSession      the underlying MINA session
      */
-    public AbstractSession(boolean isServer, FactoryManager factoryManager, IoSession ioSession) {
+    protected AbstractSession(boolean isServer, FactoryManager factoryManager, IoSession ioSession) {
         this.isServer = isServer;
         this.factoryManager = ValidateUtils.checkNotNull(factoryManager, "No factory manager provided", GenericUtils.EMPTY_OBJECT_ARRAY);
         this.ioSession = ioSession;
@@ -207,11 +207,7 @@ public abstract class AbstractSession extends AbstractInnerCloseable implements
         sessionListenerProxy = EventListenerUtils.proxyWrapper(SessionListener.class, loader, sessionListeners);
         channelListenerProxy = EventListenerUtils.proxyWrapper(ChannelListener.class, loader, channelListeners);
 
-        random = factoryManager.getRandomFactory().create();
-        authTimeoutMs = getLongProperty(FactoryManager.AUTH_TIMEOUT, authTimeoutMs);
-        authTimeoutTimestamp = System.currentTimeMillis() + authTimeoutMs;
-        idleTimeoutMs = getLongProperty(FactoryManager.IDLE_TIMEOUT, idleTimeoutMs);
-        disconnectTimeoutMs = getLongProperty(FactoryManager.DISCONNECT_TIMEOUT, disconnectTimeoutMs);
+        random = ValidateUtils.checkNotNull(factoryManager.getRandomFactory(), "No random factory").create();
     }
 
     /**
@@ -287,6 +283,16 @@ public abstract class AbstractSession extends AbstractInnerCloseable implements
     }
 
     @Override
+    public PropertyResolver getParentPropertyResolver() {
+        return getFactoryManager();
+    }
+
+    @Override
+    public Map<String, Object> getProperties() {
+        return properties;
+    }
+
+    @Override
     public String getNegotiatedKexParameter(KexProposalOption paramType) {
         if (paramType == null) {
             return null;
@@ -1260,9 +1266,10 @@ public abstract class AbstractSession extends AbstractInnerCloseable implements
         Buffer buffer = createBuffer(SshConstants.SSH_MSG_DISCONNECT, msg.length() + Short.SIZE);
         buffer.putInt(reason);
         buffer.putString(msg);
-        buffer.putString("");   // language...
+        buffer.putString("");   // TODO configure language...
         // Write the packet with a timeout to ensure a timely close of the session
         // in case the consumer does not read packets anymore.
+        long disconnectTimeoutMs = PropertyResolverUtils.getLongProperty(this, FactoryManager.DISCONNECT_TIMEOUT, FactoryManager.DEFAULT_DISCONNECT_TIMEOUT);
         writePacket(buffer, disconnectTimeoutMs, TimeUnit.MILLISECONDS).addListener(new SshFutureListener<IoWriteFuture>() {
             @Override
             public void operationComplete(IoWriteFuture future) {
@@ -1375,36 +1382,6 @@ public abstract class AbstractSession extends AbstractInnerCloseable implements
     }
 
     /**
-     * Retrieve a configuration property as an integer
-     *
-     * @param name         the name of the property
-     * @param defaultValue the default value
-     * @return the value of the configuration property or the default value if not found
-     */
-    @Override
-    public int getIntProperty(String name, int defaultValue) {
-        try {
-            return FactoryManagerUtils.getIntProperty(factoryManager, name, defaultValue);
-        } catch (Exception e) {
-            if (log.isDebugEnabled()) {
-                log.debug("getIntProperty(" + name + ") failed (" + e.getClass().getSimpleName() + ") to retrieve: " + e.getMessage());
-            }
-            return defaultValue;
-        }
-    }
-
-    public long getLongProperty(String name, long defaultValue) {
-        try {
-            return FactoryManagerUtils.getLongProperty(factoryManager, name, defaultValue);
-        } catch (Exception e) {
-            if (log.isDebugEnabled()) {
-                log.debug("getLongProperty(" + name + ") failed (" + e.getClass().getSimpleName() + ") to retrieve: " + e.getMessage());
-            }
-            return defaultValue;
-        }
-    }
-
-    /**
      * Returns the value of the user-defined attribute of this session.
      *
      * @param key the key of the attribute; must not be null.
@@ -1611,54 +1588,92 @@ public abstract class AbstractSession extends AbstractInnerCloseable implements
      * timed out, a DISCONNECT message will be sent.
      *
      * @throws IOException If failed to check
+     * @see #checkAuthenticationTimeout(long, long)
+     * @see #checkIdleTimeout(long, long)
      */
     protected void checkForTimeouts() throws IOException {
-        if (!isClosing()) {
-            long now = System.currentTimeMillis();
-            if ((!authed) && (authTimeoutMs > 0L) && (now > authTimeoutTimestamp)) {
-                timeoutStatus.set(TimeoutStatus.AuthTimeout);
-                disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "Session has timed out waiting for authentication after " + authTimeoutMs + " ms.");
-            }
-            if ((idleTimeoutMs > 0) && (idleTimeoutTimestamp > 0L) && (now > idleTimeoutTimestamp)) {
-                timeoutStatus.set(TimeoutStatus.AuthTimeout);
-                disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, "User session has timed out idling after " + idleTimeoutMs + " ms.");
-            }
+        if (isClosing()) {
+            log.debug("checkForTimeouts({}) session closing", this);
+            return;
         }
+
+        long now = System.currentTimeMillis();
+        Pair<TimeoutStatus, String> result = checkAuthenticationTimeout(now, getAuthTimeout());
+        if (result == null) {
+            result = checkIdleTimeout(now, getIdleTimeout());
+        }
+
+        TimeoutStatus status = (result == null) ? TimeoutStatus.NoTimeout : result.getFirst();
+        if ((status == null) || TimeoutStatus.NoTimeout.equals(status)) {
+            return;
+        }
+
+        if (log.isDebugEnabled()) {
+            log.debug("checkForTimeouts({}) disconnect - reason={}", this, status);
+        }
+
+        timeoutStatus.set(status);
+        disconnect(SshConstants.SSH2_DISCONNECT_PROTOCOL_ERROR, result.getSecond());
     }
 
-    @Override
-    public void resetIdleTimeout() {
-        this.idleTimeoutTimestamp = System.currentTimeMillis() + idleTimeoutMs;
+    /**
+     * Checks if authentication timeout expired
+     *
+     * @param now           The current time in millis
+     * @param authTimeoutMs The configured timeout in millis - if non-positive
+     *                      then no timeout
+     * @return A {@link Pair} specifying the timeout status and disconnect reason
+     * message if timeout expired, {@code null} or {@link TimeoutStatus#NoTimeout}
+     * if no timeout occurred
+     * @see #getAuthTimeout()
+     */
+    protected Pair<TimeoutStatus, String> checkAuthenticationTimeout(long now, long authTimeoutMs) {
+        long authDiff = now - authTimeoutStart;
+        if ((!authed) && (authTimeoutMs > 0L) && (authDiff > authTimeoutMs)) {
+            return new Pair<TimeoutStatus, String>(TimeoutStatus.AuthTimeout, "Session has timed out waiting for authentication after " + authTimeoutMs + " ms.");
+        } else {
+            return null;
+        }
     }
 
     /**
-     * Check if timeout has occurred.
+     * Checks if idle timeout expired
      *
-     * @return The {@link TimeoutStatus}
+     * @param now           The current time in millis
+     * @param authTimeoutMs The configured timeout in millis - if non-positive
+     *                      then no timeout
+     * @return A {@link Pair} specifying the timeout status and disconnect reason
+     * message if timeout expired, {@code null} or {@link TimeoutStatus#NoTimeout}
+     * if no timeout occurred
+     * @see #getIdleTimeout()
      */
+    protected Pair<TimeoutStatus, String> checkIdleTimeout(long now, long idleTimeoutMs) {
+        long idleDiff = now - idleTimeoutStart;
+        if ((idleTimeoutMs > 0L) && (idleDiff > idleTimeoutMs)) {
+            return new Pair<TimeoutStatus, String>(TimeoutStatus.IdleTimeout, "User session has timed out idling after " + idleTimeoutMs + " ms.");
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public void resetIdleTimeout() {
+        this.idleTimeoutStart = System.currentTimeMillis();
+    }
+
     @Override
     public TimeoutStatus getTimeoutStatus() {
         return timeoutStatus.get();
     }
 
-    /**
-     * What is timeout value in milliseconds for authentication stage
-     *
-     * @return The timeout value in milliseconds for authentication stage
-     */
     @Override
     public long getAuthTimeout() {
-        return authTimeoutMs;
+        return PropertyResolverUtils.getLongProperty(this, FactoryManager.AUTH_TIMEOUT, FactoryManager.DEFAULT_AUTH_TIMEOUT);
     }
 
-    /**
-     * What is timeout value in milliseconds for communication
-     *
-     * @return The timeout value in milliseconds for communication
-     */
     @Override
     public long getIdleTimeout() {
-        return idleTimeoutMs;
+        return PropertyResolverUtils.getLongProperty(this, FactoryManager.IDLE_TIMEOUT, FactoryManager.DEFAULT_IDLE_TIMEOUT);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/common/session/Session.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/session/Session.java b/sshd-core/src/main/java/org/apache/sshd/common/session/Session.java
index bd60783..3f04862 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/session/Session.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/session/Session.java
@@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit;
 
 import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.FactoryManager;
+import org.apache.sshd.common.PropertyResolver;
 import org.apache.sshd.common.Service;
 import org.apache.sshd.common.auth.UsernameHolder;
 import org.apache.sshd.common.channel.ChannelListenerManager;
@@ -39,7 +40,12 @@ import org.apache.sshd.common.util.buffer.Buffer;
  *
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public interface Session extends SessionListenerManager, ChannelListenerManager, Closeable, UsernameHolder {
+public interface Session
+        extends SessionListenerManager,
+                ChannelListenerManager,
+                PropertyResolver,
+                Closeable,
+                UsernameHolder {
 
     /**
      * Timeout status.
@@ -47,7 +53,7 @@ public interface Session extends SessionListenerManager, ChannelListenerManager,
     enum TimeoutStatus {
         NoTimeout,
         AuthTimeout,
-        IdleTimeout
+        IdleTimeout;
     }
 
     /**
@@ -102,15 +108,6 @@ public interface Session extends SessionListenerManager, ChannelListenerManager,
     String getNegotiatedKexParameter(KexProposalOption paramType);
 
     /**
-     * Retrieve a configuration property as an integer
-     *
-     * @param name         the name of the property
-     * @param defaultValue the default value
-     * @return the value of the configuration property or the default value if not found
-     */
-    int getIntProperty(String name, int defaultValue);
-
-    /**
      * Create a new buffer for the specified SSH packet and reserve the needed space
      * (5 bytes) for the packet header.
      *

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
index 29b03ea..ca806fd 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerFactoryManager.java
@@ -19,6 +19,7 @@
 package org.apache.sshd.server;
 
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.sshd.common.Factory;
 import org.apache.sshd.common.FactoryManager;
@@ -38,13 +39,16 @@ import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
  */
 public interface ServerFactoryManager extends FactoryManager, KeyPairProviderHolder {
     /**
-     * Key used to retrieve the value of the maximum concurrent open session count per username
+     * Key used to retrieve the value of the maximum concurrent open session count per username.
+     * If not set, then unlimited
      */
     String MAX_CONCURRENT_SESSIONS = "max-concurrent-sessions";
+
     /**
      * Key used to retrieve the value of the server identification string if not default.
      */
     String SERVER_IDENTIFICATION = "server-identification";
+
     /**
      * Key used to retrieve the value in the configuration properties map
      * of the maximum number of failed authentication requests before the
@@ -96,10 +100,16 @@ public interface ServerFactoryManager extends FactoryManager, KeyPairProviderHol
      * Key used to configure the timeout used when receiving a close request
      * on a channel to wait until the command cleanly exits after setting
      * an EOF on the input stream. In milliseconds.
+     * @see #DEFAULT_COMMAND_EXIT_TIMEOUT
      */
     String COMMAND_EXIT_TIMEOUT = "command-exit-timeout";
 
     /**
+     * Default {@link #COMMAND_EXIT_TIMEOUT} if not set
+     */
+    long DEFAULT_COMMAND_EXIT_TIMEOUT = TimeUnit.SECONDS.toMillis(5L);
+
+    /**
      * Key re-exchange will be automatically performed after the session
      * has sent or received the given amount of bytes.
      * The default value is 1 gigabyte.

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
index 8d1d152..55d5a5a 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
@@ -32,8 +32,8 @@ import java.util.Map;
 import org.apache.sshd.common.AbstractFactoryManager;
 import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.Factory;
-import org.apache.sshd.common.FactoryManagerUtils;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.ServiceFactory;
 import org.apache.sshd.common.io.IoAcceptor;
 import org.apache.sshd.common.io.IoServiceFactory;
@@ -465,7 +465,7 @@ public class SshServer extends AbstractFactoryManager implements ServerFactoryMa
 
         SshServer sshd = SshServer.setUpDefaultServer();
         Map<String, Object> props = sshd.getProperties();
-        FactoryManagerUtils.updateProperty(props, ServerFactoryManager.WELCOME_BANNER, "Welcome to SSHD\n");
+        PropertyResolverUtils.updateProperty(sshd, ServerFactoryManager.WELCOME_BANNER, "Welcome to SSHD\n");
         props.putAll(options);
         sshd.setPort(port);
 

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/DefaultKeyboardInteractiveAuthenticator.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/DefaultKeyboardInteractiveAuthenticator.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/DefaultKeyboardInteractiveAuthenticator.java
index 71283ff..0e3f971 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/DefaultKeyboardInteractiveAuthenticator.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/keyboard/DefaultKeyboardInteractiveAuthenticator.java
@@ -21,7 +21,7 @@ package org.apache.sshd.server.auth.keyboard;
 
 import java.util.List;
 
-import org.apache.sshd.common.FactoryManagerUtils;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
@@ -96,22 +96,22 @@ public class DefaultKeyboardInteractiveAuthenticator
     }
 
     protected String getInteractionName(ServerSession session) {
-        return FactoryManagerUtils.getStringProperty(session, KB_INTERACTIVE_NAME_PROP, DEFAULT_KB_INTERACTIVE_NAME);
+        return PropertyResolverUtils.getStringProperty(session, KB_INTERACTIVE_NAME_PROP, DEFAULT_KB_INTERACTIVE_NAME);
     }
 
     protected String getInteractionInstruction(ServerSession session) {
-        return FactoryManagerUtils.getStringProperty(session, KB_INTERACTIVE_INSTRUCTION_PROP, DEFAULT_KB_INTERACTIVE_INSTRUCTION);
+        return PropertyResolverUtils.getStringProperty(session, KB_INTERACTIVE_INSTRUCTION_PROP, DEFAULT_KB_INTERACTIVE_INSTRUCTION);
     }
 
     protected String getInteractionLanguage(ServerSession session) {
-        return FactoryManagerUtils.getStringProperty(session, KB_INTERACTIVE_LANG_PROP, DEFAULT_KB_INTERACTIVE_LANG);
+        return PropertyResolverUtils.getStringProperty(session, KB_INTERACTIVE_LANG_PROP, DEFAULT_KB_INTERACTIVE_LANG);
     }
 
     protected String getInteractionPrompt(ServerSession session) {
-        return FactoryManagerUtils.getStringProperty(session, KB_INTERACTIVE_PROMPT_PROP, DEFAULT_KB_INTERACTIVE_PROMPT);
+        return PropertyResolverUtils.getStringProperty(session, KB_INTERACTIVE_PROMPT_PROP, DEFAULT_KB_INTERACTIVE_PROMPT);
     }
 
     protected boolean isInteractionPromptEchoEnabled(ServerSession session) {
-        return FactoryManagerUtils.getBooleanProperty(session, KB_INTERACTIVE_ECHO_PROMPT_PROP, DEFAULT_KB_INTERACTIVE_ECHO_PROMPT);
+        return PropertyResolverUtils.getBooleanProperty(session, KB_INTERACTIVE_ECHO_PROMPT_PROP, DEFAULT_KB_INTERACTIVE_ECHO_PROMPT);
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/server/channel/AbstractServerChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/AbstractServerChannel.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/AbstractServerChannel.java
index 9aa5426..095d164 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/channel/AbstractServerChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/AbstractServerChannel.java
@@ -96,6 +96,7 @@ public abstract class AbstractServerChannel extends AbstractChannel implements S
                 log.debug("Send SSH_MSG_CHANNEL_REQUEST exit-status on channel {}", Integer.valueOf(id));
             }
 
+            Session session = getSession();
             Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_CHANNEL_REQUEST, Long.SIZE);
             buffer.putInt(recipient);
             buffer.putString("exit-status");

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
index 98fe92d..31cd5c1 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/ChannelSession.java
@@ -28,6 +28,7 @@ import java.util.Set;
 import java.util.TimerTask;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.sshd.agent.SshAgent;
@@ -35,8 +36,8 @@ import org.apache.sshd.agent.SshAgentFactory;
 import org.apache.sshd.common.Closeable;
 import org.apache.sshd.common.Factory;
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.channel.AbstractChannelRequestHandler;
 import org.apache.sshd.common.channel.Channel;
@@ -48,6 +49,7 @@ import org.apache.sshd.common.file.FileSystemFactory;
 import org.apache.sshd.common.future.CloseFuture;
 import org.apache.sshd.common.future.DefaultCloseFuture;
 import org.apache.sshd.common.future.SshFutureListener;
+import org.apache.sshd.common.session.Session;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.Buffer;
@@ -76,8 +78,6 @@ import org.apache.sshd.server.x11.X11ForwardSupport;
  */
 public class ChannelSession extends AbstractServerChannel {
 
-    public static final long DEFAULT_COMMAND_EXIT_TIMEOUT = 5000;
-
     protected static class StandardEnvironment implements Environment {
 
         private final Map<Signal, Set<SignalListener>> listeners;
@@ -240,13 +240,17 @@ public class ChannelSession extends AbstractServerChannel {
                     }
                 };
 
-                FactoryManager manager = getSession().getFactoryManager();
-                long timeout = FactoryManagerUtils.getLongProperty(manager, ServerFactoryManager.COMMAND_EXIT_TIMEOUT, DEFAULT_COMMAND_EXIT_TIMEOUT);
+                ChannelSession channel = ChannelSession.this;
+                long timeout = PropertyResolverUtils.getLongProperty(
+                        channel, ServerFactoryManager.COMMAND_EXIT_TIMEOUT, ServerFactoryManager.DEFAULT_COMMAND_EXIT_TIMEOUT);
                 if (log.isDebugEnabled()) {
-                    log.debug("Wait {} ms for shell to exit cleanly", Long.valueOf(timeout));
+                    log.debug("Wait {} ms for shell to exit cleanly on {}", Long.valueOf(timeout), channel);
                 }
 
-                manager.getScheduledExecutorService().schedule(task, timeout, TimeUnit.MILLISECONDS);
+                Session s = channel.getSession();
+                FactoryManager manager = ValidateUtils.checkNotNull(s.getFactoryManager(), "No factory manager");
+                ScheduledExecutorService scheduler = ValidateUtils.checkNotNull(manager.getScheduledExecutorService(), "No scheduling service");
+                scheduler.schedule(task, timeout, TimeUnit.MILLISECONDS);
                 commandExitFuture.addListener(new SshFutureListener<CloseFuture>() {
                     @Override
                     public void operationComplete(CloseFuture future) {
@@ -532,17 +536,18 @@ public class ChannelSession extends AbstractServerChannel {
 
     protected void prepareCommand() throws IOException {
         // Add the user
+        Session session = getSession();
         addEnvVariable(Environment.ENV_USER, session.getUsername());
         // If the shell wants to be aware of the session, let's do that
         if (command instanceof SessionAware) {
-            ((SessionAware) command).setSession((ServerSession) getSession());
+            ((SessionAware) command).setSession((ServerSession) session);
         }
         if (command instanceof ChannelSessionAware) {
             ((ChannelSessionAware) command).setChannelSession(this);
         }
         // If the shell wants to be aware of the file system, let's do that too
         if (command instanceof FileSystemAware) {
-            ServerFactoryManager manager = ((ServerSession) getSession()).getFactoryManager();
+            ServerFactoryManager manager = ((ServerSession) session).getFactoryManager();
             FileSystemFactory factory = manager.getFileSystemFactory();
             ((FileSystemAware) command).setFileSystem(factory.createFileSystem(session));
         }
@@ -571,7 +576,7 @@ public class ChannelSession extends AbstractServerChannel {
                 setDataReceiver(recv);
                 ((AsyncCommand) command).setIoInputStream(recv.getIn());
             } else {
-                PipeDataReceiver recv = new PipeDataReceiver(localWindow);
+                PipeDataReceiver recv = new PipeDataReceiver(this, localWindow);
                 setDataReceiver(recv);
                 command.setInputStream(recv.getIn());
             }
@@ -608,7 +613,9 @@ public class ChannelSession extends AbstractServerChannel {
     }
 
     protected boolean handleAgentForwarding(Buffer buffer) throws IOException {
+        Session session = getSession();
         ValidateUtils.checkTrue(session instanceof ServerSession, "Session not a server one");
+
         FactoryManager manager = session.getFactoryManager();
         ForwardingFilter filter = manager.getTcpipForwardingFilter();
         SshAgentFactory factory = manager.getAgentFactory();
@@ -625,7 +632,9 @@ public class ChannelSession extends AbstractServerChannel {
     }
 
     protected boolean handleX11Forwarding(Buffer buffer) throws IOException {
+        Session session = getSession();
         ValidateUtils.checkTrue(session instanceof ServerSession, "Session not a server one");
+
         FactoryManager manager = session.getFactoryManager();
         ForwardingFilter filter = manager.getTcpipForwardingFilter();
         if ((filter == null) || (!filter.canForwardX11(session))) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/server/channel/PipeDataReceiver.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/channel/PipeDataReceiver.java b/sshd-core/src/main/java/org/apache/sshd/server/channel/PipeDataReceiver.java
index deb1b25..0aa29a8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/channel/PipeDataReceiver.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/channel/PipeDataReceiver.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
+import org.apache.sshd.common.PropertyResolver;
 import org.apache.sshd.common.channel.ChannelPipedInputStream;
 import org.apache.sshd.common.channel.ChannelPipedOutputStream;
 import org.apache.sshd.common.channel.Window;
@@ -38,8 +39,8 @@ public class PipeDataReceiver extends AbstractLoggingBean implements ChannelData
     private InputStream in;
     private OutputStream out;
 
-    public PipeDataReceiver(Window localWindow) {
-        ChannelPipedInputStream in = new ChannelPipedInputStream(localWindow);
+    public PipeDataReceiver(PropertyResolver resolver, Window localWindow) {
+        ChannelPipedInputStream in = new ChannelPipedInputStream(resolver, localWindow);
         this.in = in;
         this.out = new ChannelPipedOutputStream(in);
         if (log != null && log.isTraceEnabled()) {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java b/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java
index 29ba7f5..06b0211 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/forward/TcpipServerChannel.java
@@ -301,6 +301,7 @@ public class TcpipServerChannel extends AbstractServerChannel {
                 try {
                     localWindow.consumeAndCheck(len);
                 } catch (IOException e) {
+                    Session session = getSession();
                     session.exceptionCaught(e);
                 }
             }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHServerKeyExchange.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHServerKeyExchange.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHServerKeyExchange.java
index 29b8e10..03ccda6 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHServerKeyExchange.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/AbstractDHServerKeyExchange.java
@@ -25,27 +25,31 @@ import org.apache.sshd.common.kex.dh.AbstractDHKeyExchange;
 import org.apache.sshd.common.session.AbstractSession;
 import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.server.session.ServerSession;
+import org.apache.sshd.server.session.ServerSessionHolder;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
  */
-public abstract class AbstractDHServerKeyExchange extends AbstractDHKeyExchange {
-
-    protected ServerSession session;
+public abstract class AbstractDHServerKeyExchange extends AbstractDHKeyExchange implements ServerSessionHolder {
 
     protected AbstractDHServerKeyExchange() {
         super();
     }
 
     @Override
+    public ServerSession getServerSession() {
+        return (ServerSession) super.getSession();
+    }
+
+    @Override
     public void init(AbstractSession s, byte[] v_s, byte[] v_c, byte[] i_s, byte[] i_c) throws Exception {
         super.init(s, v_s, v_c, i_s, i_c);
         ValidateUtils.checkTrue(s instanceof ServerSession, "Using a server side KeyExchange on a client");
-        session = (ServerSession) s;
     }
 
     @Override
     public PublicKey getServerKey() {
+        ServerSession session = getServerSession();
         return ValidateUtils.checkNotNull(session.getHostKey(), "No server key pair available").getPublic();
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
index 49d8a93..87536a4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGEXServer.java
@@ -27,9 +27,10 @@ import java.security.KeyPair;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.apache.sshd.common.Factory;
 import org.apache.sshd.common.FactoryManager;
-import org.apache.sshd.common.FactoryManagerUtils;
 import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.SshException;
 import org.apache.sshd.common.kex.DHFactory;
@@ -48,6 +49,7 @@ import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.BufferUtils;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
 import org.apache.sshd.server.ServerFactoryManager;
+import org.apache.sshd.server.session.ServerSession;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -97,8 +99,9 @@ public class DHGEXServer extends AbstractDHServerKeyExchange {
     public boolean next(Buffer buffer) throws Exception {
         int cmd = buffer.getUByte();
 
+        ServerSession session = getServerSession();
         if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST_OLD && expected == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST) {
-            log.debug("Received SSH_MSG_KEX_DH_GEX_REQUEST_OLD");
+            log.debug("Received SSH_MSG_KEX_DH_GEX_REQUEST_OLD on {}", session);
             oldRequest = true;
             min = 1024;
             prf = buffer.getInt();
@@ -113,7 +116,7 @@ public class DHGEXServer extends AbstractDHServerKeyExchange {
             hash = dh.getHash();
             hash.init();
 
-            log.debug("Send SSH_MSG_KEX_DH_GEX_GROUP");
+            log.debug("Send SSH_MSG_KEX_DH_GEX_GROUP on {}", session);
             buffer = session.prepareBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_GROUP, BufferUtils.clear(buffer));
             buffer.putMPInt(dh.getP());
             buffer.putMPInt(dh.getG());
@@ -123,7 +126,7 @@ public class DHGEXServer extends AbstractDHServerKeyExchange {
             return false;
         }
         if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST && expected == SshConstants.SSH_MSG_KEX_DH_GEX_REQUEST) {
-            log.debug("Received SSH_MSG_KEX_DH_GEX_REQUEST");
+            log.debug("Received SSH_MSG_KEX_DH_GEX_REQUEST on {}", session);
             min = buffer.getInt();
             prf = buffer.getInt();
             max = buffer.getInt();
@@ -136,7 +139,7 @@ public class DHGEXServer extends AbstractDHServerKeyExchange {
             hash = dh.getHash();
             hash.init();
 
-            log.debug("Send SSH_MSG_KEX_DH_GEX_GROUP");
+            log.debug("Send SSH_MSG_KEX_DH_GEX_GROUP on {}", session);
             buffer = session.prepareBuffer(SshConstants.SSH_MSG_KEX_DH_GEX_GROUP, BufferUtils.clear(buffer));
             buffer.putMPInt(dh.getP());
             buffer.putMPInt(dh.getG());
@@ -151,7 +154,7 @@ public class DHGEXServer extends AbstractDHServerKeyExchange {
         }
 
         if (cmd == SshConstants.SSH_MSG_KEX_DH_GEX_INIT) {
-            log.debug("Received SSH_MSG_KEX_DH_GEX_INIT");
+            log.debug("Received SSH_MSG_KEX_DH_GEX_INIT on {}", session);
             e = buffer.getMPIntAsBytes();
             dh.setF(e);
             k = dh.getK();
@@ -199,14 +202,14 @@ public class DHGEXServer extends AbstractDHServerKeyExchange {
             buffer.putBytes(sig.sign());
             sigH = buffer.getCompactData();
 
-            if (log.isDebugEnabled()) {
-                log.debug("K_S:  {}", BufferUtils.printHex(k_s));
-                log.debug("f:    {}", BufferUtils.printHex(f));
-                log.debug("sigH: {}", BufferUtils.printHex(sigH));
+            if (log.isTraceEnabled()) {
+                log.trace("{}[K_S]:  {}", session, BufferUtils.printHex(k_s));
+                log.trace("{}[f]:    {}", session, BufferUtils.printHex(f));
+                log.trace("{}[sigH]: {}", session, BufferUtils.printHex(sigH));
             }
 
             // Send response
-            log.debug("Send SSH_MSG_KEX_DH_GEX_REPLY");
+            log.debug("Send SSH_MSG_KEX_DH_GEX_REPLY on {}", session);
             buffer.clear();
             buffer.rpos(5);
             buffer.wpos(5);
@@ -248,16 +251,22 @@ public class DHGEXServer extends AbstractDHServerKeyExchange {
             log.warn("No suitable primes found, defaulting to DHG1");
             return getDH(new BigInteger(DHGroupData.getP1()), new BigInteger(DHGroupData.getG()));
         }
-        Random random = session.getFactoryManager().getRandomFactory().create();
+
+        ServerSession session = getServerSession();
+        FactoryManager manager = ValidateUtils.checkNotNull(session.getFactoryManager(), "No factory manager");
+        Factory<Random> factory = ValidateUtils.checkNotNull(manager.getRandomFactory(), "No random factory");
+        Random random = factory.create();
         int which = random.random(selected.size());
         Moduli.DhGroup group = selected.get(which);
         return getDH(group.p, group.g);
     }
 
     protected List<Moduli.DhGroup> loadModuliGroups() throws IOException {
+        ServerSession session = getServerSession();
+        String moduliStr = PropertyResolverUtils.getString(session, ServerFactoryManager.MODULI_URL);
+
         List<Moduli.DhGroup> groups = null;
         URL moduli;
-        String moduliStr = FactoryManagerUtils.getString(session, ServerFactoryManager.MODULI_URL);
         if (!GenericUtils.isEmpty(moduliStr)) {
             try {
                 moduli = new URL(moduliStr);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/a9d975b6/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
index 29a807d..eaa8abb 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/kex/DHGServer.java
@@ -35,6 +35,7 @@ import org.apache.sshd.common.util.ValidateUtils;
 import org.apache.sshd.common.util.buffer.Buffer;
 import org.apache.sshd.common.util.buffer.BufferUtils;
 import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
+import org.apache.sshd.server.session.ServerSession;
 
 /**
  * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
@@ -85,12 +86,12 @@ public class DHGServer extends AbstractDHServerKeyExchange {
             throw new SshException(SshConstants.SSH2_DISCONNECT_KEY_EXCHANGE_FAILED,
                     "Protocol error: expected packet " + SshConstants.SSH_MSG_KEXDH_INIT + ", got " + cmd);
         }
-        log.debug("Received SSH_MSG_KEXDH_INIT");
+        ServerSession session = getServerSession();
+        log.debug("Received SSH_MSG_KEXDH_INIT on {}", session);
         e = buffer.getMPIntAsBytes();
         dh.setF(e);
         k = dh.getK();
 
-        byte[] k_s;
         KeyPair kp = ValidateUtils.checkNotNull(session.getHostKey(), "No server key pair available");
         String algo = session.getNegotiatedKexParameter(KexProposalOption.SERVERKEYS);
         FactoryManager manager = session.getFactoryManager();
@@ -102,7 +103,7 @@ public class DHGServer extends AbstractDHServerKeyExchange {
 
         buffer = new ByteArrayBuffer();
         buffer.putRawPublicKey(kp.getPublic());
-        k_s = buffer.getCompactData();
+        byte[] k_s = buffer.getCompactData();
 
         buffer.clear();
         buffer.putBytes(v_c);
@@ -123,14 +124,14 @@ public class DHGServer extends AbstractDHServerKeyExchange {
         buffer.putBytes(sig.sign());
         sigH = buffer.getCompactData();
 
-        if (log.isDebugEnabled()) {
-            log.debug("K_S:  {}", BufferUtils.printHex(k_s));
-            log.debug("f:    {}", BufferUtils.printHex(f));
-            log.debug("sigH: {}", BufferUtils.printHex(sigH));
+        if (log.isTraceEnabled()) {
+            log.trace("{}[K_S]:  {}", session, BufferUtils.printHex(k_s));
+            log.trace("{}[f]:    {}", session, BufferUtils.printHex(f));
+            log.trace("{}[sigH]: {}", session, BufferUtils.printHex(sigH));
         }
 
         // Send response
-        log.debug("Send SSH_MSG_KEXDH_REPLY");
+        log.debug("Send SSH_MSG_KEXDH_REPLY on {}", session);
         buffer.clear();
         buffer.rpos(5);
         buffer.wpos(5);