merged tag LIBREOFFICE_3_2_99_3
[LibreOffice.git] / cppuhelper / source / bootstrap.cxx
blob245714827145ed87b12a9573d6f6391b89275172
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 // MARKER(update_precomp.py): autogen include statement, do not remove
30 #include "precompiled_cppuhelper.hxx"
32 #include <string.h>
33 #include <vector>
35 #include "rtl/process.h"
36 #include "rtl/bootstrap.hxx"
37 #include "rtl/random.h"
38 #include "rtl/string.hxx"
39 #include "rtl/ustrbuf.hxx"
40 #include "rtl/uri.hxx"
41 #if OSL_DEBUG_LEVEL > 0
42 #include "rtl/strbuf.hxx"
43 #endif
44 #include "osl/diagnose.h"
45 #include "osl/file.hxx"
46 #include "osl/module.hxx"
47 #include "osl/security.hxx"
48 #include "osl/thread.hxx"
50 #include "cppuhelper/shlib.hxx"
51 #include "cppuhelper/bootstrap.hxx"
52 #include "cppuhelper/component_context.hxx"
53 #include "cppuhelper/access_control.hxx"
54 #include "cppuhelper/findsofficepath.h"
56 #include "com/sun/star/uno/XComponentContext.hpp"
57 #include "com/sun/star/uno/XCurrentContext.hpp"
59 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
60 #include "com/sun/star/lang/XSingleComponentFactory.hpp"
61 #include "com/sun/star/lang/XInitialization.hpp"
62 #include "com/sun/star/lang/XServiceInfo.hpp"
63 #include "com/sun/star/registry/XSimpleRegistry.hpp"
64 #include "com/sun/star/container/XSet.hpp"
65 #include "com/sun/star/beans/PropertyValue.hpp"
66 #include "com/sun/star/io/IOException.hpp"
67 #include "com/sun/star/bridge/UnoUrlResolver.hpp"
68 #include "com/sun/star/bridge/XUnoUrlResolver.hpp"
70 #include "macro_expander.hxx"
72 #define OUSTR(x) ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(x) )
73 #define ARLEN(x) sizeof (x) / sizeof *(x)
76 using namespace ::rtl;
77 using namespace ::osl;
78 using namespace ::com::sun::star;
79 using namespace ::com::sun::star::uno;
81 namespace cppu
84 OUString const & get_this_libpath()
86 static OUString s_path;
87 if (0 == s_path.getLength())
89 OUString path;
90 Module::getUrlFromAddress( reinterpret_cast<oslGenericFunction>(get_this_libpath), path );
91 path = path.copy( 0, path.lastIndexOf( '/' ) );
92 MutexGuard guard( Mutex::getGlobalMutex() );
93 if (0 == s_path.getLength())
94 s_path = path;
96 return s_path;
99 Bootstrap const & get_unorc() SAL_THROW( () )
101 static rtlBootstrapHandle s_bstrap = 0;
102 if (! s_bstrap)
104 OUString iniName(
105 get_this_libpath() + OUSTR("/" SAL_CONFIGFILE("uno")) );
106 rtlBootstrapHandle bstrap = rtl_bootstrap_args_open( iniName.pData );
108 ClearableMutexGuard guard( Mutex::getGlobalMutex() );
109 if (s_bstrap)
111 guard.clear();
112 rtl_bootstrap_args_close( bstrap );
114 else
116 s_bstrap = bstrap;
119 return *(Bootstrap const *)&s_bstrap;
123 void addFactories(
124 char const * const * ppNames /* lib, implname, ..., 0 */,
125 OUString const & bootstrapPath,
126 Reference< lang::XMultiComponentFactory > const & xMgr,
127 Reference< registry::XRegistryKey > const & xKey )
128 SAL_THROW( (Exception) )
130 Reference< container::XSet > xSet( xMgr, UNO_QUERY );
131 OSL_ASSERT( xSet.is() );
132 Reference< lang::XMultiServiceFactory > xSF( xMgr, UNO_QUERY );
134 while (*ppNames)
136 OUString lib( OUString::createFromAscii( *ppNames++ ) );
137 OUString implName( OUString::createFromAscii( *ppNames++ ) );
139 Any aFac( makeAny( loadSharedLibComponentFactory(
140 lib, bootstrapPath, implName, xSF, xKey ) ) );
141 xSet->insert( aFac );
142 #if OSL_DEBUG_LEVEL > 1
143 if (xSet->has( aFac ))
145 Reference< lang::XServiceInfo > xInfo;
146 if (aFac >>= xInfo)
148 ::fprintf(
149 stderr, "> implementation %s supports: ", ppNames[ -1 ] );
150 Sequence< OUString > supported(
151 xInfo->getSupportedServiceNames() );
152 for ( sal_Int32 nPos = supported.getLength(); nPos--; )
154 OString str( OUStringToOString(
155 supported[ nPos ], RTL_TEXTENCODING_ASCII_US ) );
156 ::fprintf( stderr, nPos ? "%s, " : "%s\n", str.getStr() );
159 else
161 ::fprintf(
162 stderr,
163 "> implementation %s provides NO lang::XServiceInfo!!!\n",
164 ppNames[ -1 ] );
167 #endif
168 #if OSL_DEBUG_LEVEL > 0
169 if (! xSet->has( aFac ))
171 OStringBuffer buf( 64 );
172 buf.append( "### failed inserting shared lib \"" );
173 buf.append( ppNames[ -2 ] );
174 buf.append( "\"!!!" );
175 OString str( buf.makeStringAndClear() );
176 OSL_ENSURE( 0, str.getStr() );
178 #endif
182 // private forward decl
183 Reference< lang::XMultiComponentFactory > bootstrapInitialSF(
184 OUString const & rBootstrapPath )
185 SAL_THROW( (Exception) );
187 Reference< XComponentContext > bootstrapInitialContext(
188 Reference< lang::XMultiComponentFactory > const & xSF,
189 Reference< registry::XSimpleRegistry > const & types_xRegistry,
190 Reference< registry::XSimpleRegistry > const & services_xRegistry,
191 OUString const & rBootstrapPath, Bootstrap const & bootstrap )
192 SAL_THROW( (Exception) );
194 Reference< XComponentContext > SAL_CALL createInitialCfgComponentContext(
195 ContextEntry_Init const * pEntries, sal_Int32 nEntries,
196 Reference< XComponentContext > const & xDelegate )
197 SAL_THROW( () );
199 Reference< registry::XSimpleRegistry > SAL_CALL createRegistryWrapper(
200 const Reference< XComponentContext >& xContext );
202 namespace {
204 template< class T >
205 inline beans::PropertyValue createPropertyValue(
206 OUString const & name, T const & value )
207 SAL_THROW( () )
209 return beans::PropertyValue(
210 name, -1, makeAny( value ), beans::PropertyState_DIRECT_VALUE );
213 OUString findBoostrapArgument(
214 const Bootstrap & bootstrap,
215 const OUString & arg_name,
216 sal_Bool * pFallenBack )
217 SAL_THROW(())
219 OUString result;
221 OUString prefixed_arg_name = OUSTR("UNO_");
222 prefixed_arg_name += arg_name.toAsciiUpperCase();
224 // environment not set -> try relative to executable
225 if(!bootstrap.getFrom(prefixed_arg_name, result))
227 if(pFallenBack)
228 *pFallenBack = sal_True;
230 OUString fileName;
231 bootstrap.getIniName(fileName);
233 // cut the rc extension
234 OUStringBuffer result_buf( 64 );
235 result_buf.append(
236 fileName.copy(
237 0, fileName.getLength() - strlen(SAL_CONFIGFILE(""))) );
238 result_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM("_") );
239 result_buf.append( arg_name.toAsciiLowerCase() );
240 result_buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(".rdb") );
241 result = result_buf.makeStringAndClear();
243 #if OSL_DEBUG_LEVEL > 1
244 OString result_dbg =
245 OUStringToOString(result, RTL_TEXTENCODING_ASCII_US);
246 OString arg_name_dbg =
247 OUStringToOString(arg_name, RTL_TEXTENCODING_ASCII_US);
248 OSL_TRACE(
249 "cppuhelper::findBoostrapArgument - "
250 "setting %s relative to executable: %s\n",
251 arg_name_dbg.getStr(),
252 result_dbg.getStr() );
253 #endif
255 else
257 if(pFallenBack)
258 *pFallenBack = sal_False;
260 #if OSL_DEBUG_LEVEL > 1
261 OString prefixed_arg_name_dbg = OUStringToOString(
262 prefixed_arg_name, RTL_TEXTENCODING_ASCII_US );
263 OString result_dbg = OUStringToOString(
264 result, RTL_TEXTENCODING_ASCII_US );
265 OSL_TRACE(
266 "cppuhelper::findBoostrapArgument - found %s in env: %s",
267 prefixed_arg_name_dbg.getStr(),
268 result_dbg.getStr() );
269 #endif
272 return result;
275 Reference< registry::XSimpleRegistry > nestRegistries(
276 const OUString baseDir,
277 const Reference< lang::XSingleServiceFactory > & xSimRegFac,
278 const Reference< lang::XSingleServiceFactory > & xNesRegFac,
279 OUString csl_rdbs,
280 const OUString & write_rdb,
281 sal_Bool forceWrite_rdb,
282 sal_Bool bFallenBack )
283 SAL_THROW((Exception))
285 sal_Int32 index;
286 Reference< registry::XSimpleRegistry > lastRegistry;
288 if(write_rdb.getLength()) // is there a write registry given?
290 lastRegistry.set(xSimRegFac->createInstance(), UNO_QUERY);
294 lastRegistry->open(write_rdb, sal_False, forceWrite_rdb);
296 catch (registry::InvalidRegistryException & invalidRegistryException)
298 (void) invalidRegistryException;
299 #if OSL_DEBUG_LEVEL > 1
300 OString rdb_name_tmp = OUStringToOString(
301 write_rdb, RTL_TEXTENCODING_ASCII_US);
302 OString message_dbg = OUStringToOString(
303 invalidRegistryException.Message, RTL_TEXTENCODING_ASCII_US);
304 OSL_TRACE(
305 "warning: couldn't open %s cause of %s",
306 rdb_name_tmp.getStr(), message_dbg.getStr() );
307 #endif
310 if(!lastRegistry->isValid())
311 lastRegistry.clear();
316 index = csl_rdbs.indexOf((sal_Unicode)' ');
317 OUString rdb_name = (index == -1) ? csl_rdbs : csl_rdbs.copy(0, index);
318 csl_rdbs = (index == -1) ? OUString() : csl_rdbs.copy(index + 1);
320 if (! rdb_name.getLength())
321 continue;
323 bool optional = ('?' == rdb_name[ 0 ]);
324 if (optional)
325 rdb_name = rdb_name.copy( 1 );
329 Reference<registry::XSimpleRegistry> simpleRegistry(
330 xSimRegFac->createInstance(), UNO_QUERY_THROW );
332 osl::FileBase::getAbsoluteFileURL(baseDir, rdb_name, rdb_name);
333 simpleRegistry->open(rdb_name, sal_True, sal_False);
335 if(lastRegistry.is())
337 Reference< registry::XSimpleRegistry > nestedRegistry(
338 xNesRegFac->createInstance(), UNO_QUERY );
339 Reference< lang::XInitialization > nestedRegistry_xInit(
340 nestedRegistry, UNO_QUERY );
342 Sequence<Any> aArgs(2);
343 aArgs[0] <<= lastRegistry;
344 aArgs[1] <<= simpleRegistry;
346 nestedRegistry_xInit->initialize(aArgs);
348 lastRegistry = nestedRegistry;
350 else
351 lastRegistry = simpleRegistry;
353 catch(registry::InvalidRegistryException & invalidRegistryException)
355 if (! optional)
357 // if a registry was explicitly given, the exception shall fly
358 if( ! bFallenBack )
359 throw;
362 (void) invalidRegistryException;
363 #if OSL_DEBUG_LEVEL > 1
364 OString rdb_name_tmp = OUStringToOString(
365 rdb_name, RTL_TEXTENCODING_ASCII_US );
366 OString message_dbg = OUStringToOString(
367 invalidRegistryException.Message, RTL_TEXTENCODING_ASCII_US );
368 OSL_TRACE(
369 "warning: couldn't open %s cause of %s",
370 rdb_name_tmp.getStr(), message_dbg.getStr() );
371 #endif
374 while(index != -1 && csl_rdbs.getLength()); // are there more rdbs in list?
376 return lastRegistry;
379 Reference< XComponentContext >
380 SAL_CALL defaultBootstrap_InitialComponentContext(
381 Bootstrap const & bootstrap )
382 SAL_THROW( (Exception) )
384 OUString bootstrapPath( get_this_libpath() );
385 OUString iniDir;
387 osl_getProcessWorkingDir(&iniDir.pData);
389 Reference<lang::XMultiComponentFactory> smgr_XMultiComponentFactory(
390 bootstrapInitialSF(bootstrapPath) );
391 Reference<lang::XMultiServiceFactory> smgr_XMultiServiceFactory(
392 smgr_XMultiComponentFactory, UNO_QUERY );
394 Reference<registry::XRegistryKey> xEmptyKey;
395 Reference<lang::XSingleServiceFactory> xSimRegFac(
396 loadSharedLibComponentFactory(
397 OUSTR("bootstrap.uno" SAL_DLLEXTENSION), bootstrapPath,
398 OUSTR("com.sun.star.comp.stoc.SimpleRegistry"),
399 smgr_XMultiServiceFactory,
400 xEmptyKey),
401 UNO_QUERY);
403 Reference<lang::XSingleServiceFactory> xNesRegFac(
404 loadSharedLibComponentFactory(
405 OUSTR("bootstrap.uno" SAL_DLLEXTENSION), bootstrapPath,
406 OUSTR("com.sun.star.comp.stoc.NestedRegistry"),
407 smgr_XMultiServiceFactory,
408 xEmptyKey),
409 UNO_QUERY);
411 sal_Bool bFallenback_types;
412 OUString cls_uno_types =
413 findBoostrapArgument( bootstrap, OUSTR("TYPES"), &bFallenback_types );
415 Reference<registry::XSimpleRegistry> types_xRegistry =
416 nestRegistries(
417 iniDir, xSimRegFac, xNesRegFac, cls_uno_types,
418 OUString(), sal_False, bFallenback_types );
420 // ==== bootstrap from services registry ====
422 sal_Bool bFallenback_services;
423 OUString cls_uno_services = findBoostrapArgument(
424 bootstrap, OUSTR("SERVICES"), &bFallenback_services );
426 sal_Bool fallenBackWriteRegistry;
427 OUString write_rdb = findBoostrapArgument(
428 bootstrap, OUSTR("WRITERDB"), &fallenBackWriteRegistry );
429 if (fallenBackWriteRegistry)
431 // no standard write rdb anymore
432 write_rdb = OUString();
435 Reference<registry::XSimpleRegistry> services_xRegistry = nestRegistries(
436 iniDir, xSimRegFac, xNesRegFac, cls_uno_services, write_rdb,
437 !fallenBackWriteRegistry, bFallenback_services );
439 Reference< XComponentContext > xContext(
440 bootstrapInitialContext(
441 smgr_XMultiComponentFactory, types_xRegistry, services_xRegistry,
442 bootstrapPath, bootstrap ) );
444 // initialize sf
445 Reference< lang::XInitialization > xInit(
446 smgr_XMultiComponentFactory, UNO_QUERY );
447 OSL_ASSERT( xInit.is() );
448 Sequence< Any > aSFInit( 1 );
449 aSFInit[ 0 ] <<= services_xRegistry;
450 xInit->initialize( aSFInit );
452 return xContext;
457 Reference< XComponentContext >
458 SAL_CALL defaultBootstrap_InitialComponentContext(
459 OUString const & iniFile )
460 SAL_THROW( (Exception) )
462 Bootstrap bootstrap( iniFile );
463 if (bootstrap.getHandle() == 0)
464 throw io::IOException(OUSTR("Cannot open for reading: ") + iniFile, 0);
465 return defaultBootstrap_InitialComponentContext( bootstrap );
468 Reference< XComponentContext >
469 SAL_CALL defaultBootstrap_InitialComponentContext()
470 SAL_THROW( (Exception) )
472 return defaultBootstrap_InitialComponentContext( get_unorc() );
475 BootstrapException::BootstrapException()
479 BootstrapException::BootstrapException( const ::rtl::OUString & rMessage )
480 :m_aMessage( rMessage )
484 BootstrapException::BootstrapException( const BootstrapException & e )
486 m_aMessage = e.m_aMessage;
489 BootstrapException::~BootstrapException()
493 BootstrapException & BootstrapException::operator=( const BootstrapException & e )
495 m_aMessage = e.m_aMessage;
496 return *this;
499 const ::rtl::OUString & BootstrapException::getMessage() const
501 return m_aMessage;
504 Reference< XComponentContext > SAL_CALL bootstrap()
506 Reference< XComponentContext > xRemoteContext;
510 char const * p1 = cppuhelper_detail_findSofficePath();
511 if (p1 == NULL) {
512 throw BootstrapException(
513 OUSTR("no soffice installation found!"));
515 rtl::OUString p2;
516 if (!rtl_convertStringToUString(
517 &p2.pData, p1, strlen(p1), osl_getThreadTextEncoding(),
518 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR |
519 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR |
520 RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
522 throw BootstrapException(
523 OUSTR("bad characters in soffice installation path!"));
525 OUString path;
526 if (osl::FileBase::getFileURLFromSystemPath(p2, path) !=
527 osl::FileBase::E_None)
529 throw BootstrapException(
530 OUSTR("cannot convert soffice installation path to URL!"));
532 if (path.getLength() > 0 && path[path.getLength() - 1] != '/') {
533 path += OUSTR("/");
536 OUString uri;
537 if (!Bootstrap::get(OUSTR("URE_BOOTSTRAP"), uri)) {
538 Bootstrap::set(
539 OUSTR("URE_BOOTSTRAP"),
540 Bootstrap::encode(path + OUSTR(SAL_CONFIGFILE("fundamental"))));
543 // create default local component context
544 Reference< XComponentContext > xLocalContext(
545 defaultBootstrap_InitialComponentContext() );
546 if ( !xLocalContext.is() )
547 throw BootstrapException( OUSTR( "no local component context!" ) );
549 // create a random pipe name
550 rtlRandomPool hPool = rtl_random_createPool();
551 if ( hPool == 0 )
552 throw BootstrapException( OUSTR( "cannot create random pool!" ) );
553 sal_uInt8 bytes[ 16 ];
554 if ( rtl_random_getBytes( hPool, bytes, ARLEN( bytes ) )
555 != rtl_Random_E_None )
556 throw BootstrapException( OUSTR( "random pool error!" ) );
557 rtl_random_destroyPool( hPool );
558 ::rtl::OUStringBuffer buf;
559 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "uno" ) );
560 for ( sal_uInt32 i = 0; i < ARLEN( bytes ); ++i )
561 buf.append( static_cast< sal_Int32 >( bytes[ i ] ) );
562 OUString sPipeName( buf.makeStringAndClear() );
564 // accept string
565 OSL_ASSERT( buf.getLength() == 0 );
566 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "-accept=pipe,name=" ) );
567 buf.append( sPipeName );
568 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( ";urp;" ) );
570 // arguments
571 OUString args [] = {
572 OUSTR( "-nologo" ),
573 OUSTR( "-nodefault" ),
574 OUSTR( "-norestore" ),
575 OUSTR( "-nocrashreport" ),
576 OUSTR( "-nolockcheck" ),
577 buf.makeStringAndClear()
579 rtl_uString * ar_args [] = {
580 args[ 0 ].pData,
581 args[ 1 ].pData,
582 args[ 2 ].pData,
583 args[ 3 ].pData,
584 args[ 4 ].pData,
585 args[ 5 ].pData
587 ::osl::Security sec;
589 // start office process
590 oslProcess hProcess = 0;
591 oslProcessError rc = osl_executeProcess(
592 (path + OUSTR("soffice")).pData, ar_args, ARLEN( ar_args ),
593 osl_Process_DETACHED,
594 sec.getHandle(),
595 0, // => current working dir
596 0, 0, // => no env vars
597 &hProcess );
598 switch ( rc )
600 case osl_Process_E_None:
601 osl_freeProcessHandle( hProcess );
602 break;
603 case osl_Process_E_NotFound:
604 throw BootstrapException( OUSTR( "image not found!" ) );
605 case osl_Process_E_TimedOut:
606 throw BootstrapException( OUSTR( "timout occured!" ) );
607 case osl_Process_E_NoPermission:
608 throw BootstrapException( OUSTR( "permission denied!" ) );
609 case osl_Process_E_Unknown:
610 throw BootstrapException( OUSTR( "unknown error!" ) );
611 case osl_Process_E_InvalidError:
612 default:
613 throw BootstrapException( OUSTR( "unmapped error!" ) );
616 // create a URL resolver
617 Reference< bridge::XUnoUrlResolver > xUrlResolver(
618 bridge::UnoUrlResolver::create( xLocalContext ) );
620 // connection string
621 OSL_ASSERT( buf.getLength() == 0 );
622 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "uno:pipe,name=" ) );
623 buf.append( sPipeName );
624 buf.appendAscii( RTL_CONSTASCII_STRINGPARAM(
625 ";urp;StarOffice.ComponentContext" ) );
626 OUString sConnectString( buf.makeStringAndClear() );
628 // wait until office is started
629 for ( ; ; )
633 // try to connect to office
634 xRemoteContext.set(
635 xUrlResolver->resolve( sConnectString ), UNO_QUERY_THROW );
636 break;
638 catch ( connection::NoConnectException & )
640 // wait 500 ms, then try to connect again
641 TimeValue tv = { 0 /* secs */, 500000000 /* nanosecs */ };
642 ::osl::Thread::wait( tv );
646 catch ( Exception & e )
648 throw BootstrapException(
649 OUSTR( "unexpected UNO exception caught: " ) + e.Message );
652 return xRemoteContext;
655 OUString bootstrap_expandUri(OUString const & uri) {
656 static char const PREFIX[] = "vnd.sun.star.expand:";
657 return uri.matchAsciiL(RTL_CONSTASCII_STRINGPARAM(PREFIX))
658 ? cppuhelper::detail::expandMacros(
659 rtl::Uri::decode(
660 uri.copy(RTL_CONSTASCII_LENGTH(PREFIX)),
661 rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8))
662 : uri;
665 } // namespace cppu
667 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */