update emoji autocorrect entries from po-files
[LibreOffice.git] / binaryurp / source / bridge.cxx
blob54214c393dd5980d109eb77e560549ee500ed2f8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
22 #include <algorithm>
23 #include <cassert>
24 #include <cstddef>
25 #include <limits>
26 #include <memory>
27 #include <vector>
29 #include "com/sun/star/bridge/InvalidProtocolChangeException.hpp"
30 #include "com/sun/star/bridge/XBridge.hpp"
31 #include "com/sun/star/bridge/XInstanceProvider.hpp"
32 #include "com/sun/star/bridge/XProtocolProperties.hpp"
33 #include "com/sun/star/connection/XConnection.hpp"
34 #include "com/sun/star/io/IOException.hpp"
35 #include "com/sun/star/lang/DisposedException.hpp"
36 #include "com/sun/star/lang/EventObject.hpp"
37 #include "com/sun/star/lang/XEventListener.hpp"
38 #include "com/sun/star/uno/Reference.hxx"
39 #include "com/sun/star/uno/RuntimeException.hpp"
40 #include "com/sun/star/uno/Sequence.hxx"
41 #include "com/sun/star/uno/XInterface.hpp"
42 #include "cppuhelper/exc_hlp.hxx"
43 #include "cppuhelper/weak.hxx"
44 #include "osl/mutex.hxx"
45 #include "osl/thread.hxx"
46 #include "rtl/byteseq.hxx"
47 #include "rtl/random.h"
48 #include "rtl/ref.hxx"
49 #include "rtl/ustrbuf.hxx"
50 #include "rtl/ustring.h"
51 #include "rtl/ustring.hxx"
52 #include "sal/log.hxx"
53 #include "sal/types.h"
54 #include "typelib/typeclass.h"
55 #include "typelib/typedescription.h"
56 #include "typelib/typedescription.hxx"
57 #include "uno/dispatcher.hxx"
58 #include "uno/environment.hxx"
59 #include "uno/lbnames.h"
61 #include "binaryany.hxx"
62 #include "bridge.hxx"
63 #include "bridgefactory.hxx"
64 #include "incomingreply.hxx"
65 #include "lessoperators.hxx"
66 #include "outgoingrequest.hxx"
67 #include "outgoingrequests.hxx"
68 #include "proxy.hxx"
69 #include "reader.hxx"
71 namespace binaryurp {
73 namespace {
75 sal_Int32 random() {
76 sal_Int32 n;
77 rtlRandomPool pool = rtl_random_createPool();
78 rtl_random_getBytes(pool, &n, sizeof n);
79 rtl_random_destroyPool(pool);
80 return n;
83 OUString toString(css::uno::TypeDescription const & type) {
84 typelib_TypeDescription * d = type.get();
85 assert(d != 0 && d->pTypeName != 0);
86 return OUString(d->pTypeName);
89 extern "C" void SAL_CALL freeProxyCallback(
90 SAL_UNUSED_PARAMETER uno_ExtEnvironment *, void * pProxy)
92 assert(pProxy != 0);
93 static_cast< Proxy * >(pProxy)->do_free();
96 bool isThread(salhelper::Thread * thread) {
97 assert(thread != 0);
98 return osl::Thread::getCurrentIdentifier() == thread->getIdentifier();
101 class AttachThread {
102 public:
103 explicit AttachThread(uno_ThreadPool threadPool);
105 ~AttachThread();
107 rtl::ByteSequence getTid() throw () { return tid_;}
109 private:
110 AttachThread(const AttachThread&) SAL_DELETED_FUNCTION;
111 AttachThread& operator=(const AttachThread&) SAL_DELETED_FUNCTION;
113 uno_ThreadPool threadPool_;
114 rtl::ByteSequence tid_;
117 AttachThread::AttachThread(uno_ThreadPool threadPool): threadPool_(threadPool) {
118 sal_Sequence * s = 0;
119 uno_getIdOfCurrentThread(&s);
120 tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE);
121 uno_threadpool_attach(threadPool_);
124 AttachThread::~AttachThread() {
125 uno_threadpool_detach(threadPool_);
126 uno_releaseIdFromCurrentThread();
130 class PopOutgoingRequest {
131 public:
132 PopOutgoingRequest(
133 OutgoingRequests & requests, rtl::ByteSequence const & tid,
134 OutgoingRequest const & request);
136 ~PopOutgoingRequest();
138 void clear();
140 private:
141 PopOutgoingRequest(const PopOutgoingRequest&) SAL_DELETED_FUNCTION;
142 PopOutgoingRequest& operator=(const PopOutgoingRequest&) SAL_DELETED_FUNCTION;
144 OutgoingRequests & requests_;
145 rtl::ByteSequence tid_;
146 bool cleared_;
149 PopOutgoingRequest::PopOutgoingRequest(
150 OutgoingRequests & requests, rtl::ByteSequence const & tid,
151 OutgoingRequest const & request):
152 requests_(requests), tid_(tid), cleared_(false)
154 requests_.push(tid_, request);
157 PopOutgoingRequest::~PopOutgoingRequest() {
158 if (!cleared_) {
159 requests_.pop(tid_);
163 void PopOutgoingRequest::clear() {
164 cleared_ = true;
169 struct Bridge::SubStub {
170 com::sun::star::uno::UnoInterfaceReference object;
172 sal_uInt32 references;
175 Bridge::Bridge(
176 rtl::Reference< BridgeFactory > const & factory, OUString const & name,
177 css::uno::Reference< css::connection::XConnection > const & connection,
178 css::uno::Reference< css::bridge::XInstanceProvider > const & provider):
179 factory_(factory), name_(name), connection_(connection),
180 provider_(provider),
181 binaryUno_(UNO_LB_UNO),
182 cppToBinaryMapping_(CPPU_CURRENT_LANGUAGE_BINDING_NAME, UNO_LB_UNO),
183 binaryToCppMapping_(UNO_LB_UNO, CPPU_CURRENT_LANGUAGE_BINDING_NAME),
184 protPropTid_(
185 reinterpret_cast< sal_Int8 const * >(".UrpProtocolPropertiesTid"),
186 RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")),
187 protPropOid_("UrpProtocolProperties"),
188 protPropType_(
189 cppu::UnoType<
190 css::uno::Reference< css::bridge::XProtocolProperties > >::get()),
191 protPropRequest_("com.sun.star.bridge.XProtocolProperties::requestChange"),
192 protPropCommit_("com.sun.star.bridge.XProtocolProperties::commitChange"),
193 state_(STATE_INITIAL), threadPool_(0), currentContextMode_(false),
194 proxies_(0), calls_(0), normalCall_(false), activeCalls_(0),
195 mode_(MODE_REQUESTED)
197 assert(factory.is() && connection.is());
198 if (!binaryUno_.is()) {
199 throw css::uno::RuntimeException("URP: no binary UNO environment");
201 if (!(cppToBinaryMapping_.is() && binaryToCppMapping_.is())) {
202 throw css::uno::RuntimeException("URP: no C++ UNO mapping");
204 passive_.set();
207 void Bridge::start() {
208 rtl::Reference< Reader > r(new Reader(this));
209 rtl::Reference< Writer > w(new Writer(this));
211 osl::MutexGuard g(mutex_);
212 assert(
213 state_ == STATE_INITIAL && threadPool_ == 0 && !writer_.is() &&
214 !reader_.is());
215 threadPool_ = uno_threadpool_create();
216 assert(threadPool_ != 0);
217 reader_ = r;
218 writer_ = w;
219 state_ = STATE_STARTED;
221 // It is important to call reader_->launch() last here; both
222 // Writer::execute and Reader::execute can call Bridge::terminate, but
223 // Writer::execute is initially blocked in unblocked_.wait() until
224 // Reader::execute has called bridge_->sendRequestChangeRequest(), so
225 // effectively only reader_->launch() can lead to an early call to
226 // Bridge::terminate
227 w->launch();
228 r->launch();
231 void Bridge::terminate(bool final) {
232 uno_ThreadPool tp;
233 // Make sure function-local variables (Stubs s, etc.) are destroyed before
234 // the final uno_threadpool_destroy/threadPool_ = 0:
236 rtl::Reference< Reader > r;
237 rtl::Reference< Writer > w;
238 bool joinW;
239 Listeners ls;
241 osl::ClearableMutexGuard g(mutex_);
242 switch (state_) {
243 case STATE_INITIAL: // via ~Bridge -> dispose -> terminate
244 case STATE_FINAL:
245 return;
246 case STATE_STARTED:
247 break;
248 case STATE_TERMINATED:
249 if (final) {
250 g.clear();
251 terminated_.wait();
253 osl::MutexGuard g2(mutex_);
254 tp = threadPool_;
255 threadPool_ = 0;
256 if (reader_.is()) {
257 if (!isThread(reader_.get())) {
258 r = reader_;
260 reader_.clear();
262 if (writer_.is()) {
263 if (!isThread(writer_.get())) {
264 w = writer_;
266 writer_.clear();
268 state_ = STATE_FINAL;
270 assert(!(r.is() && w.is()));
271 if (r.is()) {
272 r->join();
273 } else if (w.is()) {
274 w->join();
276 if (tp != 0) {
277 uno_threadpool_destroy(tp);
280 return;
282 tp = threadPool_;
283 assert(!(final && isThread(reader_.get())));
284 if (!isThread(reader_.get())) {
285 std::swap(reader_, r);
287 w = writer_;
288 joinW = !isThread(writer_.get());
289 assert(!final || joinW);
290 if (joinW) {
291 writer_.clear();
293 ls.swap(listeners_);
294 state_ = final ? STATE_FINAL : STATE_TERMINATED;
296 try {
297 connection_->close();
298 } catch (const css::io::IOException & e) {
299 SAL_INFO("binaryurp", "caught IO exception '" << e.Message << '\'');
301 assert(w.is());
302 w->stop();
303 if (r.is()) {
304 r->join();
306 if (joinW) {
307 w->join();
309 assert(tp != 0);
310 uno_threadpool_dispose(tp);
311 Stubs s;
313 osl::MutexGuard g(mutex_);
314 s.swap(stubs_);
316 for (Stubs::iterator i(s.begin()); i != s.end(); ++i) {
317 for (Stub::iterator j(i->second.begin()); j != i->second.end(); ++j)
319 SAL_INFO(
320 "binaryurp",
321 "stub '" << i->first << "', '" << toString(j->first)
322 << "' still mapped at Bridge::terminate");
323 binaryUno_.get()->pExtEnv->revokeInterface(
324 binaryUno_.get()->pExtEnv, j->second.object.get());
327 factory_->removeBridge(this);
328 for (Listeners::iterator i(ls.begin()); i != ls.end(); ++i) {
329 try {
330 (*i)->disposing(
331 css::lang::EventObject(
332 static_cast< cppu::OWeakObject * >(this)));
333 } catch (const css::uno::RuntimeException & e) {
334 SAL_WARN(
335 "binaryurp",
336 "caught runtime exception '" << e.Message << '\'');
340 if (final) {
341 uno_threadpool_destroy(tp);
344 osl::MutexGuard g(mutex_);
345 if (final) {
346 threadPool_ = 0;
349 terminated_.set();
355 BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) {
356 css::uno::Any in(cppAny);
357 BinaryAny out;
358 out.~BinaryAny();
359 uno_copyAndConvertData(
360 &out.get(), &in,
361 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
362 cppToBinaryMapping_.get());
363 return out;
366 uno_ThreadPool Bridge::getThreadPool() {
367 osl::MutexGuard g(mutex_);
368 checkDisposed();
369 assert(threadPool_ != 0);
370 return threadPool_;
373 rtl::Reference< Writer > Bridge::getWriter() {
374 osl::MutexGuard g(mutex_);
375 checkDisposed();
376 assert(writer_.is());
377 return writer_;
380 css::uno::UnoInterfaceReference Bridge::registerIncomingInterface(
381 OUString const & oid, css::uno::TypeDescription const & type)
383 assert(type.is());
384 if (oid.isEmpty()) {
385 return css::uno::UnoInterfaceReference();
387 css::uno::UnoInterfaceReference obj(findStub(oid, type));
388 if (!obj.is()) {
389 binaryUno_.get()->pExtEnv->getRegisteredInterface(
390 binaryUno_.get()->pExtEnv,
391 reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData,
392 reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get()));
393 if (obj.is()) {
394 makeReleaseCall(oid, type);
395 } else {
396 obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE);
398 osl::MutexGuard g(mutex_);
399 assert(proxies_ < std::numeric_limits< std::size_t >::max());
400 ++proxies_;
402 binaryUno_.get()->pExtEnv->registerProxyInterface(
403 binaryUno_.get()->pExtEnv,
404 reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback,
405 oid.pData,
406 reinterpret_cast< typelib_InterfaceTypeDescription * >(
407 type.get()));
410 return obj;
413 OUString Bridge::registerOutgoingInterface(
414 css::uno::UnoInterfaceReference const & object,
415 css::uno::TypeDescription const & type)
417 assert(type.is());
418 if (!object.is()) {
419 return OUString();
421 OUString oid;
422 if (!Proxy::isProxy(this, object, &oid)) {
423 binaryUno_.get()->pExtEnv->getObjectIdentifier(
424 binaryUno_.get()->pExtEnv, &oid.pData, object.get());
425 osl::MutexGuard g(mutex_);
426 Stubs::iterator i(stubs_.find(oid));
427 Stub newStub;
428 Stub * stub = i == stubs_.end() ? &newStub : &i->second;
429 Stub::iterator j(stub->find(type));
430 //TODO: Release sub-stub if it is not successfully sent to remote side
431 // (otherwise, stub will leak until terminate()):
432 if (j == stub->end()) {
433 j = stub->insert(Stub::value_type(type, SubStub())).first;
434 if (stub == &newStub) {
435 i = stubs_.insert(Stubs::value_type(oid, Stub())).first;
436 std::swap(i->second, newStub);
437 j = i->second.find(type);
438 assert(j != i->second.end());
440 j->second.object = object;
441 j->second.references = 1;
442 binaryUno_.get()->pExtEnv->registerInterface(
443 binaryUno_.get()->pExtEnv,
444 reinterpret_cast< void ** >(&j->second.object.m_pUnoI),
445 oid.pData,
446 reinterpret_cast< typelib_InterfaceTypeDescription * >(
447 type.get()));
448 } else {
449 assert(stub != &newStub);
450 if (j->second.references == SAL_MAX_UINT32) {
451 throw css::uno::RuntimeException(
452 "URP: stub reference count overflow");
454 ++j->second.references;
457 return oid;
460 css::uno::UnoInterfaceReference Bridge::findStub(
461 OUString const & oid, css::uno::TypeDescription const & type)
463 assert(!oid.isEmpty() && type.is());
464 osl::MutexGuard g(mutex_);
465 Stubs::iterator i(stubs_.find(oid));
466 if (i != stubs_.end()) {
467 Stub::iterator j(i->second.find(type));
468 if (j != i->second.end()) {
469 return j->second.object;
471 for (j = i->second.begin(); j != i->second.end(); ++j) {
472 if (typelib_typedescription_isAssignableFrom(
473 type.get(), j->first.get()))
475 return j->second.object;
479 return css::uno::UnoInterfaceReference();
482 void Bridge::releaseStub(
483 OUString const & oid, css::uno::TypeDescription const & type)
485 assert(!oid.isEmpty() && type.is());
486 css::uno::UnoInterfaceReference obj;
487 bool unused;
489 osl::MutexGuard g(mutex_);
490 Stubs::iterator i(stubs_.find(oid));
491 if (i == stubs_.end()) {
492 throw css::uno::RuntimeException("URP: release unknown stub");
494 Stub::iterator j(i->second.find(type));
495 if (j == i->second.end()) {
496 throw css::uno::RuntimeException("URP: release unknown stub");
498 assert(j->second.references > 0);
499 --j->second.references;
500 if (j->second.references == 0) {
501 obj = j->second.object;
502 i->second.erase(j);
503 if (i->second.empty()) {
504 stubs_.erase(i);
507 unused = becameUnused();
509 if (obj.is()) {
510 binaryUno_.get()->pExtEnv->revokeInterface(
511 binaryUno_.get()->pExtEnv, obj.get());
513 terminateWhenUnused(unused);
516 void Bridge::resurrectProxy(Proxy & proxy) {
517 uno_Interface * p = &proxy;
518 binaryUno_.get()->pExtEnv->registerProxyInterface(
519 binaryUno_.get()->pExtEnv,
520 reinterpret_cast< void ** >(&p), &freeProxyCallback,
521 proxy.getOid().pData,
522 reinterpret_cast< typelib_InterfaceTypeDescription * >(
523 proxy.getType().get()));
524 assert(p == &proxy);
527 void Bridge::revokeProxy(Proxy & proxy) {
528 binaryUno_.get()->pExtEnv->revokeInterface(
529 binaryUno_.get()->pExtEnv, &proxy);
532 void Bridge::freeProxy(Proxy & proxy) {
533 try {
534 makeReleaseCall(proxy.getOid(), proxy.getType());
535 } catch (const css::uno::RuntimeException & e) {
536 SAL_INFO(
537 "binaryurp", "caught runtime exception '" << e.Message << '\'');
538 } catch (const std::exception & e) {
539 SAL_WARN("binaryurp", "caught C++ exception '" << e.what() << '\'');
541 bool unused;
543 osl::MutexGuard g(mutex_);
544 assert(proxies_ > 0);
545 --proxies_;
546 unused = becameUnused();
548 terminateWhenUnused(unused);
551 void Bridge::incrementCalls(bool normalCall) throw () {
552 osl::MutexGuard g(mutex_);
553 assert(calls_ < std::numeric_limits< std::size_t >::max());
554 ++calls_;
555 normalCall_ |= normalCall;
558 void Bridge::decrementCalls() {
559 bool unused;
561 osl::MutexGuard g(mutex_);
562 assert(calls_ > 0);
563 --calls_;
564 unused = becameUnused();
566 terminateWhenUnused(unused);
569 void Bridge::incrementActiveCalls() throw () {
570 osl::MutexGuard g(mutex_);
571 assert(
572 activeCalls_ <= calls_ &&
573 activeCalls_ < std::numeric_limits< std::size_t >::max());
574 ++activeCalls_;
575 passive_.reset();
578 void Bridge::decrementActiveCalls() throw () {
579 osl::MutexGuard g(mutex_);
580 assert(activeCalls_ <= calls_ && activeCalls_ > 0);
581 --activeCalls_;
582 if (activeCalls_ == 0) {
583 passive_.set();
587 bool Bridge::makeCall(
588 OUString const & oid, css::uno::TypeDescription const & member,
589 bool setter, std::vector< BinaryAny > const & inArguments,
590 BinaryAny * returnValue, std::vector< BinaryAny > * outArguments)
592 std::unique_ptr< IncomingReply > resp;
594 uno_ThreadPool tp = getThreadPool();
595 AttachThread att(tp);
596 PopOutgoingRequest pop(
597 outgoingRequests_, att.getTid(),
598 OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter));
599 sendRequest(
600 att.getTid(), oid, css::uno::TypeDescription(), member,
601 inArguments);
602 pop.clear();
603 incrementCalls(true);
604 incrementActiveCalls();
605 void * job;
606 uno_threadpool_enter(tp, &job);
607 resp.reset(static_cast< IncomingReply * >(job));
608 decrementActiveCalls();
609 decrementCalls();
611 if (resp.get() == 0) {
612 throw css::lang::DisposedException(
613 "Binary URP bridge disposed during call",
614 static_cast< cppu::OWeakObject * >(this));
616 *returnValue = resp->returnValue;
617 if (!resp->exception) {
618 *outArguments = resp->outArguments;
620 return resp->exception;
623 void Bridge::sendRequestChangeRequest() {
624 assert(mode_ == MODE_REQUESTED);
625 random_ = random();
626 std::vector< BinaryAny > a;
627 a.push_back(
628 BinaryAny(
629 css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()),
630 &random_));
631 sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a);
634 void Bridge::handleRequestChangeReply(
635 bool exception, BinaryAny const & returnValue)
637 try {
638 throwException(exception, returnValue);
639 } catch (css::uno::RuntimeException & e) {
640 // Before OOo 2.2, Java URP would throw a RuntimeException when
641 // receiving a requestChange message (see i#35277 "Java URP: Support
642 // Manipulation of Protocol Properties"):
643 if (mode_ != MODE_REQUESTED) {
644 throw;
646 SAL_WARN(
647 "binaryurp",
648 "requestChange caught RuntimeException \'" << e.Message
649 << "' in state 'requested'");
650 mode_ = MODE_NORMAL;
651 getWriter()->unblock();
652 decrementCalls();
653 return;
655 sal_Int32 n = *static_cast< sal_Int32 * >(
656 returnValue.getValue(
657 css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get())));
658 sal_Int32 exp = 0;
659 switch (mode_) {
660 case MODE_REQUESTED:
661 case MODE_REPLY_1:
662 exp = 1;
663 break;
664 case MODE_REPLY_MINUS1:
665 exp = -1;
666 mode_ = MODE_REQUESTED;
667 break;
668 case MODE_REPLY_0:
669 exp = 0;
670 mode_ = MODE_WAIT;
671 break;
672 default:
673 assert(false); // this cannot happen
674 break;
676 if (n != exp) {
677 throw css::uno::RuntimeException(
678 "URP: requestChange reply with unexpected return value received",
679 static_cast< cppu::OWeakObject * >(this));
681 decrementCalls();
682 switch (exp) {
683 case -1:
684 sendRequestChangeRequest();
685 break;
686 case 0:
687 break;
688 case 1:
689 sendCommitChangeRequest();
690 break;
691 default:
692 assert(false); // this cannot happen
693 break;
697 void Bridge::handleCommitChangeReply(
698 bool exception, BinaryAny const & returnValue)
700 bool ccMode = true;
701 try {
702 throwException(exception, returnValue);
703 } catch (const css::bridge::InvalidProtocolChangeException &) {
704 ccMode = false;
706 if (ccMode) {
707 setCurrentContextMode();
709 assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
710 mode_ = MODE_NORMAL;
711 getWriter()->unblock();
712 decrementCalls();
715 void Bridge::handleRequestChangeRequest(
716 rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
718 assert(inArguments.size() == 1);
719 switch (mode_) {
720 case MODE_REQUESTED:
722 sal_Int32 n2 = *static_cast< sal_Int32 * >(
723 inArguments[0].getValue(
724 css::uno::TypeDescription(
725 cppu::UnoType< sal_Int32 >::get())));
726 sal_Int32 ret;
727 if (n2 > random_) {
728 ret = 1;
729 mode_ = MODE_REPLY_0;
730 } else if (n2 == random_) {
731 ret = -1;
732 mode_ = MODE_REPLY_MINUS1;
733 } else {
734 ret = 0;
735 mode_ = MODE_REPLY_1;
737 getWriter()->sendDirectReply(
738 tid, protPropRequest_, false,
739 BinaryAny(
740 css::uno::TypeDescription(
741 cppu::UnoType< sal_Int32 >::get()),
742 &ret),
743 std::vector< BinaryAny >());
744 break;
746 case MODE_NORMAL:
748 mode_ = MODE_NORMAL_WAIT;
749 sal_Int32 ret = 1;
750 getWriter()->queueReply(
751 tid, protPropRequest_, false, false,
752 BinaryAny(
753 css::uno::TypeDescription(
754 cppu::UnoType< sal_Int32 >::get()),
755 &ret),
756 std::vector< BinaryAny >(), false);
757 break;
759 default:
760 throw css::uno::RuntimeException(
761 "URP: unexpected requestChange request received",
762 static_cast< cppu::OWeakObject * >(this));
766 void Bridge::handleCommitChangeRequest(
767 rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments)
769 bool ccMode = false;
770 bool exc = false;
771 BinaryAny ret;
772 assert(inArguments.size() == 1);
773 css::uno::Sequence< css::bridge::ProtocolProperty > s;
774 bool ok = (mapBinaryToCppAny(inArguments[0]) >>= s);
775 assert(ok);
776 (void) ok; // avoid warnings
777 for (sal_Int32 i = 0; i != s.getLength(); ++i) {
778 if (s[i].Name == "CurrentContext") {
779 ccMode = true;
780 } else {
781 ccMode = false;
782 exc = true;
783 ret = mapCppToBinaryAny(
784 css::uno::makeAny(
785 css::bridge::InvalidProtocolChangeException(
786 "InvalidProtocolChangeException",
787 css::uno::Reference< css::uno::XInterface >(), s[i],
788 1)));
789 break;
792 switch (mode_) {
793 case MODE_WAIT:
794 getWriter()->sendDirectReply(
795 tid, protPropCommit_, exc, ret, std::vector< BinaryAny >());
796 if (ccMode) {
797 setCurrentContextMode();
798 mode_ = MODE_NORMAL;
799 getWriter()->unblock();
800 } else {
801 mode_ = MODE_REQUESTED;
802 sendRequestChangeRequest();
804 break;
805 case MODE_NORMAL_WAIT:
806 getWriter()->queueReply(
807 tid, protPropCommit_, false, false, ret, std::vector< BinaryAny >(),
808 ccMode);
809 mode_ = MODE_NORMAL;
810 break;
811 default:
812 throw css::uno::RuntimeException(
813 "URP: unexpected commitChange request received",
814 static_cast< cppu::OWeakObject * >(this));
818 OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) {
819 OutgoingRequest req(outgoingRequests_.top(tid));
820 outgoingRequests_.pop(tid);
821 return req;
824 bool Bridge::isProtocolPropertiesRequest(
825 OUString const & oid, css::uno::TypeDescription const & type) const
827 return oid == protPropOid_ && type.equals(protPropType_);
830 void Bridge::setCurrentContextMode() {
831 osl::MutexGuard g(mutex_);
832 currentContextMode_ = true;
835 bool Bridge::isCurrentContextMode() {
836 osl::MutexGuard g(mutex_);
837 return currentContextMode_;
840 Bridge::~Bridge() {
841 #if OSL_DEBUG_LEVEL > 0
843 osl::MutexGuard g(mutex_);
844 SAL_WARN_IF(
845 state_ == STATE_STARTED || state_ == STATE_TERMINATED, "binaryurp",
846 "undisposed bridge, potential deadlock ahead");
848 #endif
849 dispose();
852 css::uno::Reference< css::uno::XInterface > Bridge::getInstance(
853 OUString const & sInstanceName) throw (css::uno::RuntimeException, std::exception)
855 if (sInstanceName.isEmpty()) {
856 throw css::uno::RuntimeException(
857 "XBridge::getInstance sInstanceName must be non-empty",
858 static_cast< cppu::OWeakObject * >(this));
860 for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) {
861 if (sInstanceName[i] > 0x7F) {
862 throw css::uno::RuntimeException(
863 "XBridge::getInstance sInstanceName contains non-ASCII"
864 " character");
867 css::uno::TypeDescription ifc(cppu::UnoType<css::uno::XInterface>::get());
868 typelib_TypeDescription * p = ifc.get();
869 std::vector< BinaryAny > inArgs;
870 inArgs.push_back(
871 BinaryAny(
872 css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()),
873 &p));
874 BinaryAny ret;
875 std::vector< BinaryAny> outArgs;
876 bool exc = makeCall(
877 sInstanceName,
878 css::uno::TypeDescription(
879 "com.sun.star.uno.XInterface::queryInterface"),
880 false, inArgs, &ret, &outArgs);
881 throwException(exc, ret);
882 return css::uno::Reference< css::uno::XInterface >(
883 static_cast< css::uno::XInterface * >(
884 binaryToCppMapping_.mapInterface(
885 *static_cast< uno_Interface ** >(ret.getValue(ifc)),
886 ifc.get())),
887 css::uno::UNO_REF_NO_ACQUIRE);
890 OUString Bridge::getName() throw (css::uno::RuntimeException, std::exception) {
891 return name_;
894 OUString Bridge::getDescription() throw (css::uno::RuntimeException, std::exception) {
895 OUStringBuffer b(name_);
896 b.append(':');
897 b.append(connection_->getDescription());
898 return b.makeStringAndClear();
901 void Bridge::dispose() throw (css::uno::RuntimeException, std::exception) {
902 // For terminate(true) not to deadlock, an external protocol must ensure
903 // that dispose is not called from a thread pool worker thread (that dispose
904 // is never called from the reader or writer thread is already ensured
905 // internally):
906 terminate(true);
907 // OOo expects dispose to not return while there are still remote calls in
908 // progress; an external protocol must ensure that dispose is not called
909 // from within an incoming or outgoing remote call, as passive_.wait() would
910 // otherwise deadlock:
911 passive_.wait();
914 void Bridge::addEventListener(
915 css::uno::Reference< css::lang::XEventListener > const & xListener)
916 throw (css::uno::RuntimeException, std::exception)
918 assert(xListener.is());
920 osl::MutexGuard g(mutex_);
921 assert(state_ != STATE_INITIAL);
922 if (state_ == STATE_STARTED) {
923 listeners_.push_back(xListener);
924 return;
927 xListener->disposing(
928 css::lang::EventObject(static_cast< cppu::OWeakObject * >(this)));
931 void Bridge::removeEventListener(
932 css::uno::Reference< css::lang::XEventListener > const & aListener)
933 throw (css::uno::RuntimeException, std::exception)
935 osl::MutexGuard g(mutex_);
936 Listeners::iterator i(
937 std::find(listeners_.begin(), listeners_.end(), aListener));
938 if (i != listeners_.end()) {
939 listeners_.erase(i);
943 void Bridge::sendCommitChangeRequest() {
944 assert(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1);
945 css::uno::Sequence< css::bridge::ProtocolProperty > s(1);
946 s[0].Name = "CurrentContext";
947 std::vector< BinaryAny > a;
948 a.push_back(mapCppToBinaryAny(css::uno::makeAny(s)));
949 sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a);
952 void Bridge::sendProtPropRequest(
953 OutgoingRequest::Kind kind, std::vector< BinaryAny > const & inArguments)
955 assert(
956 kind == OutgoingRequest::KIND_REQUEST_CHANGE ||
957 kind == OutgoingRequest::KIND_COMMIT_CHANGE);
958 incrementCalls(false);
959 css::uno::TypeDescription member(
960 kind == OutgoingRequest::KIND_REQUEST_CHANGE
961 ? protPropRequest_ : protPropCommit_);
962 PopOutgoingRequest pop(
963 outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false));
964 getWriter()->sendDirectRequest(
965 protPropTid_, protPropOid_, protPropType_, member, inArguments);
966 pop.clear();
969 void Bridge::makeReleaseCall(
970 OUString const & oid, css::uno::TypeDescription const & type)
972 AttachThread att(getThreadPool());
973 sendRequest(
974 att.getTid(), oid, type,
975 css::uno::TypeDescription("com.sun.star.uno.XInterface::release"),
976 std::vector< BinaryAny >());
979 void Bridge::sendRequest(
980 rtl::ByteSequence const & tid, OUString const & oid,
981 css::uno::TypeDescription const & type,
982 css::uno::TypeDescription const & member,
983 std::vector< BinaryAny > const & inArguments)
985 getWriter()->queueRequest(tid, oid, type, member, inArguments);
988 void Bridge::throwException(bool exception, BinaryAny const & value) {
989 if (exception) {
990 cppu::throwException(mapBinaryToCppAny(value));
994 css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) {
995 BinaryAny in(binaryAny);
996 css::uno::Any out;
997 out.~Any();
998 uno_copyAndConvertData(
999 &out, &in.get(),
1000 css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(),
1001 binaryToCppMapping_.get());
1002 return out;
1005 bool Bridge::becameUnused() const {
1006 return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_;
1009 void Bridge::terminateWhenUnused(bool unused) {
1010 if (unused) {
1011 // That the current thread considers the bridge unused implies that it
1012 // is not within an incoming or outgoing remote call (so calling
1013 // terminate cannot lead to deadlock):
1014 terminate(false);
1018 void Bridge::checkDisposed() {
1019 assert(state_ != STATE_INITIAL);
1020 if (state_ != STATE_STARTED) {
1021 throw css::lang::DisposedException(
1022 "Binary URP bridge already disposed",
1023 static_cast< cppu::OWeakObject * >(this));
1029 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */