Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/java/rmi/dgc/dgcAckFailure/DGCAckFailure.java
38828 views
/*1* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/* @test24* @bug 4017232 804633925* @summary If, after returning a reference to a remote object in the current26* VM (which gets implicitly converted to a remote stub), the client fails to27* both send a DGC dirty call and to send a "DGC acknowledgment", the RMI28* runtime should eventually allow the remote object to be garbage collected,29* rather than pinning it indefinitely.30* @author Peter Jones31*32* @build DGCAckFailure DGCAckFailure_Stub33* @run main/othervm DGCAckFailure34*/3536import java.io.*;37import java.net.*;38import java.lang.reflect.Field;39import java.lang.ref.*;4041import java.rmi.*;42import java.rmi.server.*;43import java.util.Map;4445import sun.rmi.transport.DGCAckHandler;4647interface ReturnRemote extends Remote {48Object returnRemote() throws RemoteException;49}5051public class DGCAckFailure implements ReturnRemote {5253private static final long TIMEOUT = 20000;54private static final long ACK_TIMEOUT = TIMEOUT / 2;5556public Object returnRemote() {57return new Wrapper(this);58}5960public static void main(String[] args) throws Exception {6162System.setProperty("sun.rmi.dgc.ackTimeout",63Long.toString(ACK_TIMEOUT));6465/*66* Set a socket factory that has a hook for shutting down all client67* output (writes from client-created sockets and new connection68* attempts). We then use this hook right before a remote stub gets69* deserialized, so that the client will not be able to send a DGC70* dirty call, or a DGC acknowledgment. Without the DGC ack, we71* hope that the RMI runtime will still eventually allow the remote72* object to be garbage collected.73*/74RMISocketFactory.setSocketFactory(new TestSF());75System.err.println("test socket factory set");7677Remote impl = new DGCAckFailure();78ReferenceQueue refQueue = new ReferenceQueue();79Reference weakRef = new WeakReference(impl, refQueue);80ReturnRemote stub =81(ReturnRemote) UnicastRemoteObject.exportObject(impl);82System.err.println("remote object exported; stub = " + stub);8384try {85Object wrappedStub = stub.returnRemote();86System.err.println("invocation returned: " + wrappedStub);8788impl = null;89stub = null; // in case 4114579 ever gets fixed90System.err.println("strong references to impl cleared");9192System.err.println("waiting for weak reference notification:");93Reference ref = null;94for (int i = 0; i < 6; i++) {95System.gc();96ref = refQueue.remove(TIMEOUT / 5);97if (ref != null) {98break;99}100}101if (ref != weakRef) {102throw new RuntimeException("TEST FAILED: " +103"timed out, remote object not garbage collected");104}105106// 8046339107// All DGCAckHandlers must be properly released after timeout108Thread.sleep(ACK_TIMEOUT + 100);109try {110Field field =111DGCAckHandler.class.getDeclaredField("idTable");112field.setAccessible(true);113Object obj = field.get(null);114Map<?,?> idTable = (Map<?,?>)obj;115116if (!idTable.isEmpty()) {117throw new RuntimeException("TEST FAILED: " +118"DGCAckHandler.idTable isn't empty");119}120} catch (ReflectiveOperationException roe) {121throw new RuntimeException(roe);122}123124System.err.println("TEST PASSED");125126} finally {127try {128UnicastRemoteObject.unexportObject((Remote) weakRef.get(),129true);130} catch (Exception e) {131}132}133}134135private static class Wrapper implements Serializable {136private final Remote obj;137Wrapper(Remote obj) { this.obj = obj; }138139private void readObject(ObjectInputStream in)140throws IOException, ClassNotFoundException141{142TestSF.shutdownClientOutput();143System.err.println(144"Wrapper.readObject: SHUTTING DOWN CLIENT OUTPUT");145in.defaultReadObject();146}147148public String toString() { return "Wrapper[" + obj + "]"; }149}150151private static class TestSF extends RMISocketFactory {152153private static volatile boolean shutdown = false;154static void shutdownClientOutput() { shutdown = true; }155156public Socket createSocket(String host, int port) throws IOException {157if (shutdown) {158IOException e = new java.net.ConnectException(159"test socket factory rejecting client connection");160System.err.println(e);161// e.printStackTrace();162throw e;163} else {164return new TestSocket(host, port);165}166}167168public ServerSocket createServerSocket(int port) throws IOException {169return new ServerSocket(port);170}171172private static class TestSocket extends Socket {173TestSocket(String host, int port) throws IOException {174super(host, port);175}176public OutputStream getOutputStream() throws IOException {177return new TestOutputStream(super.getOutputStream());178}179}180181private static class TestOutputStream extends FilterOutputStream {182TestOutputStream(OutputStream out) { super(out); }183public void write(int b) throws IOException {184if (shutdown) {185IOException e = new IOException(186"connection broken by test socket factory");187System.err.println(e);188// e.printStackTrace();189throw e;190} else {191super.write(b);192}193}194}195}196}197198199