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
.environments
.java
;
21 import com
.sun
.star
.uno
.IEnvironment
;
22 import com
.sun
.star
.uno
.Type
;
23 import com
.sun
.star
.uno
.UnoRuntime
;
24 import java
.lang
.ref
.ReferenceQueue
;
25 import java
.lang
.ref
.WeakReference
;
26 import java
.util
.HashMap
;
27 import java
.util
.Iterator
;
30 * The java_environment is the environment where objects and
31 * interfaces are registered, which are mapped out of java or
34 * <p>The java_environment implements the <code>IEnvironment</code> interface
35 * defined in the uno runtime.</p>
37 * @see com.sun.star.uno.UnoRuntime
38 * @see com.sun.star.uno.IEnvironment
41 public final class java_environment
implements IEnvironment
{
42 public java_environment(Object context
) {
43 this.context
= context
;
48 * @see com.sun.star.uno.IEnvironment#getContext
50 public Object
getContext() {
56 * @see com.sun.star.uno.IEnvironment#getName
58 public String
getName() {
64 * @see com.sun.star.uno.IEnvironment#registerInterface
66 public Object
registerInterface(Object object
, String
[] oid
, Type type
) {
68 oid
[0] = UnoRuntime
.generateOid(object
);
70 return (isProxy(object
) ? proxies
: localObjects
).register(
71 object
, oid
[0], type
);
75 * You have to revoke ANY interface that has been registered via this
78 * @param oid object id of interface to be revoked.
79 * @param type the type description of the interface.
80 * @see com.sun.star.uno.IEnvironment#revokeInterface
82 public void revokeInterface(String oid
, Type type
) {
83 if (!proxies
.revoke(oid
, type
)) {
84 localObjects
.revoke(oid
, type
);
89 * Retrieves an interface identified by its object id and type from this
92 * @param oid object id of interface to be retrieved.
93 * @param type the type description of the interface to be retrieved.
94 * @see com.sun.star.uno.IEnvironment#getRegisteredInterface
96 public Object
getRegisteredInterface(String oid
, Type type
) {
97 Object o
= proxies
.get(oid
, type
);
99 o
= localObjects
.get(oid
, type
);
105 * Retrieves the object identifier for a registered interface from this
108 * @param object a registered interface.
109 * @see com.sun.star.uno.IEnvironment#getRegisteredObjectIdentifier
111 public String
getRegisteredObjectIdentifier(Object object
) {
112 return UnoRuntime
.generateOid(object
);
117 * @see com.sun.star.uno.IEnvironment#list
124 * Revokes all registered proxy interfaces.
126 * <p>This method should be part of <code>IEnvironment</code>. It is called
127 * from <code>com.sun.star.lib.uno.bridges.java_remote.<!--
128 * -->java_remote_bridge.dispose</code>.</p>
130 public void revokeAllProxies() {
134 // TODO What's this??? java.lang.Object#equals requires reflexivity...
136 // Maybe this was hacked in so that different bridges use different
137 // instances of java_environment. That is desirable for the following
138 // reason: An OID is bridged in over bridge A, a proxy is created on the
139 // Java side, and recorded in the java_environment. The same OID is then
140 // bridged in over another bridge B. If there were only one
141 // java_environment shared by both bridges, the proxy from bridge A would be
142 // reused. If now bridge A is taken down programatically (e.g., because
143 // some controlling code somehow deduced that no objects are mapped over
144 // that bridge any longer), but the proxy is still used by bridge B, using
145 // the proxy would now result in errors. The explicit API to control
146 // bridges forbids to transparently share proxies between bridges, and using
147 // different java_environment instances for different bridges is the way to
150 public boolean equals(Object obj
) {
154 private static final class Registry
{
155 public synchronized Object
register(
156 Object object
, String oid
, Type type
)
159 Level1Entry l1
= level1map
.get(oid
);
161 Level2Entry l2
= l1
.level2map
.get(type
);
170 // TODO If a holder references an unreachable object, but still has
171 // a positive count, it is replaced with a new holder (referencing a
172 // reachable object, and with a count of 1). Any later calls to
173 // revoke that should decrement the count of the previous holder
174 // would now decrement the count of the new holder, removing it
175 // prematurely. This is a design flaw that will be fixed when
176 // IEnvironment.revokeInterface is changed to no longer use
177 // counting. (And this problem is harmless, as currently a holder
178 // either references a strongly held object and uses register/revoke
179 // to control it, or references a weakly held proxy and never
182 l1
= new Level1Entry();
183 level1map
.put(oid
, l1
);
185 l1
.level2map
.put(type
, new Level2Entry(oid
, type
, object
, queue
));
189 public synchronized boolean revoke(String oid
, Type type
) {
190 Level1Entry l1
= level1map
.get(oid
);
191 Level2Entry l2
= null;
193 l2
= l1
.level2map
.get(type
);
194 if (l2
!= null && l2
.release()) {
195 removeLevel2Entry(l1
, oid
, type
);
202 public synchronized Object
get(String oid
, Type type
) {
203 Level1Entry l1
= level1map
.get(oid
);
204 return l1
== null ?
null : l1
.find(type
);
207 public synchronized void clear() {
212 // must only be called while synchronized on this Registry:
213 private void cleanUp() {
215 Object tmp
= queue
.poll();
216 Level2Entry l2
= (Level2Entry
) tmp
;
220 // It is possible that a Level2Entry e1 for the OID/type pair
221 // (o,t) becomes weakly reachable, then another Level2Entry e2
222 // is registered for the same pair (o,t) (a new Level2Entry is
223 // created since now e1.get() == null), and only then e1 is
224 // enqueued. To not erroneously remove the new e2 in that case,
225 // check whether the map still contains e1:
226 Level1Entry l1
= level1map
.get(l2
.oid
);
227 if (l1
!= null && l1
.level2map
.get(l2
.type
) == l2
) {
228 removeLevel2Entry(l1
, l2
.oid
, l2
.type
);
233 // must only be called while synchronized on this Registry:
234 private void removeLevel2Entry(Level1Entry l1
, String oid
, Type type
) {
235 l1
.level2map
.remove(type
);
236 if (l1
.level2map
.isEmpty()) {
237 level1map
.remove(oid
);
241 private static final class Level1Entry
{
242 // must only be called while synchronized on enclosing Registry:
243 public Object
find(Type type
) {
244 // First, look for an exactly matching entry; then, look for an
245 // arbitrary entry for a subtype of the request type:
246 Level2Entry l2
= level2map
.get(type
);
253 for (Iterator
<Level2Entry
> i
= level2map
.values().iterator();
257 if (type
.isSupertypeOf(l2
.type
)) {
267 public final HashMap
<Type
, Level2Entry
> level2map
=
268 new HashMap
<Type
, Level2Entry
>();
271 private static final class Level2Entry
extends WeakReference
<Object
> {
273 String oid
, Type type
, Object object
, ReferenceQueue
<Object
> queue
)
275 super(object
, queue
);
280 // must only be called while synchronized on enclosing Registry:
281 public void acquire() {
285 // must only be called while synchronized on enclosing Registry:
286 public boolean release() {
290 public final String oid
;
291 public final Type type
;
293 private int count
= 1;
296 private final HashMap
<String
, Level1Entry
> level1map
=
297 new HashMap
<String
, Level1Entry
>();
298 private final ReferenceQueue
<Object
> queue
= new ReferenceQueue
<Object
>();
301 private boolean isProxy(Object object
) {
302 return object
instanceof com
.sun
.star
.lib
.uno
.Proxy
;
305 private static final Registry localObjects
= new Registry();
307 private final Object context
;
308 private final Registry proxies
= new Registry();