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/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>
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
;
62 static bool s_quiet
= false;
64 static inline void out( const sal_Char
* pText
)
67 fprintf( stderr
, "%s", pText
);
70 static inline void out( const OUString
& rText
)
74 OString
aText( OUStringToOString( rText
, RTL_TEXTENCODING_ASCII_US
) );
75 fprintf( stderr
, "%s", aText
.getStr() );
79 static const char arUsingText
[] =
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"
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
))
95 OUString aOpt
= OUString::createFromAscii( pOpt
);
97 if (aArg
.getLength() < aOpt
.getLength())
100 if (aOpt
.equalsIgnoreAsciiCase( aArg
.copy(1) ))
102 // take next argument
105 rtl_getAppCommandArg(*pnIndex
, &pValue
->pData
);
106 if (*pnIndex
>= rtl_getAppCommandArgCount() || pValue
->copy(1).equals(dash
))
108 throw RuntimeException( "incomplete option \"-" + aOpt
+ "\" given!" );
112 #if OSL_DEBUG_LEVEL > 1
113 out( "\n> identified option -" );
116 OString tmp
= OUStringToOString(aArg
, RTL_TEXTENCODING_ASCII_US
);
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 -" );
130 OString tmp
= OUStringToOString(aArg
.copy(aOpt
.getLength()), RTL_TEXTENCODING_ASCII_US
);
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)))
150 #if OSL_DEBUG_LEVEL > 1
151 out( "\n> identified option --" );
161 Reference
< T
> & rxOut
,
162 const Reference
< XComponentContext
> & xContext
,
163 const OUString
& rServiceName
)
166 Reference
< XMultiComponentFactory
> xMgr( xContext
->getServiceManager() );
167 Reference
< XInterface
> x( xMgr
->createInstanceWithContext( rServiceName
, xContext
) );
171 throw RuntimeException( "cannot get service instance \"" + rServiceName
+ "\"!" );
174 rxOut
= Reference
< T
>::query( x
);
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
)
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")
201 xLoader
, xContext
, OUString("com.sun.star.loader.SharedLibrary") );
203 else if (aExt
== "jar" || aExt
== "class")
206 xLoader
, xContext
, OUString("com.sun.star.loader.Java") );
210 throw RuntimeException(
211 "unknown extension of \"" + rLocation
+ "\"! No loader available!" );
214 Reference
< XInterface
> xInstance
;
217 Reference
< XInterface
> xFactory( xLoader
->activate(
218 rImplName
, OUString(), rLocation
, Reference
< XRegistryKey
>() ) );
221 Reference
< XSingleComponentFactory
> xCFac( xFactory
, UNO_QUERY
);
224 xInstance
= xCFac
->createInstanceWithContext( xContext
);
228 Reference
< XSingleServiceFactory
> xSFac( xFactory
, UNO_QUERY
);
231 out( "\n> warning: ignroing context for implementation \"" );
234 xInstance
= xSFac
->createInstance();
239 if (! xInstance
.is())
241 throw RuntimeException(
242 "activating component \"" + rImplName
+ "\" from location \"" + rLocation
+ "\" failed!" );
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
;
265 OUString _aServiceName
;
266 Sequence
< Any
> _aInitParams
;
268 OUString _aInstanceName
;
270 inline Reference
< XInterface
> createInstance() throw (Exception
);
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
)
287 virtual Reference
< XInterface
> SAL_CALL
getInstance( const OUString
& rName
)
288 throw (NoSuchElementException
, RuntimeException
, std::exception
) SAL_OVERRIDE
;
291 inline Reference
< XInterface
> OInstanceProvider::createInstance()
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
);
301 Reference
< XInitialization
> xInit( xRet
, UNO_QUERY
);
303 xInit
->initialize( _aInitParams
);
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" );
322 else if (_bSingleInstance
)
324 if (! _xSingleInstance
.is())
326 MutexGuard
aGuard( _aSingleInstanceMutex
);
327 if (! _xSingleInstance
.is())
329 _xSingleInstance
= createInstance();
332 xRet
= _xSingleInstance
;
336 xRet
= createInstance();
342 catch (Exception
& rExc
)
344 out( "\n> error: " );
347 throw NoSuchElementException(
348 "no such element \"" + rName
+ "\"!" );
351 struct ODisposingListener
: public WeakImplHelper1
< 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
)
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
;
383 sal_uInt32 nCount
= rtl_getAppCommandArgCount();
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
404 // read up to arguments
405 while (nPos
< nCount
)
409 rtl_getAppCommandArg(nPos
, &arg
.pData
);
411 const OUString
dashdash("--");
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!" );
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!" );
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
);
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
] );
486 Reference
< XInstanceProvider
> xInstanceProvider( new OInstanceProvider(
487 xContext
, aImplName
, aLocation
, aServiceName
, aInitParams
,
488 bSingleInstance
, aInstanceName
) );
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
496 out( "\n> accepting " );
497 out( aConnectDescr
);
499 Reference
< XConnection
> xConnection( xAcceptor
->accept( aConnectDescr
) );
500 out( "connection established." );
502 Reference
< XBridgeFactory
> xBridgeFactory
;
504 xBridgeFactory
, xContext
,
505 OUString("com.sun.star.bridge.BridgeFactory") );
508 Reference
< XBridge
> xBridge( xBridgeFactory
->createBridge(
509 OUString(), aUnoUrlToken
,
510 xConnection
, xInstanceProvider
) );
514 Reference
< XComponent
> xComp( xBridge
, UNO_QUERY
);
516 throw RuntimeException( "bridge factory does not export interface \"com.sun.star.lang.XComponent\"!" );
517 ODisposingListener::waitFor( xComp
);
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)
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
);
535 Reference
< XMain
> xMain( xInstance
, UNO_QUERY
);
538 nRet
= xMain
->run( aParams
);
542 Reference
< XComponent
> xComp( xInstance
, UNO_QUERY
);
545 throw RuntimeException( "component does not export interface interface \"com.sun.star.lang.XMain\"!" );
549 catch (Exception
& rExc
)
551 out( "\n> error: " );
553 out( "\n> dying..." );
558 Reference
< XComponent
> xComp( xContext
, UNO_QUERY
);
562 #if OSL_DEBUG_LEVEL > 1
568 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */