Collection syntax change because of Sonar
[aaf/authz.git] / auth / auth-cass / src / main / java / org / onap / aaf / auth / dao / CachedDAO.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;
23
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import org.onap.aaf.auth.dao.cass.Status;
28 import org.onap.aaf.auth.layer.Result;
29 import org.onap.aaf.misc.env.Trans;
30
31 /**
32  * CachedDAO
33  * 
34  * Cache the response of "get" of any DAO.  
35  * 
36  * For simplicity's sake, at this time, we only do this for single Object keys  
37  * 
38  * @author Jonathan
39  *
40  * @param <DATA>
41  */
42 public class CachedDAO<TRANS extends Trans,D extends DAO<TRANS,DATA>,DATA extends Cacheable> 
43                 extends Cached<TRANS,DATA> implements DAO_RO<TRANS,DATA>{
44 //      private final String dirty_str; 
45         
46         private final D dao;
47
48         public CachedDAO(D dao, CIDAO<TRANS> info, int segsize, long expireIn) {
49                 super(info, dao.table(), segsize, expireIn);
50                 
51                 // Instantiate a new Cache per DAO name (so separate instances use the same cache) 
52                 this.dao = dao;
53                 //read_str = "Cached READ for " + dao.table();
54 //              dirty_str = "Cache DIRTY on " + dao.table();
55                 if(dao instanceof CassDAOImpl) {
56                         ((CassDAOImpl<?,?>)dao).cache = this;
57                 }
58         }
59         
60         public static<T extends Trans, DA extends DAO<T,DT>, DT extends Cacheable> 
61                         CachedDAO<T,DA,DT> create(DA dao, CIDAO<T> info, int segsize, long expireIn) {
62                 return new CachedDAO<T,DA,DT>(dao,info, segsize, expireIn);
63         }
64
65         public void add(DATA data)  {
66                 String key = keyFromObjs(dao.keyFrom(data));
67                 List<DATA> list = new ArrayList<>();
68                 list.add(data);
69                 super.add(key,list);
70         }
71         
72 //      public void invalidate(TRANS trans, Object ... objs)  {
73 //              TimeTaken tt = trans.start(dirty_str, Env.SUB);
74 //              try {
75 //                      super.invalidate(keyFromObjs(objs));
76 //              } finally {
77 //                      tt.done();
78 //              }
79 //      }
80
81         public static String keyFromObjs(Object ... objs) {
82                 String key;
83                 if(objs.length==1 && objs[0] instanceof String) {
84                         key = (String)objs[0];
85                 } else {
86                         StringBuilder sb = new StringBuilder();
87                         boolean first = true;
88                         for(Object o : objs) {
89                                 if(o!=null) {
90                                         if(first) {
91                                             first =false;
92                                         } else {
93                                             sb.append('|');
94                                         }
95                                         sb.append(o.toString());
96                                 }
97                         }
98                         key = sb.toString();
99                 }
100                 return key;
101         }
102
103         public Result<DATA> create(TRANS trans, DATA data) {
104                 Result<DATA> d = dao.create(trans,data);
105                 if(d.status==Status.OK) {
106                     add(d.value);
107                 } else {
108                         trans.error().log(d.errorString());
109                 }
110                 // dao.create already modifies cache. Do not invalidate again. invalidate(trans,data);
111                 return d;
112         }
113
114         protected class DAOGetter implements Getter<DATA> {
115                 protected TRANS trans;
116                 protected Object objs[];
117                 protected D dao;
118                 public Result<List<DATA>> result;
119
120                 public DAOGetter(TRANS trans, D dao, Object ... objs) {
121                         this.trans = trans;
122                         this.dao = dao;
123                         this.objs = objs;
124                 }
125                 
126                 /**
127                  * Separated into single call for easy overloading
128                  * @return
129                  */
130                 public Result<List<DATA>> call() {
131                         return dao.read(trans, objs);
132                 }
133                 
134                 @Override
135                 public final Result<List<DATA>> get() {
136                         return call();
137 //                      if(result.isOKhasData()) { // Note, given above logic, could exist, but stale
138 //                              return result.value;
139 //                      } else {
140 //                              return null;
141 //                      }
142                 }
143         }
144
145         @Override
146         public Result<List<DATA>> read(final TRANS trans, final Object ... objs) {
147                 DAOGetter getter = new DAOGetter(trans,dao,objs); 
148                 return get(trans, keyFromObjs(objs),getter);
149 //              if(ld!=null) {
150 //                      return Result.ok(ld);//.emptyList(ld.isEmpty());
151 //              }
152 //              // Result Result if exists
153 //              if(getter.result==null) {
154 //                      return Result.err(Status.ERR_NotFound, "No Cache or Lookup found on [%s]",dao.table());
155 //              }
156 //              return getter.result;
157         }
158
159         // Slight Improved performance available when String and Obj versions are known. 
160         public Result<List<DATA>> read(final String key, final TRANS trans, final Object[] objs) {
161                 DAOGetter getter = new DAOGetter(trans,dao,objs); 
162                 return get(trans, key, getter);
163 //              if(ld!=null) {
164 //                      return Result.ok(ld);//.emptyList(ld.isEmpty());
165 //              }
166 //              // Result Result if exists
167 //              if(getter.result==null) {
168 //                      return Result.err(Status.ERR_NotFound, "No Cache or Lookup found on [%s]",dao.table());
169 //              }
170 //              return getter.result;
171         }
172         
173         @Override
174         public Result<List<DATA>> read(TRANS trans, DATA data) {
175                 return read(trans,dao.keyFrom(data));
176         }
177         public Result<Void> update(TRANS trans, DATA data) {
178                 Result<Void> d = dao.update(trans, data);
179                 if(d.status==Status.OK) {
180                     add(data);
181                 } else {
182                         trans.error().log(d.errorString());
183                 }
184                 return d;
185         }
186
187         public Result<Void> delete(TRANS trans, DATA data, boolean reread) {
188                 if(reread) { // If reread, get from Cache, if possible, not DB exclusively
189                         Result<List<DATA>> rd = read(trans,data);
190                         if(rd.notOK()) {
191                             return Result.err(rd);
192 //                      } else {
193 //                              trans.error().log(rd.errorString());
194                         }
195                         if(rd.isEmpty()) {
196                                 data.invalidate(this);
197                                 return Result.err(Status.ERR_NotFound,"Not Found");
198                         }
199                         data = rd.value.get(0);
200                 }
201                 Result<Void> rv=dao.delete(trans, data, false);
202                 data.invalidate(this);
203                 return rv;
204         }
205         
206         @Override
207         public void close(TRANS trans) {
208                 if(dao!=null) {
209                     dao.close(trans);
210                 }
211         }
212         
213
214         @Override
215         public String table() {
216                 return dao.table();
217         }
218         
219         public D dao() {
220                 return dao;
221         }
222         
223         public void invalidate(TRANS trans, DATA data) {
224         if(info.touch(trans, dao.table(),data.invalidate(this)).notOK()) {
225             trans.error().log("Cannot touch CacheInfo for Role");
226         }
227         }
228 }