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