/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ #include "sal/config.h" #include #include #include #include #include #include "boost/noncopyable.hpp" #include "com/sun/star/bridge/InvalidProtocolChangeException.hpp" #include "com/sun/star/bridge/XBridge.hpp" #include "com/sun/star/bridge/XInstanceProvider.hpp" #include "com/sun/star/bridge/XProtocolProperties.hpp" #include "com/sun/star/connection/XConnection.hpp" #include "com/sun/star/io/IOException.hpp" #include "com/sun/star/lang/DisposedException.hpp" #include "com/sun/star/lang/EventObject.hpp" #include "com/sun/star/lang/XEventListener.hpp" #include "com/sun/star/uno/Reference.hxx" #include "com/sun/star/uno/RuntimeException.hpp" #include "com/sun/star/uno/Sequence.hxx" #include "com/sun/star/uno/XInterface.hpp" #include "cppuhelper/exc_hlp.hxx" #include "cppuhelper/weak.hxx" #include "osl/diagnose.h" #include "osl/mutex.hxx" #include "osl/thread.hxx" #include "rtl/byteseq.hxx" #include "rtl/random.h" #include "rtl/ref.hxx" #include "rtl/textenc.h" #include "rtl/ustrbuf.hxx" #include "rtl/ustring.h" #include "rtl/ustring.hxx" #include "sal/types.h" #include "typelib/typeclass.h" #include "typelib/typedescription.h" #include "typelib/typedescription.hxx" #include "uno/dispatcher.hxx" #include "uno/environment.hxx" #include "uno/lbnames.h" #include "binaryany.hxx" #include "bridge.hxx" #include "bridgefactory.hxx" #include "incomingreply.hxx" #include "lessoperators.hxx" #include "outgoingrequest.hxx" #include "outgoingrequests.hxx" #include "proxy.hxx" #include "reader.hxx" namespace binaryurp { namespace { namespace css = com::sun::star; sal_Int32 random() { sal_Int32 n; rtlRandomPool pool = rtl_random_createPool(); rtl_random_getBytes(pool, &n, sizeof n); rtl_random_destroyPool(pool); return n; } extern "C" void SAL_CALL freeProxyCallback(uno_ExtEnvironment *, void * pProxy) { OSL_ASSERT(pProxy != 0); static_cast< Proxy * >(pProxy)->do_free(); } void joinThread(osl::Thread * thread) { OSL_ASSERT(thread != 0); if (thread->getIdentifier() != osl::Thread::getCurrentIdentifier()) { thread->join(); } } class AttachThread: private boost::noncopyable { public: explicit AttachThread(uno_ThreadPool threadPool); ~AttachThread(); rtl::ByteSequence getTid() throw (); private: uno_ThreadPool threadPool_; rtl::ByteSequence tid_; }; AttachThread::AttachThread(uno_ThreadPool threadPool): threadPool_(threadPool) { sal_Sequence * s = 0; uno_getIdOfCurrentThread(&s); tid_ = rtl::ByteSequence(s, rtl::BYTESEQ_NOACQUIRE); uno_threadpool_attach(threadPool_); } AttachThread::~AttachThread() { uno_threadpool_detach(threadPool_); uno_releaseIdFromCurrentThread(); } rtl::ByteSequence AttachThread::getTid() throw () { return tid_; } class PopOutgoingRequest: private boost::noncopyable { public: PopOutgoingRequest( OutgoingRequests & requests, rtl::ByteSequence const & tid, OutgoingRequest const & request); ~PopOutgoingRequest(); void clear(); private: OutgoingRequests & requests_; rtl::ByteSequence tid_; bool cleared_; }; PopOutgoingRequest::PopOutgoingRequest( OutgoingRequests & requests, rtl::ByteSequence const & tid, OutgoingRequest const & request): requests_(requests), tid_(tid), cleared_(false) { requests_.push(tid_, request); } PopOutgoingRequest::~PopOutgoingRequest() { if (!cleared_) { requests_.pop(tid_); } } void PopOutgoingRequest::clear() { cleared_ = true; } } Bridge::Bridge( rtl::Reference< BridgeFactory > const & factory, rtl::OUString const & name, css::uno::Reference< css::connection::XConnection > const & connection, css::uno::Reference< css::bridge::XInstanceProvider > const & provider): factory_(factory), name_(name), connection_(connection), provider_(provider), binaryUno_(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO))), cppToBinaryMapping_( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME)), rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO))), binaryToCppMapping_( rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(UNO_LB_UNO)), rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(CPPU_CURRENT_LANGUAGE_BINDING_NAME))), protPropTid_( reinterpret_cast< sal_Int8 const * >(".UrpProtocolPropertiesTid"), RTL_CONSTASCII_LENGTH(".UrpProtocolPropertiesTid")), protPropOid_(RTL_CONSTASCII_USTRINGPARAM("UrpProtocolProperties")), protPropType_( cppu::UnoType< css::uno::Reference< css::bridge::XProtocolProperties > >::get()), protPropRequest_( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.bridge.XProtocolProperties::requestChange"))), protPropCommit_( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.bridge.XProtocolProperties::commitChange"))), threadPool_(0), currentContextMode_(false), proxies_(0), calls_(0), normalCall_(false), activeCalls_(0), terminated_(false), mode_(MODE_REQUESTED) { OSL_ASSERT(factory.is() && connection.is()); if (!binaryUno_.is()) { throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("URP: no binary UNO environment")), css::uno::Reference< css::uno::XInterface >()); } if (!(cppToBinaryMapping_.is() && binaryToCppMapping_.is())) { throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("URP: no C++ UNO mapping")), css::uno::Reference< css::uno::XInterface >()); } passive_.set(); } void Bridge::start() { OSL_ASSERT(threadPool_ == 0 && !writer_.is() && !reader_.is()); threadPool_ = uno_threadpool_create(); OSL_ASSERT(threadPool_ != 0); writer_.set(new Writer(this)); writer_->create(); reader_.set(new Reader(this)); reader_->create(); } void Bridge::terminate() { rtl::Reference< Reader > r; rtl::Reference< Writer > w; Listeners ls; { osl::MutexGuard g(mutex_); if (terminated_) { return; } std::swap(reader_, r); std::swap(writer_, w); ls.swap(listeners_); terminated_ = true; } try { connection_->close(); } catch (css::io::IOException & e) { OSL_TRACE( OSL_LOG_PREFIX "caught IO exception '%s'", rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); } OSL_ASSERT(w.is()); w->stop(); joinThread(r.get()); joinThread(w.get()); OSL_ASSERT(threadPool_ != 0); uno_threadpool_dispose(threadPool_); Stubs s; { osl::MutexGuard g(mutex_); s.swap(stubs_); } for (Stubs::iterator i(s.begin()); i != s.end(); ++i) { for (Stub::iterator j(i->second.begin()); j != i->second.end(); ++j) { binaryUno_.get()->pExtEnv->revokeInterface( binaryUno_.get()->pExtEnv, j->second.object.get()); } } factory_->removeBridge(this); for (Listeners::iterator i(ls.begin()); i != ls.end(); ++i) { try { (*i)->disposing( css::lang::EventObject( static_cast< cppu::OWeakObject * >(this))); } catch (css::uno::RuntimeException & e) { OSL_TRACE( OSL_LOG_PREFIX "caught runtime exception '%s'", rtl::OUStringToOString( e.Message, RTL_TEXTENCODING_UTF8).getStr()); } } } css::uno::Reference< css::connection::XConnection > Bridge::getConnection() const { return connection_; } css::uno::Reference< css::bridge::XInstanceProvider > Bridge::getProvider() const { return provider_; } css::uno::Mapping & Bridge::getCppToBinaryMapping() { return cppToBinaryMapping_; } BinaryAny Bridge::mapCppToBinaryAny(css::uno::Any const & cppAny) { css::uno::Any in(cppAny); BinaryAny out; out.~BinaryAny(); uno_copyAndConvertData( out.get(), &in, css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(), cppToBinaryMapping_.get()); return out; } uno_ThreadPool Bridge::getThreadPool() const { OSL_ASSERT(threadPool_ != 0); return threadPool_; } rtl::Reference< Writer > Bridge::getWriter() { osl::MutexGuard g(mutex_); if (terminated_) { throw css::lang::DisposedException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Binary URP bridge already disposed")), static_cast< cppu::OWeakObject * >(this)); } OSL_ASSERT(writer_.is()); return writer_; } css::uno::UnoInterfaceReference Bridge::registerIncomingInterface( rtl::OUString const & oid, css::uno::TypeDescription const & type) { OSL_ASSERT(type.is()); if ( oid.isEmpty() ) { return css::uno::UnoInterfaceReference(); } css::uno::UnoInterfaceReference obj(findStub(oid, type)); if (!obj.is()) { binaryUno_.get()->pExtEnv->getRegisteredInterface( binaryUno_.get()->pExtEnv, reinterpret_cast< void ** >(&obj.m_pUnoI), oid.pData, reinterpret_cast< typelib_InterfaceTypeDescription * >(type.get())); if (obj.is()) { makeReleaseCall(oid, type); } else { obj.set(new Proxy(this, oid, type), SAL_NO_ACQUIRE); { osl::MutexGuard g(mutex_); OSL_ASSERT( proxies_ < std::numeric_limits< std::size_t >::max()); ++proxies_; } binaryUno_.get()->pExtEnv->registerProxyInterface( binaryUno_.get()->pExtEnv, reinterpret_cast< void ** >(&obj.m_pUnoI), &freeProxyCallback, oid.pData, reinterpret_cast< typelib_InterfaceTypeDescription * >( type.get())); } } return obj; } rtl::OUString Bridge::registerOutgoingInterface( css::uno::UnoInterfaceReference const & object, css::uno::TypeDescription const & type) { OSL_ASSERT(type.is()); if (!object.is()) { return rtl::OUString(); } rtl::OUString oid; if (!Proxy::isProxy(this, object, &oid)) { binaryUno_.get()->pExtEnv->getObjectIdentifier( binaryUno_.get()->pExtEnv, &oid.pData, object.get()); osl::MutexGuard g(mutex_); Stubs::iterator i(stubs_.find(oid)); Stub newStub; Stub * stub = i == stubs_.end() ? &newStub : &i->second; Stub::iterator j(stub->find(type)); //TODO: Release sub-stub if it is not successfully sent to remote side // (otherwise, stub will leak until terminate()): if (j == stub->end()) { j = stub->insert(Stub::value_type(type, SubStub())).first; if (stub == &newStub) { i = stubs_.insert(Stubs::value_type(oid, Stub())).first; std::swap(i->second, newStub); j = i->second.find(type); OSL_ASSERT(j != i->second.end()); } j->second.object = object; j->second.references = 1; binaryUno_.get()->pExtEnv->registerInterface( binaryUno_.get()->pExtEnv, reinterpret_cast< void ** >(&j->second.object.m_pUnoI), oid.pData, reinterpret_cast< typelib_InterfaceTypeDescription * >( type.get())); } else { OSL_ASSERT(stub != &newStub); if (j->second.references == SAL_MAX_UINT32) { throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URP: stub reference count overflow")), css::uno::Reference< css::uno::XInterface >()); } ++j->second.references; } } return oid; } css::uno::UnoInterfaceReference Bridge::findStub( rtl::OUString const & oid, css::uno::TypeDescription const & type) { OSL_ASSERT(!oid.isEmpty() && type.is()); osl::MutexGuard g(mutex_); Stubs::iterator i(stubs_.find(oid)); if (i != stubs_.end()) { Stub::iterator j(i->second.find(type)); if (j != i->second.end()) { return j->second.object; } for (j = i->second.begin(); j != i->second.end(); ++j) { if (typelib_typedescription_isAssignableFrom( type.get(), j->first.get())) { return j->second.object; } } } return css::uno::UnoInterfaceReference(); } void Bridge::releaseStub( rtl::OUString const & oid, css::uno::TypeDescription const & type) { OSL_ASSERT(!oid.isEmpty() && type.is()); css::uno::UnoInterfaceReference obj; bool unused; { osl::MutexGuard g(mutex_); Stubs::iterator i(stubs_.find(oid)); if (i == stubs_.end()) { throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("URP: release unknown stub")), css::uno::Reference< css::uno::XInterface >()); } Stub::iterator j(i->second.find(type)); if (j == i->second.end()) { throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("URP: release unknown stub")), css::uno::Reference< css::uno::XInterface >()); } OSL_ASSERT(j->second.references > 0); --j->second.references; if (j->second.references == 0) { obj = j->second.object; i->second.erase(j); if (i->second.empty()) { stubs_.erase(i); } } unused = becameUnused(); } if (obj.is()) { binaryUno_.get()->pExtEnv->revokeInterface( binaryUno_.get()->pExtEnv, obj.get()); } terminateWhenUnused(unused); } void Bridge::resurrectProxy(Proxy & proxy) { uno_Interface * p = &proxy; binaryUno_.get()->pExtEnv->registerProxyInterface( binaryUno_.get()->pExtEnv, reinterpret_cast< void ** >(&p), &freeProxyCallback, proxy.getOid().pData, reinterpret_cast< typelib_InterfaceTypeDescription * >( proxy.getType().get())); OSL_ASSERT(p == &proxy); } void Bridge::revokeProxy(Proxy & proxy) { binaryUno_.get()->pExtEnv->revokeInterface( binaryUno_.get()->pExtEnv, &proxy); } void Bridge::freeProxy(Proxy & proxy) { try { makeReleaseCall(proxy.getOid(), proxy.getType()); } catch (css::uno::RuntimeException & e) { OSL_TRACE( OSL_LOG_PREFIX "caught runtime exception '%s'", rtl::OUStringToOString(e.Message, RTL_TEXTENCODING_UTF8).getStr()); } catch (std::exception & e) { OSL_TRACE(OSL_LOG_PREFIX "caught C++ exception '%s'", e.what()); } bool unused; { osl::MutexGuard g(mutex_); OSL_ASSERT(proxies_ > 0); --proxies_; unused = becameUnused(); } terminateWhenUnused(unused); } void Bridge::incrementCalls(bool normalCall) throw () { osl::MutexGuard g(mutex_); OSL_ASSERT(calls_ < std::numeric_limits< std::size_t >::max()); ++calls_; normalCall_ |= normalCall; } void Bridge::decrementCalls() { bool unused; { osl::MutexGuard g(mutex_); OSL_ASSERT(calls_ > 0); --calls_; unused = becameUnused(); } terminateWhenUnused(unused); } void Bridge::incrementActiveCalls() throw () { osl::MutexGuard g(mutex_); OSL_ASSERT( activeCalls_ <= calls_ && activeCalls_ < std::numeric_limits< std::size_t >::max()); ++activeCalls_; passive_.reset(); } void Bridge::decrementActiveCalls() throw () { osl::MutexGuard g(mutex_); OSL_ASSERT(activeCalls_ <= calls_ && activeCalls_ > 0); --activeCalls_; if (activeCalls_ == 0) { passive_.set(); } } bool Bridge::makeCall( rtl::OUString const & oid, css::uno::TypeDescription const & member, bool setter, std::vector< BinaryAny > const & inArguments, BinaryAny * returnValue, std::vector< BinaryAny > * outArguments) { std::auto_ptr< IncomingReply > resp; { AttachThread att(threadPool_); PopOutgoingRequest pop( outgoingRequests_, att.getTid(), OutgoingRequest(OutgoingRequest::KIND_NORMAL, member, setter)); sendRequest( att.getTid(), oid, css::uno::TypeDescription(), member, inArguments); pop.clear(); incrementCalls(true); incrementActiveCalls(); void * job; uno_threadpool_enter(threadPool_, &job); resp.reset(static_cast< IncomingReply * >(job)); decrementActiveCalls(); decrementCalls(); } if (resp.get() == 0) { throw css::lang::DisposedException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Binary URP bridge disposed during call")), static_cast< cppu::OWeakObject * >(this)); } *returnValue = resp->returnValue; if (!resp->exception) { *outArguments = resp->outArguments; } return resp->exception; } void Bridge::sendRequestChangeRequest() { OSL_ASSERT(mode_ == MODE_REQUESTED); random_ = random(); std::vector< BinaryAny > a; a.push_back( BinaryAny( css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()), &random_)); sendProtPropRequest(OutgoingRequest::KIND_REQUEST_CHANGE, a); } void Bridge::handleRequestChangeReply( bool exception, BinaryAny const & returnValue) { throwException(exception, returnValue); sal_Int32 n = *static_cast< sal_Int32 * >( returnValue.getValue( css::uno::TypeDescription(cppu::UnoType< sal_Int32 >::get()))); sal_Int32 exp = 0; switch (mode_) { case MODE_REQUESTED: case MODE_REPLY_1: exp = 1; break; case MODE_REPLY_MINUS1: exp = -1; mode_ = MODE_REQUESTED; break; case MODE_REPLY_0: exp = 0; mode_ = MODE_WAIT; break; default: OSL_ASSERT(false); // this cannot happen break; } if (n != exp) { throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URP: requestChange reply with unexpected return value" " received")), static_cast< cppu::OWeakObject * >(this)); } decrementCalls(); switch (exp) { case -1: sendRequestChangeRequest(); break; case 0: break; case 1: sendCommitChangeRequest(); break; default: OSL_ASSERT(false); // this cannot happen break; } } void Bridge::handleCommitChangeReply( bool exception, BinaryAny const & returnValue) { bool ccMode = true; try { throwException(exception, returnValue); } catch (css::bridge::InvalidProtocolChangeException &) { ccMode = false; } if (ccMode) { setCurrentContextMode(); } OSL_ASSERT(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1); mode_ = MODE_NORMAL; getWriter()->unblock(); decrementCalls(); } void Bridge::handleRequestChangeRequest( rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments) { OSL_ASSERT(inArguments.size() == 1); switch (mode_) { case MODE_REQUESTED: { sal_Int32 n2 = *static_cast< sal_Int32 * >( inArguments[0].getValue( css::uno::TypeDescription( cppu::UnoType< sal_Int32 >::get()))); sal_Int32 ret; if (n2 > random_) { ret = 1; mode_ = MODE_REPLY_0; } else if (n2 == random_) { ret = -1; mode_ = MODE_REPLY_MINUS1; } else { ret = 0; mode_ = MODE_REPLY_1; } getWriter()->sendDirectReply( tid, protPropRequest_, false, BinaryAny( css::uno::TypeDescription( cppu::UnoType< sal_Int32 >::get()), &ret), std::vector< BinaryAny >()); break; } case MODE_NORMAL: { mode_ = MODE_NORMAL_WAIT; sal_Int32 ret = 1; getWriter()->queueReply( tid, protPropRequest_, false, false, BinaryAny( css::uno::TypeDescription( cppu::UnoType< sal_Int32 >::get()), &ret), std::vector< BinaryAny >(), false); break; } default: throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URP: unexpected requestChange request received")), static_cast< cppu::OWeakObject * >(this)); } } void Bridge::handleCommitChangeRequest( rtl::ByteSequence const & tid, std::vector< BinaryAny > const & inArguments) { bool ccMode = false; bool exc = false; BinaryAny ret; OSL_ASSERT(inArguments.size() == 1); css::uno::Sequence< css::bridge::ProtocolProperty > s; OSL_VERIFY(mapBinaryToCppAny(inArguments[0]) >>= s); for (sal_Int32 i = 0; i != s.getLength(); ++i) { if (s[i].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM("CurrentContext"))) { ccMode = true; } else { ccMode = false; exc = true; ret = mapCppToBinaryAny( css::uno::makeAny( css::bridge::InvalidProtocolChangeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "InvalidProtocolChangeException")), css::uno::Reference< css::uno::XInterface >(), s[i], 1))); break; } } switch (mode_) { case MODE_WAIT: getWriter()->sendDirectReply( tid, protPropCommit_, exc, ret, std::vector< BinaryAny >()); if (ccMode) { setCurrentContextMode(); mode_ = MODE_NORMAL; getWriter()->unblock(); } else { mode_ = MODE_REQUESTED; sendRequestChangeRequest(); } break; case MODE_NORMAL_WAIT: getWriter()->queueReply( tid, protPropCommit_, false, false, ret, std::vector< BinaryAny >(), ccMode); mode_ = MODE_NORMAL; break; default: throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "URP: unexpected commitChange request received")), static_cast< cppu::OWeakObject * >(this)); } } OutgoingRequest Bridge::lastOutgoingRequest(rtl::ByteSequence const & tid) { OutgoingRequest req(outgoingRequests_.top(tid)); outgoingRequests_.pop(tid); return req; } bool Bridge::isProtocolPropertiesRequest( rtl::OUString const & oid, css::uno::TypeDescription const & type) const { return oid == protPropOid_ && type.equals(protPropType_); } void Bridge::setCurrentContextMode() { osl::MutexGuard g(mutex_); currentContextMode_ = true; } bool Bridge::isCurrentContextMode() { osl::MutexGuard g(mutex_); return currentContextMode_; } Bridge::~Bridge() { if (threadPool_ != 0) { uno_threadpool_destroy(threadPool_); } } css::uno::Reference< css::uno::XInterface > Bridge::getInstance( rtl::OUString const & sInstanceName) throw (css::uno::RuntimeException) { if ( sInstanceName.isEmpty() ) { throw css::uno::RuntimeException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XBridge::getInstance sInstanceName must be non-empty")), static_cast< cppu::OWeakObject * >(this)); } for (sal_Int32 i = 0; i != sInstanceName.getLength(); ++i) { if (sInstanceName[i] > 0x7F) { throw css::io::IOException( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "XBridge::getInstance sInstanceName contains non-ASCII" " character")), css::uno::Reference< css::uno::XInterface >()); } } css::uno::TypeDescription ifc( cppu::UnoType< css::uno::Reference< css::uno::XInterface > >::get()); typelib_TypeDescription * p = ifc.get(); std::vector< BinaryAny > inArgs; inArgs.push_back( BinaryAny( css::uno::TypeDescription(cppu::UnoType< css::uno::Type >::get()), &p)); BinaryAny ret; std::vector< BinaryAny> outArgs; bool exc = makeCall( sInstanceName, css::uno::TypeDescription( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.uno.XInterface::queryInterface"))), false, inArgs, &ret, &outArgs); throwException(exc, ret); return css::uno::Reference< css::uno::XInterface >( static_cast< css::uno::XInterface * >( binaryToCppMapping_.mapInterface( *static_cast< uno_Interface ** >(ret.getValue(ifc)), ifc.get())), css::uno::UNO_REF_NO_ACQUIRE); } rtl::OUString Bridge::getName() throw (css::uno::RuntimeException) { return name_; } rtl::OUString Bridge::getDescription() throw (css::uno::RuntimeException) { rtl::OUStringBuffer b(name_); b.append(sal_Unicode(':')); b.append(connection_->getDescription()); return b.makeStringAndClear(); } void Bridge::dispose() throw (css::uno::RuntimeException) { terminate(); // OOo expects dispose to not return while there are still remote calls in // progress; an external protocol must ensure that dispose is not called // from within an incoming or outgoing remote call, as passive_.wait() would // otherwise deadlock: passive_.wait(); } void Bridge::addEventListener( css::uno::Reference< css::lang::XEventListener > const & xListener) throw (css::uno::RuntimeException) { OSL_ASSERT(xListener.is()); { osl::MutexGuard g(mutex_); if (!terminated_) { listeners_.push_back(xListener); return; } } xListener->disposing( css::lang::EventObject(static_cast< cppu::OWeakObject * >(this))); } void Bridge::removeEventListener( css::uno::Reference< css::lang::XEventListener > const & aListener) throw (css::uno::RuntimeException) { osl::MutexGuard g(mutex_); Listeners::iterator i( std::find(listeners_.begin(), listeners_.end(), aListener)); if (i != listeners_.end()) { listeners_.erase(i); } } void Bridge::sendCommitChangeRequest() { OSL_ASSERT(mode_ == MODE_REQUESTED || mode_ == MODE_REPLY_1); css::uno::Sequence< css::bridge::ProtocolProperty > s(1); s[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("CurrentContext")); std::vector< BinaryAny > a; a.push_back(mapCppToBinaryAny(css::uno::makeAny(s))); sendProtPropRequest(OutgoingRequest::KIND_COMMIT_CHANGE, a); } void Bridge::sendProtPropRequest( OutgoingRequest::Kind kind, std::vector< BinaryAny > const & inArguments) { OSL_ASSERT( kind == OutgoingRequest::KIND_REQUEST_CHANGE || kind == OutgoingRequest::KIND_COMMIT_CHANGE); incrementCalls(false); css::uno::TypeDescription member( kind == OutgoingRequest::KIND_REQUEST_CHANGE ? protPropRequest_ : protPropCommit_); PopOutgoingRequest pop( outgoingRequests_, protPropTid_, OutgoingRequest(kind, member, false)); getWriter()->sendDirectRequest( protPropTid_, protPropOid_, protPropType_, member, inArguments); pop.clear(); } void Bridge::makeReleaseCall( rtl::OUString const & oid, css::uno::TypeDescription const & type) { AttachThread att(threadPool_); sendRequest( att.getTid(), oid, type, css::uno::TypeDescription( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.uno.XInterface::release"))), std::vector< BinaryAny >()); } void Bridge::sendRequest( rtl::ByteSequence const & tid, rtl::OUString const & oid, css::uno::TypeDescription const & type, css::uno::TypeDescription const & member, std::vector< BinaryAny > const & inArguments) { getWriter()->queueRequest(tid, oid, type, member, inArguments); } void Bridge::throwException(bool exception, BinaryAny const & value) { if (exception) { cppu::throwException(mapBinaryToCppAny(value)); } } css::uno::Any Bridge::mapBinaryToCppAny(BinaryAny const & binaryAny) { BinaryAny in(binaryAny); css::uno::Any out; out.~Any(); uno_copyAndConvertData( &out, in.get(), css::uno::TypeDescription(cppu::UnoType< css::uno::Any >::get()).get(), binaryToCppMapping_.get()); return out; } bool Bridge::becameUnused() const { return stubs_.empty() && proxies_ == 0 && calls_ == 0 && normalCall_; } void Bridge::terminateWhenUnused(bool unused) { if (unused) { // That the current thread considers the bridge unused implies that it // is not within an incoming or outgoing remote call (so calling // terminate cannot lead to deadlock): terminate(); } } }