/*
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
*
* @summary functional test for RMIClassLoader.loadProxyClass; test
* ensures that the default RMI class loader provider implements
* RMIClassLoader.loadProxyClass correctly.
*
* @author Laird Dornin
*
* @library ../../../testlibrary
* @build TestLibrary FnnClass FnnUnmarshal NonpublicInterface
* NonpublicInterface1 PublicInterface PublicInterface1
* @run main/othervm/policy=security.policy
* -Djava.rmi.server.useCodebaseOnly=false LoadProxyClasses
*/
import java.rmi.server.RMIClassLoader;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.rmi.MarshalledObject;
import java.net.URL;
import java.net.URLClassLoader;
import java.io.Serializable;
import java.io.IOException;
import java.util.Arrays;
import java.util.zip.Checksum;
/**
* Invokes RMIClassLoader.loadProxyClass() to load a proxy class with
* multiple interfaces using using RMI class unmarshalling. Test is
* composed of cases which each unmarshal a proxy class in a
* different environment. All of the cases create needed class
* loaders, load appropriate interfaces, create a proxy class that
* implements those interfaces, create a marshalled object from that
* proxy class, and finally call .get() on that object. Get of the
* object should pass in some cases and fail in others.
*
* 1. Nonpublic interface loaded from the parent of the First
* Non-Null class Loader on the execution stack (FNNL). Public
* interface loaded from grandparent of FNNL parent. Proxy class must
* be defined in non-null FNNL parent. Should succeed.
*
* 2. Nonpublic interface (java.util.zip.ZipConstants) and public
* interface (java.util.zip.CheckSum) loaded from bootclasspath,
* proxy class defined in null/boot class loader. Should succeed.
*
* 3. Public interface classes loaded in FNNL are also available in
* RMI loader parent. FNNL is grandparent of RMI loader. Proxy class
* must be defined in RMI class loader. Should succeed. public
* interface must be defined in FNNL.
*
* 4. Non-public interfaces have multiple class loaders. Should fail
* with a LinkageError.
*
* 5. Interface classes loaded from RMI class loader. Proxy class
* defined in RMI class loader.
*
* 6. Not all interfaces classes can be loaded from a single class
* loader; should fail with ClassNotFoundException. All interface
* classes will exist (but not all interfaces will be available from
* one class loader).
*
* 7. prove that proxy loader has correct annotation.
*
* 8. REMIND: may want to add a case where the FNNL is null (This
* would be for class unmarshalling in the implemntation of a remote
* method invocation).
*/
public class LoadProxyClasses {
private static URL publicUrl = null;
public static boolean boomerangSemantics = false;
public static void main(String[] args) {
try {
System.err.println("\nFunctional test to verify that RMI " +
"loads proxy classes correctly\n");
/* install proxy interfaces */
publicUrl =
TestLibrary.installClassInCodebase("PublicInterface",
"public");
URL publicUrl1 =
TestLibrary.installClassInCodebase("PublicInterface1",
"public1");
URL nonpublicUrl =
TestLibrary.installClassInCodebase("NonpublicInterface",
"nonpublic", false);
URL nonpublicUrl1 =
TestLibrary.installClassInCodebase("NonpublicInterface1",
"nonpublic1", false);
URL bothNonpublicUrl =
TestLibrary.installClassInCodebase("NonpublicInterface",
"bothNonpublic");
TestLibrary.installClassInCodebase("NonpublicInterface1",
"bothNonpublic");
URL fnnUrl =
TestLibrary.installClassInCodebase("FnnClass", "fnn");
TestLibrary.suggestSecurityManager(null);
/* Case 1 */
ClassLoader grandParentPublic =
new URLClassLoader(new URL[] {publicUrl});
ClassLoader parentNonpublic =
new URLClassLoader(new URL[] {nonpublicUrl},
grandParentPublic);
URLClassLoader fnnLoader1 =
new URLClassLoader(new URL[] {fnnUrl}, parentNonpublic);
Class nonpublicInterface =
fnnLoader1.loadClass("NonpublicInterface");
Class publicInterface =
fnnLoader1.loadClass("PublicInterface");
Proxy proxy1 = (Proxy) Proxy.newProxyInstance(parentNonpublic,
new Class[] {nonpublicInterface, publicInterface},
new TestInvocationHandler());
unmarshalProxyClass(proxy1, fnnLoader1, parentNonpublic, 1, null);
/* Case 2 */
Class zipConstantsClass =
Class.forName("java.util.zip.ZipConstants");
URLClassLoader fnnLoader2 =
new URLClassLoader(new URL[] {fnnUrl});
Proxy proxy2 = (Proxy) Proxy.newProxyInstance(null,
new Class[] {zipConstantsClass, Checksum.class},
new TestInvocationHandler());
unmarshalProxyClass(proxy2, fnnLoader2,
(ClassLoader) null, 2, null);
/* Case 3 */
Thread currentThread = Thread.currentThread();
ClassLoader fnnLoader3 = new URLClassLoader(
new URL[] {publicUrl, fnnUrl});
ClassLoader newCtxLoader =
new URLClassLoader(new URL[] {publicUrl}, fnnLoader3);
Class publicInterface3 =
fnnLoader3.loadClass("PublicInterface");
ClassLoader currentCtxLoader =
currentThread.getContextClassLoader();
currentThread.setContextClassLoader(newCtxLoader);
Proxy proxy3 = (Proxy) Proxy.newProxyInstance(newCtxLoader,
new Class[] {publicInterface3},
new TestInvocationHandler());
unmarshalProxyClass(proxy3, fnnLoader3, fnnLoader3,
3, new Case3Checker());
currentThread.setContextClassLoader(currentCtxLoader);
/* Case 4 */
ClassLoader bothNonpublicLoader =
new URLClassLoader(new URL[] {bothNonpublicUrl});
Class nonpublicInterface4a =
bothNonpublicLoader.loadClass("NonpublicInterface");
Class nonpublicInterface4b =
bothNonpublicLoader.loadClass("NonpublicInterface1");
Proxy proxy4 = (Proxy) Proxy.newProxyInstance(bothNonpublicLoader,
new Class[] {nonpublicInterface4a, nonpublicInterface4b},
new TestInvocationHandler());
ClassLoader nonpublicLoaderA =
new URLClassLoader(new URL[] {nonpublicUrl});
ClassLoader nonpublicLoaderB =
new URLClassLoader(new URL[] {nonpublicUrl1}, nonpublicLoaderA);
currentCtxLoader =
currentThread.getContextClassLoader();
currentThread.setContextClassLoader(nonpublicLoaderB);
IllegalAccessError illegal = null;
try {
unmarshalProxyClass(proxy4, fnnLoader2, nonpublicLoaderB,
4, null);
} catch (IllegalAccessError e) {
illegal = e;
}
if (illegal == null) {
TestLibrary.bomb("case4: IllegalAccessError not thrown " +
"when multiple nonpublic interfaces have \n" +
"different class loaders");
} else {
System.err.println("\ncase4: IllegalAccessError correctly " +
"thrown \n when trying to load proxy " +
"with multiple nonpublic interfaces in \n" +
" different class loaders");
}
currentThread.setContextClassLoader(currentCtxLoader);
/* Case 5*/
ClassLoader publicLoader =
new URLClassLoader(new URL[] {publicUrl});
Class publicInterface5 =
publicLoader.loadClass("PublicInterface");
Proxy proxy5 = (Proxy) Proxy.newProxyInstance(publicLoader,
new Class[] {publicInterface5},
new TestInvocationHandler());
currentCtxLoader =
currentThread.getContextClassLoader();
currentThread.setContextClassLoader(publicLoader);
unmarshalProxyClass(proxy5, fnnLoader2, publicLoader, 5,
new Case5Checker());
currentThread.setContextClassLoader(currentCtxLoader);
/* Case 6 */
ClassLoader fnnLoader6 =
new URLClassLoader(new URL[] {fnnUrl, publicUrl});
ClassLoader publicLoader6 =
new URLClassLoader(new URL[] {publicUrl1}, fnnLoader6);
Class publicInterface6a =
publicLoader6.loadClass("PublicInterface1");
Class publicInterface6b =
fnnLoader6.loadClass("PublicInterface");
Proxy proxy6 = (Proxy) Proxy.newProxyInstance(publicLoader6,
new Class[] {publicInterface6a, publicInterface6b},
new TestInvocationHandler());
ClassNotFoundException cnfe = null;
try {
unmarshalProxyClass(proxy6, fnnLoader6, publicLoader6, 6,
null);
} catch (ClassNotFoundException e) {
cnfe = e;
}
if (cnfe == null) {
TestLibrary.bomb("ClassNotFoundException not thrown " +
"when not all proxy interfaces could " +
" be found in a single class loader ");
} else {
System.err.println("Case6: ClassNotFoundException " +
"correctly thrown when not all proxy" +
" interfaces could be found in a " +
"single class loader");
cnfe.printStackTrace();
}
System.err.println("TEST PASSED");
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
TestLibrary.bomb(e);
}
}
private interface LoadChecker {
void checkLoad(Proxy proxy, ClassLoader expectedLoader);
}
private static Proxy unmarshalProxyClass(Proxy proxy,
ClassLoader fnnLoader,
ClassLoader expectedLoader,
int n,
LoadChecker checker)
throws ClassNotFoundException, IOException,
InstantiationException, IllegalAccessException
{
FnnUnmarshal fnnUnmarshal = (FnnUnmarshal)
fnnLoader.loadClass("FnnClass").newInstance();
Proxy unmarshalled = (Proxy)
fnnUnmarshal.unmarshal(new MarshalledObject(proxy));
ClassLoader unmarshalledLoader =
unmarshalled.getClass().getClassLoader();
if (checker != null) {
checker.checkLoad(unmarshalled, expectedLoader);
} else {
if (unmarshalledLoader != expectedLoader) {
TestLibrary.bomb("case" + n + ": proxy class not " +
"placed into incorrect loader: " +
unmarshalledLoader);
} else {
System.err.println("\ncase" + n + ": proxy class correctly" +
" placed into expected loader: " +
expectedLoader);
}
}
return proxy;
}
private static class Case3Checker implements LoadChecker {
public void checkLoad(Proxy proxy, ClassLoader expectedLoader) {
ClassLoader ifaceLoader =
proxy.getClass().getInterfaces()[0].getClassLoader();
ClassLoader proxyLoader = proxy.getClass().getClassLoader();
boolean proxyOk = false;
if (boomerangSemantics) {
ClassLoader ctxLoader =
Thread.currentThread().getContextClassLoader();
if (proxyLoader == ctxLoader) {
proxyOk = true;
}
} else if (proxyLoader.getClass().
getName().indexOf("sun.rmi") >= 0)
{
proxyOk = true;
}
if (proxyOk) {
System.err.println("\ncase3: proxy loaded in" +
" correct loader: " + proxyLoader +
Arrays.asList(((URLClassLoader)
proxyLoader).getURLs()));
} else {
TestLibrary.bomb("case3: proxy class loaded in " +
"incorrect loader: " + proxyLoader +
Arrays.asList(((URLClassLoader)
proxyLoader).getURLs()));
}
if (ifaceLoader == expectedLoader) {
System.err.println("case3: proxy interface loaded in" +
" correct loader: " + ifaceLoader);
} else {
TestLibrary.bomb("public proxy interface loaded in " +
"incorrect loader: " + ifaceLoader);
}
}
}
private static class Case5Checker implements LoadChecker {
public void checkLoad(Proxy proxy, ClassLoader expectedLoader) {
ClassLoader proxyLoader = proxy.getClass().getClassLoader();
String proxyAnnotation =
RMIClassLoader.getClassAnnotation(proxy.getClass());
if ((proxyAnnotation == null) ||
!proxyAnnotation.equals(publicUrl.toString()))
{
TestLibrary.bomb("proxy class had incorrect annotation: " +
proxyAnnotation);
} else {
System.err.println("proxy class had correct annotation: " +
proxyAnnotation);
}
boolean proxyOk = false;
if (boomerangSemantics) {
ClassLoader ctxLoader =
Thread.currentThread().getContextClassLoader();
if (proxyLoader == ctxLoader) {
proxyOk = true;
}
} else if (proxyLoader.getClass().
getName().indexOf("sun.rmi") >= 0)
{
proxyOk = true;
}
if (proxyOk) {
System.err.println("\ncase5: proxy loaded from" +
" correct loader: " + proxyLoader);
} else {
TestLibrary.bomb("case5: proxy interface loaded from " +
"incorrect loader: " + proxyLoader);
}
}
}
private static class TestInvocationHandler
implements InvocationHandler, Serializable
{
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {return null;}
}
}