2 * ============LICENSE_START====================================================
4 * ===========================================================================
5 * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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====================================================
24 package org.onap.aaf.auth.dao.cass;
26 import java.io.IOException;
27 import java.util.Date;
28 import java.util.List;
29 import java.util.UUID;
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;
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;
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";
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;
60 private static final int KEYLIMIT = 1;
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);
69 public ApprovalDAO(AuthzTrans trans, HistoryDAO hDAO) {
70 super(trans, ApprovalDAO.class.getSimpleName(),hDAO,Data.class,TABLE, readConsistency(trans,TABLE), writeConsistency(trans,TABLE));
75 public static class Data {
79 public String approver;
83 public String operation;
87 private static class ApprovalLoader extends Loader<Data> {
88 public static final ApprovalLoader deflt = new ApprovalLoader(KEYLIMIT);
90 public ApprovalLoader(int keylimit) {
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);
113 protected void key(Data data, int idx, Object[] obj) {
118 protected void body(Data data, int idxParam, Object[] obj) {
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;
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) {
135 protected void key(Data data, int idx, Object[] obj) {
140 psByApprover = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + ", WRITETIME(status) FROM " + TABLE +
141 " WHERE approver = ?", new ApprovalLoader(1) {
143 protected void key(Data data, int idx, Object[] obj) {
144 obj[idx]=data.approver;
148 psByTicket = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + ", WRITETIME(status) FROM " + TABLE +
149 " WHERE ticket = ?", new ApprovalLoader(1) {
151 protected void key(Data data, int idx, Object[] obj) {
152 obj[idx]=data.ticket;
156 psByStatus = new PSInfo(trans, SELECT_SP + helpers[FIELD_COMMAS] + ", WRITETIME(status) FROM " + TABLE +
157 " WHERE status = ?", new ApprovalLoader(1) {
159 protected void key(Data data, int idx, Object[] obj) {
160 obj[idx]=data.status;
168 * @see org.onap.aaf.auth.dao.CassDAOImpl#create(com.att.inno.env.TransStore, java.lang.Object)
171 public Result<Data> create(AuthzTrans trans, Data data) {
172 // If ID is not set (typical), create one.
174 data.id = Chrono.dateToUUID(System.currentTimeMillis());
176 Result<ResultSet> rs = createPS.exec(trans, C_TEXT, data);
178 return Result.err(rs);
180 return Result.ok(data);
184 public Result<List<ApprovalDAO.Data>> readByUser(AuthzTrans trans, String user) {
185 return psByUser.read(trans, R_TEXT, new Object[]{user});
188 public Result<List<ApprovalDAO.Data>> readByApprover(AuthzTrans trans, String approver) {
189 return psByApprover.read(trans, R_TEXT, new Object[]{approver});
192 public Result<List<ApprovalDAO.Data>> readByTicket(AuthzTrans trans, UUID ticket) {
193 return psByTicket.read(trans, R_TEXT, new Object[]{ticket});
196 public Result<List<ApprovalDAO.Data>> readByStatus(AuthzTrans trans, String status) {
197 return psByStatus.read(trans, R_TEXT, new Object[]{status});
201 * @see org.onap.aaf.auth.dao.CassDAOImpl#delete(com.att.inno.env.TransStore, java.lang.Object, boolean)
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);
208 return Result.err(rd);
210 ApprovalLoader.deflt.load(data, rd.value.one());
212 if (APPROVED.equals(data.status) || DENIED.equals(data.status)) {
213 StringBuilder sb = new StringBuilder("BEGIN BATCH\n");
214 sb.append("INSERT INTO ");
216 sb.append(" (id,user,approver,type,status,memo,operation) VALUES (");
219 sb.append(data.user);
221 sb.append(data.approver);
223 sb.append(data.type);
225 sb.append(data.status);
227 sb.append(data.memo.replace("'", "''"));
229 sb.append(data.operation);
231 sb.append("DELETE FROM ");
233 sb.append(" WHERE id=");
236 sb.append("APPLY BATCH;\n");
237 TimeTaken tt = trans.start("DELETE APPROVAL",Env.REMOTE);
240 getSession(trans).executeAsync(sb.toString());
243 getSession(trans).execute(sb.toString());
246 } catch (DriverException | APIException | IOException e) {
247 reportPerhapsReset(trans,e);
248 return Result.err(Result.ERR_Backend, CassAccess.ERR_ACCESS_MSG);
253 return super.delete(trans, data, false);
260 * Log Modification statements to History
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
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;
271 HistoryDAO.Data hd = HistoryDAO.newInitedData();
272 hd.user = trans.user();
273 hd.action = modified.name();
275 hd.subject = subject?override[1]:data.user + "|" + data.approver;
277 ? String.format("%s by %s", override[0], hd.user)
278 : (modified.name() + "d approval for " + data.user);
281 if (historyDAO.create(trans, hd).status!=Status.OK) {
282 trans.error().log("Cannot log to History");