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/07/26 18:27:03 UTC
mina-sshd git commit: [SSHD-681] Provide default implementations for
ServerAuthenticationManager#getSetUserAuthFactories overloading with strings
Repository: mina-sshd
Updated Branches:
refs/heads/master 3c6b0540c -> d8e681de4
[SSHD-681] Provide default implementations for ServerAuthenticationManager#getSetUserAuthFactories overloading with strings
Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/d8e681de
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/d8e681de
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/d8e681de
Branch: refs/heads/master
Commit: d8e681de402070911d1c75bebe468d266345a33b
Parents: 3c6b054
Author: Lyor Goldstein <ly...@gmail.com>
Authored: Tue Jul 26 21:28:27 2016 +0300
Committer: Lyor Goldstein <ly...@gmail.com>
Committed: Tue Jul 26 21:28:27 2016 +0300
----------------------------------------------------------------------
.../server/ServerAuthenticationManager.java | 27 ++++
.../sshd/server/auth/AbstractUserAuth.java | 1 +
.../server/auth/BuiltinUserAuthFactories.java | 142 +++++++++++++++++++
.../client/ClientAuthenticationManagerTest.java | 2 +-
.../server/ServerAuthenticationManagerTest.java | 127 +++++++++++++++++
.../auth/BuiltinUserAuthFactoriesTest.java | 117 +++++++++++++++
6 files changed, 415 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d8e681de/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java b/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
index 4298aa9..0d8a6e8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
@@ -20,11 +20,16 @@
package org.apache.sshd.server;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.common.util.ValidateUtils;
+import org.apache.sshd.server.auth.BuiltinUserAuthFactories;
import org.apache.sshd.server.auth.UserAuth;
import org.apache.sshd.server.auth.gss.GSSAuthenticator;
import org.apache.sshd.server.auth.gss.UserAuthGSSFactory;
@@ -60,7 +65,29 @@ public interface ServerAuthenticationManager {
* @return a list of named <code>UserAuth</code> factories, never {@code null}/empty
*/
List<NamedFactory<UserAuth>> getUserAuthFactories();
+ default String getUserAuthFactoriesNameList() {
+ return NamedResource.Utils.getNames(getUserAuthFactories());
+ }
+ default List<String> getUserAuthFactoriesNames() {
+ return NamedResource.Utils.getNameList(getUserAuthFactories());
+ }
+
void setUserAuthFactories(List<NamedFactory<UserAuth>> userAuthFactories);
+ default void setUserAuthFactoriesNameList(String names) {
+ setUserAuthFactoriesNames(GenericUtils.split(names, ','));
+ }
+ default void setUserAuthFactoriesNames(String ... names) {
+ setUserAuthFactoriesNames(GenericUtils.isEmpty((Object[]) names) ? Collections.<String>emptyList() : Arrays.asList(names));
+ }
+ default void setUserAuthFactoriesNames(Collection<String> names) {
+ BuiltinUserAuthFactories.ParseResult result = BuiltinUserAuthFactories.parseFactoriesList(names);
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ List<NamedFactory<UserAuth>> factories =
+ (List) ValidateUtils.checkNotNullAndNotEmpty(result.getParsedFactories(), "No supported cipher factories: %s", names);
+ Collection<String> unsupported = result.getUnsupportedFactories();
+ ValidateUtils.checkTrue(GenericUtils.isEmpty(unsupported), "Unsupported cipher factories found: %s", unsupported);
+ setUserAuthFactories(factories);
+ }
/**
* Retrieve the <code>PublickeyAuthenticator</code> to be used by SSH server.
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d8e681de/sshd-core/src/main/java/org/apache/sshd/server/auth/AbstractUserAuth.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/AbstractUserAuth.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/AbstractUserAuth.java
index 578e1d1..7211b09 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/auth/AbstractUserAuth.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/AbstractUserAuth.java
@@ -24,6 +24,7 @@ import org.apache.sshd.common.util.logging.AbstractLoggingBean;
import org.apache.sshd.server.session.ServerSession;
/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
*/
public abstract class AbstractUserAuth extends AbstractLoggingBean implements UserAuth {
private final String name;
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d8e681de/sshd-core/src/main/java/org/apache/sshd/server/auth/BuiltinUserAuthFactories.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/auth/BuiltinUserAuthFactories.java b/sshd-core/src/main/java/org/apache/sshd/server/auth/BuiltinUserAuthFactories.java
new file mode 100644
index 0000000..05c395b
--- /dev/null
+++ b/sshd-core/src/main/java/org/apache/sshd/server/auth/BuiltinUserAuthFactories.java
@@ -0,0 +1,142 @@
+/*
+ * 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.server.auth;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import org.apache.sshd.common.Factory;
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.config.NamedFactoriesListParseResult;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.server.auth.gss.UserAuthGSSFactory;
+import org.apache.sshd.server.auth.hostbased.UserAuthHostBasedFactory;
+import org.apache.sshd.server.auth.keyboard.UserAuthKeyboardInteractiveFactory;
+import org.apache.sshd.server.auth.password.UserAuthPasswordFactory;
+import org.apache.sshd.server.auth.pubkey.UserAuthPublicKeyFactory;
+
+/**
+ * Provides a centralized location for the default built-in authentication factories
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+public enum BuiltinUserAuthFactories implements NamedFactory<UserAuthFactory> {
+ PASSWORD(UserAuthPasswordFactory.INSTANCE),
+ PUBLICKEY(UserAuthPublicKeyFactory.INSTANCE),
+ KBINTERACTIVE(UserAuthKeyboardInteractiveFactory.INSTANCE),
+ HOSTBASED(UserAuthHostBasedFactory.INSTANCE),
+ GSS(UserAuthGSSFactory.INSTANCE);
+
+ public static final Set<BuiltinUserAuthFactories> VALUES =
+ Collections.unmodifiableSet(EnumSet.allOf(BuiltinUserAuthFactories.class));
+
+ private final UserAuthFactory factory;
+
+ BuiltinUserAuthFactories(UserAuthFactory factory) {
+ this.factory = Objects.requireNonNull(factory, "No delegate factory instance");
+ }
+
+ @Override
+ public UserAuthFactory create() {
+ return factory;
+ }
+
+ @Override
+ public String getName() {
+ return factory.getName();
+ }
+
+ /**
+ * @param name The factory name (case <U>insensitive</U>) - ignored if {@code null}/empty
+ * @return The matching factory instance - {@code null} if no match found
+ */
+ public static UserAuthFactory fromFactoryName(String name) {
+ Factory<UserAuthFactory> factory = NamedResource.Utils.findByName(name, String.CASE_INSENSITIVE_ORDER, VALUES);
+ if (factory == null) {
+ return null;
+ }
+
+ return factory.create();
+ }
+
+ /**
+ * @param factories A comma-separated list of factories' names - ignored if {@code null}/empty
+ * @return A {@link ParseResult} containing the successfully parsed
+ * factories and the unknown ones. <B>Note:</B> it is up to caller to
+ * ensure that the lists do not contain duplicates
+ */
+ public static ParseResult parseFactoriesList(String factories) {
+ return parseFactoriesList(GenericUtils.split(factories, ','));
+ }
+
+ public static ParseResult parseFactoriesList(String... factories) {
+ return parseFactoriesList(GenericUtils.isEmpty((Object[]) factories) ? Collections.<String>emptyList() : Arrays.asList(factories));
+ }
+
+ public static ParseResult parseFactoriesList(Collection<String> factories) {
+ if (GenericUtils.isEmpty(factories)) {
+ return ParseResult.EMPTY;
+ }
+
+ List<UserAuthFactory> resolved = new ArrayList<>(factories.size());
+ List<String> unknown = Collections.emptyList();
+ for (String name : factories) {
+ UserAuthFactory c = resolveFactory(name);
+ if (c != null) {
+ resolved.add(c);
+ } else {
+ // replace the (unmodifiable) empty list with a real one
+ if (unknown.isEmpty()) {
+ unknown = new ArrayList<>();
+ }
+ unknown.add(name);
+ }
+ }
+
+ return new ParseResult(resolved, unknown);
+ }
+
+ public static UserAuthFactory resolveFactory(String name) {
+ if (GenericUtils.isEmpty(name)) {
+ return null;
+ }
+
+ return fromFactoryName(name);
+ }
+
+ /**
+ * Holds the result of {@link BuiltinUserAuthFactories#parseFactoriesList(String)}
+ *
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+ public static class ParseResult extends NamedFactoriesListParseResult<UserAuth, UserAuthFactory> {
+ public static final ParseResult EMPTY = new ParseResult(Collections.<UserAuthFactory>emptyList(), Collections.<String>emptyList());
+
+ public ParseResult(List<UserAuthFactory> parsed, List<String> unsupported) {
+ super(parsed, unsupported);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d8e681de/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java b/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
index 61dc4a2..0d08497 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/ClientAuthenticationManagerTest.java
@@ -68,7 +68,7 @@ public class ClientAuthenticationManagerTest extends BaseTestSupport {
@Test
public void testDefaultUserAuthFactoriesMethods() {
AtomicReference<List<NamedFactory<UserAuth>>> factoriesHolder = new AtomicReference<>();
- @SuppressWarnings({"checkstyle:anoninnerlength", "checkstyle:methodlength"})
+ @SuppressWarnings("checkstyle:anoninnerlength")
ClientAuthenticationManager manager = new ClientAuthenticationManager() {
@Override
public List<NamedFactory<UserAuth>> getUserAuthFactories() {
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d8e681de/sshd-core/src/test/java/org/apache/sshd/server/ServerAuthenticationManagerTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/ServerAuthenticationManagerTest.java b/sshd-core/src/test/java/org/apache/sshd/server/ServerAuthenticationManagerTest.java
new file mode 100644
index 0000000..75d49ae
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/server/ServerAuthenticationManagerTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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.server;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.sshd.common.NamedFactory;
+import org.apache.sshd.common.NamedResource;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.server.auth.BuiltinUserAuthFactories;
+import org.apache.sshd.server.auth.UserAuth;
+import org.apache.sshd.server.auth.gss.GSSAuthenticator;
+import org.apache.sshd.server.auth.hostbased.HostBasedAuthenticator;
+import org.apache.sshd.server.auth.keyboard.KeyboardInteractiveAuthenticator;
+import org.apache.sshd.server.auth.password.PasswordAuthenticator;
+import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
+import org.apache.sshd.util.test.BaseTestSupport;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runners.MethodSorters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+public class ServerAuthenticationManagerTest extends BaseTestSupport {
+ public ServerAuthenticationManagerTest() {
+ super();
+ }
+
+ @Test
+ public void testDefaultUserAuthFactoriesMethods() {
+ AtomicReference<List<NamedFactory<UserAuth>>> factoriesHolder = new AtomicReference<>();
+ @SuppressWarnings("checkstyle:anoninnerlength")
+ ServerAuthenticationManager manager = new ServerAuthenticationManager() {
+ @Override
+ public List<NamedFactory<UserAuth>> getUserAuthFactories() {
+ return factoriesHolder.get();
+ }
+
+ @Override
+ public void setUserAuthFactories(List<NamedFactory<UserAuth>> userAuthFactories) {
+ assertNull("Unexpected multiple invocation", factoriesHolder.getAndSet(userAuthFactories));
+ }
+
+ @Override
+ public PasswordAuthenticator getPasswordAuthenticator() {
+ return null;
+ }
+
+ @Override
+ public void setPasswordAuthenticator(PasswordAuthenticator passwordAuthenticator) {
+ throw new UnsupportedOperationException("setPasswordAuthenticator(" + passwordAuthenticator + ")");
+ }
+
+ @Override
+ public PublickeyAuthenticator getPublickeyAuthenticator() {
+ return null;
+ }
+
+ @Override
+ public void setPublickeyAuthenticator(PublickeyAuthenticator publickeyAuthenticator) {
+ throw new UnsupportedOperationException("setPublickeyAuthenticator(" + publickeyAuthenticator + ")");
+ }
+
+ @Override
+ public KeyboardInteractiveAuthenticator getKeyboardInteractiveAuthenticator() {
+ return null;
+ }
+
+ @Override
+ public void setKeyboardInteractiveAuthenticator(KeyboardInteractiveAuthenticator interactiveAuthenticator) {
+ throw new UnsupportedOperationException("setKeyboardInteractiveAuthenticator(" + interactiveAuthenticator + ")");
+ }
+
+ @Override
+ public GSSAuthenticator getGSSAuthenticator() {
+ return null;
+ }
+
+ @Override
+ public void setGSSAuthenticator(GSSAuthenticator gssAuthenticator) {
+ throw new UnsupportedOperationException("setGSSAuthenticator(" + gssAuthenticator + ")");
+ }
+
+ @Override
+ public HostBasedAuthenticator getHostBasedAuthenticator() {
+ return null;
+ }
+
+ @Override
+ public void setHostBasedAuthenticator(HostBasedAuthenticator hostBasedAuthenticator) {
+ throw new UnsupportedOperationException("setHostBasedAuthenticator(" + hostBasedAuthenticator + ")");
+ }
+ };
+ assertEquals("Mismatched initial factories list", "", manager.getUserAuthFactoriesNameList());
+
+ String expected = NamedResource.Utils.getNames(BuiltinUserAuthFactories.VALUES);
+ manager.setUserAuthFactoriesNameList(expected);
+ assertEquals("Mismatched updated factories names", expected, manager.getUserAuthFactoriesNameList());
+
+ List<NamedFactory<UserAuth>> factories = factoriesHolder.get();
+ assertEquals("Mismatched factories count", BuiltinUserAuthFactories.VALUES.size(), GenericUtils.size(factories));
+ for (BuiltinUserAuthFactories f : BuiltinUserAuthFactories.VALUES) {
+ assertTrue("Missing factory=" + f.name(), factories.contains(f.create()));
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/d8e681de/sshd-core/src/test/java/org/apache/sshd/server/auth/BuiltinUserAuthFactoriesTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/server/auth/BuiltinUserAuthFactoriesTest.java b/sshd-core/src/test/java/org/apache/sshd/server/auth/BuiltinUserAuthFactoriesTest.java
new file mode 100644
index 0000000..df6ed4c
--- /dev/null
+++ b/sshd-core/src/test/java/org/apache/sshd/server/auth/BuiltinUserAuthFactoriesTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.server.auth;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.TreeSet;
+
+import org.apache.sshd.common.auth.UserAuthMethodFactory;
+import org.apache.sshd.common.util.GenericUtils;
+import org.apache.sshd.server.auth.BuiltinUserAuthFactories.ParseResult;
+import org.apache.sshd.server.auth.gss.UserAuthGSSFactory;
+import org.apache.sshd.util.test.BaseTestSupport;
+import org.junit.BeforeClass;
+import org.junit.FixMethodOrder;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.MethodSorters;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/**
+ * @author <a href="mailto:dev@mina.apache.org">Apache MINA SSHD Project</a>
+ */
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@RunWith(Parameterized.class) // see https://github.com/junit-team/junit/wiki/Parameterized-tests
+public class BuiltinUserAuthFactoriesTest extends BaseTestSupport {
+ private final BuiltinUserAuthFactories factory;
+
+ public BuiltinUserAuthFactoriesTest(BuiltinUserAuthFactories factory) {
+ this.factory = factory;
+ }
+
+ @Parameters(name = "Factory={0}")
+ public static Collection<Object[]> parameters() {
+ return parameterize(BuiltinUserAuthFactories.VALUES);
+ }
+
+ @BeforeClass
+ public static void testAllConstantsCovered() throws Exception {
+ Field[] fields = UserAuthMethodFactory.class.getDeclaredFields();
+ Collection<String> factories = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
+
+ for (Field f : fields) {
+ if (f.getType() != String.class) {
+ continue;
+ }
+
+ int mods = f.getModifiers();
+ if ((!Modifier.isStatic(mods)) || (!Modifier.isFinal(mods)) || (!Modifier.isPublic(mods))) {
+ continue;
+ }
+
+ String name = Objects.toString(f.get(null), null);
+ UserAuthFactory factory = BuiltinUserAuthFactories.fromFactoryName(name);
+ if (factory == null) {
+ continue;
+ }
+
+ assertTrue("Duplicate factory name constant: " + name, factories.add(name));
+ }
+
+ assertTrue("Unexpected GSS name constant", factories.add(UserAuthGSSFactory.NAME));
+ assertEquals("Mismatched factories names count: " + factories, factories.size(), BuiltinUserAuthFactories.VALUES.size());
+ }
+
+ @Test
+ public void testSingletonFactoryInstance() {
+ UserAuthFactory expected = factory.create();
+ for (int index = 1; index <= Byte.SIZE; index++) {
+ assertSame("Mismatched factory instance at invocation #" + index, expected, factory.create());
+ }
+ }
+
+ @Test
+ public void testFromFactoryName() {
+ String name = factory.getName();
+ UserAuthFactory expected = factory.create();
+ for (int index = 1, count = name.length(); index <= count; index++) {
+ UserAuthFactory actual = BuiltinUserAuthFactories.fromFactoryName(name);
+ assertSame("Mismatched factory instance for name=" + name, expected, actual);
+ name = shuffleCase(name); // prepare for next iteration
+ }
+ }
+
+ @Test
+ public void testParseResult() {
+ ParseResult result = BuiltinUserAuthFactories.parseFactoriesList(factory.getName());
+ assertNotNull("No parse result", result);
+
+ List<UserAuthFactory> parsed = result.getParsedFactories();
+ assertEquals("Mismatched parsed count", 1, GenericUtils.size(parsed));
+ assertSame("Mismatched parsed factory instance", factory.create(), parsed.get(0));
+
+ Collection<String> unsupported = result.getUnsupportedFactories();
+ assertTrue("Unexpected unsupported values: " + unsupported, GenericUtils.isEmpty(unsupported));
+ }
+}