001    /*
002     * Copyright (c) 2009 The openGion Project.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
013     * either express or implied. See the License for the specific language
014     * governing permissions and limitations under the License.
015     */
016    package org.opengion.hayabusa.report2;
017    
018    import java.io.File;
019    import java.io.IOException;
020    
021    import org.opengion.fukurou.util.FileUtil;
022    import org.opengion.fukurou.util.StringUtil;
023    import org.opengion.hayabusa.common.HybsSystem;
024    import org.opengion.hayabusa.common.HybsSystemException;
025    
026    import com.sun.star.bridge.UnoUrlResolver;
027    import com.sun.star.bridge.XUnoUrlResolver;
028    import com.sun.star.comp.helper.Bootstrap;
029    import com.sun.star.comp.helper.BootstrapException;
030    import com.sun.star.frame.XDesktop;
031    import com.sun.star.frame.XDispatchHelper;
032    import com.sun.star.lang.XMultiComponentFactory;
033    import com.sun.star.uno.UnoRuntime;
034    import com.sun.star.uno.XComponentContext;
035    
036    /**
037     * OpenOfficeのプロセスを表すクラスです?
038     *
039     * bootstrap()メソ?が呼ばれたタイミングでsoffice.binのプロセスを生成します?
040     * soffice.binのプロセスを引数なしで実?た?合?通常は?ーザーで1プロセスしか
041     * 生?されな?め?-env:UserInstallationの引数を指定することで、仮想?別ユーザー
042     * として起動して?す?
043     * こ?"ユーザー"を表すキーは、コンストラクタの引数のidです?
044     *
045     * また?こ?仮想ユーザーで起動した?合?初回起動時にユーザー登録を?画面が立ち上がります?
046     * これを回避するため、デフォルト?環?ァイルを?ロセス生?前にコピ?することで、認証済みの
047     * 状態で立ち上がるよ?して?す?
048     *
049     * 起動した?ロセスとの通知は名前付きパイプで行われます?パイプ名は?env"+コンストラクタのidです?
050     * プロセス起動と、名前付きパイプでの接続?非同期で行われます?
051     * プロセス起動後?60秒経過しても接続できな??合?、BootstrapExceptionが発生します?
052     *
053     * @version  4.0
054     * @author   Hiroki Nakamura
055     * @since    JDK5.0,
056     */
057    public class SOfficeProcess {
058    
059            /** OOoのインスト?ル?レクトリ  */
060            public static final String OFFICE_HOME =
061                    ( new File ( System.getenv( "OFFICE_HOME" ) ).getAbsolutePath() ) + File.separator;
062    
063            /** 設定ファイルの雛形 */
064            private static final String DEFAULT_ENV_PATH =
065                    OFFICE_HOME + "env" + File.separator + "_default";
066    
067            /** soffice.binのパス */
068            private static final String SOFFICE_BIN =
069                    OFFICE_HOME + File.separator + "program" + File.separator + "soffice.bin";
070    
071            /** ローカルコン?ス?*/
072            private static XComponentContext xLocalContext = null;
073            static {
074                    try {
075                            xLocalContext = Bootstrap.createInitialComponentContext( null );
076                    }
077                    catch( Throwable th ) {
078                            System.out.println( "[ERROR]OOo:Can't start LocalContext,Check OFFICE_HOME!" );
079                            th.printStackTrace();
080                    }
081            }
082    
083            /** リモートデスクトップインスタンス */
084            @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
085            private XDesktop desktop        = null;
086    
087            private XComponentContext remoteContext = null;
088    
089            /** soffice.binのプロセス */
090            private Process process         = null;
091    
092            /** 環?定?パス */
093            // 5.1.7.0 (2010/06/01) ?サーバ?対応漏れ
094    //      public static final String ENV_DIR = HybsSystem.url2dir( HybsSystem.sys( "FILE_URL" ) + "oooenv" ) + File.separator;
095            public static final String ENV_DIR = HybsSystem.url2dir( StringUtil.nval( HybsSystem.sys( "REPORT_FILE_URL" )
096                                                                                                                                                            , HybsSystem.sys( "FILE_URL" ) + "REPORT" + File.separator )
097                                                                                                                            + "oooenv" ) + File.separator;
098            private final String envPath;
099    
100            /** 環?定ファイルのID */
101            private final String envId;
102    
103            /**
104             * コンストラクタです?
105             *
106             * @og.rev 4.3.0.0 (2008/07/15) 設定ファイルを各コン?ストごとに置くよ?変更
107             * @param       id      プロセスID
108             */
109            protected SOfficeProcess( final String id ) {
110                    envId = id;
111                    // envPath = OFFICE_HOME + "env" + File.separator + envId;
112                    envPath = ENV_DIR + envId;
113            }
114    
115            /**
116             * OOoへの接続を行います?
117             *
118             * @og.rev 5.0.0.0 (2009/08/03) Linux対?パイプ名に":"が含まれて?と接続できな?
119             * @og.rev 5.1.7.0 (2010/06/01) TCP接続対?
120             */
121            @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
122            protected void bootstrap() {
123                    System.out.println( "[INFO]OOo:Starting soffice process,ENV-ID=" + envId );
124    
125                    // check enviroment files, if no files, create from default files
126                    checkEnv( envPath );
127    
128                    // pipe name
129                    // 4.3.3.6 (2008/11/15) マルチサーバ対応?同?ーバでの?実行時不?合?ため?
130                    // 5.0.0.0 (2009/08/03) Linux対?
131                    //String sPipeName = "uno" + envId;
132                    String sPipeName = "uno" + "_" + HybsSystem.sys("HOST_URL").replace(':','_').replace('/','_') + "_" + envId;
133    
134                    // start office process
135                    // 5.5.2.4 (2012/05/16) int priority は使われて???で、削除します?
136    //              process = execOffice( envPath, sPipeName, 0 );
137                    process = execOffice( envPath, sPipeName );
138                    System.out.println( "[INFO]OOo:Invoke soffice.bin,ENV-ID=" + envId );
139    
140                    // create a URL resolver
141                    XUnoUrlResolver xUrlResolver = UnoUrlResolver.create( xLocalContext );
142    
143                    // connection string
144                    // 5.1.7.0 (2010/06/01) TCP接続対?
145    //              String sConnect = "uno:pipe,name=" + sPipeName + ";urp;StarOffice.ComponentContext";
146                    String sConnect = getConnParam( sPipeName );
147    
148                    // wait until office is started
149    //              XComponentContext xContext = null;
150                    try {
151                            for( int i = 0;; ++i ) {
152                                    try {
153                                            Object context = xUrlResolver.resolve( sConnect );
154                                            remoteContext = (XComponentContext) UnoRuntime.queryInterface( XComponentContext.class, context );
155                                            if( remoteContext == null ) { throw new BootstrapException( "no component context!" ); }
156                                            break;
157                                    }
158                                    catch( com.sun.star.connection.NoConnectException ex ) {
159                                            System.out.println( "[INFO]OOo:Waiting for Connect soffice process,ENV-ID=" + envId );
160                                            if( i == 60 ) { throw new BootstrapException( ex ); }
161                                            Thread.sleep( 1000 );
162                                    }
163                            }
164    
165                            // create desktop instance
166                            XMultiComponentFactory componentFactory = remoteContext.getServiceManager();
167                            desktop = (XDesktop) UnoRuntime.queryInterface( XDesktop.class, componentFactory.createInstanceWithContext( "com.sun.star.frame.Desktop", remoteContext ) );
168                    }
169                    catch ( Exception ex ) {
170                            throw new HybsSystemException( "[ERROR] Can't create Desktop Instance", ex );
171                    }
172    
173                    System.out.println( "[INFO]OOo:Connected successful,ENV-ID=" + envId );
174            }
175    
176            /**
177             * Pipe名をキーにOpenOfficeのプロセスに接続するため???を生成します?
178             *
179             * @param key Pipe?
180             *
181             * @return 接続文字?
182             */
183            protected String getConnParam( final String key ) {
184                    return "uno:pipe,name=" + key + ";urp;StarOffice.ComponentContext";
185            }
186    
187            /**
188             * ?クトップインスタンスを返しま?
189             *
190             * @return ?クトップインスタンス
191             */
192            public XDesktop getDesktop() {
193                    return desktop;
194            }
195    
196            /**
197             * プロセスを終?ます?
198             * また?同時に環?定用のファイルも削除します?
199             */
200            public void close() {
201                    process.destroy();
202                    FileUtil.deleteFiles( new File( envPath ) );
203                    System.out.println( "[INFO]OOo:Destroy process,ENV-ID=" + envId );
204            }
205    
206            /**
207             * soffice.binを起動します?
208             *
209             * @og.rev 5.1.7.0 (2010/06/01) TCP接続対?
210             * @og.rev 5.5.2.4 (2012/05/16) int priority は使われて???で、削除します?
211             *
212             * @param envPath String
213             * @param pipeName String
214             *
215             * @return soffice.binのプロセス
216             */
217    //      private Process execOffice( final String envPath, final String pipeName, final int priority ) {
218            private Process execOffice( final String envPath, final String pipeName ) {
219                    String[] cmdArray = new String[11];
220                    cmdArray[0] = SOFFICE_BIN;
221                    cmdArray[1] = "-nologo";
222                    cmdArray[2] = "-nodefault";
223                    cmdArray[3] = "-norestore";
224                    cmdArray[4] = "-nocrashreport";
225                    cmdArray[5] = "-nolockcheck";
226                    cmdArray[6] = "-minimized";
227                    cmdArray[7] = "-invisible";
228                    cmdArray[8] = "-headless";
229                    cmdArray[9] = "-env:UserInstallation=file:///" + ( envPath ).replace( '\\', '/' );
230                    // 5.1.7.0 (2010/06/01) TCP接続対?
231    //              cmdArray[10] = "-accept=pipe,name=" + pipeName + ";urp;";
232                    cmdArray[10] = getProcParam( pipeName );
233    
234                    Process process;
235                    try {
236                            process = Runtime.getRuntime().exec( cmdArray );
237                    } catch ( IOException ex ) {
238                            throw new HybsSystemException( "[ERROR] Cant't exec soffice.bin", ex );
239                    }
240    //              pipe( process.getInputStream(), System.out, "CO> " );
241    //              pipe( process.getErrorStream(), System.err, "CE> " );
242    
243                    return process;
244            }
245    
246            /**
247             * Pipe名をキーにOpenOfficeのプロセスを生成するため?パラメーター??を生成します?
248             *
249             * @param key Pipe?
250             *
251             * @return プロセス生?パラメーター
252             */
253            protected String getProcParam( final String key ) {
254                    return "-accept=pipe,name=" + key + ";urp;";
255            }
256    
257            /**
258             * OOoの環?定ファイルをコピ?します?
259             *
260             * ※ OFFICE_HOMEが設定されて???合?HybsSystemException が?throw されます?
261             *
262             * @og.rev 4.3.0.0 (2008/07/24) OS依存を?てJavaでコピ?する
263             *
264             * @param envPath String
265             */
266            private void checkEnv( final String envPath ) {
267    
268                    if( OFFICE_HOME == null || OFFICE_HOME.length() == 0 ) {
269                            throw new HybsSystemException( "OFFICE_HOMEが設定されて??め?OpenOfficeを起動できません" );
270                    }
271    
272    //              File file = new File( envPath ); // ??ァイルが消えて?かった時のため、常にコピ?
273    //              if( !file.exists() || !file.isDirectory() ) {
274    //                      String[] cmdArray = new String[7];
275    //                      cmdArray[0] = "xcopy";
276    //                      cmdArray[1] = "/e";
277    //                      cmdArray[2] = "/q";
278    //                      cmdArray[3] = "/y";
279    //                      cmdArray[4] = "/i";
280    //                      cmdArray[5] = DEFAULT_ENV_PATH;
281    //                      cmdArray[6] = envPath;
282    //
283    //                      Process proc = Runtime.getRuntime().exec( cmdArray );
284    //                      proc.waitFor();
285    
286    //              }
287                    // 4.3.0.0 (2008/07/24) OS依存からFileUtilを使??変更
288                    FileUtil.copyDirectry( DEFAULT_ENV_PATH, envPath );
289    
290                    // 5.1.7.0 (2010/06/01) ファイルマ?ジ対?
291                    if( ! ( new File( getTempPath() ) ).mkdirs() ) {
292                            System.err.println( "ファイルマ?ジ時??ポラリフォル?作?できませんでした?" + getTempPath() + "]" );
293                    }
294            }
295    
296            /**
297             * OpenOfficeのローカルコンポ?ネントコン?ストを返します?
298             *
299             * @og.rev 5.1.7.0 (2010/06/01) 新規作?
300             *
301             * @return ローカルコンポ?ネントコン?ス?
302             */
303            @SuppressWarnings("cast")       // OpenOffice 3.2 での冗長なキャスト警告?抑止。キャストをはずすと、旧3.1 では、エラーになる?
304            public XDispatchHelper getDispatcher() {
305                    XMultiComponentFactory componentFactory = remoteContext.getServiceManager();
306                    XDispatchHelper dispatcher = null;
307                    try {
308                            dispatcher = (XDispatchHelper) UnoRuntime.queryInterface( XDispatchHelper.class, componentFactory.createInstanceWithContext( "com.sun.star.frame.DispatchHelper", remoteContext ) );
309                    }
310                    catch( com.sun.star.uno.Exception ex ) {
311                            throw new HybsSystemException( "?スパッチャーの取得に失敗しました?, ex );
312                    }
313                    return dispatcher;
314            }
315    
316            /**
317             * こ?プロセスに対して固有に使用できる?ファイルのパスを指定します?
318             *
319             * @og.rev 5.1.7.0 (2010/06/01) 新規作?
320             *
321             * @return ?ファイルのパス
322             */
323            public String getTempPath() {
324                    return envPath + File.separator + "temp" + File.separator;
325            }
326    }
327