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 2016/02/18 15:31:06 UTC
mina-sshd git commit: [SSHD-647] Use system properties as fallback
PropertyResolver
Repository: mina-sshd
Updated Branches:
refs/heads/master 7e24f2e1b -> e70fb3d11
[SSHD-647] Use system properties as fallback PropertyResolver
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/e70fb3d1
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/e70fb3d1
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/e70fb3d1
Branch: refs/heads/master
Commit: e70fb3d11521d5776c6eb6d76e045c8d35228368
Parents: 7e24f2e
Author: Lyor Goldstein <ly...@gmail.com>
Authored: Thu Feb 18 16:31:42 2016 +0200
Committer: Lyor Goldstein <ly...@gmail.com>
Committed: Thu Feb 18 16:31:42 2016 +0200
----------------------------------------------------------------------
.../sshd/common/AbstractFactoryManager.java | 7 +-
.../apache/sshd/common/PropertyResolver.java | 57 +++--
.../sshd/common/PropertyResolverUtils.java | 2 +-
.../apache/sshd/common/SyspropsMapWrapper.java | 221 +++++++++++++++++++
.../apache/sshd/common/util/GenericUtils.java | 4 +-
.../java/org/apache/sshd/common/util/Pair.java | 43 +++-
.../sshd/common/PropertyResolverUtilsTest.java | 39 ++++
7 files changed, 352 insertions(+), 21 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e70fb3d1/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java b/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
index ffb3883..58bb9c2 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/AbstractFactoryManager.java
@@ -75,6 +75,7 @@ public abstract class AbstractFactoryManager extends AbstractKexFactoryManager i
protected final ChannelListener channelListenerProxy;
private final Map<String, Object> properties = new ConcurrentHashMap<>();
+ private PropertyResolver parentResolver = SyspropsMapWrapper.SYSPROPS_RESOLVER;
protected AbstractFactoryManager() {
ClassLoader loader = getClass().getClassLoader();
@@ -116,7 +117,11 @@ public abstract class AbstractFactoryManager extends AbstractKexFactoryManager i
@Override
public PropertyResolver getParentPropertyResolver() {
- return null;
+ return parentResolver;
+ }
+
+ public void setParentPropertyResolver(PropertyResolver parent) {
+ parentResolver = parent;
}
@Override
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e70fb3d1/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolver.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolver.java b/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolver.java
index 574a294..c3adff4 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolver.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolver.java
@@ -19,6 +19,7 @@
package org.apache.sshd.common;
+import java.util.Collections;
import java.util.Map;
/**
@@ -28,36 +29,60 @@ import java.util.Map;
* to a numeric or {@code boolean} value, or from {@code int} to {@code long},
* etc.. <B>Note:</B> implementations may decide to use case <U>insensitive</U>
* property names, therefore it is <U><B>highly discouraged</B></U> to use names
- * that differ from each other only in case sensitivity. Also, implementations may
- * choose to trim whitespaces, thus such are also highly discouraged.
+ * that differ from each other only in case sensitivity. Also, implementations
+ * may choose to trim whitespaces, thus such are also highly discouraged.
*
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public interface PropertyResolver {
/**
+ * An "empty" resolver with no properties and no parent
+ */
+ PropertyResolver EMPTY = new PropertyResolver() {
+ @Override
+ public PropertyResolver getParentPropertyResolver() {
+ return null;
+ }
+
+ @Override
+ public Map<String, Object> getProperties() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public String toString() {
+ return "EMPTY";
+ }
+ };
+
+ /**
* @return The parent resolver that can be used to query for missing
- * properties - {@code null} if no parent
+ * properties - {@code null} if no parent
*/
PropertyResolver getParentPropertyResolver();
/**
- * <P>A map of properties that can be used to configure the SSH server
- * or client. This map will never be changed by either the server or
- * client and is not supposed to be changed at runtime (changes are not
- * bound to have any effect on a running client or server), though it may
- * affect the creation of sessions later as these values are usually not
- * cached.</P>
+ * <P>
+ * A map of properties that can be used to configure the SSH server or
+ * client. This map will never be changed by either the server or client and
+ * is not supposed to be changed at runtime (changes are not bound to have
+ * any effect on a running client or server), though it may affect the
+ * creation of sessions later as these values are usually not cached.
+ * </P>
*
- * <P><B>Note:</B> the <U>type</U> of the mapped property should match the
+ * <P>
+ * <B>Note:</B> the <U>type</U> of the mapped property should match the
* expected configuration value type - {@code Long, Integer, Boolean,
* String}, etc.... If it doesn't, the {@code toString()} result of the
- * mapped value is used to convert it to the required type. E.g., if
- * the mapped value is the <U>string</U> "1234" and the expected
- * value is a {@code long} then it will be parsed into one. Also, if
- * the mapped value is an {@code Integer} but a {@code long} is expected,
- * then it will be converted into one.</P>
+ * mapped value is used to convert it to the required type. E.g., if the
+ * mapped value is the <U>string</U> "1234" and the expected value
+ * is a {@code long} then it will be parsed into one. Also, if the mapped
+ * value is an {@code Integer} but a {@code long} is expected, then it will
+ * be converted into one.
+ * </P>
*
- * @return a valid <code>Map</code> containing configuration values, never {@code null}
+ * @return a valid <code>Map</code> containing configuration values, never
+ * {@code null}
*/
Map<String, Object> getProperties();
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e70fb3d1/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
index 4760a48..903a796 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
@@ -21,6 +21,7 @@ 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;
@@ -28,7 +29,6 @@ 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");
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e70fb3d1/sshd-core/src/main/java/org/apache/sshd/common/SyspropsMapWrapper.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/SyspropsMapWrapper.java b/sshd-core/src/main/java/org/apache/sshd/common/SyspropsMapWrapper.java
new file mode 100644
index 0000000..698e6e2
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/common/SyspropsMapWrapper.java
@@ -0,0 +1,221 @@
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.Pair;
+
+/**
+ * A wrapper that exposes a read-only {@link Map} access to the system
+ * properties. Any attempt to modify it will throw {@link UnsupportedOperationException}.
+ * The mapper uses the {@link #SYSPROPS_MAPPED_PREFIX} to filter and access'
+ * only these properties, ignoring all others
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public final class SyspropsMapWrapper implements Map<String, Object> {
+ /**
+ * Prefix of properties used by the mapper to identify SSHD related settings
+ */
+ public static final String SYSPROPS_MAPPED_PREFIX = "org.apache.sshd.config";
+
+ /**
+ * The one and only wrapper instance
+ */
+ public static final SyspropsMapWrapper INSTANCE = new SyspropsMapWrapper();
+
+ /**
+ * A {@link PropertyResolver} with no parent that exposes the system properties
+ */
+ public static final PropertyResolver SYSPROPS_RESOLVER = new PropertyResolver() {
+ @Override
+ public Map<String, Object> getProperties() {
+ return SyspropsMapWrapper.INSTANCE;
+ }
+
+ @Override
+ public PropertyResolver getParentPropertyResolver() {
+ return null;
+ }
+
+ @Override
+ public String toString() {
+ return "SYSPROPS";
+ }
+ };
+
+ private SyspropsMapWrapper() {
+ super();
+ }
+
+ @Override
+ public void clear() {
+ throw new UnsupportedOperationException("sysprops#clear() N/A");
+ }
+
+ @Override
+ public boolean containsKey(Object key) {
+ return get(key) != null;
+ }
+
+ @Override
+ public boolean containsValue(Object value) {
+ // not the most efficient implementation, but we do not expect it to be called much
+ Properties props = System.getProperties();
+ for (String key : props.stringPropertyNames()) {
+ if (!isMappedSyspropKey(key)) {
+ continue;
+ }
+
+ Object v = props.getProperty(key);
+ if (Objects.equals(v, value)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public Set<Entry<String, Object>> entrySet() {
+ Properties props = System.getProperties();
+ // return a copy in order to avoid concurrent modifications
+ Set<Entry<String, Object>> entries =
+ new TreeSet<Entry<String, Object>>(Pair.<String, Object>byKeyEntryComparator());
+ for (String key : props.stringPropertyNames()) {
+ if (!isMappedSyspropKey(key)) {
+ continue;
+ }
+
+ Object v = props.getProperty(key);
+ if (v != null) {
+ entries.add(new Pair<>(getUnmappedSyspropKey(key), v));
+ }
+ }
+
+ return entries;
+ }
+
+ @Override
+ public Object get(Object key) {
+ return (key instanceof String) ? System.getProperty(getMappedSyspropKey(key)) : null;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return GenericUtils.isEmpty(keySet());
+ }
+
+ @Override
+ public Set<String> keySet() {
+ Properties props = System.getProperties();
+ Set<String> keys = new TreeSet<>();
+ // filter out any non-SSHD properties
+ for (String key : props.stringPropertyNames()) {
+ if (isMappedSyspropKey(key)) {
+ keys.add(getUnmappedSyspropKey(key));
+ }
+ }
+
+ return keys;
+ }
+
+ @Override
+ public Object put(String key, Object value) {
+ throw new UnsupportedOperationException("sysprops#put(" + key + ")[" + value + "] N/A");
+ }
+
+ @Override
+ public void putAll(Map<? extends String, ? extends Object> m) {
+ throw new UnsupportedOperationException("sysprops#putAll(" + m + ") N/A");
+ }
+
+ @Override
+ public Object remove(Object key) {
+ throw new UnsupportedOperationException("sysprops#remove(" + key + ") N/A");
+ }
+
+ @Override
+ public int size() {
+ return GenericUtils.size(keySet());
+ }
+
+ @Override
+ public Collection<Object> values() {
+ Properties props = System.getProperties();
+ // return a copy in order to avoid concurrent modifications
+ List<Object> values = new ArrayList<>(props.size());
+ for (String key : props.stringPropertyNames()) {
+ if (!isMappedSyspropKey(key)) {
+ continue;
+ }
+ Object v = props.getProperty(key);
+ if (v != null) {
+ values.add(v);
+ }
+ }
+
+ return values;
+ }
+
+ @Override
+ public String toString() {
+ return Objects.toString(System.getProperties(), null);
+ }
+
+ /**
+ * @param key Key to be tested
+ * @return {@code true} if key starts with {@link #SYSPROPS_MAPPED_PREFIX}
+ * and continues with a dot followed by some characters
+ */
+ public static boolean isMappedSyspropKey(String key) {
+ return (GenericUtils.length(key) > (SYSPROPS_MAPPED_PREFIX.length() + 1))
+ && key.startsWith(SYSPROPS_MAPPED_PREFIX)
+ && (key.charAt(SYSPROPS_MAPPED_PREFIX.length()) == '.');
+ }
+
+ /**
+ * @param key Key to be transformed
+ * @return The "pure" key name if a mapped one, same as input otherwise
+ * @see #isMappedSyspropKey(String)
+ */
+ public static String getUnmappedSyspropKey(Object key) {
+ String s = Objects.toString(key);
+ return isMappedSyspropKey(s) ? s.substring(SYSPROPS_MAPPED_PREFIX.length() + 1 /* skip dot */) : s;
+ }
+
+ /**
+ * @param key The original key
+ * @return A key prefixed by {@link #SYSPROPS_MAPPED_PREFIX}
+ * @see #isMappedSyspropKey(String)
+ */
+ public static String getMappedSyspropKey(Object key) {
+ return SYSPROPS_MAPPED_PREFIX + "." + key;
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e70fb3d1/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
index a07ccdc..01743ff 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/GenericUtils.java
@@ -222,7 +222,7 @@ public final class GenericUtils {
}
public static boolean isEmpty(Collection<?> c) {
- return size(c) <= 0;
+ return (c == null) || c.isEmpty();
}
public static int size(Map<?, ?> m) {
@@ -230,7 +230,7 @@ public final class GenericUtils {
}
public static boolean isEmpty(Map<?, ?> m) {
- return size(m) <= 0;
+ return (m == null) || m.isEmpty();
}
@SafeVarargs
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e70fb3d1/sshd-core/src/main/java/org/apache/sshd/common/util/Pair.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/common/util/Pair.java b/sshd-core/src/main/java/org/apache/sshd/common/util/Pair.java
index 0d34fd2..8a9bbd8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/util/Pair.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/util/Pair.java
@@ -18,6 +18,9 @@
*/
package org.apache.sshd.common.util;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
/**
@@ -27,7 +30,19 @@ import java.util.Objects;
* @param <S> Second value type
* @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
-public class Pair<F, S> {
+public class Pair<F, S> implements Map.Entry<F, S> {
+ @SuppressWarnings("rawtypes")
+ private static final Comparator<Map.Entry<Comparable, ?>> BY_KEY_COMPARATOR =
+ new Comparator<Map.Entry<Comparable, ?>>() {
+ @SuppressWarnings("unchecked")
+ @Override
+ public int compare(Entry<Comparable, ?> o1, Entry<Comparable, ?> o2) {
+ Comparable k1 = o1.getKey();
+ Comparable k2 = o2.getKey();
+ return k1.compareTo(k2);
+ }
+ };
+
private final F first;
private final S second;
@@ -36,6 +51,21 @@ public class Pair<F, S> {
this.second = second;
}
+ @Override
+ public final F getKey() {
+ return getFirst();
+ }
+
+ @Override
+ public S getValue() {
+ return getSecond();
+ }
+
+ @Override
+ public S setValue(S value) {
+ throw new UnsupportedOperationException("setValue(" + value + ") N/A");
+ }
+
public final F getFirst() {
return first;
}
@@ -71,4 +101,15 @@ public class Pair<F, S> {
public String toString() {
return Objects.toString(getFirst()) + ", " + Objects.toString(getSecond());
}
+
+ /**
+ * @param <K> The {@link Comparable} key type
+ * @param <V> The associated entry value
+ * @return A {@link Comparator} for {@link java.util.Map.Entry}-ies that
+ * compares the key values
+ */
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public static <K extends Comparable<K>, V> Comparator<Map.Entry<K, V>> byKeyEntryComparator() {
+ return (Comparator) BY_KEY_COMPARATOR;
+ }
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/e70fb3d1/sshd-core/src/test/java/org/apache/sshd/common/PropertyResolverUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/common/PropertyResolverUtilsTest.java b/sshd-core/src/test/java/org/apache/sshd/common/PropertyResolverUtilsTest.java
index 9e90173..303bdbc 100644
--- a/sshd-core/src/test/java/org/apache/sshd/common/PropertyResolverUtilsTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/common/PropertyResolverUtilsTest.java
@@ -23,6 +23,7 @@ import java.util.Map;
import java.util.TreeMap;
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.util.test.BaseTestSupport;
import org.junit.FixMethodOrder;
@@ -54,6 +55,44 @@ public class PropertyResolverUtilsTest extends BaseTestSupport {
}
@Test
+ public void testSyspropsResolver() {
+ PropertyResolver resolver = SyspropsMapWrapper.SYSPROPS_RESOLVER;
+ Map<String, ?> props = resolver.getProperties();
+ assertTrue("Unexpected initial resolver values: " + props, GenericUtils.isEmpty(props));
+
+ final String NAME = getCurrentTestName();
+ assertNull("Unexpected initial resolved value", PropertyResolverUtils.getObject(resolver, NAME));
+
+ final String PROPKEY = SyspropsMapWrapper.getMappedSyspropKey(NAME);
+ assertNull("Unexpected property value for " + PROPKEY, System.getProperty(PROPKEY));
+
+ try {
+ long expected = System.currentTimeMillis();
+ System.setProperty(PROPKEY, Long.toString(expected));
+ testLongProperty(resolver, NAME, expected);
+ } finally {
+ System.clearProperty(PROPKEY);
+ }
+
+ try {
+ int expected = 3777347;
+ System.setProperty(PROPKEY, Integer.toString(expected));
+ testIntegerProperty(resolver, NAME, expected);
+ } finally {
+ System.clearProperty(PROPKEY);
+ }
+
+ for (final boolean expected : new boolean[]{false, true}) {
+ try {
+ System.setProperty(PROPKEY, Boolean.toString(expected));
+ testBooleanProperty(resolver, NAME, expected);
+ } finally {
+ System.clearProperty(PROPKEY);
+ }
+ }
+ }
+
+ @Test
public void testLongProperty() {
final long expected = System.currentTimeMillis();
final String name = getCurrentTestName();