xref: /AOO41X/main/javaunohelper/com/sun/star/comp/helper/Bootstrap.java (revision ff0525f24f03981d56b7579b645949f111420994)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package com.sun.star.comp.helper;
25 
26 import com.sun.star.bridge.UnoUrlResolver;
27 import com.sun.star.bridge.XUnoUrlResolver;
28 import com.sun.star.comp.loader.JavaLoader;
29 import com.sun.star.container.XSet;
30 import com.sun.star.lang.XInitialization;
31 import com.sun.star.lang.XMultiServiceFactory;
32 import com.sun.star.lang.XMultiComponentFactory;
33 import com.sun.star.lang.XSingleComponentFactory;
34 import com.sun.star.lib.util.NativeLibraryLoader;
35 import com.sun.star.loader.XImplementationLoader;
36 import com.sun.star.uno.UnoRuntime;
37 import com.sun.star.uno.XComponentContext;
38 
39 import java.io.BufferedReader;
40 import java.io.File;
41 import java.io.InputStream;
42 import java.io.InputStreamReader;
43 import java.io.PrintStream;
44 import java.util.Enumeration;
45 import java.util.Hashtable;
46 import java.util.Random;
47 
48 /** Bootstrap offers functionality to obtain a context or simply
49     a service manager.
50     The service manager can create a few basic services, whose implementations  are:
51     <ul>
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>
58     </ul>
59 
60     Other services can be inserted into the service manager by
61     using its XSet interface:
62     <pre>
63         XSet xSet = UnoRuntime.queryInterface( XSet.class, aMultiComponentFactory );
64         // insert the service manager
65         xSet.insert( aSingleComponentFactory );
66     </pre>
67 */
68 public class Bootstrap {
69 
70     private static void insertBasicFactories(
71         XSet xSet, XImplementationLoader xImpLoader )
72         throws Exception
73     {
74         // insert the factory of the loader
75         xSet.insert( xImpLoader.activate(
76             "com.sun.star.comp.loader.JavaLoader", null, null, null ) );
77 
78         // insert the factory of the URLResolver
79         xSet.insert( xImpLoader.activate(
80             "com.sun.star.comp.urlresolver.UrlResolver", null, null, null ) );
81 
82         // insert the bridgefactory
83         xSet.insert( xImpLoader.activate(
84             "com.sun.star.comp.bridgefactory.BridgeFactory", null, null, null ) );
85 
86         // insert the connector
87         xSet.insert( xImpLoader.activate(
88             "com.sun.star.comp.connections.Connector", null, null, null ) );
89 
90         // insert the acceptor
91         xSet.insert( xImpLoader.activate(
92             "com.sun.star.comp.connections.Acceptor", null, null, null ) );
93     }
94 
95     /** Bootstraps an initial component context with service manager and basic
96         jurt components inserted.
97         @param context_entries the hash table contains mappings of entry names (type string) to
98         context entries (type class ComponentContextEntry).
99         @return a new context.
100     */
101     static public XComponentContext createInitialComponentContext( Hashtable context_entries )
102         throws Exception
103     {
104         XImplementationLoader xImpLoader = UnoRuntime.queryInterface(
105             XImplementationLoader.class, new JavaLoader() );
106 
107         // Get the factory of the ServiceManager
108         XSingleComponentFactory smgr_fac = UnoRuntime.queryInterface(
109             XSingleComponentFactory.class, xImpLoader.activate(
110                 "com.sun.star.comp.servicemanager.ServiceManager", null, null, null ) );
111 
112         // Create an instance of the ServiceManager
113         XMultiComponentFactory xSMgr = UnoRuntime.queryInterface(
114             XMultiComponentFactory.class, smgr_fac.createInstanceWithContext( null ) );
115 
116         // post init loader
117         XInitialization xInit = UnoRuntime.queryInterface(
118             XInitialization.class, xImpLoader );
119         Object[] args = new Object [] { xSMgr };
120         xInit.initialize( args );
121 
122         // initial component context
123         if (context_entries == null)
124             context_entries = new Hashtable( 1 );
125         // add smgr
126         context_entries.put(
127             "/singletons/com.sun.star.lang.theServiceManager",
128             new ComponentContextEntry( null, xSMgr ) );
129         // ... xxx todo: add standard entries
130         XComponentContext xContext = new ComponentContext( context_entries, null );
131 
132         // post init smgr
133         xInit = UnoRuntime.queryInterface(
134             XInitialization.class, xSMgr );
135         args = new Object [] { null, xContext }; // no registry, default context
136         xInit.initialize( args );
137 
138         XSet xSet = UnoRuntime.queryInterface( XSet.class, xSMgr );
139         // insert the service manager
140         xSet.insert( smgr_fac );
141         // and basic jurt factories
142         insertBasicFactories( xSet, xImpLoader );
143 
144         return xContext;
145     }
146 
147     /**
148      * Bootstraps a servicemanager with the jurt base components registered.
149      * <p>
150      * @return     a freshly boostrapped service manager
151      * @see        com.sun.star.lang.ServiceManager
152      */
153     static public XMultiServiceFactory createSimpleServiceManager() throws Exception
154     {
155         return UnoRuntime.queryInterface(
156             XMultiServiceFactory.class, createInitialComponentContext( null ).getServiceManager() );
157     }
158 
159 
160     /** Bootstraps the initial component context from a native UNO installation.
161 
162         @see cppuhelper/defaultBootstrap_InitialComponentContext()
163     */
164     static public final XComponentContext defaultBootstrap_InitialComponentContext()
165         throws Exception
166     {
167         return defaultBootstrap_InitialComponentContext( null, null );
168     }
169     /** Bootstraps the initial component context from a native UNO installation.
170 
171         @param ini_file
172                ini_file (may be null: uno.rc besides cppuhelper lib)
173         @param bootstrap_parameters
174                bootstrap parameters (maybe null)
175 
176         @see cppuhelper/defaultBootstrap_InitialComponentContext()
177     */
178     static public final XComponentContext defaultBootstrap_InitialComponentContext(
179         String ini_file, Hashtable bootstrap_parameters )
180         throws Exception
181     {
182         // jni convenience: easier to iterate over array than calling Hashtable
183         String pairs [] = null;
184         if (null != bootstrap_parameters)
185         {
186             pairs = new String [ 2 * bootstrap_parameters.size() ];
187             Enumeration keys = bootstrap_parameters.keys();
188             int n = 0;
189             while (keys.hasMoreElements())
190             {
191                 String name = (String)keys.nextElement();
192                 pairs[ n++ ] = name;
193                 pairs[ n++ ] = (String)bootstrap_parameters.get( name );
194             }
195         }
196 
197         if (! m_loaded_juh)
198         {
199             NativeLibraryLoader.loadLibrary( Bootstrap.class.getClassLoader(), "juh" );
200             m_loaded_juh = true;
201         }
202         return UnoRuntime.queryInterface(
203             XComponentContext.class,
204             cppuhelper_bootstrap(
205                 ini_file, pairs, Bootstrap.class.getClassLoader() ) );
206     }
207 
208     static private boolean m_loaded_juh = false;
209     static private native Object cppuhelper_bootstrap(
210         String ini_file, String bootstrap_parameters [], ClassLoader loader )
211         throws Exception;
212 
213     /**
214      * Bootstraps the component context from a UNO installation.
215      *
216      * @return a bootstrapped component context.
217      *
218      * @since UDK 3.1.0
219      */
220     public static final XComponentContext bootstrap()
221         throws BootstrapException {
222 
223         XComponentContext xContext = null;
224 
225         try {
226             // create default local component context
227             XComponentContext xLocalContext =
228                 createInitialComponentContext( null );
229             if ( xLocalContext == null )
230                 throw new BootstrapException( "no local component context!" );
231 
232             // find office executable relative to this class's class loader
233             String sOffice =
234                 System.getProperty( "os.name" ).startsWith( "Windows" ) ?
235                 "soffice.exe" : "soffice";
236             File fOffice = NativeLibraryLoader.getResource(
237                 Bootstrap.class.getClassLoader(), sOffice );
238             if ( fOffice == null )
239                 throw new BootstrapException( "no office executable found!" );
240 
241             // create random pipe name
242             String sPipeName = "uno" +
243                 Long.toString( (new Random()).nextLong() & 0x7fffffffffffffffL );
244 
245             // create call with arguments
246             String[] cmdArray = new String[7];
247             cmdArray[0] = fOffice.getPath();
248             cmdArray[1] = "-nologo";
249             cmdArray[2] = "-nodefault";
250             cmdArray[3] = "-norestore";
251             cmdArray[4] = "-nocrashreport";
252             cmdArray[5] = "-nolockcheck";
253             cmdArray[6] = "-accept=pipe,name=" + sPipeName + ";urp;";
254 
255             // start office process
256             Process p = Runtime.getRuntime().exec( cmdArray );
257             pipe( p.getInputStream(), System.out, "CO> " );
258             pipe( p.getErrorStream(), System.err, "CE> " );
259 
260             // initial service manager
261             XMultiComponentFactory xLocalServiceManager =
262                 xLocalContext.getServiceManager();
263             if ( xLocalServiceManager == null )
264                 throw new BootstrapException( "no initial service manager!" );
265 
266             // create a URL resolver
267             XUnoUrlResolver xUrlResolver =
268                 UnoUrlResolver.create( xLocalContext );
269 
270             // connection string
271             String sConnect = "uno:pipe,name=" + sPipeName +
272                 ";urp;StarOffice.ComponentContext";
273 
274             // wait until office is started
275             for (int i = 0;; ++i) {
276                 try {
277                     // try to connect to office
278                     Object context = xUrlResolver.resolve( sConnect );
279                     xContext = UnoRuntime.queryInterface(
280                         XComponentContext.class, context);
281                     if ( xContext == null )
282                         throw new BootstrapException( "no component context!" );
283                     break;
284                 } catch ( com.sun.star.connection.NoConnectException ex ) {
285                     // Wait 500 ms, then try to connect again, but do not wait
286                     // longer than 5 min (= 600 * 500 ms) total:
287                     if (i == 600) {
288                         throw new BootstrapException(ex.toString());
289                     }
290                     Thread.currentThread().sleep( 500 );
291                 }
292             }
293         } catch ( BootstrapException e ) {
294             throw e;
295         } catch ( java.lang.RuntimeException e ) {
296             throw e;
297         } catch ( java.lang.Exception e ) {
298             throw new BootstrapException( e );
299         }
300 
301         return xContext;
302     }
303 
304     private static void pipe(
305         final InputStream in, final PrintStream out, final String prefix ) {
306 
307         new Thread( "Pipe: " + prefix) {
308             public void run() {
309                 BufferedReader r = new BufferedReader(
310                     new InputStreamReader( in ) );
311                 try {
312                     for ( ; ; ) {
313                         String s = r.readLine();
314                         if ( s == null ) {
315                             break;
316                         }
317                         out.println( prefix + s );
318                     }
319                 } catch ( java.io.IOException e ) {
320                     e.printStackTrace( System.err );
321                 }
322             }
323         }.start();
324     }
325 }
326