EMMA Coverage Report (generated Mon Mar 20 21:34:30 PST 2006)
[all classes][com.moesol.bindings.platform_sdk.component_services]

COVERAGE SUMMARY FOR SOURCE FILE [ComIUnknownImpl.java]

nameclass, %method, %block, %line, %
ComIUnknownImpl.java100% (1/1)100% (12/12)88%  (263/298)93%  (52.4/56)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ComIUnknownImpl100% (1/1)100% (12/12)88%  (263/298)93%  (52.4/56)
<static initializer> 100% (1/1)69%  (18/26)71%  (1.4/2)
addRef (): long 100% (1/1)79%  (49/62)85%  (6/7)
deleteAllComThunks (): void 100% (1/1)85%  (22/26)93%  (5.6/6)
release (): long 100% (1/1)85%  (52/61)93%  (8.4/9)
addMapEntries (ComInterfaceEntry []): void 100% (1/1)97%  (28/29)80%  (4/5)
ComIUnknownImpl (ComObject): void 100% (1/1)100% (11/11)100% (4/4)
aggregate (ComObject): void 100% (1/1)100% (24/24)100% (6/6)
freezeComMap (): void 100% (1/1)100% (6/6)100% (2/2)
getComMap (): Map 100% (1/1)100% (3/3)100% (1/1)
linkTo (ComIUnknown): void 100% (1/1)100% (21/21)100% (6/6)
queryInterface (GUID): IUnknown 100% (1/1)100% (23/23)100% (6/6)
reflectComMap (): void 100% (1/1)100% (6/6)100% (2/2)

1package com.moesol.bindings.platform_sdk.component_services;
2 
3import java.util.Collections;
4import java.util.HashMap;
5import java.util.Iterator;
6import java.util.Map;
7import java.util.logging.Level;
8import java.util.logging.Logger;
9 
10/**
11 * This class provides a default implementation of ComIUnknown. It uses
12 * reflection to build a COM interface map and then correctly creates
13 * native COM vtable thunks to call back to the Java COM object server.
14 * 
15 * This inner class helps avoid most name conflicts, it provides
16 * support for IUnknown::QueryInterface, AddRef, and Release and aggregation. 
17 */
18class ComIUnknownImpl implements ComIUnknown {
19        private static final Logger s_logger = Logger.getLogger(ComIUnknownImpl.class.getName());
20 
21        private final ComObject m_object;
22 
23        /** Number of native COM references */
24        private long m_native_ref_count;
25        
26        /**
27         * Once setup the com map should not change per COM QueryInterface rules. 
28         * So when the first QueryInterface happens the m_com_map gets wrapped
29         * in an unmodifiable Map.
30         */
31        private Map m_com_map = new HashMap();
32        
33        /**
34         * @param object
35         */
36        ComIUnknownImpl(ComObject object) {
37                m_object = object;
38        }
39 
40    /* (non-Javadoc)
41         * @see com.moesol.bindings.platform_sdk.component_services.ComIUnknown#queryInterface(com.moesol.bindings.platform_sdk.component_services.GUID)
42         */
43        public IUnknown queryInterface(GUID iid) {
44                freezeComMap();
45                
46                ComInterfaceEntry entry = (ComInterfaceEntry)m_com_map.get(iid);
47                if (entry == null) {
48                        s_logger.log(Level.FINER, "Failed to find {0}", iid);
49                throw new COMException(HRESULT.E_NOINTERFACE);
50                }
51                return entry.getVtableInterface();
52        }
53 
54        /* (non-Javadoc)
55         * @see com.moesol.bindings.platform_sdk.component_services.ComIUnknown#addRef()
56         */
57    public long addRef() {
58            assert m_native_ref_count >= 0;
59            assert m_native_ref_count < Long.MAX_VALUE;
60            
61            synchronized (this) {
62                    m_native_ref_count++;
63            }
64            s_logger.log(Level.FINEST, "{0} - {1}", new Object[] {
65                                new Long(m_native_ref_count), m_object, });
66            return m_native_ref_count;
67    }
68    
69        /* (non-Javadoc)
70         * @see com.moesol.bindings.platform_sdk.component_services.ComIUnknown#release()
71         */
72    public long release() {
73            assert m_native_ref_count > 0;
74            
75            synchronized (this) {
76                    m_native_ref_count--;
77                }
78            
79            if (m_native_ref_count == 0) {
80                    m_object.FinalRelease(); // similar to ATL
81                    deleteAllComThunks();
82            }
83            
84            s_logger.log(Level.FINEST, "{0} - {1}", new Object[] {
85                                new Long(m_native_ref_count), m_object, });
86            
87            // unlike C++ we are not going to delete ourself so this works
88            return m_native_ref_count;
89    }
90    
91    /* (non-Javadoc)
92         * @see com.moesol.bindings.platform_sdk.component_services.ComIUnknown#aggregate(com.moesol.bindings.platform_sdk.component_services.ComObject)
93         */
94    public void aggregate(ComObject child) {
95            // The only time a ComObject's m_iunknown_support is not
96            // an instance of ComIUnknownImpl is when it has been aggregated
97            // at the outer most level.
98            ComIUnknownImpl child_unk_impl = (ComIUnknownImpl)child.m_iunknown_support;
99            
100                child_unk_impl.m_com_map.keySet().removeAll(m_com_map.keySet());
101            m_com_map.putAll(child_unk_impl.m_com_map);
102            child_unk_impl.linkTo(this);
103            child_unk_impl.m_com_map.clear();
104    }
105    
106    /**
107         * Returns the COM interface map used by this class to answer native
108         * {@code IUnknown::QueryInterface} calls. This map is modifiable until the
109         * first call to {@code queryInterface} is made. After the first call to
110         * {@code queryInterface} this method returns an unmodifiable Map. You
111         * should not cache the return value of this method or you will be
112         * able to by-pass this checking. See COM rules for IUnknown implementations
113         * for more information. In practice, this means than any customizations
114         * you want to make to your COM map should be done in your objects constructor.
115         * 
116         * @return the COM interface map
117         */
118    public Map getComMap() {
119            return m_com_map;
120    }
121    
122    /**
123     * Aggregation support.
124     * 
125     * @param impl
126     * @param com_map
127     */
128    public void linkTo(ComIUnknown outer) {
129            Iterator it = m_com_map.values().iterator();
130            while (it.hasNext()) {
131                    ComInterfaceEntry ce = (ComInterfaceEntry)it.next();
132                    ComObject co = (ComObject)ce.getJavaSink();
133                    co.m_iunknown_support = outer;
134            }
135    }
136    
137    private void addMapEntries(ComInterfaceEntry[] entries) {
138                for (int i = 0; i < entries.length; i++) {
139            // It is common for inner interfaces to have
140            // a redundant IUnknown
141            if (m_com_map.containsKey(entries[i].getIID())) {
142                continue;
143            }
144                        m_com_map.put(entries[i].getIID(), entries[i]);
145                }
146    }
147    
148    void freezeComMap() {
149            m_com_map = Collections.unmodifiableMap(m_com_map);
150    }
151    
152        private void deleteAllComThunks() {
153                assert m_com_map.size() > 0;
154                
155                Iterator it = m_com_map.values().iterator();
156                while (it.hasNext()) {
157                        ComInterfaceEntry entry = (ComInterfaceEntry)it.next();
158                        entry.deleteThunk();
159                }
160        }
161    
162        void reflectComMap() {
163                addMapEntries(ComReflectInterfaceMap.reflectComMap(m_object));
164        }
165}

[all classes][com.moesol.bindings.platform_sdk.component_services]
EMMA 2.0.5312 (C) Vladimir Roubtsov