J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. |
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| 4 | * |
| 5 | * This code is free software; you can redistribute it and/or modify it |
| 6 | * under the terms of the GNU General Public License version 2 only, as |
| 7 | * published by the Free Software Foundation. |
| 8 | * |
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 12 | * version 2 for more details (a copy is included in the LICENSE file that |
| 13 | * accompanied this code). |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License version |
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| 18 | * |
| 19 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 20 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 21 | * have any questions. |
| 22 | */ |
| 23 | |
| 24 | /* |
| 25 | * @test |
| 26 | * @bug 5021246 |
| 27 | * @summary Check that class downloading is supported by RMI connector |
| 28 | * @author Eamonn McManus |
| 29 | * @run main RMIDownloadTest receive without |
| 30 | * @run main RMIDownloadTest send without |
| 31 | * @run main RMIDownloadTest receive with |
| 32 | * @run main RMIDownloadTest send with |
| 33 | */ |
| 34 | |
| 35 | /* |
| 36 | * This test checks that class downloading is supported by the RMI connector. |
| 37 | * We copy a precompiled class file into the temporary directory (which we |
| 38 | * assume is not in the classpath). We also create an instance of that |
| 39 | * class using a hardcoded ClassLoader. Then we try to get a remote attribute |
| 40 | * that returns that instance, and we try to set the remote attribute to the |
| 41 | * instance. In both cases, this will only work if the class can be downloaded |
| 42 | * based on the codebase that we have set to the temporary directory. We also |
| 43 | * test that it does *not* work when the codebase is not set, in case the test |
| 44 | * is succeeding for some other reason. |
| 45 | * |
| 46 | * We run the test four times, for each combination of (send, receive) x |
| 47 | * (with-codebase, without-codebase). Doing all four tests within the same |
| 48 | * run doesn't work, probably because RMI remembers the codebase property |
| 49 | * setting at some point. |
| 50 | */ |
| 51 | |
| 52 | import java.io.File; |
| 53 | import java.io.FileOutputStream; |
| 54 | import java.io.OutputStream; |
| 55 | import java.lang.management.ManagementFactory; |
| 56 | import java.net.URL; |
| 57 | import java.security.Permission; |
| 58 | import java.util.Arrays; |
| 59 | import javax.management.Attribute; |
| 60 | import javax.management.MBeanServer; |
| 61 | import javax.management.MBeanServerConnection; |
| 62 | import javax.management.ObjectName; |
| 63 | import javax.management.remote.JMXConnector; |
| 64 | import javax.management.remote.JMXConnectorFactory; |
| 65 | import javax.management.remote.JMXConnectorServer; |
| 66 | import javax.management.remote.JMXConnectorServerFactory; |
| 67 | import javax.management.remote.JMXServiceURL; |
| 68 | |
| 69 | public class RMIDownloadTest { |
| 70 | /* Following byte array was produced from this class: |
| 71 | * |
| 72 | * public class Zooby implements java.io.Serializable {} |
| 73 | * |
| 74 | * by this program: |
| 75 | * |
| 76 | * public class MakeZooby { |
| 77 | * public static void main(String[] args) throws Exception { |
| 78 | * int b; |
| 79 | * for (int offset = 0; (b = System.in.read()) >= 0; offset++) { |
| 80 | * System.out.print((byte) b + "," + |
| 81 | * ((offset % 16) == 15 ? '\n' : ' ')); |
| 82 | * } |
| 83 | * System.out.println(); |
| 84 | * } |
| 85 | * } |
| 86 | */ |
| 87 | private static final byte[] zoobyClassBytes = { |
| 88 | -54, -2, -70, -66, 0, 0, 0, 49, 0, 12, 10, 0, 3, 0, 8, 7, |
| 89 | 0, 9, 7, 0, 10, 7, 0, 11, 1, 0, 6, 60, 105, 110, 105, 116, |
| 90 | 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 100, 101, 12, 0, |
| 91 | 5, 0, 6, 1, 0, 5, 90, 111, 111, 98, 121, 1, 0, 16, 106, 97, |
| 92 | 118, 97, 47, 108, 97, 110, 103, 47, 79, 98, 106, 101, 99, 116, 1, 0, |
| 93 | 20, 106, 97, 118, 97, 47, 105, 111, 47, 83, 101, 114, 105, 97, 108, 105, |
| 94 | 122, 97, 98, 108, 101, 0, 33, 0, 2, 0, 3, 0, 1, 0, 4, 0, |
| 95 | 0, 0, 1, 0, 1, 0, 5, 0, 6, 0, 1, 0, 7, 0, 0, 0, |
| 96 | 17, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, |
| 97 | 0, 0, 0, 0, |
| 98 | }; |
| 99 | |
| 100 | private static class ZoobyClassLoader extends ClassLoader { |
| 101 | protected Class<?> findClass(String name) throws ClassNotFoundException { |
| 102 | if (name.equals("Zooby")) { |
| 103 | return super.defineClass(name, zoobyClassBytes, |
| 104 | 0, zoobyClassBytes.length); |
| 105 | } else |
| 106 | throw new ClassNotFoundException(name); |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | |
| 111 | private static MBeanServer pmbs; |
| 112 | private static ObjectName getSetName; |
| 113 | private static GetSet getSetInstance; |
| 114 | |
| 115 | public static void main(String[] args) throws Exception { |
| 116 | int sendIndex = -1; |
| 117 | int withIndex = -1; |
| 118 | if (args.length == 2) { |
| 119 | sendIndex = |
| 120 | Arrays.asList("send", "receive").indexOf(args[0]); |
| 121 | withIndex = |
| 122 | Arrays.asList("with", "without").indexOf(args[1]); |
| 123 | } |
| 124 | if (sendIndex < 0 || withIndex < 0) |
| 125 | throw new Exception("Usage: RMIDownloadTest (send|receive) (with|without)"); |
| 126 | final boolean send = (sendIndex == 0); |
| 127 | final boolean with = (withIndex == 0); |
| 128 | |
| 129 | pmbs = ManagementFactory.getPlatformMBeanServer(); |
| 130 | getSetName = new ObjectName(":type=GetSet"); |
| 131 | getSetInstance = new GetSet(); |
| 132 | pmbs.registerMBean(getSetInstance, getSetName); |
| 133 | |
| 134 | System.setSecurityManager(new LaidBackSecurityManager()); |
| 135 | |
| 136 | // System.setProperty("sun.rmi.loader.logLevel", "VERBOSE"); |
| 137 | |
| 138 | String tmpdir = System.getProperty("java.io.tmpdir"); |
| 139 | String classfile = tmpdir + File.separator + "Zooby.class"; |
| 140 | File zoobyFile = new File(classfile); |
| 141 | zoobyFile.deleteOnExit(); |
| 142 | OutputStream os = new FileOutputStream(zoobyFile); |
| 143 | for (byte b : zoobyClassBytes) |
| 144 | os.write(b); |
| 145 | os.close(); |
| 146 | |
| 147 | // Check that we can't load the Zooby class from the classpath |
| 148 | try { |
| 149 | Class.forName("Zooby"); |
| 150 | throw new Exception("Class \"Zooby\" is in the classpath!"); |
| 151 | } catch (ClassNotFoundException e) { |
| 152 | // OK: expected |
| 153 | } |
| 154 | |
| 155 | if (send) |
| 156 | System.out.println("Testing we can send an object from client to server"); |
| 157 | else |
| 158 | System.out.println("Testing we can receive an object from server to client"); |
| 159 | |
| 160 | if (with) { |
| 161 | // Test with the codebase property. Downloading should work. |
| 162 | URL zoobyURL = zoobyFile.getParentFile().toURI().toURL(); |
| 163 | System.setProperty("java.rmi.server.codebase", zoobyURL.toString()); |
| 164 | System.out.println("Testing with codebase, should work"); |
| 165 | System.out.println("Codebase is " + |
| 166 | System.getProperty("java.rmi.server.codebase")); |
| 167 | test(send, true); |
| 168 | } else { |
| 169 | // Test without setting the codebase property. |
| 170 | // This should not work; if it does it probably means java.io.tmpdir |
| 171 | // is in the classpath. |
| 172 | System.out.println("Testing without codebase, should fail"); |
| 173 | test(send, false); |
| 174 | } |
| 175 | |
| 176 | } |
| 177 | |
| 178 | private static void test(boolean send, boolean shouldWork) throws Exception { |
| 179 | try { |
| 180 | testWithException(send); |
| 181 | } catch (Exception e) { |
| 182 | if (shouldWork) |
| 183 | throw e; |
| 184 | System.out.println("Got exception as expected: " + e); |
| 185 | return; |
| 186 | } |
| 187 | if (!shouldWork) |
| 188 | throw new Exception("Test passed without codebase but should not"); |
| 189 | } |
| 190 | |
| 191 | private static void testWithException(boolean send) |
| 192 | throws Exception { |
| 193 | ClassLoader zoobyCL = new ZoobyClassLoader(); |
| 194 | Class<?> zoobyClass = Class.forName("Zooby", false, zoobyCL); |
| 195 | Object zooby = zoobyClass.newInstance(); |
| 196 | |
| 197 | JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///"); |
| 198 | JMXConnectorServer cs = |
| 199 | JMXConnectorServerFactory.newJMXConnectorServer(url, null, pmbs); |
| 200 | cs.start(); |
| 201 | JMXServiceURL addr = cs.getAddress(); |
| 202 | JMXConnector cc = JMXConnectorFactory.connect(addr); |
| 203 | MBeanServerConnection mbsc = cc.getMBeanServerConnection(); |
| 204 | |
| 205 | Object rzooby; |
| 206 | if (send) { |
| 207 | System.out.println("Sending object..."); |
| 208 | mbsc.setAttribute(getSetName, new Attribute("It", zooby)); |
| 209 | rzooby = getSetInstance.getIt(); |
| 210 | } else { |
| 211 | System.out.println("Receiving object..."); |
| 212 | getSetInstance.setIt(zooby); |
| 213 | rzooby = mbsc.getAttribute(getSetName, "It"); |
| 214 | } |
| 215 | |
| 216 | if (!rzooby.getClass().getName().equals("Zooby")) { |
| 217 | throw new Exception("FAILED: remote object is not a Zooby"); |
| 218 | } |
| 219 | if (rzooby.getClass().getClassLoader() == |
| 220 | zooby.getClass().getClassLoader()) { |
| 221 | throw new Exception("FAILED: same class loader: " + |
| 222 | zooby.getClass().getClassLoader()); |
| 223 | } |
| 224 | |
| 225 | cc.close(); |
| 226 | cs.stop(); |
| 227 | } |
| 228 | |
| 229 | public static interface GetSetMBean { |
| 230 | public Object getIt(); |
| 231 | public void setIt(Object x); |
| 232 | } |
| 233 | |
| 234 | public static class GetSet implements GetSetMBean { |
| 235 | public GetSet() { |
| 236 | } |
| 237 | |
| 238 | public Object getIt() { |
| 239 | return what; |
| 240 | } |
| 241 | |
| 242 | public void setIt(Object x) { |
| 243 | this.what = x; |
| 244 | } |
| 245 | |
| 246 | private Object what; |
| 247 | } |
| 248 | |
| 249 | public static class LaidBackSecurityManager extends SecurityManager { |
| 250 | public void checkPermission(Permission perm) { |
| 251 | // OK, dude |
| 252 | } |
| 253 | } |
| 254 | } |