You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by kl...@apache.org on 2016/12/14 22:47:25 UTC
geode git commit: GEODE-2214: fall back to TCCL if target CL fails to
resolve class
Repository: geode
Updated Branches:
refs/heads/feature/GEODE-2214 213d8bc1c -> f122daeb2
GEODE-2214: fall back to TCCL if target CL fails to resolve class
Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/f122daeb
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/f122daeb
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/f122daeb
Branch: refs/heads/feature/GEODE-2214
Commit: f122daeb2d1c9f505ff550cf9ca6ea7d452d5c93
Parents: 213d8bc
Author: Kirk Lund <kl...@apache.org>
Authored: Wed Dec 14 14:46:04 2016 -0800
Committer: Kirk Lund <kl...@apache.org>
Committed: Wed Dec 14 14:46:04 2016 -0800
----------------------------------------------------------------------
extensions/geode-modules/build.gradle | 1 +
.../util/ClassLoaderObjectInputStream.java | 8 +-
.../util/ClassLoaderObjectInputStreamTest.java | 169 +++++++++++++++++++
3 files changed, 177 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/geode/blob/f122daeb/extensions/geode-modules/build.gradle
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/build.gradle b/extensions/geode-modules/build.gradle
index 0ac8c9a..55355fb 100644
--- a/extensions/geode-modules/build.gradle
+++ b/extensions/geode-modules/build.gradle
@@ -26,6 +26,7 @@ dependencies {
}
compile 'org.apache.tomcat:juli:' + project.'tomcat6.version'
+ testCompile 'org.apache.bcel:bcel:' + project.'bcel.version'
testCompile 'org.httpunit:httpunit:' + project.'httpunit.version'
testRuntime 'org.apache.tomcat:coyote:' + project.'tomcat6.version'
http://git-wip-us.apache.org/repos/asf/geode/blob/f122daeb/extensions/geode-modules/src/main/java/org/apache/geode/modules/util/ClassLoaderObjectInputStream.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/main/java/org/apache/geode/modules/util/ClassLoaderObjectInputStream.java b/extensions/geode-modules/src/main/java/org/apache/geode/modules/util/ClassLoaderObjectInputStream.java
index d5ebbab..6368bf6 100644
--- a/extensions/geode-modules/src/main/java/org/apache/geode/modules/util/ClassLoaderObjectInputStream.java
+++ b/extensions/geode-modules/src/main/java/org/apache/geode/modules/util/ClassLoaderObjectInputStream.java
@@ -33,6 +33,12 @@ public class ClassLoaderObjectInputStream extends ObjectInputStream {
@Override
public Class<?> resolveClass(ObjectStreamClass desc) throws ClassNotFoundException {
- return Class.forName(desc.getName(), false, loader);
+ Class<?> theClass;
+ try {
+ theClass = Class.forName(desc.getName(), false, loader);
+ } catch (ClassNotFoundException cnfe) {
+ theClass = Thread.currentThread().getContextClassLoader().loadClass(desc.getName());
+ }
+ return theClass;
}
}
http://git-wip-us.apache.org/repos/asf/geode/blob/f122daeb/extensions/geode-modules/src/test/java/org/apache/geode/modules/util/ClassLoaderObjectInputStreamTest.java
----------------------------------------------------------------------
diff --git a/extensions/geode-modules/src/test/java/org/apache/geode/modules/util/ClassLoaderObjectInputStreamTest.java b/extensions/geode-modules/src/test/java/org/apache/geode/modules/util/ClassLoaderObjectInputStreamTest.java
new file mode 100644
index 0000000..0e76aad
--- /dev/null
+++ b/extensions/geode-modules/src/test/java/org/apache/geode/modules/util/ClassLoaderObjectInputStreamTest.java
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License. You may obtain a
+ * copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.geode.modules.util;
+
+import static org.assertj.core.api.Assertions.*;
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.generic.ClassGen;
+import org.apache.geode.internal.ClassPathLoader;
+import org.apache.geode.test.junit.categories.UnitTest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TestName;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Vector;
+
+@Category(UnitTest.class)
+@SuppressWarnings("unused")
+public class ClassLoaderObjectInputStreamTest {
+
+ private ClassLoader originalTCCL;
+ private ClassLoader newTCCL;
+ private String classToLoad;
+ private Object instanceOfTCCLClass;
+
+ @Rule
+ public TestName testName = new TestName();
+
+ @Before
+ public void setUp() throws Exception {
+ this.originalTCCL = Thread.currentThread().getContextClassLoader();
+ this.newTCCL = new GeneratingClassLoader();
+ this.classToLoad = "com.nowhere." + getClass().getSimpleName() + "_" + testName.getMethodName();
+ this.instanceOfTCCLClass = createInstanceOfTCCLClass();
+ }
+
+ @After
+ public void unsetTCCL() throws Exception {
+ Thread.currentThread().setContextClassLoader(this.originalTCCL);
+ }
+
+ @Test
+ public void resolveClassFromTCCLThrowsIfTCCLDisabled() throws Exception {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(this.instanceOfTCCLClass);
+ oos.close();
+
+ ObjectInputStream ois = new ClassLoaderObjectInputStream(
+ new ByteArrayInputStream(baos.toByteArray()), getClass().getClassLoader());
+
+ assertThatThrownBy(() -> ois.readObject()).isExactlyInstanceOf(ClassNotFoundException.class);
+ }
+
+ @Test
+ public void resolveClassFindsClassFromTCCLIfTCCLEnabled() throws Exception {
+ Thread.currentThread().setContextClassLoader(this.newTCCL);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(this.instanceOfTCCLClass);
+ oos.close();
+
+ ObjectInputStream ois = new ClassLoaderObjectInputStream(
+ new ByteArrayInputStream(baos.toByteArray()), getClass().getClassLoader());
+
+ Object objectFromTCCL = ois.readObject(); // fails due to new bug
+
+ assertThat(objectFromTCCL).isNotNull();
+ assertThat(objectFromTCCL.getClass()).isNotNull();
+ assertThat(objectFromTCCL.getClass().getName()).isEqualTo(this.classToLoad);
+ }
+
+ private Object createInstanceOfTCCLClass()
+ throws ClassNotFoundException, IllegalAccessException, InstantiationException {
+ Class<?> clazz = Class.forName(this.classToLoad, false, this.newTCCL);
+ return clazz.newInstance();
+ }
+
+ /**
+ * Custom class loader which uses BCEL to always dynamically generate a class for any class name
+ * it tries to load.
+ */
+ private static class GeneratingClassLoader extends ClassLoader {
+
+ /**
+ * Currently unused but potentially useful for some future test. This causes this loader to only
+ * generate a class that the parent could not find.
+ *
+ * @param parent the parent class loader to check with first
+ */
+ public GeneratingClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ /**
+ * Specifies no parent to ensure that this loader generates the named class.
+ */
+ public GeneratingClassLoader() {
+ super(null); // no parent
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ ClassGen cg = new ClassGen(name, Object.class.getName(), "<generated>",
+ Constants.ACC_PUBLIC | Constants.ACC_SUPER, new String[] {Serializable.class.getName()});
+ cg.addEmptyConstructor(Constants.ACC_PUBLIC);
+ JavaClass jClazz = cg.getJavaClass();
+ byte[] bytes = jClazz.getBytes();
+ return defineClass(jClazz.getClassName(), bytes, 0, bytes.length);
+ }
+
+ @Override
+ protected URL findResource(String name) {
+ URL url = null;
+ try {
+ url = getTempFile().getAbsoluteFile().toURI().toURL();
+ System.out.println("GeneratingClassLoader#findResource returning " + url);
+ } catch (IOException e) {
+ throw new Error(e);
+ }
+ return url;
+ }
+
+ @Override
+ protected Enumeration<URL> findResources(String name) throws IOException {
+ URL url;
+ try {
+ url = getTempFile().getAbsoluteFile().toURI().toURL();
+ System.out.println("GeneratingClassLoader#findResources returning " + url);
+ } catch (IOException e) {
+ throw new Error(e);
+ }
+ Vector<URL> urls = new Vector<URL>();
+ urls.add(url);
+ return urls.elements();
+ }
+
+ protected File getTempFile() {
+ return null;
+ }
+ }
+
+}