/* * Copyright (c) 1998, 2012, 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. */ /* */ import java.rmi.*; import sun.rmi.transport.*; import sun.rmi.*; import java.io.*; import java.lang.reflect.*; import java.rmi.dgc.*; import java.util.*; import java.rmi.registry.*; import java.rmi.server.*; public class TestImpl extends UnicastRemoteObject implements Test { static Thread locker = null; static TestImpl foo = null; static TestImpl bar = null; TestImpl() throws RemoteException { } public String echo(String msg) throws RemoteException { if (locker == null) { // hold the target if not already held locker = lockTargetExpireLeases(foo, DGCDeadLock.HOLD_TARGET_TIME); } return "Message received: " + msg; } static public void main(String[] args) { Registry registry = null; try { int registryPort = Integer.parseInt(System.getProperty("rmi.registry.port")); registry = java.rmi.registry.LocateRegistry. createRegistry(registryPort); //export "Foo" foo = new TestImpl(); Naming.rebind("rmi://:" + registryPort + "/Foo", foo); try { //export "Bar" after leases have been expired. bar = new TestImpl(); Naming.rebind("rmi://localhost:" + registryPort + "/Bar", bar); } catch (Exception e) { throw new RemoteException(e.getMessage()); } Thread.sleep(DGCDeadLock.TEST_FAIL_TIME); System.err.println("object vm exiting..."); System.exit(0); } catch (Exception e) { System.err.println(e.getMessage()); e.printStackTrace(); } finally { TestLibrary.unexport(registry); registry = null; } } static Thread lockTargetExpireLeases(Remote toLock, int timeOut) { Thread t = new Thread((Runnable) new TargetLocker(toLock, timeOut)); t.start(); return t; } static class TargetLocker implements Runnable { Remote toLock = null; int timeOut = 0; TargetLocker(Remote toLock, int timeOut) { this.toLock = toLock; this.timeOut = timeOut; } public void run() { try { // give dgc dirty calls time to finish. Thread.currentThread().sleep(4000); java.security.AccessController. doPrivileged(new LockTargetCheckLeases(toLock, timeOut)); } catch (Exception e) { System.err.println(e.getMessage()); e.printStackTrace(); System.exit(1); } } } static class LockTargetCheckLeases implements java.security.PrivilegedAction { Remote toLock = null; int timeOut = 0; LockTargetCheckLeases(Remote toLock, int timeOut) { this.toLock = toLock; this.timeOut = timeOut; } public Object run() { try { Class args[] = new Class[1]; Class objTableClass = Class.forName ("sun.rmi.transport.ObjectTable"); /* get the Target that corresponds to toLock from the * ObjectTable */ args[0] = Class.forName("java.rmi.Remote"); Method objTableGetTarget = objTableClass.getDeclaredMethod("getTarget", args ); objTableGetTarget.setAccessible(true); Target lockTarget = ((Target) objTableGetTarget.invoke (null , new Object [] {toLock} )); // make sure the lease on this object has expired. expireLeases(lockTarget); // stop other threads from using the target for toLock. synchronized (lockTarget) { System.err.println("Locked the relevant target, sleeping " + timeOut/1000 + " seconds"); Thread.currentThread().sleep(timeOut); System.err.println("Target unlocked"); } } catch (Exception e) { System.err.println(e.getMessage()); e.printStackTrace(); System.exit(1); } return null; } } /* leases have long values, so no dirty calls which would lock out * a clean call, but the leases need to expire anyway, so we do it * explicitly. */ static void expireLeases(Target t) throws Exception { final Target target = t; java.security.AccessController.doPrivileged( // put this into another class? new java.security.PrivilegedAction() { public Object run() { try { Class DGCClass = Class.forName("sun.rmi.transport.DGCImpl"); Method getDGCImpl = DGCClass.getDeclaredMethod("getDGCImpl", null ); getDGCImpl.setAccessible(true); // make sure the lease on this object has expired. DGC dgcImpl = ((DGC) getDGCImpl.invoke(null, null)); /* Get the lease table from the DGCImpl. */ Field reflectedLeaseTable = dgcImpl.getClass().getDeclaredField("leaseTable"); reflectedLeaseTable.setAccessible(true); Map leaseTable = (Map) reflectedLeaseTable.get(dgcImpl); // dont really need this synchronization... synchronized (leaseTable) { Iterator en = leaseTable.values().iterator(); while (en.hasNext()) { Object info = en.next(); /* Get the notifySet in the leaseInfo object. */ Field notifySetField = info.getClass().getDeclaredField("notifySet"); notifySetField.setAccessible(true); HashSet notifySet = (HashSet) notifySetField.get(info); Iterator iter = notifySet.iterator(); while (iter.hasNext()) { Target notified = (Target) iter.next(); if (notified == target) { /* Get and set the expiration field from the info object. */ Field expirationField = info.getClass(). getDeclaredField("expiration"); expirationField.setAccessible(true); expirationField.setLong(info, 0); } } } } } catch (Exception e) { System.err.println(e.getMessage()); e.printStackTrace(); System.exit(1); } // no interesting return value for this privileged action return null; } }); } }