📄 identitymanager.java
字号:
/*
* IdentityManager.java -
*
* This file is part of the Jawin Project: http://jawinproject.sourceforge.net/
*
* Please consult the LICENSE file in the project root directory,
* or at the project site before using this software.
*/
/* $Id: IdentityManager.java,v 1.5 2005/03/14 19:38:20 arosii_moa Exp $ */
package org.jawin;
import java.io.IOException;
import java.util.HashMap;
import org.jawin.io.LittleEndianInputStream;
import org.jawin.io.LittleEndianOutputStream;
import org.jawin.io.NakedByteStream;
import org.jawin.marshal.StructConverter;
/**
*
*
* @version $Revision: 1.5 $
* @author Stuart Halloway, http://www.relevancellc.com/halloway/weblog/
*/
public class IdentityManager {
/**
* If the property <code>org.jawin.traceRefs</code> is set the
* reference counting for COM objects will be traced on <code>System.out</code>.
*/
public static final boolean TRACE_REFS =
(null != System.getProperty("org.jawin.traceRefs"));
/**
* a map used for storing the reference counts for GIT cookies as
* peer-Integers -> {@link Identity}-objects.
*
* Any changes to this map should be synchronized around the map itself, like:
* <pre>
* synchronized(idents) {
* do work
* }
* </pre>
*/
private static final HashMap idents = new HashMap();
/**
* a map used for storing GUID to class mappings for all registered
* proxies (see {@link #registerProxy(GUID, Class)}. Maps
* GUID -> Class for proxy.
*/
private static final HashMap guidToClass = new HashMap();
/**
* private constructor to avoid instantiation, as this class only contains
* static methods.
*/
private IdentityManager() {
// never called
}
static COMPtr queryInterface(Class newItf, COMPtr src) throws COMException {
return queryInterface(newCOMPtr(newItf), src);
}
static COMPtr queryInterface(COMPtr dest, COMPtr src) throws COMException {
return getDirectRef(dest, src, true);
}
static COMPtr queryGITInterface(Class newItf, COMPtr src) throws COMException {
return getGITRef(newCOMPtr(newItf), src, true);
}
static COMPtr createDirectRef(COMPtr src) throws COMException {
return getDirectRef(newCOMPtr(src.getClass()), src, false);
}
static COMPtr createGITRef(COMPtr src) throws COMException {
return getGITRef(newCOMPtr(src.getClass()), src, false);
}
private static COMPtr newCOMPtr(Class template) {
try {
return (COMPtr)template.newInstance();
} catch (Exception e) {
throw new COMError("Unable to create instance of " + template.getClass());
}
}
/**
* to retrieve a non-thread safe interface reference.
*
* @param dest the destination to init to a direct ref.
* @param src the source to retrieve the direct ref from.
* @param destIf if true, it is a queryInterface on the dest object. If false
* a copy of the src interface is requested (and the dest and src
* should be equal).
* @return the dest object.
*/
private static COMPtr getDirectRef(COMPtr dest, COMPtr src, boolean destIf) throws COMException {
synchronized (src) {
int unknown = src.getUnknown();
if (unknown != 0) {
// the src is a direct ref.
if (destIf) {
// query interface - the queryInterface calls AddRef so we set
// the unknown pointer the "dirty" way.
dest.setUnknown(Bootstrap.queryInterface(unknown, dest.getIIDToken()));
} else {
dest.copyUnknown(src);
}
} else {
// the src is a GIT ref, and should be unmarshalled as a src interface
int gitUnknown = Bootstrap.unmarshalFromGIT(src.getPeer(), src.getIIDToken());
if (destIf) {
dest.setUnknown(Bootstrap.queryInterface(gitUnknown, dest.getIIDToken()));
// and the release the gitUnknown again
Bootstrap.directCOM(gitUnknown, 2); // vtable index 2 is Release in IUnknown
} else {
// we take over the gitUnknown, so no reason to call release
dest.setUnknown(gitUnknown);
}
}
}
if (TRACE_REFS) {
System.out.println(src + (destIf ? " QI --> " : " unmarshal --> ") + dest);
}
return dest;
}
/**
* * to retrieve a thread safe interface reference.
*
* @param dest the destination to init to a GIT reference.
* @param src the source to retrieve the reference from.
* @param destIf if true, it is a queryInterface on the dest object. If false
* a copy of the src interface is requested (and the dest and src
* should be equal).
* @return the dest object.
*/
private static COMPtr getGITRef(COMPtr dest, COMPtr src, boolean destIf) throws COMException {
int peer;
synchronized (src) {
peer = src.getPeer();
if (peer == 0) {
// the src is a direct ref.
if (destIf) {
// query interface - the queryInterface calls AddRef so we have
// to release it again after marshalling to a GIT cookie
int unknown = Bootstrap.queryInterface(src.getUnknown(), dest.getIIDToken());
peer = Bootstrap.marshalToGIT(unknown, dest.getIIDToken());
// release the interface again - FIXME - should we do this?
Bootstrap.directCOM(unknown, 2); // vtable index 2 is Release in IUnknown
} else {
peer = Bootstrap.marshalToGIT(src.getUnknown(), src.getIIDToken());
}
} else {
if (destIf) {
// we have to unmarshal as a src interface from GIT,
// query the dest interface, marshal this to a dest GIT
// and finally call release on both the unmarshalled src interface
// and the queried dest interface.
int unknown = Bootstrap.unmarshalFromGIT(peer, src.getIIDToken());
int destUnknown = Bootstrap.queryInterface(unknown, dest.getIIDToken());
peer = Bootstrap.marshalToGIT(destUnknown, dest.getIIDToken());
// release all the interfaces again - FIXME - should we do this?
Bootstrap.directCOM(destUnknown, 2); // vtable index 2 is Release in IUnknown
Bootstrap.directCOM(unknown, 2);
}
}
}
dest.setPeer(peer);
return dest;
}
/**
* increments the cached ref count for the proxy. If identity
* does not exist yet, create it.
*/
static Identity incRef(int peer) {
Integer key = new Integer(peer);
synchronized (idents) {
Identity i = (Identity) idents.get(key);
if (i == null) {
i = new Identity(peer);
idents.put(key, i);
} else {
i.incRef();
}
return i;
}
}
/**
* decrements the cached ref count for the proxy. If count
* reaches zero, revoke the GIT pointer
*/
static void decRef(int peer) throws COMException {
int refCount = 0;
Integer key = new Integer(peer);
synchronized (idents) {
Identity i = (Identity) idents.get(key);
if (i == null) {
throw new COMError("Peer " + peer + " is not a COM identity");
}
refCount = i.decRef();
if (refCount == 0) {
idents.remove(key);
}
}
if (refCount == 0) {
Bootstrap.revokeGIT(peer);
}
}
public static COMPtr getCOMPtr(int peer, int unk, GUID iid) {
Class proxyClass = (Class) guidToClass.get(iid);
if (proxyClass == null) {
throw new COMError("No Java class for Interface Identifier: " + iid);
}
COMPtr ret = newCOMPtr(proxyClass);
ret.setUnknown(unk);
ret.setPeer(peer);
return ret;
}
public static COMPtr getCOMPtr(LittleEndianInputStream leis, GUID iid) throws IOException, COMException {
int unk = leis.readInt();
int peer = leis.readInt();
return getCOMPtr(peer, unk, iid);
}
public static COMPtr getCOMPtr(byte[] stream, int offset, GUID iid) throws COMException {
int unk = StructConverter.bytesIntoInt(stream, offset);
int peer = StructConverter.bytesIntoInt(stream, offset + 4);
return getCOMPtr(peer, unk, iid);
}
private static void registerProxyPrototype(GUID iid, Class proxy) {
guidToClass.put(iid, proxy);
}
/**
* Each COM Interface Identifier (IID) must have a proxy class registered with the system.
* See {@link COMPtr} for more information about registering your class.
*
* @throws NullPointerException if either iid or proxy is null.
* @throws COMError if any error happens during registering the proxy.
*/
public static int registerProxy(GUID iid, Class proxy) {
if ((iid == null) || (proxy == null)) {
throw new NullPointerException("neither GUID (" + iid + ") or the proxy class (" + proxy + ") can be null");
}
IdentityManager.registerProxyPrototype(iid, proxy);
NakedByteStream nbs = new NakedByteStream(GUID.SIZEOF);
LittleEndianOutputStream leos = new LittleEndianOutputStream(nbs);
try {
iid.marshal(leos, null);
// TODO carefull here we are passing a reference to an
// internal datastructure - .length can not be trusted.
return Bootstrap.registerGUID(nbs.getInternalBuffer());
} catch (IOException e) {
throw new COMError("IO-error when registering the GUID '" + iid + "' for class '" + proxy + "' (" + e.getMessage() + ")");
} catch (COMException e) {
throw new COMError("Unable to register the GUID '" + iid + "' for class '" + proxy + "' (" + e.getMessage() + ")");
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -