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