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