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