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