Update AAF Version 1.0.0
[aaf/authz.git] / authz-cass / src / main / java / com / att / dao / CachedDAO.java
1 /*******************************************************************************\r
2  * ============LICENSE_START====================================================\r
3  * * org.onap.aaf\r
4  * * ===========================================================================\r
5  * * Copyright © 2017 AT&T Intellectual Property. All rights reserved.\r
6  * * ===========================================================================\r
7  * * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * * you may not use this file except in compliance with the License.\r
9  * * You may obtain a copy of the License at\r
10  * * \r
11  *  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * * \r
13  *  * Unless required by applicable law or agreed to in writing, software\r
14  * * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * * See the License for the specific language governing permissions and\r
17  * * limitations under the License.\r
18  * * ============LICENSE_END====================================================\r
19  * *\r
20  * * ECOMP is a trademark and service mark of AT&T Intellectual Property.\r
21  * *\r
22  ******************************************************************************/\r
23 package com.att.dao;\r
24 \r
25 import java.util.ArrayList;\r
26 import java.util.List;\r
27 \r
28 import com.att.authz.layer.Result;\r
29 import com.att.dao.aaf.cass.Status;\r
30 import com.att.inno.env.Trans;\r
31 \r
32 /**\r
33  * CachedDAO\r
34  * \r
35  * Cache the response of "get" of any DAO.  \r
36  * \r
37  * For simplicity's sake, at this time, we only do this for single Object keys  \r
38  * \r
39  *\r
40  * @param <DATA>\r
41  */\r
42 public class CachedDAO<TRANS extends Trans,D extends DAO<TRANS,DATA>,DATA extends Cacheable> \r
43                 extends Cached<TRANS,DATA> implements DAO_RO<TRANS,DATA>{\r
44 //      private final String dirty_str; \r
45         \r
46         private final D dao;\r
47 \r
48         public CachedDAO(D dao, CIDAO<TRANS> info, int segsize) {\r
49                 super(info, dao.table(), segsize);\r
50                 \r
51                 // Instantiate a new Cache per DAO name (so separate instances use the same cache) \r
52                 this.dao = dao;\r
53                 //read_str = "Cached READ for " + dao.table();\r
54 //              dirty_str = "Cache DIRTY on " + dao.table();\r
55                 if(dao instanceof CassDAOImpl) {\r
56                         ((CassDAOImpl<?,?>)dao).cache = this;\r
57                 }\r
58         }\r
59         \r
60         public static<T extends Trans, DA extends DAO<T,DT>, DT extends Cacheable> \r
61                         CachedDAO<T,DA,DT> create(DA dao, CIDAO<T> info, int segsize) {\r
62                 return new CachedDAO<T,DA,DT>(dao,info, segsize);\r
63         }\r
64 \r
65         public void add(DATA data)  {\r
66                 String key = keyFromObjs(dao.keyFrom(data));\r
67                 List<DATA> list = new ArrayList<DATA>();\r
68                 list.add(data);\r
69                 super.add(key,list);\r
70         }\r
71         \r
72 //      public void invalidate(TRANS trans, Object ... objs)  {\r
73 //              TimeTaken tt = trans.start(dirty_str, Env.SUB);\r
74 //              try {\r
75 //                      super.invalidate(keyFromObjs(objs));\r
76 //              } finally {\r
77 //                      tt.done();\r
78 //              }\r
79 //      }\r
80 \r
81         public static String keyFromObjs(Object ... objs) {\r
82                 String key;\r
83                 if(objs.length==1 && objs[0] instanceof String) {\r
84                         key = (String)objs[0];\r
85                 } else {\r
86                         StringBuilder sb = new StringBuilder();\r
87                         boolean first = true;\r
88                         for(Object o : objs) {\r
89                                 if(o!=null) {\r
90                                         if(first) {\r
91                                             first =false;\r
92                                         } else {\r
93                                             sb.append('|');\r
94                                         }\r
95                                         sb.append(o.toString());\r
96                                 }\r
97                         }\r
98                         key = sb.toString();\r
99                 }\r
100                 return key;\r
101         }\r
102 \r
103         public Result<DATA> create(TRANS trans, DATA data) {\r
104                 Result<DATA> d = dao.create(trans,data);\r
105                 if(d.status==Status.OK) {\r
106                     add(d.value);\r
107                 } else {\r
108                         trans.error().log(d.errorString());\r
109                 }\r
110                 invalidate(trans,data);\r
111                 return d;\r
112         }\r
113 \r
114         protected class DAOGetter implements Getter<DATA> {\r
115                 protected TRANS trans;\r
116                 protected Object objs[];\r
117                 protected D dao;\r
118                 public Result<List<DATA>> result;\r
119 \r
120                 public DAOGetter(TRANS trans, D dao, Object ... objs) {\r
121                         this.trans = trans;\r
122                         this.dao = dao;\r
123                         this.objs = objs;\r
124                 }\r
125                 \r
126                 /**\r
127                  * Separated into single call for easy overloading\r
128                  * @return\r
129                  */\r
130                 public Result<List<DATA>> call() {\r
131                         return dao.read(trans, objs);\r
132                 }\r
133                 \r
134                 @Override\r
135                 public final Result<List<DATA>> get() {\r
136                         return call();\r
137 //                      if(result.isOKhasData()) { // Note, given above logic, could exist, but stale\r
138 //                              return result.value;\r
139 //                      } else {\r
140 //                              return null;\r
141 //                      }\r
142                 }\r
143         }\r
144 \r
145         @Override\r
146         public Result<List<DATA>> read(final TRANS trans, final Object ... objs) {\r
147                 DAOGetter getter = new DAOGetter(trans,dao,objs); \r
148                 return get(trans, keyFromObjs(objs),getter);\r
149 //              if(ld!=null) {\r
150 //                      return Result.ok(ld);//.emptyList(ld.isEmpty());\r
151 //              }\r
152 //              // Result Result if exists\r
153 //              if(getter.result==null) {\r
154 //                      return Result.err(Status.ERR_NotFound, "No Cache or Lookup found on [%s]",dao.table());\r
155 //              }\r
156 //              return getter.result;\r
157         }\r
158 \r
159         // Slight Improved performance available when String and Obj versions are known. \r
160         public Result<List<DATA>> read(final String key, final TRANS trans, final Object ... objs) {\r
161                 DAOGetter getter = new DAOGetter(trans,dao,objs); \r
162                 return get(trans, key, getter);\r
163 //              if(ld!=null) {\r
164 //                      return Result.ok(ld);//.emptyList(ld.isEmpty());\r
165 //              }\r
166 //              // Result Result if exists\r
167 //              if(getter.result==null) {\r
168 //                      return Result.err(Status.ERR_NotFound, "No Cache or Lookup found on [%s]",dao.table());\r
169 //              }\r
170 //              return getter.result;\r
171         }\r
172         \r
173         @Override\r
174         public Result<List<DATA>> read(TRANS trans, DATA data) {\r
175                 return read(trans,dao.keyFrom(data));\r
176         }\r
177         public Result<Void> update(TRANS trans, DATA data) {\r
178                 Result<Void> d = dao.update(trans, data);\r
179                 if(d.status==Status.OK) {\r
180                     add(data);\r
181                 } else {\r
182                         trans.error().log(d.errorString());\r
183                 }\r
184                 return d;\r
185         }\r
186 \r
187         public Result<Void> delete(TRANS trans, DATA data, boolean reread) {\r
188                 if(reread) { // If reread, get from Cache, if possible, not DB exclusively\r
189                         Result<List<DATA>> rd = read(trans,data);\r
190                         if(rd.notOK()) {\r
191                             return Result.err(rd);\r
192                         } else {\r
193                                 trans.error().log(rd.errorString());\r
194                         }\r
195                         if(rd.isEmpty()) {\r
196                                 data.invalidate(this);\r
197                                 return Result.err(Status.ERR_NotFound,"Not Found");\r
198                         }\r
199                         data = rd.value.get(0);\r
200                 }\r
201                 Result<Void> rv=dao.delete(trans, data, false);\r
202                 data.invalidate(this);\r
203                 return rv;\r
204         }\r
205         \r
206         @Override\r
207         public void close(TRANS trans) {\r
208                 if(dao!=null) {\r
209                     dao.close(trans);\r
210                 }\r
211         }\r
212         \r
213 \r
214         @Override\r
215         public String table() {\r
216                 return dao.table();\r
217         }\r
218         \r
219         public D dao() {\r
220                 return dao;\r
221         }\r
222         \r
223         public void invalidate(TRANS trans, DATA data) {\r
224         if(info.touch(trans, dao.table(),data.invalidate(this)).notOK()) {\r
225             trans.error().log("Cannot touch CacheInfo for Role");\r
226         }\r
227         }\r
228 }\r