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-classloaders.git
The following commit(s) were added to refs/heads/main by this push:
new 21626c0 Prepare to release CachingClassLoaderFactory (#71)
21626c0 is described below
commit 21626c06236d6a96ed0c53ef7fc9c38c3d449a9a
Author: Christopher Tubbs <[email protected]>
AuthorDate: Fri Feb 13 14:04:12 2026 -0500
Prepare to release CachingClassLoaderFactory (#71)
* Prevent deployment of example jars
* Add index to top level README
* Fix title in hdfs URL provider README
* Remove VFS factory (keep historical reference in README)
---
README.md | 36 +
modules/example-iterators-a/pom.xml | 3 +
modules/example-iterators-b/pom.xml | 3 +
modules/hdfs-urlstreamhandler-provider/README.md | 2 +-
modules/vfs-class-loader/.gitignore | 36 -
modules/vfs-class-loader/LICENSE | 201 ------
modules/vfs-class-loader/README.md | 76 --
modules/vfs-class-loader/TESTING.md | 272 -------
modules/vfs-class-loader/pom.xml | 180 -----
.../classloader/vfs/AccumuloVFSClassLoader.java | 801 ---------------------
.../accumulo/classloader/vfs/ClassPathPrinter.java | 132 ----
.../classloader/vfs/UniqueFileReplicator.java | 115 ---
.../classloader/vfs/VFSClassLoaderWrapper.java | 87 ---
.../accumulo/classloader/vfs/VFSManager.java | 225 ------
.../ReloadingVFSContextClassLoaderFactory.java | 368 ----------
.../accumulo/classloader/vfs/AccumuloDFSBase.java | 172 -----
.../vfs/AccumuloVFSClassLoaderTest.java | 87 ---
.../classloader/vfs/ClassPathPrinterTest.java | 75 --
.../classloader/vfs/VfsClassLoaderTest.java | 180 -----
.../ReloadingVFSContextClassLoaderFactoryTest.java | 256 -------
.../src/test/java/test/HelloWorldTemplate | 27 -
.../vfs-class-loader/src/test/java/test/Test.java | 27 -
.../src/test/java/test/TestTemplate | 36 -
.../src/test/resources/log4j2-test.properties | 35 -
.../src/test/shell/makeHelloWorldJars.sh | 35 -
.../src/test/shell/makeTestJars.sh | 32 -
.../new-context-configuration.json | 20 -
pom.xml | 1 -
28 files changed, 43 insertions(+), 3477 deletions(-)
diff --git a/README.md b/README.md
index ed514ef..9441cd1 100644
--- a/README.md
+++ b/README.md
@@ -20,3 +20,39 @@
-->
# Apache Accumulo Classloader Extras
+This repository contains a variety of Java classloader-related utilities, or
+libraries to support those utilities, for use with Apache Accumulo.
+
+### CachingClassLoaderFactory
+
+An implementation of Accumulo's [ContextClassLoaderFactory][spi] that
+downloads, verifies, and locally caches classloader resources using a manifest
+file at a specified URL, which itself contained a listing of resource URLs to
+download, and corresponding checksums to verify their contents.
+
+See
[modules/caching-class-loader/README.md](modules/caching-class-loader/README.md).
+
+### HdfsURLStreamHandlerProvider
+
+An implementation of [URLStreamHandlerProvider][urlprovider] that supports the
+`hdfs://` URL scheme, written to support using [HDFS][hadoop] for remote
+resource locations in the
+[CachingClassLoaderFactory](#CachingClassLoaderFactory), because that project
+does not currently implement such a provider.
+
+See
[modules/hdfs-urlstreamhandler-provider/README.md](modules/hdfs-urlstreamhandler-provider/README.md).
+
+### VFS ClassLoaderFactory (Legacy)
+
+An experimental implementation of Accumulo's [ContextClassLoaderFactory][spi]
+was developed in `modules/vfs-class-loader` in commit
+2c3eb3b18d30d9fa18d744584c4595e4b4ffca9f, but was subsequently removed. It
+supported using classpaths containing remote URLs, and used Apache commons-vfs2
+to interpret remote locations as filesystems containing resource files. Loading
+classes from VFS this way can be prone to substantial errors, and it is not
+recommended.
+
+
+[spi]:
https://accumulo.apache.org/docs/2.x/apidocs/org/apache/accumulo/core/spi/common/ContextClassLoaderFactory.html
+[urlprovider]:
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/spi/URLStreamHandlerProvider.html
+[hadoop]: https://hadoop.apache.org
diff --git a/modules/example-iterators-a/pom.xml
b/modules/example-iterators-a/pom.xml
index aa2a192..137c4cd 100644
--- a/modules/example-iterators-a/pom.xml
+++ b/modules/example-iterators-a/pom.xml
@@ -28,6 +28,9 @@
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>example-iterators-a</artifactId>
+ <properties>
+ <maven.deploy.skip>releases</maven.deploy.skip>
+ </properties>
<dependencies>
<dependency>
<!-- provided by accumulo -->
diff --git a/modules/example-iterators-b/pom.xml
b/modules/example-iterators-b/pom.xml
index c923949..bd8dcd2 100644
--- a/modules/example-iterators-b/pom.xml
+++ b/modules/example-iterators-b/pom.xml
@@ -28,6 +28,9 @@
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>example-iterators-b</artifactId>
+ <properties>
+ <maven.deploy.skip>releases</maven.deploy.skip>
+ </properties>
<dependencies>
<dependency>
<!-- provided by accumulo -->
diff --git a/modules/hdfs-urlstreamhandler-provider/README.md
b/modules/hdfs-urlstreamhandler-provider/README.md
index a3b27ea..50f3dc9 100644
--- a/modules/hdfs-urlstreamhandler-provider/README.md
+++ b/modules/hdfs-urlstreamhandler-provider/README.md
@@ -18,7 +18,7 @@
under the License.
-->
-# URLStreamHandlerProvider
+# HdfsURLStreamHandlerProvider
This library contains a single class that implements
[URLStreamHandlerProvider][1], to provide a stream handler for `hdfs:` URL
diff --git a/modules/vfs-class-loader/.gitignore
b/modules/vfs-class-loader/.gitignore
deleted file mode 100644
index 55d7f58..0000000
--- a/modules/vfs-class-loader/.gitignore
+++ /dev/null
@@ -1,36 +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
-#
-# https://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.
-#
-
-# Maven ignores
-/target/
-
-# IDE ignores
-/.settings/
-/.project
-/.classpath
-/.pydevproject
-/.idea
-/*.iml
-/*.ipr
-/*.iws
-/nbproject/
-/nbactions.xml
-/nb-configuration.xml
-/.vscode/
-/.factorypath
diff --git a/modules/vfs-class-loader/LICENSE b/modules/vfs-class-loader/LICENSE
deleted file mode 100644
index 261eeb9..0000000
--- a/modules/vfs-class-loader/LICENSE
+++ /dev/null
@@ -1,201 +0,0 @@
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed 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.
diff --git a/modules/vfs-class-loader/README.md
b/modules/vfs-class-loader/README.md
deleted file mode 100644
index 66f2093..0000000
--- a/modules/vfs-class-loader/README.md
+++ /dev/null
@@ -1,76 +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
-
- https://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.
-
--->
-# Accumulo VFS ClassLoader
-
-This module contains a
[ClassLoader](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ClassLoader.html)
implementation that can be used as the JVM
[System](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ClassLoader.html#getSystemClassLoader())
ClassLoader or a ClassLoader for Accumulo table contexts.
-
-## System Class Loader
-
-To use this ClassLoader as the System ClassLoader you must set the JVM system
property **java.system.class.loader** to the fully qualified class name
(org.apache.accumulo.classloader.vfs.AccumuloVFSClassLoader). This jar and it's
dependent jars must be on the **java.class.path**.
-
-NOTE: When used in this manner the reloading feature is disabled because the
JVM caches classes created from the standard JVM hierarchy and thus reloading
has no effect.
-
-### Configuration
-
-To set the classpath for this ClassLoader you must define the system property
**vfs.class.loader.classpath** and set it to locations that are supported by
[Apache Commons
VFS](http://commons.apache.org/proper/commons-vfs/filesystems.html).
-
-The ClassLoader monitors the classpath for changes at 5 minute intervals. To
change this interval define the sytem property
**vfs.classpath.monitor.seconds**.
-
-This ClassLoader follows the normal parent delegation model but can be set to
load classes and resources first, before checking if the parent classloader
can, by setting the system property **vfs.class.loader.delegation** to "post".
-
-## Accumulo Table Context ClassLoader
-
-To use this ClassLoader as the ContextClassLoader you must set the JVM system
property **vfs.context.class.loader.config** to a valid JSON configuration file
and set the Accumulo configuration property
**general.context.class.loader.factory** to the fully qualified class name of
the ContextClassLoaderFactory implementation
(org.apache.accumulo.classloader.vfs.context.ReloadingVFSContextClassLoaderFactory).
This jar and it's dependent jars must be on the **java.class.path**.
-
-### Configuration
-
-You will need to define the supported contexts and their configuration in a
JSON formatted file. For example:
-
-```
-{
- "contexts": [
- {
- "name": "cx1",
- "config": {
- "classPath": "file:///tmp/foo",
- "postDelegate": true,
- "monitorIntervalMs": 30000
- }
- },
- {
- "name": "cx2",
- "config": {
- "classPath": "file:///tmp/bar",
- "postDelegate": false,
- "monitorIntervalMs": 30000
- }
- }
- ]
-}
-```
-
-## Additional Configuration
-
-Finally, this ClassLoader keeps a local cache of objects pulled from remote
systems (via http, etc.). The default location for this cache directory is the
value of the system property **java.io.tmpdir**. To change this location set
the system property **vfs.cache.dir** to an existing directory.
-
-## Implementation
-
-This ClassLoader maintains a
[VFSClassLoader](http://commons.apache.org/proper/commons-vfs/commons-vfs2/apidocs/org/apache/commons/vfs2/impl/VFSClassLoader.html)
delegate that references the classpath (as specified by
**vfs.class.loader.classpath**). The ReloadingVFSClassLoader implements
[FileListener](http://commons.apache.org/proper/commons-vfs/commons-vfs2/apidocs/org/apache/commons/vfs2/FileListener.html)
and creates a [DefaultFileMonitor](http://commons.apache.org/proper/commons-vf
[...]
diff --git a/modules/vfs-class-loader/TESTING.md
b/modules/vfs-class-loader/TESTING.md
deleted file mode 100644
index c9a4f7d..0000000
--- a/modules/vfs-class-loader/TESTING.md
+++ /dev/null
@@ -1,272 +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
-
- https://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.
-
--->
-# Setup
-
-After running `mvn clean package` add the built jars to HDFS:
-
-```
-hadoop fs -mkdir -p /iterators/legacy/foo
-hadoop fs -mkdir -p /iterators/legacy/bar
-hadoop fs -mkdir -p /iterators/new/foo
-hadoop fs -mkdir -p /iterators/new/bar
-hadoop fs -mkdir -p /iterators/system
-hadoop fs -put -f
modules/example-iterators-a/target/example-iterators-a-1.0.0-SNAPSHOT.jar
/iterators/legacy/foo/examples.jar
-hadoop fs -put -f
modules/example-iterators-a/target/example-iterators-a-1.0.0-SNAPSHOT.jar
/iterators/new/foo/examples.jar
-hadoop fs -put -f
modules/example-iterators-b/target/example-iterators-b-1.0.0-SNAPSHOT.jar
/iterators/legacy/bar/examples.jar
-hadoop fs -put -f
modules/example-iterators-b/target/example-iterators-b-1.0.0-SNAPSHOT.jar
/iterators/new/bar/examples.jar
-hadoop fs -cp -f /iterators/legacy/foo/examples.jar
/iterators/system/examples.jar
-```
-
-Copy the new class loader jar to /tmp:
-
-```
-cp
./modules/vfs-class-loader/target/vfs-reloading-classloader-1.0.0-SNAPSHOT.jar
/tmp/.
-```
-
-## Running Accumulo with new VFS ClassLoader as System ClassLoader
-
-### Configure Accumulo to use new classloader
-
-Stop Accumulo if it's running and add the following to the accumulo-env.sh:
-
-**Note:** Make sure the commons-vfs2 jar is also on the classpath as well.
This dependency was removed in Accumulo 3.0.0
-so if using that version or newer you will need to add it.
-
-```
-a. Add vfs-reloading-classloader-1.0.0-SNAPSHOT.jar to CLASSPATH
-b. (if not already on classpath) Add commons-vfs2-<version>.jar to CLASSPATH
-c. Add
"-Djava.system.class.loader=org.apache.accumulo.classloader.vfs.AccumuloVFSClassLoader"
to JAVA_OPTS
-d. Add
"-Dvfs.class.loader.classpath=hdfs://localhost:9000/iterators/system/.*" to
JAVA_OPTS
-e. Add "-Dvfs.classpath.monitor.seconds=10" to JAVA_OPTS
-e. (optional) Add "-Dvfs.class.loader.debug=true" to JAVA_OPTS
-```
-
-### Test setting iterator retrieved from jar in HDFS with System ClassLoader
-
-The goal of this test is to create a table, insert some data, and change the
value of the data using an iterator that is loaded from HDFS via the
AccumuloVFSClassLoader set up as the System ClassLoader. After setting the
iterator the value should be `foo` in subsequent scans.
-
-```
-createtable test
-insert a b c this_is_a_test
-scan
-setiter -class org.apache.accumulo.classloader.vfs.examples.ExampleIterator
-scan -t test -name example -p 100
-scan
-```
-
-## Setting scan context on table (Legacy, only works on Accumulo 2.1.0 and
older)
-
-### Define a Table Context and load the iterator class with the same name, but
different behavior
-
-In this test we will define a context name with an associated classpath. Then
we will set that context on the table. Note that
-we did not change the iterator class name, the context classloader will load a
new class with the same name. Scans performed after the context is set on the
table should return the value `bar`.
-
-a. Set Accumulo Classpath Context property:
-
-```
-config -s
general.vfs.context.classpath.cx1=hdfs://localhost:9000/iterators/legacy/bar/.*
-config -s general.vfs.context.classpath.cx1.delegation=post
-```
-
-b. Set Accumulo Table Context property:
-
-```
-config -t test -s table.classpath.context=cx1
-```
-
-c. Test context classpath iterator setting:
-
-```
-scan
-```
-
-### Testing Reloading
-
-This test will continue from the previous test and we will copy a jar over the
jar referenced in the cx1 context classpath. The legacy
AccumuloReloadingVFSClassLoader has a hard-coded filesystem monitor time of 5
minutes, so we will need to wait some number of minutes after overwriting the
jar before the scans will return the new value of `foo`.
-
-a. Copy the example-a.jar over the context-examples.jar to force a reload. The
value in the scan result should change from `bar` back to `foo`.
-
-```
-hadoop fs -rm /iterators/legacy/bar/examples.jar
-hadoop fs -cp -f /iterators/legacy/foo/examples.jar
/iterators/legacy/bar/examples2.jar
-```
-
-b. Wait 10 minutes for a reload
-
-c. Test that class loader has been updated and is returning the value 'foo'
-
-```
-scan
-```
-
-### Change the context on the table
-
-In this test we will unset the properties that we set in the previous tests.
Instead of testing reloading we are testing that changing the context will have
the same effect on the iterator class.
-
-a. Unset prior properties and define two contexts:
-
-```
-deleteiter -n example -t test -scan
-config -t test -d table.classpath.context
-config -d general.vfs.context.classpath.cx1
-config -d general.vfs.context.classpath.cx1.delegation
-config -s
general.vfs.context.classpath.cx1=hdfs://localhost:9000/iterators/new/foo/examples.jar
-config -s general.vfs.context.classpath.cx1.delegation=post
-config -s
general.vfs.context.classpath.cx2=hdfs://localhost:9000/iterators/new/bar/examples.jar
-config -s general.vfs.context.classpath.cx2.delegation=post
-```
-
-b. Set Accumulo Table Context property:
-
-```
-config -t test -s table.classpath.context=cx1
-```
-
-c. Test context classpath iterator setting:
-
-The initial scan command should return the value `this_is_a_test`. After
setting the iterator, the scan should return `foo`.
-
-```
-scan
-setiter -class org.apache.accumulo.classloader.vfs.examples.ExampleIterator
-scan -t test -name example -p 100
-scan
-```
-
-d. Change the context Table Context property:
-
-```
-config -t test -s table.classpath.context=cx2
-```
-
-e. Test Context change
-
-After the context change, the scan should return `bar`.
-
-```
-scan
-```
-
-## Setting scan context on table (Accumulo 3.0.0 and newer)
-
-For this test we will use the new ReloadingVFSContextClassLoaderFactory for
the table context classloaders.
-
-a. First, let's clean up from the prior tests (**Note:** this does not apply
if running Accumulo 3.0.0)
-
-```
-droptable -f test
-config -d general.vfs.context.classpath.cx1
-config -d general.vfs.context.classpath.cx1.delegation
-config -d general.vfs.context.classpath.cx2
-config -d general.vfs.context.classpath.cx2.delegation
-```
-
-a. Then, create a file on the local filesystem for the context configuration.
-
-```
-{
- "contexts": [
- {
- "name": "cxA",
- "config": {
- "classPath": "hdfs://localhost:9000/iterators/new/foo/.*",
- "postDelegate": true,
- "monitorIntervalMs": 10000
- }
- },
- {
- "name": "cxB",
- "config": {
- "classPath": "hdfs://localhost:9000/iterators/new/bar/.*",
- "postDelegate": true,
- "monitorIntervalMs": 10000
- }
- }
- ]
-}
-```
-
-c. Next, shutdown Accumulo and make the following changes in the accumulo
configuration. Then re-start Accumulo.
-
-```
-a. Add
"general.context.class.loader.factory=org.apache.accumulo.classloader.vfs.context.ReloadingVFSContextClassLoaderFactory"
to accumulo.properties
-b. Add "-Dvfs.context.class.loader.config=file:///path/to/config/file.json" to
JAVA_OPTS
-```
-
-### Test setting iterator retrieved from jar in HDFS with System ClassLoader
-
-If you did not remove the configuration for the new System ClassLoader, then
the following test should work as it should load the ExampleIterator class from
the System ClassLoader.
-
-a. Create the table as we did in the last test. Create a table, insert some
data, and change the value of the data using an iterator that is loaded from
HDFS via the VFSClassLoader set up as the System ClassLoader. After setting the
iterator the value should be `foo` in subsequent scans.
-
-```
-createtable test
-insert a b c this_is_a_test
-scan
-setiter -class org.apache.accumulo.classloader.vfs.examples.ExampleIterator
-scan -t test -name example -p 100
-scan
-```
-
-### Change the context on the table
-
-Change the contexts on the table to test the classes being loaded from the
different jars.
-
-a. Set the table context to cxA. The scan on the table should return the value
`foo`.
-
-**Note:** The property for the context was renamed in Accumulo 3.0.0
-
-Accumulo 3.0.0
-```
-config -t test -s table.class.loader.context=cxA
-scan
-```
-
-Accumulo 2.1.0
-```
-config -t test -s table.classpath.context=cxA
-scan
-```
-
-b. Set the table context to cxB. The scan on the table should return the value
`bar`.
-
-Accumulo 3.0.0
-```
-config -t test -s table.class.loader.context=cxB
-scan
-```
-
-Accumulo 2.1.0
-```
-config -t test -s table.classpath.context=cxB
-scan
-```
-
-### Testing Reloading
-
-Now we are going to remove the jar from the `cxB` context directory and
replace it with the jar from the `cxA` context directory.
-
-a. Test the reloading by removing the existing jar from HDFS, copy
/iterators/example-a/examples.jar to /iterators/example-b/examples2.jar and
rescan. The value from the scan should be `foo`. Note that the context set on
the table is `cxB` which returned `bar` in the previous test.
-
-NOTE: Overwriting the example-b/examples.jar does not work, it does not appear
that VFS pulls down the jar from HDFS into the local cache directory and it
continues to serve up the old class.
-
-```
-hadoop fs -rm /iterators/new/bar/examples.jar
-hadoop fs -cp -f /iterators/new/foo/examples.jar
/iterators/new/bar/examples2.jar
-scan
-```
diff --git a/modules/vfs-class-loader/pom.xml b/modules/vfs-class-loader/pom.xml
deleted file mode 100644
index e4ed0af..0000000
--- a/modules/vfs-class-loader/pom.xml
+++ /dev/null
@@ -1,180 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- 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
-
- https://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.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.accumulo</groupId>
- <artifactId>classloader-extras</artifactId>
- <version>1.0.0-SNAPSHOT</version>
- <relativePath>../../pom.xml</relativePath>
- </parent>
- <artifactId>vfs-reloading-classloader</artifactId>
- <name>classloader-extras-vfs-reloading</name>
- <dependencies>
- <dependency>
- <!-- needed for build checks, but not for runtime -->
- <groupId>com.github.spotbugs</groupId>
- <artifactId>spotbugs-annotations</artifactId>
- <optional>true</optional>
- </dependency>
- <dependency>
- <!-- no longer provided by accumulo after 2.1 -->
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-vfs2</artifactId>
- <exclusions>
- <exclusion>
- <!-- exclude this outdated hadoop client from vfs -->
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-hdfs-client</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <!-- provided by accumulo -->
- <groupId>com.google.code.gson</groupId>
- <artifactId>gson</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <!-- provided by accumulo -->
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <!-- provided by accumulo -->
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <!-- provided by accumulo -->
- <groupId>org.apache.accumulo</groupId>
- <artifactId>accumulo-core</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <!-- provided by accumulo -->
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-client-api</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <!-- provided by accumulo -->
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <!-- no longer provided by accumulo after 2.1 -->
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-vfs2-hdfs</artifactId>
- <scope>runtime</scope>
- <exclusions>
- <exclusion>
- <!-- exclude this outdated hadoop client from vfs -->
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-common</artifactId>
- </exclusion>
- <exclusion>
- <!-- exclude this outdated hadoop client from vfs -->
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-hdfs</artifactId>
- </exclusion>
- <exclusion>
- <!-- exclude this outdated hadoop client from vfs -->
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-hdfs-client</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.apache.httpcomponents.client5</groupId>
- <artifactId>httpclient5</artifactId>
- <scope>runtime</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-client-minicluster</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.logging.log4j</groupId>
- <artifactId>log4j-slf4j2-impl</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.junit.jupiter</groupId>
- <artifactId>junit-jupiter-api</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>exec-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>build-test-jars</id>
- <goals>
- <goal>exec</goal>
- </goals>
- <phase>process-test-classes</phase>
- <configuration>
- <executable>src/test/shell/makeTestJars.sh</executable>
- </configuration>
- </execution>
- <execution>
- <id>build-helloworld-jars</id>
- <goals>
- <goal>exec</goal>
- </goals>
- <phase>process-test-classes</phase>
- <configuration>
- <executable>src/test/shell/makeHelloWorldJars.sh</executable>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-dependency-plugin</artifactId>
- <executions>
- <execution>
- <id>analyze</id>
- <goals>
- <goal>analyze-only</goal>
- </goals>
- <configuration>
- <ignoredUnusedDeclaredDependencies combine.children="append">
- <!-- ignore false positive runtime dependencies -->
- <unused>org.apache.commons:commons-vfs2-hdfs:*</unused>
-
<unused>org.apache.httpcomponents.client5:httpclient5:*</unused>
- </ignoredUnusedDeclaredDependencies>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-</project>
diff --git
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/AccumuloVFSClassLoader.java
b/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/AccumuloVFSClassLoader.java
deleted file mode 100644
index db87100..0000000
---
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/AccumuloVFSClassLoader.java
+++ /dev/null
@@ -1,801 +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
- *
- * https://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.classloader.vfs;
-
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Arrays;
-import java.util.Enumeration;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.function.Consumer;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import org.apache.commons.vfs2.FileChangeEvent;
-import org.apache.commons.vfs2.FileListener;
-import org.apache.commons.vfs2.FileMonitor;
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.impl.DefaultFileMonitor;
-import org.apache.commons.vfs2.provider.hdfs.HdfsFileObject;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.fs.FileSystem;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-/**
- * <p>
- * A {@code ClassLoader} implementation that watches for changes in any of the
files/directories in
- * the classpath. When a change is noticed, this classloader will then load
the new classes in
- * subsequent calls to loadClass. This classloader supports both the normal
classloader
- * pre-delegation model and a post-delegation model. To enable the
post-delegation feature set the
- * system property <b>vfs.class.loader.delegation</b> to "post".
- *
- * <p>
- * This classloader uses the following system properties:
- *
- * <ol>
- * <li><b>vfs.cache.dir</b> - for specifying the directory to use for the
local VFS cache (default
- * is the system property <b>java.io.tmpdir</b></li>
- * <li><b>vfs.classpath.monitor.seconds</b> - for specifying the file system
monitor (default:
- * 5m)</li>
- * <li><b>vfs.class.loader.classpath</b> - for specifying the class path</li>
- * <li><b>vfs.class.loader.delegation</b> - valid values are "pre" and "post"
(default: pre)</li>
- * </ol>
- *
- * <p>
- * This class will attempt to perform substitution on any environment
variables found in the values.
- * For example, the system property <b>vfs.cache.dir</b> can be set to
<b>$HOME/cache</b>.
- */
-public class AccumuloVFSClassLoader extends ClassLoader implements Closeable,
FileListener {
-
- public static final String VFS_CLASSPATH_MONITOR_INTERVAL =
"vfs.classpath.monitor.seconds";
- public static final String VFS_CACHE_DIR_PROPERTY = "vfs.cache.dir";
- public static final String VFS_CLASSLOADER_CLASSPATH =
"vfs.class.loader.classpath";
- public static final String VFS_CLASSLOADER_DELEGATION =
"vfs.class.loader.delegation";
- public static final String VFS_CLASSLOADER_DEBUG = "vfs.class.loader.debug";
-
- private static final String VFS_CACHE_DIR_DEFAULT = "java.io.tmpdir";
-
- // set to 5 mins. The rationale behind this large time is to avoid a
tservers all asking
- // the name node for info too frequently.
- private static final long DEFAULT_TIMEOUT = TimeUnit.MINUTES.toMillis(5);
-
- private static volatile boolean DEBUG = false;
- private static String CLASSPATH = null;
- private static Boolean POST_DELEGATION = null;
- private static Long MONITOR_INTERVAL = null;
- private static volatile boolean VM_INITIALIZED = false;
-
- private volatile long maxWaitInterval = 60000;
- private volatile long maxRetries = -1;
- private volatile long sleepInterval = 1000;
- private volatile boolean vfsInitializing = false;
- private volatile boolean vfsInitialized = false;
-
- private final ReentrantReadWriteLock updateLock = new
ReentrantReadWriteLock(true);
- private final String name;
- private final String classpath;
- private final Boolean postDelegation;
- private final long monitorInterval;
- private Optional<Monitor> fileMonitor = Optional.empty();
- private FileObject[] files;
- private VFSClassLoaderWrapper cl = null;
-
- static {
- DEBUG = Boolean.parseBoolean(System.getProperty(VFS_CLASSLOADER_DEBUG,
"false"));
- CLASSPATH = getClassPathProperty();
- POST_DELEGATION = getDelegationModelProperty();
- MONITOR_INTERVAL = getMonitorIntervalProperty();
- }
-
- private static void printDebug(String msg) {
- if (!DEBUG) {
- return;
- }
- System.out.println(
- String.format("DEBUG: %d AccumuloVFSClassLoader: %s",
System.currentTimeMillis(), msg));
- }
-
- private static void printError(String msg) {
- System.err.println(
- String.format("ERROR: %d AccumuloVFSClassLoader: %s",
System.currentTimeMillis(), msg));
- }
-
- private static void printWarn(String msg) {
- System.err.println(
- String.format("WARN: %d AccumuloVFSClassLoader: %s",
System.currentTimeMillis(), msg));
- }
-
- /**
- * Get the classpath value from the environment and resolve embedded env vars
- *
- * @return classpath value
- */
- private static String getClassPathProperty() {
- String cp = System.getProperty(VFS_CLASSLOADER_CLASSPATH);
- if (null == cp || cp.isBlank()) {
- printWarn(VFS_CLASSLOADER_CLASSPATH + " system property not set, using
default of \"\"");
- cp = "";
- }
- String result = replaceEnvVars(cp, System.getenv());
- printDebug("Classpath set to: " + result);
- return result;
- }
-
- /**
- * Get the delegation model
- *
- * @return true if pre delegaion, false if post delegation
- */
- private static boolean getDelegationModelProperty() {
- String property = System.getProperty(VFS_CLASSLOADER_DELEGATION);
- boolean postDelegation = false;
- if (null != property && property.equalsIgnoreCase("post")) {
- postDelegation = true;
- }
- printDebug("ClassLoader configured for pre-delegation: " + postDelegation);
- return postDelegation;
- }
-
- /**
- * Get the directory for the VFS cache
- *
- * @return VFS cache directory
- */
- static String getVFSCacheDir() {
- // Get configuration properties from the environment variables
- String vfsCacheDir = System.getProperty(VFS_CACHE_DIR_PROPERTY);
- if (null == vfsCacheDir || vfsCacheDir.isBlank()) {
- printWarn(VFS_CACHE_DIR_PROPERTY + " system property not set, using
default of "
- + VFS_CACHE_DIR_DEFAULT);
- vfsCacheDir = System.getProperty(VFS_CACHE_DIR_DEFAULT);
- }
- String cache = replaceEnvVars(vfsCacheDir, System.getenv());
- printDebug("VFS Cache Dir set to: " + cache);
- return cache;
- }
-
- /**
- * Replace environment variables in the string with their actual value
- */
- public static String replaceEnvVars(String classpath, Map<String,String>
env) {
- Pattern envPat = Pattern.compile("\\$[A-Za-z][a-zA-Z0-9_]*");
- Matcher envMatcher = envPat.matcher(classpath);
- while (envMatcher.find(0)) {
- // name comes after the '$'
- String varName = envMatcher.group().substring(1);
- String varValue = env.get(varName);
- if (varValue == null) {
- varValue = "";
- }
- classpath = (classpath.substring(0, envMatcher.start()) + varValue
- + classpath.substring(envMatcher.end()));
- envMatcher.reset(classpath);
- }
- return classpath;
- }
-
- /**
- * Get the file system monitor interval
- *
- * @return monitor interval in ms
- */
- private static long getMonitorIntervalProperty() {
- String interval = System.getProperty(VFS_CLASSPATH_MONITOR_INTERVAL);
- if (null != interval && !interval.isBlank()) {
- try {
- return TimeUnit.SECONDS.toMillis(Long.parseLong(interval));
- } catch (NumberFormatException e) {
- printWarn(VFS_CLASSPATH_MONITOR_INTERVAL + " system property not set,
using default of "
- + DEFAULT_TIMEOUT);
- return DEFAULT_TIMEOUT;
- }
- }
- return DEFAULT_TIMEOUT;
- }
-
- private class Monitor {
-
- /**
- * This task replaces the delegate classloader with a new instance when
the filesystem has
- * changed. This will orphan the old classloader and the only references
to the old classloader
- * are from the objects that it loaded.
- */
- private final Runnable refresher = new Runnable() {
- @Override
- public void run() {
- while (!executor.isTerminating()) {
- try {
- printDebug("Recreating delegate classloader due to filesystem
change event");
- updateDelegateClassloader();
- return;
- } catch (Exception e) {
- e.printStackTrace();
- try {
- Thread.sleep(getMonitorInterval());
- } catch (InterruptedException ie) {
- ie.printStackTrace();
- }
- }
- }
- }
- };
-
- private final ThreadPoolExecutor executor;
- private final DefaultFileMonitor monitor;
-
- private Monitor(AccumuloVFSClassLoader fileMonitor) {
- BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(2);
- ThreadFactory factory = r -> {
- Thread t = new Thread(r);
- t.setDaemon(true);
- return t;
- };
- this.executor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS, queue,
factory);
- this.monitor = new DefaultFileMonitor(fileMonitor);
-
- monitor.setDelay(getMonitorInterval());
- monitor.setRecursive(false);
- monitor.start();
- printDebug("Monitor started with interval set to: " +
monitor.getDelay());
- }
-
- private FileMonitor getMonitor() {
- return this.monitor;
- }
-
- private void scheduleRefresh() {
- try {
- this.executor.execute(refresher);
- } catch (RejectedExecutionException e) {
- printDebug("Ignoring refresh request (already refreshing)");
- }
- }
-
- private void shutdown() {
- this.executor.shutdownNow();
- this.monitor.stop();
- }
-
- }
-
- public AccumuloVFSClassLoader(ClassLoader parent) {
- super(AccumuloVFSClassLoader.class.getSimpleName(), parent);
- printDebug("Parent ClassLoader: " + parent.getClass().getName());
- this.name = AccumuloVFSClassLoader.class.getSimpleName();
- this.classpath = CLASSPATH;
- this.postDelegation = POST_DELEGATION;
- this.monitorInterval = MONITOR_INTERVAL;
- }
-
- private void initializeFileSystem() {
- if (!this.vfsInitialized) {
- if (DEBUG) {
- VFSManager.enableDebug();
- }
- try {
- if (DEBUG) {
- printDebug("Creating new VFS File System");
- }
- VFSManager.initialize();
- } catch (FileSystemException e) {
- printError("Error creating FileSystem: " + e.getMessage());
- throw new RuntimeException("Problem creating VFS file system", e);
- }
- printDebug("VFS File System created.");
- }
- }
-
- protected String getClassPath() {
- return this.classpath;
- }
-
- protected boolean isPostDelegationModel() {
- printDebug("isPostDelegationModel called, returning " +
this.postDelegation);
- return this.postDelegation;
- }
-
- protected long getMonitorInterval() {
- return this.monitorInterval;
- }
-
- private void addFileToMonitor(FileObject file) throws RuntimeException {
- try {
- fileMonitor.ifPresent(u -> {
- u.getMonitor().addFile(file);
- });
- } catch (RuntimeException re) {
- if (re.getMessage().contains("files-cache")) {
- printDebug("files-cache error adding " + file.toString() + " to VFS
monitor. "
- + "There is no implementation for files-cache in VFS2");
- } else {
- printDebug("Runtime error adding " + file.toString() + " to VFS
monitor");
- }
- re.printStackTrace();
-
- throw re;
- }
- }
-
- @SuppressFBWarnings(value = "SWL_SLEEP_WITH_LOCK_HELD")
- private synchronized void updateDelegateClassloader() throws Exception {
- try {
- // Re-resolve the files on the classpath, things may have changed.
- long retries = 0;
- long currentSleepMillis = sleepInterval;
- printDebug("Looking for files on classpath: " + this.getClassPath());
- FileObject[] classpathFiles = VFSManager.resolve(this.getClassPath());
- if (classpathFiles.length == 0) {
- while (classpathFiles.length == 0 && retryPermitted(retries)) {
- try {
- printWarn("VFS path was empty. Waiting " + currentSleepMillis + "
ms to retry");
- Thread.sleep(currentSleepMillis);
- classpathFiles = VFSManager.resolve(this.getClassPath());
- retries++;
- currentSleepMillis = Math.min(maxWaitInterval, currentSleepMillis
+ sleepInterval);
- } catch (InterruptedException e) {
- printError("VFS Retry Interruped");
- e.printStackTrace();
- throw new RuntimeException(e);
- }
- }
- }
- if (classpathFiles.length == 0) {
- printError("AccumuloVFSClassLoader has no resources on classpath");
- }
- this.files = classpathFiles;
- // Remove old files from monitor
- VFSClassLoaderWrapper currentDelegate = this.cl;
- if (null != currentDelegate) {
- forEachCatchRTEs(Arrays.stream(currentDelegate.getFileObjects()), f ->
{
- removeFile(f);
- printDebug("removed from monitor: " + f.toString());
- });
- }
- // There is a chance that the listener was removed from the top level
directory or
- // its children if they were deleted within some time window. Re-add
files to be
- // monitored. The Monitor will ignore files that are already/still being
monitored.
- // forEachCatchRTEs will capture a stream of thrown exceptions.
- // and can collect them to list or reduce into one exception
- forEachCatchRTEs(Arrays.stream(this.files), f -> {
- addFileToMonitor(f);
- printDebug("now monitoring: " + f.toString());
- });
- // Create the new classloader delegate
- if (DEBUG) {
- printDebug("Rebuilding dynamic classloader using files: "
- +
Arrays.stream(this.files).map(Object::toString).collect(Collectors.joining(",")));
- }
- VFSClassLoaderWrapper newDelegate;
- var parent = getParent();
- if (!this.isPostDelegationModel()) {
- // This is the normal classloader parent delegation model
- printDebug("Creating new pre-delegating VFSClassLoaderWrapper");
- newDelegate = new VFSClassLoaderWrapper(this.files, VFSManager.get(),
parent);
- } else {
- // This delegates to the parent after we lookup locally first.
- printDebug("Creating new post-delegating VFSClassLoaderWrapper");
- newDelegate = new VFSClassLoaderWrapper(this.files, VFSManager.get(),
parent) {
- @Override
- public synchronized Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
- // Check to see if this ClassLoader has already loaded the class
- Class<?> c = this.findLoadedClass(name);
- if (c != null) {
- if (DEBUG) {
- printDebug("Returning already loaded class: " + name + "@" +
c.hashCode()
- + " from classloader: " + c.getClassLoader().hashCode());
- }
- return c;
- }
- try {
- // try finding this class here instead of parent
- Class<?> clazz = super.findClass(name);
- if (DEBUG) {
- printDebug("Returning newly loaded class: " + name + "@" +
clazz.hashCode()
- + " from classloader: " +
clazz.getClassLoader().hashCode());
- }
- return clazz;
- } catch (ClassNotFoundException e) {
- printDebug("Class " + name + " not found in classloader: " +
this.hashCode()
- + ", delegating to parent.");
- }
- printDebug("Loading class " + name + " from parent classloader");
- return super.loadClass(name, resolve);
- }
- };
- }
- updateLock.writeLock().lock();
- this.cl = newDelegate;
- printDebug("AccumuloVFSClassLoader set, hash=" + this.cl.hashCode());
- } finally {
- updateLock.writeLock().unlock();
- }
- }
-
- /**
- * Remove the file from the monitor
- *
- * @param file to remove
- * @throws RuntimeException if error
- */
- private void removeFile(FileObject file) throws RuntimeException {
- try {
- fileMonitor.ifPresent(u -> {
- u.getMonitor().removeFile(file);
- // VFS DefaultFileMonitor does not remove listener from the file on
remove
- file.getFileSystem().removeListener(file, this);
- });
- } catch (RuntimeException re) {
- printError("Error removing file from VFS cache: " + file.toString());
- re.printStackTrace();
- throw re;
- }
- }
-
- @Override
- public void fileCreated(FileChangeEvent event) throws Exception {
- printDebug(event.getFileObject().getURL().toString() + " created,
recreating classloader");
- fileMonitor.ifPresent(u -> u.scheduleRefresh());
- }
-
- @Override
- public void fileDeleted(FileChangeEvent event) throws Exception {
- printDebug(event.getFileObject().getURL().toString() + " deleted,
recreating classloader");
- fileMonitor.ifPresent(u -> u.scheduleRefresh());
- }
-
- @Override
- public void fileChanged(FileChangeEvent event) throws Exception {
- printDebug(event.getFileObject().getURL().toString() + " changed,
recreating classloader");
- fileMonitor.ifPresent(u -> u.scheduleRefresh());
- }
-
- @Override
- public void close() {
-
- if (null != this.files) {
- forEachCatchRTEs(Stream.of(this.files), f -> {
- // remove file from monitor
- removeFile(f);
- printDebug("Closing, removed file from monitoring: " + f.toString());
- });
- }
- fileMonitor.ifPresent(u -> u.shutdown());
- fileMonitor = Optional.empty();
-
- this.cl = null;
-
- }
-
- public static <T> void forEachCatchRTEs(Stream<T> stream, Consumer<T>
consumer) {
- stream.flatMap(o -> {
- try {
- consumer.accept(o);
- return null;
- } catch (RuntimeException e) {
- return Stream.of(e);
- }
- }).reduce((e1, e2) -> {
- e1.addSuppressed(e2);
- return e1;
- }).ifPresent(e -> {
- throw e;
- });
- }
-
- private boolean retryPermitted(long retries) {
- return (this.maxRetries < 0 || retries < this.maxRetries);
- }
-
- public String stringify(FileObject[] files) {
- StringBuilder sb = new StringBuilder();
- sb.append('[');
- String delim = "";
- for (FileObject file : files) {
- sb.append(delim);
- delim = ", ";
- sb.append(file.getName());
- }
- sb.append(']');
- return sb.toString();
- }
-
- /**
- * Return a reference to the delegate classloader, create a new one if
necessary
- *
- * @return reference to delegate classloader
- */
- synchronized ClassLoader getDelegateClassLoader() {
- // We cannot create the VFS file system during VM initialization,
- // we have to perform some lazy initialization here due to the fact
- // that the logging libraries (and others) make use of the ServiceLoader
- // and call ClassLoader.getSystemClassLoader() which you can't do until
- // the VM is fully initialized.
- if (!isVMInitialized() || vfsInitializing) {
- return getParent();
- } else if (!this.vfsInitialized) {
- this.vfsInitializing = true;
- printDebug("getDelegateClassLoader() initializing VFS.");
- initializeFileSystem();
- this.vfsInitialized = true;
- printDebug("getDelegateClassLoader() VFS initialized.");
- }
- if (null == this.cl) {
- try {
- if (!isSystemClassLoader()) {
- printDebug("Reloading enabled, creating monitor");
- fileMonitor = Optional.of(new Monitor(this));
- } else {
- printDebug("Reloading disabled as this is the
java.system.class.loader");
- }
- printDebug("Creating initial delegate class loader");
- updateDelegateClassloader();
- if (isSystemClassLoader()) {
- // An HDFS FileSystem and Configuration object were created for each
unique HDFS namespace
- // in the call to resolve above. The HDFS Client did us a favor and
cached these objects
- // so that the next time someone calls FileSystem.get(uri), they get
the cached object.
- // However, these objects were created not with the VFS classloader,
but the
- // classloader above it. We need to override the classloader on the
Configuration objects.
- // Ran into an issue were log recovery was being attempted and
SequenceFile$Reader was
- // trying to instantiate the key class via
WritableName.getClass(String, Configuration)
- printDebug("Setting ClassLoader on HDFS FileSystem objects");
- for (FileObject fo : this.files) {
- if (fo instanceof HdfsFileObject) {
- String uri = fo.getName().getRootURI();
- Configuration c = new Configuration(true);
- c.set(FileSystem.FS_DEFAULT_NAME_KEY, uri);
- try {
- FileSystem fs = FileSystem.get(c);
- fs.getConf().setClassLoader(cl);
- } catch (IOException e) {
- throw new RuntimeException("Error setting classloader on HDFS
FileSystem object",
- e);
- }
- }
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- throw new RuntimeException("Error creating initial delegate
classloader", e);
- }
- }
- if (this.vfsInitializing) {
- this.vfsInitializing = false;
- printDebug(ClassPathPrinter.getClassPath(this, true));
- }
- try {
- updateLock.readLock().lock();
- return this.cl;
- } finally {
- updateLock.readLock().unlock();
- }
- }
-
- @Override
- public Class<?> findClass(String name) throws ClassNotFoundException {
- ClassLoader d = getDelegateClassLoader();
- if (d instanceof VFSClassLoaderWrapper) {
- return ((VFSClassLoaderWrapper) d).findClass(name);
- } else {
- return null;
- }
- }
-
- @Override
- public URL findResource(String name) {
- ClassLoader d = getDelegateClassLoader();
- if (d instanceof VFSClassLoaderWrapper) {
- return ((VFSClassLoaderWrapper) d).findResource(name);
- } else {
- return null;
- }
- }
-
- @Override
- public Enumeration<URL> findResources(String name) throws IOException {
- ClassLoader d = getDelegateClassLoader();
- if (d instanceof VFSClassLoaderWrapper) {
- return ((VFSClassLoaderWrapper) d).findResources(name);
- } else {
- return null;
- }
- }
-
- @Override
- public Class<?> loadClass(String name, boolean resolve) throws
ClassNotFoundException {
- ClassLoader d = getDelegateClassLoader();
- if (d instanceof VFSClassLoaderWrapper) {
- return ((VFSClassLoaderWrapper) d).loadClass(name, resolve);
- } else {
- return null;
- }
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- private boolean isSystemClassLoader() {
- return ClassLoader.getSystemClassLoader().equals(this);
- }
-
- protected boolean isVMInitialized() {
- if (VM_INITIALIZED) {
- return VM_INITIALIZED;
- } else {
- // We can't call VM.isBooted() directly, but we know from
System.initPhase3() that
- // when this classloader is set via 'java.system.class.loader' that it
will be initialized,
- // then set as the Thread context classloader, then the VM is fully
initialized.
- try {
- printDebug(
- "System ClassLoader: " +
ClassLoader.getSystemClassLoader().getClass().getName());
- VM_INITIALIZED = isSystemClassLoader();
- } catch (IllegalStateException e) {
- // VM is still initializing
- VM_INITIALIZED = false;
- }
- printDebug("VM Initialized: " + VM_INITIALIZED);
- return VM_INITIALIZED;
- }
- }
-
- @Override
- public Class<?> loadClass(String name) throws ClassNotFoundException {
- return getDelegateClassLoader().loadClass(name);
- }
-
- @Override
- public URL getResource(String name) {
- return getDelegateClassLoader().getResource(name);
- }
-
- @Override
- public Enumeration<URL> getResources(String name) throws IOException {
- return getDelegateClassLoader().getResources(name);
- }
-
- @Override
- public Stream<URL> resources(String name) {
- return getDelegateClassLoader().resources(name);
- }
-
- @Override
- public InputStream getResourceAsStream(String name) {
- return getDelegateClassLoader().getResourceAsStream(name);
- }
-
- @Override
- public void setDefaultAssertionStatus(boolean enabled) {
- getDelegateClassLoader().setDefaultAssertionStatus(enabled);
- }
-
- @Override
- public void setPackageAssertionStatus(String packageName, boolean enabled) {
- getDelegateClassLoader().setPackageAssertionStatus(packageName, enabled);
- }
-
- @Override
- public void setClassAssertionStatus(String className, boolean enabled) {
- getDelegateClassLoader().setClassAssertionStatus(className, enabled);
- }
-
- @Override
- public void clearAssertionStatus() {
- getDelegateClassLoader().clearAssertionStatus();
- }
-
- public ClassLoader unwrap() {
- return getDelegateClassLoader();
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- var parent = getParent();
- if (null != parent) {
- result = prime * result + ((parent.getName() == null) ? 0 :
parent.getName().hashCode());
- }
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- AccumuloVFSClassLoader other = (AccumuloVFSClassLoader) obj;
- if (name == null) {
- if (other.name != null) {
- return false;
- }
- } else if (!name.equals(other.name)) {
- return false;
- }
- var parent = getParent();
- var otherParent = other.getParent();
- if (parent == null) {
- if (otherParent != null) {
- return false;
- }
- } else if (!parent.getName().equals(otherParent.getName())) {
- return false;
- }
- return true;
- }
-
- @Override
- public String toString() {
- StringBuilder buf = new StringBuilder();
-
- if (null != this.files) {
- for (FileObject f : files) {
- try {
- buf.append("\t").append(f.getURL()).append("\n");
- } catch (FileSystemException e) {
- printError("Error getting URL for file: " + f.toString());
- e.printStackTrace();
- }
- }
- }
- return buf.toString();
- }
-
- // VisibleForTesting intentionally not using annotation from Guava
- // because it adds unwanted dependency
- public void setMaxRetries(long maxRetries) {
- this.maxRetries = maxRetries;
- }
-
- // VisibleForTesting intentionally not using annotation from Guava
- // because it adds unwanted dependency
- @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD",
- justification = "used for tests")
- public void setVMInitializedForTests() {
- VM_INITIALIZED = true;
- }
-
- @SuppressFBWarnings(value = "ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD",
- justification = "used for tests")
- public void enableDebugForTests() {
- DEBUG = true;
- }
-}
diff --git
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/ClassPathPrinter.java
b/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/ClassPathPrinter.java
deleted file mode 100644
index de7b79d..0000000
---
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/ClassPathPrinter.java
+++ /dev/null
@@ -1,132 +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
- *
- * https://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.classloader.vfs;
-
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ArrayList;
-import java.util.Collections;
-
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.impl.VFSClassLoader;
-
-public class ClassPathPrinter {
-
- public interface Printer {
- void print(String s);
- }
-
- public static void printClassPath(ClassLoader cl, boolean debug) {
- printClassPath(cl, System.out::print, debug);
- }
-
- public static String getClassPath(ClassLoader cl, boolean debug) {
- StringBuilder cp = new StringBuilder();
- printClassPath(cl, cp::append, debug);
- return cp.toString();
- }
-
- private static void printJar(Printer out, String jarPath, boolean debug,
boolean sawFirst) {
- if (debug) {
- out.print("\t");
- }
- if (!debug && sawFirst) {
- out.print(":");
- }
- out.print(jarPath);
- if (debug) {
- out.print("\n");
- }
- }
-
- public static void printClassPath(ClassLoader cl, Printer out, boolean
debug) {
- try {
- ArrayList<ClassLoader> classloaders = new ArrayList<>();
-
- while (cl != null) {
- classloaders.add(cl);
- cl = cl.getParent();
- }
-
- Collections.reverse(classloaders);
-
- int level = 0;
-
- for (ClassLoader classLoader : classloaders) {
-
- level++;
-
- if (debug && level > 1) {
- out.print("\n");
- }
- if (!debug && level < 2) {
- continue;
- }
-
- boolean sawFirst = false;
- if (classLoader.getClass().getName().startsWith("jdk.internal")) {
- if (debug) {
- out.print("Level " + level + ": " +
classLoader.getClass().getName()
- + " configuration not inspectable.\n");
- }
- } else if (classLoader instanceof URLClassLoader) {
- if (debug) {
- out.print("Level " + level + ": URL classpath, items are:\n");
- }
- for (URL u : ((URLClassLoader) classLoader).getURLs()) {
- printJar(out, u.getFile(), debug, sawFirst);
- sawFirst = true;
- }
- } else if (classLoader instanceof AccumuloVFSClassLoader) {
- if (debug) {
- out.print("Level " + level + ": ReloadingVFSClassLoader, classpath
items are:\n");
- }
- @SuppressWarnings("resource")
- AccumuloVFSClassLoader vcl = (AccumuloVFSClassLoader) classLoader;
- ClassLoader delegate = vcl.getDelegateClassLoader();
- if (delegate instanceof VFSClassLoaderWrapper) {
- VFSClassLoaderWrapper wrapper = (VFSClassLoaderWrapper) delegate;
- for (FileObject f : wrapper.getFileObjects()) {
- printJar(out, f.getURL().getFile(), debug, sawFirst);
- sawFirst = true;
- }
- }
- } else if (classLoader instanceof VFSClassLoader) {
- if (debug) {
- out.print("Level " + level + ": VFSClassLoader, classpath items
are:\n");
- }
- VFSClassLoader vcl = (VFSClassLoader) classLoader;
- for (FileObject f : vcl.getFileObjects()) {
- printJar(out, f.getURL().getFile(), debug, sawFirst);
- sawFirst = true;
- }
- } else {
- if (debug) {
- out.print("Level " + level + ": Unknown classloader configuration "
- + classLoader.getClass() + "\n");
- }
- }
- }
- out.print("\n");
- } catch (Throwable t) {
- throw new RuntimeException(t);
- }
- }
-
-}
diff --git
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/UniqueFileReplicator.java
b/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/UniqueFileReplicator.java
deleted file mode 100644
index afae636..0000000
---
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/UniqueFileReplicator.java
+++ /dev/null
@@ -1,115 +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
- *
- * https://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.classloader.vfs;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSelector;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.provider.FileReplicator;
-import org.apache.commons.vfs2.provider.UriParser;
-import org.apache.commons.vfs2.provider.VfsComponent;
-import org.apache.commons.vfs2.provider.VfsComponentContext;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-public class UniqueFileReplicator implements VfsComponent, FileReplicator {
-
- private static final char[] TMP_RESERVED_CHARS =
- {'?', '/', '\\', ' ', '&', '"', '\'', '*', '#', ';', ':', '<', '>', '|'};
-
- private File tempDir;
- private VfsComponentContext context;
- private List<File> tmpFiles = Collections.synchronizedList(new
ArrayList<>());
-
- public UniqueFileReplicator(File tempDir) {
- this.tempDir = tempDir;
- if (!tempDir.exists() && !tempDir.mkdirs()) {
- System.out.println("Unexpected error creating directory: " +
tempDir.getAbsolutePath());
- }
- }
-
- @SuppressFBWarnings(value = "PATH_TRAVERSAL_IN",
- justification = "input files are specified by admin, not unchecked user
input")
- @Override
- public File replicateFile(FileObject srcFile, FileSelector selector) throws
FileSystemException {
- String baseName = srcFile.getName().getBaseName();
-
- try {
- if (!tempDir.exists()) {
- throw new IOException("Directory no longer exists: " +
tempDir.getAbsolutePath());
- }
- String safeBasename = UriParser.encode(baseName,
TMP_RESERVED_CHARS).replace('%', '_');
- File file = null;
- try {
- file = File.createTempFile("vfsr_", "_" + safeBasename, tempDir);
- } catch (IOException ioe) {
- throw new IOException("Error creating temp file in directory: " +
tempDir, ioe);
- }
- file.deleteOnExit();
-
- final FileObject destFile = context.toFileObject(file);
- destFile.copyFrom(srcFile, selector);
-
- return file;
- } catch (IOException e) {
- throw new FileSystemException(e);
- }
- }
-
- @Override
- public void setLogger(Log logger) {
- // nothing to do
- }
-
- @Override
- public void setContext(VfsComponentContext context) {
- this.context = context;
- }
-
- @Override
- public void init() throws FileSystemException {
-
- }
-
- @Override
- public void close() {
- synchronized (tmpFiles) {
- for (File tmpFile : tmpFiles) {
- if (!tmpFile.delete()) {
- System.out.println("File does not exist: " +
tmpFile.getAbsolutePath());
- }
- }
- }
-
- if (tempDir.exists()) {
- String[] list = tempDir.list();
- int numChildren = list == null ? 0 : list.length;
- if (numChildren == 0 && !tempDir.delete()) {
- System.out.println("Cannot delete empty directory: " +
tempDir.getAbsolutePath());
- }
- }
- }
-}
diff --git
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/VFSClassLoaderWrapper.java
b/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/VFSClassLoaderWrapper.java
deleted file mode 100644
index 8909dca..0000000
---
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/VFSClassLoaderWrapper.java
+++ /dev/null
@@ -1,87 +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
- *
- * https://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.classloader.vfs;
-
-import java.io.IOException;
-import java.net.URL;
-import java.security.CodeSource;
-import java.security.PermissionCollection;
-import java.util.Enumeration;
-
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.FileSystemManager;
-import org.apache.commons.vfs2.impl.VFSClassLoader;
-
-/**
- * This class exists to expose methods that are protected in the parent class
so that we can use
- * this in a delegate pattern
- */
-public class VFSClassLoaderWrapper extends VFSClassLoader {
-
- public VFSClassLoaderWrapper(FileObject file, FileSystemManager manager,
ClassLoader parent)
- throws FileSystemException {
- super(file, manager, parent);
- }
-
- public VFSClassLoaderWrapper(FileObject file, FileSystemManager manager)
- throws FileSystemException {
- super(file, manager);
- }
-
- public VFSClassLoaderWrapper(FileObject[] files, FileSystemManager manager,
ClassLoader parent)
- throws FileSystemException {
- super(files, manager, parent);
- }
-
- public VFSClassLoaderWrapper(FileObject[] files, FileSystemManager manager)
- throws FileSystemException {
- super(files, manager);
- }
-
- @Override
- public Class<?> findClass(String name) throws ClassNotFoundException {
- return super.findClass(name);
- }
-
- @Override
- public PermissionCollection getPermissions(CodeSource cs) {
- return super.getPermissions(cs);
- }
-
- @Override
- public URL findResource(String name) {
- return super.findResource(name);
- }
-
- @Override
- public Enumeration<URL> findResources(String name) throws IOException {
- return super.findResources(name);
- }
-
- @Override
- public Class<?> loadClass(String name, boolean resolve) throws
ClassNotFoundException {
- return super.loadClass(name, resolve);
- }
-
- @Override
- public String toString() {
- return "VFSClassLoaderWrapper (hashCode: " + this.hashCode() + ")";
- }
-}
diff --git
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/VFSManager.java
b/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/VFSManager.java
deleted file mode 100644
index eed96f3..0000000
---
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/VFSManager.java
+++ /dev/null
@@ -1,225 +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
- *
- * https://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.classloader.vfs;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.management.ManagementFactory;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.vfs2.CacheStrategy;
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.FileSystemManager;
-import org.apache.commons.vfs2.FileType;
-import org.apache.commons.vfs2.cache.SoftRefFilesCache;
-import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
-import org.apache.commons.vfs2.impl.FileContentInfoFilenameFactory;
-import org.apache.commons.vfs2.provider.FileReplicator;
-import org.apache.commons.vfs2.provider.hdfs.HdfsFileProvider;
-
-public class VFSManager {
-
- public static class AccumuloVFSManagerShutdownThread implements Runnable {
-
- @Override
- public void run() {
- try {
- VFSManager.close();
- } catch (Exception e) {
- // do nothing, we are shutting down anyway
- }
- }
- }
-
- private static final AtomicBoolean initialized = new AtomicBoolean(false);
- private static DefaultFileSystemManager VFS = null;
- private static volatile boolean DEBUG = false;
-
- static {
- // Register the shutdown hook
- Runtime.getRuntime().addShutdownHook(new Thread(new
AccumuloVFSManagerShutdownThread()));
- }
-
- public static void enableDebug() {
- DEBUG = true;
- }
-
- private static void printDebug(String msg) {
- if (!DEBUG) {
- return;
- }
- System.out.println(String.format("DEBUG: %d VFSManager: %s",
System.currentTimeMillis(), msg));
- }
-
- private static void printError(String msg) {
- System.err.println(String.format("ERROR: %d VFSManager: %s",
System.currentTimeMillis(), msg));
- }
-
- public static FileObject[] resolve(String uris) throws FileSystemException {
- return resolve(VFS, uris, new ArrayList<>());
- }
-
- static FileObject[] resolve(FileSystemManager vfs, String uris,
- ArrayList<FileObject> pathsToMonitor) throws FileSystemException {
- if (uris == null) {
- return new FileObject[0];
- }
-
- ArrayList<FileObject> classpath = new ArrayList<>();
-
- pathsToMonitor.clear();
-
- for (String path : uris.split(",")) {
-
- path = path.trim();
-
- if (path.equals("")) {
- continue;
- }
-
- path = AccumuloVFSClassLoader.replaceEnvVars(path, System.getenv());
-
- printDebug("Resolving path element: " + path);
- FileObject fo = vfs.resolveFile(path);
-
- switch (fo.getType()) {
- case FILE:
- case FOLDER:
- classpath.add(fo);
- pathsToMonitor.add(fo);
- break;
- case IMAGINARY:
- // assume its a pattern
- String pattern = fo.getName().getBaseName();
- if (fo.getParent() != null) {
- // still monitor the parent
- pathsToMonitor.add(fo.getParent());
- if (fo.getParent().getType() == FileType.FOLDER) {
- FileObject[] children = fo.getParent().getChildren();
- for (FileObject child : children) {
- if (child.getType() == FileType.FILE
- && child.getName().getBaseName().matches(pattern)) {
- classpath.add(child);
- }
- }
- } else {
- if (DEBUG) {
- printDebug("classpath entry " + fo.getParent().toString() + "
is "
- + fo.getParent().getType().toString());
- }
- }
- } else {
- if (DEBUG) {
- printDebug("ignoring classpath entry: " + fo.toString());
- }
- }
- break;
- default:
- if (DEBUG) {
- printDebug("ignoring classpath entry: " + fo.toString());
- }
- break;
- }
-
- }
-
- return classpath.toArray(new FileObject[classpath.size()]);
- }
-
- public static void initialize() throws FileSystemException {
- if (initialized.compareAndSet(false, true)) {
- VFS = new DefaultFileSystemManager();
- VFS.addProvider("res", new
org.apache.commons.vfs2.provider.res.ResourceFileProvider());
- VFS.addProvider("zip", new
org.apache.commons.vfs2.provider.zip.ZipFileProvider());
- VFS.addProvider("gz", new
org.apache.commons.vfs2.provider.gzip.GzipFileProvider());
- VFS.addProvider("ram", new
org.apache.commons.vfs2.provider.ram.RamFileProvider());
- VFS.addProvider("file",
- new
org.apache.commons.vfs2.provider.local.DefaultLocalFileProvider());
- VFS.addProvider("jar", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- VFS.addProvider("http", new
org.apache.commons.vfs2.provider.http5.Http5FileProvider());
- VFS.addProvider("https", new
org.apache.commons.vfs2.provider.http5s.Http5sFileProvider());
- VFS.addProvider("ftp", new
org.apache.commons.vfs2.provider.ftp.FtpFileProvider());
- VFS.addProvider("ftps", new
org.apache.commons.vfs2.provider.ftps.FtpsFileProvider());
- VFS.addProvider("war", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- VFS.addProvider("par", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- VFS.addProvider("ear", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- VFS.addProvider("sar", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- VFS.addProvider("ejb3", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- VFS.addProvider("tmp", new
org.apache.commons.vfs2.provider.temp.TemporaryFileProvider());
- VFS.addProvider("tar", new
org.apache.commons.vfs2.provider.tar.TarFileProvider());
- VFS.addProvider("tbz2", new
org.apache.commons.vfs2.provider.tar.TarFileProvider());
- VFS.addProvider("tgz", new
org.apache.commons.vfs2.provider.tar.TarFileProvider());
- VFS.addProvider("bz2", new
org.apache.commons.vfs2.provider.bzip2.Bzip2FileProvider());
- VFS.addProvider("hdfs", new HdfsFileProvider());
- VFS.addExtensionMap("jar", "jar");
- VFS.addExtensionMap("zip", "zip");
- VFS.addExtensionMap("gz", "gz");
- VFS.addExtensionMap("tar", "tar");
- VFS.addExtensionMap("tbz2", "tar");
- VFS.addExtensionMap("tgz", "tar");
- VFS.addExtensionMap("bz2", "bz2");
- VFS.addMimeTypeMap("application/x-tar", "tar");
- VFS.addMimeTypeMap("application/x-gzip", "gz");
- VFS.addMimeTypeMap("application/zip", "zip");
- VFS.addMimeTypeMap("application/java-archive", "jar");
- VFS.setFileContentInfoFactory(new FileContentInfoFilenameFactory());
- VFS.setFilesCache(new SoftRefFilesCache());
- File cacheDir = computeTopCacheDir();
- VFS.setReplicator(new UniqueFileReplicator(cacheDir));
- VFS.setCacheStrategy(CacheStrategy.ON_RESOLVE);
- VFS.init();
- }
- }
-
- protected static FileSystemManager get() {
- return VFS;
- }
-
- private static File computeTopCacheDir() {
- String cacheDirPath = AccumuloVFSClassLoader.getVFSCacheDir();
- String procName = ManagementFactory.getRuntimeMXBean().getName();
- return Path.of(cacheDirPath,
- "accumulo-vfs-manager-cache-" + procName + "-" +
System.getProperty("user.name", "nouser"))
- .toFile();
- }
-
- private static void close() {
- printDebug("Closing VFS instance.");
- FileReplicator replicator;
- try {
- replicator = VFS.getReplicator();
- if (replicator instanceof UniqueFileReplicator) {
- ((UniqueFileReplicator) replicator).close();
- }
- } catch (FileSystemException e) {
- printError("Error occurred closing VFS instance: " + e.getMessage());
- }
- VFS.close();
- try {
- FileUtils.deleteDirectory(computeTopCacheDir());
- } catch (IOException e) {
- printError("IOException deleting cache directory");
- e.printStackTrace();
- }
- }
-}
diff --git
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/context/ReloadingVFSContextClassLoaderFactory.java
b/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/context/ReloadingVFSContextClassLoaderFactory.java
deleted file mode 100644
index 645aca7..0000000
---
a/modules/vfs-class-loader/src/main/java/org/apache/accumulo/classloader/vfs/context/ReloadingVFSContextClassLoaderFactory.java
+++ /dev/null
@@ -1,368 +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
- *
- * https://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.classloader.vfs.context;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.apache.accumulo.classloader.vfs.AccumuloVFSClassLoader;
-import org.apache.accumulo.core.spi.common.ContextClassLoaderFactory;
-import org.apache.commons.io.FileUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.gson.Gson;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-/**
- * A ClassLoaderFactory implementation that uses an {@link
AccumuloVFSClassLoader} per defined
- * context. Configuration of this class is done with a JSON file whose
location is defined by the
- * system property <b>vfs.context.class.loader.config</b>. To use this
ClassLoaderFactory you need
- * to set the Accumulo configuration property
<b>general.context.class.loader.factory</b> to the
- * fully qualified name of this class, create a configuration file that
defines the supported
- * contexts and their configuration, and set the system property
- * <b>vfs.context.class.loader.config</b> to the location of the configuration
file.
- *
- * <p>
- * Example configuration file:
- *
- * <pre>
- * {
- * "contexts": [
- * {
- * "name": "cx1",
- * "config": {
- * "classPath": "file:///tmp/foo",
- * "postDelegate": true,
- * "monitorIntervalMs": 30000
- * }
- * },
- * {
- * "name": "cx2",
- * "config": {
- * "classPath": "file:///tmp/bar",
- * "postDelegate": false,
- * "monitorIntervalMs": 30000
- * }
- * }
- * ]
- * }
- * </pre>
- */
-public class ReloadingVFSContextClassLoaderFactory implements
ContextClassLoaderFactory {
-
- // only visible for test
- static class Contexts {
- private List<Context> contexts;
-
- List<Context> getContexts() {
- return contexts;
- }
-
- void setContexts(List<Context> contexts) {
- this.contexts = contexts;
- }
-
- @Override
- public String toString() {
- return "Contexts [contexts=" + contexts + "]";
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((contexts == null) ? 0 : contexts.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- Contexts other = (Contexts) obj;
- if (contexts == null) {
- if (other.contexts != null) {
- return false;
- }
- } else if (!contexts.equals(other.contexts)) {
- return false;
- }
- return true;
- }
- }
-
- // only visible for test
- static class Context {
- private String name;
- private ContextConfig config;
-
- String getName() {
- return name;
- }
-
- void setName(String name) {
- this.name = name;
- }
-
- ContextConfig getConfig() {
- return config;
- }
-
- void setConfig(ContextConfig config) {
- this.config = config;
- }
-
- @Override
- public String toString() {
- return "Context [name=" + name + ", config=" + config + "]";
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((config == null) ? 0 : config.hashCode());
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- Context other = (Context) obj;
- if (config == null) {
- if (other.config != null) {
- return false;
- }
- } else if (!config.equals(other.config)) {
- return false;
- }
- if (name == null) {
- if (other.name != null) {
- return false;
- }
- } else if (!name.equals(other.name)) {
- return false;
- }
- return true;
- }
- }
-
- // only visible for test
- static class ContextConfig {
- private String classPath;
- private boolean postDelegate;
- private long monitorIntervalMs;
-
- String getClassPath() {
- return classPath;
- }
-
- void setClassPath(String classPath) {
- this.classPath = AccumuloVFSClassLoader.replaceEnvVars(classPath,
System.getenv());
- }
-
- boolean getPostDelegate() {
- return postDelegate;
- }
-
- void setPostDelegate(boolean postDelegate) {
- this.postDelegate = postDelegate;
- }
-
- long getMonitorIntervalMs() {
- return monitorIntervalMs;
- }
-
- void setMonitorIntervalMs(long monitorIntervalMs) {
- this.monitorIntervalMs = monitorIntervalMs;
- }
-
- @Override
- public String toString() {
- return "ContextConfig [classPath=" + classPath + ", postDelegate=" +
postDelegate
- + ", monitorIntervalMs=" + monitorIntervalMs + "]";
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((classPath == null) ? 0 :
classPath.hashCode());
- result = prime * result + (int) (monitorIntervalMs ^ (monitorIntervalMs
>>> 32));
- result = prime * result + (postDelegate ? 1231 : 1237);
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- ContextConfig other = (ContextConfig) obj;
- if (classPath == null) {
- if (other.classPath != null) {
- return false;
- }
- } else if (!classPath.equals(other.classPath)) {
- return false;
- }
- if (monitorIntervalMs != other.monitorIntervalMs) {
- return false;
- }
- if (postDelegate != other.postDelegate) {
- return false;
- }
- return true;
- }
- }
-
- private static final Logger LOG =
- LoggerFactory.getLogger(ReloadingVFSContextClassLoaderFactory.class);
- public static final String CONFIG_LOCATION =
"vfs.context.class.loader.config";
- private static final Map<String,AccumuloVFSClassLoader> CONTEXTS = new
ConcurrentHashMap<>();
- private Contexts contextDefinitions = null;
-
- public ReloadingVFSContextClassLoaderFactory() {
- try {
- initializeContexts();
- } catch (URISyntaxException | IOException e) {
- throw new RuntimeException("Error initializing contexts", e);
- }
- }
-
- protected String getConfigFileLocation() {
- String loc = System.getProperty(CONFIG_LOCATION);
- if (null == loc || loc.isBlank()) {
- throw new RuntimeException(CONFIG_LOCATION
- + " system property must be set to use
ReloadingVFSContextClassLoaderFactory");
- }
- return loc;
- }
-
- private void initializeContexts() throws URISyntaxException, IOException {
- if (!CONTEXTS.isEmpty()) {
- LOG.debug("Contexts already initialized, skipping...");
- }
- // Properties
- String conf = getConfigFileLocation();
- File f = Path.of(new URI(conf)).toFile();
- if (!f.canRead()) {
- throw new RuntimeException("Unable to read configuration file: " + conf);
- }
- Gson g = new Gson();
- LOG.debug("Context configuration: {}", FileUtils.readFileToString(f,
"UTF-8"));
- contextDefinitions = g.fromJson(Files.newBufferedReader(f.toPath()),
Contexts.class);
- LOG.debug("Deserialized JSON: {}", contextDefinitions);
- contextDefinitions.getContexts().forEach(c -> {
- CONTEXTS.put(c.getName(), create(c));
- });
- }
-
- @SuppressFBWarnings(value = "DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED",
- justification = "Security Manager is deprecated for removal as of JDK
17")
- protected AccumuloVFSClassLoader create(Context c) {
- LOG.debug("Creating ReloadingVFSClassLoader for context: {})",
c.getName());
- return new AccumuloVFSClassLoader(
- ReloadingVFSContextClassLoaderFactory.class.getClassLoader()) {
- @Override
- protected String getClassPath() {
- return c.getConfig().getClassPath();
- }
-
- @Override
- protected boolean isPostDelegationModel() {
- LOG.debug("isPostDelegationModel called, returning {}",
c.getConfig().getPostDelegate());
- return c.getConfig().getPostDelegate();
- }
-
- @Override
- protected long getMonitorInterval() {
- return c.getConfig().getMonitorIntervalMs();
- }
-
- @Override
- protected boolean isVMInitialized() {
- // The classloader is not being set using
- // `java.system.class.loader`, so the VM is initialized.
- return true;
- }
- };
- }
-
- @Override
- public synchronized ClassLoader getClassLoader(String contextName)
- throws IllegalArgumentException {
- if (!CONTEXTS.containsKey(contextName)) {
- throw new IllegalArgumentException(
- "ReloadingVFSContextClassLoaderFactory not configured for context: "
+ contextName);
- }
- // The JVM maintains a cache of loaded classes where the key is the
ClassLoader
- // instance and the loaded Class name (see ClassLoader.findLoadedClass()).
So
- // that we can return new implementations of the same class when the
context
- // changes we need to load the class from the delegate classloader directly
- // since the delegate instance will be recreated when the context changes.
- return CONTEXTS.get(contextName).unwrap();
- }
-
- public void closeForTests() {
- CONTEXTS.forEach((k, v) -> {
- v.close();
- });
- }
-
- @Deprecated
- @Override
- protected final void finalize() {
- /*
- * unused; this is final to finalizer attacks since the constructor throws
exceptions (see
- * spotbugs CT_CONSTRUCTOR_THROW)
- */
- }
-}
diff --git
a/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/AccumuloDFSBase.java
b/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/AccumuloDFSBase.java
deleted file mode 100644
index 39e67b5..0000000
---
a/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/AccumuloDFSBase.java
+++ /dev/null
@@ -1,172 +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
- *
- * https://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.classloader.vfs;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.net.URI;
-import java.nio.file.Path;
-
-import org.apache.commons.vfs2.CacheStrategy;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.cache.SoftRefFilesCache;
-import org.apache.commons.vfs2.impl.DefaultFileReplicator;
-import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
-import org.apache.commons.vfs2.impl.FileContentInfoFilenameFactory;
-import org.apache.commons.vfs2.provider.hdfs.HdfsFileProvider;
-import org.apache.hadoop.conf.Configuration;
-import org.apache.hadoop.hdfs.DFSConfigKeys;
-import org.apache.hadoop.hdfs.MiniDFSCluster;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-
-public class AccumuloDFSBase {
-
- private static Configuration conf = null;
- private static DefaultFileSystemManager vfs = null;
- private static MiniDFSCluster cluster = null;
-
- private static URI HDFS_URI;
-
- protected static URI getHdfsUri() {
- return HDFS_URI;
- }
-
- public static String computeDatanodeDirectoryPermission() {
- // MiniDFSCluster will check the permissions on the data directories, but
does not
- // do a good job of setting them properly. We need to get the users umask
and set
- // the appropriate Hadoop property so that the data directories will be
created
- // with the correct permissions.
- try {
- Process p = Runtime.getRuntime().exec("/bin/sh -c umask");
- try (BufferedReader bri =
- new BufferedReader(new InputStreamReader(p.getInputStream(),
UTF_8))) {
- String line = bri.readLine();
- p.waitFor();
-
- if (line == null) {
- throw new IOException("umask input stream closed prematurely");
- }
- short umask = Short.parseShort(line.trim(), 8);
- // Need to set permission to 777 xor umask
- // leading zero makes java interpret as base 8
- int newPermission = 0777 ^ umask;
-
- return String.format("%03o", newPermission);
- }
- } catch (Exception e) {
- throw new RuntimeException("Error getting umask from O/S", e);
- }
- }
-
- @BeforeAll
- public static void miniDfsClusterSetup() {
- System.setProperty("java.io.tmpdir", System.getProperty("user.dir") +
"/target");
-
- // Put the MiniDFSCluster directory in the target directory
- System.setProperty("test.build.data", "target/build/test/data");
-
- // Setup HDFS
- conf = new Configuration();
- conf.set("hadoop.security.token.service.use_ip", "true");
-
- conf.set("dfs.datanode.data.dir.perm",
computeDatanodeDirectoryPermission());
- conf.setLong(DFSConfigKeys.DFS_BLOCK_SIZE_KEY, 1024 * 1024); // 1M
blocksize
-
- try {
- cluster = new MiniDFSCluster.Builder(conf).build();
- cluster.waitClusterUp();
- // We can't assume that the hostname of "localhost" will still be
"localhost" after
- // starting up the NameNode. We may get mapped into a FQDN via settings
in /etc/hosts.
- HDFS_URI = cluster.getFileSystem().getUri();
- } catch (IOException e) {
- throw new RuntimeException("Error setting up mini cluster", e);
- }
-
- // Set up the VFS
- vfs = new DefaultFileSystemManager();
- try {
- vfs.addProvider("res", new
org.apache.commons.vfs2.provider.res.ResourceFileProvider());
- vfs.addProvider("zip", new
org.apache.commons.vfs2.provider.zip.ZipFileProvider());
- vfs.addProvider("gz", new
org.apache.commons.vfs2.provider.gzip.GzipFileProvider());
- vfs.addProvider("ram", new
org.apache.commons.vfs2.provider.ram.RamFileProvider());
- vfs.addProvider("file",
- new
org.apache.commons.vfs2.provider.local.DefaultLocalFileProvider());
- vfs.addProvider("jar", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- vfs.addProvider("http", new
org.apache.commons.vfs2.provider.http5.Http5FileProvider());
- vfs.addProvider("https", new
org.apache.commons.vfs2.provider.http5s.Http5sFileProvider());
- vfs.addProvider("ftp", new
org.apache.commons.vfs2.provider.ftp.FtpFileProvider());
- vfs.addProvider("ftps", new
org.apache.commons.vfs2.provider.ftps.FtpsFileProvider());
- vfs.addProvider("war", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- vfs.addProvider("par", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- vfs.addProvider("ear", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- vfs.addProvider("sar", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- vfs.addProvider("ejb3", new
org.apache.commons.vfs2.provider.jar.JarFileProvider());
- vfs.addProvider("tmp", new
org.apache.commons.vfs2.provider.temp.TemporaryFileProvider());
- vfs.addProvider("tar", new
org.apache.commons.vfs2.provider.tar.TarFileProvider());
- vfs.addProvider("tbz2", new
org.apache.commons.vfs2.provider.tar.TarFileProvider());
- vfs.addProvider("tgz", new
org.apache.commons.vfs2.provider.tar.TarFileProvider());
- vfs.addProvider("bz2", new
org.apache.commons.vfs2.provider.bzip2.Bzip2FileProvider());
- vfs.addProvider("hdfs", new HdfsFileProvider());
- vfs.addExtensionMap("jar", "jar");
- vfs.addExtensionMap("zip", "zip");
- vfs.addExtensionMap("gz", "gz");
- vfs.addExtensionMap("tar", "tar");
- vfs.addExtensionMap("tbz2", "tar");
- vfs.addExtensionMap("tgz", "tar");
- vfs.addExtensionMap("bz2", "bz2");
- vfs.addMimeTypeMap("application/x-tar", "tar");
- vfs.addMimeTypeMap("application/x-gzip", "gz");
- vfs.addMimeTypeMap("application/zip", "zip");
- vfs.addMimeTypeMap("application/java-archive", "jar");
- vfs.setFileContentInfoFactory(new FileContentInfoFilenameFactory());
- vfs.setFilesCache(new SoftRefFilesCache());
- vfs.setReplicator(new
DefaultFileReplicator(Path.of(System.getProperty("java.io.tmpdir"),
- "accumulo-vfs-cache-" + System.getProperty("user.name",
"nouser")).toFile()));
- vfs.setCacheStrategy(CacheStrategy.ON_RESOLVE);
- vfs.init();
- } catch (FileSystemException e) {
- throw new RuntimeException("Error setting up VFS", e);
- }
-
- }
-
- protected static Configuration getConfiguration() {
- return conf;
- }
-
- protected static MiniDFSCluster getCluster() {
- return cluster;
- }
-
- protected static DefaultFileSystemManager getDefaultFileSystemManager() {
- return vfs;
- }
-
- @AfterAll
- public static void tearDownMiniDfsCluster() {
- if (null != cluster) {
- cluster.shutdown();
- }
- }
-
-}
diff --git
a/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/AccumuloVFSClassLoaderTest.java
b/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/AccumuloVFSClassLoaderTest.java
deleted file mode 100644
index 1c857bf..0000000
---
a/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/AccumuloVFSClassLoaderTest.java
+++ /dev/null
@@ -1,87 +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
- *
- * https://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.classloader.vfs;
-
-import static java.util.Objects.requireNonNull;
-import static org.junit.jupiter.api.Assertions.assertArrayEquals;
-
-import java.io.File;
-import java.nio.file.Files;
-
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemException;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-public class AccumuloVFSClassLoaderTest {
-
- @TempDir
- private static File tempDir;
- String folderPath;
-
- @BeforeEach
- @SuppressFBWarnings(value = "URLCONNECTION_SSRF_FD",
- justification = "paths not set by user input")
- public void setup() throws Exception {
- System.setProperty(AccumuloVFSClassLoader.VFS_CLASSPATH_MONITOR_INTERVAL,
"1");
- VFSManager.initialize();
-
- folderPath = tempDir.toURI() + ".*";
-
- try (var in =
requireNonNull(this.getClass().getResource("/HelloWorld.jar")).openStream()) {
- Files.copy(in, tempDir.toPath().resolve("HelloWorld.jar"));
- }
- }
-
- FileObject[] createFileSystems(FileObject[] fos) throws FileSystemException {
- FileObject[] rfos = new FileObject[fos.length];
- for (int i = 0; i < fos.length; i++) {
- if (VFSManager.get().canCreateFileSystem(fos[i])) {
- rfos[i] = VFSManager.get().createFileSystem(fos[i]);
- } else {
- rfos[i] = fos[i];
- }
- }
-
- return rfos;
- }
-
- @Test
- public void testConstructor() throws Exception {
- FileObject testDir =
VFSManager.get().resolveFile(tempDir.toURI().toString());
- FileObject[] dirContents = testDir.getChildren();
-
- AccumuloVFSClassLoader arvcl = new
AccumuloVFSClassLoader(ClassLoader.getSystemClassLoader()) {
- @Override
- protected String getClassPath() {
- return folderPath;
- }
- };
- arvcl.setVMInitializedForTests();
-
- FileObject[] files = ((VFSClassLoaderWrapper)
arvcl.getDelegateClassLoader()).getFileObjects();
- assertArrayEquals(createFileSystems(dirContents), files);
-
- arvcl.close();
- }
-
-}
diff --git
a/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/ClassPathPrinterTest.java
b/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/ClassPathPrinterTest.java
deleted file mode 100644
index 6577b04..0000000
---
a/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/ClassPathPrinterTest.java
+++ /dev/null
@@ -1,75 +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
- *
- * https://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.classloader.vfs;
-
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.io.File;
-import java.net.MalformedURLException;
-
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
-
-public class ClassPathPrinterTest {
-
- @TempDir
- private static File tempDir;
-
- private final ClassLoader parent =
ClassPathPrinterTest.class.getClassLoader();
-
- private static void assertPattern(String output, String pattern, boolean
shouldMatch) {
- if (shouldMatch) {
- assertTrue(output.matches(pattern),
- "Pattern " + pattern + " did not match output: " + output);
- } else {
- assertFalse(output.matches(pattern),
- "Pattern " + pattern + " should not match output: " + output);
- }
- }
-
- @Test
- public void testPrintClassPath() throws Exception {
- File conf = tempDir.toPath().resolve("accumulo.properties").toFile();
- assertTrue(conf.isFile() || conf.createNewFile());
- VFSManager.initialize();
-
- AccumuloVFSClassLoader cl = new AccumuloVFSClassLoader(parent) {
- @Override
- protected String getClassPath() {
- try {
- return conf.toURI().toURL().toString();
- } catch (MalformedURLException e) {
- throw new RuntimeException("URL problem", e);
- }
- }
-
- };
- cl.setVMInitializedForTests();
-
- assertPattern(ClassPathPrinter.getClassPath(cl, true), "(?s).*\\s+.*\\n$",
true);
- assertTrue(ClassPathPrinter.getClassPath(cl, true)
- .contains("Level 3: ReloadingVFSClassLoader, classpath items are"));
- assertTrue(ClassPathPrinter.getClassPath(cl, true).length()
- > ClassPathPrinter.getClassPath(cl, false).length());
- assertPattern(ClassPathPrinter.getClassPath(cl, false),
"(?s).*\\s+.*\\n$", false);
- assertFalse(ClassPathPrinter.getClassPath(cl, false)
- .contains("Level 3: ReloadingVFSClassLoader, classpath items are"));
- }
-}
diff --git
a/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/VfsClassLoaderTest.java
b/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/VfsClassLoaderTest.java
deleted file mode 100644
index e665397..0000000
---
a/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/VfsClassLoaderTest.java
+++ /dev/null
@@ -1,180 +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
- *
- * https://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.classloader.vfs;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.net.URL;
-import java.util.Arrays;
-
-import org.apache.commons.vfs2.FileChangeEvent;
-import org.apache.commons.vfs2.FileListener;
-import org.apache.commons.vfs2.FileObject;
-import org.apache.commons.vfs2.FileSystemException;
-import org.apache.commons.vfs2.impl.DefaultFileMonitor;
-import org.apache.commons.vfs2.impl.DefaultFileSystemManager;
-import org.apache.commons.vfs2.impl.VFSClassLoader;
-import org.apache.hadoop.fs.FileSystem;
-import org.apache.hadoop.fs.Path;
-import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class VfsClassLoaderTest extends AccumuloDFSBase {
-
- private static final Logger LOG =
LoggerFactory.getLogger(VfsClassLoaderTest.class);
- private static final Path TEST_DIR = new Path(getHdfsUri() + "/test-dir");
-
- private static FileSystem hdfs = null;
- private static DefaultFileSystemManager vfs = null;
-
- @BeforeAll
- public static void setup() throws Exception {
-
- // miniDfsClusterSetup();
-
- hdfs = getCluster().getFileSystem();
- assertTrue(hdfs.mkdirs(TEST_DIR), "Unable to create: " + TEST_DIR);
-
- vfs = getDefaultFileSystemManager();
-
- }
-
- @BeforeEach
- public void before() throws Exception {
- // Copy jar file to TEST_DIR
- URL jarPath = VfsClassLoaderTest.class.getResource("/HelloWorld.jar");
- assertNotNull(jarPath, "Unable to find HelloWorld.jar");
- Path src = new Path(jarPath.toURI().toString());
- Path dst = new Path(TEST_DIR, src.getName());
- LOG.info("Copying {} to {}", src, dst);
- hdfs.copyFromLocalFile(src, dst);
- }
-
- @Test
- public void testGetClass() throws Exception {
-
- FileObject testDir = vfs.resolveFile(TEST_DIR.toUri().toString());
- assertNotNull(testDir, "Unable to resolve test dir via VFS");
- FileObject[] dirContents = testDir.getChildren();
- LOG.info("Test directory contents according to VFS: {}",
Arrays.toString(dirContents));
-
- final VFSClassLoader cl;
-
- // Point the VFSClassLoader to all of the objects in TEST_DIR
- try {
- cl = new VFSClassLoader(dirContents, vfs);
- } catch (FileSystemException e) {
- throw new RuntimeException("Error creating VFSClassLoader", e);
- }
-
- LOG.info("VFSClassLoader has the following files: {}",
Arrays.toString(cl.getFileObjects()));
- LOG.info("Looking for HelloWorld.class");
- Class<?> helloWorldClass = cl.loadClass("test.HelloWorld");
- Object o = helloWorldClass.getDeclaredConstructor().newInstance();
- assertEquals("Hello World!", o.toString());
- }
-
- @Test
- public void testFileMonitor() throws Exception {
- MyFileMonitor listener = new MyFileMonitor();
- DefaultFileMonitor monitor = new DefaultFileMonitor(listener);
- monitor.setRecursive(true);
- FileObject testDir = vfs.resolveFile(TEST_DIR.toUri().toString());
- monitor.addFile(testDir);
- monitor.start();
-
- // Copy jar file to a new file name
- URL jarPath = this.getClass().getResource("/HelloWorld.jar");
- Path src = new Path(jarPath.toURI().toString());
- Path dst = new Path(TEST_DIR, "HelloWorld2.jar");
- hdfs.copyFromLocalFile(src, dst);
-
- // VFS-487 significantly wait to avoid failure
- Thread.sleep(7000);
- assertTrue(listener.isFileCreated());
-
- // Update the jar
- jarPath = this.getClass().getResource("/HelloWorld.jar");
- src = new Path(jarPath.toURI().toString());
- dst = new Path(TEST_DIR, "HelloWorld2.jar");
- hdfs.copyFromLocalFile(src, dst);
-
- // VFS-487 significantly wait to avoid failure
- Thread.sleep(7000);
- assertTrue(listener.isFileChanged());
-
- hdfs.delete(dst, false);
- // VFS-487 significantly wait to avoid failure
- Thread.sleep(7000);
- assertTrue(listener.isFileDeleted());
-
- monitor.stop();
-
- }
-
- @AfterAll
- public static void tearDown() throws Exception {
- hdfs.delete(TEST_DIR, true);
- tearDownMiniDfsCluster();
- }
-
- public static class MyFileMonitor implements FileListener {
-
- private boolean fileChanged = false;
- private boolean fileDeleted = false;
- private boolean fileCreated = false;
-
- @Override
- public void fileCreated(FileChangeEvent event) throws Exception {
- // System.out.println(event.getFile() + " created");
- this.fileCreated = true;
- }
-
- @Override
- public void fileDeleted(FileChangeEvent event) throws Exception {
- // System.out.println(event.getFile() + " deleted");
- this.fileDeleted = true;
- }
-
- @Override
- public void fileChanged(FileChangeEvent event) throws Exception {
- // System.out.println(event.getFile() + " changed");
- this.fileChanged = true;
- }
-
- public boolean isFileChanged() {
- return fileChanged;
- }
-
- public boolean isFileDeleted() {
- return fileDeleted;
- }
-
- public boolean isFileCreated() {
- return fileCreated;
- }
-
- }
-}
diff --git
a/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/context/ReloadingVFSContextClassLoaderFactoryTest.java
b/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/context/ReloadingVFSContextClassLoaderFactoryTest.java
deleted file mode 100644
index 9039183..0000000
---
a/modules/vfs-class-loader/src/test/java/org/apache/accumulo/classloader/vfs/context/ReloadingVFSContextClassLoaderFactoryTest.java
+++ /dev/null
@@ -1,256 +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
- *
- * https://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.classloader.vfs.context;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.nio.file.StandardOpenOption.WRITE;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.StandardCopyOption;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.accumulo.classloader.vfs.AccumuloVFSClassLoader;
-import
org.apache.accumulo.classloader.vfs.context.ReloadingVFSContextClassLoaderFactory.Context;
-import
org.apache.accumulo.classloader.vfs.context.ReloadingVFSContextClassLoaderFactory.ContextConfig;
-import
org.apache.accumulo.classloader.vfs.context.ReloadingVFSContextClassLoaderFactory.Contexts;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.TestInfo;
-import org.junit.jupiter.api.io.TempDir;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.gson.Gson;
-
-import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-
-public class ReloadingVFSContextClassLoaderFactoryTest {
-
- private static final Logger LOG =
- LoggerFactory.getLogger(ReloadingVFSContextClassLoaderFactoryTest.class);
-
- private static class TestReloadingVFSContextClassLoaderFactory
- extends ReloadingVFSContextClassLoaderFactory {
-
- private final String dir;
-
- public TestReloadingVFSContextClassLoaderFactory(String dir) {
- this.dir = dir;
- }
-
- @SuppressFBWarnings(value = "DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED",
- justification = "Security Manager is deprecated for removal as of JDK
17")
- @Override
- protected AccumuloVFSClassLoader create(Context c) {
- final AccumuloVFSClassLoader cl =
- new
AccumuloVFSClassLoader(ReloadingVFSContextClassLoaderFactory.class.getClassLoader())
{
- @Override
- protected String getClassPath() {
- return dir;
- }
-
- @Override
- protected boolean isPostDelegationModel() {
- LOG.debug("isPostDelegationModel called, returning {}",
- c.getConfig().getPostDelegate());
- return c.getConfig().getPostDelegate();
- }
-
- @Override
- protected long getMonitorInterval() {
- return 500l;
- }
-
- @Override
- protected boolean isVMInitialized() {
- return true;
- }
- };
- cl.setVMInitializedForTests();
- cl.setMaxRetries(2);
- return cl;
- }
- }
-
- @TempDir
- private static File tempDir;
-
- private static final Contexts c = new Contexts();
-
- private static Path foo = Path.of(System.getProperty("user.dir"), "target",
"foo");
- private static Path bar = Path.of(System.getProperty("user.dir"), "target",
"bar");
-
- @BeforeAll
- public static void setup() throws Exception {
-
- assertTrue(foo.toFile().mkdir());
- assertTrue(bar.toFile().mkdir());
-
- System.setProperty(AccumuloVFSClassLoader.VFS_CLASSLOADER_DEBUG, "true");
- ContextConfig cc1 = new ContextConfig();
- cc1.setClassPath(foo.resolve(".*").toUri().toString());
- cc1.setPostDelegate(true);
- cc1.setMonitorIntervalMs(1000);
- Context c1 = new Context();
- c1.setName("cx1");
- c1.setConfig(cc1);
-
- ContextConfig cc2 = new ContextConfig();
- cc2.setClassPath(bar.resolve(".*").toUri().toString());
- cc2.setPostDelegate(false);
- cc2.setMonitorIntervalMs(1000);
- Context c2 = new Context();
- c2.setName("cx2");
- c2.setConfig(cc2);
-
- List<Context> list = new ArrayList<>();
- list.add(c1);
- list.add(c2);
- c.setContexts(list);
- }
-
- @Test
- public void testDeSer() throws Exception {
- Gson g = new Gson().newBuilder().setPrettyPrinting().create();
- String contexts = g.toJson(c);
- System.out.println(contexts);
-
- Gson g2 = new Gson();
- Contexts actual = g2.fromJson(contexts, Contexts.class);
-
- assertEquals(c, actual);
-
- }
-
- @Test
- public void testCreation(TestInfo testInfo) throws Exception {
-
- try (var in = this.getClass().getResource("/HelloWorld.jar").openStream())
{
- Files.copy(in, foo.resolve("HelloWorld.jar"),
StandardCopyOption.REPLACE_EXISTING);
- }
- try (var in =
this.getClass().getResource("/HelloWorld2.jar").openStream()) {
- Files.copy(in, bar.resolve("HelloWorld2.jar"),
StandardCopyOption.REPLACE_EXISTING);
- }
-
- String testMethodName = testInfo.getTestMethod().orElseThrow().getName();
- File testSubDir = tempDir.toPath().resolve(testMethodName).toFile();
- assertTrue(testSubDir.isDirectory() || testSubDir.mkdir());
-
- File f = testSubDir.toPath().resolve("configFile").toFile();
- assertTrue(f.isFile() || f.createNewFile());
- f.deleteOnExit();
- Gson g = new Gson();
- String contexts = g.toJson(c);
- try (BufferedWriter writer = Files.newBufferedWriter(f.toPath(), UTF_8,
WRITE)) {
- writer.write(contexts);
- }
- ReloadingVFSContextClassLoaderFactory cl = new
ReloadingVFSContextClassLoaderFactory() {
- @Override
- protected String getConfigFileLocation() {
- return f.toURI().toString();
- }
- };
- try {
- cl.getClassLoader("c1");
- fail("Expected illegal argument exception");
- } catch (IllegalArgumentException e) {
- // works
- }
- cl.getClassLoader("cx1");
- cl.getClassLoader("cx2");
- cl.closeForTests();
- }
-
- @Test
- public void testReloading(TestInfo testInfo) throws Exception {
-
- System.setProperty(AccumuloVFSClassLoader.VFS_CLASSPATH_MONITOR_INTERVAL,
"1");
-
- try (var in = this.getClass().getResource("/HelloWorld.jar").openStream())
{
- Files.copy(in, foo.resolve("HelloWorld.jar"),
StandardCopyOption.REPLACE_EXISTING);
- }
- try (var in = this.getClass().getResource("/HelloWorld.jar").openStream())
{
- Files.copy(in, bar.resolve("HelloWorld2.jar"),
StandardCopyOption.REPLACE_EXISTING);
- }
-
- String testMethodName = testInfo.getTestMethod().orElseThrow().getName();
- File testSubDir = tempDir.toPath().resolve(testMethodName).toFile();
- assertTrue(testSubDir.isDirectory() || testSubDir.mkdir());
-
- File f = testSubDir.toPath().resolve("configFile").toFile();
- assertTrue(f.isFile() || f.createNewFile());
- f.deleteOnExit();
- Gson g = new Gson();
- String contexts = g.toJson(c);
- try (BufferedWriter writer = Files.newBufferedWriter(f.toPath(), UTF_8,
WRITE)) {
- writer.write(contexts);
- }
-
- TestReloadingVFSContextClassLoaderFactory factory =
- new
TestReloadingVFSContextClassLoaderFactory(foo.resolve(".*").toUri().toString())
{
- @Override
- protected String getConfigFileLocation() {
- return f.toURI().toString();
- }
- };
-
- ClassLoader cl1 = factory.getClassLoader("cx1");
- Class<?> clazz1 = cl1.loadClass("test.HelloWorld");
- Object o1 = clazz1.getDeclaredConstructor().newInstance();
- assertEquals("Hello World!", o1.toString());
-
- // Check that the class is the same before the update
- Class<?> clazz1_5 = cl1.loadClass("test.HelloWorld");
- assertEquals(clazz1, clazz1_5);
-
- assertTrue(foo.resolve("HelloWorld.jar").toFile().delete());
-
- Thread.sleep(1000);
-
- // Update the class
- try (var in = this.getClass().getResource("/HelloWorld.jar").openStream())
{
- Files.copy(in, foo.resolve("HelloWorld2.jar"),
StandardCopyOption.REPLACE_EXISTING);
- }
-
- // Wait for the monitor to notice
- Thread.sleep(1000);
-
- ClassLoader cl2 = factory.getClassLoader("cx1");
- assertNotEquals(cl1, cl2);
-
- Class<?> clazz2 =
factory.getClassLoader("cx1").loadClass("test.HelloWorld");
- Object o2 = clazz2.getDeclaredConstructor().newInstance();
- assertEquals("Hello World!", o2.toString());
-
- // This is false because they are loaded by a different classloader
- assertNotEquals(clazz1, clazz2);
- assertNotEquals(o1, o2);
-
- factory.closeForTests();
- }
-
-}
diff --git a/modules/vfs-class-loader/src/test/java/test/HelloWorldTemplate
b/modules/vfs-class-loader/src/test/java/test/HelloWorldTemplate
deleted file mode 100644
index c6def69..0000000
--- a/modules/vfs-class-loader/src/test/java/test/HelloWorldTemplate
+++ /dev/null
@@ -1,27 +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
- *
- * https://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 test;
-
-public class HelloWorld {
-
- @Override
- public String toString() {
- return "%%";
- }
-}
diff --git a/modules/vfs-class-loader/src/test/java/test/Test.java
b/modules/vfs-class-loader/src/test/java/test/Test.java
deleted file mode 100644
index 3c2b196..0000000
--- a/modules/vfs-class-loader/src/test/java/test/Test.java
+++ /dev/null
@@ -1,27 +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
- *
- * https://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 test;
-
-public interface Test {
-
- String hello();
-
- int add();
-
-}
diff --git a/modules/vfs-class-loader/src/test/java/test/TestTemplate
b/modules/vfs-class-loader/src/test/java/test/TestTemplate
deleted file mode 100644
index c22d687..0000000
--- a/modules/vfs-class-loader/src/test/java/test/TestTemplate
+++ /dev/null
@@ -1,36 +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
- *
- * https://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 test;
-
-public class TestObject implements Test {
-
- int i = 0;
-
- @Override
- public String hello() {
- return "Hello from testX";
- }
-
- @Override
- public int add() {
- i += 1;
- return i;
- }
-
-}
diff --git a/modules/vfs-class-loader/src/test/resources/log4j2-test.properties
b/modules/vfs-class-loader/src/test/resources/log4j2-test.properties
deleted file mode 100644
index 022268c..0000000
--- a/modules/vfs-class-loader/src/test/resources/log4j2-test.properties
+++ /dev/null
@@ -1,35 +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
-#
-# https://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.
-#
-
-status = info
-dest = err
-name = AccumuloVFSClassLoaderTestLoggingProperties
-
-appender.console.type = Console
-appender.console.name = STDOUT
-appender.console.target = SYSTEM_OUT
-appender.console.layout.type = PatternLayout
-appender.console.layout.pattern = %d{ISO8601} [%-8c{2}] %-5p: %m%n
-
-logger.01.name = org.apache.hadoop
-logger.01.level = warn
-
-rootLogger.level = debug
-rootLogger.appenderRef.console.ref = STDOUT
-
diff --git a/modules/vfs-class-loader/src/test/shell/makeHelloWorldJars.sh
b/modules/vfs-class-loader/src/test/shell/makeHelloWorldJars.sh
deleted file mode 100755
index 8ddefab..0000000
--- a/modules/vfs-class-loader/src/test/shell/makeHelloWorldJars.sh
+++ /dev/null
@@ -1,35 +0,0 @@
-#! /usr/bin/env bash
-#
-# 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
-#
-# https://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.
-#
-
-if [[ -z $JAVA_HOME ]]; then
- echo "JAVA_HOME is not set. Java is required to proceed"
- exit 1
-fi
-mkdir -p target/generated-sources/HelloWorld/test
-sed "s/%%/Hello World\!/" <src/test/java/test/HelloWorldTemplate
>target/generated-sources/HelloWorld/test/HelloWorld.java
-"$JAVA_HOME/bin/javac" --release 11
target/generated-sources/HelloWorld/test/HelloWorld.java -d
target/generated-sources/HelloWorld
-"$JAVA_HOME/bin/jar" -cf target/test-classes/HelloWorld.jar -C
target/generated-sources/HelloWorld test/HelloWorld.class
-rm -r target/generated-sources/HelloWorld/test
-
-mkdir -p target/generated-sources/HalloWelt/test
-sed "s/%%/Hallo Welt/" <src/test/java/test/HelloWorldTemplate
>target/generated-sources/HalloWelt/test/HelloWorld.java
-"$JAVA_HOME/bin/javac" --release 11
target/generated-sources/HalloWelt/test/HelloWorld.java -d
target/generated-sources/HalloWelt
-"$JAVA_HOME/bin/jar" -cf target/test-classes/HelloWorld2.jar -C
target/generated-sources/HalloWelt test/HelloWorld.class
-rm -r target/generated-sources/HalloWelt/test
diff --git a/modules/vfs-class-loader/src/test/shell/makeTestJars.sh
b/modules/vfs-class-loader/src/test/shell/makeTestJars.sh
deleted file mode 100755
index 02006e8..0000000
--- a/modules/vfs-class-loader/src/test/shell/makeTestJars.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-#! /usr/bin/env bash
-#
-# 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
-#
-# https://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.
-#
-
-if [[ -z $JAVA_HOME ]]; then
- echo "JAVA_HOME is not set. Java is required to proceed"
- exit 1
-fi
-
-for x in A B C; do
- mkdir -p target/generated-sources/$x/test
target/test-classes/ClassLoaderTest$x
- sed "s/testX/test$x/" <src/test/java/test/TestTemplate
>target/generated-sources/$x/test/TestObject.java
- CLASSPATH=target/test-classes "$JAVA_HOME/bin/javac" --release 11
target/generated-sources/$x/test/TestObject.java -d target/generated-sources/$x
- "$JAVA_HOME/bin/jar" -cf target/test-classes/ClassLoaderTest$x/Test.jar -C
target/generated-sources/$x test/TestObject.class
- rm -r target/generated-sources/$x
-done
diff --git
a/modules/vfs-class-loader/test-configurations/new-context-configuration.json
b/modules/vfs-class-loader/test-configurations/new-context-configuration.json
deleted file mode 100644
index eacd78f..0000000
---
a/modules/vfs-class-loader/test-configurations/new-context-configuration.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "contexts": [
- {
- "name": "cxA",
- "config": {
- "classPath": "hdfs://localhost:9000/iterators/example-a/examples.jar",
- "postDelegate": true,
- "monitorIntervalMs": 10000
- }
- },
- {
- "name": "cxB",
- "config": {
- "classPath": "hdfs://localhost:9000/iterators/example-b/examples.jar",
- "postDelegate": true,
- "monitorIntervalMs": 10000
- }
- }
- ]
-}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 6d4dd53..2a6e55d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,7 +77,6 @@
<module>modules/example-iterators-b</module>
<module>modules/caching-class-loader</module>
<module>modules/hdfs-urlstreamhandler-provider</module>
- <module>modules/vfs-class-loader</module>
</modules>
<scm>
<connection>scm:git:https://gitbox.apache.org/repos/asf/accumulo-classloaders.git</connection>