merge the formfield patch from ooo-build
[ooovba.git] / cppuhelper / source / bootstrap.cxx
blob39b00b45c06066e9abb99cfe1282e954b1c3ad30
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: bootstrap.cxx,v $
10 * $Revision: 1.33 $
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"
34 #include <string.h>
35 #include <vector>
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"
45 #endif
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;
83 namespace cppu
86 OUString const & get_this_libpath()
88 static OUString s_path;
89 if (0 == s_path.getLength())
91 OUString path;
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())
96 s_path = path;
98 return s_path;
101 Bootstrap const & get_unorc() SAL_THROW( () )
103 static rtlBootstrapHandle s_bstrap = 0;
104 if (! s_bstrap)
106 OUString iniName(
107 get_this_libpath() + OUSTR("/" SAL_CONFIGFILE("uno")) );
108 rtlBootstrapHandle bstrap = rtl_bootstrap_args_open( iniName.pData );
110 ClearableMutexGuard guard( Mutex::getGlobalMutex() );
111 if (s_bstrap)
113 guard.clear();
114 rtl_bootstrap_args_close( bstrap );
116 else
118 s_bstrap = bstrap;
121 return *(Bootstrap const *)&s_bstrap;
125 void addFactories(
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 );
136 while (*ppNames)
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;
148 if (aFac >>= xInfo)
150 ::fprintf(
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() );
161 else
163 ::fprintf(
164 stderr,
165 "> implementation %s provides NO lang::XServiceInfo!!!\n",
166 ppNames[ -1 ] );
169 #endif
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() );
180 #endif
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 )
199 SAL_THROW( () );
201 Reference< registry::XSimpleRegistry > SAL_CALL createRegistryWrapper(
202 const Reference< XComponentContext >& xContext );
204 namespace {
206 template< class T >
207 inline beans::PropertyValue createPropertyValue(
208 OUString const & name, T const & value )
209 SAL_THROW( () )
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 )
219 SAL_THROW(())
221 OUString result;
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))
229 if(pFallenBack)
230 *pFallenBack = sal_True;
232 OUString fileName;
233 bootstrap.getIniName(fileName);
235 // cut the rc extension
236 OUStringBuffer result_buf( 64 );
237 result_buf.append(
238 fileName.copy(
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
246 OString result_dbg =
247 OUStringToOString(result, RTL_TEXTENCODING_ASCII_US);
248 OString arg_name_dbg =
249 OUStringToOString(arg_name, RTL_TEXTENCODING_ASCII_US);
250 OSL_TRACE(
251 "cppuhelper::findBoostrapArgument - "
252 "setting %s relative to executable: %s\n",
253 arg_name_dbg.getStr(),
254 result_dbg.getStr() );
255 #endif
257 else
259 if(pFallenBack)
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 );
267 OSL_TRACE(
268 "cppuhelper::findBoostrapArgument - found %s in env: %s",
269 prefixed_arg_name_dbg.getStr(),
270 result_dbg.getStr() );
271 #endif
274 return result;
277 Reference< registry::XSimpleRegistry > nestRegistries(
278 const OUString baseDir,
279 const Reference< lang::XSingleServiceFactory > & xSimRegFac,
280 const Reference< lang::XSingleServiceFactory > & xNesRegFac,
281 OUString csl_rdbs,
282 const OUString & write_rdb,
283 sal_Bool forceWrite_rdb,
284 sal_Bool bFallenBack )
285 SAL_THROW((Exception))
287 sal_Int32 index;
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);
306 OSL_TRACE(
307 "warning: couldn't open %s cause of %s",
308 rdb_name_tmp.getStr(), message_dbg.getStr() );
309 #endif
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())
323 continue;
325 bool optional = ('?' == rdb_name[ 0 ]);
326 if (optional)
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;
352 else
353 lastRegistry = simpleRegistry;
355 catch(registry::InvalidRegistryException & invalidRegistryException)
357 if (! optional)
359 // if a registry was explicitly given, the exception shall fly
360 if( ! bFallenBack )
361 throw;
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 );
370 OSL_TRACE(
371 "warning: couldn't open %s cause of %s",
372 rdb_name_tmp.getStr(), message_dbg.getStr() );
373 #endif
376 while(index != -1 && csl_rdbs.getLength()); // are there more rdbs in list?
378 return lastRegistry;
381 Reference< XComponentContext >
382 SAL_CALL defaultBootstrap_InitialComponentContext(
383 Bootstrap const & bootstrap )
384 SAL_THROW( (Exception) )
386 OUString bootstrapPath( get_this_libpath() );
387 OUString iniDir;
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,
402 xEmptyKey),
403 UNO_QUERY);
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,
410 xEmptyKey),
411 UNO_QUERY);
413 sal_Bool bFallenback_types;
414 OUString cls_uno_types =
415 findBoostrapArgument( bootstrap, OUSTR("TYPES"), &bFallenback_types );
417 Reference<registry::XSimpleRegistry> types_xRegistry =
418 nestRegistries(
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 ) );
446 // initialize sf
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 );
454 return xContext;
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;
498 return *this;
501 const ::rtl::OUString & BootstrapException::getMessage() const
503 return m_aMessage;
506 Reference< XComponentContext > SAL_CALL bootstrap()
508 Reference< XComponentContext > xRemoteContext;
512 char const * p1 = cppuhelper_detail_findSofficePath();
513 if (p1 == NULL) {
514 throw BootstrapException(
515 OUSTR("no soffice installation found!"));
517 rtl::OUString p2;
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!"));
527 OUString 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] != '/') {
535 path += OUSTR("/");
538 OUString uri;
539 if (!Bootstrap::get(OUSTR("URE_BOOTSTRAP"), uri)) {
540 Bootstrap::set(
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();
553 if ( hPool == 0 )
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() );
566 // accept string
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;" ) );
572 // arguments
573 OUString args [] = {
574 OUSTR( "-nologo" ),
575 OUSTR( "-nodefault" ),
576 OUSTR( "-norestore" ),
577 OUSTR( "-nocrashreport" ),
578 OUSTR( "-nolockcheck" ),
579 buf.makeStringAndClear()
581 rtl_uString * ar_args [] = {
582 args[ 0 ].pData,
583 args[ 1 ].pData,
584 args[ 2 ].pData,
585 args[ 3 ].pData,
586 args[ 4 ].pData,
587 args[ 5 ].pData
589 ::osl::Security sec;
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,
596 sec.getHandle(),
597 0, // => current working dir
598 0, 0, // => no env vars
599 &hProcess );
600 switch ( rc )
602 case osl_Process_E_None:
603 osl_freeProcessHandle( hProcess );
604 break;
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:
614 default:
615 throw BootstrapException( OUSTR( "unmapped error!" ) );
618 // create a URL resolver
619 Reference< bridge::XUnoUrlResolver > xUrlResolver(
620 bridge::UnoUrlResolver::create( xLocalContext ) );
622 // connection string
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
631 for ( ; ; )
635 // try to connect to office
636 xRemoteContext.set(
637 xUrlResolver->resolve( sConnectString ), UNO_QUERY_THROW );
638 break;
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(
661 rtl::Uri::decode(
662 uri.copy(RTL_CONSTASCII_LENGTH(PREFIX)),
663 rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8))
664 : uri;
667 } // namespace cppu