METRON-1515: Errors loading stellar functions currently bomb the entire topology, they should be recoverable closes apache/incubator-metron#985
Project: http://git-wip-us.apache.org/repos/asf/metron/repo Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/3fcbf8b4 Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/3fcbf8b4 Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/3fcbf8b4 Branch: refs/heads/feature/METRON-1090-stellar-assignment Commit: 3fcbf8b4e4e38f9c50842b8af857092b091c7c40 Parents: 1d3e7fc Author: cstella <ceste...@gmail.com> Authored: Mon Apr 16 15:12:11 2018 -0400 Committer: cstella <ceste...@gmail.com> Committed: Mon Apr 16 15:12:11 2018 -0400 ---------------------------------------------------------------------- .../resolver/ClasspathFunctionResolver.java | 45 +++++++++++++++----- .../resolver/ClasspathFunctionResolverTest.java | 30 +++++++++++++ 2 files changed, 65 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/metron/blob/3fcbf8b4/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/resolver/ClasspathFunctionResolver.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/resolver/ClasspathFunctionResolver.java b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/resolver/ClasspathFunctionResolver.java index 85aa015..b17233a 100644 --- a/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/resolver/ClasspathFunctionResolver.java +++ b/metron-stellar/stellar-common/src/main/java/org/apache/metron/stellar/dsl/functions/resolver/ClasspathFunctionResolver.java @@ -34,6 +34,7 @@ import org.apache.metron.stellar.dsl.Context; import org.apache.metron.stellar.dsl.Stellar; import org.apache.metron.stellar.dsl.StellarFunction; +import org.atteo.classindex.ClassFilter; import org.atteo.classindex.ClassIndex; import org.reflections.util.FilterBuilder; @@ -219,6 +220,17 @@ public class ClasspathFunctionResolver extends BaseFunctionResolver { } } + protected Iterable<Class<?>> getStellarClasses(ClassLoader cl) { + return ClassIndex.getAnnotated(Stellar.class, cl); + } + + protected boolean includeClass(Class<?> c, FilterBuilder filterBuilder) + { + boolean isAssignable = StellarFunction.class.isAssignableFrom(c); + boolean isFiltered = filterBuilder.apply(c.getCanonicalName()); + return isAssignable && isFiltered; + } + /** * Returns a set of classes that should undergo further interrogation for resolution * (aka discovery) of Stellar functions. @@ -254,16 +266,29 @@ public class ClasspathFunctionResolver extends BaseFunctionResolver { Set<String> classes = new HashSet<>(); Set<Class<? extends StellarFunction>> ret = new HashSet<>(); for(ClassLoader cl : cls) { - for(Class<?> c : ClassIndex.getAnnotated(Stellar.class, cl)) { - LOG.debug("{}: Found class: {}", cl.getClass().getCanonicalName(), c.getCanonicalName()); - boolean isAssignable = StellarFunction.class.isAssignableFrom(c); - boolean isFiltered = filterBuilder.apply(c.getCanonicalName()); - if( isAssignable && isFiltered ) { - String className = c.getName(); - if(!classes.contains(className)) { - LOG.debug("{}: Added class: {}", cl.getClass().getCanonicalName(), className); - ret.add((Class<? extends StellarFunction>) c); - classes.add(className); + for(Class<?> c : getStellarClasses(cl)) { + try { + LOG.debug("{}: Found class: {}", cl.getClass().getCanonicalName(), c.getCanonicalName()); + if (includeClass(c, filterBuilder)) { + String className = c.getName(); + if (!classes.contains(className)) { + LOG.debug("{}: Added class: {}", cl.getClass().getCanonicalName(), className); + ret.add((Class<? extends StellarFunction>) c); + classes.add(className); + } + } + } + catch(Error le) { + //we have had some error loading a stellar function. This could mean that + //the classpath is unstable (e.g. old copies of jars are on the classpath). + try { + LOG.error("Skipping class " + c.getName() + ": " + le.getMessage() + + ", please check that there are not old versions of stellar functions on the classpath.", le); + } + catch(Error ie) { + //it's possible that getName() will throw an exception if the class is VERY malformed. + LOG.error("Skipping class: " + le.getMessage() + + ", please check that there are not old versions of stellar functions on the classpath.", le); } } } http://git-wip-us.apache.org/repos/asf/metron/blob/3fcbf8b4/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/resolver/ClasspathFunctionResolverTest.java ---------------------------------------------------------------------- diff --git a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/resolver/ClasspathFunctionResolverTest.java b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/resolver/ClasspathFunctionResolverTest.java index 1d37f99..cc5bc7c 100644 --- a/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/resolver/ClasspathFunctionResolverTest.java +++ b/metron-stellar/stellar-common/src/test/java/org/apache/metron/stellar/dsl/functions/resolver/ClasspathFunctionResolverTest.java @@ -18,20 +18,27 @@ package org.apache.metron.stellar.dsl.functions.resolver; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import org.apache.commons.vfs2.FileSystemException; import org.apache.metron.stellar.dsl.Context; +import org.apache.metron.stellar.dsl.StellarFunction; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; +import org.reflections.util.FilterBuilder; import java.io.File; import java.util.HashSet; import java.util.List; import java.util.Properties; +import java.util.Set; import static org.apache.metron.stellar.dsl.functions.resolver.ClasspathFunctionResolver.Config.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class ClasspathFunctionResolverTest { @@ -121,4 +128,27 @@ public class ClasspathFunctionResolverTest { Assert.assertTrue(functions.contains("NOW")); } + @Test + public void testInvalidStellarClass() throws Exception { + StellarFunction goodFunc = mock(StellarFunction.class); + StellarFunction badFunc = mock(StellarFunction.class); + ClasspathFunctionResolver resolver = new ClasspathFunctionResolver() { + @Override + protected Iterable<Class<?>> getStellarClasses(ClassLoader cl) { + return ImmutableList.of(goodFunc.getClass(), badFunc.getClass()); + } + + @Override + protected boolean includeClass(Class<?> c, FilterBuilder filterBuilder) { + if(c != goodFunc.getClass()) { + throw new LinkageError("failed!"); + } + return true; + } + }; + Set<Class<? extends StellarFunction>> funcs = resolver.resolvables(); + Assert.assertEquals(1, funcs.size()); + Assert.assertEquals(goodFunc.getClass(), Iterables.getFirst(funcs, null)); + } + }