2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 package com
.sun
.star
.lib
.uno
.bridges
.java_remote
;
21 import com
.sun
.star
.bridge
.XBridge
;
22 import com
.sun
.star
.lib
.util
.AsynchronousFinalizer
;
23 import com
.sun
.star
.uno
.IQueryInterface
;
24 import com
.sun
.star
.uno
.Type
;
25 import com
.sun
.star
.uno
.UnoRuntime
;
27 import java
.lang
.reflect
.InvocationHandler
;
28 import java
.lang
.reflect
.Method
;
29 import java
.lang
.reflect
.Proxy
;
32 * A factory for proxies specific to the <code>java_remote_bridge</code>.
34 * <p>Eventually, this class should be united with all other proxy classes
35 * specific to certain bridges (for example, the JNI bridge), resulting in a
36 * generic proxy class.</p>
38 final class ProxyFactory
{
39 public ProxyFactory(RequestHandler requestHandler
, XBridge bridge
) {
40 this.requestHandler
= requestHandler
;
44 public Object
create(String oid
, Type type
) {
45 return Proxy
.newProxyInstance(
46 getClass().getClassLoader(),
47 new Class
[] { com
.sun
.star
.lib
.uno
.Proxy
.class,
48 IQueryInterface
.class, type
.getZClass() },
49 new Handler(oid
, type
));
52 public boolean isProxy(Object obj
) {
53 if (Proxy
.isProxyClass(obj
.getClass())) {
54 InvocationHandler h
= Proxy
.getInvocationHandler(obj
);
55 return h
instanceof Handler
&& ((Handler
) h
).matches(this);
61 public void dispose() throws InterruptedException
{
62 asynchronousFinalizer
.drain();
65 public static XBridge
getBridge(Object obj
) {
66 if (Proxy
.isProxyClass(obj
.getClass())) {
67 InvocationHandler h
= Proxy
.getInvocationHandler(obj
);
68 if (h
instanceof Handler
) {
69 return ((Handler
) h
).getBridge();
75 static int getDebugCount() {
76 synchronized (debugCountLock
) {
81 private static void incrementDebugCount() {
82 synchronized (debugCountLock
) {
87 private static void decrementDebugCount() {
88 synchronized (debugCountLock
) {
93 private final class Handler
implements InvocationHandler
{
94 public Handler(String oid
, Type type
) {
97 incrementDebugCount();
100 public boolean matches(ProxyFactory factory
) {
101 return ProxyFactory
.this == factory
;
104 public XBridge
getBridge() {
108 public Object
invoke(Object proxy
, Method method
, Object
[] args
)
111 if (method
.equals(METHOD_EQUALS
) || method
.equals(METHOD_IS_SAME
)) {
112 return Boolean
.valueOf(args
[0] != null
113 && oid
.equals(UnoRuntime
.generateOid(args
[0])));
114 } else if (method
.equals(METHOD_HASH_CODE
)) {
115 return Integer
.valueOf(oid
.hashCode());
116 } else if (method
.equals(METHOD_TO_STRING
)) {
117 return "[Proxy:" + System
.identityHashCode(proxy
) + "," + oid
119 } else if (method
.equals(METHOD_QUERY_INTERFACE
)) {
120 // See the comment in java_remote_bridge.mapInterfaceTo for one
121 // reason why this implementation must not satisfy a request for
122 // a super-interface with a proxy itself:
123 return args
[0].equals(type
) ? proxy
124 : request("queryInterface", args
);
125 } else if (method
.equals(METHOD_GET_OID
)) {
128 return request(method
.getName(), args
);
133 protected void finalize() {
134 decrementDebugCount();
135 asynchronousFinalizer
.add(new AsynchronousFinalizer
.Job() {
136 public void run() throws Throwable
{
137 request("release", null);
142 private Object
request(String operation
, Object
[] args
) throws Throwable
144 Object res
= requestHandler
.sendRequest(oid
, type
, operation
, args
);
145 // Avoid early finalization of this object, while an invoke ->
146 // request call is still ongoing; as finalize also calls request,
147 // this should fulfil the condition from The Java Language
148 // Specification, 3rd ed., that "if an object's finalizer can result
149 // in synchronization on that object, then that object must be alive
150 // and considered reachable whenever a lock is held on it:"
151 synchronized (this) {
157 private final String oid
;
158 private final Type type
;
159 @SuppressWarnings("unused")
160 private int dummy
= 0;
163 private static final Method METHOD_EQUALS
;
164 private static final Method METHOD_HASH_CODE
;
165 private static final Method METHOD_TO_STRING
;
166 private static final Method METHOD_QUERY_INTERFACE
;
167 private static final Method METHOD_IS_SAME
;
168 private static final Method METHOD_GET_OID
;
171 METHOD_EQUALS
= Object
.class.getMethod(
172 "equals", new Class
[] { Object
.class });
173 METHOD_HASH_CODE
= Object
.class.getMethod(
174 "hashCode", (Class
[]) null);
175 METHOD_TO_STRING
= Object
.class.getMethod(
176 "toString", (Class
[]) null);
177 METHOD_QUERY_INTERFACE
= IQueryInterface
.class.getMethod(
178 "queryInterface", new Class
[] { Type
.class });
179 METHOD_IS_SAME
= IQueryInterface
.class.getMethod(
180 "isSame", new Class
[] { Object
.class });
181 METHOD_GET_OID
= IQueryInterface
.class.getMethod(
182 "getOid", (Class
[]) null);
183 } catch (NoSuchMethodException e
) {
184 throw new ExceptionInInitializerError(e
);
188 private static final Object debugCountLock
= new Object();
189 private static int debugCount
= 0;
191 private final RequestHandler requestHandler
;
192 private final XBridge bridge
;
193 private final AsynchronousFinalizer asynchronousFinalizer
=
194 new AsynchronousFinalizer();