1 // -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
4 * This file is part of the LibreOffice project.
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 * This file incorporates work covered by the following license notice:
12 * Licensed to the Apache Software Foundation (ASF) under one or more
13 * contributor license agreements. See the NOTICE file distributed
14 * with this work for additional information regarding copyright
15 * ownership. The ASF licenses this file to you under the Apache
16 * License, Version 2.0 (the "License"); you may not use this file
17 * except in compliance with the License. You may obtain a copy of
18 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 package com
.sun
.star
.comp
.helper
;
23 import com
.sun
.star
.bridge
.UnoUrlResolver
;
24 import com
.sun
.star
.bridge
.XUnoUrlResolver
;
25 import com
.sun
.star
.comp
.loader
.JavaLoader
;
26 import com
.sun
.star
.comp
.servicemanager
.ServiceManager
;
27 import com
.sun
.star
.container
.XSet
;
28 import com
.sun
.star
.lang
.XInitialization
;
29 import com
.sun
.star
.lang
.XMultiServiceFactory
;
30 import com
.sun
.star
.lang
.XMultiComponentFactory
;
31 import com
.sun
.star
.lib
.util
.NativeLibraryLoader
;
32 import com
.sun
.star
.loader
.XImplementationLoader
;
33 import com
.sun
.star
.uno
.UnoRuntime
;
34 import com
.sun
.star
.uno
.XComponentContext
;
35 import com
.sun
.star
.beans
.XPropertySet
;
37 import java
.io
.BufferedReader
;
39 import java
.io
.InputStream
;
40 import java
.io
.InputStreamReader
;
41 import java
.io
.PrintStream
;
42 import java
.io
.UnsupportedEncodingException
;
43 import java
.util
.HashMap
;
44 import java
.util
.Hashtable
;
46 import java
.util
.Random
;
48 /** Bootstrap offers functionality to obtain a context or simply
50 The service manager can create a few basic services, whose implementations are:
52 <li>com.sun.star.comp.loader.JavaLoader</li>
53 <li>com.sun.star.comp.urlresolver.UrlResolver</li>
54 <li>com.sun.star.comp.bridgefactory.BridgeFactory</li>
55 <li>com.sun.star.comp.connections.Connector</li>
56 <li>com.sun.star.comp.connections.Acceptor</li>
57 <li>com.sun.star.comp.servicemanager.ServiceManager</li>
60 Other services can be inserted into the service manager by
61 using its XSet interface:
63 XSet xSet = UnoRuntime.queryInterface( XSet.class, aMultiComponentFactory );
64 // insert the service manager
65 xSet.insert( aSingleComponentFactory );
68 public class Bootstrap
{
70 private static void insertBasicFactories(
71 XSet xSet
, XImplementationLoader xImpLoader
)
74 // insert the factory of the loader
75 xSet
.insert( xImpLoader
.activate(
76 "com.sun.star.comp.loader.JavaLoader", null, null, null ) );
78 // insert the factory of the URLResolver
79 xSet
.insert( xImpLoader
.activate(
80 "com.sun.star.comp.urlresolver.UrlResolver", null, null, null ) );
82 // insert the bridgefactory
83 xSet
.insert( xImpLoader
.activate(
84 "com.sun.star.comp.bridgefactory.BridgeFactory", null, null, null ) );
86 // insert the connector
87 xSet
.insert( xImpLoader
.activate(
88 "com.sun.star.comp.connections.Connector", null, null, null ) );
90 // insert the acceptor
91 xSet
.insert( xImpLoader
.activate(
92 "com.sun.star.comp.connections.Acceptor", null, null, null ) );
96 * Returns an array of default commandline options to start bootstrapped
97 * instance of soffice with. You may use it in connection with bootstrap
98 * method for example like this:
100 * List list = Arrays.asList( Bootstrap.getDefaultOptions() );
101 * list.remove("--nologo");
102 * list.remove("--nodefault");
103 * list.add("--invisible");
105 * Bootstrap.bootstrap( list.toArray( new String[list.size()] );
108 * @return an array of default commandline options
109 * @see #bootstrap( String[] )
110 * @since LibreOffice 5.1
112 public static final String
[] getDefaultOptions()
124 backwards compatibility stub.
125 @param context_entries the hash table contains mappings of entry names (type string) to
126 context entries (type class ComponentContextEntry).
127 @throws Exception if things go awry.
128 @return a new context.
130 public static XComponentContext
createInitialComponentContext( Hashtable
<String
, Object
> context_entries
)
133 return createInitialComponentContext((Map
<String
, Object
>) context_entries
);
135 /** Bootstraps an initial component context with service manager and basic
136 jurt components inserted.
137 @param context_entries the hash table contains mappings of entry names (type string) to
138 context entries (type class ComponentContextEntry).
139 @throws Exception if things go awry.
140 @return a new context.
142 public static XComponentContext
createInitialComponentContext( Map
<String
, Object
> context_entries
)
145 ServiceManager xSMgr
= new ServiceManager();
147 XImplementationLoader xImpLoader
= UnoRuntime
.queryInterface(
148 XImplementationLoader
.class, new JavaLoader() );
149 XInitialization xInit
= UnoRuntime
.queryInterface(
150 XInitialization
.class, xImpLoader
);
151 Object
[] args
= new Object
[] { xSMgr
};
152 xInit
.initialize( args
);
154 // initial component context
155 if (context_entries
== null)
156 context_entries
= new HashMap
<String
,Object
>( 1 );
159 "/singletons/com.sun.star.lang.theServiceManager",
160 new ComponentContextEntry( null, xSMgr
) );
161 // ... xxx todo: add standard entries
162 XComponentContext xContext
= new ComponentContext( context_entries
, null );
164 xSMgr
.setDefaultContext(xContext
);
166 XSet xSet
= UnoRuntime
.queryInterface( XSet
.class, xSMgr
);
167 // insert basic jurt factories
168 insertBasicFactories( xSet
, xImpLoader
);
174 * Bootstraps a servicemanager with the jurt base components registered.
176 * See also UNOIDL <code>com.sun.star.lang.ServiceManager</code>.
178 * @throws Exception if things go awry.
179 * @return a freshly bootstrapped service manager
181 public static XMultiServiceFactory
createSimpleServiceManager() throws Exception
183 return UnoRuntime
.queryInterface(
184 XMultiServiceFactory
.class, createInitialComponentContext( (Map
<String
, Object
>) null ).getServiceManager() );
188 /** Bootstraps the initial component context from a native UNO installation.
190 @throws Exception if things go awry.
191 @return a freshly bootstrapped component context.
194 <code>cppuhelper/defaultBootstrap_InitialComponentContext()</code>.
196 public static final XComponentContext
defaultBootstrap_InitialComponentContext()
199 return defaultBootstrap_InitialComponentContext( (String
) null, (Map
<String
,String
>) null );
202 * Backwards compatibility stub.
205 * ini_file (may be null: uno.rc besides cppuhelper lib)
206 * @param bootstrap_parameters
207 * bootstrap parameters (maybe null)
209 * @throws Exception if things go awry.
210 * @return a freshly bootstrapped component context.
212 public static final XComponentContext
defaultBootstrap_InitialComponentContext(
213 String ini_file
, Hashtable
<String
,String
> bootstrap_parameters
)
216 return defaultBootstrap_InitialComponentContext(ini_file
, (Map
<String
,String
>) bootstrap_parameters
);
219 /** Bootstraps the initial component context from a native UNO installation.
222 <code>cppuhelper/defaultBootstrap_InitialComponentContext()</code>.
225 ini_file (may be null: uno.rc besides cppuhelper lib)
226 @param bootstrap_parameters
227 bootstrap parameters (maybe null)
229 @throws Exception if things go awry.
230 @return a freshly bootstrapped component context.
232 public static final XComponentContext
defaultBootstrap_InitialComponentContext(
233 String ini_file
, Map
<String
,String
> bootstrap_parameters
)
236 // jni convenience: easier to iterate over array than calling Hashtable
237 String pairs
[] = null;
238 if (null != bootstrap_parameters
)
240 pairs
= new String
[ 2 * bootstrap_parameters
.size() ];
242 for (Map
.Entry
<String
, String
> bootstrap_parameter
: bootstrap_parameters
.entrySet()) {
243 pairs
[ n
++ ] = bootstrap_parameter
.getKey();
244 pairs
[ n
++ ] = bootstrap_parameter
.getValue();
250 if ("The Android Project".equals(System
.getProperty("java.vendor")))
252 // Find out if we are configured with DISABLE_DYNLOADING or
253 // not. Try to load the lo-bootstrap shared library which
254 // won't exist in the DISABLE_DYNLOADING case. (And which will
255 // be already loaded otherwise, so nothing unexpected happens
256 // that case.) Yeah, this would be simpler if I just could be
257 // bothered to keep a separate branch for DISABLE_DYNLOADING
258 // on Android, merging in master periodically, until I know
259 // for sure whether it is what I want, or not.
261 boolean disable_dynloading
= false;
263 System
.loadLibrary( "lo-bootstrap" );
264 } catch ( UnsatisfiedLinkError e
) {
265 disable_dynloading
= true;
268 if (!disable_dynloading
)
270 NativeLibraryLoader
.loadLibrary( Bootstrap
.class.getClassLoader(), "juh" );
275 NativeLibraryLoader
.loadLibrary( Bootstrap
.class.getClassLoader(), "juh" );
279 return UnoRuntime
.queryInterface(
280 XComponentContext
.class,
281 cppuhelper_bootstrap(
282 ini_file
, pairs
, Bootstrap
.class.getClassLoader() ) );
285 private static boolean m_loaded_juh
= false;
286 private static native Object
cppuhelper_bootstrap(
287 String ini_file
, String bootstrap_parameters
[], ClassLoader loader
)
291 * Bootstraps the component context from a UNO installation.
293 * @throws BootstrapException if things go awry.
295 * @return a bootstrapped component context.
299 public static final XComponentContext
bootstrap()
300 throws BootstrapException
{
302 String
[] defaultArgArray
= getDefaultOptions();
303 return bootstrap( defaultArgArray
);
307 * Bootstraps the component context from a UNO installation.
310 * an array of strings - commandline options to start instance of
312 * @see #getDefaultOptions()
314 * @throws BootstrapException if things go awry.
316 * @return a bootstrapped component context.
318 * @since LibreOffice 5.1
320 public static final XComponentContext
bootstrap( String
[] argArray
)
321 throws BootstrapException
{
323 XComponentContext xContext
= null;
326 // create default local component context
327 XComponentContext xLocalContext
=
328 createInitialComponentContext( (Map
<String
, Object
>) null );
329 if ( xLocalContext
== null )
330 throw new BootstrapException( "no local component context!" );
332 // find office executable relative to this class's class loader
334 System
.getProperty( "os.name" ).startsWith( "Windows" ) ?
335 "soffice.exe" : "soffice";
336 File fOffice
= NativeLibraryLoader
.getResource(
337 Bootstrap
.class.getClassLoader(), sOffice
);
338 if ( fOffice
== null )
339 throw new BootstrapException( "no office executable found!" );
341 // create random pipe name
342 String sPipeName
= "uno" +
343 Long
.toString(randomPipeName
.nextLong() & 0x7fffffffffffffffL
);
345 // create call with arguments
346 String
[] cmdArray
= new String
[ argArray
.length
+ 2 ];
347 cmdArray
[0] = fOffice
.getPath();
348 cmdArray
[1] = ( "--accept=pipe,name=" + sPipeName
+ ";urp;" );
350 System
.arraycopy( argArray
, 0, cmdArray
, 2, argArray
.length
);
352 // start office process
353 Process p
= Runtime
.getRuntime().exec( cmdArray
);
354 pipe( p
.getInputStream(), System
.out
, "CO> " );
355 pipe( p
.getErrorStream(), System
.err
, "CE> " );
357 // initial service manager
358 XMultiComponentFactory xLocalServiceManager
=
359 xLocalContext
.getServiceManager();
360 if ( xLocalServiceManager
== null )
361 throw new BootstrapException( "no initial service manager!" );
363 // create a URL resolver
364 XUnoUrlResolver xUrlResolver
=
365 UnoUrlResolver
.create( xLocalContext
);
368 String sConnect
= "uno:pipe,name=" + sPipeName
+
369 ";urp;StarOffice.ComponentContext";
371 // wait until office is started
372 for (int i
= 0;; ++i
) {
374 // try to connect to office
375 Object context
= xUrlResolver
.resolve( sConnect
);
376 xContext
= UnoRuntime
.queryInterface(
377 XComponentContext
.class, context
);
378 if ( xContext
== null )
379 throw new BootstrapException( "no component context!" );
381 } catch ( com
.sun
.star
.connection
.NoConnectException ex
) {
382 // Wait 500 ms, then try to connect again, but do not wait
383 // longer than 5 min (= 600 * 500 ms) total:
385 throw new BootstrapException(ex
);
390 } catch ( BootstrapException e
) {
392 } catch ( java
.lang
.RuntimeException e
) {
394 } catch ( java
.lang
.Exception e
) {
395 throw new BootstrapException( e
);
402 * Bootstraps the component context from a websocket location.
405 * the ws:// or wss:// url of the websocket server
407 * @throws BootstrapException if things go awry.
409 * @return a bootstrapped component context.
411 * @since LibreOffice 24.2
413 public static final XComponentContext
bootstrapWebsocketConnection( String url
)
414 throws BootstrapException
{
416 XComponentContext xContext
= null;
419 // create default local component context
420 XComponentContext xLocalContext
=
421 createInitialComponentContext( (Map
<String
, Object
>) null );
422 if ( xLocalContext
== null )
423 throw new BootstrapException( "no local component context!" );
425 // initial service manager
426 XMultiComponentFactory xLocalServiceManager
=
427 xLocalContext
.getServiceManager();
428 if ( xLocalServiceManager
== null )
429 throw new BootstrapException( "no initial service manager!" );
431 // create a URL resolver
432 XUnoUrlResolver xUrlResolver
=
433 UnoUrlResolver
.create( xLocalContext
);
436 String sConnect
= "uno:websocket"
438 + ";urp;StarOffice.ComponentContext";
441 // try to connect to office
442 Object xOfficeServiceManager
= xUrlResolver
.resolve(sConnect
);
444 xContext
= UnoRuntime
.queryInterface(XComponentContext
.class, xOfficeServiceManager
);
446 if ( xContext
== null )
447 throw new BootstrapException( "no component context!" );
448 } catch ( com
.sun
.star
.connection
.NoConnectException ex
) {
449 throw new BootstrapException(ex
);
451 } catch ( BootstrapException e
) {
453 } catch ( java
.lang
.RuntimeException e
) {
455 } catch ( java
.lang
.Exception e
) {
456 throw new BootstrapException( e
);
463 private static final Random randomPipeName
= new Random();
465 private static void pipe(
466 final InputStream in
, final PrintStream out
, final String prefix
) {
468 new Thread( "Pipe: " + prefix
) {
472 BufferedReader r
= new BufferedReader(
473 new InputStreamReader(in
, "UTF-8") );
476 String s
= r
.readLine();
480 out
.println( prefix
+ s
);
482 } catch ( UnsupportedEncodingException e
) {
483 e
.printStackTrace( System
.err
);
484 } catch ( java
.io
.IOException e
) {
485 e
.printStackTrace( System
.err
);
492 // vim:set shiftwidth=4 softtabstop=4 expandtab: