Author: arielch Date: Tue Feb 26 12:43:34 2013 New Revision: 1450154 URL: http://svn.apache.org/r1450154 Log: Add example for connection aware client in C++
Added: openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/ openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/ openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/Makefile (with props) openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/main.cxx Added: openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/Makefile URL: http://svn.apache.org/viewvc/openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/Makefile?rev=1450154&view=auto ============================================================================== --- openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/Makefile (added) +++ openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/Makefile Tue Feb 26 12:43:34 2013 @@ -0,0 +1,125 @@ +#************************************************************** +# +# 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. +# +#************************************************************** + +# On *nix can be overridden with +# make PRJ=$OO_SDK_HOME +PRJ=../../../../.. +SETTINGS=$(PRJ)/settings + +include $(SETTINGS)/settings.mk +include $(SETTINGS)/std.mk +include $(SETTINGS)/dk.mk + +# Define non-platform/compiler specific settings +APP_NAME=ConnectionAwareClient +MAINTARGET=$(APP_NAME)_Example + +#this should be in odk/settings/std.mk +OUT_DEPLOY=$(OUT)/deploy + +OUT_APP_INC=$(OUT_INC)/$(APP_NAME) +OUT_APP_GEN=$(OUT_MISC)/$(APP_NAME) +OUT_APP_OBJ=$(OUT_OBJ)/$(APP_NAME) +OUT_APP_LIB=$(SHAREDLIB_OUT)/$(APP_NAME) +OUT_APP_BIN=$(OUT_BIN)/$(APP_NAME) +OUT_APP_DEPLOY=$(OUT_DEPLOY)/$(APP_NAME) + + +CONNECTION_URL=socket,host=localhost,port=2083;urp; +# Allow deploying the extension when running it +ENV_USER_INSTALL=-env:"UserInstallation=$(URLPREFIX)$(OUT_APP_DEPLOY)" +ENV_OFFICE_TYPES=-env:URE_MORE_TYPES=$(URLPREFIX)$(OFFICE_TYPES) +OFFICE_START_OPTIONS=-nologo -nofirststartwizard -norestore -quickstart=no +OXT_DEPLOYEDFLAG=$(OUT_COMP_GEN)/so_deployed_$(COMP_NAME).flag + + +CXXFILES = main.cxx + +OBJFILES = $(patsubst %.cxx,$(OUT_APP_OBJ)/%.$(OBJ_EXT),$(CXXFILES)) +# remove in 4.0 +ifneq "$(DEBUG)" "" + CC_DEFINES+=-DOSL_DEBUG_LEVEL=3 +endif + +# Targets +.PHONY: ALL StartAOOListening +ALL : \ + $(MAINTARGET) + +include $(SETTINGS)/stdtarget.mk + + +$(OUT_APP_OBJ)/%.$(OBJ_EXT) : %.cxx $(SDKTYPEFLAG) + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(CC) $(CC_FLAGS) $(STL_INCLUDES) $(CC_INCLUDES) -I$(OUT_APP_INC) $(CC_DEFINES) $(CC_OUTPUT_SWITCH)$(subst /,$(PS),$@) $< + +$(OUT_APP_BIN)/_$(APP_NAME)$(EXE_EXT) : $(OBJFILES) + -$(MKDIR) $(subst /,$(PS),$(@D)) + -$(MKDIR) $(subst /,$(PS),$(OUT_APP_GEN)) +ifeq "$(OS)" "WIN" + $(LINK) $(EXE_LINK_FLAGS) /OUT:$@ /MAP:$(OUT_APP_GEN)/$(basename $(@F)).map \ + $(OBJFILES) $(CPPUHELPERLIB) $(CPPULIB) $(SALHELPERLIB) $(SALLIB) $(STLPORTLIB) +else + $(LINK) $(EXE_LINK_FLAGS) $(LINK_LIBS) -o $@ $(OBJFILES) \ + $(CPPUHELPERLIB) $(CPPULIB) $(SALHELPERLIB) $(SALLIB) $(STLPORTLIB) $(STDC++LIB) $(CPPUHELPERDYLIB) $(CPPUDYLIB) $(SALHELPERDYLIB) $(SALDYLIB) +ifeq "$(OS)" "MACOSX" + $(INSTALL_NAME_URELIBS_BIN) $@ +endif +endif + +$(OUT_APP_BIN)/$(APP_NAME)$(EXE_EXT) : $(OUT_APP_BIN)/_$(APP_NAME)$(EXE_EXT) + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(COPY) $(subst /,$(PS),$(BIN_DIR)/unoapploader$(EXE_EXT)) $(subst /,$(PS),$@) +# workaround for touch problem under Windows with full qualified paths + make -t $@ + +$(OUT_APP_BIN)/$(TEST_DOC) : $(TEST_DOC) + -$(MKDIR) $(subst /,$(PS),$(@D)) + $(COPY) $(subst /,$(PS),$<) $(subst /,$(PS),$@) + + +$(MAINTARGET) : $(OUT_APP_BIN)/$(APP_NAME)$(EXE_EXT) + @echo -------------------------------------------------------------------------------- + @echo Please use the following command to execute the example! + @echo - + @echo $(MAKE) $(APP_NAME).run + @echo -------------------------------------------------------------------------------- + +StartAOOListening: + -$(MKDIR) $(subst /,$(PS),$(OUT_APP_DEPLOY)) + "$(OFFICE_PROGRAM_PATH)$(PS)soffice" \ + $(OFFICE_START_OPTIONS) \ + $(ENV_USER_INSTALL) \ + -accept="$(CONNECTION_URL)" & + +$(APP_NAME).run: $(OUT_APP_BIN)/$(APP_NAME)$(EXE_EXT) StartAOOListening + cd $(subst /,$(PS),$(OUT_APP_BIN)) && $(basename $@) \ + $(ENV_OFFICE_TYPES) \ + "uno:$(CONNECTION_URL)StarOffice.ComponentContext" + +.PHONY: clean +clean : + -$(DELRECURSIVE) $(subst /,$(PS),$(OUT_APP_INC)) + -$(DELRECURSIVE) $(subst /,$(PS),$(OUT_APP_GEN)) + -$(DELRECURSIVE) $(subst /,$(PS),$(OUT_APP_OBJ)) + -$(DELRECURSIVE) $(subst /,$(PS),$(OUT_APP_LIB)) + -$(DELRECURSIVE) $(subst /,$(PS),$(OUT_APP_BIN)) + -$(DELRECURSIVE) $(subst /,$(PS),$(OUT_APP_DEPLOY)) Propchange: openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/Makefile ------------------------------------------------------------------------------ svn:eol-style = native Added: openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/main.cxx URL: http://svn.apache.org/viewvc/openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/main.cxx?rev=1450154&view=auto ============================================================================== --- openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/main.cxx (added) +++ openoffice/devtools/sdk-examples/trunk/cpp/cppbindings/ConnectionAwareClient/src/main.cxx Tue Feb 26 12:43:34 2013 @@ -0,0 +1,391 @@ +/************************************************************** + * + * 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 <algorithm> +#include <cstdlib> +#include <functional> +#include <iostream> +#include <vector> + +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/bootstrap.hxx> +#include <cppuhelper/implbase1.hxx> +#include <osl/process.h> +#include <rtl/instance.hxx> +#include <rtl/ref.hxx> +#include <sal/main.h> + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/bridge/XBridgeFactory.hpp> +#include <com/sun/star/connection/XConnector.hpp> +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/frame/XDesktop.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <com/sun/star/util/XModifiable.hpp> + +#define C2U( constAsciiStr ) \ + ( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( constAsciiStr ) ) ) + +namespace css = ::com::sun::star; +using namespace osl; + +namespace connection_aware_client +{ + static std::ostream & + operator<<( std::ostream &stream, const rtl::OUString &rStr ) + { + return stream << rtl::OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ).getStr(); + } + + static std::ostream & + operator<<( std::ostream &stream, const css::uno::Exception &e ) + { + return stream << e.Message; + } + + struct UnoConnUrl + { + rtl::OUString Connection; + rtl::OUString Object; + }; + + static bool lcl_ParseUnoUrl( const rtl::OUString &sUrl, UnoConnUrl &url ) + { + // must start with "uno:" + if ( sUrl.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "uno:" ) != 0 ) ) + return false; + + sal_Int32 nIndex = sizeof( "uno:" ) - 1; + + url.Connection = sUrl.getToken( 0, sal_Unicode( ';' ), nIndex ); + // there should be an initial object + if ( nIndex == -1 ) + return false; + + // protocol must be "urp" + rtl::OUString sProtocol = sUrl.getToken( 0, sal_Unicode( ';' ), nIndex ); + if ( nIndex == -1 || !sProtocol.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "urp" ) ) ) + return false; + + url.Object = sUrl.getToken( 0, sal_Unicode( ';' ), nIndex ); + + return url.Object.getLength() > 0 /* && nIndex == -1 */; + } + + typedef ::cppu::WeakImplHelper1< css::lang::XEventListener > RemoteConnection_Base; + + class RemoteConnection + : protected ::cppu::BaseMutex, public RemoteConnection_Base + { + private: + css::uno::Reference< css::uno::XComponentContext > m_xLocalContext; + css::uno::Reference< css::lang::XComponent > m_xBridge; + css::uno::Reference< css::uno::XInterface > m_xRemoteObject; + UnoConnUrl m_aUnoURL; + public: + RemoteConnection( + const css::uno::Reference< css::uno::XComponentContext > &xLocalContext, + const UnoConnUrl &url ); + ~RemoteConnection(); + + void close(); + + void SAL_CALL disposing( const css::lang::EventObject &aEvent ) + throw ( css::uno::RuntimeException ); + + css::uno::Reference< css::uno::XInterface > getRemoteObject(); + }; +} + +using namespace connection_aware_client; + +RemoteConnection::RemoteConnection( + const css::uno::Reference< css::uno::XComponentContext > &xLocalContext, + const UnoConnUrl &url ) + : RemoteConnection_Base() + , m_xLocalContext( xLocalContext ) + , m_xBridge() + , m_xRemoteObject() + , m_aUnoURL( url ) +{ + OSL_TRACE( "RemoteConnection::RemoteConnection" ); +} + +RemoteConnection::~RemoteConnection() +{ + OSL_TRACE( "RemoteConnection::~RemoteConnection" ); +} + +void RemoteConnection::close() +{ + OSL_TRACE( "RemoteConnection::close" ); + osl::MutexGuard aGuard( m_aMutex ); + if ( m_xBridge.is() ) + { + m_xBridge->removeEventListener( this ); + m_xBridge.clear(); + m_xRemoteObject.clear(); + } +} + +void SAL_CALL +RemoteConnection::disposing( const css::lang::EventObject &aEvent ) +throw ( css::uno::RuntimeException ) +{ + OSL_TRACE( "RemoteConnection::disposing" ); + + osl::MutexGuard aGuard( m_aMutex ); + OSL_ENSURE( aEvent.Source == m_xBridge, "Different source object!" ); + + m_xBridge.clear(); + m_xRemoteObject.clear(); +} + +css::uno::Reference< css::uno::XInterface > +RemoteConnection::getRemoteObject() +{ + OSL_TRACE( "RemoteConnection::getRemoteObject" ); + + osl::ResettableMutexGuard aGuard( m_aMutex ); + css::uno::Reference< css::uno::XInterface > xRemoteObject = m_xRemoteObject; + css::uno::Reference< css::bridge::XBridge > xBridge( m_xBridge, css::uno::UNO_QUERY ); + css::uno::Reference< css::uno::XComponentContext > xContext = m_xLocalContext; + aGuard.clear(); + + if ( xRemoteObject.is() || !xContext.is() ) + return xRemoteObject; + + if ( !xBridge.is() ) + { + try + { + css::uno::Reference< css::connection::XConnector > xConnector( + xContext->getServiceManager()->createInstanceWithContext( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.connection.Connector" ) ), + xContext ), css::uno::UNO_QUERY ); + + css::uno::Reference< css::connection::XConnection > xConnection( + xConnector->connect( m_aUnoURL.Connection ) ); + + css::uno::Reference< css::bridge::XBridgeFactory > xBridgeFactory( + xContext->getServiceManager()->createInstanceWithContext( + rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( + "com.sun.star.bridge.BridgeFactory" ) ), + xContext ), css::uno::UNO_QUERY ); + + xBridge.set( + xBridgeFactory->createBridge( + rtl::OUString(), + C2U( "urp" ), + xConnection, + css::uno::Reference< css::bridge::XInstanceProvider>() ) ); + + css::uno::Reference< css::lang::XComponent > xBridgeComp( + xBridge, css::uno::UNO_QUERY_THROW ); + xBridgeComp->addEventListener( this ); + + aGuard.reset(); + m_xBridge = xBridgeComp; + aGuard.clear(); + } + catch ( const css::uno::Exception &e ) + { + std::cerr << "getRemoteObject() caugth an exception: " << e << '\n'; + } + } + + if ( xBridge.is() ) + { + try + { + xRemoteObject.set( + xBridge->getInstance( + m_aUnoURL.Object ), + css::uno::UNO_QUERY_THROW ); + } + catch ( const css::uno::Exception &e ) + { + std::cerr << "getRemoteObject() caugth an exception: " << e << '\n'; + } + + aGuard.reset(); + m_xRemoteObject = xRemoteObject; + aGuard.clear(); + } + + return xRemoteObject; +} + + +static css::uno::Reference< css::uno::XInterface > +testRemoteContext( + const css::uno::Reference< css::uno::XComponentContext > &xContext ) +{ + try + { + css::uno::Reference< css::frame::XComponentLoader > xLoader( + xContext->getServiceManager()->createInstanceWithContext( + C2U( "com.sun.star.frame.Desktop" ), xContext ), + css::uno::UNO_QUERY_THROW ); + + css::uno::Reference< css::text::XTextDocument > xDoc( + xLoader->loadComponentFromURL( + C2U( "private:factory/swriter" ), + C2U( "_default" ), + css::frame::FrameSearchFlag::ALL, + css::uno::Sequence< css::beans::PropertyValue >() ), + css::uno::UNO_QUERY_THROW ); + + css::uno::Reference< css::text::XText > xText( xDoc->getText() ); + xText->setString( C2U( "Hello world!" ) ); + + // change the modified flag to close the document without interaction + css::uno::Reference< css::util::XModifiable > xModified( + xDoc, css::uno::UNO_QUERY_THROW ); + xModified->setModified( sal_False ); + + return xLoader; + } + catch ( const css::uno::Exception &e ) + { + std::cerr << "getRemoteObject() caugth an exception: " << e << '\n'; + } + + return 0; +} + + +SAL_IMPLEMENT_MAIN_WITH_ARGS( argc, argv ) +{ + oslProcessError eError; + sal_Int32 n = osl_getCommandArgCount( ); + if ( n != 2 ) + { + rtl::OUString sProgFile; + sal_Int32 nLen; + eError = osl_getExecutableFile( &sProgFile.pData ); + + if ( eError == osl_Process_E_None && ( nLen = sProgFile.getLength( ) ) ) + n = sProgFile.lastIndexOf( sal_Unicode( '/' ) ); + + if ( n != -1 && n < nLen ) + sProgFile = sProgFile.copy( ++n ); + + std::cerr << "Usage:\n\t" << sProgFile << "-env:URE_MORE_TYPES=<path to offapi.rdb> <UNO url>\n"; + + return EXIT_FAILURE; + } + + // In this example, the second argument should contain a UNO connection URL + // to connect to the remote server running in the UNO executable launched + // in server mode. + UnoConnUrl aUrl; + rtl::OUString sUrl; + eError = osl_getCommandArg( 1, &sUrl.pData ); + + if ( eError != osl_Process_E_None || + !sUrl.getLength() || + !lcl_ParseUnoUrl( sUrl, aUrl ) ) + { + std::cerr << "You must specify a valid UNO connection URL\n"; + return EXIT_FAILURE; + } + + std::cout << "Make sure OpenOffice is running and listening for connections!\n"; + std::cout << "Press ENTER to start the test..."; + std::cin.get(); + + // get the local component context + css::uno::Reference< css::uno::XComponentContext > xLocalContext; + try + { + xLocalContext.set( + cppu::defaultBootstrap_InitialComponentContext() ); + } + catch ( const css::uno::Exception &e ) + { + std::cerr << "Exception bootstrapping URE! " << e << '\n'; + return EXIT_FAILURE; + } + + // Hold a reference to the connection so that it lives during this function + rtl::Reference< RemoteConnection > aConnection( + new RemoteConnection( xLocalContext, aUrl ) ); + + // get the object exported by the remote server + css::uno::Reference< css::uno::XComponentContext > xRemoteContext( + aConnection->getRemoteObject(), css::uno::UNO_QUERY ); + + if ( !xRemoteContext.is() ) + { + std::cerr << "Cannot get remote component context!\n"; + } + else + { + css::uno::Reference< css::frame::XDesktop > xDesktop( + testRemoteContext( xRemoteContext ), + css::uno::UNO_QUERY_THROW ); + + if ( xDesktop.is() ) + { + std::cout << "Press ENTER to terminate the Desktop..."; + std::cin.get(); + bool bTerminate = true; + try + { + xDesktop->terminate(); + } + catch ( const css::uno::Exception &e ) + { + std::cerr << "Cannot terminate the Desktop!\n"; + bTerminate = false; + } + + if ( bTerminate ) + { + // wait a little until it terminates + std::cout << "The office is terminating...\nPress ENTER to test the bridge..."; + std::cin.get(); + + // retreiving the remote context should fail now: + // the bridge gets disposed, we try to reconnect, + // but there is no office instance listening + xRemoteContext.set( aConnection->getRemoteObject(), css::uno::UNO_QUERY ); + if ( xRemoteContext.is() ) + std::cerr << "Got a remote context with a ternimated office!\n"; + } + } + } + + std::cout << "Press ENTER to finish the example..."; + std::cin.get(); + + aConnection->close(); + aConnection.clear(); + + return EXIT_SUCCESS; +} +