1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 package com
.sun
.star
.lib
.uno
.environments
.java
;
22 import com
.sun
.star
.uno
.IEnvironment
;
23 import com
.sun
.star
.uno
.Type
;
24 import com
.sun
.star
.uno
.UnoRuntime
;
25 import java
.lang
.ref
.ReferenceQueue
;
26 import java
.lang
.ref
.WeakReference
;
27 import java
.util
.HashMap
;
28 import java
.util
.Iterator
;
31 * The java_environment is the environment where objects and
32 * interfaces are registered, which are mapped out of java or
35 * <p>The java_environment implements the <code>IEnvironment</code> interface
36 * defined in the uno runtime.</p>
38 * @see com.sun.star.uno.UnoRuntime
39 * @see com.sun.star.uno.IEnvironment
42 public final class java_environment
implements IEnvironment
{
43 public java_environment(Object context
) {
44 this.context
= context
;
49 * @see com.sun.star.uno.IEnvironment#getContext
51 public Object
getContext() {
57 * @see com.sun.star.uno.IEnvironment#getName
59 public String
getName() {
65 * @see com.sun.star.uno.IEnvironment#registerInterface
67 public Object
registerInterface(Object object
, String
[] oid
, Type type
) {
69 oid
[0] = UnoRuntime
.generateOid(object
);
71 return (isProxy(object
) ? proxies
: localObjects
).register(
72 object
, oid
[0], type
);
76 * You have to revoke ANY interface that has been registered via this
79 * @param oid object id of interface to be revoked.
80 * @param type the type description of the interface.
81 * @see com.sun.star.uno.IEnvironment#revokeInterface
83 public void revokeInterface(String oid
, Type type
) {
84 if (!proxies
.revoke(oid
, type
)) {
85 localObjects
.revoke(oid
, type
);
90 * Retrieves an interface identified by its object id and type from this
93 * @param oid object id of interface to be retrieved.
94 * @param type the type description of the interface to be retrieved.
95 * @see com.sun.star.uno.IEnvironment#getRegisteredInterface
97 public Object
getRegisteredInterface(String oid
, Type type
) {
98 Object o
= proxies
.get(oid
, type
);
100 o
= localObjects
.get(oid
, type
);
106 * Retrieves the object identifier for a registered interface from this
109 * @param object a registered interface.
110 * @see com.sun.star.uno.IEnvironment#getRegisteredObjectIdentifier
112 public String
getRegisteredObjectIdentifier(Object object
) {
113 return UnoRuntime
.generateOid(object
);
118 * @see com.sun.star.uno.IEnvironment#list
125 * Revokes all registered proxy interfaces.
127 * <p>This method should be part of <code>IEnvironment</code>. It is called
128 * from <code>com.sun.star.lib.uno.bridges.java_remote.<!--
129 * -->java_remote_bridge.dispose</code>.</p>
131 public void revokeAllProxies() {
135 // TODO What's this??? java.lang.Object#equals requires reflexivity...
137 // Maybe this was hacked in so that different bridges use different
138 // instances of java_environment. That is desirable for the following
139 // reason: An OID is bridged in over bridge A, a proxy is created on the
140 // Java side, and recorded in the java_environment. The same OID is then
141 // bridged in over another bridge B. If there were only one
142 // java_environment shared by both bridges, the proxy from bridge A would be
143 // reused. If now bridge A is taken down programmatically (e.g., because
144 // some controlling code somehow deduced that no objects are mapped over
145 // that bridge any longer), but the proxy is still used by bridge B, using
146 // the proxy would now result in errors. The explicit API to control
147 // bridges forbids to transparently share proxies between bridges, and using
148 // different java_environment instances for different bridges is the way to
151 public boolean equals(Object obj
) {
155 private static final class Registry
{
156 public synchronized Object
register(
157 Object object
, String oid
, Type type
)
160 Level1Entry l1
= level1map
.get(oid
);
162 Level2Entry l2
= l1
.level2map
.get(type
);
171 // TODO If a holder references an unreachable object, but still has
172 // a positive count, it is replaced with a new holder (referencing a
173 // reachable object, and with a count of 1). Any later calls to
174 // revoke that should decrement the count of the previous holder
175 // would now decrement the count of the new holder, removing it
176 // prematurely. This is a design flaw that will be fixed when
177 // IEnvironment.revokeInterface is changed to no longer use
178 // counting. (And this problem is harmless, as currently a holder
179 // either references a strongly held object and uses register/revoke
180 // to control it, or references a weakly held proxy and never
183 l1
= new Level1Entry();
184 level1map
.put(oid
, l1
);
186 l1
.level2map
.put(type
, new Level2Entry(oid
, type
, object
, queue
));
190 public synchronized boolean revoke(String oid
, Type type
) {
191 Level1Entry l1
= level1map
.get(oid
);
192 Level2Entry l2
= null;
194 l2
= l1
.level2map
.get(type
);
195 if (l2
!= null && l2
.release()) {
196 removeLevel2Entry(l1
, oid
, type
);
203 public synchronized Object
get(String oid
, Type type
) {
204 Level1Entry l1
= level1map
.get(oid
);
205 return l1
== null ?
null : l1
.find(type
);
208 public synchronized void clear() {
213 // must only be called while synchronized on this Registry:
214 private void cleanUp() {
216 Object tmp
= queue
.poll();
217 Level2Entry l2
= (Level2Entry
) tmp
;
221 // It is possible that a Level2Entry e1 for the OID/type pair
222 // (o,t) becomes weakly reachable, then another Level2Entry e2
223 // is registered for the same pair (o,t) (a new Level2Entry is
224 // created since now e1.get() == null), and only then e1 is
225 // enqueued. To not erroneously remove the new e2 in that case,
226 // check whether the map still contains e1:
227 Level1Entry l1
= level1map
.get(l2
.oid
);
228 if (l1
!= null && l1
.level2map
.get(l2
.type
) == l2
) {
229 removeLevel2Entry(l1
, l2
.oid
, l2
.type
);
234 // must only be called while synchronized on this Registry:
235 private void removeLevel2Entry(Level1Entry l1
, String oid
, Type type
) {
236 l1
.level2map
.remove(type
);
237 if (l1
.level2map
.isEmpty()) {
238 level1map
.remove(oid
);
242 private static final class Level1Entry
{
243 // must only be called while synchronized on enclosing Registry:
244 public Object
find(Type type
) {
245 // First, look for an exactly matching entry; then, look for an
246 // arbitrary entry for a subtype of the request type:
247 Level2Entry l2
= level2map
.get(type
);
254 for (Iterator
<Level2Entry
> i
= level2map
.values().iterator();
258 if (type
.isSupertypeOf(l2
.type
)) {
268 public final HashMap
<Type
, Level2Entry
> level2map
=
269 new HashMap
<Type
, Level2Entry
>();
272 private static final class Level2Entry
extends WeakReference
<Object
> {
274 String oid
, Type type
, Object object
, ReferenceQueue
<Object
> queue
)
276 super(object
, queue
);
281 // must only be called while synchronized on enclosing Registry:
282 public void acquire() {
286 // must only be called while synchronized on enclosing Registry:
287 public boolean release() {
291 public final String oid
;
292 public final Type type
;
294 private int count
= 1;
297 private final HashMap
<String
, Level1Entry
> level1map
=
298 new HashMap
<String
, Level1Entry
>();
299 private final ReferenceQueue
<Object
> queue
= new ReferenceQueue
<Object
>();
302 private boolean isProxy(Object object
) {
303 return object
instanceof com
.sun
.star
.lib
.uno
.Proxy
;
306 private static final Registry localObjects
= new Registry();
308 private final Object context
;
309 private final Registry proxies
= new Registry();
312 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */