update credits
[LibreOffice.git] / cpputools / source / unoexe / unoexe.cxx
blob073a9751522cd638d068dc0c76a5b9452bd72d03
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/shlib.hxx>
34 #include <cppuhelper/implbase1.hxx>
36 #include <com/sun/star/lang/XMain.hpp>
37 #include <com/sun/star/lang/XInitialization.hpp>
38 #include <com/sun/star/lang/XComponent.hpp>
39 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
40 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
41 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
42 #include <com/sun/star/lang/XEventListener.hpp>
43 #include <com/sun/star/container/XSet.hpp>
44 #include <com/sun/star/loader/XImplementationLoader.hpp>
45 #include <com/sun/star/registry/XRegistryKey.hpp>
46 #include <com/sun/star/connection/XAcceptor.hpp>
47 #include <com/sun/star/connection/XConnection.hpp>
48 #include <com/sun/star/bridge/XBridgeFactory.hpp>
49 #include <com/sun/star/bridge/XBridge.hpp>
51 using namespace std;
52 using namespace osl;
53 using namespace cppu;
54 using namespace com::sun::star::uno;
55 using namespace com::sun::star::lang;
56 using namespace com::sun::star::loader;
57 using namespace com::sun::star::registry;
58 using namespace com::sun::star::connection;
59 using namespace com::sun::star::bridge;
60 using namespace com::sun::star::container;
62 namespace unoexe
65 static sal_Bool s_quiet = false;
67 static inline void out( const sal_Char * pText )
69 if (! s_quiet)
70 fprintf( stderr, "%s", pText );
73 static inline void out( const OUString & rText )
75 if (! s_quiet)
77 OString aText( OUStringToOString( rText, RTL_TEXTENCODING_ASCII_US ) );
78 fprintf( stderr, "%s", aText.getStr() );
82 static const char arUsingText[] =
83 "\nusing:\n\n"
84 "uno [-c ComponentImplementationName -l LocationUrl | -s ServiceName]\n"
85 " [-u uno:(socket[,host=HostName][,port=nnn]|pipe[,name=PipeName]);<protocol>;Name\n"
86 " [--singleaccept] [--singleinstance]]\n"
87 " [--quiet]\n"
88 " [-- Argument1 Argument2 ...]\n";
90 static sal_Bool readOption( OUString * pValue, const sal_Char * pOpt,
91 sal_uInt32 * pnIndex, const OUString & aArg)
92 throw (RuntimeException)
94 const OUString dash("-");
95 if(aArg.indexOf(dash) != 0)
96 return sal_False;
98 OUString aOpt = OUString::createFromAscii( pOpt );
100 if (aArg.getLength() < aOpt.getLength())
101 return sal_False;
103 if (aOpt.equalsIgnoreAsciiCase( aArg.copy(1) ))
105 // take next argument
106 ++(*pnIndex);
108 rtl_getAppCommandArg(*pnIndex, &pValue->pData);
109 if (*pnIndex >= rtl_getAppCommandArgCount() || pValue->copy(1).equals(dash))
111 OUStringBuffer buf( 32 );
112 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("incomplete option \"-") );
113 buf.appendAscii( pOpt );
114 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" given!") );
115 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
117 else
119 #if OSL_DEBUG_LEVEL > 1
120 out( "\n> identified option -" );
121 out( pOpt );
122 out( " = " );
123 OString tmp = OUStringToOString(aArg, RTL_TEXTENCODING_ASCII_US);
124 out( tmp.getStr() );
125 #endif
126 ++(*pnIndex);
127 return sal_True;
130 else if (aArg.indexOf(aOpt) == 1)
132 *pValue = aArg.copy(1 + aOpt.getLength());
133 #if OSL_DEBUG_LEVEL > 1
134 out( "\n> identified option -" );
135 out( pOpt );
136 out( " = " );
137 OString tmp = OUStringToOString(aArg.copy(aOpt.getLength()), RTL_TEXTENCODING_ASCII_US);
138 out( tmp.getStr() );
139 #endif
140 ++(*pnIndex);
142 return sal_True;
144 return sal_False;
147 static sal_Bool readOption( sal_Bool * pbOpt, const sal_Char * pOpt,
148 sal_uInt32 * pnIndex, const OUString & aArg)
150 const OUString dashdash("--");
151 OUString aOpt = OUString::createFromAscii(pOpt);
153 if(aArg.indexOf(dashdash) == 0 && aOpt.equals(aArg.copy(2)))
155 ++(*pnIndex);
156 *pbOpt = sal_True;
157 #if OSL_DEBUG_LEVEL > 1
158 out( "\n> identified option --" );
159 out( pOpt );
160 #endif
161 return sal_True;
163 return sal_False;
166 template< class T >
167 void createInstance(
168 Reference< T > & rxOut,
169 const Reference< XComponentContext > & xContext,
170 const OUString & rServiceName )
171 throw (Exception)
173 Reference< XMultiComponentFactory > xMgr( xContext->getServiceManager() );
174 Reference< XInterface > x( xMgr->createInstanceWithContext( rServiceName, xContext ) );
176 if (! x.is())
178 static sal_Bool s_bSet = sal_False;
179 if (! s_bSet)
181 MutexGuard aGuard( Mutex::getGlobalMutex() );
182 if (! s_bSet)
184 Reference< XSet > xSet( xMgr, UNO_QUERY );
185 if (xSet.is())
187 Reference< XMultiServiceFactory > xSF( xMgr, UNO_QUERY );
188 // acceptor
189 xSet->insert( makeAny( loadSharedLibComponentFactory(
190 OUString( "acceptor.uno" SAL_DLLEXTENSION ),
191 OUString(),
192 OUString( "com.sun.star.comp.io.Acceptor" ),
193 xSF, Reference< XRegistryKey >(),
194 "acceptor_" ) ) );
195 // connector
196 xSet->insert( makeAny( loadSharedLibComponentFactory(
197 OUString( "connector.uno" SAL_DLLEXTENSION ),
198 OUString(),
199 OUString( "com.sun.star.comp.io.Connector" ),
200 xSF, Reference< XRegistryKey >(),
201 "connector_" ) ) );
202 // bridge factory
203 xSet->insert( makeAny( loadSharedLibComponentFactory(
204 OUString( "binaryurp.uno" SAL_DLLEXTENSION ),
205 OUString(),
206 OUString( "com.sun.star.comp.bridge.BridgeFactory" ),
207 xSF, Reference< XRegistryKey >(),
208 "binaryurp_" ) ) );
210 s_bSet = sal_True;
213 x = xMgr->createInstanceWithContext( rServiceName, xContext );
216 if (! x.is())
218 OUStringBuffer buf( 64 );
219 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("cannot get service instance \"") );
220 buf.append( rServiceName );
221 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
222 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
225 rxOut = Reference< T >::query( x );
226 if (! rxOut.is())
228 OUStringBuffer buf( 64 );
229 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("service instance \"") );
230 buf.append( rServiceName );
231 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" does not support demanded interface \"") );
232 const Type & rType = ::getCppuType( (const Reference< T > *)0 );
233 buf.append( rType.getTypeName() );
234 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
235 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
239 static Reference< XInterface > loadComponent(
240 const Reference< XComponentContext > & xContext,
241 const OUString & rImplName, const OUString & rLocation )
242 throw (Exception)
244 // determine loader to be used
245 sal_Int32 nDot = rLocation.lastIndexOf( '.' );
246 if (nDot > 0 && nDot < rLocation.getLength())
248 Reference< XImplementationLoader > xLoader;
250 OUString aExt( rLocation.copy( nDot +1 ) );
252 if (aExt.compareToAscii( "dll" ) == 0 ||
253 aExt.compareToAscii( "exe" ) == 0 ||
254 aExt.compareToAscii( "dylib" ) == 0 ||
255 aExt.compareToAscii( "so" ) == 0)
257 createInstance(
258 xLoader, xContext, OUString("com.sun.star.loader.SharedLibrary") );
260 else if (aExt.compareToAscii( "jar" ) == 0 ||
261 aExt.compareToAscii( "class" ) == 0)
263 createInstance(
264 xLoader, xContext, OUString("com.sun.star.loader.Java") );
266 else
268 OUStringBuffer buf( 64 );
269 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("unknown extension of \"") );
270 buf.append( rLocation );
271 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"! No loader available!") );
272 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
275 Reference< XInterface > xInstance;
277 // activate
278 Reference< XInterface > xFactory( xLoader->activate(
279 rImplName, OUString(), rLocation, Reference< XRegistryKey >() ) );
280 if (xFactory.is())
282 Reference< XSingleComponentFactory > xCFac( xFactory, UNO_QUERY );
283 if (xCFac.is())
285 xInstance = xCFac->createInstanceWithContext( xContext );
287 else
289 Reference< XSingleServiceFactory > xSFac( xFactory, UNO_QUERY );
290 if (xSFac.is())
292 out( "\n> warning: ignroing context for implementation \"" );
293 out( rImplName );
294 out( "\"!" );
295 xInstance = xSFac->createInstance();
300 if (! xInstance.is())
302 OUStringBuffer buf( 64 );
303 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("activating component \"") );
304 buf.append( rImplName );
305 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" from location \"") );
306 buf.append( rLocation );
307 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" failed!") );
308 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
311 return xInstance;
313 else
315 OUStringBuffer buf( 64 );
316 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("location \"") );
317 buf.append( rLocation );
318 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\" has no extension! Cannot determine loader to be used!") );
319 throw RuntimeException( buf.makeStringAndClear(), Reference< XInterface >() );
323 class OInstanceProvider
324 : public WeakImplHelper1< XInstanceProvider >
326 Reference< XComponentContext > _xContext;
328 Mutex _aSingleInstanceMutex;
329 Reference< XInterface > _xSingleInstance;
330 sal_Bool _bSingleInstance;
332 OUString _aImplName;
333 OUString _aLocation;
334 OUString _aServiceName;
335 Sequence< Any > _aInitParams;
337 OUString _aInstanceName;
339 inline Reference< XInterface > createInstance() throw (Exception);
341 public:
342 OInstanceProvider( const Reference< XComponentContext > & xContext,
343 const OUString & rImplName, const OUString & rLocation,
344 const OUString & rServiceName, const Sequence< Any > & rInitParams,
345 sal_Bool bSingleInstance, const OUString & rInstanceName )
346 : _xContext( xContext )
347 , _bSingleInstance( bSingleInstance )
348 , _aImplName( rImplName )
349 , _aLocation( rLocation )
350 , _aServiceName( rServiceName )
351 , _aInitParams( rInitParams )
352 , _aInstanceName( rInstanceName )
355 // XInstanceProvider
356 virtual Reference< XInterface > SAL_CALL getInstance( const OUString & rName )
357 throw (NoSuchElementException, RuntimeException);
360 inline Reference< XInterface > OInstanceProvider::createInstance()
361 throw (Exception)
363 Reference< XInterface > xRet;
364 if (!_aImplName.isEmpty()) // manually via loader
365 xRet = loadComponent( _xContext, _aImplName, _aLocation );
366 else // via service manager
367 unoexe::createInstance( xRet, _xContext, _aServiceName );
369 // opt XInit
370 Reference< XInitialization > xInit( xRet, UNO_QUERY );
371 if (xInit.is())
372 xInit->initialize( _aInitParams );
374 return xRet;
377 Reference< XInterface > OInstanceProvider::getInstance( const OUString & rName )
378 throw (NoSuchElementException, RuntimeException)
382 if (_aInstanceName == rName)
384 Reference< XInterface > xRet;
386 if (_aImplName.isEmpty() && _aServiceName.isEmpty())
388 OSL_ASSERT( rName == "uno.ComponentContext" );
389 xRet = _xContext;
391 else if (_bSingleInstance)
393 if (! _xSingleInstance.is())
395 MutexGuard aGuard( _aSingleInstanceMutex );
396 if (! _xSingleInstance.is())
398 _xSingleInstance = createInstance();
401 xRet = _xSingleInstance;
403 else
405 xRet = createInstance();
408 return xRet;
411 catch (Exception & rExc)
413 out( "\n> error: " );
414 out( rExc.Message );
416 OUStringBuffer buf( 64 );
417 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("no such element \"") );
418 buf.append( rName );
419 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
420 throw NoSuchElementException( buf.makeStringAndClear(), Reference< XInterface >() );
423 struct ODisposingListener : public WeakImplHelper1< XEventListener >
425 Condition cDisposed;
427 // XEventListener
428 virtual void SAL_CALL disposing( const EventObject & rEvt )
429 throw (RuntimeException);
431 static void waitFor( const Reference< XComponent > & xComp );
434 void ODisposingListener::disposing( const EventObject & )
435 throw (RuntimeException)
437 cDisposed.set();
440 void ODisposingListener::waitFor( const Reference< XComponent > & xComp )
442 ODisposingListener * pListener = new ODisposingListener();
443 Reference< XEventListener > xListener( pListener );
445 xComp->addEventListener( xListener );
446 pListener->cDisposed.wait();
449 } // namespace unoexe
451 using namespace unoexe;
453 SAL_IMPLEMENT_MAIN()
455 sal_uInt32 nCount = rtl_getAppCommandArgCount();
456 if (nCount == 0)
458 out( arUsingText );
459 return 0;
462 sal_Int32 nRet = 0;
463 Reference< XComponentContext > xContext;
468 OUString aImplName, aLocation, aServiceName, aUnoUrl;
469 Sequence< OUString > aParams;
470 sal_Bool bSingleAccept = sal_False;
471 sal_Bool bSingleInstance = sal_False;
473 // read command line arguments
475 sal_uInt32 nPos = 0;
476 // read up to arguments
477 while (nPos < nCount)
479 OUString arg;
481 rtl_getAppCommandArg(nPos, &arg.pData);
483 const OUString dashdash("--");
484 if (dashdash == arg)
486 ++nPos;
487 break;
490 if (!(readOption( &aImplName, "c", &nPos, arg) ||
491 readOption( &aLocation, "l", &nPos, arg) ||
492 readOption( &aServiceName, "s", &nPos, arg) ||
493 readOption( &aUnoUrl, "u", &nPos, arg) ||
494 readOption( &s_quiet, "quiet", &nPos, arg) ||
495 readOption( &bSingleAccept, "singleaccept", &nPos, arg) ||
496 readOption( &bSingleInstance, "singleinstance", &nPos, arg)))
498 throw RuntimeException(
499 "unexpected argument \"" + arg + "\"",
500 Reference< XInterface >() );
504 if (!(aImplName.isEmpty() || aServiceName.isEmpty()))
505 throw RuntimeException( OUString("give component exOR service name!" ), Reference< XInterface >() );
506 if (aImplName.isEmpty() && aServiceName.isEmpty())
508 if (! aUnoUrl.endsWithIgnoreAsciiCaseAsciiL(
509 RTL_CONSTASCII_STRINGPARAM(";uno.ComponentContext") ))
510 throw RuntimeException(
511 OUString("expected UNO-URL with instance name uno.ComponentContext!" ),
512 Reference<XInterface>() );
513 if (bSingleInstance)
514 throw RuntimeException(
515 OUString("unexpected option --singleinstance!"),
516 Reference<XInterface>() );
518 if (!aImplName.isEmpty() && aLocation.isEmpty())
519 throw RuntimeException( OUString("give component location!" ), Reference< XInterface >() );
520 if (!aServiceName.isEmpty() && !aLocation.isEmpty())
521 out( "\n> warning: service name given, will ignore location!" );
523 // read component params
524 aParams.realloc( nCount - nPos );
525 OUString * pParams = aParams.getArray();
527 sal_uInt32 nOffset = nPos;
528 for ( ; nPos < nCount; ++nPos )
530 rtl_getAppCommandArg( nPos, &pParams[nPos -nOffset].pData );
533 xContext = defaultBootstrap_InitialComponentContext();
535 // accept, instanciate, etc.
537 if (!aUnoUrl.isEmpty()) // accepting connections
539 sal_Int32 nIndex = 0, nTokens = 0;
540 do { aUnoUrl.getToken( 0, ';', nIndex ); nTokens++; } while( nIndex != -1 );
541 if (nTokens != 3 || aUnoUrl.getLength() < 10 ||
542 !aUnoUrl.copy( 0, 4 ).equalsIgnoreAsciiCase( OUString("uno:") ))
544 throw RuntimeException( OUString("illegal uno url given!" ), Reference< XInterface >() );
546 nIndex = 0;
547 OUString aConnectDescr( aUnoUrl.getToken( 0, ';', nIndex ).copy( 4 ) ); // uno:CONNECTDESCR;iiop;InstanceName
548 OUString aInstanceName( aUnoUrl.getToken( 1, ';', nIndex ) );
550 Reference< XAcceptor > xAcceptor;
551 createInstance(
552 xAcceptor, xContext,
553 OUString("com.sun.star.connection.Acceptor") );
555 // init params
556 Sequence< Any > aInitParams( aParams.getLength() );
557 const OUString * p = aParams.getConstArray();
558 Any * pInitParams = aInitParams.getArray();
559 for ( sal_Int32 i = aParams.getLength(); i--; )
561 pInitParams[i] = makeAny( p[i] );
564 // instance provider
565 Reference< XInstanceProvider > xInstanceProvider( new OInstanceProvider(
566 xContext, aImplName, aLocation, aServiceName, aInitParams,
567 bSingleInstance, aInstanceName ) );
569 nIndex = 0;
570 OUString aUnoUrlToken( aUnoUrl.getToken( 1, ';', nIndex ) );
571 for (;;)
573 // accepting
574 out( "\n> accepting " );
575 out( aConnectDescr );
576 out( "..." );
577 Reference< XConnection > xConnection( xAcceptor->accept( aConnectDescr ) );
578 out( "connection established." );
580 Reference< XBridgeFactory > xBridgeFactory;
581 createInstance(
582 xBridgeFactory, xContext,
583 OUString("com.sun.star.bridge.BridgeFactory") );
585 // bridge
586 Reference< XBridge > xBridge( xBridgeFactory->createBridge(
587 OUString(), aUnoUrlToken,
588 xConnection, xInstanceProvider ) );
590 if (bSingleAccept)
592 Reference< XComponent > xComp( xBridge, UNO_QUERY );
593 if (! xComp.is())
594 throw RuntimeException( OUString( "bridge factory does not export interface \"com.sun.star.lang.XComponent\"!" ), Reference< XInterface >() );
595 ODisposingListener::waitFor( xComp );
596 xComp->dispose();
597 // explicitly dispose the remote bridge so that it joins
598 // on all spawned threads before process exit (see
599 // binaryurp/source/bridge.cxx for details)
600 break;
604 else // no uno url
606 Reference< XInterface > xInstance;
607 if (!aImplName.isEmpty()) // manually via loader
608 xInstance = loadComponent( xContext, aImplName, aLocation );
609 else // via service manager
610 createInstance( xInstance, xContext, aServiceName );
612 // execution
613 Reference< XMain > xMain( xInstance, UNO_QUERY );
614 if (xMain.is())
616 nRet = xMain->run( aParams );
618 else
620 Reference< XComponent > xComp( xInstance, UNO_QUERY );
621 if (xComp.is())
622 xComp->dispose();
623 throw RuntimeException( OUString( "component does not export interface interface \"com.sun.star.lang.XMain\"!" ), Reference< XInterface >() );
627 catch (Exception & rExc)
629 out( "\n> error: " );
630 out( rExc.Message );
631 out( "\n> dying..." );
632 nRet = 1;
635 // cleanup
636 Reference< XComponent > xComp( xContext, UNO_QUERY );
637 if (xComp.is())
638 xComp->dispose();
640 #if OSL_DEBUG_LEVEL > 1
641 out( "\n" );
642 #endif
643 return nRet;
646 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */