bump product version to 5.0.4.1
[LibreOffice.git] / jurt / com / sun / star / lib / uno / environments / java / java_environment.java
blob654b9ad511583ba0920ccb5fc892053153616b4d
1 /*
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;
29 /**
30 * The java_environment is the environment where objects and
31 * interfaces are registered, which are mapped out of java or
32 * into java.
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
39 * @since UDK1.0
41 public final class java_environment implements IEnvironment {
42 public java_environment(Object context) {
43 this.context = context;
46 /**
48 * @see com.sun.star.uno.IEnvironment#getContext
50 public Object getContext() {
51 return context;
54 /**
56 * @see com.sun.star.uno.IEnvironment#getName
58 public String getName() {
59 return "java";
62 /**
64 * @see com.sun.star.uno.IEnvironment#registerInterface
66 public Object registerInterface(Object object, String[] oid, Type type) {
67 if (oid[0] == null) {
68 oid[0] = UnoRuntime.generateOid(object);
70 return (isProxy(object) ? proxies : localObjects).register(
71 object, oid[0], type);
74 /**
75 * You have to revoke ANY interface that has been registered via this
76 * method.
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);
88 /**
89 * Retrieves an interface identified by its object id and type from this
90 * environment.
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);
98 if (o == null) {
99 o = localObjects.get(oid, type);
101 return o;
105 * Retrieves the object identifier for a registered interface from this
106 * environment.
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
119 public void list() {
120 // TODO???
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() {
131 proxies.clear();
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
148 // enforce this.
149 @Override
150 public boolean equals(Object obj) {
151 return false;
154 private static final class Registry {
155 public synchronized Object register(
156 Object object, String oid, Type type)
158 cleanUp();
159 Level1Entry l1 = level1map.get(oid);
160 if (l1 != null) {
161 Level2Entry l2 = l1.level2map.get(type);
162 if (l2 != null) {
163 Object o = l2.get();
164 if (o != null) {
165 l2.acquire();
166 return o;
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
180 // revokes it.)
181 if (l1 == null) {
182 l1 = new Level1Entry();
183 level1map.put(oid, l1);
185 l1.level2map.put(type, new Level2Entry(oid, type, object, queue));
186 return object;
189 public synchronized boolean revoke(String oid, Type type) {
190 Level1Entry l1 = level1map.get(oid);
191 Level2Entry l2 = null;
192 if (l1 != null) {
193 l2 = l1.level2map.get(type);
194 if (l2 != null && l2.release()) {
195 removeLevel2Entry(l1, oid, type);
198 cleanUp();
199 return l2 != null;
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() {
208 level1map.clear();
209 cleanUp();
212 // must only be called while synchronized on this Registry:
213 private void cleanUp() {
214 for (;;) {
215 Object tmp = queue.poll();
216 Level2Entry l2 = (Level2Entry) tmp;
217 if (l2 == null) {
218 break;
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);
247 if (l2 != null) {
248 Object o = l2.get();
249 if (o != null) {
250 return o;
253 for (Iterator<Level2Entry> i = level2map.values().iterator();
254 i.hasNext();)
256 l2 = i.next();
257 if (type.isSupertypeOf(l2.type)) {
258 Object o = l2.get();
259 if (o != null) {
260 return o;
264 return null;
267 public final HashMap<Type, Level2Entry> level2map =
268 new HashMap<Type, Level2Entry>();
271 private static final class Level2Entry extends WeakReference<Object> {
272 public Level2Entry(
273 String oid, Type type, Object object, ReferenceQueue<Object> queue)
275 super(object, queue);
276 this.oid = oid;
277 this.type = type;
280 // must only be called while synchronized on enclosing Registry:
281 public void acquire() {
282 ++count;
285 // must only be called while synchronized on enclosing Registry:
286 public boolean release() {
287 return --count == 0;
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();