AT&T 2.0.19 Code drop, stage 3
[aaf/authz.git] / auth / auth-cass / src / main / java / org / onap / aaf / auth / dao / cass / HistoryDAO.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6  * ===========================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.auth.dao.cass;
23
24 import java.nio.ByteBuffer;
25 import java.text.SimpleDateFormat;
26 import java.util.Date;
27 import java.util.List;
28 import java.util.UUID;
29
30 import org.onap.aaf.auth.dao.AbsCassDAO;
31 import org.onap.aaf.auth.dao.CassDAOImpl;
32 import org.onap.aaf.auth.dao.Loader;
33 import org.onap.aaf.auth.env.AuthzTrans;
34 import org.onap.aaf.auth.layer.Result;
35
36 import com.datastax.driver.core.Cluster;
37 import com.datastax.driver.core.ConsistencyLevel;
38 import com.datastax.driver.core.ResultSet;
39 import com.datastax.driver.core.Row;
40
41 /**
42  * History
43  * 
44  * Originally written PE3617
45  * @author Jonathan
46  * 
47  * History is a special case, because we don't want Updates or Deletes...  Too likely to mess up history.
48  * 
49  * Jonathan 9-9-2013 - Found a problem with using "Prepare".  You cannot prepare anything with a "now()" in it, as
50  * it is evaluated once during the prepare, and kept.  That renders any use of "now()" pointless.  Therefore
51  * the Create function needs to be run fresh everytime.
52  * 
53  * Fixed in Cassandra 1.2.6 https://issues.apache.org/jira/browse/CASSANDRA-5616
54  *
55  */
56 public class HistoryDAO extends CassDAOImpl<AuthzTrans, HistoryDAO.Data> {
57         private static final String TABLE = "history";
58
59         public static final SimpleDateFormat monthFormat = new SimpleDateFormat("yyyyMM");
60 //      private static final SimpleDateFormat dayTimeFormat = new SimpleDateFormat("ddHHmmss");
61
62         private String[] helpers;
63
64         private HistLoader defLoader;
65
66         private AbsCassDAO<AuthzTrans, Data>.PSInfo readByUser, readBySubject, readByYRMN;
67
68         public HistoryDAO(AuthzTrans trans, Cluster cluster, String keyspace) {
69                 super(trans, HistoryDAO.class.getSimpleName(),cluster,keyspace,Data.class,TABLE,ConsistencyLevel.LOCAL_ONE,ConsistencyLevel.ANY);
70                 init(trans);
71         }
72
73         public HistoryDAO(AuthzTrans trans, AbsCassDAO<AuthzTrans,?> aDao) {
74                 super(trans, HistoryDAO.class.getSimpleName(),aDao,Data.class,TABLE,ConsistencyLevel.LOCAL_ONE,ConsistencyLevel.ANY);
75                 init(trans);
76         }
77
78
79         private static final int KEYLIMIT = 1;
80         public static class Data {
81                 public UUID id;
82                 public int      yr_mon;
83                 public String user;
84                 public String action;
85                 public String target;
86                 public String subject;
87                 public String  memo;
88 //              Map<String, String>  detail = null;
89 //              public Map<String, String>  detail() {
90 //                      if(detail == null) {
91 //                              detail = new HashMap<String, String>();
92 //                      }
93 //                      return detail;
94 //              }
95                 public ByteBuffer reconstruct;
96         }
97         
98         private static class HistLoader extends Loader<Data> {
99                 public HistLoader(int keylimit) {
100                         super(keylimit);
101                 }
102
103                 @Override
104                 public Data load(Data data, Row row) {
105                         data.id = row.getUUID(0);
106                         data.yr_mon = row.getInt(1);
107                         data.user = row.getString(2);
108                         data.action = row.getString(3);
109                         data.target = row.getString(4);
110                         data.subject = row.getString(5);
111                         data.memo = row.getString(6);
112 //                      data.detail = row.getMap(6, String.class, String.class);
113                         data.reconstruct = row.getBytes(7);
114                         return data;
115                 }
116
117                 @Override
118                 protected void key(Data data, int idx, Object[] obj) {
119                         obj[idx]=data.id;
120                 }
121
122                 @Override
123                 protected void body(Data data, int _idx, Object[] obj) {
124                         int idx = _idx;
125                         obj[idx]=data.yr_mon;
126                         obj[++idx]=data.user;
127                         obj[++idx]=data.action;
128                         obj[++idx]=data.target;
129                         obj[++idx]=data.subject;
130                         obj[++idx]=data.memo;
131 //                      obj[++idx]=data.detail;
132                         obj[++idx]=data.reconstruct;            
133                 }
134         };
135         
136         private void init(AuthzTrans trans) {
137                 // Loader must match fields order
138                 defLoader = new HistLoader(KEYLIMIT);
139                 helpers = setCRUD(trans, TABLE, Data.class, defLoader);
140
141                 // Need a specialty Creator to handle the "now()"
142                 // 9/9/2013 - Jonathan - Just great... now() is evaluated once on Client side, invalidating usage (what point is a now() from a long time in the past?
143                 // Unless this is fixed, we're putting in non-prepared statement
144                 // Solved in Cassandra.  Make sure you are running 1.2.6 Cassandra or later. https://issues.apache.org/jira/browse/CASSANDRA-5616       
145                 replace(CRUD.create, new PSInfo(trans, "INSERT INTO history (" +  helpers[FIELD_COMMAS] +
146                                         ") VALUES(now(),?,?,?,?,?,?,?)", 
147                                         new HistLoader(0) {
148                                                 @Override
149                                                 protected void key(Data data, int idx, Object[] obj) {
150                                                 }
151                                         },writeConsistency)
152                                 );
153 //              disable(CRUD.Create);
154                 
155                 replace(CRUD.read, new PSInfo(trans, SELECT_SP +  helpers[FIELD_COMMAS] +
156                                 " FROM history WHERE id = ?", defLoader,readConsistency) 
157 //                              new HistLoader(2) {
158 //                                      @Override
159 //                                      protected void key(Data data, int idx, Object[] obj) {
160 //                                              obj[idx]=data.yr_mon;
161 //                                              obj[++idx]=data.id;
162 //                                      }
163 //                              })
164                         );
165                 disable(CRUD.update);
166                 disable(CRUD.delete);
167                 
168                 readByUser = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + 
169                                 " FROM history WHERE user = ?", defLoader,readConsistency);
170                 readBySubject = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + 
171                                 " FROM history WHERE subject = ? and target = ? ALLOW FILTERING", defLoader,readConsistency);
172                 readByYRMN = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + 
173                                 " FROM history WHERE yr_mon = ?", defLoader,readConsistency);
174                 async(true); //TODO dropping messages with Async
175         }
176
177         public static Data newInitedData() {
178                 Data data = new Data();
179                 Date now = new Date();
180                 data.yr_mon = Integer.parseInt(monthFormat.format(now));
181                 // data.day_time = Integer.parseInt(dayTimeFormat.format(now));
182                 return data;            
183         }
184
185         public Result<List<Data>> readByYYYYMM(AuthzTrans trans, int yyyymm) {
186                 Result<ResultSet> rs = readByYRMN.exec(trans, "yr_mon", yyyymm);
187                 if(rs.notOK()) {
188                         return Result.err(rs);
189                 }
190                 return extract(defLoader,rs.value,null,dflt);
191         }
192
193         /**
194          * Gets the history for a user in the specified year and month
195          * year - the year in yyyy format
196          * month -  the month in a year ...values 1 - 12
197          **/
198         public Result<List<Data>> readByUser(AuthzTrans trans, String user, int ... yyyymm) {
199                 if(yyyymm.length==0) {
200                         return Result.err(Status.ERR_BadData, "No or invalid yyyymm specified");
201                 }
202                 Result<ResultSet> rs = readByUser.exec(trans, "user", user);
203                 if(rs.notOK()) {
204                         return Result.err(rs);
205                 }
206                 return extract(defLoader,rs.value,null,yyyymm.length>0?new YYYYMM(yyyymm):dflt);
207         }
208         
209         public Result<List<Data>> readBySubject(AuthzTrans trans, String subject, String target, int ... yyyymm) {
210                 if(yyyymm.length==0) {
211                         return Result.err(Status.ERR_BadData, "No or invalid yyyymm specified");
212                 }
213                 Result<ResultSet> rs = readBySubject.exec(trans, "subject", subject, target);
214                 if(rs.notOK()) {
215                         return Result.err(rs);
216                 }
217                 return extract(defLoader,rs.value,null,yyyymm.length>0?new YYYYMM(yyyymm):dflt);
218         }
219         
220         private class YYYYMM implements Accept<Data> {
221                 private int[] yyyymm;
222                 public YYYYMM(int yyyymm[]) {
223                         this.yyyymm = yyyymm;
224                 }
225                 @Override
226                 public boolean ok(Data data) {
227                         int dym = data.yr_mon;
228                         for(int ym:yyyymm) {
229                                 if(dym==ym) {
230                                         return true;
231                                 }
232                         }
233                         return false;
234                 }
235                 
236         };
237         
238 }