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.resource;
017
018import java.util.HashMap;
019import java.util.Locale;
020import java.util.Map;
021
022import org.opengion.fukurou.db.DBUtil;
023import org.opengion.fukurou.util.ApplicationInfo;
024import org.opengion.fukurou.util.StringUtil;
025import org.opengion.hayabusa.common.HybsSystem;
026
027/**
028 * データロールは、データへのアクセス権限を管理するクラスです。
029 *
030 * データロール情報は、データロールマスタ(GEA06)で管理されます。
031 *
032 * あるユーザーのデータロール情報に対してひもつくデータロールマスタの
033 * カラム、条件値、条件式の一覧に対して、カラム単位に条件式を構築します。
034 *
035 * このクラスでは、インスタンス作成時にデータロールマスタのDBを直接検索しています。
036 * このため、データ変更時の変更内容を次回ログイン時から反映させるため、
037 * 自身のオブジェクトキャッシュは保持していません。
038 *
039 * また、各条件式について、1つのカラムに対して複数の条件式が適用される場合、
040 * 条件式が"="または"LIKE"だけの場合は、"OR"結合されます。
041 * "!="及び"NOT LIKE"条件が1つでも含まれる場合は、"AND"結合されます。
042 *
043 * データロールがNULLの場合、全データへのアクセス可能となり、条件式としては、
044 *  "LIKE '%'" が付加されます。
045 * また、'--'の場合、全データへのアクセスが不可能となり、条件式としては、
046 *  "NOT LIKE '%'" が付加されます。
047 * ユーザーのデータロールが指定されているにも関わらず、データロールの検索ができない
048 * 場合は、全禁止になります。
049 *
050 * 検索条件を取得する際に、テーブル名又は、テーブル名の別名が指定された場合、
051 * 条件の取得する際には、テーブル名は無視されますが、返される条件には、テーブル名
052 * は付加された状態になります。
053 *
054 * 例)
055 *  ABC(=)              BCD(=)          ⇒ (CLM = 'ABC' or CLM = 'BCD' )
056 *  ABC(=)              BCD(LIKE)       ⇒ (CLM = 'ABC' or CLM like 'BCD%' )
057 *  ABC(=)              BCD(!=)         ⇒ (CLM = 'ABC' and CLM != 'BCD' )
058 *  ABC(LIKE)   BCD(LIKE)       ⇒ (CLM like 'ABC%' or CLM like 'BCD%' )
059 *  ABC(LIKE)   BCD(!=)         ⇒ (CLM like 'ABC%' and CLM != 'BCD' )
060 *  ABC(LIKE)   BCD(!=)         ⇒ (CLM != 'ABC' and CLM != 'BCD' )
061 *  ABC(=)              BCD(=)          ⇒ (A.CLM = 'ABC' or A.CLM = 'BCD' ) ※ {@SEC.A.CLM}でアクセス
062 *
063 * @og.rev 4.4.0.0 (2009/08/02) 新規作成
064 * @og.group リソース管理
065 *
066 * @version  4.0
067 * @author   Hiroki Nakamura
068 * @since    JDK5.0,
069 */
070public final class DataRole {
071        private static final String QUERY_GEA06_SELECT
072                                        = "select CLM, CVALUE, VALCDTN from GEA06"
073                                                + " where SYSTEM_ID = ? and DROLE = ? and FGJ = '1'";
074
075        private static final int IDX_CLM        = 0;
076        private static final int IDX_CVALUE     = 1;
077        private static final int IDX_VALCDTN= 2;
078
079        private static final DataRole FULL_ACCESS_DATAROLE_OBJ = new DataRole( true ) ;
080        private static final DataRole FULL_DENY_DATAROLE_OBJ = new DataRole( false ) ;
081
082        private static final String FULL_ACCESS_CONDITION = null ;
083        private static final String FULL_DENY_CONDITION = " NOT LIKE '%'" ;
084        private static final String FULL_DENY_DROLES_KEY = "--";
085
086        private final Map<String,String> cdtnMap = new HashMap<String,String>( HybsSystem.BUFFER_SMALL );
087
088        private final String                    droles ;                // データロールズ
089        private final String                    systemId ;              // システムID
090        private final ApplicationInfo   appInfo ;
091        private final String DBID = HybsSystem.sys( "RESOURCE_DBID" );          // 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対応
092
093        private boolean         isFullAcess             = false;
094        private boolean         isFullDeny              = false;
095
096        /**
097         * 固定データロール(全アクセス可 or 全アクセス不可)のインスタンスを生成します。
098         *
099         * @param isFull true:全アクセス可 false:全アクセス不可
100         */
101        private DataRole( final boolean isFull ) {
102                droles = null;
103                systemId = null;
104                appInfo = null;
105
106                if( isFull )    { isFullAcess = true; }
107                else                    { isFullDeny = true; }
108        }
109
110        /**
111         * ロール文字列から、データロールマスタ(GEA05)を検索し、カラム単位の
112         * 条件式を生成します。
113         *
114         * @param droles "|"で区切られた データロール文字列
115         * @param systemId システムID
116         * @param appInfo 接続情報
117         */
118        private DataRole( final String droles,final String systemId, final ApplicationInfo appInfo ) {
119                this.droles = droles ;          // データロールズ
120                this.systemId = systemId;       // システムID
121                this.appInfo = appInfo ;
122
123                if( appInfo != null ) {
124                        appInfo.setModuleInfo( "DataRole",null,"CreateInstance" );
125                }
126
127                String[] drole = StringUtil.csv2Array( droles, '|' );
128                if( drole == null || drole.length == 0 ) {
129                        isFullAcess = true;
130                        return;
131                }
132                else {
133                        makeConditionMap( drole );
134                }
135        }
136
137        /**
138         * ロール文字列から、データロールマスタ(GEA05)を検索し、カラム単位の
139         * 条件式を生成します。
140         *
141         * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
142         *
143         * @param drole データロール文字列の配列
144         */
145        private void makeConditionMap( final String[] drole ) {
146//              String[][] vals = null;
147                String clm = null;
148                String cvalue =null;
149                String valcdtn = null;
150                for( int i=0; i<drole.length; i++ ) {
151                        String[] args = new String[] { systemId, drole[i] };
152//                      String[][] vals = DBUtil.dbExecute( QUERY_GEA06_SELECT,args,appInfo );
153                        String[][] vals = DBUtil.dbExecute( QUERY_GEA06_SELECT,args,appInfo, DBID );    // 5.5.5.1 (2012/08/07)
154                        for( int j=0; j<vals.length; j++ ) {
155                                clm = vals[j][IDX_CLM];
156                                cvalue = vals[j][IDX_CVALUE];
157                                valcdtn = vals[j][IDX_VALCDTN];
158
159                                String cdtn = cdtnMap.get( clm );
160                                if( cdtn == null ) { cdtn = ""; }
161                                else if( "=".equals( valcdtn ) || "LIKE".equalsIgnoreCase( valcdtn ) ) {
162                                        cdtn += " or ";
163                                }
164                                else {
165                                        cdtn += " and ";
166                                }
167                                cdtn += clm + " " + valcdtn + " '" + cvalue;
168                                if( valcdtn.toUpperCase( Locale.JAPAN ).indexOf( "LIKE" ) >= 0 ) {
169                                        cdtn += "%";
170                                }
171                                cdtn += "'";
172
173                                if( cdtn.indexOf( " and " ) >= 0 ) { cdtn = cdtn.replace( " or ", "and" ); }
174
175                                cdtnMap.put( clm, cdtn );
176                        }
177                }
178        }
179
180        /**
181         * ロール文字列から、データロールマスタ(GEA05)を検索し、カラム単位の
182         * 条件式を生成します。
183         *
184         * @param       droles  "|"で区切られた データロール文字列
185         * @param systemId システムID
186         * @param appInfo 接続情報
187         *
188         * @return データロールオブジェクト
189         */
190        public static DataRole newInstance( final String droles, final String systemId, final ApplicationInfo appInfo ) {
191                if( droles == null || droles.length() == 0 ) {
192                        return FULL_ACCESS_DATAROLE_OBJ;
193                }
194                else if( FULL_DENY_DROLES_KEY.equals( droles ) ) {
195                        return FULL_DENY_DATAROLE_OBJ;
196                }
197
198//              DataRole dataRole = new DataRole( droles, systemId, appInfo );
199//              return dataRole;
200                return new DataRole( droles, systemId, appInfo );
201        }
202
203        /**
204         * ロールズを返します。
205         *
206         * @return ロールズ文字列
207         */
208        public String getDataRoles() { return droles; }
209
210        /**
211         * ロールズを返します。
212         *
213         * @og.rev 4.4.0.1 (2009/08/08) テーブルIDが付加されている場合の条件を追加
214         *
215         * @param clm カラム名
216         *
217         * @return ロールズ文字列
218         */
219        public String getCondition( final String clm ) {
220                if( isFullAcess ) { return FULL_ACCESS_CONDITION; }
221                if( isFullDeny ) { return "(" + clm + FULL_DENY_CONDITION + ")"; }
222
223                String rtn = null;
224                if( clm.indexOf( '.' ) >= 0 ) {
225                        String clmTmp = clm.substring( clm.lastIndexOf( '.' ) + 1 );
226                        rtn = cdtnMap.get( clmTmp );
227                        if( rtn == null || rtn.length() == 0 ) {
228                                return "(" + clm + FULL_DENY_CONDITION + ")";
229                        }
230                        return "(" + rtn.replace( clmTmp, clm ) + ")";
231                }
232                else {
233                        rtn = cdtnMap.get( clm );
234                        if( rtn == null || rtn.length() == 0 ) {
235                                return "(" + clm + FULL_DENY_CONDITION + ")";
236                        }
237                        return "(" + rtn + ")";
238                }
239        }
240
241        /** オブジェクトの識別子として,詳細なユーザー情報を返します。
242         *
243         * @return  詳細な画面情報
244         */
245        @Override
246        public String toString() {
247                StringBuilder rtn = new StringBuilder( HybsSystem.BUFFER_MIDDLE );
248                rtn.append( "droles  : " ).append( droles ).append( HybsSystem.CR );
249                return rtn.toString();
250        }
251}