    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.fukurou.util;
    017
    018import java.sql.Connection;
    019import java.sql.CallableStatement;
    020import java.sql.SQLException;
    021
    022/**
    023 * <P>ApplicationInfo.java は、共通的に使用される 内部情報を格納するオブジェクトです。</P>
    024 *
    025 * 内部情報とは、接続ユーザーのクライアント情報と、実行状況のアプリケーション情報があります。
    026 *
    027 * クライアント情報とは、"i=192.168.51.81,h=null,u=C12345" 的な文字列で、
    028 * i=の後ろに IPアドレス、h=の後ろにホスト名、u=の後ろにユーザー名をセットして、
    029 * DBMS_APPLICATION_INFO.SET_CLIENT_INFO( "i=192.168.51.81,h=null,u=C12345" ) を
    030 * CALL します。
    031 *
    032 * アプリケーション情報とは、"o=SELECT,p=GEXXXX" 的な文字列で、o=の後ろに 操作、
    033 * p=の後ろにプログラムIDをセットして、
    034 * DBMS_APPLICATION_INFO.SET_MODULE( "GE0010","o=操作,p=プログラムID" ) を
    035 * CALL します。
    036 *
    037 * このPL/SQL を使用するコネクションについて実行すると、アクセスログ記録を行う為の
    038 * 情報として取り出すことが可能になります。
    039 * 確認は、V$SESSION の MODULE , ACTION , CLIENT_INFO で行います。
    040 *
    041 * このクラスは、同期化されていません。
    042 *
    043 * @og.rev 3.8.7.0 (2006/12/15) 新規追加
    044 *
    045 * @version  0.9.0      2000/10/12
    046 * @author       Kazuhiko Hasegawa
    047 * @since        JDK1.1,
    048 */
    049public final class ApplicationInfo {
    050        /** SET_CLIENT_INFO( "i=192.168.51.81,h=null,u=C12345" ) */
    051        public static final String CLIENT_INFO = "{ call DBMS_APPLICATION_INFO.SET_CLIENT_INFO( ? ) }" ;
    052        /** SET_MODULE( "GE0010","o=操作,p=プログラムID" ) */
    053        public static final String MODULE      = "{ call DBMS_APPLICATION_INFO.SET_MODULE( ?,? ) }" ;
    054
    055        private String gamenId          = null;
    056        private String clientInfo       = "";
    057        private String moduleInfo       = "";
    058
    059        /**
    060         * ユーザーID,IPアドレス,ホスト名 を指定して、クライアント情報を設定します。
    061         *
    062         * クライアント情報とは、"i=192.168.51.81,h=null,u=C12345" 的な文字列で、
    063         * i=の後ろに IPアドレス、h=の後ろにホスト名、u=の後ろにユーザー名をセット
    064         * しています。
    065         *
    066         * @param       userId  ユーザーID
    067         * @param       ipAdrs  IPアドレス
    068         * @param       host    ホスト名
    069         */
    070        public void setClientInfo( final String userId,final String ipAdrs,final String host ) {
    071                StringBuilder buf = new StringBuilder();
    072                append( "i=" , ipAdrs , buf );
    073                append( "h=" , host   , buf );
    074                append( "u=" , userId , buf );
    075
    076                clientInfo = buf.toString() ;
    077        }
    078
    079        /**
    080         * 画面ID,操作,プログラムIDを指定して、アプリケーションに関する情報を設定します。
    081         *
    082         * クライアント情報とは、"o=SELECT,p=GEXXXX" 的な文字列で、
    083         * o=の後ろに 操作、p=の後ろにプログラムIDをセットしています。
    084         *
    085         * @param       gamenId 画面ID
    086         * @param       ope             オペレーション(操作)
    087         * @param       prgId   プログラムID
    088         */
    089        public void setModuleInfo( final String gamenId,final String ope,final String prgId ) {
    090                this.gamenId    = gamenId       ;
    091
    092                StringBuilder buf = new StringBuilder();
    093                append( "o=" , ope   , buf );
    094                append( "p=" , prgId , buf );
    095
    096                moduleInfo = buf.toString() ;
    097        }
    098
    099        /**
    100         * setModuleInfo で最後に設定された 画面IDを返します。
    101         *
    102         * なにも設定されていない初期状態は、null です。
    103         *
    104         * @return      画面ID
    105         * @see #setModuleInfo( String,String,String )
    106         */
    107        public String getGamenId() {
    108                return gamenId ;
    109        }
    110
    111        /**
    112         * key と val を連結した文字列を作成します。
    113         * 引数の val が null の場合は、何も操作しません。
    114         * buf にすでになにかが登録済みの場合は、"," を追加してから、連結します。
    115         *
    116         * @param       key     キー
    117         * @param       val     値
    118         * @param       buf     連結するStringBuilderオブジェクト
    119         */
    120        private void append( final String key,final String val,final StringBuilder buf ) {
    121                if( val != null ) {
    122                        if( buf.length() == 0 ) { buf.append( key ).append( val ); }
    123                        else { buf.append( ',' ).append( key ).append( val ); }
    124                }
    125        }
    126
    127        /**
    128         * アクセスログ記録を行う為の DBMS_APPLICATION_INFO.SET_CLIENT_INFO と、
    129         * DBMS_APPLICATION_INFO.SET_MODULE を CALL します。
    130         *
    131         * SET_CLIENT_INFO( "i=192.168.51.81,h=null,u=C12345" ) では、
    132         * クライアント情報として、"i=192.168.51.81,h=null,u=C12345" 的な文字列で、
    133         * i=の後ろに IPアドレス、h=の後ろにホスト名、u=の後ろにユーザー名をセットしています。
    134         *
    135         * SET_MODULE( "GE0010","o=操作,p=プログラムID" )では、
    136         * アプリケーションに関する情報として、"o=操作,p=プログラムID" をセットしています。
    137         * 確認は、V$SESSION の MODULE , ACTION , CLIENT_INFO で行います。
    138         *
    139         * @param   conn 接続先(コネクション)
    140         */
    141        public void callAppInfo( final Connection conn ) {
    142                CallableStatement callStmt ;
    143                try {
    144                        callStmt = conn.prepareCall( CLIENT_INFO );
    145                        callStmt.setString( 1,clientInfo );
    146                        callStmt.executeUpdate();
    147                        callStmt.close();
    148
    149                        callStmt = conn.prepareCall( MODULE );
    150                        callStmt.setString( 1,gamenId );
    151                        callStmt.setString( 2,moduleInfo );
    152                        callStmt.executeUpdate();
    153                        callStmt.close();
    154                }
    155                catch (SQLException ex) {
    156                        String errMsg = "履歴収集処理を実行できませんでした。"
    157                                        + ex.getMessage() + ":" + ex.getSQLState() ;
    158                        throw new RuntimeException( errMsg,ex );
    159                }
    160        }
    161
    162        /**
    163         * この接続が、PreparedStatement#getParameterMetaData() を使用するかどうかを判定します。
    164         *
    165         * PreparedStatement に対して、String化された 数字などを setObject( int,String ) するとき、
    166         * ORACLE と SQLServer は、そのまま設定すれば、自動的に変換されます。
    167         * postgreSQL では、ParameterMetaData#getParameterType(int) で、カラムタイプを取得し、
    168         * setObject( int,String,int ) する必要があります。
    169         * その判定に、このメソッドを使用します。
    170         * この結果は、あくまで、各種データベース毎の実地調査の結果を元に、判定結果を
    171         * 返すようにしています。
    172         * ORACLE の場合は、使用しない(false)が返るように設定しています。
    173         * SQLServer では、ORACLEと同様に、false を返します。
    174         *
    175         * @og.rev 4.0.0.0 (2007/09/25) 新規追加
    176         * @og.rev 5.1.1.0 (2009/12/01) MySQL/PostgreSQL 対応
    177         * @og.rev 5.3.8.0 (2011/08/01) 廃止( ConnectionFactory#useParameterMetaData(String) に移動 )
    178         *
    179         * @param   conn 接続先(コネクション)
    180         *
    181         * @return      使用する場合：true / その他:false
    182         */
    183//      public static boolean useParameterMetaData( final Connection conn ) {
    184////            return false;
    185//
    186//              try {
    187//                      DatabaseMetaData meta = conn.getMetaData();
    188//                      String dbProductName = meta.getDatabaseProductName();
    189//
    190//      //              if( "ORACLE".equalsIgnoreCase( dbProductName ) ) { return false; }
    191//      //              if( "Microsoft SQL Server".equalsIgnoreCase( dbProductName ) ) { return false; }
    192//
    193//                      if( "PostgreSQL".equalsIgnoreCase( dbProductName ) ) { return true; }
    194//
    195//                      return false ;
    196//              }
    197//              catch (SQLException ex) {
    198//                      String errMsg = "DatabaseMetaData から、getDatabaseProductName を取得できませんでした。"
    199//                                      + ex.getMessage() + ":" + ex.getSQLState() ;
    200//                      throw new RuntimeException( errMsg,ex );
    201//              }
    202//      }
    203}