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