1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 #include "sal/config.h"
29 #include "boost/noncopyable.hpp"
30 #include "com/sun/star/bridge/InvalidProtocolChangeException.hpp"
31 #include "com/sun/star/bridge/XBridge.hpp"
32 #include "com/sun/star/bridge/XInstanceProvider.hpp"
33 #include "com/sun/star/bridge/XProtocolProperties.hpp"
34 #include "com/sun/star/connection/XConnection.hpp"
35 #include "com/sun/star/io/IOException.hpp"
36 #include "com/sun/star/lang/DisposedException.hpp"
37 #include "com/sun/star/lang/EventObject.hpp"
38 #include "com/sun/star/lang/XEventListener.hpp"
39 #include "com/sun/star/uno/Reference.hxx"
40 #include "com/sun/star/uno/RuntimeException.hpp"
41 #include "com/sun/star/uno/Sequence.hxx"
42 #include "com/sun/star/uno/XInterface.hpp"
43 #include "cppuhelper/exc_hlp.hxx"
44 #include "cppuhelper/weak.hxx"
45 #include "osl/mutex.hxx"
46 #include "osl/thread.hxx"
47 #include "rtl/byteseq.hxx"
48 #include "rtl/random.h"
49 #include "rtl/ref.hxx"
50 #include "rtl/ustrbuf.hxx"
51 #include "rtl/ustring.h"
52 #include "rtl/ustring.hxx"
53 #include "sal/log.hxx"
54 #include "sal/types.h"
55 #include "typelib/typeclass.h"
56 #include "typelib/typedescription.h"
57 #include "typelib/typedescription.hxx"
58 #include "uno/dispatcher.hxx"
59 #include "uno/environment.hxx"
60 #include "uno/lbnames.h"
62 #include "binaryany.hxx"
64 #include "bridgefactory.hxx"
65 #include "incomingreply.hxx"
66 #include "lessoperators.hxx"
67 #include "outgoingrequest.hxx"
68 #include "outgoingrequests.hxx"
78 rtlRandomPool pool
= rtl_random_createPool();
79 rtl_random_getBytes(pool
, &n
, sizeof n
);
80 rtl_random_destroyPool(pool
);
84 OUString
toString(css::uno::TypeDescription
const & type
) {
85 typelib_TypeDescription
* d
= type
.get();
86 assert(d
!= 0 && d
->pTypeName
!= 0);
87 return OUString(d
->pTypeName
);
90 extern "C" void SAL_CALL
freeProxyCallback(
91 SAL_UNUSED_PARAMETER uno_ExtEnvironment
*, void * pProxy
)
94 static_cast< Proxy
* >(pProxy
)->do_free();
97 bool isThread(salhelper::Thread
* thread
) {
99 return osl::Thread::getCurrentIdentifier() == thread
->getIdentifier();
102 class AttachThread
: private boost::noncopyable
{
104 explicit AttachThread(uno_ThreadPool threadPool
);
108 rtl::ByteSequence
getTid() throw ();
111 uno_ThreadPool threadPool_
;
112 rtl::ByteSequence tid_
;
115 AttachThread::AttachThread(uno_ThreadPool threadPool
): threadPool_(threadPool
) {
116 sal_Sequence
* s
= 0;
117 uno_getIdOfCurrentThread(&s
);
118 tid_
= rtl::ByteSequence(s
, rtl::BYTESEQ_NOACQUIRE
);
119 uno_threadpool_attach(threadPool_
);
122 AttachThread::~AttachThread() {
123 uno_threadpool_detach(threadPool_
);
124 uno_releaseIdFromCurrentThread();
127 rtl::ByteSequence
AttachThread::getTid() throw () {
131 class PopOutgoingRequest
: private boost::noncopyable
{
134 OutgoingRequests
& requests
, rtl::ByteSequence
const & tid
,
135 OutgoingRequest
const & request
);
137 ~PopOutgoingRequest();
142 OutgoingRequests
& requests_
;
143 rtl::ByteSequence tid_
;
147 PopOutgoingRequest::PopOutgoingRequest(
148 OutgoingRequests
& requests
, rtl::ByteSequence
const & tid
,
149 OutgoingRequest
const & request
):
150 requests_(requests
), tid_(tid
), cleared_(false)
152 requests_
.push(tid_
, request
);
155 PopOutgoingRequest::~PopOutgoingRequest() {
161 void PopOutgoingRequest::clear() {
167 struct Bridge::SubStub
{
168 com::sun::star::uno::UnoInterfaceReference object
;
170 sal_uInt32 references
;
174 rtl::Reference
< BridgeFactory
> const & factory
, OUString
const & name
,
175 css::uno::Reference
< css::connection::XConnection
> const & connection
,
176 css::uno::Reference
< css::bridge::XInstanceProvider
> const & provider
):
177 factory_(factory
), name_(name
), connection_(connection
),
179 binaryUno_(UNO_LB_UNO
),
180 cppToBinaryMapping_(CPPU_CURRENT_LANGUAGE_BINDING_NAME
, UNO_LB_UNO
),
181 binaryToCppMapping_(UNO_LB_UNO
, CPPU_CURRENT_LANGUAGE_BINDING_NAME
),
183 reinterpret_cast< sal_Int8
const * >(".UrpProtocolPropertiesTid"),
184 RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
185 protPropOid_("UrpProtocolProperties"),
188 css::uno::Reference
< css::bridge::XProtocolProperties
> >::get()),
189 protPropRequest_("com.sun.star.bridge.XProtocolProperties::requestChange"),
190 protPropCommit_("com.sun.star.bridge.XProtocolProperties::commitChange"),
191 state_(STATE_INITIAL
), threadPool_(0), currentContextMode_(false),
192 proxies_(0), calls_(0), normalCall_(false), activeCalls_(0),
193 mode_(MODE_REQUESTED
)
195 assert(factory
.is() && connection
.is());
196 if (!binaryUno_
.is()) {
197 throw css::uno::RuntimeException(
198 "URP: no binary UNO environment",
199 css::uno::Reference
< css::uno::XInterface
>());
201 if (!(cppToBinaryMapping_
.is() && binaryToCppMapping_
.is())) {
202 throw css::uno::RuntimeException(
203 "URP: no C++ UNO mapping",
204 css::uno::Reference
< css::uno::XInterface
>());
209 void Bridge::start() {
210 rtl::Reference
< Reader
> r(new Reader(this));
211 rtl::Reference
< Writer
> w(new Writer(this));
213 osl::MutexGuard
g(mutex_
);
215 state_
== STATE_INITIAL
&& threadPool_
== 0 && !writer_
.is() &&
217 threadPool_
= uno_threadpool_create();
218 assert(threadPool_
!= 0);
221 state_
= STATE_STARTED
;
223 // It is important to call reader_->launch() last here; both
224 // Writer::execute and Reader::execute can call Bridge::terminate, but
225 // Writer::execute is initially blocked in unblocked_.wait() until
226 // Reader::execute has called bridge_->sendRequestChangeRequest(), so
227 // effectively only reader_->launch() can lead to an early call to
233 void Bridge::terminate(bool final
) {
235 // Make sure function-local variables (Stubs s, etc.) are destroyed before
236 // the final uno_threadpool_destroy/threadPool_ = 0:
238 rtl::Reference
< Reader
> r
;
239 rtl::Reference
< Writer
> w
;
243 osl::ClearableMutexGuard
g(mutex_
);
245 case STATE_INITIAL
: // via ~Bridge -> dispose -> terminate
250 case STATE_TERMINATED
:
255 osl::MutexGuard
g2(mutex_
);
259 if (!isThread(reader_
.get())) {
265 if (!isThread(writer_
.get())) {
270 state_
= STATE_FINAL
;
272 assert(!(r
.is() && w
.is()));
279 uno_threadpool_destroy(tp
);
285 assert(!(final
&& isThread(reader_
.get())));
286 if (!isThread(reader_
.get())) {
287 std::swap(reader_
, r
);
290 joinW
= !isThread(writer_
.get());
291 assert(!final
|| joinW
);
296 state_
= final
? STATE_FINAL
: STATE_TERMINATED
;
299 connection_
->close();
300 } catch (const css::io::IOException
& e
) {
301 SAL_INFO("binaryurp", "caught IO exception '" << e
.Message
<< '\'');
312 uno_threadpool_dispose(tp
);
315 osl::MutexGuard
g(mutex_
);
318 for (Stubs::iterator
i(s
.begin()); i
!= s
.end(); ++i
) {
319 for (Stub::iterator
j(i
->second
.begin()); j
!= i
->second
.end(); ++j
)
323 "stub '" << i
->first
<< "', '" << toString(j
->first
)
324 << "' still mapped at Bridge::terminate");
325 binaryUno_
.get()->pExtEnv
->revokeInterface(
326 binaryUno_
.get()->pExtEnv
, j
->second
.object
.get());
329 factory_
->removeBridge(this);
330 for (Listeners::iterator
i(ls
.begin()); i
!= ls
.end(); ++i
) {
333 css::lang::EventObject(
334 static_cast< cppu::OWeakObject
* >(this)));
335 } catch (const css::uno::RuntimeException
& e
) {
338 "caught runtime exception '" << e
.Message
<< '\'');
343 uno_threadpool_destroy(tp
);
346 osl::MutexGuard
g(mutex_
);
354 css::uno::Reference
< css::connection::XConnection
> Bridge::getConnection()
360 css::uno::Reference
< css::bridge::XInstanceProvider
> Bridge::getProvider()
366 css::uno::Mapping
& Bridge::getCppToBinaryMapping() {
367 return cppToBinaryMapping_
;
370 BinaryAny
Bridge::mapCppToBinaryAny(css::uno::Any
const & cppAny
) {
371 css::uno::Any
in(cppAny
);
374 uno_copyAndConvertData(
376 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()).get(),
377 cppToBinaryMapping_
.get());
381 uno_ThreadPool
Bridge::getThreadPool() {
382 osl::MutexGuard
g(mutex_
);
384 assert(threadPool_
!= 0);
388 rtl::Reference
< Writer
> Bridge::getWriter() {
389 osl::MutexGuard
g(mutex_
);
391 assert(writer_
.is());
395 css::uno::UnoInterfaceReference
Bridge::registerIncomingInterface(
396 OUString
const & oid
, css::uno::TypeDescription
const & type
)
400 return css::uno::UnoInterfaceReference();
402 css::uno::UnoInterfaceReference
obj(findStub(oid
, type
));
404 binaryUno_
.get()->pExtEnv
->getRegisteredInterface(
405 binaryUno_
.get()->pExtEnv
,
406 reinterpret_cast< void ** >(&obj
.m_pUnoI
), oid
.pData
,
407 reinterpret_cast< typelib_InterfaceTypeDescription
* >(type
.get()));
409 makeReleaseCall(oid
, type
);
411 obj
.set(new Proxy(this, oid
, type
), SAL_NO_ACQUIRE
);
413 osl::MutexGuard
g(mutex_
);
414 assert(proxies_
< std::numeric_limits
< std::size_t >::max());
417 binaryUno_
.get()->pExtEnv
->registerProxyInterface(
418 binaryUno_
.get()->pExtEnv
,
419 reinterpret_cast< void ** >(&obj
.m_pUnoI
), &freeProxyCallback
,
421 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
428 OUString
Bridge::registerOutgoingInterface(
429 css::uno::UnoInterfaceReference
const & object
,
430 css::uno::TypeDescription
const & type
)
437 if (!Proxy::isProxy(this, object
, &oid
)) {
438 binaryUno_
.get()->pExtEnv
->getObjectIdentifier(
439 binaryUno_
.get()->pExtEnv
, &oid
.pData
, object
.get());
440 osl::MutexGuard
g(mutex_
);
441 Stubs::iterator
i(stubs_
.find(oid
));
443 Stub
* stub
= i
== stubs_
.end() ? &newStub
: &i
->second
;
444 Stub::iterator
j(stub
->find(type
));
445 //TODO: Release sub-stub if it is not successfully sent to remote side
446 // (otherwise, stub will leak until terminate()):
447 if (j
== stub
->end()) {
448 j
= stub
->insert(Stub::value_type(type
, SubStub())).first
;
449 if (stub
== &newStub
) {
450 i
= stubs_
.insert(Stubs::value_type(oid
, Stub())).first
;
451 std::swap(i
->second
, newStub
);
452 j
= i
->second
.find(type
);
453 assert(j
!= i
->second
.end());
455 j
->second
.object
= object
;
456 j
->second
.references
= 1;
457 binaryUno_
.get()->pExtEnv
->registerInterface(
458 binaryUno_
.get()->pExtEnv
,
459 reinterpret_cast< void ** >(&j
->second
.object
.m_pUnoI
),
461 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
464 assert(stub
!= &newStub
);
465 if (j
->second
.references
== SAL_MAX_UINT32
) {
466 throw css::uno::RuntimeException(
467 "URP: stub reference count overflow",
468 css::uno::Reference
< css::uno::XInterface
>());
470 ++j
->second
.references
;
476 css::uno::UnoInterfaceReference
Bridge::findStub(
477 OUString
const & oid
, css::uno::TypeDescription
const & type
)
479 assert(!oid
.isEmpty() && type
.is());
480 osl::MutexGuard
g(mutex_
);
481 Stubs::iterator
i(stubs_
.find(oid
));
482 if (i
!= stubs_
.end()) {
483 Stub::iterator
j(i
->second
.find(type
));
484 if (j
!= i
->second
.end()) {
485 return j
->second
.object
;
487 for (j
= i
->second
.begin(); j
!= i
->second
.end(); ++j
) {
488 if (typelib_typedescription_isAssignableFrom(
489 type
.get(), j
->first
.get()))
491 return j
->second
.object
;
495 return css::uno::UnoInterfaceReference();
498 void Bridge::releaseStub(
499 OUString
const & oid
, css::uno::TypeDescription
const & type
)
501 assert(!oid
.isEmpty() && type
.is());
502 css::uno::UnoInterfaceReference obj
;
505 osl::MutexGuard
g(mutex_
);
506 Stubs::iterator
i(stubs_
.find(oid
));
507 if (i
== stubs_
.end()) {
508 throw css::uno::RuntimeException(
509 "URP: release unknown stub",
510 css::uno::Reference
< css::uno::XInterface
>());
512 Stub::iterator
j(i
->second
.find(type
));
513 if (j
== i
->second
.end()) {
514 throw css::uno::RuntimeException(
515 "URP: release unknown stub",
516 css::uno::Reference
< css::uno::XInterface
>());
518 assert(j
->second
.references
> 0);
519 --j
->second
.references
;
520 if (j
->second
.references
== 0) {
521 obj
= j
->second
.object
;
523 if (i
->second
.empty()) {
527 unused
= becameUnused();
530 binaryUno_
.get()->pExtEnv
->revokeInterface(
531 binaryUno_
.get()->pExtEnv
, obj
.get());
533 terminateWhenUnused(unused
);
536 void Bridge::resurrectProxy(Proxy
& proxy
) {
537 uno_Interface
* p
= &proxy
;
538 binaryUno_
.get()->pExtEnv
->registerProxyInterface(
539 binaryUno_
.get()->pExtEnv
,
540 reinterpret_cast< void ** >(&p
), &freeProxyCallback
,
541 proxy
.getOid().pData
,
542 reinterpret_cast< typelib_InterfaceTypeDescription
* >(
543 proxy
.getType().get()));
547 void Bridge::revokeProxy(Proxy
& proxy
) {
548 binaryUno_
.get()->pExtEnv
->revokeInterface(
549 binaryUno_
.get()->pExtEnv
, &proxy
);
552 void Bridge::freeProxy(Proxy
& proxy
) {
554 makeReleaseCall(proxy
.getOid(), proxy
.getType());
555 } catch (const css::uno::RuntimeException
& e
) {
557 "binaryurp", "caught runtime exception '" << e
.Message
<< '\'');
558 } catch (const std::exception
& e
) {
559 SAL_WARN("binaryurp", "caught C++ exception '" << e
.what() << '\'');
563 osl::MutexGuard
g(mutex_
);
564 assert(proxies_
> 0);
566 unused
= becameUnused();
568 terminateWhenUnused(unused
);
571 void Bridge::incrementCalls(bool normalCall
) throw () {
572 osl::MutexGuard
g(mutex_
);
573 assert(calls_
< std::numeric_limits
< std::size_t >::max());
575 normalCall_
|= normalCall
;
578 void Bridge::decrementCalls() {
581 osl::MutexGuard
g(mutex_
);
584 unused
= becameUnused();
586 terminateWhenUnused(unused
);
589 void Bridge::incrementActiveCalls() throw () {
590 osl::MutexGuard
g(mutex_
);
592 activeCalls_
<= calls_
&&
593 activeCalls_
< std::numeric_limits
< std::size_t >::max());
598 void Bridge::decrementActiveCalls() throw () {
599 osl::MutexGuard
g(mutex_
);
600 assert(activeCalls_
<= calls_
&& activeCalls_
> 0);
602 if (activeCalls_
== 0) {
607 bool Bridge::makeCall(
608 OUString
const & oid
, css::uno::TypeDescription
const & member
,
609 bool setter
, std::vector
< BinaryAny
> const & inArguments
,
610 BinaryAny
* returnValue
, std::vector
< BinaryAny
> * outArguments
)
612 std::auto_ptr
< IncomingReply
> resp
;
614 uno_ThreadPool tp
= getThreadPool();
615 AttachThread
att(tp
);
616 PopOutgoingRequest
pop(
617 outgoingRequests_
, att
.getTid(),
618 OutgoingRequest(OutgoingRequest::KIND_NORMAL
, member
, setter
));
620 att
.getTid(), oid
, css::uno::TypeDescription(), member
,
623 incrementCalls(true);
624 incrementActiveCalls();
626 uno_threadpool_enter(tp
, &job
);
627 resp
.reset(static_cast< IncomingReply
* >(job
));
628 decrementActiveCalls();
631 if (resp
.get() == 0) {
632 throw css::lang::DisposedException(
633 "Binary URP bridge disposed during call",
634 static_cast< cppu::OWeakObject
* >(this));
636 *returnValue
= resp
->returnValue
;
637 if (!resp
->exception
) {
638 *outArguments
= resp
->outArguments
;
640 return resp
->exception
;
643 void Bridge::sendRequestChangeRequest() {
644 assert(mode_
== MODE_REQUESTED
);
646 std::vector
< BinaryAny
> a
;
649 css::uno::TypeDescription(cppu::UnoType
< sal_Int32
>::get()),
651 sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE
, a
);
654 void Bridge::handleRequestChangeReply(
655 bool exception
, BinaryAny
const & returnValue
)
658 throwException(exception
, returnValue
);
659 } catch (css::uno::RuntimeException
& e
) {
660 // Before OOo 2.2, Java URP would throw a RuntimeException when
661 // receiving a requestChange message (see i#35277 "Java URP: Support
662 // Manipulation of Protocol Properties"):
663 if (mode_
!= MODE_REQUESTED
) {
668 "requestChange caught RuntimeException \'" << e
.Message
669 << "' in state 'requested'");
671 getWriter()->unblock();
675 sal_Int32 n
= *static_cast< sal_Int32
* >(
676 returnValue
.getValue(
677 css::uno::TypeDescription(cppu::UnoType
< sal_Int32
>::get())));
684 case MODE_REPLY_MINUS1
:
686 mode_
= MODE_REQUESTED
;
693 assert(false); // this cannot happen
697 throw css::uno::RuntimeException(
698 "URP: requestChange reply with unexpected return value received",
699 static_cast< cppu::OWeakObject
* >(this));
704 sendRequestChangeRequest();
709 sendCommitChangeRequest();
712 assert(false); // this cannot happen
717 void Bridge::handleCommitChangeReply(
718 bool exception
, BinaryAny
const & returnValue
)
722 throwException(exception
, returnValue
);
723 } catch (const css::bridge::InvalidProtocolChangeException
&) {
727 setCurrentContextMode();
729 assert(mode_
== MODE_REQUESTED
|| mode_
== MODE_REPLY_1
);
731 getWriter()->unblock();
735 void Bridge::handleRequestChangeRequest(
736 rtl::ByteSequence
const & tid
, std::vector
< BinaryAny
> const & inArguments
)
738 assert(inArguments
.size() == 1);
742 sal_Int32 n2
= *static_cast< sal_Int32
* >(
743 inArguments
[0].getValue(
744 css::uno::TypeDescription(
745 cppu::UnoType
< sal_Int32
>::get())));
749 mode_
= MODE_REPLY_0
;
750 } else if (n2
== random_
) {
752 mode_
= MODE_REPLY_MINUS1
;
755 mode_
= MODE_REPLY_1
;
757 getWriter()->sendDirectReply(
758 tid
, protPropRequest_
, false,
760 css::uno::TypeDescription(
761 cppu::UnoType
< sal_Int32
>::get()),
763 std::vector
< BinaryAny
>());
768 mode_
= MODE_NORMAL_WAIT
;
770 getWriter()->queueReply(
771 tid
, protPropRequest_
, false, false,
773 css::uno::TypeDescription(
774 cppu::UnoType
< sal_Int32
>::get()),
776 std::vector
< BinaryAny
>(), false);
780 throw css::uno::RuntimeException(
781 "URP: unexpected requestChange request received",
782 static_cast< cppu::OWeakObject
* >(this));
786 void Bridge::handleCommitChangeRequest(
787 rtl::ByteSequence
const & tid
, std::vector
< BinaryAny
> const & inArguments
)
792 assert(inArguments
.size() == 1);
793 css::uno::Sequence
< css::bridge::ProtocolProperty
> s
;
794 bool ok
= (mapBinaryToCppAny(inArguments
[0]) >>= s
);
796 (void) ok
; // avoid warnings
797 for (sal_Int32 i
= 0; i
!= s
.getLength(); ++i
) {
798 if (s
[i
].Name
== "CurrentContext") {
803 ret
= mapCppToBinaryAny(
805 css::bridge::InvalidProtocolChangeException(
806 "InvalidProtocolChangeException",
807 css::uno::Reference
< css::uno::XInterface
>(), s
[i
],
814 getWriter()->sendDirectReply(
815 tid
, protPropCommit_
, exc
, ret
, std::vector
< BinaryAny
>());
817 setCurrentContextMode();
819 getWriter()->unblock();
821 mode_
= MODE_REQUESTED
;
822 sendRequestChangeRequest();
825 case MODE_NORMAL_WAIT
:
826 getWriter()->queueReply(
827 tid
, protPropCommit_
, false, false, ret
, std::vector
< BinaryAny
>(),
832 throw css::uno::RuntimeException(
833 "URP: unexpected commitChange request received",
834 static_cast< cppu::OWeakObject
* >(this));
838 OutgoingRequest
Bridge::lastOutgoingRequest(rtl::ByteSequence
const & tid
) {
839 OutgoingRequest
req(outgoingRequests_
.top(tid
));
840 outgoingRequests_
.pop(tid
);
844 bool Bridge::isProtocolPropertiesRequest(
845 OUString
const & oid
, css::uno::TypeDescription
const & type
) const
847 return oid
== protPropOid_
&& type
.equals(protPropType_
);
850 void Bridge::setCurrentContextMode() {
851 osl::MutexGuard
g(mutex_
);
852 currentContextMode_
= true;
855 bool Bridge::isCurrentContextMode() {
856 osl::MutexGuard
g(mutex_
);
857 return currentContextMode_
;
861 #if OSL_DEBUG_LEVEL > 0
863 osl::MutexGuard
g(mutex_
);
865 state_
== STATE_STARTED
|| state_
== STATE_TERMINATED
, "binaryurp",
866 "undisposed bridge, potential deadlock ahead");
872 css::uno::Reference
< css::uno::XInterface
> Bridge::getInstance(
873 OUString
const & sInstanceName
) throw (css::uno::RuntimeException
)
875 if (sInstanceName
.isEmpty()) {
876 throw css::uno::RuntimeException(
877 "XBridge::getInstance sInstanceName must be non-empty",
878 static_cast< cppu::OWeakObject
* >(this));
880 for (sal_Int32 i
= 0; i
!= sInstanceName
.getLength(); ++i
) {
881 if (sInstanceName
[i
] > 0x7F) {
882 throw css::io::IOException(
883 ("XBridge::getInstance sInstanceName contains non-ASCII"
885 css::uno::Reference
< css::uno::XInterface
>());
888 css::uno::TypeDescription
ifc(
889 cppu::UnoType
< css::uno::Reference
< css::uno::XInterface
> >::get());
890 typelib_TypeDescription
* p
= ifc
.get();
891 std::vector
< BinaryAny
> inArgs
;
894 css::uno::TypeDescription(cppu::UnoType
< css::uno::Type
>::get()),
897 std::vector
< BinaryAny
> outArgs
;
900 css::uno::TypeDescription(
901 "com.sun.star.uno.XInterface::queryInterface"),
902 false, inArgs
, &ret
, &outArgs
);
903 throwException(exc
, ret
);
904 return css::uno::Reference
< css::uno::XInterface
>(
905 static_cast< css::uno::XInterface
* >(
906 binaryToCppMapping_
.mapInterface(
907 *static_cast< uno_Interface
** >(ret
.getValue(ifc
)),
909 css::uno::UNO_REF_NO_ACQUIRE
);
912 OUString
Bridge::getName() throw (css::uno::RuntimeException
) {
916 OUString
Bridge::getDescription() throw (css::uno::RuntimeException
) {
917 OUStringBuffer
b(name_
);
918 b
.append(sal_Unicode(':'));
919 b
.append(connection_
->getDescription());
920 return b
.makeStringAndClear();
923 void Bridge::dispose() throw (css::uno::RuntimeException
) {
924 // For terminate(true) not to deadlock, an external protocol must ensure
925 // that dispose is not called from a thread pool worker thread (that dispose
926 // is never called from the reader or writer thread is already ensured
929 // OOo expects dispose to not return while there are still remote calls in
930 // progress; an external protocol must ensure that dispose is not called
931 // from within an incoming or outgoing remote call, as passive_.wait() would
932 // otherwise deadlock:
936 void Bridge::addEventListener(
937 css::uno::Reference
< css::lang::XEventListener
> const & xListener
)
938 throw (css::uno::RuntimeException
)
940 assert(xListener
.is());
942 osl::MutexGuard
g(mutex_
);
943 assert(state_
!= STATE_INITIAL
);
944 if (state_
== STATE_STARTED
) {
945 listeners_
.push_back(xListener
);
949 xListener
->disposing(
950 css::lang::EventObject(static_cast< cppu::OWeakObject
* >(this)));
953 void Bridge::removeEventListener(
954 css::uno::Reference
< css::lang::XEventListener
> const & aListener
)
955 throw (css::uno::RuntimeException
)
957 osl::MutexGuard
g(mutex_
);
958 Listeners::iterator
i(
959 std::find(listeners_
.begin(), listeners_
.end(), aListener
));
960 if (i
!= listeners_
.end()) {
965 void Bridge::sendCommitChangeRequest() {
966 assert(mode_
== MODE_REQUESTED
|| mode_
== MODE_REPLY_1
);
967 css::uno::Sequence
< css::bridge::ProtocolProperty
> s(1);
968 s
[0].Name
= "CurrentContext";
969 std::vector
< BinaryAny
> a
;
970 a
.push_back(mapCppToBinaryAny(css::uno::makeAny(s
)));
971 sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE
, a
);
974 void Bridge::sendProtPropRequest(
975 OutgoingRequest::Kind kind
, std::vector
< BinaryAny
> const & inArguments
)
978 kind
== OutgoingRequest::KIND_REQUEST_CHANGE
||
979 kind
== OutgoingRequest::KIND_COMMIT_CHANGE
);
980 incrementCalls(false);
981 css::uno::TypeDescription
member(
982 kind
== OutgoingRequest::KIND_REQUEST_CHANGE
983 ? protPropRequest_
: protPropCommit_
);
984 PopOutgoingRequest
pop(
985 outgoingRequests_
, protPropTid_
, OutgoingRequest(kind
, member
, false));
986 getWriter()->sendDirectRequest(
987 protPropTid_
, protPropOid_
, protPropType_
, member
, inArguments
);
991 void Bridge::makeReleaseCall(
992 OUString
const & oid
, css::uno::TypeDescription
const & type
)
994 AttachThread
att(getThreadPool());
996 att
.getTid(), oid
, type
,
997 css::uno::TypeDescription("com.sun.star.uno.XInterface::release"),
998 std::vector
< BinaryAny
>());
1001 void Bridge::sendRequest(
1002 rtl::ByteSequence
const & tid
, OUString
const & oid
,
1003 css::uno::TypeDescription
const & type
,
1004 css::uno::TypeDescription
const & member
,
1005 std::vector
< BinaryAny
> const & inArguments
)
1007 getWriter()->queueRequest(tid
, oid
, type
, member
, inArguments
);
1010 void Bridge::throwException(bool exception
, BinaryAny
const & value
) {
1012 cppu::throwException(mapBinaryToCppAny(value
));
1016 css::uno::Any
Bridge::mapBinaryToCppAny(BinaryAny
const & binaryAny
) {
1017 BinaryAny
in(binaryAny
);
1020 uno_copyAndConvertData(
1022 css::uno::TypeDescription(cppu::UnoType
< css::uno::Any
>::get()).get(),
1023 binaryToCppMapping_
.get());
1027 bool Bridge::becameUnused() const {
1028 return stubs_
.empty() && proxies_
== 0 && calls_
== 0 && normalCall_
;
1031 void Bridge::terminateWhenUnused(bool unused
) {
1033 // That the current thread considers the bridge unused implies that it
1034 // is not within an incoming or outgoing remote call (so calling
1035 // terminate cannot lead to deadlock):
1040 void Bridge::checkDisposed() {
1041 assert(state_
!= STATE_INITIAL
);
1042 if (state_
!= STATE_STARTED
) {
1043 throw css::lang::DisposedException(
1044 "Binary URP bridge already disposed",
1045 static_cast< cppu::OWeakObject
* >(this));
1051 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */