xref: /AOO41X/main/binaryurp/source/bridge.cxx (revision 37adc4f0f5a9bc19fbf2ac1042b5fb92b6f58586)
1*37adc4f0SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*37adc4f0SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*37adc4f0SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*37adc4f0SAndrew Rist  * distributed with this work for additional information
6*37adc4f0SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*37adc4f0SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*37adc4f0SAndrew Rist  * "License"); you may not use this file except in compliance
9*37adc4f0SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11*37adc4f0SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13*37adc4f0SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*37adc4f0SAndrew Rist  * software distributed under the License is distributed on an
15*37adc4f0SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*37adc4f0SAndrew Rist  * KIND, either express or implied.  See the License for the
17*37adc4f0SAndrew Rist  * specific language governing permissions and limitations
18*37adc4f0SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20*37adc4f0SAndrew Rist  *************************************************************/
21*37adc4f0SAndrew Rist 
22*37adc4f0SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir #include "sal/config.h"
25cdf0e10cSrcweir 
26cdf0e10cSrcweir #include <algorithm>
27cdf0e10cSrcweir #include <cstddef>
28cdf0e10cSrcweir #include <limits>
29cdf0e10cSrcweir #include <memory>
30cdf0e10cSrcweir #include <vector>
31cdf0e10cSrcweir 
32cdf0e10cSrcweir #include "boost/noncopyable.hpp"
33cdf0e10cSrcweir #include "com/sun/star/bridge/InvalidProtocolChangeException.hpp"
34cdf0e10cSrcweir #include "com/sun/star/bridge/XBridge.hpp"
35cdf0e10cSrcweir #include "com/sun/star/bridge/XInstanceProvider.hpp"
36cdf0e10cSrcweir #include "com/sun/star/bridge/XProtocolProperties.hpp"
37cdf0e10cSrcweir #include "com/sun/star/connection/XConnection.hpp"
38cdf0e10cSrcweir #include "com/sun/star/io/IOException.hpp"
39cdf0e10cSrcweir #include "com/sun/star/lang/DisposedException.hpp"
40cdf0e10cSrcweir #include "com/sun/star/lang/EventObject.hpp"
41cdf0e10cSrcweir #include "com/sun/star/lang/XEventListener.hpp"
42cdf0e10cSrcweir #include "com/sun/star/uno/Reference.hxx"
43cdf0e10cSrcweir #include "com/sun/star/uno/RuntimeException.hpp"
44cdf0e10cSrcweir #include "com/sun/star/uno/Sequence.hxx"
45cdf0e10cSrcweir #include "com/sun/star/uno/XInterface.hpp"
46cdf0e10cSrcweir #include "cppuhelper/exc_hlp.hxx"
47cdf0e10cSrcweir #include "cppuhelper/weak.hxx"
48cdf0e10cSrcweir #include "osl/diagnose.h"
49cdf0e10cSrcweir #include "osl/mutex.hxx"
50cdf0e10cSrcweir #include "osl/thread.hxx"
51cdf0e10cSrcweir #include "rtl/byteseq.hxx"
52cdf0e10cSrcweir #include "rtl/random.h"
53cdf0e10cSrcweir #include "rtl/ref.hxx"
54cdf0e10cSrcweir #include "rtl/textenc.h"
55cdf0e10cSrcweir #include "rtl/ustrbuf.hxx"
56cdf0e10cSrcweir #include "rtl/ustring.h"
57cdf0e10cSrcweir #include "rtl/ustring.hxx"
58cdf0e10cSrcweir #include "sal/types.h"
59cdf0e10cSrcweir #include "typelib/typeclass.h"
60cdf0e10cSrcweir #include "typelib/typedescription.h"
61cdf0e10cSrcweir #include "typelib/typedescription.hxx"
62cdf0e10cSrcweir #include "uno/dispatcher.hxx"
63cdf0e10cSrcweir #include "uno/environment.hxx"
64cdf0e10cSrcweir #include "uno/lbnames.h"
65cdf0e10cSrcweir 
66cdf0e10cSrcweir #include "binaryany.hxx"
67cdf0e10cSrcweir #include "bridge.hxx"
68cdf0e10cSrcweir #include "bridgefactory.hxx"
69cdf0e10cSrcweir #include "incomingreply.hxx"
70cdf0e10cSrcweir #include "lessoperators.hxx"
71cdf0e10cSrcweir #include "outgoingrequest.hxx"
72cdf0e10cSrcweir #include "outgoingrequests.hxx"
73cdf0e10cSrcweir #include "proxy.hxx"
74cdf0e10cSrcweir #include "reader.hxx"
75cdf0e10cSrcweir 
76cdf0e10cSrcweir namespace binaryurp {
77cdf0e10cSrcweir 
78cdf0e10cSrcweir namespace {
79cdf0e10cSrcweir 
80cdf0e10cSrcweir namespace css = com::sun::star;
81cdf0e10cSrcweir 
82cdf0e10cSrcweir sal_Int32 random() {
83cdf0e10cSrcweir     sal_Int32 n;
84cdf0e10cSrcweir     rtlRandomPool pool = rtl_random_createPool();
85cdf0e10cSrcweir     rtl_random_getBytes(pool, &n, sizeof n);
86cdf0e10cSrcweir     rtl_random_destroyPool(pool);
87cdf0e10cSrcweir     return n;
88cdf0e10cSrcweir }
89cdf0e10cSrcweir 
90cdf0e10cSrcweir extern "C" void SAL_CALL freeProxyCallback(uno_ExtEnvironment *, void * pProxy)
91cdf0e10cSrcweir {
92cdf0e10cSrcweir     OSL_ASSERT(pProxy != 0);
93cdf0e10cSrcweir     static_cast< Proxy * >(pProxy)->do_free();
94cdf0e10cSrcweir }
95cdf0e10cSrcweir 
96cdf0e10cSrcweir void joinThread(osl::Thread * thread) {
97cdf0e10cSrcweir     OSL_ASSERT(thread != 0);
98cdf0e10cSrcweir     if (thread->getIdentifier() != osl::Thread::getCurrentIdentifier()) {
99cdf0e10cSrcweir         thread->join();
100cdf0e10cSrcweir     }
101cdf0e10cSrcweir }
102cdf0e10cSrcweir 
103cdf0e10cSrcweir class AttachThread: private boost::noncopyable {
104cdf0e10cSrcweir public:
105cdf0e10cSrcweir     explicit AttachThread(uno_ThreadPool threadPool);
106cdf0e10cSrcweir 
107cdf0e10cSrcweir     ~AttachThread();
108cdf0e10cSrcweir 
109cdf0e10cSrcweir     rtl::ByteSequence getTid() throw ();
110cdf0e10cSrcweir 
111cdf0e10cSrcweir private:
112cdf0e10cSrcweir     uno_ThreadPool threadPool_;
113cdf0e10cSrcweir     rtl::ByteSequence tid_;
114cdf0e10cSrcweir };
115cdf0e10cSrcweir 
116cdf0e10cSrcweir AttachThread::AttachThread(uno_ThreadPool threadPool): threadPool_(threadPool) {
117cdf0e10cSrcweir     sal_Sequence * s = 0;
118cdf0e10cSrcweir     uno_getIdOfCurrentThread(&s);
119cdf0e10cSrcweir     tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE);
120cdf0e10cSrcweir     uno_threadpool_attach(threadPool_);
121cdf0e10cSrcweir }
122cdf0e10cSrcweir 
123cdf0e10cSrcweir AttachThread::~AttachThread() {
124cdf0e10cSrcweir     uno_threadpool_detach(threadPool_);
125cdf0e10cSrcweir     uno_releaseIdFromCurrentThread();
126cdf0e10cSrcweir }
127cdf0e10cSrcweir 
128cdf0e10cSrcweir rtl::ByteSequence AttachThread::getTid() throw () {
129cdf0e10cSrcweir     return tid_;
130cdf0e10cSrcweir }
131cdf0e10cSrcweir 
132cdf0e10cSrcweir class PopOutgoingRequest: private boost::noncopyable {
133cdf0e10cSrcweir public:
134cdf0e10cSrcweir     PopOutgoingRequest(
135cdf0e10cSrcweir         OutgoingRequests & requests, rtl::ByteSequence const & tid,
136cdf0e10cSrcweir         OutgoingRequest const & request);
137cdf0e10cSrcweir 
138cdf0e10cSrcweir     ~PopOutgoingRequest();
139cdf0e10cSrcweir 
140cdf0e10cSrcweir     void clear();
141cdf0e10cSrcweir 
142cdf0e10cSrcweir private:
143cdf0e10cSrcweir     OutgoingRequests & requests_;
144cdf0e10cSrcweir     rtl::ByteSequence tid_;
145cdf0e10cSrcweir     bool cleared_;
146cdf0e10cSrcweir };
147cdf0e10cSrcweir 
148cdf0e10cSrcweir PopOutgoingRequest::PopOutgoingRequest(
149cdf0e10cSrcweir     OutgoingRequests & requests, rtl::ByteSequence const & tid,
150cdf0e10cSrcweir     OutgoingRequest const & request):
151cdf0e10cSrcweir     requests_(requests), tid_(tid), cleared_(false)
152cdf0e10cSrcweir {
153cdf0e10cSrcweir     requests_.push(tid_, request);
154cdf0e10cSrcweir }
155cdf0e10cSrcweir 
156cdf0e10cSrcweir PopOutgoingRequest::~PopOutgoingRequest() {
157cdf0e10cSrcweir     if (!cleared_) {
158cdf0e10cSrcweir         requests_.pop(tid_);
159cdf0e10cSrcweir     }
160cdf0e10cSrcweir }
161cdf0e10cSrcweir 
162cdf0e10cSrcweir void PopOutgoingRequest::clear() {
163cdf0e10cSrcweir     cleared_ = true;
164cdf0e10cSrcweir }
165cdf0e10cSrcweir 
166cdf0e10cSrcweir }
167cdf0e10cSrcweir 
168cdf0e10cSrcweir struct Bridge::SubStub {
169cdf0e10cSrcweir     com::sun::star::uno::UnoInterfaceReference object;
170cdf0e10cSrcweir 
171cdf0e10cSrcweir     sal_uInt32 references;
172cdf0e10cSrcweir };
173cdf0e10cSrcweir 
174cdf0e10cSrcweir Bridge::Bridge(
175cdf0e10cSrcweir     rtl::Reference< BridgeFactory > const & factory, rtl::OUString const & name,
176cdf0e10cSrcweir     css::uno::Reference< css::connection::XConnection > const & connection,
177cdf0e10cSrcweir     css::uno::Reference< css::bridge::XInstanceProvider > const & provider):
178cdf0e10cSrcweir     factory_(factory), name_(name), connection_(connection),
179cdf0e10cSrcweir     provider_(provider),
180cdf0e10cSrcweir     binaryUno_(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO))),
181cdf0e10cSrcweir     cppToBinaryMapping_(
182cdf0e10cSrcweir         rtl::OUString(
183cdf0e10cSrcweir             RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME)),
184cdf0e10cSrcweir         rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO))),
185cdf0e10cSrcweir     binaryToCppMapping_(
186cdf0e10cSrcweir         rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO)),
187cdf0e10cSrcweir         rtl::OUString(
188cdf0e10cSrcweir             RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME))),
189cdf0e10cSrcweir     protPropTid_(
190cdf0e10cSrcweir         reinterpret_cast< sal_Int8 const * >(".UrpProtocolPropertiesTid"),
191cdf0e10cSrcweir         RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
192cdf0e10cSrcweir     protPropOid_(RTL_CONSTASCII_USTRINGPARAM("UrpProtocolProperties")),
193cdf0e10cSrcweir     protPropType_(
194cdf0e10cSrcweir         cppu::UnoType<
195cdf0e10cSrcweir             css::uno::Reference< css::bridge::XProtocolProperties > >::get()),
196cdf0e10cSrcweir     protPropRequest_(
197cdf0e10cSrcweir         rtl::OUString(
198cdf0e10cSrcweir             RTL_CONSTASCII_USTRINGPARAM(
199cdf0e10cSrcweir                 "com.sun.star.bridge.XProtocolProperties::requestChange"))),
200cdf0e10cSrcweir     protPropCommit_(
201cdf0e10cSrcweir         rtl::OUString(
202cdf0e10cSrcweir             RTL_CONSTASCII_USTRINGPARAM(
203cdf0e10cSrcweir                 "com.sun.star.bridge.XProtocolProperties::commitChange"))),
204cdf0e10cSrcweir     threadPool_(0), currentContextMode_(false), proxies_(0), calls_(0),
205cdf0e10cSrcweir     normalCall_(false), activeCalls_(0), terminated_(false),
206cdf0e10cSrcweir     mode_(MODE_REQUESTED)
207cdf0e10cSrcweir {
208cdf0e10cSrcweir     OSL_ASSERT(factory.is() && connection.is());
209cdf0e10cSrcweir     if (!binaryUno_.is()) {
210cdf0e10cSrcweir         throw css::uno::RuntimeException(
211cdf0e10cSrcweir             rtl::OUString(
212cdf0e10cSrcweir                 RTL_CONSTASCII_USTRINGPARAM("URP: no binary UNO environment")),
213cdf0e10cSrcweir             css::uno::Reference< css::uno::XInterface >());
214cdf0e10cSrcweir     }
215cdf0e10cSrcweir     if (!(cppToBinaryMapping_.is() && binaryToCppMapping_.is())) {
216cdf0e10cSrcweir         throw css::uno::RuntimeException(
217cdf0e10cSrcweir             rtl::OUString(
218cdf0e10cSrcweir                 RTL_CONSTASCII_USTRINGPARAM("URP: no C++ UNO mapping")),
219cdf0e10cSrcweir             css::uno::Reference< css::uno::XInterface >());
220cdf0e10cSrcweir     }
221cdf0e10cSrcweir     passive_.set();
222cdf0e10cSrcweir }
223cdf0e10cSrcweir 
224cdf0e10cSrcweir void Bridge::start() {
225cdf0e10cSrcweir     OSL_ASSERT(threadPool_ == 0 && !writer_.is() && !reader_.is());
226cdf0e10cSrcweir     threadPool_ = uno_threadpool_create();
227cdf0e10cSrcweir     OSL_ASSERT(threadPool_ != 0);
228cdf0e10cSrcweir     writer_.set(new Writer(this));
229cdf0e10cSrcweir     writer_->create();
230cdf0e10cSrcweir     reader_.set(new Reader(this));
231cdf0e10cSrcweir     reader_->create();
232cdf0e10cSrcweir }
233cdf0e10cSrcweir 
234cdf0e10cSrcweir void Bridge::terminate() {
235cdf0e10cSrcweir     rtl::Reference< Reader > r;
236cdf0e10cSrcweir     rtl::Reference< Writer > w;
237cdf0e10cSrcweir     Listeners ls;
238cdf0e10cSrcweir     {
239cdf0e10cSrcweir         osl::MutexGuard g(mutex_);
240cdf0e10cSrcweir         if (terminated_) {
241cdf0e10cSrcweir             return;
242cdf0e10cSrcweir         }
243cdf0e10cSrcweir         std::swap(reader_, r);
244cdf0e10cSrcweir         std::swap(writer_, w);
245cdf0e10cSrcweir         ls.swap(listeners_);
246cdf0e10cSrcweir         terminated_ = true;
247cdf0e10cSrcweir     }
248cdf0e10cSrcweir     try {
249cdf0e10cSrcweir         connection_->close();
250cdf0e10cSrcweir     } catch (css::io::IOException & e) {
251cdf0e10cSrcweir         OSL_TRACE(
252cdf0e10cSrcweir             OSL_LOG_PREFIX "caught IO exception '%s'",
253cdf0e10cSrcweir             rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
254cdf0e10cSrcweir     }
255cdf0e10cSrcweir     OSL_ASSERT(w.is());
256cdf0e10cSrcweir     w->stop();
257cdf0e10cSrcweir     joinThread(r.get());
258cdf0e10cSrcweir     joinThread(w.get());
259cdf0e10cSrcweir     OSL_ASSERT(threadPool_ != 0);
260cdf0e10cSrcweir     uno_threadpool_dispose(threadPool_);
261cdf0e10cSrcweir     Stubs s;
262cdf0e10cSrcweir     {
263cdf0e10cSrcweir         osl::MutexGuard g(mutex_);
264cdf0e10cSrcweir         s.swap(stubs_);
265cdf0e10cSrcweir     }
266cdf0e10cSrcweir     for (Stubs::iterator i(s.begin()); i != s.end(); ++i) {
267cdf0e10cSrcweir         for (Stub::iterator j(i->second.begin()); j != i->second.end(); ++j) {
268cdf0e10cSrcweir             binaryUno_.get()->pExtEnv->revokeInterface(
269cdf0e10cSrcweir                 binaryUno_.get()->pExtEnv, j->second.object.get());
270cdf0e10cSrcweir         }
271cdf0e10cSrcweir     }
272cdf0e10cSrcweir     factory_->removeBridge(this);
273cdf0e10cSrcweir     for (Listeners::iterator i(ls.begin()); i != ls.end(); ++i) {
274cdf0e10cSrcweir         try {
275cdf0e10cSrcweir             (*i)->disposing(
276cdf0e10cSrcweir                 css::lang::EventObject(
277cdf0e10cSrcweir                     static_cast< cppu::OWeakObject * >(this)));
278cdf0e10cSrcweir         } catch (css::uno::RuntimeException & e) {
279cdf0e10cSrcweir             OSL_TRACE(
280cdf0e10cSrcweir                 OSL_LOG_PREFIX "caught runtime exception '%s'",
281cdf0e10cSrcweir                 rtl::OUStringToOString(
282cdf0e10cSrcweir                     e.Message, RTL_TEXTENCODING_UTF8).getStr());
283cdf0e10cSrcweir         }
284cdf0e10cSrcweir     }
285cdf0e10cSrcweir }
286cdf0e10cSrcweir 
287cdf0e10cSrcweir css::uno::Reference< css::connection::XConnection > Bridge::getConnection()
288cdf0e10cSrcweir     const
289cdf0e10cSrcweir {
290cdf0e10cSrcweir     return connection_;
291cdf0e10cSrcweir }
292cdf0e10cSrcweir 
293cdf0e10cSrcweir css::uno::Reference< css::bridge::XInstanceProvider > Bridge::getProvider()
294cdf0e10cSrcweir     const
295cdf0e10cSrcweir {
296cdf0e10cSrcweir     return provider_;
297cdf0e10cSrcweir }
298cdf0e10cSrcweir 
299cdf0e10cSrcweir css::uno::Mapping & Bridge::getCppToBinaryMapping() {
300cdf0e10cSrcweir     return cppToBinaryMapping_;
301cdf0e10cSrcweir }
302cdf0e10cSrcweir 
303cdf0e10cSrcweir BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) {
304cdf0e10cSrcweir     css::uno::Any in(cppAny);
305cdf0e10cSrcweir     BinaryAny out;
306cdf0e10cSrcweir     out.~BinaryAny();
307cdf0e10cSrcweir     uno_copyAndConvertData(
308cdf0e10cSrcweir         out.get(), &in,
309cdf0e10cSrcweir         css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
310cdf0e10cSrcweir         cppToBinaryMapping_.get());
311cdf0e10cSrcweir     return out;
312cdf0e10cSrcweir }
313cdf0e10cSrcweir 
314cdf0e10cSrcweir uno_ThreadPool Bridge::getThreadPool() const {
315cdf0e10cSrcweir     OSL_ASSERT(threadPool_ != 0);
316cdf0e10cSrcweir     return threadPool_;
317cdf0e10cSrcweir }
318cdf0e10cSrcweir 
319cdf0e10cSrcweir rtl::Reference< Writer > Bridge::getWriter() {
320cdf0e10cSrcweir     osl::MutexGuard g(mutex_);
321cdf0e10cSrcweir     if (terminated_) {
322cdf0e10cSrcweir         throw css::lang::DisposedException(
323cdf0e10cSrcweir             rtl::OUString(
324cdf0e10cSrcweir                 RTL_CONSTASCII_USTRINGPARAM(
325cdf0e10cSrcweir                     "Binary URP bridge already disposed")),
326cdf0e10cSrcweir             static_cast< cppu::OWeakObject * >(this));
327cdf0e10cSrcweir     }
328cdf0e10cSrcweir     OSL_ASSERT(writer_.is());
329cdf0e10cSrcweir     return writer_;
330cdf0e10cSrcweir }
331cdf0e10cSrcweir 
332cdf0e10cSrcweir css::uno::UnoInterfaceReference Bridge::registerIncomingInterface(
333cdf0e10cSrcweir     rtl::OUString const & oid, css::uno::TypeDescription const & type)
334cdf0e10cSrcweir {
335cdf0e10cSrcweir     OSL_ASSERT(type.is());
336cdf0e10cSrcweir     if (oid.getLength() == 0) {
337cdf0e10cSrcweir         return css::uno::UnoInterfaceReference();
338cdf0e10cSrcweir     }
339cdf0e10cSrcweir     css::uno::UnoInterfaceReference obj(findStub(oid, type));
340cdf0e10cSrcweir     if (!obj.is()) {
341cdf0e10cSrcweir         binaryUno_.get()->pExtEnv->getRegisteredInterface(
342cdf0e10cSrcweir             binaryUno_.get()->pExtEnv,
343cdf0e10cSrcweir             reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData,
344cdf0e10cSrcweir             reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()));
345cdf0e10cSrcweir         if (obj.is()) {
346cdf0e10cSrcweir             makeReleaseCall(oid, type);
347cdf0e10cSrcweir         } else {
348cdf0e10cSrcweir             obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE);
349cdf0e10cSrcweir             {
350cdf0e10cSrcweir                 osl::MutexGuard g(mutex_);
351cdf0e10cSrcweir                 OSL_ASSERT(
352cdf0e10cSrcweir                     proxies_ < std::numeric_limits< std::size_t >::max());
353cdf0e10cSrcweir                 ++proxies_;
354cdf0e10cSrcweir             }
355cdf0e10cSrcweir             binaryUno_.get()->pExtEnv->registerProxyInterface(
356cdf0e10cSrcweir                 binaryUno_.get()->pExtEnv,
357cdf0e10cSrcweir                 reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback,
358cdf0e10cSrcweir                 oid.pData,
359cdf0e10cSrcweir                 reinterpret_cast< typelib_InterfaceTypeDescription * >(
360cdf0e10cSrcweir                     type.get()));
361cdf0e10cSrcweir         }
362cdf0e10cSrcweir     }
363cdf0e10cSrcweir     return obj;
364cdf0e10cSrcweir }
365cdf0e10cSrcweir 
366cdf0e10cSrcweir rtl::OUString Bridge::registerOutgoingInterface(
367cdf0e10cSrcweir     css::uno::UnoInterfaceReference const & object,
368cdf0e10cSrcweir     css::uno::TypeDescription const & type)
369cdf0e10cSrcweir {
370cdf0e10cSrcweir     OSL_ASSERT(type.is());
371cdf0e10cSrcweir     if (!object.is()) {
372cdf0e10cSrcweir         return rtl::OUString();
373cdf0e10cSrcweir     }
374cdf0e10cSrcweir     rtl::OUString oid;
375cdf0e10cSrcweir     if (!Proxy::isProxy(this, object, &oid)) {
376cdf0e10cSrcweir         binaryUno_.get()->pExtEnv->getObjectIdentifier(
377cdf0e10cSrcweir             binaryUno_.get()->pExtEnv, &oid.pData, object.get());
378cdf0e10cSrcweir         osl::MutexGuard g(mutex_);
379cdf0e10cSrcweir         Stubs::iterator i(stubs_.find(oid));
380cdf0e10cSrcweir         Stub newStub;
381cdf0e10cSrcweir         Stub * stub = i == stubs_.end() ? &newStub : &i->second;
382cdf0e10cSrcweir         Stub::iterator j(stub->find(type));
383cdf0e10cSrcweir         //TODO: Release sub-stub if it is not successfully sent to remote side
384cdf0e10cSrcweir         // (otherwise, stub will leak until terminate()):
385cdf0e10cSrcweir         if (j == stub->end()) {
386cdf0e10cSrcweir             j = stub->insert(Stub::value_type(type, SubStub())).first;
387cdf0e10cSrcweir             if (stub == &newStub) {
388cdf0e10cSrcweir                 i = stubs_.insert(Stubs::value_type(oid, Stub())).first;
389cdf0e10cSrcweir                 std::swap(i->second, newStub);
390cdf0e10cSrcweir                 j = i->second.find(type);
391cdf0e10cSrcweir                 OSL_ASSERT(j !=  i->second.end());
392cdf0e10cSrcweir             }
393cdf0e10cSrcweir             j->second.object = object;
394cdf0e10cSrcweir             j->second.references = 1;
395cdf0e10cSrcweir             binaryUno_.get()->pExtEnv->registerInterface(
396cdf0e10cSrcweir                 binaryUno_.get()->pExtEnv,
397cdf0e10cSrcweir                 reinterpret_cast< void ** >(&j->second.object.m_pUnoI),
398cdf0e10cSrcweir                 oid.pData,
399cdf0e10cSrcweir                 reinterpret_cast< typelib_InterfaceTypeDescription * >(
400cdf0e10cSrcweir                     type.get()));
401cdf0e10cSrcweir         } else {
402cdf0e10cSrcweir             OSL_ASSERT(stub != &newStub);
403cdf0e10cSrcweir             if (j->second.references == SAL_MAX_UINT32) {
404cdf0e10cSrcweir                 throw css::uno::RuntimeException(
405cdf0e10cSrcweir                     rtl::OUString(
406cdf0e10cSrcweir                         RTL_CONSTASCII_USTRINGPARAM(
407cdf0e10cSrcweir                             "URP: stub reference count overflow")),
408cdf0e10cSrcweir                     css::uno::Reference< css::uno::XInterface >());
409cdf0e10cSrcweir             }
410cdf0e10cSrcweir             ++j->second.references;
411cdf0e10cSrcweir         }
412cdf0e10cSrcweir     }
413cdf0e10cSrcweir     return oid;
414cdf0e10cSrcweir }
415cdf0e10cSrcweir 
416cdf0e10cSrcweir css::uno::UnoInterfaceReference Bridge::findStub(
417cdf0e10cSrcweir     rtl::OUString const & oid, css::uno::TypeDescription const & type)
418cdf0e10cSrcweir {
419cdf0e10cSrcweir     OSL_ASSERT(oid.getLength() != 0 && type.is());
420cdf0e10cSrcweir     osl::MutexGuard g(mutex_);
421cdf0e10cSrcweir     Stubs::iterator i(stubs_.find(oid));
422cdf0e10cSrcweir     if (i != stubs_.end()) {
423cdf0e10cSrcweir         Stub::iterator j(i->second.find(type));
424cdf0e10cSrcweir         if (j != i->second.end()) {
425cdf0e10cSrcweir             return j->second.object;
426cdf0e10cSrcweir         }
427cdf0e10cSrcweir         for (j = i->second.begin(); j != i->second.end(); ++j) {
428cdf0e10cSrcweir             if (typelib_typedescription_isAssignableFrom(
429cdf0e10cSrcweir                     type.get(), j->first.get()))
430cdf0e10cSrcweir             {
431cdf0e10cSrcweir                 return j->second.object;
432cdf0e10cSrcweir             }
433cdf0e10cSrcweir         }
434cdf0e10cSrcweir     }
435cdf0e10cSrcweir     return css::uno::UnoInterfaceReference();
436cdf0e10cSrcweir }
437cdf0e10cSrcweir 
438cdf0e10cSrcweir void Bridge::releaseStub(
439cdf0e10cSrcweir     rtl::OUString const & oid, css::uno::TypeDescription const & type)
440cdf0e10cSrcweir {
441cdf0e10cSrcweir     OSL_ASSERT(oid.getLength() != 0 && type.is());
442cdf0e10cSrcweir     css::uno::UnoInterfaceReference obj;
443cdf0e10cSrcweir     bool unused;
444cdf0e10cSrcweir     {
445cdf0e10cSrcweir         osl::MutexGuard g(mutex_);
446cdf0e10cSrcweir         Stubs::iterator i(stubs_.find(oid));
447cdf0e10cSrcweir         if (i == stubs_.end()) {
448cdf0e10cSrcweir             throw css::uno::RuntimeException(
449cdf0e10cSrcweir                 rtl::OUString(
450cdf0e10cSrcweir                     RTL_CONSTASCII_USTRINGPARAM("URP: release unknown stub")),
451cdf0e10cSrcweir                 css::uno::Reference< css::uno::XInterface >());
452cdf0e10cSrcweir         }
453cdf0e10cSrcweir         Stub::iterator j(i->second.find(type));
454cdf0e10cSrcweir         if (j == i->second.end()) {
455cdf0e10cSrcweir             throw css::uno::RuntimeException(
456cdf0e10cSrcweir                 rtl::OUString(
457cdf0e10cSrcweir                     RTL_CONSTASCII_USTRINGPARAM("URP: release unknown stub")),
458cdf0e10cSrcweir                 css::uno::Reference< css::uno::XInterface >());
459cdf0e10cSrcweir         }
460cdf0e10cSrcweir         OSL_ASSERT(j->second.references > 0);
461cdf0e10cSrcweir         --j->second.references;
462cdf0e10cSrcweir         if (j->second.references == 0) {
463cdf0e10cSrcweir             obj = j->second.object;
464cdf0e10cSrcweir             i->second.erase(j);
465cdf0e10cSrcweir             if (i->second.empty()) {
466cdf0e10cSrcweir                 stubs_.erase(i);
467cdf0e10cSrcweir             }
468cdf0e10cSrcweir         }
469cdf0e10cSrcweir         unused = becameUnused();
470cdf0e10cSrcweir     }
471cdf0e10cSrcweir     if (obj.is()) {
472cdf0e10cSrcweir         binaryUno_.get()->pExtEnv->revokeInterface(
473cdf0e10cSrcweir             binaryUno_.get()->pExtEnv, obj.get());
474cdf0e10cSrcweir     }
475cdf0e10cSrcweir     terminateWhenUnused(unused);
476cdf0e10cSrcweir }
477cdf0e10cSrcweir 
478cdf0e10cSrcweir void Bridge::resurrectProxy(Proxy & proxy) {
479cdf0e10cSrcweir     uno_Interface * p = &proxy;
480cdf0e10cSrcweir     binaryUno_.get()->pExtEnv->registerProxyInterface(
481cdf0e10cSrcweir         binaryUno_.get()->pExtEnv,
482cdf0e10cSrcweir         reinterpret_cast< void ** >(&p), &freeProxyCallback,
483cdf0e10cSrcweir         proxy.getOid().pData,
484cdf0e10cSrcweir         reinterpret_cast< typelib_InterfaceTypeDescription * >(
485cdf0e10cSrcweir             proxy.getType().get()));
486cdf0e10cSrcweir     OSL_ASSERT(p == &proxy);
487cdf0e10cSrcweir }
488cdf0e10cSrcweir 
489cdf0e10cSrcweir void Bridge::revokeProxy(Proxy & proxy) {
490cdf0e10cSrcweir     binaryUno_.get()->pExtEnv->revokeInterface(
491cdf0e10cSrcweir         binaryUno_.get()->pExtEnv, &proxy);
492cdf0e10cSrcweir }
493cdf0e10cSrcweir 
494cdf0e10cSrcweir void Bridge::freeProxy(Proxy & proxy) {
495cdf0e10cSrcweir     try {
496cdf0e10cSrcweir         makeReleaseCall(proxy.getOid(), proxy.getType());
497cdf0e10cSrcweir     } catch (css::uno::RuntimeException & e) {
498cdf0e10cSrcweir         OSL_TRACE(
499cdf0e10cSrcweir             OSL_LOG_PREFIX "caught runtime exception '%s'",
500cdf0e10cSrcweir             rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr());
501cdf0e10cSrcweir     } catch (std::exception & e) {
502cdf0e10cSrcweir         OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what());
503cdf0e10cSrcweir     }
504cdf0e10cSrcweir     bool unused;
505cdf0e10cSrcweir     {
506cdf0e10cSrcweir         osl::MutexGuard g(mutex_);
507cdf0e10cSrcweir         OSL_ASSERT(proxies_ > 0);
508cdf0e10cSrcweir         --proxies_;
509cdf0e10cSrcweir         unused = becameUnused();
510cdf0e10cSrcweir     }
511cdf0e10cSrcweir     terminateWhenUnused(unused);
512cdf0e10cSrcweir }
513cdf0e10cSrcweir 
514cdf0e10cSrcweir void Bridge::incrementCalls(bool normalCall) throw () {
515cdf0e10cSrcweir     osl::MutexGuard g(mutex_);
516cdf0e10cSrcweir     OSL_ASSERT(calls_ < std::numeric_limits< std::size_t >::max());
517cdf0e10cSrcweir     ++calls_;
518cdf0e10cSrcweir     normalCall_ |= normalCall;
519cdf0e10cSrcweir }
520cdf0e10cSrcweir 
521cdf0e10cSrcweir void Bridge::decrementCalls() {
522cdf0e10cSrcweir     bool unused;
523cdf0e10cSrcweir     {
524cdf0e10cSrcweir         osl::MutexGuard g(mutex_);
525cdf0e10cSrcweir         OSL_ASSERT(calls_ > 0);
526cdf0e10cSrcweir         --calls_;
527cdf0e10cSrcweir         unused = becameUnused();
528cdf0e10cSrcweir     }
529cdf0e10cSrcweir     terminateWhenUnused(unused);
530cdf0e10cSrcweir }
531cdf0e10cSrcweir 
532cdf0e10cSrcweir void Bridge::incrementActiveCalls() throw () {
533cdf0e10cSrcweir     osl::MutexGuard g(mutex_);
534cdf0e10cSrcweir     OSL_ASSERT(
535cdf0e10cSrcweir         activeCalls_ <= calls_ &&
536cdf0e10cSrcweir         activeCalls_ < std::numeric_limits< std::size_t >::max());
537cdf0e10cSrcweir     ++activeCalls_;
538cdf0e10cSrcweir     passive_.reset();
539cdf0e10cSrcweir }
540cdf0e10cSrcweir 
541cdf0e10cSrcweir void Bridge::decrementActiveCalls() throw () {
542cdf0e10cSrcweir     osl::MutexGuard g(mutex_);
543cdf0e10cSrcweir     OSL_ASSERT(activeCalls_ <= calls_ && activeCalls_ > 0);
544cdf0e10cSrcweir     --activeCalls_;
545cdf0e10cSrcweir     if (activeCalls_ == 0) {
546cdf0e10cSrcweir         passive_.set();
547cdf0e10cSrcweir     }
548cdf0e10cSrcweir }
549cdf0e10cSrcweir 
550cdf0e10cSrcweir bool Bridge::makeCall(
551cdf0e10cSrcweir     rtl::OUString const & oid, css::uno::TypeDescription const & member,
552cdf0e10cSrcweir     bool setter, std::vector< BinaryAny > const & inArguments,
553cdf0e10cSrcweir     BinaryAny * returnValue, std::vector< BinaryAny > * outArguments)
554cdf0e10cSrcweir {
555cdf0e10cSrcweir     std::auto_ptr< IncomingReply > resp;
556cdf0e10cSrcweir     {
557cdf0e10cSrcweir         AttachThread att(threadPool_);
558cdf0e10cSrcweir         PopOutgoingRequest pop(
559cdf0e10cSrcweir             outgoingRequests_, att.getTid(),
560cdf0e10cSrcweir             OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter));
561cdf0e10cSrcweir         sendRequest(
562cdf0e10cSrcweir             att.getTid(), oid, css::uno::TypeDescription(), member,
563cdf0e10cSrcweir             inArguments);
564cdf0e10cSrcweir         pop.clear();
565cdf0e10cSrcweir         incrementCalls(true);
566cdf0e10cSrcweir         incrementActiveCalls();
567cdf0e10cSrcweir         void * job;
568cdf0e10cSrcweir         uno_threadpool_enter(threadPool_, &job);
569cdf0e10cSrcweir         resp.reset(static_cast< IncomingReply * >(job));
570cdf0e10cSrcweir         decrementActiveCalls();
571cdf0e10cSrcweir         decrementCalls();
572cdf0e10cSrcweir     }
573cdf0e10cSrcweir     if (resp.get() == 0) {
574cdf0e10cSrcweir         throw css::lang::DisposedException(
575cdf0e10cSrcweir             rtl::OUString(
576cdf0e10cSrcweir                 RTL_CONSTASCII_USTRINGPARAM(
577cdf0e10cSrcweir                     "Binary URP bridge disposed during call")),
578cdf0e10cSrcweir             static_cast< cppu::OWeakObject * >(this));
579cdf0e10cSrcweir     }
580cdf0e10cSrcweir     *returnValue = resp->returnValue;
581cdf0e10cSrcweir     if (!resp->exception) {
582cdf0e10cSrcweir         *outArguments = resp->outArguments;
583cdf0e10cSrcweir     }
584cdf0e10cSrcweir     return resp->exception;
585cdf0e10cSrcweir }
586cdf0e10cSrcweir 
587cdf0e10cSrcweir void Bridge::sendRequestChangeRequest() {
588cdf0e10cSrcweir     OSL_ASSERT(mode_ == MODE_REQUESTED);
589cdf0e10cSrcweir     random_ = random();
590cdf0e10cSrcweir     std::vector< BinaryAny > a;
591cdf0e10cSrcweir     a.push_back(
592cdf0e10cSrcweir         BinaryAny(
593cdf0e10cSrcweir             css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()),
594cdf0e10cSrcweir             &random_));
595cdf0e10cSrcweir     sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a);
596cdf0e10cSrcweir }
597cdf0e10cSrcweir 
598cdf0e10cSrcweir void Bridge::handleRequestChangeReply(
599cdf0e10cSrcweir     bool exception, BinaryAny const & returnValue)
600cdf0e10cSrcweir {
601cdf0e10cSrcweir     throwException(exception, returnValue);
602cdf0e10cSrcweir     sal_Int32 n = *static_cast< sal_Int32 * >(
603cdf0e10cSrcweir         returnValue.getValue(
604cdf0e10cSrcweir             css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get())));
605cdf0e10cSrcweir     sal_Int32 exp = 0;
606cdf0e10cSrcweir     switch (mode_) {
607cdf0e10cSrcweir     case MODE_REQUESTED:
608cdf0e10cSrcweir     case MODE_REPLY_1:
609cdf0e10cSrcweir         exp = 1;
610cdf0e10cSrcweir         break;
611cdf0e10cSrcweir     case MODE_REPLY_MINUS1:
612cdf0e10cSrcweir         exp = -1;
613cdf0e10cSrcweir         mode_ = MODE_REQUESTED;
614cdf0e10cSrcweir         break;
615cdf0e10cSrcweir     case MODE_REPLY_0:
616cdf0e10cSrcweir         exp = 0;
617cdf0e10cSrcweir         mode_ = MODE_WAIT;
618cdf0e10cSrcweir         break;
619cdf0e10cSrcweir     default:
620cdf0e10cSrcweir         OSL_ASSERT(false); // this cannot happen
621cdf0e10cSrcweir         break;
622cdf0e10cSrcweir     }
623cdf0e10cSrcweir     if (n != exp) {
624cdf0e10cSrcweir         throw css::uno::RuntimeException(
625cdf0e10cSrcweir             rtl::OUString(
626cdf0e10cSrcweir                 RTL_CONSTASCII_USTRINGPARAM(
627cdf0e10cSrcweir                     "URP: requestChange reply with unexpected return value"
628cdf0e10cSrcweir                     " received")),
629cdf0e10cSrcweir             static_cast< cppu::OWeakObject * >(this));
630cdf0e10cSrcweir     }
631cdf0e10cSrcweir     decrementCalls();
632cdf0e10cSrcweir     switch (exp) {
633cdf0e10cSrcweir     case -1:
634cdf0e10cSrcweir         sendRequestChangeRequest();
635cdf0e10cSrcweir         break;
636cdf0e10cSrcweir     case 0:
637cdf0e10cSrcweir         break;
638cdf0e10cSrcweir     case 1:
639cdf0e10cSrcweir         sendCommitChangeRequest();
640cdf0e10cSrcweir         break;
641cdf0e10cSrcweir     default:
642cdf0e10cSrcweir         OSL_ASSERT(false); // this cannot happen
643cdf0e10cSrcweir         break;
644cdf0e10cSrcweir     }
645cdf0e10cSrcweir }
646cdf0e10cSrcweir 
647cdf0e10cSrcweir void Bridge::handleCommitChangeReply(
648cdf0e10cSrcweir     bool exception, BinaryAny const & returnValue)
649cdf0e10cSrcweir {
650cdf0e10cSrcweir     bool ccMode = true;
651cdf0e10cSrcweir     try {
652cdf0e10cSrcweir         throwException(exception, returnValue);
653cdf0e10cSrcweir     } catch (css::bridge::InvalidProtocolChangeException &) {
654cdf0e10cSrcweir         ccMode = false;
655cdf0e10cSrcweir     }
656cdf0e10cSrcweir     if (ccMode) {
657cdf0e10cSrcweir         setCurrentContextMode();
658cdf0e10cSrcweir     }
659cdf0e10cSrcweir     OSL_ASSERT(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
660cdf0e10cSrcweir     mode_ = MODE_NORMAL;
661cdf0e10cSrcweir     getWriter()->unblock();
662cdf0e10cSrcweir     decrementCalls();
663cdf0e10cSrcweir }
664cdf0e10cSrcweir 
665cdf0e10cSrcweir void Bridge::handleRequestChangeRequest(
666cdf0e10cSrcweir     rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
667cdf0e10cSrcweir {
668cdf0e10cSrcweir     OSL_ASSERT(inArguments.size() == 1);
669cdf0e10cSrcweir     switch (mode_) {
670cdf0e10cSrcweir     case MODE_REQUESTED:
671cdf0e10cSrcweir         {
672cdf0e10cSrcweir             sal_Int32 n2 = *static_cast< sal_Int32 * >(
673cdf0e10cSrcweir                 inArguments[0].getValue(
674cdf0e10cSrcweir                     css::uno::TypeDescription(
675cdf0e10cSrcweir                         cppu::UnoType< sal_Int32 >::get())));
676cdf0e10cSrcweir             sal_Int32 ret;
677cdf0e10cSrcweir             if (n2 > random_) {
678cdf0e10cSrcweir                 ret = 1;
679cdf0e10cSrcweir                 mode_ = MODE_REPLY_0;
680cdf0e10cSrcweir             } else if (n2 == random_) {
681cdf0e10cSrcweir                 ret = -1;
682cdf0e10cSrcweir                 mode_ = MODE_REPLY_MINUS1;
683cdf0e10cSrcweir             } else {
684cdf0e10cSrcweir                 ret = 0;
685cdf0e10cSrcweir                 mode_ = MODE_REPLY_1;
686cdf0e10cSrcweir             }
687cdf0e10cSrcweir             getWriter()->sendDirectReply(
688cdf0e10cSrcweir                 tid, protPropRequest_, false,
689cdf0e10cSrcweir                 BinaryAny(
690cdf0e10cSrcweir                     css::uno::TypeDescription(
691cdf0e10cSrcweir                         cppu::UnoType< sal_Int32 >::get()),
692cdf0e10cSrcweir                     &ret),
693cdf0e10cSrcweir             std::vector< BinaryAny >());
694cdf0e10cSrcweir             break;
695cdf0e10cSrcweir         }
696cdf0e10cSrcweir     case MODE_NORMAL:
697cdf0e10cSrcweir         {
698cdf0e10cSrcweir             mode_ = MODE_NORMAL_WAIT;
699cdf0e10cSrcweir             sal_Int32 ret = 1;
700cdf0e10cSrcweir             getWriter()->queueReply(
701cdf0e10cSrcweir                 tid, protPropRequest_, false, false,
702cdf0e10cSrcweir                 BinaryAny(
703cdf0e10cSrcweir                     css::uno::TypeDescription(
704cdf0e10cSrcweir                         cppu::UnoType< sal_Int32 >::get()),
705cdf0e10cSrcweir                     &ret),
706cdf0e10cSrcweir             std::vector< BinaryAny >(), false);
707cdf0e10cSrcweir             break;
708cdf0e10cSrcweir         }
709cdf0e10cSrcweir     default:
710cdf0e10cSrcweir         throw css::uno::RuntimeException(
711cdf0e10cSrcweir             rtl::OUString(
712cdf0e10cSrcweir                 RTL_CONSTASCII_USTRINGPARAM(
713cdf0e10cSrcweir                     "URP: unexpected requestChange request received")),
714cdf0e10cSrcweir             static_cast< cppu::OWeakObject * >(this));
715cdf0e10cSrcweir     }
716cdf0e10cSrcweir }
717cdf0e10cSrcweir 
718cdf0e10cSrcweir void Bridge::handleCommitChangeRequest(
719cdf0e10cSrcweir     rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
720cdf0e10cSrcweir {
721cdf0e10cSrcweir     bool ccMode = false;
722cdf0e10cSrcweir     bool exc = false;
723cdf0e10cSrcweir     BinaryAny ret;
724cdf0e10cSrcweir     OSL_ASSERT(inArguments.size() == 1);
725cdf0e10cSrcweir     css::uno::Sequence< css::bridge::ProtocolProperty > s;
726cdf0e10cSrcweir     OSL_VERIFY(mapBinaryToCppAny(inArguments[0]) >>= s);
727cdf0e10cSrcweir     for (sal_Int32 i = 0; i != s.getLength(); ++i) {
728cdf0e10cSrcweir         if (s[i].Name.equalsAsciiL(
729cdf0e10cSrcweir                 RTL_CONSTASCII_STRINGPARAM("CurrentContext")))
730cdf0e10cSrcweir         {
731cdf0e10cSrcweir             ccMode = true;
732cdf0e10cSrcweir         } else {
733cdf0e10cSrcweir             ccMode = false;
734cdf0e10cSrcweir             exc = true;
735cdf0e10cSrcweir             ret = mapCppToBinaryAny(
736cdf0e10cSrcweir                 css::uno::makeAny(
737cdf0e10cSrcweir                     css::bridge::InvalidProtocolChangeException(
738cdf0e10cSrcweir                         rtl::OUString(
739cdf0e10cSrcweir                             RTL_CONSTASCII_USTRINGPARAM(
740cdf0e10cSrcweir                                 "InvalidProtocolChangeException")),
741cdf0e10cSrcweir                         css::uno::Reference< css::uno::XInterface >(), s[i],
742cdf0e10cSrcweir                         1)));
743cdf0e10cSrcweir             break;
744cdf0e10cSrcweir         }
745cdf0e10cSrcweir     }
746cdf0e10cSrcweir     switch (mode_) {
747cdf0e10cSrcweir     case MODE_WAIT:
748cdf0e10cSrcweir         getWriter()->sendDirectReply(
749cdf0e10cSrcweir             tid, protPropCommit_, exc, ret, std::vector< BinaryAny >());
750cdf0e10cSrcweir         if (ccMode) {
751cdf0e10cSrcweir             setCurrentContextMode();
752cdf0e10cSrcweir             mode_ = MODE_NORMAL;
753cdf0e10cSrcweir             getWriter()->unblock();
754cdf0e10cSrcweir         } else {
755cdf0e10cSrcweir             mode_ = MODE_REQUESTED;
756cdf0e10cSrcweir             sendRequestChangeRequest();
757cdf0e10cSrcweir         }
758cdf0e10cSrcweir         break;
759cdf0e10cSrcweir     case MODE_NORMAL_WAIT:
760cdf0e10cSrcweir         getWriter()->queueReply(
761cdf0e10cSrcweir             tid, protPropCommit_, false, false, ret, std::vector< BinaryAny >(),
762cdf0e10cSrcweir             ccMode);
763cdf0e10cSrcweir         mode_ = MODE_NORMAL;
764cdf0e10cSrcweir         break;
765cdf0e10cSrcweir     default:
766cdf0e10cSrcweir         throw css::uno::RuntimeException(
767cdf0e10cSrcweir             rtl::OUString(
768cdf0e10cSrcweir                 RTL_CONSTASCII_USTRINGPARAM(
769cdf0e10cSrcweir                     "URP: unexpected commitChange request received")),
770cdf0e10cSrcweir             static_cast< cppu::OWeakObject * >(this));
771cdf0e10cSrcweir     }
772cdf0e10cSrcweir }
773cdf0e10cSrcweir 
774cdf0e10cSrcweir OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) {
775cdf0e10cSrcweir     OutgoingRequest req(outgoingRequests_.top(tid));
776cdf0e10cSrcweir     outgoingRequests_.pop(tid);
777cdf0e10cSrcweir     return req;
778cdf0e10cSrcweir }
779cdf0e10cSrcweir 
780cdf0e10cSrcweir bool Bridge::isProtocolPropertiesRequest(
781cdf0e10cSrcweir     rtl::OUString const & oid, css::uno::TypeDescription const & type) const
782cdf0e10cSrcweir {
783cdf0e10cSrcweir     return oid == protPropOid_ && type.equals(protPropType_);
784cdf0e10cSrcweir }
785cdf0e10cSrcweir 
786cdf0e10cSrcweir void Bridge::setCurrentContextMode() {
787cdf0e10cSrcweir     osl::MutexGuard g(mutex_);
788cdf0e10cSrcweir     currentContextMode_ = true;
789cdf0e10cSrcweir }
790cdf0e10cSrcweir 
791cdf0e10cSrcweir bool Bridge::isCurrentContextMode() {
792cdf0e10cSrcweir     osl::MutexGuard g(mutex_);
793cdf0e10cSrcweir     return currentContextMode_;
794cdf0e10cSrcweir }
795cdf0e10cSrcweir 
796cdf0e10cSrcweir Bridge::~Bridge() {
797cdf0e10cSrcweir     if (threadPool_ != 0) {
798cdf0e10cSrcweir         uno_threadpool_destroy(threadPool_);
799cdf0e10cSrcweir     }
800cdf0e10cSrcweir }
801cdf0e10cSrcweir 
802cdf0e10cSrcweir css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
803cdf0e10cSrcweir     rtl::OUString const & sInstanceName) throw (css::uno::RuntimeException)
804cdf0e10cSrcweir {
805cdf0e10cSrcweir     if (sInstanceName.getLength() == 0) {
806cdf0e10cSrcweir         throw css::uno::RuntimeException(
807cdf0e10cSrcweir             rtl::OUString(
808cdf0e10cSrcweir                 RTL_CONSTASCII_USTRINGPARAM(
809cdf0e10cSrcweir                     "XBridge::getInstance sInstanceName must be non-empty")),
810cdf0e10cSrcweir             static_cast< cppu::OWeakObject * >(this));
811cdf0e10cSrcweir     }
812cdf0e10cSrcweir     for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) {
813cdf0e10cSrcweir         if (sInstanceName[i] > 0x7F) {
814cdf0e10cSrcweir             throw css::io::IOException(
815cdf0e10cSrcweir                 rtl::OUString(
816cdf0e10cSrcweir                     RTL_CONSTASCII_USTRINGPARAM(
817cdf0e10cSrcweir                         "XBridge::getInstance sInstanceName contains non-ASCII"
818cdf0e10cSrcweir                         " character")),
819cdf0e10cSrcweir                 css::uno::Reference< css::uno::XInterface >());
820cdf0e10cSrcweir         }
821cdf0e10cSrcweir     }
822cdf0e10cSrcweir     css::uno::TypeDescription ifc(
823cdf0e10cSrcweir         cppu::UnoType< css::uno::Reference< css::uno::XInterface > >::get());
824cdf0e10cSrcweir     typelib_TypeDescription * p = ifc.get();
825cdf0e10cSrcweir     std::vector< BinaryAny > inArgs;
826cdf0e10cSrcweir     inArgs.push_back(
827cdf0e10cSrcweir         BinaryAny(
828cdf0e10cSrcweir             css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()),
829cdf0e10cSrcweir             &p));
830cdf0e10cSrcweir     BinaryAny ret;
831cdf0e10cSrcweir     std::vector< BinaryAny> outArgs;
832cdf0e10cSrcweir     bool exc = makeCall(
833cdf0e10cSrcweir         sInstanceName,
834cdf0e10cSrcweir         css::uno::TypeDescription(
835cdf0e10cSrcweir             rtl::OUString(
836cdf0e10cSrcweir                 RTL_CONSTASCII_USTRINGPARAM(
837cdf0e10cSrcweir                     "com.sun.star.uno.XInterface::queryInterface"))),
838cdf0e10cSrcweir         false, inArgs, &ret, &outArgs);
839cdf0e10cSrcweir     throwException(exc, ret);
840cdf0e10cSrcweir     return css::uno::Reference< css::uno::XInterface >(
841cdf0e10cSrcweir         static_cast< css::uno::XInterface * >(
842cdf0e10cSrcweir             binaryToCppMapping_.mapInterface(
843cdf0e10cSrcweir                 *static_cast< uno_Interface ** >(ret.getValue(ifc)),
844cdf0e10cSrcweir                 ifc.get())),
845cdf0e10cSrcweir         css::uno::UNO_REF_NO_ACQUIRE);
846cdf0e10cSrcweir }
847cdf0e10cSrcweir 
848cdf0e10cSrcweir rtl::OUString Bridge::getName() throw (css::uno::RuntimeException) {
849cdf0e10cSrcweir     return name_;
850cdf0e10cSrcweir }
851cdf0e10cSrcweir 
852cdf0e10cSrcweir rtl::OUString Bridge::getDescription() throw (css::uno::RuntimeException) {
853cdf0e10cSrcweir     rtl::OUStringBuffer b(name_);
854cdf0e10cSrcweir     b.append(sal_Unicode(':'));
855cdf0e10cSrcweir     b.append(connection_->getDescription());
856cdf0e10cSrcweir     return b.makeStringAndClear();
857cdf0e10cSrcweir }
858cdf0e10cSrcweir 
859cdf0e10cSrcweir void Bridge::dispose() throw (css::uno::RuntimeException) {
860cdf0e10cSrcweir     terminate();
861cdf0e10cSrcweir     // OOo expects dispose to not return while there are still remote calls in
862cdf0e10cSrcweir     // progress; an external protocol must ensure that dispose is not called
863cdf0e10cSrcweir     // from within an incoming or outgoing remote call, as passive_.wait() would
864cdf0e10cSrcweir     // otherwise deadlock:
865cdf0e10cSrcweir     passive_.wait();
866cdf0e10cSrcweir }
867cdf0e10cSrcweir 
868cdf0e10cSrcweir void Bridge::addEventListener(
869cdf0e10cSrcweir     css::uno::Reference< css::lang::XEventListener > const & xListener)
870cdf0e10cSrcweir     throw (css::uno::RuntimeException)
871cdf0e10cSrcweir {
872cdf0e10cSrcweir     OSL_ASSERT(xListener.is());
873cdf0e10cSrcweir     {
874cdf0e10cSrcweir         osl::MutexGuard g(mutex_);
875cdf0e10cSrcweir         if (!terminated_) {
876cdf0e10cSrcweir             listeners_.push_back(xListener);
877cdf0e10cSrcweir             return;
878cdf0e10cSrcweir         }
879cdf0e10cSrcweir     }
880cdf0e10cSrcweir     xListener->disposing(
881cdf0e10cSrcweir         css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
882cdf0e10cSrcweir }
883cdf0e10cSrcweir 
884cdf0e10cSrcweir void Bridge::removeEventListener(
885cdf0e10cSrcweir     css::uno::Reference< css::lang::XEventListener > const & aListener)
886cdf0e10cSrcweir     throw (css::uno::RuntimeException)
887cdf0e10cSrcweir {
888cdf0e10cSrcweir     osl::MutexGuard g(mutex_);
889cdf0e10cSrcweir     Listeners::iterator i(
890cdf0e10cSrcweir         std::find(listeners_.begin(), listeners_.end(), aListener));
891cdf0e10cSrcweir     if (i != listeners_.end()) {
892cdf0e10cSrcweir         listeners_.erase(i);
893cdf0e10cSrcweir     }
894cdf0e10cSrcweir }
895cdf0e10cSrcweir 
896cdf0e10cSrcweir void Bridge::sendCommitChangeRequest() {
897cdf0e10cSrcweir     OSL_ASSERT(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
898cdf0e10cSrcweir     css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
899cdf0e10cSrcweir     s[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CurrentContext"));
900cdf0e10cSrcweir     std::vector< BinaryAny > a;
901cdf0e10cSrcweir     a.push_back(mapCppToBinaryAny(css::uno::makeAny(s)));
902cdf0e10cSrcweir     sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a);
903cdf0e10cSrcweir }
904cdf0e10cSrcweir 
905cdf0e10cSrcweir void Bridge::sendProtPropRequest(
906cdf0e10cSrcweir     OutgoingRequest::Kind kind, std::vector< BinaryAny > const & inArguments)
907cdf0e10cSrcweir {
908cdf0e10cSrcweir     OSL_ASSERT(
909cdf0e10cSrcweir         kind == OutgoingRequest::KIND_REQUEST_CHANGE ||
910cdf0e10cSrcweir         kind == OutgoingRequest::KIND_COMMIT_CHANGE);
911cdf0e10cSrcweir     incrementCalls(false);
912cdf0e10cSrcweir     css::uno::TypeDescription member(
913cdf0e10cSrcweir         kind == OutgoingRequest::KIND_REQUEST_CHANGE
914cdf0e10cSrcweir         ? protPropRequest_ : protPropCommit_);
915cdf0e10cSrcweir     PopOutgoingRequest pop(
916cdf0e10cSrcweir         outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false));
917cdf0e10cSrcweir     getWriter()->sendDirectRequest(
918cdf0e10cSrcweir         protPropTid_, protPropOid_, protPropType_, member, inArguments);
919cdf0e10cSrcweir     pop.clear();
920cdf0e10cSrcweir }
921cdf0e10cSrcweir 
922cdf0e10cSrcweir void Bridge::makeReleaseCall(
923cdf0e10cSrcweir     rtl::OUString const & oid, css::uno::TypeDescription const & type)
924cdf0e10cSrcweir {
925cdf0e10cSrcweir     AttachThread att(threadPool_);
926cdf0e10cSrcweir     sendRequest(
927cdf0e10cSrcweir         att.getTid(), oid, type,
928cdf0e10cSrcweir         css::uno::TypeDescription(
929cdf0e10cSrcweir             rtl::OUString(
930cdf0e10cSrcweir                 RTL_CONSTASCII_USTRINGPARAM(
931cdf0e10cSrcweir                     "com.sun.star.uno.XInterface::release"))),
932cdf0e10cSrcweir         std::vector< BinaryAny >());
933cdf0e10cSrcweir }
934cdf0e10cSrcweir 
935cdf0e10cSrcweir void Bridge::sendRequest(
936cdf0e10cSrcweir     rtl::ByteSequence const & tid, rtl::OUString const & oid,
937cdf0e10cSrcweir     css::uno::TypeDescription const & type,
938cdf0e10cSrcweir     css::uno::TypeDescription const & member,
939cdf0e10cSrcweir     std::vector< BinaryAny > const & inArguments)
940cdf0e10cSrcweir {
941cdf0e10cSrcweir     getWriter()->queueRequest(tid, oid, type, member, inArguments);
942cdf0e10cSrcweir }
943cdf0e10cSrcweir 
944cdf0e10cSrcweir void Bridge::throwException(bool exception, BinaryAny const & value) {
945cdf0e10cSrcweir     if (exception) {
946cdf0e10cSrcweir         cppu::throwException(mapBinaryToCppAny(value));
947cdf0e10cSrcweir     }
948cdf0e10cSrcweir }
949cdf0e10cSrcweir 
950cdf0e10cSrcweir css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) {
951cdf0e10cSrcweir     BinaryAny in(binaryAny);
952cdf0e10cSrcweir     css::uno::Any out;
953cdf0e10cSrcweir     out.~Any();
954cdf0e10cSrcweir     uno_copyAndConvertData(
955cdf0e10cSrcweir         &out, in.get(),
956cdf0e10cSrcweir         css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
957cdf0e10cSrcweir         binaryToCppMapping_.get());
958cdf0e10cSrcweir     return out;
959cdf0e10cSrcweir }
960cdf0e10cSrcweir 
961cdf0e10cSrcweir bool Bridge::becameUnused() const {
962cdf0e10cSrcweir     return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_;
963cdf0e10cSrcweir }
964cdf0e10cSrcweir 
965cdf0e10cSrcweir void Bridge::terminateWhenUnused(bool unused) {
966cdf0e10cSrcweir     if (unused) {
967cdf0e10cSrcweir         // That the current thread considers the bridge unused implies that it
968cdf0e10cSrcweir         // is not within an incoming or outgoing remote call (so calling
969cdf0e10cSrcweir         // terminate cannot lead to deadlock):
970cdf0e10cSrcweir         terminate();
971cdf0e10cSrcweir     }
972cdf0e10cSrcweir }
973cdf0e10cSrcweir 
974cdf0e10cSrcweir }
975