Bump version to 5.0-14
[LibreOffice.git] / cpputools / source / unoexe / unoexe.cxx
blobb292deb6e35e27dab0a9d3d182b629fab7b82014
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 <stdio.h>
22 #include "sal/main.h"
23 #include <osl/diagnose.h>
24 #include <osl/mutex.hxx>
25 #include <osl/conditn.hxx>
27 #include <rtl/process.h>
28 #include <rtl/string.h>
29 #include <rtl/strbuf.hxx>
30 #include <rtl/ustrbuf.hxx>
32 #include <cppuhelper/bootstrap.hxx>
33 #include <cppuhelper/implbase1.hxx>
35 #include <com/sun/star/lang/XMain.hpp>
36 #include <com/sun/star/lang/XInitialization.hpp>
37 #include <com/sun/star/lang/XComponent.hpp>
38 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
39 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
40 #include <com/sun/star/lang/XEventListener.hpp>
41 #include <com/sun/star/loader/XImplementationLoader.hpp>
42 #include <com/sun/star/registry/XRegistryKey.hpp>
43 #include <com/sun/star/connection/Acceptor.hpp>
44 #include <com/sun/star/connection/XConnection.hpp>
45 #include <com/sun/star/bridge/XBridgeFactory.hpp>
46 #include <com/sun/star/bridge/XBridge.hpp>
48 using namespace std;
49 using namespace osl;
50 using namespace cppu;
51 using namespace com::sun::star::uno;
52 using namespace com::sun::star::lang;
53 using namespace com::sun::star::loader;
54 using namespace com::sun::star::registry;
55 using namespace com::sun::star::connection;
56 using namespace com::sun::star::bridge;
57 using namespace com::sun::star::container;
59 namespace unoexe
62 static bool s_quiet = false;
64 static inline void out( const sal_Char * pText )
66 if (! s_quiet)
67 fprintf( stderr, "%s", pText );
70 static inline void out( const OUString & rText )
72 if (! s_quiet)
74 OString aText( OUStringToOString( rText, RTL_TEXTENCODING_ASCII_US ) );
75 fprintf( stderr, "%s", aText.getStr() );
79 static const char arUsingText[] =
80 "\nusing:\n\n"
81 "uno [-c ComponentImplementationName -l LocationUrl | -s ServiceName]\n"
82 " [-u uno:(socket[,host=HostName][,port=nnn]|pipe[,name=PipeName]);<protocol>;Name\n"
83 " [--singleaccept] [--singleinstance]]\n"
84 " [--quiet]\n"
85 " [-- Argument1 Argument2 ...]\n";
87 static bool readOption( OUString * pValue, const sal_Char * pOpt,
88 sal_uInt32 * pnIndex, const OUString & aArg)
89 throw (RuntimeException)
91 const OUString dash("-");
92 if(!aArg.startsWith(dash))
93 return false;
95 OUString aOpt = OUString::createFromAscii( pOpt );
97 if (aArg.getLength() < aOpt.getLength())
98 return false;
100 if (aOpt.equalsIgnoreAsciiCase( aArg.copy(1) ))
102 // take next argument
103 ++(*pnIndex);
105 rtl_getAppCommandArg(*pnIndex, &pValue->pData);
106 if (*pnIndex >= rtl_getAppCommandArgCount() || pValue->copy(1).equals(dash))
108 throw RuntimeException( "incomplete option \"-" + aOpt + "\" given!" );
110 else
112 #if OSL_DEBUG_LEVEL > 1
113 out( "\n> identified option -" );
114 out( pOpt );
115 out( " = " );
116 OString tmp = OUStringToOString(aArg, RTL_TEXTENCODING_ASCII_US);
117 out( tmp.getStr() );
118 #endif
119 ++(*pnIndex);
120 return true;
123 else if (aArg.indexOf(aOpt) == 1)
125 *pValue = aArg.copy(1 + aOpt.getLength());
126 #if OSL_DEBUG_LEVEL > 1
127 out( "\n> identified option -" );
128 out( pOpt );
129 out( " = " );
130 OString tmp = OUStringToOString(aArg.copy(aOpt.getLength()), RTL_TEXTENCODING_ASCII_US);
131 out( tmp.getStr() );
132 #endif
133 ++(*pnIndex);
135 return true;
137 return false;
140 static bool readOption( bool * pbOpt, const sal_Char * pOpt,
141 sal_uInt32 * pnIndex, const OUString & aArg)
143 const OUString dashdash("--");
144 OUString aOpt = OUString::createFromAscii(pOpt);
146 if(aArg.startsWith(dashdash) && aOpt.equals(aArg.copy(2)))
148 ++(*pnIndex);
149 *pbOpt = true;
150 #if OSL_DEBUG_LEVEL > 1
151 out( "\n> identified option --" );
152 out( pOpt );
153 #endif
154 return true;
156 return false;
159 template< class T >
160 void createInstance(
161 Reference< T > & rxOut,
162 const Reference< XComponentContext > & xContext,
163 const OUString & rServiceName )
164 throw (Exception)
166 Reference< XMultiComponentFactory > xMgr( xContext->getServiceManager() );
167 Reference< XInterface > x( xMgr->createInstanceWithContext( rServiceName, xContext ) );
169 if (! x.is())
171 throw RuntimeException( "cannot get service instance \"" + rServiceName + "\"!" );
174 rxOut = Reference< T >::query( x );
175 if (! rxOut.is())
177 const Type & rType = cppu::UnoType<T>::get();
178 throw RuntimeException(
179 "service instance \"" + rServiceName +
180 "\" does not support demanded interface \"" +
181 rType.getTypeName() + "\"!" );
185 static Reference< XInterface > loadComponent(
186 const Reference< XComponentContext > & xContext,
187 const OUString & rImplName, const OUString & rLocation )
188 throw (Exception)
190 // determine loader to be used
191 sal_Int32 nDot = rLocation.lastIndexOf( '.' );
192 if (nDot > 0 && nDot < rLocation.getLength())
194 Reference< XImplementationLoader > xLoader;
196 OUString aExt( rLocation.copy( nDot +1 ) );
198 if (aExt == "dll" || aExt == "exe" || aExt == "dylib" || aExt == "so")
200 createInstance(
201 xLoader, xContext, OUString("com.sun.star.loader.SharedLibrary") );
203 else if (aExt == "jar" || aExt == "class")
205 createInstance(
206 xLoader, xContext, OUString("com.sun.star.loader.Java") );
208 else
210 throw RuntimeException(
211 "unknown extension of \"" + rLocation + "\"! No loader available!" );
214 Reference< XInterface > xInstance;
216 // activate
217 Reference< XInterface > xFactory( xLoader->activate(
218 rImplName, OUString(), rLocation, Reference< XRegistryKey >() ) );
219 if (xFactory.is())
221 Reference< XSingleComponentFactory > xCFac( xFactory, UNO_QUERY );
222 if (xCFac.is())
224 xInstance = xCFac->createInstanceWithContext( xContext );
226 else
228 Reference< XSingleServiceFactory > xSFac( xFactory, UNO_QUERY );
229 if (xSFac.is())
231 out( "\n> warning: ignroing context for implementation \"" );
232 out( rImplName );
233 out( "\"!" );
234 xInstance = xSFac->createInstance();
239 if (! xInstance.is())
241 throw RuntimeException(
242 "activating component \"" + rImplName + "\" from location \"" + rLocation + "\" failed!" );
245 return xInstance;
247 else
249 throw RuntimeException(
250 "location \"" + rLocation + "\" has no extension! Cannot determine loader to be used!" );
254 class OInstanceProvider
255 : public WeakImplHelper1< XInstanceProvider >
257 Reference< XComponentContext > _xContext;
259 Mutex _aSingleInstanceMutex;
260 Reference< XInterface > _xSingleInstance;
261 bool _bSingleInstance;
263 OUString _aImplName;
264 OUString _aLocation;
265 OUString _aServiceName;
266 Sequence< Any > _aInitParams;
268 OUString _aInstanceName;
270 inline Reference< XInterface > createInstance() throw (Exception);
272 public:
273 OInstanceProvider( const Reference< XComponentContext > & xContext,
274 const OUString & rImplName, const OUString & rLocation,
275 const OUString & rServiceName, const Sequence< Any > & rInitParams,
276 bool bSingleInstance, const OUString & rInstanceName )
277 : _xContext( xContext )
278 , _bSingleInstance( bSingleInstance )
279 , _aImplName( rImplName )
280 , _aLocation( rLocation )
281 , _aServiceName( rServiceName )
282 , _aInitParams( rInitParams )
283 , _aInstanceName( rInstanceName )
286 // XInstanceProvider
287 virtual Reference< XInterface > SAL_CALL getInstance( const OUString & rName )
288 throw (NoSuchElementException, RuntimeException, std::exception) SAL_OVERRIDE;
291 inline Reference< XInterface > OInstanceProvider::createInstance()
292 throw (Exception)
294 Reference< XInterface > xRet;
295 if (!_aImplName.isEmpty()) // manually via loader
296 xRet = loadComponent( _xContext, _aImplName, _aLocation );
297 else // via service manager
298 unoexe::createInstance( xRet, _xContext, _aServiceName );
300 // opt XInit
301 Reference< XInitialization > xInit( xRet, UNO_QUERY );
302 if (xInit.is())
303 xInit->initialize( _aInitParams );
305 return xRet;
308 Reference< XInterface > OInstanceProvider::getInstance( const OUString & rName )
309 throw (NoSuchElementException, RuntimeException, std::exception)
313 if (_aInstanceName == rName)
315 Reference< XInterface > xRet;
317 if (_aImplName.isEmpty() && _aServiceName.isEmpty())
319 OSL_ASSERT( rName == "uno.ComponentContext" );
320 xRet = _xContext;
322 else if (_bSingleInstance)
324 if (! _xSingleInstance.is())
326 MutexGuard aGuard( _aSingleInstanceMutex );
327 if (! _xSingleInstance.is())
329 _xSingleInstance = createInstance();
332 xRet = _xSingleInstance;
334 else
336 xRet = createInstance();
339 return xRet;
342 catch (Exception & rExc)
344 out( "\n> error: " );
345 out( rExc.Message );
347 throw NoSuchElementException(
348 "no such element \"" + rName + "\"!" );
351 struct ODisposingListener : public WeakImplHelper1< XEventListener >
353 Condition cDisposed;
355 // XEventListener
356 virtual void SAL_CALL disposing( const EventObject & rEvt )
357 throw (RuntimeException, std::exception) SAL_OVERRIDE;
359 static void waitFor( const Reference< XComponent > & xComp );
362 void ODisposingListener::disposing( const EventObject & )
363 throw (RuntimeException, std::exception)
365 cDisposed.set();
368 void ODisposingListener::waitFor( const Reference< XComponent > & xComp )
370 ODisposingListener * pListener = new ODisposingListener();
371 Reference< XEventListener > xListener( pListener );
373 xComp->addEventListener( xListener );
374 pListener->cDisposed.wait();
377 } // namespace unoexe
379 using namespace unoexe;
381 SAL_IMPLEMENT_MAIN()
383 sal_uInt32 nCount = rtl_getAppCommandArgCount();
384 if (nCount == 0)
386 out( arUsingText );
387 return 0;
390 sal_Int32 nRet = 0;
391 Reference< XComponentContext > xContext;
396 OUString aImplName, aLocation, aServiceName, aUnoUrl;
397 Sequence< OUString > aParams;
398 bool bSingleAccept = false;
399 bool bSingleInstance = false;
401 // read command line arguments
403 sal_uInt32 nPos = 0;
404 // read up to arguments
405 while (nPos < nCount)
407 OUString arg;
409 rtl_getAppCommandArg(nPos, &arg.pData);
411 const OUString dashdash("--");
412 if (dashdash == arg)
414 ++nPos;
415 break;
418 if (!(readOption( &aImplName, "c", &nPos, arg) ||
419 readOption( &aLocation, "l", &nPos, arg) ||
420 readOption( &aServiceName, "s", &nPos, arg) ||
421 readOption( &aUnoUrl, "u", &nPos, arg) ||
422 readOption( &s_quiet, "quiet", &nPos, arg) ||
423 readOption( &bSingleAccept, "singleaccept", &nPos, arg) ||
424 readOption( &bSingleInstance, "singleinstance", &nPos, arg)))
426 throw RuntimeException(
427 "unexpected argument \"" + arg + "\"" );
431 if (!(aImplName.isEmpty() || aServiceName.isEmpty()))
432 throw RuntimeException("give component exOR service name!" );
433 if (aImplName.isEmpty() && aServiceName.isEmpty())
435 if (! aUnoUrl.endsWithIgnoreAsciiCase( ";uno.ComponentContext" ))
436 throw RuntimeException(
437 "expected UNO-URL with instance name uno.ComponentContext!" );
438 if (bSingleInstance)
439 throw RuntimeException(
440 "unexpected option --singleinstance!" );
442 if (!aImplName.isEmpty() && aLocation.isEmpty())
443 throw RuntimeException("give component location!" );
444 if (!aServiceName.isEmpty() && !aLocation.isEmpty())
445 out( "\n> warning: service name given, will ignore location!" );
447 // read component params
448 aParams.realloc( nCount - nPos );
449 OUString * pParams = aParams.getArray();
451 sal_uInt32 nOffset = nPos;
452 for ( ; nPos < nCount; ++nPos )
454 rtl_getAppCommandArg( nPos, &pParams[nPos -nOffset].pData );
457 xContext = defaultBootstrap_InitialComponentContext();
459 // accept, instanciate, etc.
461 if (!aUnoUrl.isEmpty()) // accepting connections
463 sal_Int32 nIndex = 0, nTokens = 0;
464 do { aUnoUrl.getToken( 0, ';', nIndex ); nTokens++; } while( nIndex != -1 );
465 if (nTokens != 3 || aUnoUrl.getLength() < 10 ||
466 !aUnoUrl.copy( 0, 4 ).equalsIgnoreAsciiCase( "uno:" ))
468 throw RuntimeException("illegal uno url given!" );
470 nIndex = 0;
471 OUString aConnectDescr( aUnoUrl.getToken( 0, ';', nIndex ).copy( 4 ) ); // uno:CONNECTDESCR;iiop;InstanceName
472 OUString aInstanceName( aUnoUrl.getToken( 1, ';', nIndex ) );
474 Reference< XAcceptor > xAcceptor = Acceptor::create(xContext);
476 // init params
477 Sequence< Any > aInitParams( aParams.getLength() );
478 const OUString * p = aParams.getConstArray();
479 Any * pInitParams = aInitParams.getArray();
480 for ( sal_Int32 i = aParams.getLength(); i--; )
482 pInitParams[i] = makeAny( p[i] );
485 // instance provider
486 Reference< XInstanceProvider > xInstanceProvider( new OInstanceProvider(
487 xContext, aImplName, aLocation, aServiceName, aInitParams,
488 bSingleInstance, aInstanceName ) );
490 nIndex = 0;
491 OUString aUnoUrlToken( aUnoUrl.getToken( 1, ';', nIndex ) );
492 // coverity[loop_top] - not really an infinite loop, we can be instructed to exit via the connection
493 for (;;)
495 // accepting
496 out( "\n> accepting " );
497 out( aConnectDescr );
498 out( "..." );
499 Reference< XConnection > xConnection( xAcceptor->accept( aConnectDescr ) );
500 out( "connection established." );
502 Reference< XBridgeFactory > xBridgeFactory;
503 createInstance(
504 xBridgeFactory, xContext,
505 OUString("com.sun.star.bridge.BridgeFactory") );
507 // bridge
508 Reference< XBridge > xBridge( xBridgeFactory->createBridge(
509 OUString(), aUnoUrlToken,
510 xConnection, xInstanceProvider ) );
512 if (bSingleAccept)
514 Reference< XComponent > xComp( xBridge, UNO_QUERY );
515 if (! xComp.is())
516 throw RuntimeException( "bridge factory does not export interface \"com.sun.star.lang.XComponent\"!" );
517 ODisposingListener::waitFor( xComp );
518 xComp->dispose();
519 // explicitly dispose the remote bridge so that it joins
520 // on all spawned threads before process exit (see
521 // binaryurp/source/bridge.cxx for details)
522 break;
526 else // no uno url
528 Reference< XInterface > xInstance;
529 if (!aImplName.isEmpty()) // manually via loader
530 xInstance = loadComponent( xContext, aImplName, aLocation );
531 else // via service manager
532 createInstance( xInstance, xContext, aServiceName );
534 // execution
535 Reference< XMain > xMain( xInstance, UNO_QUERY );
536 if (xMain.is())
538 nRet = xMain->run( aParams );
540 else
542 Reference< XComponent > xComp( xInstance, UNO_QUERY );
543 if (xComp.is())
544 xComp->dispose();
545 throw RuntimeException( "component does not export interface interface \"com.sun.star.lang.XMain\"!" );
549 catch (Exception & rExc)
551 out( "\n> error: " );
552 out( rExc.Message );
553 out( "\n> dying..." );
554 nRet = 1;
557 // cleanup
558 Reference< XComponent > xComp( xContext, UNO_QUERY );
559 if (xComp.is())
560 xComp->dispose();
562 #if OSL_DEBUG_LEVEL > 1
563 out( "\n" );
564 #endif
565 return nRet;
568 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */