This is an automated email from the ASF dual-hosted git repository. ctubbsii pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/main by this push: new 68acf9f Fix warnings leftover from VFS deprecation (#1804) 68acf9f is described below commit 68acf9f101efeaf3a612b39e898a3a58090470fa Author: Christopher Tubbs <ctubb...@apache.org> AuthorDate: Thu Nov 26 14:17:23 2020 -0500 Fix warnings leftover from VFS deprecation (#1804) * Fix warnings leftover from VFS deprecation This addresses warnings introduced recently and generally improves the overall context class loader feature and related code. Fixing warnings: * Deprecate some classes that exist only to support deprecated code * Reduce references to deprecated classes by putting them behind more utility methods (especially in ClassLoaderUtil) * Remove references to deprecated classes in javadoc `@see` tags * Remove unused variables * Remove Deprecated annotation when it would propagate and create too many warnings for internal classes that aren't user-facing and don't need to advertise their deprecation status * Suppress unavoidable compiler warnings due to deprecations * Prevent new compiler warnings from being introduced, by adding a flag for the compiler plugin to fail the build on warnings. Since we keep untriaged (unsuppressed) warnings at `0`, this should not cause a problem for most builds, but can be suppressed during development with `-Dmaven.compiler.failOnWarning=false`. Other improvements: * Deprecate old table.classpath.context in favor of new table.class.loader.context, and update Property docs * Update ContextClassLoaderFactory javadocs and remove declared RuntimeExceptions from interface definition * Consolidate ContextClassLoaders and ClassLoaderUtil utility classes * Rename LegacyVFSContextClassLoaderFactory to DefaultContextClassLoaderFactory * Use more functional and streams, wherever possible, and use generics where previously rawtypes or excessive casting was used * Remove unneeded initialize method from factory interface * Push down IOException handling into utility methods in AccumuloVFSClassLoader that were previously propagated and handled outside the class to simplify calling code * Fix tests Add implementation for isPropertySet in ConfigurationCopy, because it is used for per-table context lookup in some test code paths. * Add deprecated annotation to a few missed classes --- .../accumulo/core/classloader/ClassLoaderUtil.java | 81 +++++++++++++++++-- .../core/classloader/ContextClassLoaders.java | 88 -------------------- .../DefaultContextClassLoaderFactory.java | 82 +++++++++++++++++++ .../LegacyVFSContextClassLoaderFactory.java | 94 ---------------------- .../accumulo/core/conf/ConfigurationCopy.java | 5 ++ .../apache/accumulo/core/conf/IterConfigUtil.java | 2 +- .../org/apache/accumulo/core/conf/Property.java | 42 ++++++---- .../apache/accumulo/core/conf/PropertyType.java | 1 + .../accumulo/core/file/BloomFilterLayer.java | 4 +- .../cache/impl/BlockCacheManagerFactory.java | 2 +- .../core/iterators/TypedValueCombiner.java | 4 +- .../accumulo/core/sample/impl/SamplerFactory.java | 3 +- .../core/spi/common/ContextClassLoaderFactory.java | 55 +++++++------ .../accumulo/core/summary/SummarizerFactory.java | 3 +- .../classloader/ContextClassLoaderFactoryTest.java | 14 ++-- .../core/classloader/URLClassLoaderFactory.java | 20 ++--- .../core/conf/AccumuloConfigurationTest.java | 21 ++--- .../apache/accumulo/core/crypto/CryptoTest.java | 2 +- .../minicluster/MiniAccumuloClusterTest.java | 12 ++- pom.xml | 2 + .../org/apache/accumulo/server/AbstractServer.java | 2 + .../accumulo/server/ServiceEnvironmentImpl.java | 4 +- .../server/client/ClientServiceHandler.java | 9 +-- .../accumulo/server/conf/TableConfiguration.java | 4 +- .../server/master/balancer/TableLoadBalancer.java | 2 +- .../accumulo/server/util/LoginProperties.java | 8 +- .../server/master/balancer/GroupBalancerTest.java | 3 - .../master/balancer/TableLoadBalancerTest.java | 6 +- .../java/org/apache/accumulo/master/Master.java | 11 --- .../org/apache/accumulo/tracer/TraceServer.java | 17 ++-- .../org/apache/accumulo/tserver/TabletServer.java | 7 -- .../tserver/constraints/ConstraintChecker.java | 2 +- .../accumulo/tserver/tablet/CompactableUtils.java | 3 +- .../main/java/org/apache/accumulo/shell/Shell.java | 63 +++++++++------ .../accumulo/shell/commands/ClasspathCommand.java | 4 +- .../accumulo/shell/commands/ScanCommand.java | 10 +-- .../shell/commands/SetIterCommandTest.java | 4 +- .../main/java/org/apache/accumulo/start/Main.java | 15 ++-- .../start/classloader/AccumuloClassLoader.java | 2 +- .../vfs/AccumuloReloadingVFSClassLoader.java | 2 +- .../classloader/vfs/AccumuloVFSClassLoader.java | 63 ++++++++++----- .../start/classloader/vfs/ContextManager.java | 17 ++-- .../vfs/PostDelegatingVFSClassLoader.java | 2 +- .../classloader/vfs/ReloadingClassLoader.java | 2 +- .../classloader/vfs/UniqueFileReplicator.java | 2 +- .../classloader/vfs/AccumuloClasspathTest.java | 6 +- .../vfs/AccumuloReloadingVFSClassLoaderTest.java | 1 + .../vfs/AccumuloVFSClassLoaderTest.java | 2 + .../start/classloader/vfs/ContextManagerTest.java | 10 +-- .../org/apache/accumulo/test/ShellServerIT.java | 34 ++++---- .../accumulo/test/UserCompactionStrategyIT.java | 3 +- .../test/functional/ConfigurableCompactionIT.java | 2 +- .../accumulo/test/functional/ScannerContextIT.java | 10 ++- 53 files changed, 451 insertions(+), 418 deletions(-) diff --git a/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java b/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java index 89bf835..1ac0474 100644 --- a/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java +++ b/core/src/main/java/org/apache/accumulo/core/classloader/ClassLoaderUtil.java @@ -18,17 +18,84 @@ */ package org.apache.accumulo.core.classloader; -import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; +import org.apache.accumulo.core.conf.AccumuloConfiguration; +import org.apache.accumulo.core.conf.Property; +import org.apache.accumulo.core.spi.common.ContextClassLoaderFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class ClassLoaderUtil { - public static <U> Class<? extends U> loadClass(String contextName, String className, + private static final Logger LOG = LoggerFactory.getLogger(ClassLoaderUtil.class); + private static ContextClassLoaderFactory FACTORY; + + private ClassLoaderUtil() { + // cannot construct; static utilities only + } + + /** + * Initialize the ContextClassLoaderFactory + */ + public static synchronized void initContextFactory(AccumuloConfiguration conf) { + if (FACTORY == null) { + LOG.debug("Creating {}", ContextClassLoaderFactory.class.getName()); + String factoryName = conf.get(Property.GENERAL_CONTEXT_CLASSLOADER_FACTORY.getKey()); + if (factoryName == null || factoryName.isEmpty()) { + // load the default implementation + LOG.info("Using default {}, which is subject to change in a future release", + ContextClassLoaderFactory.class.getName()); + FACTORY = new DefaultContextClassLoaderFactory(conf); + } else { + // load user's selected implementation + try { + var factoryClass = Class.forName(factoryName).asSubclass(ContextClassLoaderFactory.class); + LOG.info("Creating {}: {}", ContextClassLoaderFactory.class.getName(), factoryName); + FACTORY = factoryClass.getDeclaredConstructor().newInstance(); + } catch (ReflectiveOperationException e) { + throw new IllegalStateException("Unable to load and initialize class: " + factoryName, e); + } + } + } else { + LOG.debug("{} already initialized with {}.", ContextClassLoaderFactory.class.getName(), + FACTORY.getClass().getName()); + } + } + + // for testing + static ContextClassLoaderFactory getContextFactory() { + return FACTORY; + } + + // for testing + static synchronized void resetContextFactoryForTests() { + FACTORY = null; + } + + @SuppressWarnings("deprecation") + public static ClassLoader getClassLoader(String context) { + if (context != null && !context.isEmpty()) { + return FACTORY.getClassLoader(context); + } else { + return org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader.getClassLoader(); + } + } + + public static <U> Class<? extends U> loadClass(String context, String className, Class<U> extension) throws ClassNotFoundException { - if (contextName != null && !contextName.isEmpty()) - return ContextClassLoaders.getContextClassLoaderFactory().getClassLoader(contextName) - .loadClass(className).asSubclass(extension); - else - return AccumuloVFSClassLoader.loadClass(className, extension); + return getClassLoader(context).loadClass(className).asSubclass(extension); + } + public static <U> Class<? extends U> loadClass(String className, Class<U> extension) + throws ClassNotFoundException { + return loadClass(null, className, extension); } + + /** + * Retrieve the classloader context from a table's configuration. + */ + @SuppressWarnings("removal") + public static String tableContext(AccumuloConfiguration conf) { + return conf.get(conf.resolve(Property.TABLE_CLASSLOADER_CONTEXT, Property.TABLE_CLASSPATH)); + } + } diff --git a/core/src/main/java/org/apache/accumulo/core/classloader/ContextClassLoaders.java b/core/src/main/java/org/apache/accumulo/core/classloader/ContextClassLoaders.java deleted file mode 100644 index 92f30ff..0000000 --- a/core/src/main/java/org/apache/accumulo/core/classloader/ContextClassLoaders.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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.accumulo.core.classloader; - -import java.lang.reflect.InvocationTargetException; - -import org.apache.accumulo.core.conf.AccumuloConfiguration; -import org.apache.accumulo.core.conf.Property; -import org.apache.accumulo.core.spi.common.ContextClassLoaderFactory; -import org.apache.accumulo.core.util.ConfigurationImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class ContextClassLoaders { - - private static final Logger LOG = LoggerFactory.getLogger(ContextClassLoaders.class); - - private static ContextClassLoaderFactory FACTORY; - private static AccumuloConfiguration CONF; - - /** - * Initialize the ContextClassLoaderFactory - * - * @param conf - * AccumuloConfiguration object - */ - public static synchronized void initialize(AccumuloConfiguration conf) throws Exception { - if (null == CONF) { - CONF = conf; - LOG.info("Creating ContextClassLoaderFactory"); - var factoryName = CONF.get(Property.GENERAL_CONTEXT_CLASSLOADER_FACTORY.toString()); - if (null == factoryName || factoryName.isEmpty()) { - LOG.info("No ClassLoaderFactory specified"); - return; - } - try { - var factoryClass = Class.forName(factoryName); - if (ContextClassLoaderFactory.class.isAssignableFrom(factoryClass)) { - LOG.info("Creating ContextClassLoaderFactory: {}", factoryName); - FACTORY = ((Class<? extends ContextClassLoaderFactory>) factoryClass) - .getDeclaredConstructor().newInstance(); - FACTORY.initialize(new ConfigurationImpl(CONF)); - } else { - throw new RuntimeException(factoryName + " does not implement ContextClassLoaderFactory"); - } - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException - | IllegalArgumentException | InvocationTargetException | NoSuchMethodException - | SecurityException e) { - LOG.error( - "Unable to load and initialize class: {}. Ensure that the jar containing the ContextClassLoaderFactory is on the classpath", - factoryName); - throw e; - } - } else { - LOG.debug("ContextClassLoaderFactory already initialized."); - } - } - - /** - * Get the ContextClassLoaderFactory - * - * @return the configured context classloader factory - */ - public static ContextClassLoaderFactory getContextClassLoaderFactory() { - return FACTORY; - } - - public static void resetForTests() { - CONF = null; - } - -} diff --git a/core/src/main/java/org/apache/accumulo/core/classloader/DefaultContextClassLoaderFactory.java b/core/src/main/java/org/apache/accumulo/core/classloader/DefaultContextClassLoaderFactory.java new file mode 100644 index 0000000..3613842 --- /dev/null +++ b/core/src/main/java/org/apache/accumulo/core/classloader/DefaultContextClassLoaderFactory.java @@ -0,0 +1,82 @@ +/* + * 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.accumulo.core.classloader; + +import java.util.Map; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +import org.apache.accumulo.core.conf.AccumuloConfiguration; +import org.apache.accumulo.core.conf.Property; +import org.apache.accumulo.core.spi.common.ContextClassLoaderFactory; +import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The default implementation of ContextClassLoaderFactory. This implementation is subject to change + * over time. It currently implements the legacy context class loading behavior based on Accumulo's + * custom class loaders and commons-vfs2. In future, it may simply return the system class loader + * for all requested contexts. This class is used internally to Accumulo only, and should not be + * used by users in their configuration. + */ +@SuppressWarnings({"deprecation", "removal"}) +public class DefaultContextClassLoaderFactory implements ContextClassLoaderFactory { + + private static final AtomicBoolean isInstantiated = new AtomicBoolean(false); + private static final Logger LOG = LoggerFactory.getLogger(DefaultContextClassLoaderFactory.class); + private static final String className = DefaultContextClassLoaderFactory.class.getName(); + + public DefaultContextClassLoaderFactory(final AccumuloConfiguration accConf) { + if (!isInstantiated.compareAndSet(false, true)) { + throw new IllegalStateException("Can only instantiate " + className + " once"); + } + Supplier<Map<String,String>> contextConfigSupplier = + () -> accConf.getAllPropertiesWithPrefix(Property.VFS_CONTEXT_CLASSPATH_PROPERTY); + AccumuloVFSClassLoader.setContextConfig(contextConfigSupplier); + LOG.debug("ContextManager configuration set"); + startCleanupThread(contextConfigSupplier); + } + + private static void startCleanupThread(final Supplier<Map<String,String>> contextConfigSupplier) { + new Timer(className + "-cleanup", true).scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + Map<String,String> contextConfigs = contextConfigSupplier.get(); + LOG.trace("{}-cleanup thread, properties: {}", className, contextConfigs); + int prefixlen = Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey().length(); + Set<String> contextsInUse = contextConfigs.keySet().stream() + .map(k -> k.substring(prefixlen)).collect(Collectors.toSet()); + LOG.trace("{}-cleanup thread, contexts in use: {}", className, contextsInUse); + AccumuloVFSClassLoader.removeUnusedContexts(contextsInUse); + } + }, 60_000, 60_000); + LOG.debug("Context cleanup timer started at 60s intervals"); + } + + @Override + public ClassLoader getClassLoader(String contextName) { + return AccumuloVFSClassLoader.getContextClassLoader(contextName); + } + +} diff --git a/core/src/main/java/org/apache/accumulo/core/classloader/LegacyVFSContextClassLoaderFactory.java b/core/src/main/java/org/apache/accumulo/core/classloader/LegacyVFSContextClassLoaderFactory.java deleted file mode 100644 index 6578e49..0000000 --- a/core/src/main/java/org/apache/accumulo/core/classloader/LegacyVFSContextClassLoaderFactory.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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.accumulo.core.classloader; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; - -import org.apache.accumulo.core.client.PluginEnvironment.Configuration; -import org.apache.accumulo.core.conf.Property; -import org.apache.accumulo.core.spi.common.ContextClassLoaderFactory; -import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; -import org.apache.accumulo.start.classloader.vfs.ContextManager; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Deprecated(since = "2.1.0", forRemoval = true) -public class LegacyVFSContextClassLoaderFactory implements ContextClassLoaderFactory { - - private static final Logger LOG = - LoggerFactory.getLogger(LegacyVFSContextClassLoaderFactory.class); - - public void initialize(Configuration contextProperties) { - try { - AccumuloVFSClassLoader.getContextManager() - .setContextConfig(new ContextManager.DefaultContextsConfig() { - @Override - public Map<String,String> getVfsContextClasspathProperties() { - return contextProperties - .getWithPrefix(Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey()); - } - }); - LOG.debug("ContextManager configuration set"); - new Timer("LegacyVFSContextClassLoaderFactory-cleanup", true) - .scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - try { - if (LOG.isTraceEnabled()) { - LOG.trace("LegacyVFSContextClassLoaderFactory-cleanup thread, properties: {}", - contextProperties); - } - Set<String> configuredContexts = new HashSet<>(); - contextProperties.getWithPrefix(Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey()) - .forEach((k, v) -> { - configuredContexts.add( - k.substring(Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey().length())); - }); - LOG.trace("LegacyVFSContextClassLoaderFactory-cleanup thread, contexts in use: {}", - configuredContexts); - AccumuloVFSClassLoader.getContextManager().removeUnusedContexts(configuredContexts); - } catch (IOException e) { - LOG.warn("{}", e.getMessage(), e); - } - } - }, 60000, 60000); - LOG.debug("Context cleanup timer started at 60s intervals"); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - - } - - @Override - public ClassLoader getClassLoader(String contextName) throws IllegalArgumentException { - try { - return AccumuloVFSClassLoader.getContextManager().getClassLoader(contextName); - } catch (IOException e) { - throw new UncheckedIOException( - "Error getting context class loader for context: " + contextName, e); - } - } - -} diff --git a/core/src/main/java/org/apache/accumulo/core/conf/ConfigurationCopy.java b/core/src/main/java/org/apache/accumulo/core/conf/ConfigurationCopy.java index 6336af5..3f0162b 100644 --- a/core/src/main/java/org/apache/accumulo/core/conf/ConfigurationCopy.java +++ b/core/src/main/java/org/apache/accumulo/core/conf/ConfigurationCopy.java @@ -111,4 +111,9 @@ public class ConfigurationCopy extends AccumuloConfiguration { return updateCount; } } + + @Override + public boolean isPropertySet(Property prop, boolean cacheAndWatch) { + return copy.containsKey(prop.getKey()); + } } diff --git a/core/src/main/java/org/apache/accumulo/core/conf/IterConfigUtil.java b/core/src/main/java/org/apache/accumulo/core/conf/IterConfigUtil.java index 82c1290..605e69f 100644 --- a/core/src/main/java/org/apache/accumulo/core/conf/IterConfigUtil.java +++ b/core/src/main/java/org/apache/accumulo/core/conf/IterConfigUtil.java @@ -184,7 +184,7 @@ public class IterConfigUtil { } IterLoad il = loadIterConf(scope, ssiList, ssio, conf); - il = il.iterEnv(env).useAccumuloClassLoader(true).context(conf.get(Property.TABLE_CLASSPATH)); + il = il.iterEnv(env).useAccumuloClassLoader(true).context(ClassLoaderUtil.tableContext(conf)); return loadIterators(source, il); } diff --git a/core/src/main/java/org/apache/accumulo/core/conf/Property.java b/core/src/main/java/org/apache/accumulo/core/conf/Property.java index f9bd878..bbc956d 100644 --- a/core/src/main/java/org/apache/accumulo/core/conf/Property.java +++ b/core/src/main/java/org/apache/accumulo/core/conf/Property.java @@ -26,7 +26,7 @@ import java.util.Map; import java.util.Map.Entry; import org.apache.accumulo.core.Constants; -import org.apache.accumulo.core.classloader.LegacyVFSContextClassLoaderFactory; +import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.client.security.tokens.PasswordToken; import org.apache.accumulo.core.constraints.NoDeleteConstraint; import org.apache.accumulo.core.file.rfile.RFile; @@ -40,8 +40,6 @@ import org.apache.accumulo.core.spi.scan.ScanPrioritizer; import org.apache.accumulo.core.spi.scan.SimpleScanDispatcher; import org.apache.accumulo.core.util.format.DefaultFormatter; import org.apache.accumulo.core.util.interpret.DefaultScanInterpreter; -import org.apache.accumulo.start.classloader.AccumuloClassLoader; -import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -187,8 +185,10 @@ public enum Property { "Properties in this category affect the behavior of accumulo overall, but" + " do not have to be consistent throughout a cloud."), @Deprecated(since = "2.0.0") - GENERAL_DYNAMIC_CLASSPATHS(AccumuloVFSClassLoader.DYNAMIC_CLASSPATH_PROPERTY_NAME, - AccumuloVFSClassLoader.DEFAULT_DYNAMIC_CLASSPATH_VALUE, PropertyType.STRING, + GENERAL_DYNAMIC_CLASSPATHS( + org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader.DYNAMIC_CLASSPATH_PROPERTY_NAME, + org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader.DEFAULT_DYNAMIC_CLASSPATH_VALUE, + PropertyType.STRING, "This property is deprecated since 2.0.0. A list of all of the places where changes " + "in jars or classes will force a reload of the classloader. Built-in dynamic class " + "loading will be removed in a future version. If this is needed, consider overriding " @@ -197,9 +197,10 @@ public enum Property { + "Additionally, this property no longer does property interpolation of environment " + "variables, such as '$ACCUMULO_HOME'. Use commons-configuration syntax," + "'${env:ACCUMULO_HOME}' instead."), - GENERAL_CONTEXT_CLASSLOADER_FACTORY("general.context.class.loader.factory", - LegacyVFSContextClassLoaderFactory.class.getName(), PropertyType.STRING, - "Name of classloader factory to be used to create classloaders for named contexts."), + GENERAL_CONTEXT_CLASSLOADER_FACTORY("general.context.class.loader.factory", "", + PropertyType.CLASSNAME, + "Name of classloader factory to be used to create classloaders for named contexts," + + " such as per-table contexts set by `table.class.loader.context`."), GENERAL_RPC_TIMEOUT("general.rpc.timeout", "120s", PropertyType.TIMEDURATION, "Time to wait on I/O for simple, short RPC calls"), @Experimental @@ -879,6 +880,11 @@ public enum Property { "The Formatter class to apply on results in the shell"), TABLE_INTERPRETER_CLASS("table.interepreter", DefaultScanInterpreter.class.getName(), PropertyType.STRING, "The ScanInterpreter class to apply on scan arguments in the shell"), + TABLE_CLASSLOADER_CONTEXT("table.class.loader.context", "", PropertyType.STRING, + "The context to use for loading per-table resources, such as iterators" + + " from the configured factory in `general.context.class.loader.factory`."), + @Deprecated(since = "2.1.0", forRemoval = true) + @ReplacedBy(property = TABLE_CLASSLOADER_CONTEXT) TABLE_CLASSPATH("table.classpath.context", "", PropertyType.STRING, "Per table classpath context"), TABLE_REPLICATION("table.replication", "false", PropertyType.BOOLEAN, @@ -929,12 +935,14 @@ public enum Property { // defined by its use in AccumuloVFSClassLoader when generating the property documentation @Deprecated(since = "2.1.0", forRemoval = true) VFS_CLASSLOADER_SYSTEM_CLASSPATH_PROPERTY( - AccumuloVFSClassLoader.VFS_CLASSLOADER_SYSTEM_CLASSPATH_PROPERTY, "", PropertyType.STRING, + org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader.VFS_CLASSLOADER_SYSTEM_CLASSPATH_PROPERTY, + "", PropertyType.STRING, "Configuration for a system level vfs classloader. Accumulo jar can be" + " configured here and loaded out of HDFS."), @Deprecated(since = "2.1.0", forRemoval = true) - VFS_CONTEXT_CLASSPATH_PROPERTY(AccumuloVFSClassLoader.VFS_CONTEXT_CLASSPATH_PROPERTY, null, - PropertyType.PREFIX, + VFS_CONTEXT_CLASSPATH_PROPERTY( + org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader.VFS_CONTEXT_CLASSPATH_PROPERTY, + null, PropertyType.PREFIX, "Properties in this category are define a classpath. These properties" + " start with the category prefix, followed by a context name. The value is" + " a comma separated list of URIs. Supports full regex on filename alone." @@ -948,8 +956,9 @@ public enum Property { // this property shouldn't be used directly; it exists solely to document the default value // defined by its use in AccumuloVFSClassLoader when generating the property documentation @Deprecated(since = "2.1.0", forRemoval = true) - VFS_CLASSLOADER_CACHE_DIR(AccumuloVFSClassLoader.VFS_CACHE_DIR, "${java.io.tmpdir}", - PropertyType.ABSOLUTEPATH, + VFS_CLASSLOADER_CACHE_DIR( + org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader.VFS_CACHE_DIR, + "${java.io.tmpdir}", PropertyType.ABSOLUTEPATH, "The base directory to use for the vfs cache. The actual cached files will be located" + " in a subdirectory, `accumulo-vfs-cache-<jvmProcessName>-${user.name}`, where" + " `<jvmProcessName>` is determined by the JVM's internal management engine." @@ -1025,7 +1034,8 @@ public enum Property { + "HDFS directory in which accumulo instance will run. " + "Do not change after accumulo is initialized."), @Deprecated(since = "2.0.0") - GENERAL_CLASSPATHS(AccumuloClassLoader.GENERAL_CLASSPATHS, "", PropertyType.STRING, + GENERAL_CLASSPATHS(org.apache.accumulo.start.classloader.AccumuloClassLoader.GENERAL_CLASSPATHS, + "", PropertyType.STRING, "This property is deprecated since 2.0.0. The class path should instead be configured" + " by the launch environment (for example, accumulo-env.sh). A list of all" + " of the places to look for a class. Order does matter, as it will look for" @@ -1371,12 +1381,11 @@ public enum Property { * @param defaultInstance * instance to use if creation fails * @return new class instance, or default instance if creation failed - * @see AccumuloVFSClassLoader */ public static <T> T createTableInstanceFromPropertyName(AccumuloConfiguration conf, Property property, Class<T> base, T defaultInstance) { String clazzName = conf.get(property); - String context = conf.get(TABLE_CLASSPATH); + String context = ClassLoaderUtil.tableContext(conf); return ConfigurationTypeHelper.getClassInstance(context, clazzName, base, defaultInstance); } @@ -1392,7 +1401,6 @@ public enum Property { * @param defaultInstance * instance to use if creation fails * @return new class instance, or default instance if creation failed - * @see AccumuloVFSClassLoader */ public static <T> T createInstanceFromPropertyName(AccumuloConfiguration conf, Property property, Class<T> base, T defaultInstance) { diff --git a/core/src/main/java/org/apache/accumulo/core/conf/PropertyType.java b/core/src/main/java/org/apache/accumulo/core/conf/PropertyType.java index ce45ae9..0b607ce 100644 --- a/core/src/main/java/org/apache/accumulo/core/conf/PropertyType.java +++ b/core/src/main/java/org/apache/accumulo/core/conf/PropertyType.java @@ -107,6 +107,7 @@ public enum PropertyType { + "config file using '${env:ACCUMULO_HOME}' or similar."), // VFS_CLASSLOADER_CACHE_DIR's default value is a special case, for documentation purposes + @SuppressWarnings("removal") ABSOLUTEPATH("absolute path", x -> x == null || x.trim().isEmpty() || new Path(x.trim()).isAbsolute() || x.equals(Property.VFS_CLASSLOADER_CACHE_DIR.getDefaultValue()), diff --git a/core/src/main/java/org/apache/accumulo/core/file/BloomFilterLayer.java b/core/src/main/java/org/apache/accumulo/core/file/BloomFilterLayer.java index 8f9333e..dcc96c2 100644 --- a/core/src/main/java/org/apache/accumulo/core/file/BloomFilterLayer.java +++ b/core/src/main/java/org/apache/accumulo/core/file/BloomFilterLayer.java @@ -122,7 +122,7 @@ public class BloomFilterLayer { * load KeyFunctor */ try { - String context = acuconf.get(Property.TABLE_CLASSPATH); + String context = ClassLoaderUtil.tableContext(acuconf); String classname = acuconf.get(Property.TABLE_BLOOM_KEY_FUNCTOR); Class<? extends KeyFunctor> clazz; if (!useAccumuloStart) @@ -213,7 +213,7 @@ public class BloomFilterLayer { loadThreshold = acuconf.getCount(Property.TABLE_BLOOM_LOAD_THRESHOLD); - final String context = acuconf.get(Property.TABLE_CLASSPATH); + final String context = ClassLoaderUtil.tableContext(acuconf); loadTask = () -> { // no need to load the bloom filter if the map file is closed diff --git a/core/src/main/java/org/apache/accumulo/core/file/blockfile/cache/impl/BlockCacheManagerFactory.java b/core/src/main/java/org/apache/accumulo/core/file/blockfile/cache/impl/BlockCacheManagerFactory.java index 2ee6b1d..5ba4b0f 100644 --- a/core/src/main/java/org/apache/accumulo/core/file/blockfile/cache/impl/BlockCacheManagerFactory.java +++ b/core/src/main/java/org/apache/accumulo/core/file/blockfile/cache/impl/BlockCacheManagerFactory.java @@ -43,7 +43,7 @@ public class BlockCacheManagerFactory { throws Exception { String impl = conf.get(Property.TSERV_CACHE_MANAGER_IMPL); Class<? extends BlockCacheManager> clazz = - ClassLoaderUtil.loadClass(null, impl, BlockCacheManager.class); + ClassLoaderUtil.loadClass(impl, BlockCacheManager.class); LOG.info("Created new block cache manager of type: {}", clazz.getSimpleName()); return clazz.getDeclaredConstructor().newInstance(); } diff --git a/core/src/main/java/org/apache/accumulo/core/iterators/TypedValueCombiner.java b/core/src/main/java/org/apache/accumulo/core/iterators/TypedValueCombiner.java index ba904ee..85a6640 100644 --- a/core/src/main/java/org/apache/accumulo/core/iterators/TypedValueCombiner.java +++ b/core/src/main/java/org/apache/accumulo/core/iterators/TypedValueCombiner.java @@ -128,8 +128,8 @@ public abstract class TypedValueCombiner<V> extends Combiner { protected void setEncoder(String encoderClass) { try { @SuppressWarnings("unchecked") - Class<? extends Encoder<V>> clazz = (Class<? extends Encoder<V>>) ClassLoaderUtil - .loadClass(null, encoderClass, Encoder.class); + Class<? extends Encoder<V>> clazz = + (Class<? extends Encoder<V>>) ClassLoaderUtil.loadClass(encoderClass, Encoder.class); encoder = clazz.getDeclaredConstructor().newInstance(); } catch (ReflectiveOperationException e) { throw new IllegalArgumentException(e); diff --git a/core/src/main/java/org/apache/accumulo/core/sample/impl/SamplerFactory.java b/core/src/main/java/org/apache/accumulo/core/sample/impl/SamplerFactory.java index e28656d..f35d005 100644 --- a/core/src/main/java/org/apache/accumulo/core/sample/impl/SamplerFactory.java +++ b/core/src/main/java/org/apache/accumulo/core/sample/impl/SamplerFactory.java @@ -23,12 +23,11 @@ import java.io.IOException; import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.client.sample.Sampler; import org.apache.accumulo.core.conf.AccumuloConfiguration; -import org.apache.accumulo.core.conf.Property; public class SamplerFactory { public static Sampler newSampler(SamplerConfigurationImpl config, AccumuloConfiguration acuconf, boolean useAccumuloStart) throws IOException { - String context = acuconf.get(Property.TABLE_CLASSPATH); + String context = ClassLoaderUtil.tableContext(acuconf); Class<? extends Sampler> clazz; try { diff --git a/core/src/main/java/org/apache/accumulo/core/spi/common/ContextClassLoaderFactory.java b/core/src/main/java/org/apache/accumulo/core/spi/common/ContextClassLoaderFactory.java index 9ac7862..104cfa3 100644 --- a/core/src/main/java/org/apache/accumulo/core/spi/common/ContextClassLoaderFactory.java +++ b/core/src/main/java/org/apache/accumulo/core/spi/common/ContextClassLoaderFactory.java @@ -18,39 +18,44 @@ */ package org.apache.accumulo.core.spi.common; -import org.apache.accumulo.core.client.PluginEnvironment.Configuration; - /** - * The ClassLoaderFactory is defined by the property general.context.factory. The factory - * implementation is configured externally to Accumulo and will return a ClassLoader for a given - * contextName. + * The ContextClassLoaderFactory provides a mechanism for various Accumulo components to use a + * custom ClassLoader for specific contexts, such as loading table iterators. This factory is + * initialized at startup and supplies ClassLoaders when provided a context. * - * @since 2.1.0 + * <p> + * This factory can be configured using the <code>general.context.class.loader.factory</code> + * property. All implementations of this factory must have a default (no-argument) public + * constructor. + * + * <p> + * A default implementation is provided for Accumulo 2.x to retain existing context class loader + * behavior based on per-table configuration. However, after Accumulo 2.x, the default is expected + * to change to a simpler implementation, and users will need to provide their own implementation to + * support advanced context class loading features. Some implementations may be maintained by the + * Accumulo developers in a separate package. Check the Accumulo website or contact the developers + * for more details on the status of these implementations. * + * <p> + * Because this factory is expected to be instantiated early in the application startup process, + * configuration is expected to be provided within the environment (such as in Java system + * properties or process environment variables), and is implementation-specific. + * + * @since 2.1.0 */ public interface ContextClassLoaderFactory { /** - * Initialize the ClassLoaderFactory. Implementations may need a reference to the configuration so - * that it can clean up contexts that are no longer being used. - * - * @param contextProperties - * Accumulo configuration properties - * @throws Exception - * if error initializing ClassLoaderFactory - */ - void initialize(Configuration contextProperties) throws Exception; - - /** - * Get the classloader for the context name. Callers should not cache the ClassLoader result as it - * may change if/when the ClassLoader reloads + * Get the class loader for the given context. Callers should not cache the ClassLoader result as + * it may change if/when the ClassLoader reloads. Implementations should throw a RuntimeException + * of some type (such as IllegalArgumentException) if the provided context is not supported or + * fails to be constructed. * - * @param contextName - * name of classloader context - * @return classloader configured for the context - * @throws IllegalArgumentException - * if contextName is not supported + * @param context + * the context that represents a class loader that is managed by this factory (can be + * null) + * @return the class loader for the given context */ - ClassLoader getClassLoader(String contextName) throws IllegalArgumentException; + ClassLoader getClassLoader(String context); } diff --git a/core/src/main/java/org/apache/accumulo/core/summary/SummarizerFactory.java b/core/src/main/java/org/apache/accumulo/core/summary/SummarizerFactory.java index 0c1a8f2..3b79694 100644 --- a/core/src/main/java/org/apache/accumulo/core/summary/SummarizerFactory.java +++ b/core/src/main/java/org/apache/accumulo/core/summary/SummarizerFactory.java @@ -24,7 +24,6 @@ import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.client.summary.Summarizer; import org.apache.accumulo.core.client.summary.SummarizerConfiguration; import org.apache.accumulo.core.conf.AccumuloConfiguration; -import org.apache.accumulo.core.conf.Property; public class SummarizerFactory { private ClassLoader classloader; @@ -39,7 +38,7 @@ public class SummarizerFactory { } public SummarizerFactory(AccumuloConfiguration tableConfig) { - this.context = tableConfig.get(Property.TABLE_CLASSPATH); + this.context = ClassLoaderUtil.tableContext(tableConfig); } private Summarizer newSummarizer(String classname) diff --git a/core/src/test/java/org/apache/accumulo/core/classloader/ContextClassLoaderFactoryTest.java b/core/src/test/java/org/apache/accumulo/core/classloader/ContextClassLoaderFactoryTest.java index 40fdd9b..54f9924 100644 --- a/core/src/test/java/org/apache/accumulo/core/classloader/ContextClassLoaderFactoryTest.java +++ b/core/src/test/java/org/apache/accumulo/core/classloader/ContextClassLoaderFactoryTest.java @@ -24,6 +24,7 @@ import java.io.File; import java.net.URLClassLoader; import org.apache.accumulo.core.conf.ConfigurationCopy; +import org.apache.accumulo.core.conf.Property; import org.apache.commons.io.FileUtils; import org.junit.Before; import org.junit.Rule; @@ -63,18 +64,17 @@ public class ContextClassLoaderFactoryTest { public void differentContexts() throws Exception { ConfigurationCopy cc = new ConfigurationCopy(); - cc.set("general.context.class.loader.factory", URLClassLoaderFactory.class.getName()); - ContextClassLoaders.resetForTests(); - ContextClassLoaders.initialize(cc); + cc.set(Property.GENERAL_CONTEXT_CLASSLOADER_FACTORY.getKey(), + URLClassLoaderFactory.class.getName()); + ClassLoaderUtil.resetContextFactoryForTests(); + ClassLoaderUtil.initContextFactory(cc); - URLClassLoader cl1 = - (URLClassLoader) ContextClassLoaders.getContextClassLoaderFactory().getClassLoader(uri1); + URLClassLoader cl1 = (URLClassLoader) ClassLoaderUtil.getContextFactory().getClassLoader(uri1); var urls1 = cl1.getURLs(); assertEquals(1, urls1.length); assertEquals(uri1, urls1[0].toString()); - URLClassLoader cl2 = - (URLClassLoader) ContextClassLoaders.getContextClassLoaderFactory().getClassLoader(uri2); + URLClassLoader cl2 = (URLClassLoader) ClassLoaderUtil.getContextFactory().getClassLoader(uri2); var urls2 = cl2.getURLs(); assertEquals(1, urls2.length); assertEquals(uri2, urls2[0].toString()); diff --git a/core/src/test/java/org/apache/accumulo/core/classloader/URLClassLoaderFactory.java b/core/src/test/java/org/apache/accumulo/core/classloader/URLClassLoaderFactory.java index 23bfda1..beece5f 100644 --- a/core/src/test/java/org/apache/accumulo/core/classloader/URLClassLoaderFactory.java +++ b/core/src/test/java/org/apache/accumulo/core/classloader/URLClassLoaderFactory.java @@ -21,31 +21,27 @@ package org.apache.accumulo.core.classloader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; -import java.util.ArrayList; +import java.util.stream.Collectors; +import java.util.stream.Stream; -import org.apache.accumulo.core.client.PluginEnvironment.Configuration; import org.apache.accumulo.core.spi.common.ContextClassLoaderFactory; +// test implementation public class URLClassLoaderFactory implements ContextClassLoaderFactory { private static final String COMMA = ","; @Override - public void initialize(Configuration contextProperties) throws Exception {} - - @Override - public ClassLoader getClassLoader(String contextName) throws IllegalArgumentException { + public ClassLoader getClassLoader(String contextName) { // The context name is the classpath. - var parts = contextName.split(COMMA); - var urls = new ArrayList<URL>(); - for (String p : parts) { + URL[] urls = Stream.of(contextName.split(COMMA)).map(p -> { try { - urls.add(new URL(p)); + return new URL(p); } catch (MalformedURLException e) { throw new IllegalArgumentException("Error creating URL from classpath segment: " + p, e); } - } - return URLClassLoader.newInstance(urls.toArray(new URL[urls.size()])); + }).collect(Collectors.toList()).toArray(new URL[0]); + return URLClassLoader.newInstance(urls); } } diff --git a/core/src/test/java/org/apache/accumulo/core/conf/AccumuloConfigurationTest.java b/core/src/test/java/org/apache/accumulo/core/conf/AccumuloConfigurationTest.java index 55f0af7..28ee628 100644 --- a/core/src/test/java/org/apache/accumulo/core/conf/AccumuloConfigurationTest.java +++ b/core/src/test/java/org/apache/accumulo/core/conf/AccumuloConfigurationTest.java @@ -37,6 +37,10 @@ import org.junit.Test; public class AccumuloConfigurationTest { + @SuppressWarnings("removal") + private static final Property VFS_CONTEXT_CLASSPATH_PROPERTY = + Property.VFS_CONTEXT_CLASSPATH_PROPERTY; + @Test public void testGetPropertyByString() { AccumuloConfiguration c = DefaultConfiguration.getInstance(); @@ -227,8 +231,8 @@ public class AccumuloConfigurationTest { expected2.put(Property.TABLE_ITERATOR_SCAN_PREFIX.getKey() + "i1.opt", "o99"); assertEquals(expected2, pm3); - Map<String,String> pm5 = tc.getAllPropertiesWithPrefix(Property.VFS_CONTEXT_CLASSPATH_PROPERTY); - Map<String,String> pm6 = tc.getAllPropertiesWithPrefix(Property.VFS_CONTEXT_CLASSPATH_PROPERTY); + Map<String,String> pm5 = tc.getAllPropertiesWithPrefix(VFS_CONTEXT_CLASSPATH_PROPERTY); + Map<String,String> pm6 = tc.getAllPropertiesWithPrefix(VFS_CONTEXT_CLASSPATH_PROPERTY); assertSame(pm5, pm6); assertEquals(0, pm5.size()); @@ -239,7 +243,7 @@ public class AccumuloConfigurationTest { Map<String,String> pm8 = tc.getAllPropertiesWithPrefix(Property.TABLE_ITERATOR_SCAN_PREFIX); assertSame(pm3, pm8); - Map<String,String> pm9 = tc.getAllPropertiesWithPrefix(Property.VFS_CONTEXT_CLASSPATH_PROPERTY); + Map<String,String> pm9 = tc.getAllPropertiesWithPrefix(VFS_CONTEXT_CLASSPATH_PROPERTY); assertSame(pm5, pm9); tc.set(Property.TABLE_ITERATOR_SCAN_PREFIX.getKey() + "i2", "class42"); @@ -260,14 +264,13 @@ public class AccumuloConfigurationTest { assertSame(pmC, pmD); assertEquals(expected1, pmC); - tc.set(Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "ctx123", "hdfs://ib/p1"); + tc.set(VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "ctx123", "hdfs://ib/p1"); - Map<String,String> pmE = tc.getAllPropertiesWithPrefix(Property.VFS_CONTEXT_CLASSPATH_PROPERTY); - Map<String,String> pmF = tc.getAllPropertiesWithPrefix(Property.VFS_CONTEXT_CLASSPATH_PROPERTY); + Map<String,String> pmE = tc.getAllPropertiesWithPrefix(VFS_CONTEXT_CLASSPATH_PROPERTY); + Map<String,String> pmF = tc.getAllPropertiesWithPrefix(VFS_CONTEXT_CLASSPATH_PROPERTY); assertSame(pmE, pmF); assertNotSame(pm5, pmE); - assertEquals( - Map.of(Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "ctx123", "hdfs://ib/p1"), pmE); + assertEquals(Map.of(VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "ctx123", "hdfs://ib/p1"), pmE); Map<String,String> pmG = tc.getAllPropertiesWithPrefix(Property.TABLE_ITERATOR_SCAN_PREFIX); Map<String,String> pmH = tc.getAllPropertiesWithPrefix(Property.TABLE_ITERATOR_SCAN_PREFIX); @@ -281,7 +284,7 @@ public class AccumuloConfigurationTest { assertSame(pmI, pmJ); assertEquals(expected1, pmI); - Map<String,String> pmK = tc.getAllPropertiesWithPrefix(Property.VFS_CONTEXT_CLASSPATH_PROPERTY); + Map<String,String> pmK = tc.getAllPropertiesWithPrefix(VFS_CONTEXT_CLASSPATH_PROPERTY); assertSame(pmE, pmK); Map<String,String> pmL = tc.getAllPropertiesWithPrefix(Property.TABLE_ITERATOR_SCAN_PREFIX); diff --git a/core/src/test/java/org/apache/accumulo/core/crypto/CryptoTest.java b/core/src/test/java/org/apache/accumulo/core/crypto/CryptoTest.java index f96730d..b0d75f4 100644 --- a/core/src/test/java/org/apache/accumulo/core/crypto/CryptoTest.java +++ b/core/src/test/java/org/apache/accumulo/core/crypto/CryptoTest.java @@ -271,7 +271,7 @@ public class CryptoTest { "org.apache.accumulo.core.cryptoImpl.AESCryptoService"); String configuredClass = aconf.get(Property.INSTANCE_CRYPTO_SERVICE.getKey()); Class<? extends CryptoService> clazz = - ClassLoaderUtil.loadClass(null, configuredClass, CryptoService.class); + ClassLoaderUtil.loadClass(configuredClass, CryptoService.class); CryptoService cs = clazz.getDeclaredConstructor().newInstance(); assertEquals(AESCryptoService.class, cs.getClass()); diff --git a/minicluster/src/test/java/org/apache/accumulo/minicluster/MiniAccumuloClusterTest.java b/minicluster/src/test/java/org/apache/accumulo/minicluster/MiniAccumuloClusterTest.java index 968de66..398322e 100644 --- a/minicluster/src/test/java/org/apache/accumulo/minicluster/MiniAccumuloClusterTest.java +++ b/minicluster/src/test/java/org/apache/accumulo/minicluster/MiniAccumuloClusterTest.java @@ -63,6 +63,10 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "paths not set by user input") public class MiniAccumuloClusterTest { + @SuppressWarnings("removal") + private static final Property VFS_CONTEXT_CLASSPATH_PROPERTY = + Property.VFS_CONTEXT_CLASSPATH_PROPERTY; + public static File testDir; private static MiniAccumuloCluster accumulo; @@ -180,9 +184,10 @@ public class MiniAccumuloClusterTest { File jarFile = folder.newFile("iterator.jar"); FileUtils.copyURLToFile(this.getClass().getResource("/FooFilter.jar"), jarFile); - conn.instanceOperations().setProperty(Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "cx1", + conn.instanceOperations().setProperty(VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "cx1", jarFile.toURI().toString()); - conn.tableOperations().setProperty("table2", Property.TABLE_CLASSPATH.getKey(), "cx1"); + conn.tableOperations().setProperty("table2", Property.TABLE_CLASSLOADER_CONTEXT.getKey(), + "cx1"); conn.tableOperations().attachIterator("table2", new IteratorSetting(100, "foocensor", "org.apache.accumulo.test.FooFilter")); @@ -212,8 +217,7 @@ public class MiniAccumuloClusterTest { assertEquals(2, count); - conn.instanceOperations() - .removeProperty(Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "cx1"); + conn.instanceOperations().removeProperty(VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "cx1"); conn.tableOperations().delete("table2"); } diff --git a/pom.xml b/pom.xml index b0b4497..7a4123e 100644 --- a/pom.xml +++ b/pom.xml @@ -133,6 +133,8 @@ <jaxb.version>2.3.0.1</jaxb.version> <jersey.version>2.30.1</jersey.version> <jetty.version>9.4.27.v20200227</jetty.version> + <!-- prevent introduction of new compiler warnings --> + <maven.compiler.failOnWarning>true</maven.compiler.failOnWarning> <maven.compiler.release>11</maven.compiler.release> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> diff --git a/server/base/src/main/java/org/apache/accumulo/server/AbstractServer.java b/server/base/src/main/java/org/apache/accumulo/server/AbstractServer.java index 9ac39df..f6609b0 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/AbstractServer.java +++ b/server/base/src/main/java/org/apache/accumulo/server/AbstractServer.java @@ -22,6 +22,7 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.conf.AccumuloConfiguration; import org.apache.accumulo.core.trace.TraceUtil; import org.apache.accumulo.server.metrics.Metrics; @@ -49,6 +50,7 @@ public abstract class AbstractServer implements AutoCloseable, Runnable { log.info("Version " + Constants.VERSION); log.info("Instance " + context.getInstanceID()); ServerUtil.init(context, appName); + ClassLoaderUtil.initContextFactory(context.getConfiguration()); this.metricsSystem = Metrics.initSystem(getClass().getSimpleName()); TraceUtil.enableServerTraces(hostname, appName, context.getConfiguration()); if (context.getSaslParams() != null) { diff --git a/server/base/src/main/java/org/apache/accumulo/server/ServiceEnvironmentImpl.java b/server/base/src/main/java/org/apache/accumulo/server/ServiceEnvironmentImpl.java index 6b74454..b0845f3 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/ServiceEnvironmentImpl.java +++ b/server/base/src/main/java/org/apache/accumulo/server/ServiceEnvironmentImpl.java @@ -20,10 +20,10 @@ package org.apache.accumulo.server; import java.io.IOException; +import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.clientImpl.Tables; import org.apache.accumulo.core.conf.ConfigurationTypeHelper; -import org.apache.accumulo.core.conf.Property; import org.apache.accumulo.core.data.TableId; import org.apache.accumulo.core.spi.common.ServiceEnvironment; import org.apache.accumulo.core.util.ConfigurationImpl; @@ -62,7 +62,7 @@ public class ServiceEnvironmentImpl implements ServiceEnvironment { @Override public <T> T instantiate(TableId tableId, String className, Class<T> base) throws ReflectiveOperationException, IOException { - String ctx = srvCtx.getTableConfiguration(tableId).get(Property.TABLE_CLASSPATH); + String ctx = ClassLoaderUtil.tableContext(srvCtx.getTableConfiguration(tableId)); return ConfigurationTypeHelper.getClassInstance(ctx, className, base); } } diff --git a/server/base/src/main/java/org/apache/accumulo/server/client/ClientServiceHandler.java b/server/base/src/main/java/org/apache/accumulo/server/client/ClientServiceHandler.java index 34255af..8ac9f48 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/client/ClientServiceHandler.java +++ b/server/base/src/main/java/org/apache/accumulo/server/client/ClientServiceHandler.java @@ -353,17 +353,16 @@ public class ClientServiceHandler implements ClientService.Iface { return transactionWatcher.isActive(tid); } - @SuppressWarnings({"rawtypes", "unchecked"}) @Override public boolean checkClass(TInfo tinfo, TCredentials credentials, String className, String interfaceMatch) throws TException { security.authenticateUser(credentials, credentials); ClassLoader loader = getClass().getClassLoader(); - Class shouldMatch; + Class<?> shouldMatch; try { shouldMatch = loader.loadClass(interfaceMatch); - Class test = ClassLoaderUtil.loadClass(null, className, shouldMatch); + Class<?> test = ClassLoaderUtil.loadClass(className, shouldMatch); test.getDeclaredConstructor().newInstance(); return true; } catch (ClassCastException | ReflectiveOperationException e) { @@ -386,7 +385,7 @@ public class ClientServiceHandler implements ClientService.Iface { try { shouldMatch = loader.loadClass(interfaceMatch); AccumuloConfiguration conf = context.getTableConfiguration(tableId); - String context = conf.get(Property.TABLE_CLASSPATH); + String context = ClassLoaderUtil.tableContext(conf); Class<?> test = ClassLoaderUtil.loadClass(context, className, shouldMatch); test.getDeclaredConstructor().newInstance(); return true; @@ -410,7 +409,7 @@ public class ClientServiceHandler implements ClientService.Iface { try { shouldMatch = loader.loadClass(interfaceMatch); AccumuloConfiguration conf = context.getNamespaceConfiguration(namespaceId); - String context = conf.get(Property.TABLE_CLASSPATH); + String context = ClassLoaderUtil.tableContext(conf); Class<?> test = ClassLoaderUtil.loadClass(context, className, shouldMatch); test.getDeclaredConstructor().newInstance(); return true; diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java b/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java index eb3164a..8e24224 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java +++ b/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java @@ -30,6 +30,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Predicate; import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.conf.AccumuloConfiguration; import org.apache.accumulo.core.conf.IterConfigUtil; import org.apache.accumulo.core.conf.Property; @@ -75,8 +76,7 @@ public class TableConfiguration extends AccumuloConfiguration { Map<String,Map<String,String>> allOpts = new HashMap<>(); List<IterInfo> iters = IterConfigUtil.parseIterConf(scope, Collections.emptyList(), allOpts, conf); - return new ParsedIteratorConfig(iters, allOpts, conf.get(Property.TABLE_CLASSPATH)); - + return new ParsedIteratorConfig(iters, allOpts, ClassLoaderUtil.tableContext(conf)); })); } diff --git a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/TableLoadBalancer.java b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/TableLoadBalancer.java index c8c9289..b13670a 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/master/balancer/TableLoadBalancer.java +++ b/server/base/src/main/java/org/apache/accumulo/server/master/balancer/TableLoadBalancer.java @@ -48,7 +48,7 @@ public class TableLoadBalancer extends TabletBalancer { private TabletBalancer constructNewBalancerForTable(String clazzName, TableId tableId) throws Exception { String context = null; - context = this.context.getTableConfiguration(tableId).get(Property.TABLE_CLASSPATH); + context = ClassLoaderUtil.tableContext(this.context.getTableConfiguration(tableId)); Class<? extends TabletBalancer> clazz = ClassLoaderUtil.loadClass(context, clazzName, TabletBalancer.class); Constructor<? extends TabletBalancer> constructor = clazz.getConstructor(TableId.class); diff --git a/server/base/src/main/java/org/apache/accumulo/server/util/LoginProperties.java b/server/base/src/main/java/org/apache/accumulo/server/util/LoginProperties.java index 3b0633d..e12a588 100644 --- a/server/base/src/main/java/org/apache/accumulo/server/util/LoginProperties.java +++ b/server/base/src/main/java/org/apache/accumulo/server/util/LoginProperties.java @@ -18,6 +18,7 @@ */ package org.apache.accumulo.server.util; +import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.client.security.tokens.AuthenticationToken; import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.TokenProperty; import org.apache.accumulo.core.conf.AccumuloConfiguration; @@ -25,7 +26,6 @@ import org.apache.accumulo.core.conf.Property; import org.apache.accumulo.core.conf.SiteConfiguration; import org.apache.accumulo.server.ServerContext; import org.apache.accumulo.server.security.handler.Authenticator; -import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; import org.apache.accumulo.start.spi.KeywordExecutable; import com.google.auto.service.AutoService; @@ -47,9 +47,9 @@ public class LoginProperties implements KeywordExecutable { public void execute(String[] args) throws Exception { try (var context = new ServerContext(SiteConfiguration.auto())) { AccumuloConfiguration config = context.getConfiguration(); - Authenticator authenticator = AccumuloVFSClassLoader.getClassLoader() - .loadClass(config.get(Property.INSTANCE_SECURITY_AUTHENTICATOR)) - .asSubclass(Authenticator.class).getDeclaredConstructor().newInstance(); + Authenticator authenticator = ClassLoaderUtil + .loadClass(config.get(Property.INSTANCE_SECURITY_AUTHENTICATOR), Authenticator.class) + .getDeclaredConstructor().newInstance(); System.out .println("Supported token types for " + authenticator.getClass().getName() + " are : "); diff --git a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/GroupBalancerTest.java b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/GroupBalancerTest.java index 5cec0e9..f09a68f 100644 --- a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/GroupBalancerTest.java +++ b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/GroupBalancerTest.java @@ -38,11 +38,9 @@ import org.apache.accumulo.core.data.TableId; import org.apache.accumulo.core.dataImpl.KeyExtent; import org.apache.accumulo.core.master.thrift.TabletServerStatus; import org.apache.accumulo.core.metadata.TServerInstance; -import org.apache.accumulo.core.metadata.schema.TabletsMetadata; import org.apache.accumulo.core.util.MapCounter; import org.apache.accumulo.server.master.state.TabletMigration; import org.apache.hadoop.io.Text; -import org.easymock.EasyMock; import org.junit.Test; public class GroupBalancerTest { @@ -59,7 +57,6 @@ public class GroupBalancerTest { public static class TabletServers { private final Set<TServerInstance> tservers = new HashSet<>(); private final Map<KeyExtent,TServerInstance> tabletLocs = new HashMap<>(); - private final TabletsMetadata mockMetadata = EasyMock.createMock(TabletsMetadata.class); public void addTservers(String... locs) { for (String loc : locs) { diff --git a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/TableLoadBalancerTest.java b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/TableLoadBalancerTest.java index 7d3be08..b2b1c48 100644 --- a/server/base/src/test/java/org/apache/accumulo/server/master/balancer/TableLoadBalancerTest.java +++ b/server/base/src/test/java/org/apache/accumulo/server/master/balancer/TableLoadBalancerTest.java @@ -148,7 +148,11 @@ public class TableLoadBalancerTest { public void test() { final ServerContext context = createMockContext(); TableConfiguration conf = createMock(TableConfiguration.class); - expect(conf.get(Property.TABLE_CLASSPATH)).andReturn("").anyTimes(); + @SuppressWarnings("removal") + Property TABLE_CLASSPATH = Property.TABLE_CLASSPATH; + expect(conf.resolve(Property.TABLE_CLASSLOADER_CONTEXT, TABLE_CLASSPATH)) + .andReturn(Property.TABLE_CLASSLOADER_CONTEXT).anyTimes(); + expect(conf.get(Property.TABLE_CLASSLOADER_CONTEXT)).andReturn("").anyTimes(); expect(context.getTableConfiguration(EasyMock.anyObject())).andReturn(conf).anyTimes(); replay(context, conf); diff --git a/server/manager/src/main/java/org/apache/accumulo/master/Master.java b/server/manager/src/main/java/org/apache/accumulo/master/Master.java index a6b7f15..708e5c1 100644 --- a/server/manager/src/main/java/org/apache/accumulo/master/Master.java +++ b/server/manager/src/main/java/org/apache/accumulo/master/Master.java @@ -46,7 +46,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import org.apache.accumulo.core.Constants; -import org.apache.accumulo.core.classloader.ContextClassLoaders; import org.apache.accumulo.core.client.AccumuloClient; import org.apache.accumulo.core.client.Scanner; import org.apache.accumulo.core.client.TableNotFoundException; @@ -377,16 +376,6 @@ public class Master extends AbstractServer Property.MASTER_TABLET_BALANCER, TabletBalancer.class, new DefaultLoadBalancer()); this.tabletBalancer.init(context); - try { - ContextClassLoaders.initialize(aconf); - } catch (Exception e1) { - log.error("Error configuring ContextClassLoaderFactory", e1); - if (e1 instanceof RuntimeException) { - throw (RuntimeException) e1; - } - throw new RuntimeException("Error configuring ContextClassLoaderFactory", e1); - } - this.security = AuditedSecurityOperation.getInstance(context); // Create the secret manager (can generate and verify delegation tokens) diff --git a/server/tracer/src/main/java/org/apache/accumulo/tracer/TraceServer.java b/server/tracer/src/main/java/org/apache/accumulo/tracer/TraceServer.java index d3859a8..1c46948 100644 --- a/server/tracer/src/main/java/org/apache/accumulo/tracer/TraceServer.java +++ b/server/tracer/src/main/java/org/apache/accumulo/tracer/TraceServer.java @@ -21,7 +21,6 @@ package org.apache.accumulo.tracer; import static java.nio.charset.StandardCharsets.UTF_8; import static org.apache.accumulo.fate.util.UtilWaitThread.sleepUninterruptibly; -import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; @@ -34,6 +33,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.client.Accumulo; import org.apache.accumulo.core.client.AccumuloClient; import org.apache.accumulo.core.client.AccumuloException; @@ -60,7 +60,6 @@ import org.apache.accumulo.server.ServerOpts; import org.apache.accumulo.server.ServerUtil; import org.apache.accumulo.server.security.SecurityUtil; import org.apache.accumulo.server.util.time.SimpleTimer; -import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; import org.apache.accumulo.tracer.thrift.RemoteSpan; import org.apache.accumulo.tracer.thrift.SpanReceiver.Iface; import org.apache.accumulo.tracer.thrift.SpanReceiver.Processor; @@ -265,9 +264,9 @@ public class TraceServer implements Watcher, AutoCloseable { at = new PasswordToken(conf.get(p).getBytes(UTF_8)); } else { Properties props = new Properties(); - AuthenticationToken token = - AccumuloVFSClassLoader.getClassLoader().loadClass(conf.get(Property.TRACE_TOKEN_TYPE)) - .asSubclass(AuthenticationToken.class).getDeclaredConstructor().newInstance(); + AuthenticationToken token = ClassLoaderUtil + .loadClass(conf.get(Property.TRACE_TOKEN_TYPE), AuthenticationToken.class) + .getDeclaredConstructor().newInstance(); int prefixLength = Property.TRACE_TOKEN_PROPERTY_PREFIX.getKey().length(); for (Entry<String,String> entry : loginMap.entrySet()) { @@ -289,7 +288,7 @@ public class TraceServer implements Watcher, AutoCloseable { accumuloClient.tableOperations().setProperty(tableName, Property.TABLE_FORMATTER_CLASS.getKey(), TraceFormatter.class.getName()); break; - } catch (AccumuloException | TableExistsException | TableNotFoundException | IOException + } catch (AccumuloException | TableExistsException | TableNotFoundException | RuntimeException ex) { log.info("Waiting to checking/create the trace table.", ex); sleepUninterruptibly(1, TimeUnit.SECONDS); @@ -362,8 +361,8 @@ public class TraceServer implements Watcher, AutoCloseable { private static void loginTracer(AccumuloConfiguration acuConf) { try { - Class<? extends AuthenticationToken> traceTokenType = AccumuloVFSClassLoader.getClassLoader() - .loadClass(acuConf.get(Property.TRACE_TOKEN_TYPE)).asSubclass(AuthenticationToken.class); + Class<? extends AuthenticationToken> traceTokenType = ClassLoaderUtil + .loadClass(acuConf.get(Property.TRACE_TOKEN_TYPE), AuthenticationToken.class); if (KerberosToken.class.isAssignableFrom(traceTokenType)) { // We're using Kerberos to talk to Accumulo, so check for trace user specific auth details. @@ -395,7 +394,7 @@ public class TraceServer implements Watcher, AutoCloseable { log.info("Handling login under the assumption that Accumulo users are not using Kerberos."); SecurityUtil.serverLogin(acuConf); } - } catch (IOException | ClassNotFoundException exception) { + } catch (ClassNotFoundException exception) { final String msg = String.format("Failed to retrieve trace user token information based on property %1s.", Property.TRACE_TOKEN_TYPE); diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java index 93900a2..d16d4bb 100644 --- a/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java +++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/TabletServer.java @@ -53,7 +53,6 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReentrantLock; import org.apache.accumulo.core.Constants; -import org.apache.accumulo.core.classloader.ContextClassLoaders; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.Durability; import org.apache.accumulo.core.clientImpl.DurabilityImpl; @@ -997,12 +996,6 @@ public class TabletServer extends AbstractServer { clientAddress = HostAndPort.fromParts(getHostname(), 0); final AccumuloConfiguration aconf = getConfiguration(); - try { - ContextClassLoaders.initialize(aconf); - } catch (Exception e1) { - log.error("Error configuring ContextClassLoaderFactory", e1); - throw new RuntimeException("Error configuring ContextClassLoaderFactory", e1); - } FileSystemMonitor.start(aconf, Property.TSERV_MONITOR_FS); diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/constraints/ConstraintChecker.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/constraints/ConstraintChecker.java index 5a2588d..51e4cc6 100644 --- a/server/tserver/src/main/java/org/apache/accumulo/tserver/constraints/ConstraintChecker.java +++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/constraints/ConstraintChecker.java @@ -47,7 +47,7 @@ public class ConstraintChecker { constrains = new ArrayList<>(); try { - String context = conf.get(Property.TABLE_CLASSPATH); + String context = ClassLoaderUtil.tableContext(conf); for (Entry<String,String> entry : conf .getAllPropertiesWithPrefix(Property.TABLE_CONSTRAINT_PREFIX).entrySet()) { diff --git a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableUtils.java b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableUtils.java index 78845d6..cc6ffe8 100644 --- a/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableUtils.java +++ b/server/tserver/src/main/java/org/apache/accumulo/tserver/tablet/CompactableUtils.java @@ -33,6 +33,7 @@ import java.util.concurrent.ExecutionException; import java.util.function.Predicate; import java.util.stream.Collectors; +import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.client.IteratorSetting; import org.apache.accumulo.core.client.PluginEnvironment; import org.apache.accumulo.core.client.admin.CompactionConfig; @@ -269,7 +270,7 @@ public class CompactableUtils { static <T> T newInstance(AccumuloConfiguration tableConfig, String className, Class<T> baseClass) { - String context = tableConfig.get(Property.TABLE_CLASSPATH); + String context = ClassLoaderUtil.tableContext(tableConfig); try { return ConfigurationTypeHelper.getClassInstance(context, className, baseClass); } catch (IOException | ReflectiveOperationException e) { diff --git a/shell/src/main/java/org/apache/accumulo/shell/Shell.java b/shell/src/main/java/org/apache/accumulo/shell/Shell.java index 62d4203..dc6327b 100644 --- a/shell/src/main/java/org/apache/accumulo/shell/Shell.java +++ b/shell/src/main/java/org/apache/accumulo/shell/Shell.java @@ -44,9 +44,11 @@ import java.util.Properties; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; +import java.util.stream.Stream; import org.apache.accumulo.core.Constants; -import org.apache.accumulo.core.classloader.ContextClassLoaders; +import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.cli.ClientOpts.PasswordConverter; import org.apache.accumulo.core.client.Accumulo; import org.apache.accumulo.core.client.AccumuloClient; @@ -161,7 +163,6 @@ import org.apache.accumulo.shell.commands.UserCommand; import org.apache.accumulo.shell.commands.UserPermissionsCommand; import org.apache.accumulo.shell.commands.UsersCommand; import org.apache.accumulo.shell.commands.WhoAmICommand; -import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; import org.apache.accumulo.start.spi.KeywordExecutable; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.DefaultParser; @@ -192,6 +193,8 @@ public class Shell extends ShellOptions implements KeywordExecutable { public static final Logger log = LoggerFactory.getLogger(Shell.class); private static final Logger audit = LoggerFactory.getLogger(Shell.class.getName() + ".audit"); + private static final Predicate<String> IS_HELP_OPT = + s -> s != null && (s.equals("-" + helpOption) || s.equals("--" + helpLongOption)); public static final Charset CHARSET = ISO_8859_1; public static final int NO_FIXED_ARG_LENGTH_CHECK = -1; public static final String COMMENT_PREFIX = "#"; @@ -433,14 +436,13 @@ public class Shell extends ShellOptions implements KeywordExecutable { } public ClassLoader getClassLoader(final CommandLine cl, final Shell shellState) - throws AccumuloException, TableNotFoundException, AccumuloSecurityException, IOException, + throws AccumuloException, TableNotFoundException, AccumuloSecurityException, FileSystemException { boolean tables = cl.hasOption(OptUtil.tableOpt().getOpt()) || !shellState.getTableName().isEmpty(); boolean namespaces = cl.hasOption(OptUtil.namespaceOpt().getOpt()); - String tableContext = null; Iterable<Entry<String,String>> tableProps; if (namespaces) { @@ -456,27 +458,37 @@ public class Shell extends ShellOptions implements KeywordExecutable { } else { throw new IllegalArgumentException("No table or namespace specified"); } - for (Entry<String,String> entry : tableProps) { - if (entry.getKey().equals(Property.TABLE_CLASSPATH.getKey())) { - tableContext = entry.getValue(); - } - } + String tableContext = getTableContextFromProps(tableProps); - ClassLoader classloader; + if (tableContext != null && !tableContext.isEmpty()) { + ClassLoaderUtil.initContextFactory(new ConfigurationCopy( + shellState.getAccumuloClient().instanceOperations().getSystemConfiguration())); + } + return ClassLoaderUtil.getClassLoader(tableContext); + } - if (tableContext != null && !tableContext.equals("")) { - try { - ContextClassLoaders.initialize(new ConfigurationCopy( - shellState.getAccumuloClient().instanceOperations().getSystemConfiguration())); - } catch (Exception e1) { - log.error("Error configuring ContextClassLoaderFactory", e1); - throw new RuntimeException("Error configuring ContextClassLoaderFactory", e1); + private static String getTableContextFromProps(Iterable<Entry<String,String>> props) { + String tableContext = null; + for (Entry<String,String> entry : props) { + // look for either the old property or the new one, but + // if the new one is set, stop looking and let it take precedence + if (entry.getKey().equals(Property.TABLE_CLASSLOADER_CONTEXT.getKey()) + && entry.getValue() != null && !entry.getKey().isEmpty()) { + return entry.getValue(); + } + @SuppressWarnings("removal") + Property TABLE_CLASSPATH = Property.TABLE_CLASSPATH; + if (entry.getKey().equals(TABLE_CLASSPATH.getKey())) { + // don't return even if this is set; instead, + // keep looking, in case we find the newer property set + tableContext = entry.getValue(); + if (tableContext != null && !tableContext.isEmpty()) { + log.warn("Deprecated table context property detected. '{}' should be replaced by '{}'", + TABLE_CLASSPATH.getKey(), Property.TABLE_CLASSLOADER_CONTEXT.getKey()); + } } - classloader = ContextClassLoaders.getContextClassLoaderFactory().getClassLoader(tableContext); - } else { - classloader = AccumuloVFSClassLoader.getClassLoader(); } - return classloader; + return tableContext; } @Override @@ -774,11 +786,10 @@ public class Shell extends ShellOptions implements KeywordExecutable { } printException(e); } catch (ParseException e) { - // not really an error if the exception is a missing required - // option when the user is asking for help - if (!(e instanceof MissingOptionException - && (Arrays.asList(fields).contains("-" + helpOption) - || Arrays.asList(fields).contains("--" + helpLongOption)))) { + if (e instanceof MissingOptionException && Stream.of(fields).anyMatch(IS_HELP_OPT)) { + // not really an error if the exception shows a required option is missing + // and the user is asking for help + } else { ++exitCode; printException(e); } diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/ClasspathCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/ClasspathCommand.java index 165da34..d0195b1 100644 --- a/shell/src/main/java/org/apache/accumulo/shell/commands/ClasspathCommand.java +++ b/shell/src/main/java/org/apache/accumulo/shell/commands/ClasspathCommand.java @@ -23,16 +23,16 @@ import java.io.UncheckedIOException; import org.apache.accumulo.shell.Shell; import org.apache.accumulo.shell.Shell.Command; -import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; import org.apache.commons.cli.CommandLine; import jline.console.ConsoleReader; public class ClasspathCommand extends Command { + @SuppressWarnings("deprecation") @Override public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) { final ConsoleReader reader = shellState.getReader(); - AccumuloVFSClassLoader.printClassPath(s -> { + org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader.printClassPath(s -> { try { reader.print(s); } catch (IOException ex) { diff --git a/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java b/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java index 986f24b..8f5fe5f 100644 --- a/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java +++ b/shell/src/main/java/org/apache/accumulo/shell/commands/ScanCommand.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Map.Entry; import java.util.concurrent.TimeUnit; +import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.IteratorSetting; @@ -50,7 +51,6 @@ import org.apache.accumulo.shell.Shell.PrintFile; import org.apache.accumulo.shell.ShellCommandException; import org.apache.accumulo.shell.ShellCommandException.ErrorCode; import org.apache.accumulo.shell.ShellUtil; -import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; @@ -223,13 +223,13 @@ public class ScanCommand extends Command { Shell.log .warn("Scan Interpreter option is deprecated and will be removed in a future version."); - clazz = AccumuloVFSClassLoader.loadClass(cl.getOptionValue(interpreterOpt.getOpt()), + clazz = ClassLoaderUtil.loadClass(cl.getOptionValue(interpreterOpt.getOpt()), ScanInterpreter.class); } else if (cl.hasOption(formatterInterpeterOpt.getOpt())) { Shell.log .warn("Scan Interpreter option is deprecated and will be removed in a future version."); - clazz = AccumuloVFSClassLoader.loadClass(cl.getOptionValue(formatterInterpeterOpt.getOpt()), + clazz = ClassLoaderUtil.loadClass(cl.getOptionValue(formatterInterpeterOpt.getOpt()), ScanInterpreter.class); } } catch (ClassNotFoundException e) { @@ -398,8 +398,8 @@ public class ScanCommand extends Command { o.addOption(interpreterOpt); o.addOption(formatterInterpeterOpt); o.addOption(timeoutOption); - if (Arrays.asList(new String[] {ScanCommand.class.getName(), GrepCommand.class.getName(), - EGrepCommand.class.getName()}).contains(this.getClass().getName())) { + if (Arrays.asList(ScanCommand.class.getName(), GrepCommand.class.getName(), + EGrepCommand.class.getName()).contains(this.getClass().getName())) { // supported subclasses must handle the output file option properly // only add this option to commands which handle it correctly o.addOption(outputFileOpt); diff --git a/shell/src/test/java/org/apache/accumulo/shell/commands/SetIterCommandTest.java b/shell/src/test/java/org/apache/accumulo/shell/commands/SetIterCommandTest.java index 169ae78..3e41020 100644 --- a/shell/src/test/java/org/apache/accumulo/shell/commands/SetIterCommandTest.java +++ b/shell/src/test/java/org/apache/accumulo/shell/commands/SetIterCommandTest.java @@ -23,13 +23,13 @@ import java.io.Writer; import java.lang.reflect.Field; import java.util.EnumSet; +import org.apache.accumulo.core.classloader.ClassLoaderUtil; import org.apache.accumulo.core.client.AccumuloClient; import org.apache.accumulo.core.client.IteratorSetting; import org.apache.accumulo.core.client.admin.TableOperations; import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; import org.apache.accumulo.core.iterators.SortedKeyValueIterator; import org.apache.accumulo.shell.Shell; -import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader; import org.apache.commons.cli.CommandLine; import org.easymock.EasyMock; import org.junit.Before; @@ -76,7 +76,7 @@ public class SetIterCommandTest { // Loading the class EasyMock.expect(shellState.getClassLoader(cli, shellState)) - .andReturn(AccumuloVFSClassLoader.getClassLoader()); + .andReturn(ClassLoaderUtil.getClassLoader(null)); // Set the output object Field field = reader.getClass().getSuperclass().getDeclaredField("out"); diff --git a/start/src/main/java/org/apache/accumulo/start/Main.java b/start/src/main/java/org/apache/accumulo/start/Main.java index 6e04a72..f48f4ee 100644 --- a/start/src/main/java/org/apache/accumulo/start/Main.java +++ b/start/src/main/java/org/apache/accumulo/start/Main.java @@ -29,7 +29,6 @@ import java.util.ServiceLoader; import java.util.TreeMap; import java.util.TreeSet; -import org.apache.accumulo.start.classloader.AccumuloClassLoader; import org.apache.accumulo.start.spi.KeywordExecutable; import org.apache.accumulo.start.spi.KeywordExecutable.UsageGroup; import org.slf4j.Logger; @@ -49,8 +48,10 @@ public class Main { ClassLoader loader = getClassLoader(); Class<?> confClass = null; try { - confClass = - AccumuloClassLoader.getClassLoader().loadClass("org.apache.hadoop.conf.Configuration"); + @SuppressWarnings("deprecation") + var deprecatedConfClass = org.apache.accumulo.start.classloader.AccumuloClassLoader + .getClassLoader().loadClass("org.apache.hadoop.conf.Configuration"); + confClass = deprecatedConfClass; } catch (ClassNotFoundException e) { log.error("Unable to find Hadoop Configuration class on classpath, check configuration.", e); @@ -113,11 +114,13 @@ public class Main { return classLoader; } - public static synchronized Class<?> getVFSClassLoader() + @Deprecated + private static synchronized Class<?> getVFSClassLoader() throws IOException, ClassNotFoundException { if (vfsClassLoader == null) { - Thread.currentThread().setContextClassLoader(AccumuloClassLoader.getClassLoader()); - vfsClassLoader = AccumuloClassLoader.getClassLoader() + Thread.currentThread().setContextClassLoader( + org.apache.accumulo.start.classloader.AccumuloClassLoader.getClassLoader()); + vfsClassLoader = org.apache.accumulo.start.classloader.AccumuloClassLoader.getClassLoader() .loadClass("org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader"); } return vfsClassLoader; diff --git a/start/src/main/java/org/apache/accumulo/start/classloader/AccumuloClassLoader.java b/start/src/main/java/org/apache/accumulo/start/classloader/AccumuloClassLoader.java index 3dd5bdc..77b4b0c 100644 --- a/start/src/main/java/org/apache/accumulo/start/classloader/AccumuloClassLoader.java +++ b/start/src/main/java/org/apache/accumulo/start/classloader/AccumuloClassLoader.java @@ -39,7 +39,7 @@ import org.slf4j.LoggerFactory; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -@Deprecated(since = "2.1.0", forRemoval = true) +@Deprecated public class AccumuloClassLoader { public static final String GENERAL_CLASSPATHS = "general.classpaths"; diff --git a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/AccumuloReloadingVFSClassLoader.java b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/AccumuloReloadingVFSClassLoader.java index 3c1904c..39a2fda 100644 --- a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/AccumuloReloadingVFSClassLoader.java +++ b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/AccumuloReloadingVFSClassLoader.java @@ -45,7 +45,7 @@ import org.slf4j.LoggerFactory; * changes in any of the files/directories that are in the classpath and will recreate the delegate * object if there is any change in the classpath. */ -@Deprecated(since = "2.1.0", forRemoval = true) +@Deprecated public class AccumuloReloadingVFSClassLoader implements FileListener, ReloadingClassLoader { private static final Logger log = LoggerFactory.getLogger(AccumuloReloadingVFSClassLoader.class); diff --git a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/AccumuloVFSClassLoader.java b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/AccumuloVFSClassLoader.java index e1a9a1f..4a1390a 100644 --- a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/AccumuloVFSClassLoader.java +++ b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/AccumuloVFSClassLoader.java @@ -20,6 +20,7 @@ package org.apache.accumulo.start.classloader.vfs; import java.io.File; import java.io.IOException; +import java.io.UncheckedIOException; import java.lang.management.ManagementFactory; import java.lang.ref.WeakReference; import java.net.URL; @@ -27,6 +28,9 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; import org.apache.accumulo.start.classloader.AccumuloClassLoader; import org.apache.commons.io.FileUtils; @@ -68,7 +72,7 @@ import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; * Used to load jar dynamically. * </pre> */ -@Deprecated(since = "2.1.0", forRemoval = true) +@Deprecated public class AccumuloVFSClassLoader { public static class AccumuloVFSClassLoaderShutdownThread implements Runnable { @@ -110,19 +114,6 @@ public class AccumuloVFSClassLoader { Runtime.getRuntime().addShutdownHook(new Thread(new AccumuloVFSClassLoaderShutdownThread())); } - public static synchronized <U> Class<? extends U> loadClass(String classname, Class<U> extension) - throws ClassNotFoundException { - try { - return getClassLoader().loadClass(classname).asSubclass(extension); - } catch (IOException e) { - throw new ClassNotFoundException("IO Error loading class " + classname, e); - } - } - - public static Class<?> loadClass(String classname) throws ClassNotFoundException { - return loadClass(classname, Object.class).asSubclass(Object.class); - } - static FileObject[] resolve(FileSystemManager vfs, String uris) throws FileSystemException { return resolve(vfs, uris, new ArrayList<>()); } @@ -202,7 +193,15 @@ public class AccumuloVFSClassLoader { return new AccumuloReloadingVFSClassLoader(dynamicCPath, generateVfs(), wrapper, 1000, true); } - public static ClassLoader getClassLoader() throws IOException { + public static ClassLoader getClassLoader() { + try { + return getClassLoader_Internal(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private static ClassLoader getClassLoader_Internal() throws IOException { ReloadingClassLoader localLoader = loader; while (localLoader == null) { synchronized (lock) { @@ -397,15 +396,37 @@ public class AccumuloVFSClassLoader { } } - public static synchronized ContextManager getContextManager() throws IOException { + public static void setContextConfig(Supplier<Map<String,String>> contextConfigSupplier) { + var config = new ContextManager.DefaultContextsConfig(contextConfigSupplier); + try { + getContextManager().setContextConfig(config); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public static void removeUnusedContexts(Set<String> contextsInUse) { + try { + getContextManager().removeUnusedContexts(contextsInUse); + } catch (IOException e) { + log.warn("{}", e.getMessage(), e); + } + } + + public static ClassLoader getContextClassLoader(String context) { + try { + return getContextManager().getClassLoader(context); + } catch (IOException e) { + throw new UncheckedIOException("Error getting context class loader for context: " + context, + e); + } + } + + private static synchronized ContextManager getContextManager() throws IOException { if (contextManager == null) { getClassLoader(); contextManager = new ContextManager(generateVfs(), () -> { - try { - return getClassLoader(); - } catch (IOException e) { - throw new RuntimeException(e); - } + return getClassLoader(); }); } diff --git a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/ContextManager.java b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/ContextManager.java index b9fd161..8c4db84 100644 --- a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/ContextManager.java +++ b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/ContextManager.java @@ -23,14 +23,15 @@ import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.function.Supplier; import org.apache.commons.vfs2.FileSystemException; import org.apache.commons.vfs2.FileSystemManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@Deprecated(since = "2.1.0", forRemoval = true) -public class ContextManager { +@Deprecated +class ContextManager { private static final Logger log = LoggerFactory.getLogger(ContextManager.class); @@ -79,6 +80,7 @@ public class ContextManager { this.parent = parent; } + @Deprecated public static class ContextConfig { final String name; final String uris; @@ -112,15 +114,20 @@ public class ContextManager { ContextConfig getContextConfig(String context); } - public abstract static class DefaultContextsConfig implements ContextsConfig { + public static class DefaultContextsConfig implements ContextsConfig { - public abstract Map<String,String> getVfsContextClasspathProperties(); + private final Supplier<Map<String,String>> vfsContextClasspathPropertiesProvider; + + public DefaultContextsConfig( + Supplier<Map<String,String>> vfsContextClasspathPropertiesProvider) { + this.vfsContextClasspathPropertiesProvider = vfsContextClasspathPropertiesProvider; + } @Override public ContextConfig getContextConfig(String context) { String prop = AccumuloVFSClassLoader.VFS_CONTEXT_CLASSPATH_PROPERTY + context; - Map<String,String> props = getVfsContextClasspathProperties(); + Map<String,String> props = vfsContextClasspathPropertiesProvider.get(); String uris = props.get(prop); diff --git a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/PostDelegatingVFSClassLoader.java b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/PostDelegatingVFSClassLoader.java index 0eb2ef6..4fed6cd 100644 --- a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/PostDelegatingVFSClassLoader.java +++ b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/PostDelegatingVFSClassLoader.java @@ -23,7 +23,7 @@ import org.apache.commons.vfs2.FileSystemException; import org.apache.commons.vfs2.FileSystemManager; import org.apache.commons.vfs2.impl.VFSClassLoader; -@Deprecated(since = "2.1.0", forRemoval = true) +@Deprecated public class PostDelegatingVFSClassLoader extends VFSClassLoader { public PostDelegatingVFSClassLoader(FileObject[] files, FileSystemManager manager, diff --git a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/ReloadingClassLoader.java b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/ReloadingClassLoader.java index 8dae67e..ac1b807 100644 --- a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/ReloadingClassLoader.java +++ b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/ReloadingClassLoader.java @@ -18,7 +18,7 @@ */ package org.apache.accumulo.start.classloader.vfs; -@Deprecated(since = "2.1.0", forRemoval = true) +@Deprecated public interface ReloadingClassLoader { ClassLoader getClassLoader(); } diff --git a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/UniqueFileReplicator.java b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/UniqueFileReplicator.java index c23bda0..e75d6c2 100644 --- a/start/src/main/java/org/apache/accumulo/start/classloader/vfs/UniqueFileReplicator.java +++ b/start/src/main/java/org/apache/accumulo/start/classloader/vfs/UniqueFileReplicator.java @@ -37,7 +37,7 @@ import org.slf4j.LoggerFactory; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -@Deprecated(since = "2.1.0", forRemoval = true) +@Deprecated public class UniqueFileReplicator implements VfsComponent, FileReplicator { private static final char[] TMP_RESERVED_CHARS = diff --git a/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloClasspathTest.java b/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloClasspathTest.java index fe46cad..c1e5e2f 100644 --- a/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloClasspathTest.java +++ b/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloClasspathTest.java @@ -18,7 +18,6 @@ */ package org.apache.accumulo.start.classloader.vfs; -import static org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader.getClassPath; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -48,4 +47,9 @@ public class AccumuloClasspathTest { assertFalse(getClassPath(false).contains("app")); assertFalse(getClassPath(false).contains("Level")); } + + @SuppressWarnings("deprecation") + private String getClassPath(boolean b) { + return org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader.getClassPath(b); + } } diff --git a/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloReloadingVFSClassLoaderTest.java b/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloReloadingVFSClassLoaderTest.java index 4c434b5..50206f3 100644 --- a/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloReloadingVFSClassLoaderTest.java +++ b/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloReloadingVFSClassLoaderTest.java @@ -38,6 +38,7 @@ import org.junit.rules.TemporaryFolder; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +@Deprecated @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "paths not set by user input") public class AccumuloReloadingVFSClassLoaderTest { diff --git a/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloVFSClassLoaderTest.java b/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloVFSClassLoaderTest.java index 52b143a..93c97b3 100644 --- a/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloVFSClassLoaderTest.java +++ b/start/src/test/java/org/apache/accumulo/start/classloader/vfs/AccumuloVFSClassLoaderTest.java @@ -43,6 +43,8 @@ import org.powermock.reflect.Whitebox; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +@SuppressWarnings("deprecation") +@Deprecated @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "paths not set by user input") @RunWith(PowerMockRunner.class) @PrepareForTest(AccumuloVFSClassLoader.class) diff --git a/start/src/test/java/org/apache/accumulo/start/classloader/vfs/ContextManagerTest.java b/start/src/test/java/org/apache/accumulo/start/classloader/vfs/ContextManagerTest.java index 0794ecf..636a16c 100644 --- a/start/src/test/java/org/apache/accumulo/start/classloader/vfs/ContextManagerTest.java +++ b/start/src/test/java/org/apache/accumulo/start/classloader/vfs/ContextManagerTest.java @@ -27,7 +27,6 @@ import static org.junit.Assert.assertSame; import java.io.File; import java.util.HashSet; -import org.apache.accumulo.start.classloader.vfs.ContextManager.ContextConfig; import org.apache.commons.io.FileUtils; import org.apache.commons.vfs2.FileObject; import org.apache.commons.vfs2.FileSystemException; @@ -40,6 +39,7 @@ import org.junit.rules.TemporaryFolder; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +@Deprecated @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN", justification = "paths not set by user input") public class ContextManagerTest { @@ -97,9 +97,9 @@ public class ContextManagerTest { cm.setContextConfig(context -> { if (context.equals("CX1")) { - return new ContextConfig("CX1", uri1, true); + return new ContextManager.ContextConfig("CX1", uri1, true); } else if (context.equals("CX2")) { - return new ContextConfig("CX2", uri2, true); + return new ContextManager.ContextConfig("CX2", uri2, true); } return null; }); @@ -139,9 +139,9 @@ public class ContextManagerTest { cm.setContextConfig(context -> { if (context.equals("CX1")) { - return new ContextConfig("CX1", uri1.toString(), true); + return new ContextManager.ContextConfig("CX1", uri1.toString(), true); } else if (context.equals("CX2")) { - return new ContextConfig("CX2", uri2.toString(), false); + return new ContextManager.ContextConfig("CX2", uri2.toString(), false); } return null; }); diff --git a/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java b/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java index 1631f50..c33d354 100644 --- a/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java +++ b/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java @@ -122,6 +122,11 @@ import jline.console.ConsoleReader; @Category({MiniClusterOnlyTests.class, SunnyDayTests.class}) public class ShellServerIT extends SharedMiniClusterBase { + + @SuppressWarnings("removal") + private static final Property VFS_CONTEXT_CLASSPATH_PROPERTY = + Property.VFS_CONTEXT_CLASSPATH_PROPERTY; + public static class TestOutputStream extends OutputStream { StringBuilder sb = new StringBuilder(); @@ -1667,11 +1672,12 @@ public class ShellServerIT extends SharedMiniClusterBase { fooConstraintJar); fooConstraintJar.deleteOnExit(); - ts.exec("config -s " + Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "cx1=" - + fooFilterJar.toURI() + "," + fooConstraintJar.toURI(), true); + ts.exec("config -s " + VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "cx1=" + fooFilterJar.toURI() + + "," + fooConstraintJar.toURI(), true); ts.exec("createtable " + table, true); - ts.exec("config -t " + table + " -s " + Property.TABLE_CLASSPATH.getKey() + "=cx1", true); + ts.exec("config -t " + table + " -s " + Property.TABLE_CLASSLOADER_CONTEXT.getKey() + "=cx1", + true); sleepUninterruptibly(200, TimeUnit.MILLISECONDS); @@ -1697,7 +1703,7 @@ public class ShellServerIT extends SharedMiniClusterBase { ts.exec("insert ok foo q v", true); ts.exec("deletetable -f " + table, true); - ts.exec("config -d " + Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "cx1"); + ts.exec("config -d " + VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "cx1"); } @@ -1842,15 +1848,15 @@ public class ShellServerIT extends SharedMiniClusterBase { make10(); setupFakeContextPath(); // Add the context to the table so that setiter works. - result = ts.exec("config -s " + Property.VFS_CONTEXT_CLASSPATH_PROPERTY + FAKE_CONTEXT + "=" + result = ts.exec("config -s " + VFS_CONTEXT_CLASSPATH_PROPERTY + FAKE_CONTEXT + "=" + FAKE_CONTEXT_CLASSPATH); - assertEquals("root@miniInstance t> config -s " + Property.VFS_CONTEXT_CLASSPATH_PROPERTY - + FAKE_CONTEXT + "=" + FAKE_CONTEXT_CLASSPATH + "\n", result); + assertEquals("root@miniInstance t> config -s " + VFS_CONTEXT_CLASSPATH_PROPERTY + FAKE_CONTEXT + + "=" + FAKE_CONTEXT_CLASSPATH + "\n", result); - result = ts.exec("config -t t -s table.classpath.context=" + FAKE_CONTEXT); - assertEquals( - "root@miniInstance t> config -t t -s table.classpath.context=" + FAKE_CONTEXT + "\n", - result); + result = ts + .exec("config -t t -s " + Property.TABLE_CLASSLOADER_CONTEXT.getKey() + "=" + FAKE_CONTEXT); + assertEquals("root@miniInstance t> config -t t -s " + + Property.TABLE_CLASSLOADER_CONTEXT.getKey() + "=" + FAKE_CONTEXT + "\n", result); result = ts.exec("setshelliter -pn baz -n reverse -p 21 -class " + VALUE_REVERSING_ITERATOR); assertTrue(result.contains("The iterator class does not implement OptionDescriber")); @@ -1877,10 +1883,10 @@ public class ShellServerIT extends SharedMiniClusterBase { setupRealContextPath(); // Define a new classloader context, but don't set it on the table - result = ts.exec("config -s " + Property.VFS_CONTEXT_CLASSPATH_PROPERTY + REAL_CONTEXT + "=" + result = ts.exec("config -s " + VFS_CONTEXT_CLASSPATH_PROPERTY + REAL_CONTEXT + "=" + REAL_CONTEXT_CLASSPATH); - assertEquals("root@miniInstance t> config -s " + Property.VFS_CONTEXT_CLASSPATH_PROPERTY - + REAL_CONTEXT + "=" + REAL_CONTEXT_CLASSPATH + "\n", result); + assertEquals("root@miniInstance t> config -s " + VFS_CONTEXT_CLASSPATH_PROPERTY + REAL_CONTEXT + + "=" + REAL_CONTEXT_CLASSPATH + "\n", result); // Override the table classloader context with the REAL implementation of // ValueReversingIterator, which does reverse the value. result = ts.exec("scan -pn baz -np -b row1 -e row1 -cc " + REAL_CONTEXT); diff --git a/test/src/main/java/org/apache/accumulo/test/UserCompactionStrategyIT.java b/test/src/main/java/org/apache/accumulo/test/UserCompactionStrategyIT.java index ed198f7..b8dbe11 100644 --- a/test/src/main/java/org/apache/accumulo/test/UserCompactionStrategyIT.java +++ b/test/src/main/java/org/apache/accumulo/test/UserCompactionStrategyIT.java @@ -164,7 +164,8 @@ public class UserCompactionStrategyIT extends AccumuloClusterHarness { c.tableOperations().create(tableName); c.instanceOperations().setProperty( Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "context1", destFile.toString()); - c.tableOperations().setProperty(tableName, Property.TABLE_CLASSPATH.getKey(), "context1"); + c.tableOperations().setProperty(tableName, Property.TABLE_CLASSLOADER_CONTEXT.getKey(), + "context1"); c.tableOperations().addSplits(tableName, new TreeSet<>(Arrays.asList(new Text("efg")))); diff --git a/test/src/main/java/org/apache/accumulo/test/functional/ConfigurableCompactionIT.java b/test/src/main/java/org/apache/accumulo/test/functional/ConfigurableCompactionIT.java index 9efca32..155b214 100644 --- a/test/src/main/java/org/apache/accumulo/test/functional/ConfigurableCompactionIT.java +++ b/test/src/main/java/org/apache/accumulo/test/functional/ConfigurableCompactionIT.java @@ -121,7 +121,7 @@ public class ConfigurableCompactionIT extends ConfigurableMacBase { Property.VFS_CONTEXT_CLASSPATH_PROPERTY.getKey() + "context1", destFile.toString()); Map<String,String> props = new HashMap<>(); props.put(Property.TABLE_MAJC_RATIO.getKey(), "10"); - props.put(Property.TABLE_CLASSPATH.getKey(), "context1"); + props.put(Property.TABLE_CLASSLOADER_CONTEXT.getKey(), "context1"); // EfgCompactionStrat will only compact a tablet w/ end row of 'efg'. No other tablets are // compacted. props.put(Property.TABLE_COMPACTION_STRATEGY.getKey(), diff --git a/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java b/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java index fb41529..beb9fd6 100644 --- a/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java +++ b/test/src/main/java/org/apache/accumulo/test/functional/ScannerContextIT.java @@ -52,7 +52,10 @@ import org.junit.Test; public class ScannerContextIT extends AccumuloClusterHarness { private static final String CONTEXT = ScannerContextIT.class.getSimpleName(); - private static final String CONTEXT_PROPERTY = Property.VFS_CONTEXT_CLASSPATH_PROPERTY + CONTEXT; + @SuppressWarnings("removal") + private static final Property VFS_CONTEXT_CLASSPATH_PROPERTY = + Property.VFS_CONTEXT_CLASSPATH_PROPERTY; + private static final String CONTEXT_PROPERTY = VFS_CONTEXT_CLASSPATH_PROPERTY + CONTEXT; private static final String CONTEXT_DIR = "file://" + System.getProperty("user.dir") + "/target"; private static final String CONTEXT_CLASSPATH = CONTEXT_DIR + "/Test.jar"; private static int ITERATIONS = 10; @@ -140,7 +143,7 @@ public class ScannerContextIT extends AccumuloClusterHarness { // Create two contexts FOO and ScanContextIT. The FOO context will point to a classpath // that contains nothing. The ScanContextIT context will point to the test iterators jar String tableContext = "FOO"; - String tableContextProperty = Property.VFS_CONTEXT_CLASSPATH_PROPERTY + tableContext; + String tableContextProperty = VFS_CONTEXT_CLASSPATH_PROPERTY + tableContext; String tableContextDir = "file://" + System.getProperty("user.dir") + "/target"; String tableContextClasspath = tableContextDir + "/TestFoo.jar"; // Define both contexts @@ -150,7 +153,8 @@ public class ScannerContextIT extends AccumuloClusterHarness { String tableName = getUniqueNames(1)[0]; c.tableOperations().create(tableName); // Set the FOO context on the table - c.tableOperations().setProperty(tableName, Property.TABLE_CLASSPATH.getKey(), tableContext); + c.tableOperations().setProperty(tableName, Property.TABLE_CLASSLOADER_CONTEXT.getKey(), + tableContext); try (BatchWriter bw = c.createBatchWriter(tableName)) { for (int i = 0; i < ITERATIONS; i++) { Mutation m = new Mutation("row" + i);