bump product version to 6.4.0.3
[LibreOffice.git] / jurt / com / sun / star / lib / uno / environments / java / java_environment.java
blob89e4b10880ca4bf160de6c08e97eff81dd0096d5
1 /* -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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;
30 /**
31 * The java_environment is the environment where objects and
32 * interfaces are registered, which are mapped out of java or
33 * into java.
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
40 * @since UDK1.0
42 public final class java_environment implements IEnvironment {
43 public java_environment(Object context) {
44 this.context = context;
47 /**
49 * @see com.sun.star.uno.IEnvironment#getContext
51 public Object getContext() {
52 return context;
55 /**
57 * @see com.sun.star.uno.IEnvironment#getName
59 public String getName() {
60 return "java";
63 /**
65 * @see com.sun.star.uno.IEnvironment#registerInterface
67 public Object registerInterface(Object object, String[] oid, Type type) {
68 if (oid[0] == null) {
69 oid[0] = UnoRuntime.generateOid(object);
71 return (isProxy(object) ? proxies : localObjects).register(
72 object, oid[0], type);
75 /**
76 * You have to revoke ANY interface that has been registered via this
77 * method.
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);
89 /**
90 * Retrieves an interface identified by its object id and type from this
91 * environment.
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);
99 if (o == null) {
100 o = localObjects.get(oid, type);
102 return o;
106 * Retrieves the object identifier for a registered interface from this
107 * environment.
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
120 public void list() {
121 // TODO???
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() {
132 proxies.clear();
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
149 // enforce this.
150 @Override
151 public boolean equals(Object obj) {
152 return false;
155 private static final class Registry {
156 public synchronized Object register(
157 Object object, String oid, Type type)
159 cleanUp();
160 Level1Entry l1 = level1map.get(oid);
161 if (l1 != null) {
162 Level2Entry l2 = l1.level2map.get(type);
163 if (l2 != null) {
164 Object o = l2.get();
165 if (o != null) {
166 l2.acquire();
167 return o;
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
181 // revokes it.)
182 if (l1 == null) {
183 l1 = new Level1Entry();
184 level1map.put(oid, l1);
186 l1.level2map.put(type, new Level2Entry(oid, type, object, queue));
187 return object;
190 public synchronized boolean revoke(String oid, Type type) {
191 Level1Entry l1 = level1map.get(oid);
192 Level2Entry l2 = null;
193 if (l1 != null) {
194 l2 = l1.level2map.get(type);
195 if (l2 != null && l2.release()) {
196 removeLevel2Entry(l1, oid, type);
199 cleanUp();
200 return l2 != null;
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() {
209 level1map.clear();
210 cleanUp();
213 // must only be called while synchronized on this Registry:
214 private void cleanUp() {
215 for (;;) {
216 Object tmp = queue.poll();
217 Level2Entry l2 = (Level2Entry) tmp;
218 if (l2 == null) {
219 break;
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);
248 if (l2 != null) {
249 Object o = l2.get();
250 if (o != null) {
251 return o;
254 for (Iterator<Level2Entry> i = level2map.values().iterator();
255 i.hasNext();)
257 l2 = i.next();
258 if (type.isSupertypeOf(l2.type)) {
259 Object o = l2.get();
260 if (o != null) {
261 return o;
265 return null;
268 public final HashMap<Type, Level2Entry> level2map =
269 new HashMap<Type, Level2Entry>();
272 private static final class Level2Entry extends WeakReference<Object> {
273 public Level2Entry(
274 String oid, Type type, Object object, ReferenceQueue<Object> queue)
276 super(object, queue);
277 this.oid = oid;
278 this.type = type;
281 // must only be called while synchronized on enclosing Registry:
282 public void acquire() {
283 ++count;
286 // must only be called while synchronized on enclosing Registry:
287 public boolean release() {
288 return --count == 0;
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: */