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 */ 016package org.opengion.hayabusa.report2; 017 018import java.io.File; 019import java.util.Map; 020import java.util.HashMap; 021import java.util.Locale; 022 023import org.opengion.fukurou.system.HybsConst; // 8.0.1.0 (2021/10/29) 024import org.opengion.fukurou.util.FileUtil; 025import org.opengion.fukurou.util.StringUtil; 026import org.opengion.hayabusa.common.HybsSystem; 027import org.opengion.hayabusa.common.HybsSystemException; 028import static org.opengion.fukurou.system.HybsConst.CR ; // 6.1.0.0 (2014/12/26) 029 030import com.sun.star.beans.PropertyValue; 031import com.sun.star.frame.XComponentLoader; 032import com.sun.star.frame.XController; 033import com.sun.star.frame.XDispatchHelper; 034import com.sun.star.frame.XDispatchProvider; 035import com.sun.star.frame.XModel; 036import com.sun.star.frame.XStorable; 037import com.sun.star.io.IOException; 038import com.sun.star.lang.EventObject; 039import com.sun.star.lang.IllegalArgumentException; 040import com.sun.star.lang.XComponent; 041import com.sun.star.uno.UnoRuntime; 042import com.sun.star.util.CloseVetoException; 043import com.sun.star.util.XCloseable; 044import com.sun.star.view.PrintJobEvent; 045import com.sun.star.view.PrintableState; 046import com.sun.star.view.XPrintJobBroadcaster; 047import com.sun.star.view.XPrintJobListener; 048import com.sun.star.view.XPrintable; 049 050/** 051 * OpenOfficeを利用して様々な形式のファイルを読み込み、出力・印刷を行うための変換クラスです。 052 * 053 * 変換を行うことのできる入出力のフォーマット以下の通りです。 054 * 055 * [対応フォーマット] 056 * 入力[Calc(ods) ,Excel(xls) ] ⇒ 出力[Calc(ods) ,Excel(xls,xlsx) ,PDF] 057 * 入力[Writer(odt) ,Word(doc) ] ⇒ 出力[Writer(odt) ,Word(doc,docx) ,PDF] 058 * 入力[Impress(odp),PowerPoint(ppt)] ⇒ 出力[Impress(odp),PowerPoint(ppt,pptx) ,PDF] 059 * 入力[ * 上記の全て ] ⇒ 印刷 060 * 061 * ※ xlsx,docx,pptx は、MS 2007形式の為、LibreOffice のみ利用できます。 062 * 063 * 変換を行うには、以下の2通りの方法があります。 064 * (1)簡易的な変換メソッドを利用する場合 065 * {@link #convert(String, String)}を利用して、変換を行います。 066 * この場合、出力形式は、出力ファイルの拡張子に従って自動的に決定されます。 067 * このため、印刷処理などを行う場合は、(2)の方法で出力して下さい。 068 * (2)段階的に書くメソッドを呼び出して変換する場合 069 * オブジェクトを生成した後、{@link #open()}、#(各種変換メソッド)、{@link #clone()}を 070 * 順番に呼び出して変換を行います。 071 * この場合、出力形式は、それに対応するメソッドを呼び出ることで決定されます。 072 * 073 * また、変換を行うための、各種メソッドは、例外としてThrowableを投げるように定義されています。 074 * このクラスを利用する場合は、このThrowableをcatchし、catch句で、必ず{@link #close( boolean )}に、 075 * "true"(エラー発生時のクローズ処理)を指定して、終了処理を行って下さい。 076 * (これを行わない場合、OpenOfficeの不要なプロセスが残ってしまう可能性があります) 077 * 078 * また、出力ファイルが既に存在する場合、出力ファイルは一旦削除された後、処理されます。 079 * なお、入力ファイルと出力ファイルが同じ場合、何も処理されません。(例外も発行されません) 080 * 081 * 入力ファイルを、CSV形式で複数指定した場合、複数の入力ファイルをマージして出力します。 082 * ※1 現状は、ファイルのマージは、入力ファイルがExcelまたはCalcの場合のみ対応しています。 083 * 084 * ※ DocConverter は、クラウド対応されていません。変換時はローカルファイル間で行ってください。 085 * 086 * @og.group 帳票システム 087 * 088 * @version 4.0 089 * @author Hiroki.Nakamura 090 * @since JDK1.6 091 */ 092public class DocConverter_OOO { 093 private static final String OFFICE_VER = HybsConst.getenv( "OPENOFFICE_VER","NULL" ); // 8.0.1.0 (2021/10/29) 環境変数から取得 094 095 private final boolean isOnline; // オンライン処理かどうか(オンライン処理の場合、プロセスはファクトリクラス経由で生成されます) 096 private final String[] mergeFile; 097 098 private String inputName; 099 private String origName; 100 101 private XComponent xComp; // 5.1.8.0 (2010/07/01) メソッドと重なる変数名の変更 102 private SOfficeProcess soffice; 103 104 // 入力、出力の拡張子とこれに対応するフィルター名 105 // \share\config\registry\instance\org\openoffice\office\TypeDetection.xml 106 // share¥registry¥calc.xcd 形式のファイル <node oor:name="****" 部分? 107 108 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */ 109 private static final Map<String,String> FILTER_MAP = new HashMap<>(); // 6.4.1.1 (2016/01/16) filterMap → FILTER_MAP refactoring 110 static { 111 FILTER_MAP.put( "ods_ods", "calc8" ); 112 FILTER_MAP.put( "xls_ods", "calc8" ); 113 FILTER_MAP.put( "ods_xls", "MS Excel 97" ); 114 FILTER_MAP.put( "xls_xls", "MS Excel 97" ); 115 FILTER_MAP.put( "ods_pdf", "calc_pdf_Export" ); 116 FILTER_MAP.put( "xls_pdf", "calc_pdf_Export" ); 117 FILTER_MAP.put( "odt_odt", "writer8" ); 118 FILTER_MAP.put( "doc_odt", "writer8" ); 119 FILTER_MAP.put( "odt_doc", "MS Word 97" ); 120 FILTER_MAP.put( "doc_doc", "MS Word 97" ); 121 FILTER_MAP.put( "odt_pdf", "writer_pdf_Export" ); 122 FILTER_MAP.put( "doc_pdf", "writer_pdf_Export" ); 123 FILTER_MAP.put( "odp_odp", "impress8" ); 124 FILTER_MAP.put( "ppt_odp", "impress8" ); 125 FILTER_MAP.put( "odp_ppt", "MS PowerPoint 97" ); 126 FILTER_MAP.put( "ppt_ppt", "MS PowerPoint 97" ); 127 FILTER_MAP.put( "odp_pdf", "impress_pdf_Export" ); 128 FILTER_MAP.put( "ppt_pdf", "impress_pdf_Export" ); 129 130 if( OFFICE_VER.contains( "LibreOffice" ) ) { // 8.0.1.0 (2021/10/29) LibreOffice の時のみ使用可能 131 // FILTER_MAP.put( "ods_xlsx", "Calc MS Excel 2007 XML" ); // 8.0.1.0 (2021/10/29) 132 // FILTER_MAP.put( "xls_xlsx", "Calc MS Excel 2007 XML" ); // 8.0.1.0 (2021/10/29) 133 134 FILTER_MAP.put( "ods_xlsx", "Calc Office Open XML" ); // 8.0.1.0 (2021/10/29) 135 FILTER_MAP.put( "xls_xlsx", "Calc Office Open XML" ); // 8.0.1.0 (2021/10/29) 136 137 // share¥registry¥writer.xcd 138 FILTER_MAP.put( "odt_docx", "MS Word 2007 XML" ); // 8.0.1.0 (2021/10/29) 139 FILTER_MAP.put( "doc_docx", "MS Word 2007 XML" ); // 8.0.1.0 (2021/10/29) 140 // ※ writer_MS_Word_2007 は、failed: 0x81a(Error Area:Io Class:Parameter Code:26) 141 142 // share¥registry¥impress.xcd 143 FILTER_MAP.put( "odp_pptx", "Impress MS PowerPoint 2007 XML" ); // 8.0.1.0 (2021/10/29) 144 FILTER_MAP.put( "ppt_pptx", "Impress MS PowerPoint 2007 XML" ); // 8.0.1.0 (2021/10/29) 145 // ※ MS PowerPoint 2007 XML は、failed: 0x81a(Error Area:Io Class:Parameter Code:26) 146 // ※ Office Open XML Presentation は、failed: 0x81a(Error Area:Io Class:Parameter Code:26) 147 } 148 }; 149 150 /** 151 * コンストラクタです。 152 * 153 * #DocConverter(input, true)と同じです。 154 * 155 * @param input ファイル一覧(CSV形式) 156 * @see #DocConverter_OOO(String[]) 157 */ 158 public DocConverter_OOO( final String input ) { 159 this( StringUtil.csv2Array( input ), true ); 160 } 161 162 /** 163 * コンストラクタです。 164 * 165 * #DocConverter(input, true)と同じです。 166 * 167 * @param input ファイル一覧(配列) 168 * @see #DocConverter_OOO(String[], boolean) 169 */ 170 public DocConverter_OOO( final String input[] ) { 171 this( input, true ); 172 } 173 174 /** 175 * コンストラクタです。 176 * 177 * isOnline(isOl)がtrueに指定された場合、soffice.binのプロセスをファクトリークラス経由で生成し、 178 * キャッシュします。 179 * 但し、システムリソースが読み込まれないような、バッチファイルから起動した場合は、この方法は 180 * 利用できないため、isOnlineをfalseに指定する必要があります。 181 * 182 * @param input ファイル一覧(配列) 183 * @param isOl オンライン(Web環境での使用)かどうか 184 */ 185 public DocConverter_OOO( final String input[], final boolean isOl ) { 186 if( input == null || input.length == 0 || input[0].isEmpty() ) { 187 throw new HybsSystemException( "入力ファイルが指定されていません。" ); 188 } 189 origName = input[0]; 190 final File inFile = new File( origName ); 191 if( !inFile.exists() ) { 192 throw new HybsSystemException( "入力ファイルが存在しません。[file=" + input[0] + "]" ); 193 } 194 isOnline = isOl; 195 inputName = origName; 196// origName = input[0]; 197 198 if( input.length == 1 ) { 199 mergeFile = null; 200 } 201 else { 202 if( !"xls".equals( getSuffix( origName ) ) && !"ods".equals( getSuffix( origName ) ) ) { 203 throw new HybsSystemException( "ファイルのマージを行う場合、入力ファイルは、ExcelまたはCacl形式である必要があります。" ); 204 } 205 206 mergeFile = new String[input.length-1]; 207 for( int i=0; i<mergeFile.length; i++ ) { 208 final String mrgFile = input[i+1]; 209 if( mrgFile.isEmpty() || !( new File( mrgFile ) ).exists() ) { 210 throw new HybsSystemException( "マージファイルが指定されていないか、または存在しません。[file=" + mrgFile + "]" ); 211 } 212 if( inputName.equals( mrgFile ) ) { 213 throw new HybsSystemException( "マージファイルに入力ファイルと同じファイルが指定されてます。[file=" + mrgFile + "]" ); 214 } 215 if( !"xls".equals( getSuffix( mrgFile ) ) && !"ods".equals( getSuffix( mrgFile ) ) ) { 216 throw new HybsSystemException( "ファイルのマージを行う場合、マージファイルは、ExcelまたはCacl形式である必要があります。" ); 217 } 218 mergeFile[i] = mrgFile; 219 } 220 } 221 } 222 223 /** 224 * SOficeのコンポーネントを起動します。 225 * 226 * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。 227 * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 228 * 229 * @og.rev 5.1.7.0 (2010/06/01) マージ処理対応 230 * 231 * @throws Throwable 何らかのエラーが発生した場合。 232 * @see #close() 233 * @see #close(boolean) 234 */ 235 public void open() throws Throwable { 236 // プロセスの取得 237 if( soffice == null ) { 238 if( isOnline ) { 239 soffice = ProcessFactory.newInstance(); 240 } 241 else { 242 soffice = new SOfficeProcess( "docconverter.class" ); 243 soffice.bootstrap(); 244 } 245 246 // マージする場合は、マージ対象のファイルをテンポラリにコピーする(readOnly回避のため) 247 // テンプレート(無題)として上げると、シートコピー先として特定できなくなるため 248 if( mergeFile != null ) { 249 final File origFile = new File( origName ); 250 inputName = soffice.getTempPath() + System.currentTimeMillis() + "_" + origFile.getName(); 251 FileUtil.copy( origFile, new File( inputName ) ); 252 } 253 } 254 255 // 5.1.7.0 (2010/06/01) マージ処理対応 256 xComp = getComponent( inputName, ( mergeFile == null ? true : false ), false ); 257 258 if( mergeFile != null ) { 259 for( int i=0; i<mergeFile.length; i++ ) { 260 merge( mergeFile[i] ); 261 } 262 } 263 } 264 265 /** 266 * ドキュメントコンポーネントを取得します。 267 * 268 * @param input ファイル名 269 * @param isHidden 隠し属性[true/false] 270 * @param isAsTemplate OpenOffice上のTemplate属性[true/false] 271 * 272 * @return ドキュメントコンポーネント 273 */ 274 @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。 275 private XComponent getComponent( final String input, final boolean isHidden, final boolean isAsTemplate ) { 276 final PropertyValue[] calcProps = new PropertyValue[2]; 277 calcProps[0] = new PropertyValue(); 278 calcProps[0].Name = "Hidden"; 279 calcProps[0].Value = isHidden; 280 calcProps[1] = new PropertyValue(); 281 calcProps[1].Name = "AsTemplate"; 282 calcProps[1].Value = isAsTemplate; 283 284 final String url = "file:///" + input.replace( '\\', '/' ); 285 286 XComponent rtnDoc; 287 final XComponentLoader cloader = (XComponentLoader) UnoRuntime.queryInterface( XComponentLoader.class, soffice.getDesktop() ); 288 try { 289 rtnDoc = cloader.loadComponentFromURL( url, "_blank", 0, calcProps ); 290 } 291 catch( final IOException ex ) { 292 throw new HybsSystemException( "OpenOfficeの立ち上げ時にエラーが発生しました(入出力エラー)。", ex ); 293 } 294 catch( final IllegalArgumentException ex ) { 295 throw new HybsSystemException( "OpenOfficeの立ち上げ時にエラーが発生しました(パラメーター不正)。", ex ); 296 } 297 return rtnDoc; 298 } 299 300 /** 301 * ドキュメント(xls,ods)のマージを行います。 302 * 303 * @param mergeInputName マージ対象のファイル名 304 */ 305 @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。 306 private void merge( final String mergeInputName ) { 307 // マージする副ファイルは、テンプレート(無題)として上げる(readOnly回避のため) 308 final XComponent subDoc = getComponent( mergeInputName, false, true ); 309 310 final XDispatchProvider dispatchProvider 311 = (XDispatchProvider)UnoRuntime.queryInterface( XDispatchProvider.class 312 ,((XController)UnoRuntime.queryInterface( XController.class 313 ,((XModel)UnoRuntime.queryInterface( XModel.class 314 ,subDoc 315 )).getCurrentController() 316 )).getFrame() 317 ); 318 319 final XDispatchHelper xDispatchHelper = soffice.getDispatcher(); 320 xDispatchHelper.executeDispatch(dispatchProvider, ".uno:TableSelectAll", "", 0, new PropertyValue[0]); 321 322 String title = new File( inputName ).getName() ; 323 title = title.substring( 0, title.indexOf( '.' ) ); 324 325 final PropertyValue[] moveProps = new PropertyValue[3]; 326 moveProps[0] = new PropertyValue(); 327 moveProps[0].Name = "DocName"; 328 moveProps[0].Value = title; 329 moveProps[1] = new PropertyValue(); 330 moveProps[1].Name = "Index"; 331 moveProps[1].Value = 32767; 332 moveProps[2] = new PropertyValue(); 333 moveProps[2].Name = "Copy"; 334 moveProps[2].Value = true; 335 xDispatchHelper.executeDispatch(dispatchProvider, ".uno:Move", "", 0, moveProps); 336 337 closeComponent( subDoc ); 338 } 339 340 /** 341 * Calcコンポーネントをクローズします。 342 * 343 * このクローズ処理は、処理が正常終了した場合に呼び出しする必要があります。 344 * 例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 345 * 346 * このメソッドは#close(false)と同じです。 347 * 348 * @throws Throwable 何らかのエラーが発生した場合。 349 * @see #close(boolean) 350 */ 351 public void close() throws Throwable { 352 close( false ); 353 } 354 355 /** 356 * Calcコンポーネントをクローズします。 357 * 358 * 引数のisErrがtrueの場合、この変換オブジェクトで生成されたプロセスは強制的に破棄されます。 359 * falseの場合は、プロセスは、ファクトリクラスを経由して、キャッシュに戻されます。 360 * (バッチ処理の場合は、いずれの場合も、プロセスは強制的に破棄されます) 361 * 362 * 起動から変換、クローズまでの書く処理で例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 363 * 364 * #close(false)は#close()と同じであるため、通常利用することはありません。 365 * 366 * @og.rev 4.2.4.1 (2008/07/07 ) 終了処理を60回で終わるように修正 367 * @og.rev 4.3.0.0 (2008/07/15 ) ↑は6秒しか待っていなかったので、60秒待つように修正 368 * 369 * @param isErr trueの場合、この変換オブジェクトで生成されたプロセスは強制的に破棄されます。 370 */ 371 @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。 372 public void close( final boolean isErr ) { 373 if( xComp != null ) { 374 closeComponent( xComp ); 375 } 376 377 if( soffice != null ) { 378 if( isOnline ) { 379 if( isErr ) { 380 ProcessFactory.remove( soffice ); 381 } 382 else { 383 ProcessFactory.release( soffice ); 384 } 385 } 386 else { 387 soffice.close(); 388 } 389 } 390 391 // マージした場合は、テンポラリにコピーしたファイルを削除 392 // 6.0.0.1 (2014/04/25) These nested if statements could be combined 393 if( mergeFile != null && ! ( new File( inputName ) ).delete() ) { 394 System.err.println( "テンポラリにコピーしたファイルを削除できませんでした。[" + inputName + "]" ); 395 } 396 } 397 398 /** 399 * ドキュメントコンポーネントをクローズします。 400 * 401 * @param comp ドキュメントコンポーネント 402 */ 403 @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。 404 private void closeComponent( final XComponent comp ) { 405 XCloseable closeable = null; 406 for( int i=0;; ++i ) { 407 try { 408 closeable = (XCloseable) UnoRuntime.queryInterface( XCloseable.class, comp ); 409 closeable.close( true ); 410 break; 411 } 412 catch( final CloseVetoException ex ) { 413 // 4.2.4.1 (2008/07/07 ) 414 // 4.3.4.4 (2009/01/01) 415 if( i == 600 ) { throw new HybsSystemException( "sofficeプロセスに接続できません。", ex ); } 416 try { 417 Thread.sleep( 100 ); 418 } 419 catch( final InterruptedException ex2 ) { 420 // throw new HybsSystemException( ex2 ); 421 } 422 } 423 } 424 } 425 426 /** 427 * 印刷を行います。 428 * 429 * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。 430 * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 431 * 432 * @og.rev 4.3.0.0 (2008/07/16) スプールが終わるまでwaitし、さらにプリンタ発行の状況を監視し、正常終了かどうかを判断 433 * @og.rev 4.3.7.3 (2009/06/22) 存在しないプリンターを指定した場合のエラーハンドリングを追加 434 * @og.rev 5.1.2.0 (2010/01/01) CentOS等は、OS_INFOがLinux UNKNOWNとなるため、判定条件を変更 435 * 436 * @param printer プリンター名 437 * @throws Throwable 何らかのエラーが発生した場合。 438 */ 439 public void print( final String printer ) throws Throwable { 440 if( printer == null || printer.isEmpty() ) { 441 throw new HybsSystemException( "プリンターが指定されていません。" ); 442 } 443 444 // if( xComp == null ) { throw new HybsSystemException( "初めに、#open()を実行して下さい(1)" ); } 445 @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。 446 final XPrintable xprintable = (XPrintable) UnoRuntime.queryInterface( XPrintable.class, xComp ); 447 @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。 448 final XPrintJobBroadcaster selection = (XPrintJobBroadcaster) UnoRuntime.queryInterface(XPrintJobBroadcaster.class, xprintable); 449 final MyPrintJobListener listener = new MyPrintJobListener(); 450 selection.addPrintJobListener( listener ); 451 452 final PropertyValue[] tmpProps = new PropertyValue[1]; 453 tmpProps[0] = new PropertyValue(); 454 tmpProps[0].Name = "Name"; 455 // 5.1.2.0 (2010/01/01) CentOS等は、OS_INFOがLinux UNKNOWNとなるため、判定条件を変更 456 // OSがLinuxの場合は、プリンタ名称の前後に"<",">"を付加 457 tmpProps[0].Value = "LINUX".indexOf( HybsSystem.sys( "OS_INFO" ).toUpperCase( Locale.JAPAN ) ) >= 0 ? "<" + printer + ">" : printer; 458 459 // 4.3.4.4 (2009/01/01) 460 try { 461 xprintable.setPrinter( tmpProps ); 462 } 463 catch( final IllegalArgumentException ex ) { 464 throw new HybsSystemException( "印刷時にエラーが発生しました。", ex ); 465 } 466 467 // 4.3.7.3 (2009/06/22) 存在しないプリンタを指定した場合は、PropertyValueに 468 // デフォルトプリンターが入るため、引数の値と合致しているかで正しく設定されたかを確認 469 String curPrinter = null; 470 final PropertyValue[] chkProps = xprintable.getPrinter(); 471 for( int i=0; i<chkProps.length; i++ ) { 472 if( "Name".equals( chkProps[i].Name) ) { 473 curPrinter = (String)chkProps[i].Value; 474 break; 475 } 476 } 477 if( !(printer.equalsIgnoreCase( curPrinter ) ) ) { 478 final String errMsg = "プリンター[" + printer + "]を発行先に指定できませんでした。" + CR 479 + "存在しないプリンタ名が指定されている可能性があります。"; 480 throw new HybsSystemException( errMsg ); 481 } 482 483 // 4.3.0.0 (2008/07/16) 484 final PropertyValue[] printProps = new PropertyValue[1]; 485 printProps[0] = new PropertyValue(); 486 printProps[0].Name = "Wait"; 487 printProps[0].Value = true; 488 489 // 4.3.4.4 (2009/01/01) 490 try { 491 xprintable.print( printProps ); 492 } 493 catch( final IllegalArgumentException ex ) { 494 throw new HybsSystemException( "印刷時にエラーが発生しました。", ex ); 495 } 496 497 // 4.3.0.0 (2008/07/16) 498 // 6.9.7.0 (2018/05/14) PMD Useless parentheses. 499 if( listener.getStatus() == null 500 || listener.getStatus() != PrintableState.JOB_COMPLETED && listener.getStatus() != PrintableState.JOB_SPOOLED ) { 501 throw new HybsSystemException ( "Error Occured while spooling print job. Check Spooler-Service!!!"); 502 } 503 } 504 505 /** 506 * プリンタジョブの状況を監視するリスナーです。 507 * 508 * @author Hiroki.Nakamura 509 */ 510 private static final class MyPrintJobListener implements XPrintJobListener { 511 private PrintableState status ; 512 513 /** 514 * PrintJobEventのステータスを内部変数にセットします。 515 * 516 * @param event PrintJobEventオブジェクト 517 */ 518 @Override 519 public void printJobEvent( final PrintJobEvent event ) { 520 status = event.State; 521 } 522 523 /** 524 * EventObjectの処理を実施します。(ここでは何も行いません。) 525 * 526 * @param event EventObjectオブジェクト 527 */ 528 @Override 529 public void disposing( final EventObject event ) { 530 // 何もありません。(PMD エラー回避) 531 } 532 533 /** 534 * PrintableStateオブジェクトを返します。 535 * 536 * @return PrintableStateオブジェクト 537 */ 538 public PrintableState getStatus() { 539 return status; 540 } 541 } 542 543 /** 544 * PDF出力を行います。 545 * 546 * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。 547 * 548 * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。 549 * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 550 * 551 * @param outputName 出力ファイル名 552 * @param pdfPasswd PDFパスワード 553 * @throws Throwable 何らかのエラーが発生した場合。 554 */ 555 public void pdf( final String outputName, final String pdfPasswd ) throws Throwable { 556 // savePdf( outputName, getFilterName( getSuffix( inputName ), "pdf" ), pdfPasswd ); 557 savePdf( outputName, getFilterName( inputName, "pdf" ), pdfPasswd ); 558 } 559 560 /** 561 * Calc(ods)出力を行います。 562 * 563 * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。 564 * 565 * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。 566 * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 567 * 568 * @param outputName 出力ファイル名 569 * @throws Throwable 何らかのエラーが発生した場合。 570 */ 571// public void ods( final String outputName ) throws Throwable { 572// // saveDoc( outputName, getFilterName( getSuffix( inputName ), "ods" ) ); 573// saveDoc( outputName, getFilterName( inputName, "ods" ) ); 574// } 575 576// /** 577// * Excel(xls)出力を行います。 578// * 579// * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。 580// * 581// * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。 582// * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 583// * 584// * @param outputName 出力ファイル名 585// * @throws Throwable 何らかのエラーが発生した場合。 586// */ 587// public void xls( final String outputName ) throws Throwable { 588// // saveDoc( outputName, getFilterName( getSuffix( inputName ), "xls" ) ); 589// saveDoc( outputName, getFilterName( inputName, "xls" ) ); 590// } 591 592// /** 593// * Excel2007(xlsx)出力を行います。 594// * 595// * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。 596// * 597// * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。 598// * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 599// * 600// * @og.rev 8.0.1.0 (2021/10/29) OUT_ODS_XSLX (Excel2007形式) 評価用 601// * 602// * @param outputName 出力ファイル名 603// * @throws Throwable 何らかのエラーが発生した場合。 604// */ 605// public void xlsx( final String outputName ) throws Throwable { 606// // saveDoc( outputName, getFilterName( getSuffix( inputName ), "xlsx" ) ); 607// saveDoc( outputName, getFilterName( inputName, "xlsx" ) ); 608// } 609 610// /** 611// * Writer(ods)出力を行います。 612// * 613// * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。 614// * 615// * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。 616// * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 617// * 618// * @param outputName 出力ファイル名 619// * @throws Throwable 何らかのエラーが発生した場合。 620// */ 621// public void odt( final String outputName ) throws Throwable { 622// // saveDoc( outputName, getFilterName( getSuffix( inputName ), "odt" ) ); 623// saveDoc( outputName, getFilterName( inputName, "odt" ) ); 624// } 625 626// /** 627// * Word(doc)出力を行います。 628// * 629// * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。 630// * 631// * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。 632// * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 633// * 634// * @param outputName 出力ファイル名 635// * @throws Throwable 何らかのエラーが発生した場合。 636// */ 637// public void doc( final String outputName ) throws Throwable { 638// // saveDoc( outputName, getFilterName( getSuffix( inputName ), "doc" ) ); 639// saveDoc( outputName, getFilterName( inputName, "doc" ) ); 640// } 641 642// /** 643// * Impress(odp)出力を行います。 644// * 645// * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。 646// * 647// * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。 648// * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 649// * 650// * @param outputName 出力ファイル名 651// * @throws Throwable 何らかのエラーが発生した場合。 652// */ 653// public void odp( final String outputName ) throws Throwable { 654// // saveDoc( outputName, getFilterName( getSuffix( inputName ), "odp" ) ); 655// saveDoc( outputName, getFilterName( inputName, "odp" ) ); 656// } 657 658// /** 659// * PowerPoint(ppt)出力を行います。 660// * 661// * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。 662// * 663// * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。 664// * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 665// * 666// * @param outputName 出力ファイル名 667// * @throws Throwable 何らかのエラーが発生した場合。 668// */ 669// public void ppt( final String outputName ) throws Throwable { 670// // saveDoc( outputName, getFilterName( getSuffix( inputName ), "ppt" ) ); 671// saveDoc( outputName, getFilterName( inputName, "ppt" ) ); 672// } 673 674 /** 675 * 出力ファイルから出力形式を自動判別し、変換を行います。 676 * 677 * 入出力形式で未対応の場合(形式は入出力ファイルの拡張子で判別)、例外が発行されます。 678 * 679 * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。 680 * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。 681 * 682 * @param outputName 出力ファイル名 683 * @throws Throwable 何らかのエラーが発生した場合。 684 */ 685 public void auto( final String outputName ) throws Throwable { 686 final String outSuffix = getSuffix( outputName ); 687 if( "pdf".equalsIgnoreCase( outSuffix ) ) { 688// savePdf( outputName, getFilterName( getSuffix( inputName ), outSuffix ), null ); 689 savePdf( outputName, getFilterName( inputName, outSuffix ), null ); 690 } 691 else { 692// saveDoc( outputName, getFilterName( getSuffix( inputName ), outSuffix ) ); 693 saveDoc( outputName, getFilterName( inputName, outSuffix ) ); 694 } 695 } 696 697 /** 698 * フィルター名を指定して、各種ファイル形式に出力を行います。 699 * 700 * @param outputName 出力ファイル名 701 * @param filter フィルター名 702 */ 703 private void saveDoc( final String outputName, final String filter ) { 704 if( !checkOutput( outputName ) ){ return; } 705 706 final PropertyValue[] storeProps = new PropertyValue[1]; 707 storeProps[0] = new PropertyValue(); 708 storeProps[0].Name = "FilterName"; 709 storeProps[0].Value = filter; 710 711 final String url = "file:///" + outputName.replace( '\\', '/' ); 712 // if( xComp == null ) { throw new HybsSystemException( "初めに、#open()を実行して下さい(2)" ); } 713 @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。 714 final XStorable xstorable = (XStorable) UnoRuntime.queryInterface( XStorable.class, xComp ); 715 try { 716 xstorable.storeAsURL( url, storeProps ); 717 } 718 catch( final Throwable th ) { 719 throw new HybsSystemException( "ファイルへの変換時にエラーが発生しました。[filter=" + filter + "]", th ); 720 } 721 } 722 723 /** 724 * フィルターを指定してPDF出力を行います。 725 * 726 * @param outputName 出力ファイル名 727 * @param filter フィルター名 728 * @param pdfPasswd PDFパスワード 729 */ 730 private void savePdf( final String outputName, final String filter, final String pdfPasswd ) { 731 if( !checkOutput( outputName ) ){ return; } 732 733 final PropertyValue[] storeProps; 734 if( pdfPasswd == null || pdfPasswd.isEmpty() ) { 735 storeProps = new PropertyValue[1]; 736 storeProps[0] = new PropertyValue(); 737 storeProps[0].Name = "FilterName"; 738 storeProps[0].Value = filter; 739 } 740 // 帳票要求テーブルでPDFパスワードが設定されている場合 741 else { 742 final PropertyValue[] filterProps = new PropertyValue[2]; 743 filterProps[0] = new PropertyValue(); 744 filterProps[0].Name = "EncryptFile"; 745 filterProps[0].Value = true; 746 filterProps[1] = new PropertyValue(); 747 filterProps[1].Name = "DocumentOpenPassword"; 748 filterProps[1].Value = pdfPasswd; 749 750 storeProps = new PropertyValue[2]; 751 storeProps[0] = new PropertyValue(); 752 storeProps[0].Name = "FilterName"; 753 storeProps[0].Value = "calc_pdf_Export"; 754 storeProps[1] = new PropertyValue(); 755 storeProps[1].Name = "FilterData"; 756 storeProps[1].Value = filterProps; 757 } 758 759 final String url = "file:///" + outputName.replace( '\\', '/' ); 760 // if( xComp == null ) { throw new HybsSystemException( "初めに、#open()を実行して下さい(3)" ); } 761 @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。 762 final XStorable xstorable = (XStorable) UnoRuntime.queryInterface( XStorable.class, xComp ); 763 try { 764 xstorable.storeToURL( url, storeProps ); 765 } 766 catch( final Throwable th ) { 767 final String err = "PDFファイルへの変換時にエラーが発生しました。[filter=" + filter + "]" 768 + " URL=" + url + " , storeProps=" + storeProps + " , xComp=" + xComp ; 769 770// throw new HybsSystemException( "PDFファイルへの変換時にエラーが発生しました。[filter=" + filter + "]", th ); 771 throw new HybsSystemException( err, th ); 772 } 773 } 774 775 /** 776 * 出力ファイルのチェックを行います。 777 * 778 * @param outputName 出力ファイル名 779 * 780 * @return 処理対象かどうか(入力ファイルと出力ファイルが同じ場合は、falseが返ります) 781 */ 782 private boolean checkOutput( final String outputName ) { 783 if( outputName == null || outputName.isEmpty() ) { 784 throw new HybsSystemException( "出力ファイルが指定されていません。" ); 785 } 786 787 final File inFile = new File( inputName ); 788 final File outFile = new File( outputName ); 789 790 if( outFile.exists() ) { 791 if( inFile.getAbsoluteFile().equals( outFile.getAbsoluteFile() ) ) { 792 // 入力と出力が同じファイルの場合な何もしない 793 return false; 794 } 795 else if( !outFile.delete() ) { 796 throw new HybsSystemException( "出力先の既存ファイルが削除できません。[file=" + outputName + "]" ); 797 } 798 } 799 return true; 800 } 801 802 /** 803 * 入出力の形式(拡張子)からフィルター名を取得します。 804 * 805 * 入力ファイル名からサフィックスを取り出して、FILTER_MAP からフィルター名を取り出します。 806 * 807 * @og.rev 8.0.1.0 (2021/10/29) メッセージ修正 808 * 809// * @param inSuffix 入力拡張子 810 * @param inputName 入力ファイル名 811 * @param outSuffix 出力拡張子 812 * 813 * @return フィルター名 814 */ 815// private static String getFilterName( final String inSuffix, final String outSuffix ) { 816 private static String getFilterName( final String inputName, final String outSuffix ) { 817 final String inSuffix = getSuffix( inputName ); 818 819 final String filterName = FILTER_MAP.get( inSuffix + "_" + outSuffix ); 820 if( filterName == null ) { 821 final String errMsg = "入力ファイル=[" + inputName + "] , 出力形式=[" + outSuffix + "]" + CR 822 + "入力形式、出力形式は、以下の対応表に基づき、設定して下さい。" + CR 823 + "入力[Calc(ods) ,Excel(xls) ] ⇒ 出力[Calc(ods) ,Excel(xls,xslx) ,PDF]" + CR 824 + "入力[Writer(odt) ,Word(doc) ] ⇒ 出力[Writer(odt) ,Word(doc,docx) ,PDF]" + CR 825 + "入力[Impress(odp),PowerPoint(ppt)] ⇒ 出力[Impress(odp),PowerPoint(ppt,pptx),PDF]" + CR 826 + "xlsx,docx,pptx は、MS 2007形式の為、LibreOffice のみ利用できます。" + CR ; 827 throw new HybsSystemException( errMsg ); 828 } 829 return filterName; 830 } 831 832 /** 833 * ファイル名から拡張子(小文字)を求めます。 834 * 835 * @param fileName ファイル名 836 * 837 * @return 拡張子(小文字) 838 */ 839 private static String getSuffix( final String fileName ) { 840 String suffix = null; 841 if( fileName != null ) { 842 final int sufIdx = fileName.lastIndexOf( '.' ); 843 if( sufIdx >= 0 ) { 844 suffix = fileName.substring( sufIdx + 1 ).toLowerCase( Locale.JAPAN ); 845 } 846 } 847 return suffix; 848 } 849 850 /** 851 * ドキュメントの変換を行うための簡易メソッドです。 852 * 853 * 変換方法は、出力ファイルの拡張子により自動的に決定されます。 854 * 855 * @param inputFile 入力ファイル名 856 * @param outputFile 出力ファイル名 857 * @see #convert(String[], String, boolean) 858 */ 859 public static final void convert( final String inputFile, final String outputFile ) { 860 convert( StringUtil.csv2Array( inputFile ), outputFile ); 861 } 862 863 /** 864 * ドキュメントの変換を行うための簡易メソッドです。 865 * 866 * 変換方法は、出力ファイルの拡張子により自動的に決定されます。 867 * 868 * @param inputFile 入力ファイル名配列 869 * @param outputFile 出力ファイル名 870 * @see #convert(String[], String, boolean) 871 */ 872 public static final void convert( final String[] inputFile, final String outputFile ) { 873 convert( inputFile, outputFile, true ); 874 } 875 876 /** 877 * ドキュメントの変換を行うための簡易メソッドです。 878 * 879 * 変換方法は、出力ファイルの拡張子により自動的に決定されます。 880 * 881 * isOnlineがtrueに指定された場合、soffice.binのプロセスをファクトリークラス経由で生成し、 882 * キャッシュします。 883 * 但し、システムリソースが読み込まれないような、バッチファイルから起動した場合は、この方法は 884 * 利用できないため、isOnlineをfalseに指定する必要があります。 885 * 886 * @param inputFile 入力ファイル名配列 887 * @param outputFile 出力ファイル名 888 * @param isOnline オンライン(Web環境での使用)かどうか 889 */ 890 public static final void convert( final String inputFile[], final String outputFile, final boolean isOnline ) { 891 final DocConverter_OOO dc = new DocConverter_OOO( inputFile, isOnline ); 892 try { 893 dc.open(); 894 dc.auto( outputFile ); 895 dc.close(); 896 } 897 catch( final Throwable th ) { 898 dc.close( true ); 899 throw new HybsSystemException( th ); 900 } 901 } 902 903 /** 904 * ドキュメントの変換を行います。 905 * 906 * 変換方法は、出力ファイルの拡張子により自動的に決定されます。 907 * 908 * @og.rev 4.3.1.1 (2008/08/23) mkdirs の戻り値判定 909 * @og.rev 6.3.9.1 (2015/11/27) A method/constructor shouldnt explicitly throw java.lang.Exception(PMD)。 910 * 911 * @param args コマンド引数配列 912 */ 913 public static void main( final String[] args ) { 914 if( args.length < 2 ) { 915 System.out.println( "usage : OdsConverter [inputFile or inputDir] [outputDir]" ); 916 return; 917 } 918 919 final File input = new File( args[0] ); 920 final File output = new File( args[1] ); 921 922 // 4.3.1.1 (2008/08/23) mkdirs の戻り値判定 923 if( output.mkdirs() ) { 924 System.err.println( args[1] + " の ディレクトリ作成に失敗しました。" ); 925 } 926 927 if( input.isDirectory() ) { 928 final File[] inputFiles = input.listFiles(); 929 // 6.3.9.0 (2015/11/06) null になっている可能性があるメソッドの戻り値を利用している(findbugs) 930 if( inputFiles != null ) { 931 for( final File file : inputFiles ) { 932 final String inputFile = file.getAbsolutePath(); 933 final String outputFile = output.getAbsolutePath() + File.separator + file.getName().replace( ".xls", ".ods" ); 934 convert( StringUtil.csv2Array( inputFile ), outputFile, false ); 935 } 936 } 937 } 938 else { 939 final String inputFile = input.getAbsolutePath(); 940 final String outputFile = output.getAbsolutePath() + File.separator + input.getName().replace( ".xls", ".ods" ); 941 convert( StringUtil.csv2Array( inputFile ), outputFile, false ); 942 } 943 } 944}