AT&T 2.0.19 Code drop, stage 3
[aaf/authz.git] / auth / auth-cass / src / main / java / org / onap / aaf / auth / dao / cass / ApprovalDAO.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.io.IOException;
25 import java.util.Date;
26 import java.util.List;
27 import java.util.UUID;
28
29 import org.onap.aaf.auth.dao.CassAccess;
30 import org.onap.aaf.auth.dao.CassDAOImpl;
31 import org.onap.aaf.auth.dao.Loader;
32 import org.onap.aaf.auth.env.AuthzTrans;
33 import org.onap.aaf.auth.layer.Result;
34 import org.onap.aaf.misc.env.APIException;
35 import org.onap.aaf.misc.env.Env;
36 import org.onap.aaf.misc.env.TimeTaken;
37 import org.onap.aaf.misc.env.util.Chrono;
38
39 import com.datastax.driver.core.Cluster;
40 import com.datastax.driver.core.ResultSet;
41 import com.datastax.driver.core.Row;
42 import com.datastax.driver.core.exceptions.DriverException;
43
44
45 public class ApprovalDAO extends CassDAOImpl<AuthzTrans,ApprovalDAO.Data> {
46         public static final String PENDING = "pending";
47         public static final String DENIED = "denied";
48         public static final String APPROVED = "approved";
49         
50         private static final String TABLE = "approval";
51         private static final String TABLELOG = "approved";
52         private HistoryDAO historyDAO;
53         private PSInfo psByUser, psByApprover, psByTicket, psByStatus;
54
55         
56         public ApprovalDAO(AuthzTrans trans, Cluster cluster, String keyspace) {
57                 super(trans, ApprovalDAO.class.getSimpleName(),cluster,keyspace,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE));
58         historyDAO = new HistoryDAO(trans, this);
59                 init(trans);
60         }
61
62
63         public ApprovalDAO(AuthzTrans trans, HistoryDAO hDAO) {
64                 super(trans, ApprovalDAO.class.getSimpleName(),hDAO,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE));
65                 historyDAO=hDAO;
66                 init(trans);
67         }
68
69         private static final int KEYLIMIT = 1;
70         public static class Data {
71                 public UUID   id;
72         public UUID   ticket;
73                 public String user;
74                 public String approver;
75                 public String type;
76                 public String status;
77                 public String memo;
78                 public String operation;
79                 public Date last_notified;
80                 public Date updated;
81         }
82         
83         private static class ApprovalLoader extends Loader<Data> {
84                 public static final ApprovalLoader deflt = new ApprovalLoader(KEYLIMIT);
85                 
86                 public ApprovalLoader(int keylimit) {
87                         super(keylimit);
88                 }
89                 
90                 @Override
91                 public Data load(Data data, Row row) {
92                         data.id = row.getUUID(0);
93                         data.ticket = row.getUUID(1);
94                         data.user = row.getString(2);
95                         data.approver = row.getString(3);
96                         data.type = row.getString(4);
97                         data.status = row.getString(5);
98                         data.memo = row.getString(6);
99                         data.operation = row.getString(7);
100                         data.last_notified = row.getTimestamp(8);
101                         // This is used to get "WRITETIME(STATUS)" from Approval, which gives us an "updated" 
102                         if(row.getColumnDefinitions().size()>9) {
103                                 // Rows reported in MicroSeconds
104                                 data.updated = new Date(row.getLong(9)/1000);
105                         }
106                         return data;
107                 }
108
109                 @Override
110                 protected void key(Data data, int idx, Object[] obj) {
111                         obj[idx]=data.id;
112                 }
113
114                 @Override
115                 protected void body(Data data, int _idx, Object[] obj) {
116                         int idx = _idx;
117                         obj[idx]=data.ticket;
118                         obj[++idx]=data.user;
119                         obj[++idx]=data.approver;
120                         obj[++idx]=data.type;
121                         obj[++idx]=data.status;
122                         obj[++idx]=data.memo;
123                         obj[++idx]=data.operation;
124                         obj[++idx]=data.last_notified;
125                 }
126         }       
127         
128         private void init(AuthzTrans trans) {
129                 String[] helpers = setCRUD(trans, TABLE, Data.class, ApprovalLoader.deflt,9);
130                 psByUser = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + ", WRITETIME(status) FROM " + TABLE + 
131                                 " WHERE user = ?", new ApprovalLoader(1) {
132                         @Override
133                         protected void key(Data data, int idx, Object[] obj) {
134                                 obj[idx]=data.user;
135                         }
136                 }, readConsistency);
137                 
138                 psByApprover = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + ", WRITETIME(status) FROM " + TABLE + 
139                                 " WHERE approver = ?", new ApprovalLoader(1) {
140                         @Override
141                         protected void key(Data data, int idx, Object[] obj) {
142                                 obj[idx]=data.approver;
143                         }
144                 }, readConsistency);
145
146                 psByTicket = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + ", WRITETIME(status) FROM " + TABLE + 
147                                 " WHERE ticket = ?", new ApprovalLoader(1) {
148                         @Override
149                         protected void key(Data data, int idx, Object[] obj) {
150                                 obj[idx]=data.ticket;
151                         }
152                 }, readConsistency);
153
154                 psByStatus = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + ", WRITETIME(status) FROM " + TABLE + 
155                                 " WHERE status = ?", new ApprovalLoader(1) {
156                         @Override
157                         protected void key(Data data, int idx, Object[] obj) {
158                                 obj[idx]=data.status;
159                         }
160                 }, readConsistency);
161
162
163         }
164
165         /* (non-Javadoc)
166          * @see org.onap.aaf.auth.dao.CassDAOImpl#create(com.att.inno.env.TransStore, java.lang.Object)
167          */
168         @Override
169         public Result<Data> create(AuthzTrans trans, Data data) {
170                 // If ID is not set (typical), create one.
171                 if(data.id==null) {
172                         data.id = Chrono.dateToUUID(System.currentTimeMillis());
173                 }
174                 Result<ResultSet> rs = createPS.exec(trans, C_TEXT, data);
175                 if(rs.notOK()) {
176                         return Result.err(rs);
177                 }
178                 return Result.ok(data); 
179         }
180
181
182         public Result<List<ApprovalDAO.Data>> readByUser(AuthzTrans trans, String user) {
183                 return psByUser.read(trans, R_TEXT, new Object[]{user});
184         }
185
186         public Result<List<ApprovalDAO.Data>> readByApprover(AuthzTrans trans, String approver) {
187                 return psByApprover.read(trans, R_TEXT, new Object[]{approver});
188         }
189
190         public Result<List<ApprovalDAO.Data>> readByTicket(AuthzTrans trans, UUID ticket) {
191                 return psByTicket.read(trans, R_TEXT, new Object[]{ticket});
192         }
193
194         public Result<List<ApprovalDAO.Data>> readByStatus(AuthzTrans trans, String status) {
195                 return psByStatus.read(trans, R_TEXT, new Object[]{status});
196         }       
197
198         /* (non-Javadoc)
199          * @see org.onap.aaf.auth.dao.CassDAOImpl#delete(com.att.inno.env.TransStore, java.lang.Object, boolean)
200          */
201         @Override
202         public Result<Void> delete(AuthzTrans trans, Data data, boolean reread) {
203                 if(reread || data.status == null) { // if Memo is empty, likely not full record
204                         Result<ResultSet> rd = readPS.exec(trans, R_TEXT, data);
205                         if(rd.notOK()) {
206                                 return Result.err(rd);
207                         }
208                         ApprovalLoader.deflt.load(data, rd.value.one());
209                 }
210                 if("approved".equals(data.status) || "denied".equals(data.status)) { 
211                         StringBuilder sb = new StringBuilder("BEGIN BATCH\n");
212                         sb.append("INSERT INTO ");
213                         sb.append(TABLELOG);
214                         sb.append(" (id,user,approver,type,status,memo,operation) VALUES (");
215                         sb.append(data.id);
216                         sb.append(",'"); sb.append(data.user);
217                         sb.append("','"); sb.append(data.approver);
218                         sb.append("','"); sb.append(data.type);
219                         sb.append("','"); sb.append(data.status);
220                         sb.append("','"); sb.append(data.memo.replace("'", "''"));
221                         sb.append("','"); sb.append(data.operation);
222                         sb.append("');\n");
223                         sb.append("DELETE FROM ");
224                         sb.append(TABLE);
225                         sb.append(" WHERE id=");
226                         sb.append(data.id);
227                         sb.append(";\n");
228                         sb.append("APPLY BATCH;\n");
229                         TimeTaken tt = trans.start("DELETE APPROVAL",Env.REMOTE);
230                         try {
231                                 if(async) {
232                                         getSession(trans).executeAsync(sb.toString());
233                                         return Result.ok();
234                                 } else {
235                                         getSession(trans).execute(sb.toString());
236                                         return Result.ok();
237                                 }
238                         } catch (DriverException | APIException | IOException e) {
239                                 reportPerhapsReset(trans,e);
240                                 return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG);
241                         } finally {
242                                 tt.done();
243                         }
244                 } else {
245                         return super.delete(trans, data, false);
246                 }
247
248         }
249
250
251         /**
252      * Log Modification statements to History
253      *
254      * @param modified        which CRUD action was done
255      * @param data            entity data that needs a log entry
256      * @param overrideMessage if this is specified, we use it rather than crafting a history message based on data
257      */
258     @Override
259     protected void wasModified(AuthzTrans trans, CRUD modified, Data data, String ... override) {
260         boolean memo = override.length>0 && override[0]!=null;
261         boolean subject = override.length>1 && override[1]!=null;
262
263         HistoryDAO.Data hd = HistoryDAO.newInitedData();
264         hd.user = trans.user();
265         hd.action = modified.name();
266         hd.target = TABLE;
267         hd.subject = subject?override[1]:data.user + "|" + data.approver;
268         hd.memo = memo
269                 ? String.format("%s by %s", override[0], hd.user)
270                 : (modified.name() + "d approval for " + data.user);
271         // Detail?
272         // Reconstruct?
273         if(historyDAO.create(trans, hd).status!=Status.OK) {
274                 trans.error().log("Cannot log to History");
275         }
276     }
277 }