2 * Copyright (c) 2009 The openGion Project.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 * either express or implied. See the License for the specific language
14 * governing permissions and limitations under the License.
16 package org.opengion.hayabusa.report2;
20 import java.util.HashMap;
21 import java.util.Locale;
22 // import java.util.List; // 8.0.3.0 (2021/12/17) 【保留】
23 import java.nio.file.Files; // 8.1.0.3 (2022/01/21)
24 import java.nio.file.Paths; // 8.1.0.3 (2022/01/21)
25 import java.nio.file.Path; // 8.1.0.3 (2022/01/21)
26 import java.nio.file.StandardCopyOption; // 8.1.0.3 (2022/01/21)
28 // import org.opengion.fukurou.system.HybsConst; // 8.0.1.0 (2021/10/29)
29 // import org.opengion.fukurou.model.ExcelModel; // 8.0.3.0 (2021/12/17)【保留】
30 import org.opengion.fukurou.util.FileUtil;
31 import org.opengion.fukurou.util.StringUtil;
32 import org.opengion.hayabusa.common.HybsSystem;
33 import org.opengion.hayabusa.common.HybsSystemException;
34 import static org.opengion.fukurou.system.HybsConst.CR ; // 6.1.0.0 (2014/12/26)
35 // import static org.opengion.fukurou.system.HybsConst.FS ; // 8.0.3.0 (2021/12/17)
37 import com.sun.star.beans.PropertyValue;
38 import com.sun.star.frame.XComponentLoader;
39 import com.sun.star.frame.XController;
40 import com.sun.star.frame.XDispatchHelper;
41 import com.sun.star.frame.XDispatchProvider;
42 import com.sun.star.frame.XModel;
43 import com.sun.star.frame.XStorable;
44 import com.sun.star.io.IOException;
45 import com.sun.star.lang.EventObject;
46 import com.sun.star.lang.IllegalArgumentException;
47 import com.sun.star.lang.XComponent;
48 import com.sun.star.uno.UnoRuntime;
49 import com.sun.star.util.CloseVetoException;
50 import com.sun.star.util.XCloseable;
51 import com.sun.star.view.PrintJobEvent;
52 import com.sun.star.view.PrintableState;
53 import com.sun.star.view.XPrintJobBroadcaster;
54 import com.sun.star.view.XPrintJobListener;
55 import com.sun.star.view.XPrintable;
57 import com.sun.star.sheet.XCalculatable; // 8.1.1.2 (2022/02/25)
60 * OpenOfficeを利用して様々な形式のファイルを読み込み、出力・印刷を行うための変換クラスです。
62 * 変換を行うことのできる入出力のフォーマット以下の通りです。
65 * 入力[Calc(ods) ,Excel(xls) ] ⇒ 出力[Calc(ods) ,Excel(xls,xlsx) ,PDF]
66 * 入力[Writer(odt) ,Word(doc) ] ⇒ 出力[Writer(odt) ,Word(doc,docx) ,PDF]
67 * 入力[Impress(odp),PowerPoint(ppt)] ⇒ 出力[Impress(odp),PowerPoint(ppt,pptx) ,PDF]
70 * ※ xlsx,docx,pptx は、MS 2007形式の為、LibreOffice のみ利用できます。
72 * 変換を行うには、以下の2通りの方法があります。
74 * (1)簡易的な変換メソッドを利用する場合
75 * #convert(String, String)を利用して、変換を行います。
76 * この場合、出力形式は、出力ファイルの拡張子に従って自動的に決定されます。
77 * このため、印刷処理などを行う場合は、(2)の方法で出力して下さい。
79 * (2)段階的に各メソッドを呼び出して変換する場合
80 * オブジェクトを生成した後、{@link #open()}、#(各種変換メソッド)、{@link #clone()}を
82 * この場合、出力形式は、それに対応するメソッドを呼び出すことで決定されます。
84 * また、変換を行うための、各種メソッドは、例外としてThrowableを投げるように定義されています。
85 * このクラスを利用する場合は、このThrowableをcatchし、catch句で、必ず{@link #close( boolean )}に、
86 * "true"(エラー発生時のクローズ処理)を指定して、終了処理を行って下さい。
87 * (これを行わない場合、OpenOfficeの不要なプロセスが残ってしまう可能性があります)
89 * また、出力ファイルが既に存在する場合、出力ファイルは一旦削除された後、処理されます。
90 * なお、入力ファイルと出力ファイルが同じ場合、何も処理されません。(例外も発行されません)
92 * 入力ファイルを、CSV形式で複数指定した場合、複数の入力ファイルをマージして出力します。
93 * ※1 現状は、ファイルのマージは、入力ファイルがExcelまたはCalcの場合のみ対応しています。
95 * ※ DocConverter は、クラウド対応されていません。変換時はローカルファイル間で行ってください。
100 * @author Hiroki.Nakamura
103 public class DocConverter_OOO {
104 // // XLSX は、LibreOffice のみ実行可能なので、その判定用に使用する。
105 // private static final String OFFICE_HOME = HybsConst.getenv( "OFFICE_HOME","NULL" ); // 8.0.1.0 (2021/10/29) 環境変数から取得
107 private final boolean isOnline; // オンライン処理かどうか(オンライン処理の場合、プロセスはファクトリクラス経由で生成されます)
108 private final String[] mergeFile;
110 private String inputName;
111 private String origName;
113 private XComponent xComp; // 5.1.8.0 (2010/07/01) メソッドと重なる変数名の変更
114 private SOfficeProcess soffice;
116 // 入力、出力の拡張子とこれに対応するフィルター名
117 // share¥registry¥calc.xcd 形式のファイル <node oor:name="****" 部分?
119 /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
120 private static final Map<String,String> FILTER_MAP = new HashMap<>(); // 6.4.1.1 (2016/01/16) filterMap → FILTER_MAP refactoring
122 // 8.1.0.3 (2022/01/21) ファイルの拡張子が同じ場合は、copyで対応する。
123 // FILTER_MAP.put( "ods_ods", "calc8" );
124 FILTER_MAP.put( "xls_ods", "calc8" );
125 FILTER_MAP.put( "ods_xls", "MS Excel 97" );
126 // FILTER_MAP.put( "xls_xls", "MS Excel 97" );
127 FILTER_MAP.put( "ods_pdf", "calc_pdf_Export" );
128 FILTER_MAP.put( "xls_pdf", "calc_pdf_Export" );
129 // FILTER_MAP.put( "odt_odt", "writer8" );
130 FILTER_MAP.put( "doc_odt", "writer8" );
131 FILTER_MAP.put( "odt_doc", "MS Word 97" );
132 // FILTER_MAP.put( "doc_doc", "MS Word 97" );
133 FILTER_MAP.put( "odt_pdf", "writer_pdf_Export" );
134 FILTER_MAP.put( "doc_pdf", "writer_pdf_Export" );
135 // FILTER_MAP.put( "odp_odp", "impress8" );
136 FILTER_MAP.put( "ppt_odp", "impress8" );
137 FILTER_MAP.put( "odp_ppt", "MS PowerPoint 97" );
138 // FILTER_MAP.put( "ppt_ppt", "MS PowerPoint 97" );
139 FILTER_MAP.put( "odp_pdf", "impress_pdf_Export" );
140 FILTER_MAP.put( "ppt_pdf", "impress_pdf_Export" );
142 // if( OFFICE_HOME.contains( "LibreOffice" ) ) { // 8.0.1.0 (2021/10/29) LibreOffice の時のみ使用可能
143 // FILTER_MAP.put( "ods_xlsx", "Calc MS Excel 2007 XML" ); // 8.0.1.0 (2021/10/29)
144 // FILTER_MAP.put( "xls_xlsx", "Calc MS Excel 2007 XML" ); // 8.0.1.0 (2021/10/29)
146 FILTER_MAP.put( "ods_xlsx", "Calc Office Open XML" ); // 8.0.1.0 (2021/10/29)
147 FILTER_MAP.put( "xls_xlsx", "Calc Office Open XML" ); // 8.0.1.0 (2021/10/29)
149 // share¥registry¥writer.xcd
150 FILTER_MAP.put( "odt_docx", "MS Word 2007 XML" ); // 8.0.1.0 (2021/10/29)
151 FILTER_MAP.put( "doc_docx", "MS Word 2007 XML" ); // 8.0.1.0 (2021/10/29)
152 // ※ writer_MS_Word_2007 は、failed: 0x81a(Error Area:Io Class:Parameter Code:26)
154 // share¥registry¥impress.xcd
155 FILTER_MAP.put( "odp_pptx", "Impress MS PowerPoint 2007 XML" ); // 8.0.1.0 (2021/10/29)
156 FILTER_MAP.put( "ppt_pptx", "Impress MS PowerPoint 2007 XML" ); // 8.0.1.0 (2021/10/29)
157 // ※ MS PowerPoint 2007 XML は、failed: 0x81a(Error Area:Io Class:Parameter Code:26)
158 // ※ Office Open XML Presentation は、failed: 0x81a(Error Area:Io Class:Parameter Code:26)
165 * #DocConverter(input, true)と同じです。
167 * @param input ファイル一覧(CSV形式)
168 * @see #DocConverter_OOO(String[])
170 public DocConverter_OOO( final String input ) {
171 this( StringUtil.csv2Array( input ), true );
177 * #DocConverter(input, true)と同じです。
179 * @param input ファイル一覧(配列)
180 * @see #DocConverter_OOO(String[], boolean)
182 public DocConverter_OOO( final String input[] ) {
189 * isOnline(isOl)がtrueに指定された場合、soffice.binのプロセスをファクトリークラス経由で生成し、
191 * 但し、システムリソースが読み込まれないような、バッチファイルから起動した場合は、この方法は
192 * 利用できないため、isOnlineをfalseに指定する必要があります。
194 * @param input ファイル一覧(配列)
195 * @param isOl オンライン(Web環境での使用)かどうか
197 public DocConverter_OOO( final String input[], final boolean isOl ) {
198 if( input == null || input.length == 0 || input[0].isEmpty() ) {
199 throw new HybsSystemException( "入力ファイルが指定されていません。" );
202 final File inFile = new File( origName );
203 if( !inFile.exists() ) {
204 throw new HybsSystemException( "入力ファイルが存在しません。[file=" + input[0] + "]" );
207 inputName = origName;
208 // origName = input[0];
210 if( input.length == 1 ) {
214 if( !"xls".equals( getSuffix( origName ) ) && !"ods".equals( getSuffix( origName ) ) ) {
215 throw new HybsSystemException( "ファイルのマージを行う場合、入力ファイルは、ExcelまたはCacl形式である必要があります。" );
218 mergeFile = new String[input.length-1];
219 for( int i=0; i<mergeFile.length; i++ ) {
220 final String mrgFile = input[i+1];
221 if( mrgFile.isEmpty() || !( new File( mrgFile ) ).exists() ) {
222 throw new HybsSystemException( "マージファイルが指定されていないか、または存在しません。[file=" + mrgFile + "]" );
224 if( inputName.equals( mrgFile ) ) {
225 throw new HybsSystemException( "マージファイルに入力ファイルと同じファイルが指定されてます。[file=" + mrgFile + "]" );
227 if( !"xls".equals( getSuffix( mrgFile ) ) && !"ods".equals( getSuffix( mrgFile ) ) ) {
228 throw new HybsSystemException( "ファイルのマージを行う場合、マージファイルは、ExcelまたはCacl形式である必要があります。" );
230 mergeFile[i] = mrgFile;
236 * SOficeのコンポーネントを起動します。
238 * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。
239 * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
241 * @og.rev 5.1.7.0 (2010/06/01) マージ処理対応
243 * @throws Throwable 何らかのエラーが発生した場合。
245 * @see #close(boolean)
247 public void open() throws Throwable {
249 if( soffice == null ) {
251 soffice = ProcessFactory.newInstance();
254 soffice = new SOfficeProcess( "docconverter.class" );
258 // マージする場合は、マージ対象のファイルをテンポラリにコピーする(readOnly回避のため)
259 // テンプレート(無題)として上げると、シートコピー先として特定できなくなるため
260 if( mergeFile != null ) {
261 final File origFile = new File( origName );
262 inputName = soffice.getTempPath() + System.currentTimeMillis() + "_" + origFile.getName();
263 FileUtil.copy( origFile, new File( inputName ) );
267 // 5.1.7.0 (2010/06/01) マージ処理対応
268 xComp = getComponent( inputName, ( mergeFile == null ? true : false ), false );
270 if( mergeFile != null ) {
271 for( int i=0; i<mergeFile.length; i++ ) {
272 merge( mergeFile[i] );
278 * ドキュメントコンポーネントを取得します。
281 * @param isHidden 隠し属性[true/false]
282 * @param isAsTemplate OpenOffice上のTemplate属性[true/false]
284 * @og.rev 8.1.0.2 (2022/01/14) odsフォーマットエラー時には、rtnDoc が null になる
285 * @og.rev 8.1.1.2 (2022/02/25) calcの計算式がLibreOfficeで実行されない対応
287 * @return ドキュメントコンポーネント
289 // @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。
290 private XComponent getComponent( final String input, final boolean isHidden, final boolean isAsTemplate ) {
291 final PropertyValue[] calcProps = new PropertyValue[2];
292 calcProps[0] = new PropertyValue();
293 calcProps[0].Name = "Hidden";
294 calcProps[0].Value = isHidden;
295 calcProps[1] = new PropertyValue();
296 calcProps[1].Name = "AsTemplate";
297 calcProps[1].Value = isAsTemplate;
299 final String url = "file:///" + input.replace( '\\', '/' );
302 // final XComponentLoader cloader = (XComponentLoader) UnoRuntime.queryInterface( XComponentLoader.class, soffice.getDesktop() );
303 final XComponentLoader cloader = UnoRuntime.queryInterface( XComponentLoader.class, soffice.getDesktop() );
305 rtnDoc = cloader.loadComponentFromURL( url, "_blank", 0, calcProps );
307 // 8.1.1.2 (2022/02/25) calcの計算式がLibreOfficeで実行されない対応
308 final XCalculatable calc = UnoRuntime.queryInterface(XCalculatable.class,rtnDoc);
309 // calc.enableAutomaticCalculation(true);
312 catch( final IOException ex ) {
313 throw new HybsSystemException( "OpenOfficeの立ち上げ時にエラーが発生しました(入出力エラー)。", ex );
315 catch( final IllegalArgumentException ex ) {
316 throw new HybsSystemException( "OpenOfficeの立ち上げ時にエラーが発生しました(パラメーター不正)。", ex );
319 // 8.1.0.2 (2022/01/14)
320 if( rtnDoc == null ) {
321 final String errMsg = "OpenOffice[" + input + "]ファイルが不正です。" + CR
322 + "印刷範囲設定や、データにCTRL文字等が含まれていないかご確認ください。";
323 throw new HybsSystemException( errMsg );
330 * ドキュメント(xls,ods)のマージを行います。
332 * @param mergeInputName マージ対象のファイル名
334 // @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。
335 private void merge( final String mergeInputName ) {
336 // マージする副ファイルは、テンプレート(無題)として上げる(readOnly回避のため)
337 final XComponent subDoc = getComponent( mergeInputName, false, true );
339 final XDispatchProvider dispatchProvider
340 // = (XDispatchProvider)UnoRuntime.queryInterface( XDispatchProvider.class
341 = UnoRuntime.queryInterface( XDispatchProvider.class
342 // ,((XController)UnoRuntime.queryInterface( XController.class
343 ,(UnoRuntime.queryInterface( XController.class
344 // ,((XModel)UnoRuntime.queryInterface( XModel.class
345 ,(UnoRuntime.queryInterface( XModel.class
347 )).getCurrentController()
351 final XDispatchHelper xDispatchHelper = soffice.getDispatcher();
352 xDispatchHelper.executeDispatch(dispatchProvider, ".uno:TableSelectAll", "", 0, new PropertyValue[0]);
354 String title = new File( inputName ).getName() ;
355 title = title.substring( 0, title.indexOf( '.' ) );
357 final PropertyValue[] moveProps = new PropertyValue[3];
358 moveProps[0] = new PropertyValue();
359 moveProps[0].Name = "DocName";
360 moveProps[0].Value = title;
361 moveProps[1] = new PropertyValue();
362 moveProps[1].Name = "Index";
363 moveProps[1].Value = 32767;
364 moveProps[2] = new PropertyValue();
365 moveProps[2].Name = "Copy";
366 moveProps[2].Value = true;
367 xDispatchHelper.executeDispatch(dispatchProvider, ".uno:Move", "", 0, moveProps);
369 closeComponent( subDoc );
373 * Calcコンポーネントをクローズします。
375 * このクローズ処理は、処理が正常終了した場合に呼び出しする必要があります。
376 * 例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
378 * このメソッドは#close(false)と同じです。
380 * @throws Throwable 何らかのエラーが発生した場合。
381 * @see #close(boolean)
383 public void close() throws Throwable {
388 * Calcコンポーネントをクローズします。
390 * 引数のisErrがtrueの場合、この変換オブジェクトで生成されたプロセスは強制的に破棄されます。
391 * falseの場合は、プロセスは、ファクトリクラスを経由して、キャッシュに戻されます。
392 * (バッチ処理の場合は、いずれの場合も、プロセスは強制的に破棄されます)
394 * 起動から変換、クローズまでの書く処理で例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
396 * #close(false)は#close()と同じであるため、通常利用することはありません。
398 * @og.rev 4.2.4.1 (2008/07/07 ) 終了処理を60回で終わるように修正
399 * @og.rev 4.3.0.0 (2008/07/15 ) ↑は6秒しか待っていなかったので、60秒待つように修正
401 * @param isErr trueの場合、この変換オブジェクトで生成されたプロセスは強制的に破棄されます。
403 // @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。
404 public void close( final boolean isErr ) {
405 if( xComp != null ) {
406 closeComponent( xComp );
409 if( soffice != null ) {
412 ProcessFactory.remove( soffice );
415 ProcessFactory.release( soffice );
423 // マージした場合は、テンポラリにコピーしたファイルを削除
424 // 6.0.0.1 (2014/04/25) These nested if statements could be combined
425 if( mergeFile != null && ! ( new File( inputName ) ).delete() ) {
426 System.err.println( "テンポラリにコピーしたファイルを削除できませんでした。[" + inputName + "]" );
431 * ドキュメントコンポーネントをクローズします。
433 * @param comp ドキュメントコンポーネント
435 // @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。
436 private void closeComponent( final XComponent comp ) {
437 XCloseable closeable = null;
438 for( int i=0;; ++i ) {
440 // closeable = (XCloseable) UnoRuntime.queryInterface( XCloseable.class, comp );
441 closeable = UnoRuntime.queryInterface( XCloseable.class, comp );
442 closeable.close( true );
445 catch( final CloseVetoException ex ) {
446 // 4.2.4.1 (2008/07/07 )
447 // 4.3.4.4 (2009/01/01)
448 if( i == 600 ) { throw new HybsSystemException( "sofficeプロセスに接続できません。", ex ); }
452 catch( final InterruptedException ex2 ) {
453 // throw new HybsSystemException( ex2 );
462 * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。
463 * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
465 * @og.rev 4.3.0.0 (2008/07/16) スプールが終わるまでwaitし、さらにプリンタ発行の状況を監視し、正常終了かどうかを判断
466 * @og.rev 4.3.7.3 (2009/06/22) 存在しないプリンターを指定した場合のエラーハンドリングを追加
467 * @og.rev 5.1.2.0 (2010/01/01) CentOS等は、OS_INFOがLinux UNKNOWNとなるため、判定条件を変更
469 * @param printer プリンター名
470 * @throws Throwable 何らかのエラーが発生した場合。
472 public void print( final String printer ) throws Throwable {
473 if( printer == null || printer.isEmpty() ) {
474 throw new HybsSystemException( "プリンターが指定されていません。" );
477 // if( xComp == null ) { throw new HybsSystemException( "初めに、#open()を実行して下さい(1)" ); }
478 // @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。
479 // final XPrintable xprintable = (XPrintable) UnoRuntime.queryInterface( XPrintable.class, xComp );
480 final XPrintable xprintable = UnoRuntime.queryInterface( XPrintable.class, xComp );
481 // @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。
482 // final XPrintJobBroadcaster selection = (XPrintJobBroadcaster) UnoRuntime.queryInterface(XPrintJobBroadcaster.class, xprintable);
483 final XPrintJobBroadcaster selection = UnoRuntime.queryInterface(XPrintJobBroadcaster.class, xprintable);
484 final MyPrintJobListener listener = new MyPrintJobListener();
485 selection.addPrintJobListener( listener );
487 final PropertyValue[] tmpProps = new PropertyValue[1];
488 tmpProps[0] = new PropertyValue();
489 tmpProps[0].Name = "Name";
490 // 5.1.2.0 (2010/01/01) CentOS等は、OS_INFOがLinux UNKNOWNとなるため、判定条件を変更
491 // OSがLinuxの場合は、プリンタ名称の前後に"<",">"を付加
492 tmpProps[0].Value = "LINUX".indexOf( HybsSystem.sys( "OS_INFO" ).toUpperCase( Locale.JAPAN ) ) >= 0 ? "<" + printer + ">" : printer;
494 // 4.3.4.4 (2009/01/01)
496 xprintable.setPrinter( tmpProps );
498 catch( final IllegalArgumentException ex ) {
499 throw new HybsSystemException( "印刷時にエラーが発生しました。", ex );
502 // 4.3.7.3 (2009/06/22) 存在しないプリンタを指定した場合は、PropertyValueに
503 // デフォルトプリンターが入るため、引数の値と合致しているかで正しく設定されたかを確認
504 String curPrinter = null;
505 for( final PropertyValue chkProp : xprintable.getPrinter() ) {
506 if( "Name".equals( chkProp.Name) ) {
507 curPrinter = (String)chkProp.Value;
512 // final PropertyValue[] chkProps = xprintable.getPrinter();
513 // for( int i=0; i<chkProps.length; i++ ) {
514 // if( "Name".equals( chkProps[i].Name) ) {
515 // curPrinter = (String)chkProps[i].Value;
519 if( !(printer.equalsIgnoreCase( curPrinter ) ) ) {
520 final String errMsg = "プリンター[" + printer + "]を発行先に指定できませんでした。" + CR
521 + "存在しないプリンタ名が指定されている可能性があります。";
522 throw new HybsSystemException( errMsg );
525 // 4.3.0.0 (2008/07/16)
526 final PropertyValue[] printProps = new PropertyValue[1];
527 printProps[0] = new PropertyValue();
528 printProps[0].Name = "Wait";
529 printProps[0].Value = true;
531 // 4.3.4.4 (2009/01/01)
533 xprintable.print( printProps );
535 catch( final IllegalArgumentException ex ) {
536 throw new HybsSystemException( "印刷時にエラーが発生しました。", ex );
539 // 4.3.0.0 (2008/07/16)
540 // 6.9.7.0 (2018/05/14) PMD Useless parentheses.
541 // if( listener.getStatus() == null
542 // || listener.getStatus() != PrintableState.JOB_COMPLETED && listener.getStatus() != PrintableState.JOB_SPOOLED ) {
543 if( listener.isError() ) {
544 throw new HybsSystemException ( "Error Occured while spooling print job. Check Spooler-Service!!!");
549 * プリンタジョブの状況を監視するリスナーです。
551 * @author Hiroki.Nakamura
553 private static final class MyPrintJobListener implements XPrintJobListener {
554 private PrintableState status ;
557 * PrintJobEventのステータスを内部変数にセットします。
559 * @param event PrintJobEventオブジェクト
561 @Override // XPrintJobListener
562 public void printJobEvent( final PrintJobEvent event ) {
563 status = event.State;
567 * EventObjectの処理を実施します。(ここでは何も行いません。)
569 * @param event EventObjectオブジェクト
571 @Override // XPrintJobListener
572 public void disposing( final EventObject event ) {
573 // 何もありません。(PMD エラー回避)
577 // * PrintableStateオブジェクトを返します。
579 // * @og.rev 8.0.3.0 (2021/12/17) Delete
581 // * @return PrintableStateオブジェクト
583 // public PrintableState getStatus() {
588 * PrintableStateオブジェクトの状態を返します。
590 * statusが nullか、COMPLETEDでなく、SPOOLEDでない場合にエラーと判断します。
592 * @return エラーの場合、true
594 public boolean isError() {
595 return status == null || status != PrintableState.JOB_COMPLETED && status != PrintableState.JOB_SPOOLED ;
602 * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。
604 * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。
605 * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
607 * @param outputName 出力ファイル名
608 * @throws Throwable 何らかのエラーが発生した場合。
610 // public void ods( final String outputName ) throws Throwable {
611 // // saveDoc( outputName, getFilterName( getSuffix( inputName ), "ods" ) );
612 // saveDoc( outputName, getFilterName( inputName, "ods" ) );
616 // * Excel(xls)出力を行います。
618 // * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。
620 // * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。
621 // * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
623 // * @param outputName 出力ファイル名
624 // * @throws Throwable 何らかのエラーが発生した場合。
626 // public void xls( final String outputName ) throws Throwable {
627 // // saveDoc( outputName, getFilterName( getSuffix( inputName ), "xls" ) );
628 // saveDoc( outputName, getFilterName( inputName, "xls" ) );
632 // * Writer(ods)出力を行います。
634 // * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。
636 // * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。
637 // * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
639 // * @param outputName 出力ファイル名
640 // * @throws Throwable 何らかのエラーが発生した場合。
642 // public void odt( final String outputName ) throws Throwable {
643 // // saveDoc( outputName, getFilterName( getSuffix( inputName ), "odt" ) );
644 // saveDoc( outputName, getFilterName( inputName, "odt" ) );
648 // * Word(doc)出力を行います。
650 // * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。
652 // * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。
653 // * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
655 // * @param outputName 出力ファイル名
656 // * @throws Throwable 何らかのエラーが発生した場合。
658 // public void doc( final String outputName ) throws Throwable {
659 // // saveDoc( outputName, getFilterName( getSuffix( inputName ), "doc" ) );
660 // saveDoc( outputName, getFilterName( inputName, "doc" ) );
664 // * Impress(odp)出力を行います。
666 // * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。
668 // * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。
669 // * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
671 // * @param outputName 出力ファイル名
672 // * @throws Throwable 何らかのエラーが発生した場合。
674 // public void odp( final String outputName ) throws Throwable {
675 // // saveDoc( outputName, getFilterName( getSuffix( inputName ), "odp" ) );
676 // saveDoc( outputName, getFilterName( inputName, "odp" ) );
680 // * PowerPoint(ppt)出力を行います。
682 // * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。
684 // * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。
685 // * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
687 // * @param outputName 出力ファイル名
688 // * @throws Throwable 何らかのエラーが発生した場合。
690 // public void ppt( final String outputName ) throws Throwable {
691 // // saveDoc( outputName, getFilterName( getSuffix( inputName ), "ppt" ) );
692 // saveDoc( outputName, getFilterName( inputName, "ppt" ) );
698 * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。
700 * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。
701 * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
703 * @og.rev 8.1.0.3 (2022/01/21) checkOutputメソッドは呼出元で判定する。
705 * @param outputName 出力ファイル名
706 * @param pdfPasswd PDFパスワード
707 * @throws Throwable 何らかのエラーが発生した場合。
709 public void pdf( final String outputName, final String pdfPasswd ) throws Throwable {
710 if( !checkOutput( outputName ) ){ return; } // 8.1.0.3 (2022/01/21)
712 // savePdf( outputName, getFilterName( getSuffix( inputName ), "pdf" ), pdfPasswd );
713 savePdf( outputName, getFilterName( inputName, "pdf" ), pdfPasswd );
717 // * 【保留】Excel2007(xlsx)出力を行います。
719 // * 入力形式で未対応の場合(形式は入力ファイルの拡張子で判別)、例外が発行されます。
721 // * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。
722 // * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
724 // * @og.rev 8.0.3.0 (2021/12/17) ods→xlsx変換時のシート毎の行数
726 // * @param outputName 出力ファイル名
727 // * @param sheetRows シート毎の行数List
728 // * @throws Throwable 何らかのエラーが発生した場合。
730 // public void xlsx( final String outputName,final List<Integer> sheetRows ) throws Throwable {
731 // saveDoc( outputName, getFilterName( inputName, "xlsx" ) );
733 // // 余分な行やカラムを除去(ただし、ものすごく遅い)
734 // final File outputFile = new File( outputName );
735 // final ExcelModel excel = new ExcelModel( outputFile , true );
736 // excel.activeWorkbook( sheetRows );
737 // excel.saveFile( outputFile );
741 * 出力ファイルから出力形式を自動判別し、変換を行います。
743 * 入出力形式で未対応の場合(形式は入出力ファイルの拡張子で判別)、例外が発行されます。
745 * 正常に処理が終了した場合は、#close()を発行し、終了処理を行って下さい。
746 * また、例外が発生した場合は、#close(true)を発行し、終了処理を行って下さい。
748 * @og.rev 8.1.0.3 (2022/01/21) checkOutputメソッドは呼出元で判定する。
750 * @param outputName 出力ファイル名
751 * @throws Throwable 何らかのエラーが発生した場合。
753 public void auto( final String outputName ) throws Throwable {
754 if( !checkOutput( outputName ) ){ return; } // 8.1.0.3 (2022/01/21)
756 final String outSuffix = getSuffix( outputName );
757 if( "pdf".equalsIgnoreCase( outSuffix ) ) {
758 // savePdf( outputName, getFilterName( getSuffix( inputName ), outSuffix ), null );
759 savePdf( outputName, getFilterName( inputName, outSuffix ), null );
762 // saveDoc( outputName, getFilterName( getSuffix( inputName ), outSuffix ) );
763 saveDoc( outputName, getFilterName( inputName, outSuffix ) );
768 * フィルター名を指定して、各種ファイル形式に出力を行います。
770 * @og.rev 8.1.0.3 (2022/01/21) checkOutputメソッドは呼出元で判定する。
772 * @param outputName 出力ファイル名
773 * @param filter フィルター名
775 private void saveDoc( final String outputName, final String filter ) {
776 // if( !checkOutput( outputName ) ){ return; }
778 final PropertyValue[] storeProps = new PropertyValue[1];
779 storeProps[0] = new PropertyValue();
780 storeProps[0].Name = "FilterName";
781 storeProps[0].Value = filter;
783 final String url = "file:///" + outputName.replace( '\\', '/' );
784 // if( xComp == null ) { throw new HybsSystemException( "初めに、#open()を実行して下さい(2)" ); }
785 // @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。
786 // final XStorable xstorable = (XStorable) UnoRuntime.queryInterface( XStorable.class, xComp );
787 final XStorable xstorable = UnoRuntime.queryInterface( XStorable.class, xComp );
789 xstorable.storeAsURL( url, storeProps );
791 catch( final Throwable th ) {
792 throw new HybsSystemException( "ファイルへの変換時にエラーが発生しました。[filter=" + filter + "]", th );
797 * フィルターを指定してPDF出力を行います。
799 * @og.rev 8.1.0.3 (2022/01/21) checkOutputメソッドは呼出元で判定する。
801 * @param outputName 出力ファイル名
802 * @param filter フィルター名
803 * @param pdfPasswd PDFパスワード
805 private void savePdf( final String outputName, final String filter, final String pdfPasswd ) {
806 // if( !checkOutput( outputName ) ){ return; }
808 final PropertyValue[] storeProps;
809 if( pdfPasswd == null || pdfPasswd.isEmpty() ) {
810 storeProps = new PropertyValue[1];
811 storeProps[0] = new PropertyValue();
812 storeProps[0].Name = "FilterName";
813 storeProps[0].Value = filter;
815 // 帳票要求テーブルでPDFパスワードが設定されている場合
817 final PropertyValue[] filterProps = new PropertyValue[2];
818 filterProps[0] = new PropertyValue();
819 filterProps[0].Name = "EncryptFile";
820 filterProps[0].Value = true;
821 filterProps[1] = new PropertyValue();
822 filterProps[1].Name = "DocumentOpenPassword";
823 filterProps[1].Value = pdfPasswd;
825 storeProps = new PropertyValue[2];
826 storeProps[0] = new PropertyValue();
827 storeProps[0].Name = "FilterName";
828 storeProps[0].Value = "calc_pdf_Export";
829 storeProps[1] = new PropertyValue();
830 storeProps[1].Name = "FilterData";
831 storeProps[1].Value = filterProps;
834 final String url = "file:///" + outputName.replace( '\\', '/' );
835 // if( xComp == null ) { throw new HybsSystemException( "初めに、#open()を実行して下さい(3)" ); }
836 // @SuppressWarnings("cast") // OpenOffice 3.2 での冗長なキャスト警告の抑止。キャストをはずすと、旧3.1 では、エラーになる。
837 // final XStorable xstorable = (XStorable) UnoRuntime.queryInterface( XStorable.class, xComp );
838 final XStorable xstorable = UnoRuntime.queryInterface( XStorable.class, xComp );
840 xstorable.storeToURL( url, storeProps );
842 catch( final Throwable th ) {
843 final String err = "PDFファイルへの変換時にエラーが発生しました。[filter=" + filter + "]"
844 + " URL=" + url + " , storeProps=" + storeProps + " , xComp=" + xComp ;
846 // throw new HybsSystemException( "PDFファイルへの変換時にエラーが発生しました。[filter=" + filter + "]", th );
847 throw new HybsSystemException( err, th );
854 * @og.rev 8.1.0.3 (2022/01/21) ファイルの拡張子が同じ場合は、copyで対応する。
856 * @param outputName 出力ファイル名
858 * @return 処理対象かどうか(入力ファイルと出力ファイルが同じ場合は、falseが返ります)
860 private boolean checkOutput( final String outputName ) {
861 if( outputName == null || outputName.isEmpty() ) {
862 throw new HybsSystemException( "出力ファイルが指定されていません。" );
866 // 8.1.0.3 (2022/01/21) 出力ファイルがあれば、無条件削除
867 final Path outPath = Paths.get( outputName );
868 if( Files.exists( outPath ) ) { Files.delete( outPath ); }
869 // if( Files.exists( outPath ) && !Files.deleteIfExists( outPath ) ) {
870 // throw new HybsSystemException( "出力先の既存ファイルが削除できません。[file=" + outputName + "]" );
873 // 8.1.0.3 (2022/01/21) 拡張子が同じなら、copyする。
874 if( getSuffix( inputName ).equals( getSuffix( outputName ) ) ) {
875 final Path inPath = Paths.get( inputName );
876 Files.copy( inPath , outPath , StandardCopyOption.REPLACE_EXISTING );
880 // catch( final IOException ex ) { // 意味不明なエラーが出る。
881 catch( final Throwable ex ) {
882 throw new HybsSystemException( "ファイルコピーが失敗しました。[in=" + inputName + "],out=" + outputName + "]" ,ex );
887 // if( outFile.exists() ) {
888 // if( inFile.getAbsoluteFile().equals( outFile.getAbsoluteFile() ) ) {
889 // // 入力と出力が同じファイルの場合な何もしない
892 // else if( !outFile.delete() ) {
893 // throw new HybsSystemException( "出力先の既存ファイルが削除できません。[file=" + outputName + "]" );
900 * 入出力の形式(拡張子)からフィルター名を取得します。
902 * 入力ファイル名からサフィックスを取り出して、FILTER_MAP からフィルター名を取り出します。
904 * @og.rev 8.0.1.0 (2021/10/29) メッセージ修正
906 // * @param inSuffix 入力拡張子
907 * @param inputName 入力ファイル名
908 * @param outSuffix 出力拡張子
912 // private static String getFilterName( final String inSuffix, final String outSuffix ) {
913 private static String getFilterName( final String inputName, final String outSuffix ) {
914 final String inSuffix = getSuffix( inputName );
916 final String filterName = FILTER_MAP.get( inSuffix + "_" + outSuffix );
917 if( filterName == null ) {
918 final String errMsg = "入力ファイル=[" + inputName + "] , 出力形式=[" + outSuffix + "]" + CR
919 + "入力形式、出力形式は、以下の対応表に基づき、設定して下さい。" + CR
920 + "入力[Calc(ods) ,Excel(xls) ] ⇒ 出力[Calc(ods) ,Excel(xls,xlsx) ,PDF]" + CR
921 + "入力[Writer(odt) ,Word(doc) ] ⇒ 出力[Writer(odt) ,Word(doc,docx) ,PDF]" + CR
922 + "入力[Impress(odp),PowerPoint(ppt)] ⇒ 出力[Impress(odp),PowerPoint(ppt,pptx),PDF]" + CR
923 + "xlsx,docx,pptx は、MS 2007形式の為、LibreOffice のみ利用できます。" + CR ;
924 throw new HybsSystemException( errMsg );
930 * ファイル名から拡張子(小文字)を求めます。
932 * @param fileName ファイル名
934 * @return 拡張子(小文字)…存在しない場合は、空文字列
936 private static String getSuffix( final String fileName ) {
937 // String suffix = null;
939 if( fileName != null ) {
940 final int sufIdx = fileName.lastIndexOf( '.' );
942 suffix = fileName.substring( sufIdx + 1 ).toLowerCase( Locale.JAPAN );
949 // * ドキュメントの変換を行うための簡易メソッドです。
951 // * 変換方法は、出力ファイルの拡張子により自動的に決定されます。
953 // * @og.rev 8.0.3.0 (2021/12/17) ファイル連結の簡易メソッドは、使用しません。
955 // * @param inputFile 入力ファイル名
956 // * @param outputFile 出力ファイル名
957 // * @see #convert(String[], String, boolean)
959 // public static final void convert( final String inputFile, final String outputFile ) {
960 //// convert( StringUtil.csv2Array( inputFile ), outputFile );
961 // convert( StringUtil.csv2Array( inputFile ), outputFile, true ); // 8.0.3.0 (2021/12/17)
965 // * ドキュメントの変換を行うための簡易メソッドです。
967 // * 変換方法は、出力ファイルの拡張子により自動的に決定されます。
969 // * @og.rev 8.0.3.0 (2021/12/17) ファイル連結の簡易メソッドは、使用しません。
971 // * @param inputFile 入力ファイル名配列
972 // * @param outputFile 出力ファイル名
973 // * @see #convert(String[], String, boolean)
975 // public static final void convert( final String[] inputFile, final String outputFile ) {
976 // convert( inputFile, outputFile, true );
980 * ドキュメントの変換を行うための簡易メソッドです。
982 * 変換方法は、出力ファイルの拡張子により自動的に決定されます。
984 * isOnlineがtrueに指定された場合、soffice.binのプロセスをファクトリークラス経由で生成し、
986 * 但し、システムリソースが読み込まれないような、バッチファイルから起動した場合は、この方法は
987 * 利用できないため、isOnlineをfalseに指定する必要があります。
989 * @og.rev 8.0.3.0 (2021/12/17) ファイル連結の簡易メソッドは、使用しません。
991 * @param inputFile 入力ファイル名配列
992 * @param outputFile 出力ファイル名
993 * @param isOnline オンライン(Web環境での使用)かどうか
995 public static final void convert( final String inputFile[], final String outputFile, final boolean isOnline ) {
996 final DocConverter_OOO dc = new DocConverter_OOO( inputFile, isOnline );
999 dc.auto( outputFile );
1002 catch( final Throwable th ) {
1004 throw new HybsSystemException( th );
1011 * 変換方法は、出力ファイルの拡張子により自動的に決定されます。
1013 * @og.rev 4.3.1.1 (2008/08/23) mkdirs の戻り値判定
1014 * @og.rev 6.3.9.1 (2015/11/27) A method/constructor shouldnt explicitly throw java.lang.Exception(PMD)。
1015 * @og.rev 8.0.3.0 (2021/12/17) ファイル連結の簡易メソッドは、使用しません。
1017 * @param args コマンド引数配列
1019 public static void main( final String[] args ) {
1020 if( args.length < 2 ) {
1021 System.out.println( "usage : OdsConverter [inputFile] [outputFile]" );
1025 DocConverter_OOO.convert( new String[] {args[0]}, args[1], false );
1027 // final File input = new File( args[0] );
1028 // final File output = new File( args[1] );
1030 // // 4.3.1.1 (2008/08/23) mkdirs の戻り値判定
1031 // if( outPath.mkdirs() ) {
1032 // System.err.println( args[1] + " の ディレクトリ作成に失敗しました。" );
1035 // final String absPath = output.getAbsolutePath() + FS ; // 8.0.3.0 (2021/12/17)
1036 // if( input.isDirectory() ) {
1037 // final File[] inputFiles = input.listFiles();
1038 // // 6.3.9.0 (2015/11/06) null になっている可能性があるメソッドの戻り値を利用している(findbugs)
1039 // if( inputFiles != null ) {
1040 // for( final File file : inputFiles ) {
1041 // final String inputFile = file.getAbsolutePath();
1042 //// final String outputFile = output.getAbsolutePath() + File.separator + file.getName().replace( ".xls", ".ods" );
1043 // final String outputFile = absPath + file.getName().replace( ".xls", ".ods" );
1044 // convert( StringUtil.csv2Array( inputFile ), outputFile, false );
1049 // final String inputFile = input.getAbsolutePath();
1050 //// final String outputFile = output.getAbsolutePath() + File.separator + input.getName().replace( ".xls", ".ods" );
1051 // final String outputFile = absPath + input.getName().replace( ".xls", ".ods" );
1052 // convert( StringUtil.csv2Array( inputFile ), outputFile, false );