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.xml;
017
018 import org.opengion.fukurou.util.Closer;
019 import org.opengion.fukurou.util.LogWriter;
020 import org.opengion.fukurou.db.DBUtil;
021
022 import java.io.Reader;
023 import java.io.BufferedReader;
024 import java.io.InputStreamReader;
025 import java.io.FileInputStream;
026 import java.util.Map;
027 import java.util.List;
028 import java.util.ArrayList;
029 import java.util.regex.Pattern;
030 import java.util.regex.Matcher;
031 import java.util.Arrays;
032 import java.util.Locale;
033
034 import java.sql.DriverManager;
035 import java.sql.Connection;
036 import java.sql.Statement;
037 import java.sql.PreparedStatement;
038 import java.sql.ParameterMetaData;
039 import java.sql.DatabaseMetaData;
040 import java.sql.SQLException;
041
042 /**
043 * こã?クラスは、オラクル XDKの oracle.xml.sql.dml.OracleXMLSave クラスと
044 * ほぼ同様ã?目çš?�§使用できるクラスですã?
045 * 拡張XDK形式ã?XMLファイルを読み込み、データベã?スに INSERT しますã?
046 *
047 * 拡張XDK形式ã?å…?�¨なã‚?オラクル XDK(Oracle XML Developer's Kit)につã�?�¦は、以下ã?
048 * リンクを参照願いますã?
049 * <a href="http://otn.oracle.co.jp/software/tech/xml/xdk/index.html" target="_blank" >
050 * XDK(Oracle XML Developer's Kit)</a>
051 *
052 * こã?クラスでは、MAP を登録する[ setDefaultMap( Map ) ]ことによりã€?
053 * XMLファイルに存在しなã�?‚«ラãƒ?‚’初期値として設定することが可能になりますã?
054 * 例えば、登録日ã‚??登録è€??またã?、テンプレートより各シスãƒ?ƒ ID毎に
055 * 登録するなどですã?
056 * 同様に、読み取っã�?XMLファイルのæƒ??を書き換える機è?[ setAfterMap( Map ) ]メソãƒ?ƒ‰
057 * により、カラãƒ??値の置き換えも可能ですã?
058 *
059 * 拡張XDK形式ã?å…?�¨なã‚?オラクル XDK(Oracle XML Developer's Kit)につã�?�¦は、以下ã?
060 * リンクを参照願いますã?
061 * <a href="http://otn.oracle.co.jp/software/tech/xml/xdk/index.html" target="_blank" >
062 * XDK(Oracle XML Developer's Kit)</a>
063 *
064 * 拡張XDK形式とは、ROW 以外に、SQL処ç�?”¨タグ(EXEC_SQL)を持つ XML ファイルですã?
065 * またã?登録するãƒ??ブル(table)ã‚?ROWSETタグの属æ?æƒ??として付与することができますã?
066 * (大æ–?—小文字に注æ„?
067 * これは、オラクルXDKで処ç�?�™るå?合ã?無視されますã?で、同様に扱ã�?�“とがå?来ますã?
068 * こã?、EXEC_SQL は、それそれã? XMLãƒ??タをデータベã?スに登録する際にã€?
069 * SQL処ç�?‚’自動的に流す為の、SQLæ–?‚’記載しますã?
070 * こã?処ç�??、イベント毎に実行される為、その配置é ??重要ですã?
071 * こã?タグは、è¤?•°記述することもå?来ますが、BODY部にはã€?¼‘つのSQLæ–??み記述しますã?
072 *
073 * <ROWSET tableName="XX" >
074 * <EXEC_SQL> æœ??に記載して、å?期å?ç�?ãƒ??タクリアç?を実行させるã€?
075 * delete from GEXX where YYYYY
076 * </EXEC_SQL>
077 * <MERGE_SQL> こã?SQLæ–?�§ UPDATEして、結果が0件ならINSERTを行いますã?
078 * update GEXX set AA=[AA] , BB=[BB] where CC=[CC]
079 * </MERGE_SQL>
080 * <ROW num="1">
081 * <カラãƒ?>値1</カラãƒ?>
082 * ?¥?¥?¥
083 * <カラãƒ?>値n</カラãƒ?>
084 * </ROW>
085 * ?¥?¥?¥
086 * <ROW num="n">
087 * ?¥?¥?¥
088 * </ROW>
089 * <EXEC_SQL> æœ?¾Œに記載してã€??目の設å®?整合æ?登録)を行うã€?
090 * update GEXX set AA='XX' , BB='XX' where YYYYY
091 * </EXEC_SQL>
092 * <ROWSET>
093 *
094 * @version 4.0
095 * @author Kazuhiko Hasegawa
096 * @since JDK5.0,
097 */
098 public class HybsXMLSave implements TagElementListener {
099 /** シスãƒ?ƒ 依存ã?改行記号をセãƒ?ƒˆしますã? */
100 private static final String CR = System.getProperty("line.separator");
101
102 private String tableName = null;
103 private String[] keyColumns = null;
104 private Connection connection = null;
105 private PreparedStatement insPstmt = null; // INSERT用の PreparedStatement
106 private PreparedStatement updPstmt = null; // UPDATE用の PreparedStatement
107 private ParameterMetaData insMeta = null;
108 private ParameterMetaData updMeta = null;
109 private int insCnt = 0;
110 private int updCnt = 0;
111 private int delCnt = 0;
112 private int ddlCnt = 0; // 5.6.7.0 (2013/07/27) DDLæ–??カウンター
113 private Map<String,String> defaultMap = null;
114 private Map<String,String> afterMap = null;
115 private List<String> updClms = null;
116 private String[] insClms = null;
117 private String lastSQL = null; // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用。最後に使用したSQLæ–?
118
119 private final boolean useParamMetaData ; // 4.0.0.0 (2007/09/25)
120
121 // UPDATE時ã? [XXX] を取りå?しますã?\w は、単語構æ?æ–?? [a-zA-Z_0-9]と同じ
122 private static final Pattern pattern = Pattern.compile( "\\[\\w*\\]" );
123
124 // 5.6.9.2 (2013/10/18) EXEC_SQL のエラーを無視するかどã�?�‹を指定できますã?
125 private boolean isExecErrException = true; // true は、エラー時に Exception を発行しますã?
126
127 /**
128 * コネクションを指定して、オブジェクトを構築しますã?
129 * ãƒ??ブル名ã?、拡張XDK形式ã?ROWSETタグのtableName属æ?に
130 * 記述しておくå¿?¦�がありますã?
131 *
132 * @param conn ãƒ??タベã?ス接ç¶?
133 */
134 public HybsXMLSave( final Connection conn ) {
135 this( conn,null );
136 }
137
138 /**
139 * コネクションとãƒ??ブル名をæŒ?®šして、オブジェクトを構築しますã?
140 * ここでæŒ?®šするテーブル名ã?、デフォルトテーブルとã�?�†扱ã�?�§すã?
141 * 拡張XDK形式ã?ROWSETタグのtableName属æ?にãƒ??ブル名が記述されてã�?‚‹場合ã?ã€?
142 * そちらが優先されますã?
143 *
144 * @og.rev 4.0.0.0 (2007/09/25) ParameterMetaData を使用したパラメータ設定追åŠ??
145 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData ã‚?こã?クラスで直接取得するã?(PostgreSQL対å¿?
146 *
147 * @param conn ãƒ??タベã?ス接ç¶?
148 * @param table ãƒ??ブルå�?ROWSETタグのtable属æ?が未設定時に使用)
149 */
150 public HybsXMLSave( final Connection conn,final String table ) {
151 connection = conn;
152 tableName = table;
153 // useParamMetaData = ApplicationInfo.useParameterMetaData( conn );
154 useParamMetaData = useParameterMetaData( connection ); // 5.3.8.0 (2011/08/01)
155 }
156
157 /**
158 * EXEC_SQL のエラー時に Exception を発行するかどã�?�‹を指定できまã�?初期値:true)ã€?
159 * true を指定すると、エラー時にはã€?RuntimeException ã‚?throw しますã?
160 * false にすると、標準エラー出力にのみ、å?力しますã?
161 * こã?フラグは、EXEC_SQL のみ有効ですã?それ以外ã?タブã?処ç�?�§は、エラーが発生すると
162 * そã?時点で、Exception を発行して、å?ç�?‚’終äº?�—ますã?
163 * 初期値は、true(Exception を発行すã‚? ですã?
164 *
165 * @og.rev 5.6.9.2 (2013/10/18) 新規追åŠ?
166 *
167 * @param flag true:Exception を発行すã‚?false:標準エラー出力に出力すã‚?
168 */
169 public void onExecErrException( final boolean flag ) {
170 isExecErrException = flag;
171 }
172
173 /**
174 * <ROWSET> タグのä¸?•ªæœ??に呼び出されますã?
175 * ROWSET の属æ?である、table 属æ?と、dbid 属æ? をã?TagElement の
176 * get メソãƒ?ƒ‰で取得できますã?
177 * 取得時のキーは、それぞれã?"TABLE" と "DBID" ですã?
178 *
179 * @param tag タグエレメンãƒ?
180 * @see org.opengion.fukurou.xml.TagElement
181 * @see HybsXMLHandler#setTagElementListener( TagElementListener )
182 */
183 public void actionInit( final TagElement tag ) {
184 String table = tag.get( "tableName" );
185 if( table != null ) { tableName = table; }
186 }
187
188 /**
189 * <ROW> タグの endElement 処ç�?¯Žに呼び出されますã?
190 * こã? Listener をセãƒ?ƒˆすることにより、行データを取得é?度ã€?
191 * TagElement オブジェクトを作æ?しã?こã?メソãƒ?ƒ‰が呼び出されますã?
192 *
193 * @og.rev 4.0.0.0 (2007/05/09) ParameterMetaData を使用したパラメータ設定追åŠ??
194 * @og.rev 4.0.0.0 (2007/09/25) isOracle から useParamMetaData に変更
195 * @og.rev 4.3.7.0 (2009/06/01) HSQLDB対å¿?
196 * @og.rev 5.3.8.0 (2011/08/01) useParamMetaData setNull 対å¿?PostgreSQL対å¿?
197 * @og.rev 5.6.6.1 (2013/07/12) lastSQL 対応ã?ãƒ?ƒ�ãƒ?‚°用に、最後に使用したSQLæ–?‚’残しますã?
198 *
199 * @param tag タグエレメンãƒ?
200 * @see org.opengion.fukurou.xml.TagElement
201 * @see HybsXMLHandler#setTagElementListener( TagElementListener )
202 */
203 public void actionRow( final TagElement tag ) {
204 tag.setAfterMap( afterMap );
205
206 String[] vals = null; // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
207 try {
208 // 更新SQL(MERGE_SQLタグ)が存在する場合ã?処ç�?
209 int tempCnt = 0;
210 if( updPstmt != null ) {
211 // String[] vals = tag.getValues( updClms );
212 vals = tag.getValues( updClms ); // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
213 for( int j=0; j<vals.length; j++ ) {
214 // 4.3.7.0 (2009/06/01) HSQLDB対応ã?空æ–?—ã?場å�?ullに置換え
215 if( vals[j] != null && vals[j].length() == 0 ){
216 vals[j] = null;
217 }
218
219 // 4.0.0.0 (2007/09/25) ParameterMetaData を使用したパラメータ設定追åŠ?
220 if( useParamMetaData ) {
221 int type = updMeta.getParameterType( j+1 );
222 // 5.3.8.0 (2011/08/01) setNull 対å¿?
223 // updPstmt.setObject( j+1,vals[j],type );
224 String val = vals[j];
225 if( val == null || val.isEmpty() ) {
226 updPstmt.setNull( j+1, type );
227 }
228 else {
229 updPstmt.setObject( j+1, val, type );
230 }
231 }
232 else {
233 updPstmt.setObject( j+1,vals[j] );
234 }
235
236 }
237 tempCnt = updPstmt.executeUpdate();
238 if( tempCnt > 1 ) {
239 String errMsg = "Update キーが重è¤?�—てã�?�¾すã?"
240 + "TABLE=[" + tableName + "] ROW=["
241 + tag.getRowNo() + "]" + CR
242 + " SQL=[" + lastSQL + "]" + CR // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
243 + tag.toString() + CR
244 + Arrays.toString( vals ) + CR ; // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
245 throw new RuntimeException( errMsg );
246 }
247 updCnt += tempCnt;
248 }
249 // 更新ã�?0件の場合ã?、INSERT処ç�?‚’行いますã?
250 if( tempCnt == 0 ) {
251 // 初回INSERT時ã?タグより、DB登録SQLæ–?‚’構築しますã?
252 if( insPstmt == null ) {
253 insClms = tag.getKeys();
254 // String sql = insertSQL( insClms,tableName );
255 // insPstmt = connection.prepareStatement( sql );
256 lastSQL = insertSQL( insClms,tableName ); // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
257 insPstmt = connection.prepareStatement( lastSQL );
258 // 4.0.0.0 (2007/09/25) ParameterMetaData を使用したパラメータ設定追åŠ?
259 if( useParamMetaData ) { insMeta = insPstmt.getParameterMetaData(); }
260 }
261 // String[] vals = tag.getValues( insClms );
262 vals = tag.getValues( insClms ); // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
263 for( int j=0; j<vals.length; j++ ) {
264 // 4.3.7.0 (2009/06/01) HSQLDB対応ã?空æ–?—ã?場å�?ullに置換え
265 if( vals[j] != null && vals[j].length() == 0 ){
266 vals[j] = null;
267 }
268
269 // 4.0.0.0 (2007/09/25) ParameterMetaData を使用したパラメータ設定追åŠ?
270 if( useParamMetaData ) {
271 int type = insMeta.getParameterType( j+1 );
272 // 5.3.8.0 (2011/08/01) setNull 対å¿?
273 // insPstmt.setObject( j+1,vals[j],type );
274 String val = vals[j];
275 if( val == null || val.isEmpty() ) {
276 insPstmt.setNull( j+1, type );
277 }
278 else {
279 insPstmt.setObject( j+1, val, type );
280 }
281 }
282 else {
283 insPstmt.setObject( j+1,vals[j] );
284 }
285 }
286 insCnt += insPstmt.executeUpdate();
287 }
288 }
289 catch( SQLException ex ) {
290 String errMsg = "DB登録エラーが発生しましたã€?
291 + "TABLE=[" + tableName + "] ROW=["
292 + tag.getRowNo() + "]" + CR
293 + " SQL=[" + lastSQL + "]" + CR // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
294 + tag.toString() + CR
295 + Arrays.toString( vals ) + CR // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
296 + ex.getMessage() + ":" + ex.getSQLState() + CR ;
297 throw new RuntimeException( errMsg,ex );
298 }
299 }
300
301 /**
302 * <EXEC_SQL> タグの endElement 処ç�?¯Žに呼び出されますã?
303 * getBody メソãƒ?ƒ‰を使用して、このタグのBODY部のæ–?—å?を取得しますã?
304 * こã? Listener をセãƒ?ƒˆすることにより、EXEC_SQL ãƒ??タを取得é?度ã€?
305 * TagElement オブジェクトを作æ?しã?こã?メソãƒ?ƒ‰が呼び出されますã?
306 * EXEC_SQL タグでは、deleteæ–?‚„updateæ–?�ªど、特殊な前å?ç�?‚„後å?ç�?”¨の SQLと
307 * DDL?ˆデータ定義è¨?ªž:Data Definition Language?‰ã?処ç�?�ªども記述できますã?
308 * ここでは簡易的に、何か実行された場合ã?、delete 処ç�?�¨è€?�ˆ、削除カウントをåŠ?®—しã€?
309 * 0件で帰ってきた場合に、DDLが実行されたとè€?�ˆ、DDLカウントを?‹1しますã?
310 * ただしã?0件 delete もè?えられるため、SQLæ–??先é?æ–?—によるチェãƒ?‚¯は入れておきますã?
311 *
312 * @og.rev 5.6.6.1 (2013/07/12) lastSQL 対応ã?ãƒ?ƒ�ãƒ?‚°用に、最後に使用したSQLæ–?‚’残しますã?
313 * @og.rev 5.6.7.0 (2013/07/27) DDL?ˆデータ定義è¨?ªž:Data Definition Language?‰ã?処ç�?»¶数追åŠ?
314 * @og.rev 5.6.9.2 (2013/10/18) EXEC_SQL のエラー時に Exception を発行するかどã�?�‹を指å®?
315 *
316 * @param tag タグエレメンãƒ?
317 * @see org.opengion.fukurou.xml.TagElement
318 * @see HybsXMLHandler#setTagElementListener( TagElementListener )
319 */
320 public void actionExecSQL( final TagElement tag ) {
321 Statement execSQL = null ;
322 try {
323 // String sql = tag.getBody();
324 lastSQL = tag.getBody(); // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
325 execSQL = connection.createStatement();
326 // delCnt += execSQL.executeUpdate( sql ) ;
327
328 // 5.6.7.0 (2013/07/27) DDL?ˆデータ定義è¨?ªž:Data Definition Language?‰ã?処ç�?»¶数追åŠ?
329 // delCnt += execSQL.executeUpdate( lastSQL ) ;
330 int cnt = execSQL.executeUpdate( lastSQL ) ;
331 if( cnt > 0 ) { delCnt += cnt; } // 件数が返れば、DDLでなã�?�Ÿめã?削除数を加ç®?
332 else {
333 String sql = lastSQL.trim().toUpperCase( Locale.JAPAN );
334 if( !sql.startsWith( "DELETE" ) && !sql.startsWith( "INSERT" ) && !sql.startsWith( "UPDATE" ) ) {
335 ddlCnt ++ ;
336 }
337 }
338 }
339 catch( SQLException ex ) {
340 String errMsg = "DB登録エラーが発生しましたã€?
341 + "TABLE=[" + tableName + "] ROW=["
342 + tag.getRowNo() + "]" + CR
343 + " SQL=[" + lastSQL + "]" + CR // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
344 + tag.toString() + CR
345 + ex.getMessage() + ":" + ex.getSQLState() + CR ;
346
347 // 5.6.9.2 (2013/10/18) EXEC_SQL のエラー時に Exception を発行するかどã�?�‹を指å®?
348
349 if( isExecErrException ) {
350 throw new RuntimeException( errMsg,ex );
351 }
352 else {
353 System.err.println( errMsg );
354 }
355 }
356 finally {
357 Closer.stmtClose( execSQL );
358 }
359 }
360
361 /**
362 * <MERGE_SQL> タグの endElement 処ç�?™‚に呼び出されますã?
363 * getBody メソãƒ?ƒ‰を使用して、このタグのBODY部のæ–?—å?を取得しますã?
364 * MERGE_SQLタグは、ã?ージ処ç�?�—たいãƒ??タ部よりも上位に記述しておく
365 * å¿?¦�がありますが、中間部にè¤?•°回記述しても構いませんã€?
366 * こã?タグが現れるまでは、INSERT のみ実行されますã?こã?タグ以降ã?ã€?
367 * ä¸?—¦ UPDATE しã?結果ã�??�件の場合ã?、INSERTする流れになりますã?
368 * 完å?に INSERT のみであるãƒ??タを前半に、UPDATE/INSERTを行う
369 * ãƒ??タを後半に、その間に、MERGE_SQL タグをå?れることで、無意味な
370 * UPDATE を避けることが可能ですã?
371 * こã? Listener をセãƒ?ƒˆすることにより、MERGE_SQL ãƒ??タを取得é?度ã€?
372 * TagElement オブジェクトを作æ?しã?こã?メソãƒ?ƒ‰が呼び出されますã?
373 *
374 * @og.rev 4.0.0.0 (2007/05/09) ParameterMetaData を使用したパラメータ設定追åŠ??
375 * @og.rev 4.0.0.0 (2007/09/25) isOracle から useParamMetaData に変更
376 * @og.rev 5.6.6.1 (2013/07/12) lastSQL 対応ã?ãƒ?ƒ�ãƒ?‚°用に、最後に使用したSQLæ–?‚’残しますã?
377 *
378 * @param tag タグエレメンãƒ?
379 * @see org.opengion.fukurou.xml.TagElement
380 * @see HybsXMLHandler#setTagElementListener( TagElementListener )
381 */
382 public void actionMergeSQL( final TagElement tag ) {
383 if( updPstmt != null ) {
384 String errMsg = "MERGE_SQLタグがã?è¤?•°回記述されてã�?�¾すã?"
385 + "TABLE=[" + tableName + "] ROW=["
386 + tag.getRowNo() + "]" + CR
387 + " SQL=[" + lastSQL + "]" + CR // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
388 + tag.toString() + CR;
389 throw new RuntimeException( errMsg );
390 }
391
392 String orgSql = tag.getBody();
393 Matcher matcher = pattern.matcher( orgSql );
394 updClms = new ArrayList<String>();
395 while( matcher.find() ) {
396 // ここでは、[XXX]にマッチする為、前後ã?[]を取り除きますã?
397 updClms.add( orgSql.substring( matcher.start()+1,matcher.end()-1 ) );
398 }
399 // String sql = matcher.replaceAll( "?" );
400 lastSQL = matcher.replaceAll( "?" ); // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
401
402 try {
403 // updPstmt = connection.prepareStatement( sql );
404 updPstmt = connection.prepareStatement( lastSQL );
405 // 4.0.0.0 (2007/09/25) ParameterMetaData を使用したパラメータ設定追åŠ?
406 if( useParamMetaData ) { updMeta = updPstmt.getParameterMetaData(); }
407 }
408 catch( SQLException ex ) {
409 String errMsg = "Statement作æ?時にエラーが発生しましたã€?
410 + "TABLE=[" + tableName + "] ROW=["
411 + tag.getRowNo() + "]" + CR
412 + " SQL=[" + lastSQL + "]" + CR // 5.6.6.1 (2013/07/12) ãƒ?ƒ�ãƒ?‚°用
413 + tag.toString() + CR
414 + ex.getMessage() + ":" + ex.getSQLState() + CR ;
415 throw new RuntimeException( errMsg,ex );
416 }
417 }
418
419 /**
420 * UPDATE,DELETE を行う場合ã? WHERE 条件になるキー配å?
421 * こã?キーの AND 条件でカラãƒ?‚’特定し、UPDATE,DELETE などの処ç�?‚’
422 * 行いますã?
423 *
424 * @param keyCols WHERE条件になるキー配å?
425 */
426 public void setKeyColumns( final String[] keyCols ) {
427 keyColumns = new String[keyCols.length];
428 System.arraycopy( keyCols,0,keyColumns,0,keyColumns.length );
429 }
430
431 /**
432 * XMLファイルを読み取る前にæŒ?®šするカラãƒ?�¨値のペア(マッãƒ?æƒ??をセãƒ?ƒˆしますã?
433 *
434 * こã?カラãƒ?�¨値のペアのマップã?、オブジェクト構築前に設定される為ã€?
435 * XMLファイルにキーが存在してã�?‚‹場合ã?、å?が書き変わりますã?(XML優å…?
436 * XMLファイルにキーが存在してã�?�ªã�??合ã?、ここでæŒ?®šするMapの値ã�?
437 * 初期設定å?として使用されますã?
438 * ここでæŒ?®šすã‚?Map に LinkedHashMap を使用する場合ã?カラãƒ??ã‚?
439 * æŒ?®šすることがå?来ますã?
440 *
441 * @param map 初期設定するカラãƒ?ƒ‡ータマッãƒ?
442 * @see #setAfterMap( Map )
443 */
444 public void setDefaultMap( final Map<String,String> map ) { defaultMap = map; }
445
446 /**
447 * XMLファイルを読み取った後でæŒ?®šするカラãƒ?�¨値のペア(マッãƒ?æƒ??をセãƒ?ƒˆしますã?
448 *
449 * こã?カラãƒ?�¨値のペアのマップã?、オブジェクト構築後に設定される為ã€?
450 * XMLファイルのキーの存在に関係なくã?Mapのキーと値が使用されますã?(Map優å…?
451 * null を設定したå?合ã?、なにもå?ç�?�•れませんã€?
452 *
453 * @param map 後設定するカラãƒ?ƒ‡ータマッãƒ?
454 * @see #setDefaultMap( Map )
455 */
456 public void setAfterMap( final Map<String,String> map ) { afterMap = map; }
457
458 /**
459 * ãƒ??タベã?スに追åŠ??ç�?INSERT)を行いますã?
460 *
461 * 先にæŒ?®šされたコネクションを用ã�?�¦、指定ã?ãƒ??ブルに INSERT しますã?
462 * 引数には、XMLファイルを指定したリーãƒ??をセãƒ?ƒˆしますã?
463 * コネクションは、終äº?¾Œã?コミットされますã?(close されませんã€?
464 * リーãƒ??のクローズは、ここでは行ってã�?�¾せんã€?
465 *
466 * @og.rev 5.1.1.0 (2009/11/11) insMeta , updMeta のクリア(気休め)
467 *
468 * @param reader XMLファイルを指定するリーãƒ??
469 */
470 public void insertXML( final Reader reader ) {
471 try {
472 HybsXMLHandler handler = new HybsXMLHandler();
473 handler.setTagElementListener( this );
474 handler.setDefaultMap( defaultMap );
475
476 handler.parse( reader );
477 }
478 finally {
479 Closer.stmtClose( insPstmt );
480 Closer.stmtClose( updPstmt );
481 insPstmt = null;
482 updPstmt = null;
483 insMeta = null; // 5.1.1.0 (2009/11/11)
484 updMeta = null; // 5.1.1.0 (2009/11/11)
485 }
486 }
487
488 /**
489 * インサート用のSQLæ–?‚’作æ?しますã?
490 *
491 * @param columns インサートするカラãƒ?��
492 * @param tableName インサートするテーブルå�?
493 *
494 * @return インサート用のSQLæ–?
495 */
496 private String insertSQL( final String[] columns,final String tableName ) {
497 if( tableName == null ) {
498 String errMsg = "tableName がセãƒ?ƒˆされてã�?�¾せんã€? + CR
499 + "tableName は、コンストラクタでæŒ?®šするか、ROWSETのtableName属æ?で"
500 + "æŒ?®šしておくå¿?¦�がありまã�? + CR ;
501 throw new RuntimeException( errMsg );
502 }
503
504 StringBuilder sql = new StringBuilder();
505 sql.append( "INSERT INTO " ).append( tableName );
506 sql.append( " ( " );
507 sql.append( columns[0] );
508 for( int i=1; i<columns.length; i++ ) {
509 sql.append( "," ).append( columns[i] );
510 }
511 sql.append( " ) VALUES ( " );
512 sql.append( "?" );
513 for( int i=1; i<columns.length; i++ ) {
514 sql.append( "," ).append( "?" );
515 }
516 sql.append( " )" );
517
518 return sql.toString();
519 }
520
521 /**
522 * ãƒ??タベã?スに追åŠ?�—た件数を返しますã?
523 *
524 * @return 登録件数
525 */
526 public int getInsertCount() { return insCnt; }
527
528 /**
529 * ãƒ??タベã?スを更新した件数を返しますã?
530 * これは、拡張XDK形式で、MERGE_SQL タグを使用した場合ã?更新処ç�?»¶数ã‚?
531 * 合計したå?を返しますã?
532 *
533 * @return 更新件数
534 */
535 public int getUpdateCount() { return updCnt; }
536
537 /**
538 * ãƒ??タベã?スに変更(更新、削除を含ã‚?した件数を返しますã?
539 * これは、拡張XDK形式で、EXEC_SQL タグを使用した場合ã?実行件数を合計しã�?
540 * 値を返しますã?
541 * よって、更新かã?追åŠ?�‹、削除かã?、判りませんがã?通常 登録前に削除する
542 * ケースで使われることから、deleteCount としてã�?�¾すã?
543 *
544 * @return 変更件数(主に、削除件数)
545 */
546 public int getDeleteCount() { return delCnt; }
547
548 /**
549 * ãƒ??タベã?スにDDL?ˆデータ定義è¨?ªž:Data Definition Language?‰å?ç�?�—た件数を返しますã?
550 * これは、拡張XDK形式で、EXEC_SQL タグを使用した場合ã?実行件数を合計しã�?
551 * 値を返しますã?
552 * EXEC_SQL では、登録前に削除する delete 処ç�?‚‚、EXEC_SQL タグを使用して実行しますが
553 * そã?処ç�?�¨åˆ?�‘てカウントしますã?
554 *
555 * @og.rev 5.6.7.0 (2013/07/27) DDL?ˆデータ定義è¨?ªž:Data Definition Language?‰ã?処ç�?»¶数追åŠ?
556 *
557 * @return DDL?ˆデータ定義è¨?ªž:Data Definition Language?‰å?ç�?�—た件数
558 */
559 public int getDDLCount() { return ddlCnt; }
560
561 /**
562 * 実際に登録されã�?ãƒ??ブル名を返しますã?
563 *
564 * ãƒ??ブル名ã?、拡張XDK形式ã?ROWSETタグのtableName属æ?に
565 * 記述しておくかã?コンストラクターで引数として渡しますã?
566 * 両方æŒ?®šされた場合ã?、ROWSETタグのtableName属æ?が優先されますã?
567 * ここでの返り値は、実際に使用されã�?ãƒ??ブル名ですã?
568 *
569 * @return 変更件数(主に、削除件数)
570 */
571 public String getTableName() { return tableName; }
572
573 /**
574 * こã?接続が、PreparedStatement#getParameterMetaData() を使用するかどã�?�‹を判定しますã?
575 * 本来は、ConnectionFactory#useParameterMetaData(String)を使ã�?�¹きだがã?dbid が無ã�?�Ÿめã?直接取得しますã?
576 *
577 * @og.rev 5.3.8.0 (2011/08/01) 新規作æ? ( ApplicationInfo#useParameterMetaData(Connection) からコピã? )
578 * @og.rev 5.6.7.0 (2013/07/27) ProductName は、DBUtil 経由で取得するã?
579 *
580 * @param conn 接続å?(コネクション)
581 *
582 * @return 使用する場合:true / そã?ä»?false
583 */
584 private static boolean useParameterMetaData( final Connection conn ) {
585
586 String dbProductName = DBUtil.getProductName( conn );
587
588 return "PostgreSQL".equalsIgnoreCase( dbProductName ) ;
589
590 // try {
591 // DatabaseMetaData meta = conn.getMetaData();
592 // String dbProductName = meta.getDatabaseProductName();
593 //
594 // if( "PostgreSQL".equalsIgnoreCase( dbProductName ) ) { return true; }
595 //
596 // return false ;
597 // }
598 // catch( SQLException ex ) {
599 // String errMsg = "DatabaseMetaData から、getDatabaseProductName を取得できませんでしたã€?
600 // + ex.getMessage() + ":" + ex.getSQLState() ;
601 // throw new RuntimeException( errMsg,ex );
602 // }
603 }
604
605 /**
606 * ãƒ?‚¹ト用のメインメソãƒ?ƒ‰
607 *
608 * Usage: java org.opengion.fukurou.xml.HybsXMLSave USER PASSWD URL TABLE FILE [ENCODE] [DRIVER]
609 * USER : DB接続ユーザー(GE)
610 * PASSWD : DB接続パスワーãƒ?GE)
611 * URL : DB接続JDBCドライバURL(jdbc:oracle:thin:@localhost:1521:HYBS
612 * TABLE : 登録するãƒ??ブルID(GE21)
613 * FILE : 登録するORACLE XDK 形å¼?XMLファイル(GE21.xml)
614 * [ENCODE]: ファイルのエンコーãƒ?初期値:UTF-8
615 * [DRIVER]: JDBCドライバã? 初期値:oracle.jdbc.OracleDriver
616 *
617 * ※ ファイルが存在しなかったå?合ã?FileNotFoundException ã‚?RuntimeException に変換して、throw しますã?
618 * ※ æŒ?®šã?エンコードが存在しなかったå?合ã?UnsupportedEncodingException ã‚?RuntimeException に変換して、throw しますã?
619 *
620 * @og.rev 5.1.1.0 (2009/12/01) MySQL対å¿?明示çš?�«、TRANSACTION_READ_COMMITTED を指定するã?
621 * @og.rev 5.6.7.0 (2013/07/27) DDL?ˆデータ定義è¨?ªž:Data Definition Language?‰ã?処ç�?»¶数追åŠ?
622 *
623 * @param args コマンド引数配å?
624 * @throws ClassNotFoundException クラスを見つけることができなかったå?合ã?
625 * @throws SQLException ãƒ??タベã?ス接続エラーが発生したå?合ã?
626 */
627 public static void main( final String[] args )
628 throws ClassNotFoundException , SQLException {
629 if( args.length < 5 ) {
630 LogWriter.log( "Usage: java org.opengion.fukurou.xml.HybsXMLSave USER PASSWD URL TABLE FILE [ENCODE] [DRIVER]" );
631 LogWriter.log( " USER : DB接続ユーザー(GE)" );
632 LogWriter.log( " PASSWD: DB接続パスワーãƒ?GE)" );
633 LogWriter.log( " URL : DB接続JDBCドライバURL(jdbc:oracle:thin:@localhost:1521:HYBS)" );
634 LogWriter.log( " TABLE : 登録するãƒ??ブルID(GE21)" );
635 LogWriter.log( " FILE : 登録するORACLE XDK 形å¼?XMLファイル(GE21.xml)" );
636 LogWriter.log( " [ ENCODE: ファイルのエンコーãƒ?初期値:UTF-8 ]" );
637 LogWriter.log( " [ DRIVER: JDBCドライバã? 初期値:oracle.jdbc.OracleDriver ]" );
638 return ;
639 }
640
641 String user = args[0] ;
642 String passwd = args[1] ;
643 String url = args[2] ;
644 String table = args[3] ;
645 String file = args[4] ;
646 String encode = ( args.length == 6 ) ? args[5] : "UTF-8" ;
647 String driver = ( args.length == 7 ) ? args[6] : "oracle.jdbc.OracleDriver" ;
648
649 Class.forName(driver);
650
651 Connection conn = DriverManager.getConnection( url,user,passwd );
652 Reader reader = null;
653 int insCnt;
654 int updCnt;
655 int delCnt;
656 int ddlCnt; // 5.6.7.0 (2013/07/27) DDL処ç�?»¶数追åŠ?
657 try {
658 conn.setAutoCommit( false );
659 conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); // 5.1.1.0 (2009/12/01)
660 HybsXMLSave save = new HybsXMLSave( conn,table );
661
662 reader = new BufferedReader(new InputStreamReader(
663 new FileInputStream( file ) ,encode ));
664 save.insertXML( reader );
665 insCnt = save.getInsertCount();
666 updCnt = save.getUpdateCount();
667 delCnt = save.getDeleteCount();
668 ddlCnt = save.getDDLCount(); // 5.6.7.0 (2013/07/27) DDL処ç�?»¶数追åŠ?
669
670 Closer.commit( conn );
671 }
672 // FileNotFoundException , UnsupportedEncodingException
673 catch( java.io.FileNotFoundException ex ) {
674 String errMsg = "ファイルが存在しませんã€? + ex.getMessage()
675 + CR + "Table=[" + table + "] File =[" + file + "]" ;
676 throw new RuntimeException( errMsg,ex );
677 }
678 catch( java.io.UnsupportedEncodingException ex ) {
679 String errMsg = "æŒ?®šã?エンコードが存在しませんã€? + ex.getMessage()
680 + CR + "Table=[" + table + "] Encode =[" + encode + "]" ;
681 throw new RuntimeException( errMsg,ex );
682 }
683 finally {
684 Closer.ioClose( reader );
685 Closer.connClose( conn );
686 }
687
688 System.out.println( "XML File[" + file + "] Into [" + table + "] Table" );
689 System.out.println( " Insert Count : [" + insCnt + "]" );
690 System.out.println( " Update Count : [" + updCnt + "]" );
691 System.out.println( " Delete Count : [" + delCnt + "]" );
692 System.out.println( " DDL Count : [" + ddlCnt + "]" );
693 }
694 }