| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| package com.sun.star.lib.uno.bridges.java_remote; |
| |
| import com.sun.star.bridge.XBridge; |
| import com.sun.star.lib.util.AsynchronousFinalizer; |
| import com.sun.star.uno.IQueryInterface; |
| import com.sun.star.uno.Type; |
| import com.sun.star.uno.UnoRuntime; |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Proxy; |
| |
| /** |
| * A factory for proxies specific to the <code>java_remote_bridge</code>. |
| * |
| * <p>Eventually, this class should be united with all other proxy classes |
| * specific to certain bridges (for example, the JNI bridge), resulting in a |
| * generic proxy class.</p> |
| */ |
| final class ProxyFactory { |
| public ProxyFactory(RequestHandler requestHandler, XBridge bridge) { |
| this.requestHandler = requestHandler; |
| this.bridge = bridge; |
| } |
| |
| public Object create(String oid, Type type) { |
| return Proxy.newProxyInstance( |
| getClass().getClassLoader(), |
| new Class[] { com.sun.star.lib.uno.Proxy.class, |
| IQueryInterface.class, type.getZClass() }, |
| new Handler(oid, type)); |
| } |
| |
| public boolean isProxy(Object obj) { |
| if (Proxy.isProxyClass(obj.getClass())) { |
| InvocationHandler h = Proxy.getInvocationHandler(obj); |
| return h instanceof Handler && ((Handler) h).matches(this); |
| } else { |
| return false; |
| } |
| } |
| |
| public static XBridge getBridge(Object obj) { |
| if (Proxy.isProxyClass(obj.getClass())) { |
| InvocationHandler h = Proxy.getInvocationHandler(obj); |
| if (h instanceof Handler) { |
| return ((Handler) h).getBridge(); |
| } |
| } |
| return null; |
| } |
| |
| static int getDebugCount() { |
| synchronized (debugCountLock) { |
| return debugCount; |
| } |
| } |
| |
| private static void incrementDebugCount() { |
| synchronized (debugCountLock) { |
| ++debugCount; |
| } |
| } |
| |
| private static void decrementDebugCount() { |
| synchronized (debugCountLock) { |
| --debugCount; |
| } |
| } |
| |
| private final class Handler implements InvocationHandler { |
| public Handler(String oid, Type type) { |
| this.oid = oid; |
| this.type = type; |
| incrementDebugCount(); |
| } |
| |
| public boolean matches(ProxyFactory factory) { |
| return ProxyFactory.this == factory; |
| } |
| |
| public XBridge getBridge() { |
| return bridge; |
| } |
| |
| public Object invoke(Object proxy, Method method, Object[] args) |
| throws Throwable |
| { |
| if (method.equals(METHOD_EQUALS) || method.equals(METHOD_IS_SAME)) { |
| return Boolean.valueOf(args[0] != null |
| && oid.equals(UnoRuntime.generateOid(args[0]))); |
| } else if (method.equals(METHOD_HASH_CODE)) { |
| return new Integer(oid.hashCode()); |
| } else if (method.equals(METHOD_TO_STRING)) { |
| return "[Proxy:" + System.identityHashCode(proxy) + "," + oid |
| + "," + type + "]"; |
| } else if (method.equals(METHOD_QUERY_INTERFACE)) { |
| // See the comment in java_remote_bridge.mapInterfaceTo for one |
| // reason why this implementation must not satisfy a request for |
| // a super-interface with a proxy itself: |
| return args[0].equals(type) ? proxy |
| : request("queryInterface", args); |
| } else if (method.equals(METHOD_GET_OID)) { |
| return oid; |
| } else { |
| return request(method.getName(), args); |
| } |
| } |
| |
| protected void finalize() { |
| AsynchronousFinalizer.add(new AsynchronousFinalizer.Job() { |
| public void run() throws Throwable { |
| try { |
| request("release", null); |
| } finally { |
| decrementDebugCount(); |
| } |
| } |
| }); |
| } |
| |
| private Object request(String operation, Object[] args) throws Throwable |
| { |
| Object res = requestHandler.sendRequest(oid, type, operation, args); |
| // Avoid early finalization of this object, while an invoke -> |
| // request call is still ongoing; as finalize also calls request, |
| // this should fulfil the condition from The Java Language |
| // Specification, 3rd ed., that "if an object's finalizer can result |
| // in synchronization on that object, then that object must be alive |
| // and considered reachable whenever a lock is held on it:" |
| synchronized (this) { |
| ++dummy; |
| } |
| return res; |
| } |
| |
| private final String oid; |
| private final Type type; |
| private int dummy = 0; |
| } |
| |
| private static final Method METHOD_EQUALS; |
| private static final Method METHOD_HASH_CODE; |
| private static final Method METHOD_TO_STRING; |
| private static final Method METHOD_QUERY_INTERFACE; |
| private static final Method METHOD_IS_SAME; |
| private static final Method METHOD_GET_OID; |
| static { |
| try { |
| METHOD_EQUALS = Object.class.getMethod( |
| "equals", new Class[] { Object.class }); |
| METHOD_HASH_CODE = Object.class.getMethod("hashCode", null); |
| METHOD_TO_STRING = Object.class.getMethod("toString", null); |
| METHOD_QUERY_INTERFACE = IQueryInterface.class.getMethod( |
| "queryInterface", new Class[] { Type.class }); |
| METHOD_IS_SAME = IQueryInterface.class.getMethod( |
| "isSame", new Class[] { Object.class }); |
| METHOD_GET_OID = IQueryInterface.class.getMethod("getOid", null); |
| } catch (NoSuchMethodException e) { |
| throw new ExceptionInInitializerError(e); |
| } |
| } |
| |
| private static final Object debugCountLock = new Object(); |
| private static int debugCount = 0; |
| |
| private final RequestHandler requestHandler; |
| private final XBridge bridge; |
| } |