1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bootstrap.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_cppuhelper.hxx"
37 #include "rtl/process.h"
38 #include "rtl/bootstrap.hxx"
39 #include "rtl/random.h"
40 #include "rtl/string.hxx"
41 #include "rtl/ustrbuf.hxx"
42 #include "rtl/uri.hxx"
43 #if OSL_DEBUG_LEVEL > 0
44 #include "rtl/strbuf.hxx"
46 #include "osl/diagnose.h"
47 #include "osl/file.hxx"
48 #include "osl/module.hxx"
49 #include "osl/security.hxx"
50 #include "osl/thread.hxx"
52 #include "cppuhelper/shlib.hxx"
53 #include "cppuhelper/bootstrap.hxx"
54 #include "cppuhelper/component_context.hxx"
55 #include "cppuhelper/access_control.hxx"
56 #include "cppuhelper/findsofficepath.h"
58 #include "com/sun/star/uno/XComponentContext.hpp"
59 #include "com/sun/star/uno/XCurrentContext.hpp"
61 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
62 #include "com/sun/star/lang/XSingleComponentFactory.hpp"
63 #include "com/sun/star/lang/XInitialization.hpp"
64 #include "com/sun/star/lang/XServiceInfo.hpp"
65 #include "com/sun/star/registry/XSimpleRegistry.hpp"
66 #include "com/sun/star/container/XSet.hpp"
67 #include "com/sun/star/beans/PropertyValue.hpp"
68 #include "com/sun/star/io/IOException.hpp"
69 #include "com/sun/star/bridge/UnoUrlResolver.hpp"
70 #include "com/sun/star/bridge/XUnoUrlResolver.hpp"
72 #include "macro_expander.hxx"
74 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
75 #define ARLEN(x) sizeof (x) / sizeof *(x)
78 using namespace ::rtl
;
79 using namespace ::osl
;
80 using namespace ::com::sun::star
;
81 using namespace ::com::sun::star::uno
;
86 OUString
const & get_this_libpath()
88 static OUString s_path
;
89 if (0 == s_path
.getLength())
92 Module::getUrlFromAddress( reinterpret_cast<oslGenericFunction
>(get_this_libpath
), path
);
93 path
= path
.copy( 0, path
.lastIndexOf( '/' ) );
94 MutexGuard
guard( Mutex::getGlobalMutex() );
95 if (0 == s_path
.getLength())
101 Bootstrap
const & get_unorc() SAL_THROW( () )
103 static rtlBootstrapHandle s_bstrap
= 0;
107 get_this_libpath() + OUSTR("/" SAL_CONFIGFILE("uno")) );
108 rtlBootstrapHandle bstrap
= rtl_bootstrap_args_open( iniName
.pData
);
110 ClearableMutexGuard
guard( Mutex::getGlobalMutex() );
114 rtl_bootstrap_args_close( bstrap
);
121 return *(Bootstrap
const *)&s_bstrap
;
126 char const * const * ppNames
/* lib, implname, ..., 0 */,
127 OUString
const & bootstrapPath
,
128 Reference
< lang::XMultiComponentFactory
> const & xMgr
,
129 Reference
< registry::XRegistryKey
> const & xKey
)
130 SAL_THROW( (Exception
) )
132 Reference
< container::XSet
> xSet( xMgr
, UNO_QUERY
);
133 OSL_ASSERT( xSet
.is() );
134 Reference
< lang::XMultiServiceFactory
> xSF( xMgr
, UNO_QUERY
);
138 OUString
lib( OUString::createFromAscii( *ppNames
++ ) );
139 OUString
implName( OUString::createFromAscii( *ppNames
++ ) );
141 Any
aFac( makeAny( loadSharedLibComponentFactory(
142 lib
, bootstrapPath
, implName
, xSF
, xKey
) ) );
143 xSet
->insert( aFac
);
144 #if OSL_DEBUG_LEVEL > 1
145 if (xSet
->has( aFac
))
147 Reference
< lang::XServiceInfo
> xInfo
;
151 stderr
, "> implementation %s supports: ", ppNames
[ -1 ] );
152 Sequence
< OUString
> supported(
153 xInfo
->getSupportedServiceNames() );
154 for ( sal_Int32 nPos
= supported
.getLength(); nPos
--; )
156 OString
str( OUStringToOString(
157 supported
[ nPos
], RTL_TEXTENCODING_ASCII_US
) );
158 ::fprintf( stderr
, nPos
? "%s, " : "%s\n", str
.getStr() );
165 "> implementation %s provides NO lang::XServiceInfo!!!\n",
170 #if OSL_DEBUG_LEVEL > 0
171 if (! xSet
->has( aFac
))
173 OStringBuffer
buf( 64 );
174 buf
.append( "### failed inserting shared lib \"" );
175 buf
.append( ppNames
[ -2 ] );
176 buf
.append( "\"!!!" );
177 OString
str( buf
.makeStringAndClear() );
178 OSL_ENSURE( 0, str
.getStr() );
184 // private forward decl
185 Reference
< lang::XMultiComponentFactory
> bootstrapInitialSF(
186 OUString
const & rBootstrapPath
)
187 SAL_THROW( (Exception
) );
189 Reference
< XComponentContext
> bootstrapInitialContext(
190 Reference
< lang::XMultiComponentFactory
> const & xSF
,
191 Reference
< registry::XSimpleRegistry
> const & types_xRegistry
,
192 Reference
< registry::XSimpleRegistry
> const & services_xRegistry
,
193 OUString
const & rBootstrapPath
, Bootstrap
const & bootstrap
)
194 SAL_THROW( (Exception
) );
196 Reference
< XComponentContext
> SAL_CALL
createInitialCfgComponentContext(
197 ContextEntry_Init
const * pEntries
, sal_Int32 nEntries
,
198 Reference
< XComponentContext
> const & xDelegate
)
201 Reference
< registry::XSimpleRegistry
> SAL_CALL
createRegistryWrapper(
202 const Reference
< XComponentContext
>& xContext
);
207 inline beans::PropertyValue
createPropertyValue(
208 OUString
const & name
, T
const & value
)
211 return beans::PropertyValue(
212 name
, -1, makeAny( value
), beans::PropertyState_DIRECT_VALUE
);
215 OUString
findBoostrapArgument(
216 const Bootstrap
& bootstrap
,
217 const OUString
& arg_name
,
218 sal_Bool
* pFallenBack
)
223 OUString prefixed_arg_name
= OUSTR("UNO_");
224 prefixed_arg_name
+= arg_name
.toAsciiUpperCase();
226 // environment not set -> try relative to executable
227 if(!bootstrap
.getFrom(prefixed_arg_name
, result
))
230 *pFallenBack
= sal_True
;
233 bootstrap
.getIniName(fileName
);
235 // cut the rc extension
236 OUStringBuffer
result_buf( 64 );
239 0, fileName
.getLength() - strlen(SAL_CONFIGFILE(""))) );
240 result_buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM("_") );
241 result_buf
.append( arg_name
.toAsciiLowerCase() );
242 result_buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(".rdb") );
243 result
= result_buf
.makeStringAndClear();
245 #if OSL_DEBUG_LEVEL > 1
247 OUStringToOString(result
, RTL_TEXTENCODING_ASCII_US
);
248 OString arg_name_dbg
=
249 OUStringToOString(arg_name
, RTL_TEXTENCODING_ASCII_US
);
251 "cppuhelper::findBoostrapArgument - "
252 "setting %s relative to executable: %s\n",
253 arg_name_dbg
.getStr(),
254 result_dbg
.getStr() );
260 *pFallenBack
= sal_False
;
262 #if OSL_DEBUG_LEVEL > 1
263 OString prefixed_arg_name_dbg
= OUStringToOString(
264 prefixed_arg_name
, RTL_TEXTENCODING_ASCII_US
);
265 OString result_dbg
= OUStringToOString(
266 result
, RTL_TEXTENCODING_ASCII_US
);
268 "cppuhelper::findBoostrapArgument - found %s in env: %s",
269 prefixed_arg_name_dbg
.getStr(),
270 result_dbg
.getStr() );
277 Reference
< registry::XSimpleRegistry
> nestRegistries(
278 const OUString baseDir
,
279 const Reference
< lang::XSingleServiceFactory
> & xSimRegFac
,
280 const Reference
< lang::XSingleServiceFactory
> & xNesRegFac
,
282 const OUString
& write_rdb
,
283 sal_Bool forceWrite_rdb
,
284 sal_Bool bFallenBack
)
285 SAL_THROW((Exception
))
288 Reference
< registry::XSimpleRegistry
> lastRegistry
;
290 if(write_rdb
.getLength()) // is there a write registry given?
292 lastRegistry
.set(xSimRegFac
->createInstance(), UNO_QUERY
);
296 lastRegistry
->open(write_rdb
, sal_False
, forceWrite_rdb
);
298 catch (registry::InvalidRegistryException
& invalidRegistryException
)
300 (void) invalidRegistryException
;
301 #if OSL_DEBUG_LEVEL > 1
302 OString rdb_name_tmp
= OUStringToOString(
303 write_rdb
, RTL_TEXTENCODING_ASCII_US
);
304 OString message_dbg
= OUStringToOString(
305 invalidRegistryException
.Message
, RTL_TEXTENCODING_ASCII_US
);
307 "warning: couldn't open %s cause of %s",
308 rdb_name_tmp
.getStr(), message_dbg
.getStr() );
312 if(!lastRegistry
->isValid())
313 lastRegistry
.clear();
318 index
= csl_rdbs
.indexOf((sal_Unicode
)' ');
319 OUString rdb_name
= (index
== -1) ? csl_rdbs
: csl_rdbs
.copy(0, index
);
320 csl_rdbs
= (index
== -1) ? OUString() : csl_rdbs
.copy(index
+ 1);
322 if (! rdb_name
.getLength())
325 bool optional
= ('?' == rdb_name
[ 0 ]);
327 rdb_name
= rdb_name
.copy( 1 );
331 Reference
<registry::XSimpleRegistry
> simpleRegistry(
332 xSimRegFac
->createInstance(), UNO_QUERY_THROW
);
334 osl::FileBase::getAbsoluteFileURL(baseDir
, rdb_name
, rdb_name
);
335 simpleRegistry
->open(rdb_name
, sal_True
, sal_False
);
337 if(lastRegistry
.is())
339 Reference
< registry::XSimpleRegistry
> nestedRegistry(
340 xNesRegFac
->createInstance(), UNO_QUERY
);
341 Reference
< lang::XInitialization
> nestedRegistry_xInit(
342 nestedRegistry
, UNO_QUERY
);
344 Sequence
<Any
> aArgs(2);
345 aArgs
[0] <<= lastRegistry
;
346 aArgs
[1] <<= simpleRegistry
;
348 nestedRegistry_xInit
->initialize(aArgs
);
350 lastRegistry
= nestedRegistry
;
353 lastRegistry
= simpleRegistry
;
355 catch(registry::InvalidRegistryException
& invalidRegistryException
)
359 // if a registry was explicitly given, the exception shall fly
364 (void) invalidRegistryException
;
365 #if OSL_DEBUG_LEVEL > 1
366 OString rdb_name_tmp
= OUStringToOString(
367 rdb_name
, RTL_TEXTENCODING_ASCII_US
);
368 OString message_dbg
= OUStringToOString(
369 invalidRegistryException
.Message
, RTL_TEXTENCODING_ASCII_US
);
371 "warning: couldn't open %s cause of %s",
372 rdb_name_tmp
.getStr(), message_dbg
.getStr() );
376 while(index
!= -1 && csl_rdbs
.getLength()); // are there more rdbs in list?
381 Reference
< XComponentContext
>
382 SAL_CALL
defaultBootstrap_InitialComponentContext(
383 Bootstrap
const & bootstrap
)
384 SAL_THROW( (Exception
) )
386 OUString
bootstrapPath( get_this_libpath() );
389 osl_getProcessWorkingDir(&iniDir
.pData
);
391 Reference
<lang::XMultiComponentFactory
> smgr_XMultiComponentFactory(
392 bootstrapInitialSF(bootstrapPath
) );
393 Reference
<lang::XMultiServiceFactory
> smgr_XMultiServiceFactory(
394 smgr_XMultiComponentFactory
, UNO_QUERY
);
396 Reference
<registry::XRegistryKey
> xEmptyKey
;
397 Reference
<lang::XSingleServiceFactory
> xSimRegFac(
398 loadSharedLibComponentFactory(
399 OUSTR("bootstrap.uno" SAL_DLLEXTENSION
), bootstrapPath
,
400 OUSTR("com.sun.star.comp.stoc.SimpleRegistry"),
401 smgr_XMultiServiceFactory
,
405 Reference
<lang::XSingleServiceFactory
> xNesRegFac(
406 loadSharedLibComponentFactory(
407 OUSTR("bootstrap.uno" SAL_DLLEXTENSION
), bootstrapPath
,
408 OUSTR("com.sun.star.comp.stoc.NestedRegistry"),
409 smgr_XMultiServiceFactory
,
413 sal_Bool bFallenback_types
;
414 OUString cls_uno_types
=
415 findBoostrapArgument( bootstrap
, OUSTR("TYPES"), &bFallenback_types
);
417 Reference
<registry::XSimpleRegistry
> types_xRegistry
=
419 iniDir
, xSimRegFac
, xNesRegFac
, cls_uno_types
,
420 OUString(), sal_False
, bFallenback_types
);
422 // ==== bootstrap from services registry ====
424 sal_Bool bFallenback_services
;
425 OUString cls_uno_services
= findBoostrapArgument(
426 bootstrap
, OUSTR("SERVICES"), &bFallenback_services
);
428 sal_Bool fallenBackWriteRegistry
;
429 OUString write_rdb
= findBoostrapArgument(
430 bootstrap
, OUSTR("WRITERDB"), &fallenBackWriteRegistry
);
431 if (fallenBackWriteRegistry
)
433 // no standard write rdb anymore
434 write_rdb
= OUString();
437 Reference
<registry::XSimpleRegistry
> services_xRegistry
= nestRegistries(
438 iniDir
, xSimRegFac
, xNesRegFac
, cls_uno_services
, write_rdb
,
439 !fallenBackWriteRegistry
, bFallenback_services
);
441 Reference
< XComponentContext
> xContext(
442 bootstrapInitialContext(
443 smgr_XMultiComponentFactory
, types_xRegistry
, services_xRegistry
,
444 bootstrapPath
, bootstrap
) );
447 Reference
< lang::XInitialization
> xInit(
448 smgr_XMultiComponentFactory
, UNO_QUERY
);
449 OSL_ASSERT( xInit
.is() );
450 Sequence
< Any
> aSFInit( 1 );
451 aSFInit
[ 0 ] <<= services_xRegistry
;
452 xInit
->initialize( aSFInit
);
459 Reference
< XComponentContext
>
460 SAL_CALL
defaultBootstrap_InitialComponentContext(
461 OUString
const & iniFile
)
462 SAL_THROW( (Exception
) )
464 Bootstrap
bootstrap( iniFile
);
465 if (bootstrap
.getHandle() == 0)
466 throw io::IOException(OUSTR("Cannot open for reading: ") + iniFile
, 0);
467 return defaultBootstrap_InitialComponentContext( bootstrap
);
470 Reference
< XComponentContext
>
471 SAL_CALL
defaultBootstrap_InitialComponentContext()
472 SAL_THROW( (Exception
) )
474 return defaultBootstrap_InitialComponentContext( get_unorc() );
477 BootstrapException::BootstrapException()
481 BootstrapException::BootstrapException( const ::rtl::OUString
& rMessage
)
482 :m_aMessage( rMessage
)
486 BootstrapException::BootstrapException( const BootstrapException
& e
)
488 m_aMessage
= e
.m_aMessage
;
491 BootstrapException::~BootstrapException()
495 BootstrapException
& BootstrapException::operator=( const BootstrapException
& e
)
497 m_aMessage
= e
.m_aMessage
;
501 const ::rtl::OUString
& BootstrapException::getMessage() const
506 Reference
< XComponentContext
> SAL_CALL
bootstrap()
508 Reference
< XComponentContext
> xRemoteContext
;
512 char const * p1
= cppuhelper_detail_findSofficePath();
514 throw BootstrapException(
515 OUSTR("no soffice installation found!"));
518 if (!rtl_convertStringToUString(
519 &p2
.pData
, p1
, strlen(p1
), osl_getThreadTextEncoding(),
520 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
|
521 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
|
522 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
524 throw BootstrapException(
525 OUSTR("bad characters in soffice installation path!"));
528 if (osl::FileBase::getFileURLFromSystemPath(p2
, path
) !=
529 osl::FileBase::E_None
)
531 throw BootstrapException(
532 OUSTR("cannot convert soffice installation path to URL!"));
534 if (path
.getLength() > 0 && path
[path
.getLength() - 1] != '/') {
539 if (!Bootstrap::get(OUSTR("URE_BOOTSTRAP"), uri
)) {
541 OUSTR("URE_BOOTSTRAP"),
542 Bootstrap::encode(path
+ OUSTR(SAL_CONFIGFILE("fundamental"))));
545 // create default local component context
546 Reference
< XComponentContext
> xLocalContext(
547 defaultBootstrap_InitialComponentContext() );
548 if ( !xLocalContext
.is() )
549 throw BootstrapException( OUSTR( "no local component context!" ) );
551 // create a random pipe name
552 rtlRandomPool hPool
= rtl_random_createPool();
554 throw BootstrapException( OUSTR( "cannot create random pool!" ) );
555 sal_uInt8 bytes
[ 16 ];
556 if ( rtl_random_getBytes( hPool
, bytes
, ARLEN( bytes
) )
557 != rtl_Random_E_None
)
558 throw BootstrapException( OUSTR( "random pool error!" ) );
559 rtl_random_destroyPool( hPool
);
560 ::rtl::OUStringBuffer buf
;
561 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "uno" ) );
562 for ( sal_uInt32 i
= 0; i
< ARLEN( bytes
); ++i
)
563 buf
.append( static_cast< sal_Int32
>( bytes
[ i
] ) );
564 OUString
sPipeName( buf
.makeStringAndClear() );
567 OSL_ASSERT( buf
.getLength() == 0 );
568 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "-accept=pipe,name=" ) );
569 buf
.append( sPipeName
);
570 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( ";urp;" ) );
575 OUSTR( "-nodefault" ),
576 OUSTR( "-norestore" ),
577 OUSTR( "-nocrashreport" ),
578 OUSTR( "-nolockcheck" ),
579 buf
.makeStringAndClear()
581 rtl_uString
* ar_args
[] = {
591 // start office process
592 oslProcess hProcess
= 0;
593 oslProcessError rc
= osl_executeProcess(
594 (path
+ OUSTR("soffice")).pData
, ar_args
, ARLEN( ar_args
),
595 osl_Process_DETACHED
,
597 0, // => current working dir
598 0, 0, // => no env vars
602 case osl_Process_E_None
:
603 osl_freeProcessHandle( hProcess
);
605 case osl_Process_E_NotFound
:
606 throw BootstrapException( OUSTR( "image not found!" ) );
607 case osl_Process_E_TimedOut
:
608 throw BootstrapException( OUSTR( "timout occured!" ) );
609 case osl_Process_E_NoPermission
:
610 throw BootstrapException( OUSTR( "permission denied!" ) );
611 case osl_Process_E_Unknown
:
612 throw BootstrapException( OUSTR( "unknown error!" ) );
613 case osl_Process_E_InvalidError
:
615 throw BootstrapException( OUSTR( "unmapped error!" ) );
618 // create a URL resolver
619 Reference
< bridge::XUnoUrlResolver
> xUrlResolver(
620 bridge::UnoUrlResolver::create( xLocalContext
) );
623 OSL_ASSERT( buf
.getLength() == 0 );
624 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM( "uno:pipe,name=" ) );
625 buf
.append( sPipeName
);
626 buf
.appendAscii( RTL_CONSTASCII_STRINGPARAM(
627 ";urp;StarOffice.ComponentContext" ) );
628 OUString
sConnectString( buf
.makeStringAndClear() );
630 // wait until office is started
635 // try to connect to office
637 xUrlResolver
->resolve( sConnectString
), UNO_QUERY_THROW
);
640 catch ( connection::NoConnectException
& )
642 // wait 500 ms, then try to connect again
643 TimeValue tv
= { 0 /* secs */, 500000000 /* nanosecs */ };
644 ::osl::Thread::wait( tv
);
648 catch ( Exception
& e
)
650 throw BootstrapException(
651 OUSTR( "unexpected UNO exception caught: " ) + e
.Message
);
654 return xRemoteContext
;
657 OUString
bootstrap_expandUri(OUString
const & uri
) {
658 static char const PREFIX
[] = "vnd.sun.star.expand:";
659 return uri
.matchAsciiL(RTL_CONSTASCII_STRINGPARAM(PREFIX
))
660 ? cppuhelper::detail::expandMacros(
662 uri
.copy(RTL_CONSTASCII_LENGTH(PREFIX
)),
663 rtl_UriDecodeWithCharset
, RTL_TEXTENCODING_UTF8
))