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 */ 016 package org.opengion.fukurou.process; 017 018 import org.opengion.fukurou.util.Argument; 019 import org.opengion.fukurou.util.SystemParameter; 020 import org.opengion.fukurou.util.StringUtil; 021 import org.opengion.fukurou.util.LogWriter; 022 import org.opengion.fukurou.util.HybsEntry ; 023 import org.opengion.fukurou.util.Closer; 024 import org.opengion.fukurou.model.Formatter; 025 import org.opengion.fukurou.db.ConnectionFactory; 026 027 import java.util.Map ; 028 import java.util.LinkedHashMap ; 029 import java.util.Set ; 030 import java.util.HashSet ; 031 032 import java.sql.Connection; 033 import java.sql.Statement; 034 import java.sql.PreparedStatement; 035 import java.sql.ParameterMetaData; 036 import java.sql.SQLException; 037 038 /** 039 * Process_DBWriter は、上流から受け取ったデータをデータベ?スに書き込? 040 * CainProcess インターフェースの実?ラスです? 041 * 042 * 上?プロセスチェインの??タは上流から下流へと渡されます?)から受け取っ? 043 * LineModel を?に、データベ?スへの書き込みを行います? 044 * 045 * ??タベ?ス接続?等?、ParamProcess のサブクラス(Process_DBParam)に 046 * 設定された接?Connection)を使用します? 047 * 048 * 引数??中にスペ?スを含??合?、ダブルコー??ション("") で括って下さ?? 049 * 引数??の ?』?前後には、スペ?スは挟めません。??key=value の様に 050 * 繋げてください? 051 * 052 * SQL?は、{@DATE.YMDH}等?シス?変数が使用できます? 053 * 054 * @og.formSample 055 * Process_DBWriter -dbid=DBGE -table=GE41 056 * 057 * [ -dbid=DB接続ID ] ??-dbid=DBGE (? Process_DBParam の -configFile で?す?DBConfig.xml ファイルで規? 058 * [ -table=登録??ブルID ] ???????する?合?不要?INSERT する場合???ブルID 059 * [ -sql=検索SQL? ] ??-sql="UPDATE GE41 SET NAME_JA = [NAME_JA],LABEL_NAME = [LABEL_NAME] 060 * WHERE SYSTEM_ID = [SYSTEM_ID] AND CLM = [CLM]" 061 * [ -sqlFile=登録SQL?ァ??? ] ??-sqlFile=update.sql 062 * ?? -sql ?-sqlFile が指定されな??合??table で????ブルに全カラ?insert です? 063 * [ -sql_XXXX=固定? ] ??-sql_SYSTEM_ID=GE 064 * SQL?の{@XXXX}??を指定?固定?で置き換えます? 065 * WHERE SYSTEM_ID='{@SYSTEM_ID}' ?WHERE SYSTEM_ID='GE' 066 * [ -const_XXXX=固定? ] ??-const_FGJ=1 067 * LineModel のキー(const_ に続く??)の値に、固定?を設定します? 068 * キーが異なれ?、?のカラ?を指定できます? 069 * [ -omitClms=AAA,BBB,… ] ??-omitClms=UNIQ,FGJ,DYSET 070 * -table 属?でINSERT?自動作?する場合?取り除くカラ?? 071 * カンマ区?で??できます? 072 * [ -initSql=開始時SQL? ] ??-initSql="DELETE FROM GE41 WHERE FGJ = '9'" 073 * [ -initSqlFile=開始時SQL?ァ??] ??-initSqlFile=update.sql 074 * [ -endSql=終?SQL? ] ??-endSql="UPDATE GE41 SET FGJ = '1'" 075 * [ -endSqlFile=終?SQL?ァ???] ??-endSqlFile=update.sql 076 * [ -commitCnt=commit処??] ???数毎にコミットを発行します?0 の場合?、終?でコミットしません? 077 * [ -display=[false/true] ] ??結果を標準?力に表示する(true)かしな?false)?初期値:false[表示しない]) 078 * [ -debug=[false/true] ] ?デバッグ??を標準?力に表示する(true)かしな?false)?初期値:false[表示しない]) 079 * 080 * @version 4.0 081 * @author Kazuhiko Hasegawa 082 * @since JDK5.0, 083 */ 084 public class Process_DBWriter extends AbstractProcess implements ChainProcess { 085 private static final String CNST_KEY = "const_" ; 086 private static final String SQL_KEY = "sql_" ; 087 088 private Connection connection = null; 089 private PreparedStatement pstmt = null; 090 private ParameterMetaData pMeta = null; // 5.1.1.0 (2009/11/11) setObject に、Type を渡す?(PostgreSQL対? 091 private boolean useParamMetaData = false; // 5.1.1.0 (2009/11/11) setObject に、Type を渡す?(PostgreSQL対? 092 093 private String dbid = null; 094 private String sql = null; 095 private String initSql = null; // 5.7.2.2 (2014/01/24) 追? 096 private String endSql = null; // 5.7.2.2 (2014/01/24) 追? 097 private String table = null; 098 private int[] clmNos = null; // ファイルのヘッ??のカラ?号 099 private int commitCnt = 0; // コミットするまとめ件数 100 private boolean display = false; // 表示しな? 101 private boolean debug = false; // 5.7.3.0 (2014/02/07) ???? 102 103 private String[] cnstClm = null; // 固定?を設定するカラ? 104 private int[] cnstClmNos = null; // 固定?を設定するカラ?号 105 private String[] constVal = null; // カラ?号に対応した固定? 106 107 private boolean firstRow = true; // ??の?目 108 private int count = 0; 109 private String[] omitClms = null; // 4.0.0.0 (2007/09/21) table ?時に取り除くカラ? 110 111 private static final Map<String,String> mustProparty ; // ?プロパティ???チェ?用 Map 112 private static final Map<String,String> usableProparty ; // ?プロパティ?整合?チェ? Map 113 114 static { 115 mustProparty = new LinkedHashMap<String,String>(); 116 117 usableProparty = new LinkedHashMap<String,String>(); 118 usableProparty.put( "dbid", "Process_DBParam の -configFile で?す?DBConfig.xml ファイルで規? ); 119 usableProparty.put( "table", "INSERT する場合???ブルID SQL??する?合?不要?" ); 120 usableProparty.put( "sql", "更新SQL?sql or sqlFile ??)" + 121 CR + "? \"UPDATE GE41 " + 122 CR + "SET NAME_JA = [NAME_JA],LABEL_NAME = [LABEL_NAME] " + 123 CR + "WHERE SYSTEM_ID = [SYSTEM_ID] AND CLM = [CLM]\"" ); 124 usableProparty.put( "sqlFile", "登録SQLファイル(sql or sqlFile ??)? update.sql" ); 125 usableProparty.put( "sql_", "SQL?の{@XXXX}??を指定?固定?で置き換えます?" + 126 CR + "WHERE SYSTEM_ID='{@SYSTEM_ID}' ?WHERE SYSTEM_ID='GE'" ); 127 usableProparty.put( "const_", "LineModel のキー(const_ に続く??)の値に、固定?? + 128 CR + "設定します?キーが異なれ?、?のカラ?を指定できます?" + 129 CR + "? -sql_SYSTEM_ID=GE" ); 130 // 4.0.0.0 (2007/09/21) 属?を追? 131 usableProparty.put( "omitClms", "-table 属?でINSERT?自動作?する場合?取り除くカラ?? + 132 CR + "カンマ区?で??できます?" + 133 CR + "? -omitClms=UNIQ,FGJ,DYSET" ); 134 usableProparty.put( "initSql" , "開始時に??実行されるSQL??します?" ); // 5.7.2.2 (2014/01/24) 追? 135 usableProparty.put( "initSqlFile", "開始時に??実行されるSQLファイルを指定します?" ); // 5.7.2.2 (2014/01/24) 追? 136 usableProparty.put( "endSql" , "終?に??実行されるSQL??します?" ); // 5.7.2.2 (2014/01/24) 追? 137 usableProparty.put( "endSqlFile" , "終?に??実行されるSQLファイルを指定します?" ); // 5.7.2.2 (2014/01/24) 追? 138 usableProparty.put( "commitCnt", "?数毎にコミットを発行します?" + 139 CR + "0 の場合?、終?でコミットしません(初期値:0)" ); 140 usableProparty.put( "display", "結果を標準?力に表示する(true)かしな?false)? + 141 CR + "(初期値:false:表示しな?" ); 142 usableProparty.put( "debug", "????を標準?力に表示する(true)かしな?false)? + 143 CR + "(初期値:false:表示しな?" ); // 5.7.3.0 (2014/02/07) ???? 144 } 145 146 /** 147 * ?ォルトコンストラクター? 148 * こ?クラスは、動??されます??ォルトコンストラクターで? 149 * super クラスに対して、?な初期化を行っておきます? 150 * 151 */ 152 public Process_DBWriter() { 153 super( "org.opengion.fukurou.process.Process_DBWriter",mustProparty,usableProparty ); 154 } 155 156 /** 157 * プロセスの初期化を行います?初めに??、呼び出されます? 158 * 初期処?ファイルオープン??オープン?に使用します? 159 * 160 * @og.rev 4.0.0.0 (2007/09/21) omitClms 属?を追? 161 * @og.rev 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対? 162 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData ?ConnectionFactory経由で取得?(PostgreSQL対? 163 * @og.rev 5.7.2.2 (2014/01/24) initSql,initSqlFile,endSql,endSqlFile 追? 164 * 165 * @param paramProcess ??タベ?スの接続???などを持って?オブジェク? 166 */ 167 public void init( final ParamProcess paramProcess ) { 168 Argument arg = getArgument(); 169 170 table = arg.getProparty("table"); 171 sql = arg.getFileProparty("sql","sqlFile",false); 172 initSql = arg.getFileProparty("initSql","initSqlFile",false); // 5.7.2.2 (2014/01/24) 追? 173 endSql = arg.getFileProparty("endSql","endSqlFile",false); // 5.7.2.2 (2014/01/24) 追? 174 commitCnt = arg.getProparty("commitCnt",commitCnt); 175 display = arg.getProparty("display",display); 176 debug = arg.getProparty("debug",debug); // 5.7.3.0 (2014/02/07) ???? 177 // if( debug ) { println( arg.toString() ); } // 5.7.3.0 (2014/02/07) ???? 178 179 dbid = arg.getProparty("dbid"); 180 connection = paramProcess.getConnection( dbid ); 181 // 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対? 182 // useParamMetaData = ApplicationInfo.useParameterMetaData( connection ); 183 useParamMetaData = ConnectionFactory.useParameterMetaData( dbid ); // 5.3.8.0 (2011/08/01) 184 185 // 取り除くカラ?リストを配?に変換します? 186 String tempClms = arg.getProparty("omitClms",null); 187 if( tempClms != null ) { 188 omitClms = StringUtil.csv2Array( tempClms ); 189 } 190 191 if( sql == null && table == null ) { 192 String errMsg = "sql を指定しな??合?、table を??してください?; 193 throw new RuntimeException( errMsg ); 194 } 195 196 // 3.8.0.1 (2005/06/17) {@DATE.XXXX} 変換処??追? 197 // {@DATE.YMDH} などの??を?yyyyMMddHHmmss 型?日付に置き換えます? 198 // SQL?? {@XXXX} ??の固定?への置き換? 199 HybsEntry[] entry =arg.getEntrys(SQL_KEY); // 配? 200 SystemParameter sysParam = new SystemParameter( sql ); 201 sql = sysParam.replace( entry ); 202 203 // 5.7.2.2 (2014/01/24) initSql,endSql に?@XXXX} ??の置き換えを行います? 204 if( initSql != null ) { 205 SystemParameter sysParam2 = new SystemParameter( initSql ); 206 initSql = sysParam2.replace( entry ); 207 execSql( initSql ); 208 } 209 if( endSql != null ) { 210 SystemParameter sysParam3 = new SystemParameter( endSql ); 211 endSql = sysParam3.replace( entry ); 212 } 213 214 HybsEntry[] cnstKey = arg.getEntrys( CNST_KEY ); // 配? 215 int csize = cnstKey.length; 216 cnstClm = new String[csize]; 217 constVal = new String[csize]; 218 for( int i=0; i<csize; i++ ) { 219 cnstClm[i] = cnstKey[i].getKey(); 220 constVal[i] = cnstKey[i].getValue(); 221 } 222 } 223 224 /** 225 * プロセスの終?行います??に??、呼び出されます? 226 * 終???ファイルクローズ??クローズ?に使用します? 227 * 228 * @og.rev 4.0.0.0 (2007/11/27) commit,rollback,remove 処?追? 229 * @og.rev 5.1.1.0 (2009/11/11) pMeta のクリア 230 * @og.rev 5.7.2.2 (2014/01/24) endSql 処??追? 231 * 232 * @param isOK ト?タルで、OK?たかど?[true:成功/false:失敗] 233 */ 234 public void end( final boolean isOK ) { 235 boolean flag = Closer.stmtClose( pstmt ); 236 pstmt = null; 237 pMeta = null; // 5.1.1.0 (2009/11/11) 238 239 // 5.7.2.2 (2014/01/24) endSql の実? 240 Throwable th2 = null; 241 if( isOK && endSql != null ) { 242 try { execSql( endSql ); } catch (Throwable th) { th2 = th ; } 243 } 244 245 // 5.7.2.2 (2014/01/24) すべて異常がな??合?み、??る様に変更? 246 // if( isOK ) { 247 if( isOK && flag && th2 == null ) { 248 Closer.commit( connection ); 249 } 250 else { 251 Closer.rollback( connection ); 252 } 253 ConnectionFactory.remove( connection,dbid ); 254 255 if( !flag ) { 256 String errMsg = "ス??トメントをクローズ出来ません?; 257 throw new RuntimeException( errMsg ); 258 } 259 260 // 5.7.2.2 (2014/01/24) endSql の実行失敗時の処? 261 if( th2 != null ) { 262 String errMsg = "endSql の実行に失敗しました。sql=[" + endSql + "]" + CR 263 + th2.getMessage() + CR ; 264 throw new RuntimeException( errMsg,th2 ); 265 } 266 } 267 268 /** 269 * 引数の LineModel を??るメソ?です? 270 * 変換処?? LineModel を返します? 271 * 後続??行わな?????タのフィルタリングを行う場?は? 272 * null ??タを返します?つまり?null ??タは、後続??行わな? 273 * フラグの代わりにも使用して?す? 274 * なお?変換処?? LineModel と、オリジナルの LineModel が? 275 * 同?、コピ?(クローン)か?、各処?ソ??決めて?す? 276 * ドキュメントに明記されて???合?、副作用が問題になる?合?? 277 * ???とに自?コピ?(クローン)して下さ?? 278 * 279 * @og.rev 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対? 280 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData setNull 対?PostgreSQL対? 281 * @og.rev 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します? 282 * 283 * @param data オリジナルのLineModel 284 * 285 * @return 処?換後?LineModel 286 */ 287 public LineModel action( final LineModel data ) { 288 count++ ; 289 // if( display ) { println( data.dataLine() ); } 290 try { 291 if( firstRow ) { 292 pstmt = makePrepareStatement( table,data ); 293 // 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対? 294 if( useParamMetaData ) { 295 pMeta = pstmt.getParameterMetaData(); 296 } 297 298 int size = cnstClm.length; 299 cnstClmNos = new int[size]; 300 for( int i=0; i<size; i++ ) { 301 cnstClmNos[i] = data.getColumnNo( cnstClm[i] ); 302 } 303 304 firstRow = false; 305 if( display ) { println( data.nameLine() ); } // 5.7.3.0 (2014/02/07) ???? 306 } 307 308 // 固定?置き換え?? 309 for( int j=0; j<cnstClmNos.length; j++ ) { 310 data.setValue( cnstClmNos[j],constVal[j] ); 311 } 312 313 // 5.1.1.0 (2009/11/11) setObject に ParameterMetaData の getParameterType を渡す?(PostgreSQL対? 314 if( useParamMetaData ) { 315 for( int i=0; i<clmNos.length; i++ ) { 316 int type = pMeta.getParameterType( i+1 ); 317 // 5.3.8.0 (2011/08/01) setNull 対? 318 // pstmt.setObject( i+1,data.getValue(clmNos[i]),type ); 319 Object val = data.getValue(clmNos[i]); 320 if( val == null || ( val instanceof String && ((String)val).isEmpty() ) ) { 321 pstmt.setNull( i+1, type ); 322 } 323 else { 324 pstmt.setObject( i+1, val, type ); 325 } 326 } 327 } 328 else { 329 for( int i=0; i<clmNos.length; i++ ) { 330 pstmt.setObject( i+1,data.getValue(clmNos[i]) ); 331 } 332 } 333 334 pstmt.execute(); 335 if( commitCnt > 0 && ( count%commitCnt == 0 ) ) { 336 Closer.commit( connection ); 337 } 338 } 339 catch (SQLException ex) { 340 // 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します? 341 String errMsg = "SQL を実行できませんでした? + CR 342 + "errMsg=[" + ex.getMessage() + "]" + CR 343 + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR 344 + "dbid=[" + dbid + "]" + CR 345 + "sql =[" + sql + "]" + CR 346 + "data=[" + data.dataLine() + "]" + CR ; 347 // String errMsg = "sql=[" + sql + "]" + CR 348 // + "errorCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR ; 349 throw new RuntimeException( errMsg,ex ); 350 } 351 if( display ) { println( data.dataLine() ); } // 5.1.2.0 (2010/01/01) display の条件変更 352 return data; 353 } 354 355 /** 356 * ?で使用する PreparedStatement を作?します? 357 * 引数?? SQL また?、LineModel から作?した SQL より構築します? 358 * 359 * @og.rev 4.0.0.0 (2007/09/21) omitClms 属?を追? 360 * @og.rev 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します? 361 * 362 * @param table 処?象の??ブルID 363 * @param data 処?象のLineModel 364 * 365 * @return PreparedStatementオブジェク? 366 */ 367 private PreparedStatement makePrepareStatement( final String table,final LineModel data ) { 368 if( sql == null ) { 369 StringBuilder buf = new StringBuilder(); 370 String[] names = data.getNames(); 371 372 // カラ?取り除く?? 373 if( omitClms != null ) { 374 Set<String> set = new HashSet<String>(); 375 for( int i=0; i<names.length; i++ ) { 376 set.add( names[i] ); 377 } 378 for( int i=0; i<omitClms.length; i++ ) { 379 set.remove( omitClms[i] ); 380 } 381 names = set.toArray( new String[set.size()] ); 382 } 383 int size = names.length; 384 385 buf.append( "INSERT INTO " ).append( table ).append( " (" ); 386 buf.append( names[0] ); 387 for( int i=1; i<size; i++ ) { 388 buf.append( "," ).append( names[i] ); 389 } 390 buf.append( " ) VALUES ( ?" ); 391 for( int i=1; i<size; i++ ) { 392 buf.append( ",?" ); 393 } 394 buf.append( " )" ); 395 sql = buf.toString(); 396 397 // カラ?号を設定します? 398 clmNos = new int[size]; 399 for( int i=0; i<size; i++ ) { 400 clmNos[i] = data.getColumnNo( names[i] ); // 4.0.0.0 (2007/09/21) 401 } 402 } 403 else { 404 Formatter format = new Formatter( data ); 405 format.setFormat( sql ); 406 sql = format.getQueryFormatString(); 407 clmNos = format.getClmNos(); 408 } 409 410 final PreparedStatement ps ; 411 try { 412 ps = connection.prepareStatement( sql ); 413 } 414 catch (SQLException ex) { 415 // 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します? 416 String errMsg = "PreparedStatement を取得できませんでした? + CR 417 + "errMsg=[" + ex.getMessage() + "]" + CR 418 + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR 419 + "dbid =[" + dbid + "]" + CR 420 + "sql =[" + sql + "]" + CR 421 + "table=[" + table + "]" + CR 422 + "data =[" + data.dataLine() + "]" + CR ; 423 // String errMsg = "PreparedStatement を取得できませんでした? + CR 424 // + "sql=[" + sql + "]" + CR 425 // + "table=[" + table + "]" + CR 426 // + "nameLine=[" + data.nameLine() + "]" ; 427 throw new RuntimeException( errMsg,ex ); 428 } 429 430 return ps; 431 } 432 433 /** 434 * SQL処?実行します? 435 * 主に、initSql,endSqlの実行用です? 436 * ここでは、エラーが発生しても?connection は閉じません? 437 * ?的に、endメソ?で処?れるためです? 438 * 439 * @og.rev 5.7.2.2 (2014/01/24) 新規追? 440 * 441 * @param sql 実行するSQL? 442 */ 443 private void execSql( final String sql ) { 444 Statement stmt = null; 445 try { 446 stmt = connection.createStatement(); 447 stmt.execute( sql ); 448 } 449 catch (SQLException ex) { 450 // 5.7.2.2 (2014/01/24) SQL実行エラーを少し詳細に出力します? 451 String errMsg = "SQL を実行できませんでした? + CR 452 + "errMsg=[" + ex.getMessage() + "]" + CR 453 + "errCode=[" + ex.getErrorCode() + "] State=[" + ex.getSQLState() + "]" + CR 454 + "dbid=[" + dbid + "]" + CR 455 + "sql =[" + sql + "]" + CR ; 456 // String errMsg = "SQL を実行できませんでした? + CR 457 // + "DBID=" + dbid + CR 458 // + "SQL =" + sql ; 459 throw new RuntimeException( errMsg,ex ); 460 } 461 finally { 462 // connection は、endメソ?で処?れます? 463 Closer.stmtClose( stmt ); 464 } 465 } 466 467 /** 468 * プロセスの処?果のレポ?ト表現を返します? 469 * 処??ログラ?、?力件数、?力件数などの??です? 470 * こ???をそのまま、標準?力に出すことで、結果レポ?トと出来るよ? 471 * 形式で出してください? 472 * 473 * @return 処?果のレポ?? 474 */ 475 public String report() { 476 String report = "[" + getClass().getName() + "]" + CR 477 + TAB + "DBID : " + dbid + CR 478 + TAB + "Output Count : " + count ; 479 480 return report ; 481 } 482 483 /** 484 * こ?クラスの使用方法を返します? 485 * 486 * @return こ?クラスの使用方? 487 */ 488 public String usage() { 489 StringBuilder buf = new StringBuilder(); 490 491 buf.append( "Process_DBWriter は、上流から受け取ったデータをデータベ?スに書き込? ).append( CR ); 492 buf.append( "CainProcess インターフェースの実?ラスです?" ).append( CR ); 493 buf.append( CR ); 494 buf.append( "上?プロセスチェインの??タは上流から下流へと渡されます?)から" ).append( CR ); 495 buf.append( "受け取っ?LineModel を?に、データベ?スへの書き込みを行います?" ).append( CR ); 496 buf.append( CR ); 497 buf.append( "??タベ?ス接続?等?、ParamProcess のサブクラス(Process_DBParam)に" ).append( CR ); 498 buf.append( "設定された接?Connection)を使用します?" ).append( CR ); 499 buf.append( CR ); 500 buf.append( "引数??中に空白を含??合?、ダブルコー??ション(\"\") で括って下さ??" ).append( CR ); 501 buf.append( "引数??の ?』?前後には、空白は挟めません。??key=value の様に" ).append( CR ); 502 buf.append( "繋げてください? ).append( CR ); 503 buf.append( CR ); 504 buf.append( "SQL?は、{@DATE.YMDH}等?シス?変数が使用できます?" ).append( CR ); 505 buf.append( CR ).append( CR ); 506 buf.append( getArgument().usage() ).append( CR ); 507 508 return buf.toString(); 509 } 510 511 /** 512 * こ?クラスは、main メソ?から実行できません? 513 * 514 * @param args コマンド引数配? 515 */ 516 public static void main( final String[] args ) { 517 LogWriter.log( new Process_DBWriter().usage() ); 518 } 519 }