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 2018/11/07 18:01:08 UTC
[5/5] mina-sshd git commit: [SSHD-860] Using lazy iterator in
AuthenticationIdentitiesProvider#wrap
[SSHD-860] Using lazy iterator in AuthenticationIdentitiesProvider#wrap
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/044a1ca8
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/044a1ca8
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/044a1ca8
Branch: refs/heads/master
Commit: 044a1ca8dbdbfdd386108a571d5c130b53e4432b
Parents: 99dd4aa
Author: Lyor Goldstein <lg...@apache.org>
Authored: Wed Nov 7 07:50:11 2018 +0200
Committer: Lyor Goldstein <lg...@apache.org>
Committed: Wed Nov 7 20:06:39 2018 +0200
----------------------------------------------------------------------
.../auth/AuthenticationIdentitiesProvider.java | 31 +----
.../apache/sshd/common/util/GenericUtils.java | 116 ++++++++++++++++++-
.../sshd/common/util/GenericUtilsTest.java | 57 +++++++++
3 files changed, 175 insertions(+), 29 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/044a1ca8/sshd-common/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java b/sshd-common/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java
index cfd1f85..3fa61ba 100644
--- a/sshd-common/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java
+++ b/sshd-common/src/main/java/org/apache/sshd/client/auth/AuthenticationIdentitiesProvider.java
@@ -20,11 +20,7 @@
package org.apache.sshd.client.auth;
import java.security.KeyPair;
-import java.util.Collection;
-import java.util.Collections;
import java.util.Comparator;
-import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import org.apache.sshd.client.auth.password.PasswordIdentityProvider;
@@ -87,38 +83,17 @@ public interface AuthenticationIdentitiesProvider extends KeyIdentityProvider, P
return new AuthenticationIdentitiesProvider() {
@Override
public Iterable<KeyPair> loadKeys() {
- return selectIdentities(KeyPair.class);
+ return GenericUtils.lazySelectMatchingTypes(identities, KeyPair.class);
}
@Override
public Iterable<String> loadPasswords() {
- return selectIdentities(String.class);
+ return GenericUtils.lazySelectMatchingTypes(identities, String.class);
}
@Override
public Iterable<?> loadIdentities() {
- return selectIdentities(Object.class);
- }
-
- // NOTE: returns a NEW Collection on every call so that the original
- // identities remain unchanged
- private <T> Collection<T> selectIdentities(Class<T> type) {
- Collection<T> matches = null;
- for (Iterator<?> iter = GenericUtils.iteratorOf(identities); iter.hasNext();) {
- Object o = iter.next();
- Class<?> t = o.getClass();
- if (!type.isAssignableFrom(t)) {
- continue;
- }
-
- if (matches == null) {
- matches = new LinkedList<>();
- }
-
- matches.add(type.cast(o));
- }
-
- return (matches == null) ? Collections.<T>emptyList() : matches;
+ return GenericUtils.lazySelectMatchingTypes(identities, Object.class);
}
};
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/044a1ca8/sshd-common/src/main/java/org/apache/sshd/common/util/GenericUtils.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/main/java/org/apache/sshd/common/util/GenericUtils.java b/sshd-common/src/main/java/org/apache/sshd/common/util/GenericUtils.java
index c924d1e..52cf171 100644
--- a/sshd-common/src/main/java/org/apache/sshd/common/util/GenericUtils.java
+++ b/sshd-common/src/main/java/org/apache/sshd/common/util/GenericUtils.java
@@ -36,6 +36,7 @@ import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
+import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
@@ -867,6 +868,118 @@ public final class GenericUtils {
}
/**
+ * @param <T> Generic selected identities type
+ * @param The source values - ignored if {@code null}
+ * @param type The (never @code null) type of values to select - any value
+ * whose type is assignable to this type will be selected by the iterator.
+ * @return {@link Iterable} whose {@link Iterator} selects only values
+ * matching the specific type. <b>Note:</b> the matching values are not
+ * pre-calculated (hence the "lazy" denomination) - i.e.,
+ * the match is performed only when {@link Iterator#hasNext()} is called.
+ */
+ public static <T> Iterable<T> lazySelectMatchingTypes(Iterable<?> values, Class<T> type) {
+ Objects.requireNonNull(type, "No type selector specified");
+ if (values == null) {
+ return Collections.emptyList();
+ }
+
+ return new Iterable<T>() {
+ @Override
+ public Iterator<T> iterator() {
+ return lazySelectMatchingTypes(values.iterator(), type);
+ }
+
+ @Override
+ public String toString() {
+ return Iterable.class.getSimpleName() + "[lazy-select](" + type.getSimpleName() + ")";
+ }
+ };
+ }
+
+ /**
+ * @param <T> Generic selected identities type
+ * @param The source values - ignored if {@code null}
+ * @param type The (never @code null) type of values to select - any value
+ * whose type is assignable to this type will be selected by the iterator.
+ * @return An {@link Iterator} whose {@code next()} call selects only values
+ * matching the specific type. <b>Note:</b> the matching values are not
+ * pre-calculated (hence the "lazy" denomination) - i.e.,
+ * the match is performed only when {@link Iterator#hasNext()} is called.
+ */
+ public static <T> Iterator<T> lazySelectMatchingTypes(Iterator<?> values, Class<T> type) {
+ Objects.requireNonNull(type, "No type selector specified");
+ if (values == null) {
+ return Collections.emptyIterator();
+ }
+
+ return new Iterator<T>() {
+ private boolean finished;
+ private T nextValue;
+
+ @Override
+ public boolean hasNext() {
+ if (finished) {
+ return false;
+ }
+
+ nextValue = selectNextMatchingValue(values, type);
+ if (nextValue == null) {
+ finished = true;
+ }
+
+ return !finished;
+ }
+
+ @Override
+ public T next() {
+ if (finished) {
+ throw new NoSuchElementException("All values have been exhausted");
+ }
+ if (nextValue == null) {
+ throw new IllegalStateException("'next()' called without asking 'hasNext()'");
+ }
+
+ T v = nextValue;
+ nextValue = null; // so it will be re-fetched when 'hasNext' is called
+ return v;
+ }
+
+ @Override
+ public String toString() {
+ return Iterator.class.getSimpleName() + "[lazy-select](" + type.getSimpleName() + ")";
+ }
+ };
+ }
+
+ /**
+ * @param <T> Generic return type
+ * @param The source values - ignored if {@code null}
+ * @param type The (never @code null) type of values to select - any value
+ * whose type is assignable to this type will be selected by the iterator.
+ * @return The first value that matches the specified type - {@code null} if none found
+ */
+ public static <T> T selectNextMatchingValue(Iterator<?> values, Class<T> type) {
+ Objects.requireNonNull(type, "No type selector specified");
+ if (values == null) {
+ return null;
+ }
+
+ while (values.hasNext()) {
+ Object o = values.next();
+ if (o == null) {
+ continue;
+ }
+
+ Class<?> t = o.getClass();
+ if (type.isAssignableFrom(t)) {
+ return type.cast(o);
+ }
+ }
+
+ return null;
+ }
+
+ /**
* Wraps a group of {@link Supplier}s of {@link Iterable} instances into a "unified"
* {@link Iterable} of their values, in the same order as the suppliers - i.e., once the values
* from a specific supplier are exhausted, the next one is consulted, and so on, until all
@@ -876,7 +989,8 @@ public final class GenericUtils {
* @param providers The providers - ignored if {@code null} (i.e., return an empty iterable instance)
* @return The wrapping instance
*/
- public static <T> Iterable<T> multiIterableSuppliers(Iterable<? extends Supplier<? extends Iterable<? extends T>>> providers) {
+ public static <T> Iterable<T> multiIterableSuppliers(
+ Iterable<? extends Supplier<? extends Iterable<? extends T>>> providers) {
return () -> stream(providers).<T>flatMap(s -> stream(s.get())).map(Function.identity()).iterator();
}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/044a1ca8/sshd-common/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java
----------------------------------------------------------------------
diff --git a/sshd-common/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java b/sshd-common/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java
index 2b25f4a..8470385 100644
--- a/sshd-common/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java
+++ b/sshd-common/src/test/java/org/apache/sshd/common/util/GenericUtilsTest.java
@@ -19,10 +19,21 @@
package org.apache.sshd.common.util;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.temporal.Temporal;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import org.apache.sshd.util.test.JUnitTestSupport;
import org.apache.sshd.util.test.NoIoTestCase;
@@ -173,4 +184,50 @@ public class GenericUtilsTest extends JUnitTestSupport {
assertEquals("s1 vs. s2", Integer.signum(s1.compareTo(s2)), Integer.signum(GenericUtils.compare(c1, c2)));
assertEquals("s2 vs. s1", Integer.signum(s2.compareTo(s1)), Integer.signum(GenericUtils.compare(c2, c1)));
}
+
+ @Test
+ public void testLazySelectMatchingTypes() {
+ Collection<String> strings = Arrays.asList(
+ getCurrentTestName(),
+ getClass().getSimpleName(),
+ getClass().getPackage().getName());
+ Collection<Temporal> times = Arrays.asList(
+ LocalDateTime.now(),
+ LocalTime.now(),
+ LocalDate.now());
+ List<Object> values = Stream.concat(strings.stream(), times.stream()).collect(Collectors.toList());
+ AtomicInteger matchCount = new AtomicInteger(0);
+ for (int index = 1, count = values.size(); index <= count; index++) {
+ Collections.shuffle(values);
+ Class<?> type = ((index & 0x01) == 0) ? String.class : Temporal.class;
+ Iterator<?> lazy = GenericUtils.lazySelectMatchingTypes(
+ new Iterator<Object>() {
+ private final Iterator<?> iter = values.iterator();
+
+ {
+ matchCount.set(0);
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iter.hasNext();
+ }
+
+ @Override
+ public Object next() {
+ Object v = iter.next();
+ if (type.isInstance(v)) {
+ matchCount.incrementAndGet();
+ }
+ return v;
+ }
+ }, type);
+ Set<?> expected = (type == String.class) ? new HashSet<>(strings) : new HashSet<>(times);
+ for (int c = 1; lazy.hasNext(); c++) {
+ Object o = lazy.next();
+ assertEquals("Mismatched match count for " + o, c, matchCount.get());
+ assertTrue("Unexpected value: " + o, expected.remove(o));
+ }
+ }
+ }
}