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