1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package com.sun.star.lib.uno.bridges.javaremote;
25 
26 import com.sun.star.bridge.XInstanceProvider;
27 import com.sun.star.lib.TestBed;
28 import com.sun.star.lib.uno.typeinfo.MethodTypeInfo;
29 import com.sun.star.lib.uno.typeinfo.TypeInfo;
30 import com.sun.star.uno.UnoRuntime;
31 import com.sun.star.uno.XComponentContext;
32 import com.sun.star.uno.XInterface;
33 import complexlib.ComplexTestCase;
34 
35 /**
36  * Test case for bug #108825#.
37  *
38  * <p>Bug #108825# "Java UNO Remote Bridge: Mapped-out Objects Not Held" shows
39  * that local objects that are mapped out via a remote bridge, but not held
40  * locally, might be garbage collected while there are still remote references
41  * to them.  This test is not guaranteed to always work reliably, see comment in
42  * the code.</p>
43  */
44 public final class Bug108825_Test extends ComplexTestCase {
getTestObjectName()45     public String getTestObjectName() {
46         return getClass().getName();
47     }
48 
getTestMethodNames()49     public String[] getTestMethodNames() {
50         return new String[] { "test" };
51     }
52 
test()53     public void test() throws Exception {
54         TestBed t = new TestBed();
55         assure("test", t.execute(new Provider(t), true, Client.class, 0));
56     }
57 
58     public static final class Client extends TestBed.Client {
main(String[] args)59         public static void main(String[] args) {
60             new Client().execute();
61         }
62 
run(XComponentContext context)63         protected boolean run(XComponentContext context) throws Throwable {
64             XTest test = UnoRuntime.queryInterface(
65                 XTest.class, getBridge(context).getInstance("Test"));
66             // Send the XObject that is held on the server side amidst two
67             // dummies that are not held on the server side; then wait for the
68             // dummies to be garbage collected, hoping that the XObject, if it
69             // is erroneously not held on the client side, will be garbage
70             // collected, too.  Obviously, this is not guaranteed to always work
71             // (the VM might chose not to garbage collect the dummies, hanging
72             // the test forever; or the VM might chose to garbage collect the
73             // dummies but not the XObject, making the test pass erroneously).
74             test.offer(new Dummy(), new XObject() { public void call() {} },
75                        new Dummy());
76             System.out.println("Client waiting for garbage collection...");
77             for (;;) {
78                 synchronized (lock) {
79                     if (finalizedCount == 2) {
80                         break;
81                     }
82                 }
83                 test.remoteGc();
84                 gc();
85             }
86             System.out.println("Client garbage collection done.");
87             test.notification();
88             return true;
89         }
90 
91         private final class Dummy implements XDummy {
finalize()92             protected void finalize() {
93                 synchronized (lock) {
94                     ++finalizedCount;
95                 }
96             }
97         }
98 
99         private final Object lock = new Object();
100         private int finalizedCount = 0;
101     }
102 
103     // Make it as likely as possible that the VM reclaims all garbage:
gc()104     private static void gc() {
105         System.gc();
106         System.runFinalization();
107         byte[] garbage = new byte[1024 * 1024];
108     }
109 
110     private static final class Provider implements XInstanceProvider {
Provider(TestBed testBed)111         public Provider(TestBed testBed) {
112             this.testBed = testBed;
113         }
114 
getInstance(String instanceName)115         public Object getInstance(String instanceName) {
116             return new XTest() {
117                     public void offer(XDummy dummy1, XObject obj, XDummy dummy2)
118                     {
119                         this.obj = obj;
120                     }
121 
122                     public void remoteGc() {
123                         gc();
124                     }
125 
126                     public void notification() {
127                         obj.call();
128                         testBed.serverDone(true);
129                     }
130 
131                     private XObject obj;
132                 };
133         }
134 
135         private final TestBed testBed;
136     }
137 
138     public interface XDummy extends XInterface {
139         TypeInfo[] UNOTYPEINFO = null;
140     }
141 
142     public interface XObject extends XInterface {
143         void call();
144 
145         TypeInfo[] UNOTYPEINFO = { new MethodTypeInfo("call", 0, 0) };
146     }
147 
148     public interface XTest extends XInterface {
149         void offer(XDummy dummy1, XObject obj, XDummy dummy2);
150 
151         void remoteGc();
152 
153         void notification();
154 
155         TypeInfo[] UNOTYPEINFO = { new MethodTypeInfo("offer", 0, 0),
156                                    new MethodTypeInfo("remoteGc", 1, 0),
157                                    new MethodTypeInfo("notification", 2, 0) };
158     }
159 }
160