| /************************************************************** |
| * |
| * 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 <list> |
| #include <vector> |
| |
| #include "boost/noncopyable.hpp" |
| #include "com/sun/star/bridge/XInstanceProvider.hpp" |
| #include "cppuhelper/exc_hlp.hxx" |
| #include "rtl/byteseq.hxx" |
| #include "rtl/ref.hxx" |
| #include "rtl/ustring.hxx" |
| #include "sal/types.h" |
| #include "typelib/typedescription.hxx" |
| #include "uno/dispatcher.hxx" |
| |
| #include "binaryany.hxx" |
| #include "bridge.hxx" |
| #include "currentcontext.hxx" |
| #include "incomingrequest.hxx" |
| #include "specialfunctionids.hxx" |
| |
| namespace binaryurp { |
| |
| namespace { |
| |
| namespace css = com::sun::star; |
| |
| } |
| |
| IncomingRequest::IncomingRequest( |
| rtl::Reference< Bridge > const & bridge, rtl::ByteSequence const & tid, |
| rtl::OUString const & oid, css::uno::UnoInterfaceReference const & object, |
| css::uno::TypeDescription const & type, sal_uInt16 functionId, |
| bool synchronous, css::uno::TypeDescription const & member, bool setter, |
| std::vector< BinaryAny > const & inArguments, bool currentContextMode, |
| css::uno::UnoInterfaceReference const & currentContext): |
| bridge_(bridge), tid_(tid), oid_(oid), object_(object), type_(type), |
| functionId_(functionId), synchronous_(synchronous), member_(member), |
| setter_(setter), inArguments_(inArguments), |
| currentContextMode_(currentContextMode), currentContext_(currentContext) |
| { |
| OSL_ASSERT(bridge.is() && member.is() && member.get()->bComplete); |
| } |
| |
| IncomingRequest::~IncomingRequest() {} |
| |
| void IncomingRequest::execute() const { |
| BinaryAny ret; |
| std::vector< BinaryAny > outArgs; |
| bool isExc; |
| try { |
| bool resetCc = false; |
| css::uno::UnoInterfaceReference oldCc; |
| if (currentContextMode_) { |
| oldCc = current_context::get(); |
| current_context::set(currentContext_); |
| resetCc = true; |
| } |
| try { |
| try { |
| isExc = !execute_throw(&ret, &outArgs); |
| } catch (std::exception & e) { |
| throw css::uno::RuntimeException( |
| (rtl::OUString( |
| RTL_CONSTASCII_USTRINGPARAM("caught C++ exception: ")) + |
| rtl::OStringToOUString( |
| rtl::OString(e.what()), RTL_TEXTENCODING_ASCII_US)), |
| css::uno::Reference< css::uno::XInterface >()); |
| // best-effort string conversion |
| } |
| } catch (css::uno::RuntimeException &) { |
| css::uno::Any exc(cppu::getCaughtException()); |
| ret = bridge_->mapCppToBinaryAny(exc); |
| isExc = true; |
| } |
| if (resetCc) { |
| current_context::set(oldCc); |
| } |
| } catch (css::uno::RuntimeException &) { |
| css::uno::Any exc(cppu::getCaughtException()); |
| ret = bridge_->mapCppToBinaryAny(exc); |
| isExc = true; |
| } |
| if (synchronous_) { |
| bridge_->decrementActiveCalls(); |
| try { |
| bridge_->getWriter()->queueReply( |
| tid_, member_, setter_, isExc, ret, outArgs, false); |
| return; |
| } catch (css::uno::RuntimeException & e) { |
| OSL_TRACE( |
| OSL_LOG_PREFIX "caught UNO 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()); |
| } |
| bridge_->terminate(); |
| } else { |
| if (isExc) { |
| OSL_TRACE(OSL_LOG_PREFIX "oneway method raised exception"); |
| } |
| bridge_->decrementCalls(); |
| } |
| } |
| |
| bool IncomingRequest::execute_throw( |
| BinaryAny * returnValue, std::vector< BinaryAny > * outArguments) const |
| { |
| OSL_ASSERT( |
| returnValue != 0 && |
| returnValue->getType().equals( |
| css::uno::TypeDescription( |
| cppu::UnoType< cppu::UnoVoidType >::get())) && |
| outArguments != 0 && outArguments->empty()); |
| bool isExc = false; |
| switch (functionId_) { |
| case SPECIAL_FUNCTION_ID_RESERVED: |
| OSL_ASSERT(false); // this cannot happen |
| break; |
| case SPECIAL_FUNCTION_ID_RELEASE: |
| bridge_->releaseStub(oid_, type_); |
| break; |
| case SPECIAL_FUNCTION_ID_QUERY_INTERFACE: |
| if (!object_.is()) { |
| css::uno::Reference< css::uno::XInterface > ifc; |
| css::uno::Reference< css::bridge::XInstanceProvider > prov( |
| bridge_->getProvider()); |
| if (prov.is()) { |
| try { |
| ifc = prov->getInstance(oid_); |
| } catch (css::container::NoSuchElementException & e) { |
| OSL_TRACE( |
| (OSL_LOG_PREFIX "initial element '%s':" |
| " NoSuchElementException '%s'"), |
| (rtl::OUStringToOString(oid_, RTL_TEXTENCODING_UTF8). |
| getStr()), |
| (rtl::OUStringToOString( |
| e.Message, RTL_TEXTENCODING_UTF8). |
| getStr())); |
| } |
| } |
| if (ifc.is()) { |
| css::uno::UnoInterfaceReference unoIfc( |
| static_cast< uno_Interface * >( |
| bridge_->getCppToBinaryMapping().mapInterface( |
| ifc.get(), |
| (css::uno::TypeDescription( |
| cppu::UnoType< |
| css::uno::Reference< |
| css::uno::XInterface > >::get()). |
| get()))), |
| SAL_NO_ACQUIRE); |
| *returnValue = BinaryAny( |
| css::uno::TypeDescription( |
| cppu::UnoType< |
| css::uno::Reference< |
| css::uno::XInterface > >::get()), |
| &unoIfc.m_pUnoI); |
| } |
| break; |
| } |
| // fall through |
| default: |
| { |
| OSL_ASSERT(object_.is()); |
| css::uno::TypeDescription retType; |
| std::list< std::vector< char > > outBufs; |
| std::vector< void * > args; |
| switch (member_.get()->eTypeClass) { |
| case typelib_TypeClass_INTERFACE_ATTRIBUTE: |
| { |
| css::uno::TypeDescription t( |
| reinterpret_cast< |
| typelib_InterfaceAttributeTypeDescription * >( |
| member_.get())-> |
| pAttributeTypeRef); |
| if (setter_) { |
| OSL_ASSERT(inArguments_.size() == 1); |
| args.push_back(inArguments_[0].getValue(t)); |
| } else { |
| OSL_ASSERT(inArguments_.empty()); |
| retType = t; |
| } |
| break; |
| } |
| case typelib_TypeClass_INTERFACE_METHOD: |
| { |
| typelib_InterfaceMethodTypeDescription * mtd = |
| reinterpret_cast< |
| typelib_InterfaceMethodTypeDescription * >( |
| member_.get()); |
| retType = css::uno::TypeDescription(mtd->pReturnTypeRef); |
| std::vector< BinaryAny >::const_iterator i( |
| inArguments_.begin()); |
| for (sal_Int32 j = 0; j != mtd->nParams; ++j) { |
| void * p; |
| if (mtd->pParams[j].bIn) { |
| p = i++->getValue( |
| css::uno::TypeDescription( |
| mtd->pParams[j].pTypeRef)); |
| } else { |
| outBufs.push_back( |
| std::vector< char >( |
| css::uno::TypeDescription( |
| mtd->pParams[j].pTypeRef). |
| get()->nSize)); |
| p = &outBufs.back()[0]; |
| } |
| args.push_back(p); |
| if (mtd->pParams[j].bOut) { |
| outArguments->push_back(BinaryAny()); |
| } |
| } |
| OSL_ASSERT(i == inArguments_.end()); |
| break; |
| } |
| default: |
| OSL_ASSERT(false); // this cannot happen |
| break; |
| } |
| std::vector< char > retBuf(retType.is() ? retType.get()->nSize : 0); |
| uno_Any exc; |
| uno_Any * pexc = &exc; |
| (*object_.get()->pDispatcher)( |
| object_.get(), member_.get(), retBuf.empty() ? 0 : &retBuf[0], |
| args.empty() ? 0 : &args[0], &pexc); |
| isExc = pexc != 0; |
| if (isExc) { |
| *returnValue = BinaryAny( |
| css::uno::TypeDescription( |
| cppu::UnoType< css::uno::Any >::get()), |
| &exc); |
| uno_any_destruct(&exc, 0); |
| } else { |
| if (!retBuf.empty()) { |
| *returnValue = BinaryAny(retType, &retBuf[0]); |
| uno_destructData(&retBuf[0], retType.get(), 0); |
| } |
| if (!outArguments->empty()) { |
| OSL_ASSERT( |
| member_.get()->eTypeClass == |
| typelib_TypeClass_INTERFACE_METHOD); |
| typelib_InterfaceMethodTypeDescription * mtd = |
| reinterpret_cast< |
| typelib_InterfaceMethodTypeDescription * >( |
| member_.get()); |
| std::vector< BinaryAny >::iterator i(outArguments->begin()); |
| std::list< std::vector< char > >::iterator j( |
| outBufs.begin()); |
| for (sal_Int32 k = 0; k != mtd->nParams; ++k) { |
| if (mtd->pParams[k].bOut) { |
| *i++ = BinaryAny( |
| css::uno::TypeDescription( |
| mtd->pParams[k].pTypeRef), |
| args[k]); |
| } |
| if (!mtd->pParams[k].bIn) { |
| uno_type_destructData( |
| &(*j++)[0], mtd->pParams[k].pTypeRef, 0); |
| } |
| } |
| OSL_ASSERT(i == outArguments->end()); |
| OSL_ASSERT(j == outBufs.end()); |
| } |
| } |
| break; |
| } |
| } |
| return !isExc; |
| } |
| |
| } |