1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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>
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
;
65 static sal_Bool s_quiet
= false;
67 static inline void out( const sal_Char
* pText
)
70 fprintf( stderr
, "%s", pText
);
73 static inline void out( const OUString
& rText
)
77 OString
aText( OUStringToOString( rText
, RTL_TEXTENCODING_ASCII_US
) );
78 fprintf( stderr
, "%s", aText
.getStr() );
82 static const char arUsingText
[] =
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"
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)
98 OUString aOpt
= OUString::createFromAscii( pOpt
);
100 if (aArg
.getLength() < aOpt
.getLength())
103 if (aOpt
.equalsIgnoreAsciiCase( aArg
.copy(1) ))
105 // take next argument
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
>() );
119 #if OSL_DEBUG_LEVEL > 1
120 out( "\n> identified option -" );
123 OString tmp
= OUStringToOString(aArg
, RTL_TEXTENCODING_ASCII_US
);
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 -" );
137 OString tmp
= OUStringToOString(aArg
.copy(aOpt
.getLength()), RTL_TEXTENCODING_ASCII_US
);
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)))
157 #if OSL_DEBUG_LEVEL > 1
158 out( "\n> identified option --" );
168 Reference
< T
> & rxOut
,
169 const Reference
< XComponentContext
> & xContext
,
170 const OUString
& rServiceName
)
173 Reference
< XMultiComponentFactory
> xMgr( xContext
->getServiceManager() );
174 Reference
< XInterface
> x( xMgr
->createInstanceWithContext( rServiceName
, xContext
) );
178 static sal_Bool s_bSet
= sal_False
;
181 MutexGuard
aGuard( Mutex::getGlobalMutex() );
184 Reference
< XSet
> xSet( xMgr
, UNO_QUERY
);
187 Reference
< XMultiServiceFactory
> xSF( xMgr
, UNO_QUERY
);
189 xSet
->insert( makeAny( loadSharedLibComponentFactory(
190 OUString( "acceptor.uno" SAL_DLLEXTENSION
),
192 OUString( "com.sun.star.comp.io.Acceptor" ),
193 xSF
, Reference
< XRegistryKey
>(),
196 xSet
->insert( makeAny( loadSharedLibComponentFactory(
197 OUString( "connector.uno" SAL_DLLEXTENSION
),
199 OUString( "com.sun.star.comp.io.Connector" ),
200 xSF
, Reference
< XRegistryKey
>(),
203 xSet
->insert( makeAny( loadSharedLibComponentFactory(
204 OUString( "binaryurp.uno" SAL_DLLEXTENSION
),
206 OUString( "com.sun.star.comp.bridge.BridgeFactory" ),
207 xSF
, Reference
< XRegistryKey
>(),
213 x
= xMgr
->createInstanceWithContext( rServiceName
, xContext
);
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
);
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
)
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)
258 xLoader
, xContext
, OUString("com.sun.star.loader.SharedLibrary") );
260 else if (aExt
.compareToAscii( "jar" ) == 0 ||
261 aExt
.compareToAscii( "class" ) == 0)
264 xLoader
, xContext
, OUString("com.sun.star.loader.Java") );
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
;
278 Reference
< XInterface
> xFactory( xLoader
->activate(
279 rImplName
, OUString(), rLocation
, Reference
< XRegistryKey
>() ) );
282 Reference
< XSingleComponentFactory
> xCFac( xFactory
, UNO_QUERY
);
285 xInstance
= xCFac
->createInstanceWithContext( xContext
);
289 Reference
< XSingleServiceFactory
> xSFac( xFactory
, UNO_QUERY
);
292 out( "\n> warning: ignroing context for implementation \"" );
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
>() );
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
;
334 OUString _aServiceName
;
335 Sequence
< Any
> _aInitParams
;
337 OUString _aInstanceName
;
339 inline Reference
< XInterface
> createInstance() throw (Exception
);
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
)
356 virtual Reference
< XInterface
> SAL_CALL
getInstance( const OUString
& rName
)
357 throw (NoSuchElementException
, RuntimeException
);
360 inline Reference
< XInterface
> OInstanceProvider::createInstance()
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
);
370 Reference
< XInitialization
> xInit( xRet
, UNO_QUERY
);
372 xInit
->initialize( _aInitParams
);
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" );
391 else if (_bSingleInstance
)
393 if (! _xSingleInstance
.is())
395 MutexGuard
aGuard( _aSingleInstanceMutex
);
396 if (! _xSingleInstance
.is())
398 _xSingleInstance
= createInstance();
401 xRet
= _xSingleInstance
;
405 xRet
= createInstance();
411 catch (Exception
& rExc
)
413 out( "\n> error: " );
416 OUStringBuffer
buf( 64 );
417 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("no such element \"") );
419 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("\"!") );
420 throw NoSuchElementException( buf
.makeStringAndClear(), Reference
< XInterface
>() );
423 struct ODisposingListener
: public WeakImplHelper1
< 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
)
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
;
455 sal_uInt32 nCount
= rtl_getAppCommandArgCount();
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
476 // read up to arguments
477 while (nPos
< nCount
)
481 rtl_getAppCommandArg(nPos
, &arg
.pData
);
483 const OUString
dashdash("--");
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
>() );
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
>() );
547 OUString
aConnectDescr( aUnoUrl
.getToken( 0, ';', nIndex
).copy( 4 ) ); // uno:CONNECTDESCR;iiop;InstanceName
548 OUString
aInstanceName( aUnoUrl
.getToken( 1, ';', nIndex
) );
550 Reference
< XAcceptor
> xAcceptor
;
553 OUString("com.sun.star.connection.Acceptor") );
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
] );
565 Reference
< XInstanceProvider
> xInstanceProvider( new OInstanceProvider(
566 xContext
, aImplName
, aLocation
, aServiceName
, aInitParams
,
567 bSingleInstance
, aInstanceName
) );
570 OUString
aUnoUrlToken( aUnoUrl
.getToken( 1, ';', nIndex
) );
574 out( "\n> accepting " );
575 out( aConnectDescr
);
577 Reference
< XConnection
> xConnection( xAcceptor
->accept( aConnectDescr
) );
578 out( "connection established." );
580 Reference
< XBridgeFactory
> xBridgeFactory
;
582 xBridgeFactory
, xContext
,
583 OUString("com.sun.star.bridge.BridgeFactory") );
586 Reference
< XBridge
> xBridge( xBridgeFactory
->createBridge(
587 OUString(), aUnoUrlToken
,
588 xConnection
, xInstanceProvider
) );
592 Reference
< XComponent
> xComp( xBridge
, UNO_QUERY
);
594 throw RuntimeException( OUString( "bridge factory does not export interface \"com.sun.star.lang.XComponent\"!" ), Reference
< XInterface
>() );
595 ODisposingListener::waitFor( xComp
);
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)
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
);
613 Reference
< XMain
> xMain( xInstance
, UNO_QUERY
);
616 nRet
= xMain
->run( aParams
);
620 Reference
< XComponent
> xComp( xInstance
, UNO_QUERY
);
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: " );
631 out( "\n> dying..." );
636 Reference
< XComponent
> xComp( xContext
, UNO_QUERY
);
640 #if OSL_DEBUG_LEVEL > 1
646 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */