6749c1fa6e80e85d50cf316b6ec1e9e5c6751fa6
[aai/sparky-be.git] / src / main / java / org / openecomp / sparky / dal / cache / PersistentEntityCache.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017 Amdocs
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  *
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  */
23 package org.openecomp.sparky.dal.cache;
24
25 import static java.util.concurrent.CompletableFuture.supplyAsync;
26
27 import java.io.IOException;
28 import java.net.URI;
29 import java.net.URISyntaxException;
30 import java.nio.file.Files;
31 import java.nio.file.LinkOption;
32 import java.nio.file.Path;
33 import java.nio.file.Paths;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.concurrent.CompletableFuture;
37 import java.util.concurrent.ExecutionException;
38 import java.util.concurrent.ExecutorService;
39
40 import org.openecomp.cl.api.Logger;
41 import org.openecomp.cl.eelf.LoggerFactory;
42 import org.openecomp.sparky.dal.aai.ActiveInventoryAdapter;
43 import org.openecomp.sparky.dal.rest.OperationResult;
44 import org.openecomp.sparky.logging.AaiUiMsgs;
45 import org.openecomp.sparky.synchronizer.task.PersistOperationResultToDisk;
46 import org.openecomp.sparky.synchronizer.task.RetrieveOperationResultFromDisk;
47 import org.openecomp.sparky.util.NodeUtils;
48
49 import com.fasterxml.jackson.databind.ObjectMapper;
50
51 /**
52  * The Class PersistentEntityCache.
53  */
54 public class PersistentEntityCache implements EntityCache {
55
56   private static final Logger LOG =
57       LoggerFactory.getInstance().getLogger(ActiveInventoryAdapter.class);
58
59   /*
60    * TODO: <li>implement time-to-live on the cache, maybe pull in one of Guava's eviction caches?
61    * <li>implement abstract-base-cache to hold common cach-y things (like ttl)
62    */
63
64   private static final String DEFAULT_OUTPUT_PATH = "offlineEntityCache";
65   private ExecutorService persistentExecutor;
66   private ObjectMapper mapper;
67   private String storagePath;
68
69   /**
70    * Instantiates a new persistent entity cache.
71    */
72   public PersistentEntityCache() {
73     this(null, 10);
74   }
75
76   /**
77    * Instantiates a new persistent entity cache.
78    *
79    * @param numWorkers the num workers
80    */
81   public PersistentEntityCache(int numWorkers) {
82     this(null, numWorkers);
83   }
84
85   /**
86    * Instantiates a new persistent entity cache.
87    *
88    * @param storageFolderOverride the storage folder override
89    * @param numWorkers the num workers
90    */
91   public PersistentEntityCache(String storageFolderOverride, int numWorkers) {
92     persistentExecutor = NodeUtils.createNamedExecutor("PEC", numWorkers, LOG);
93     mapper = new ObjectMapper();
94
95     if (storageFolderOverride != null && storageFolderOverride.length() > 0) {
96       this.storagePath = storageFolderOverride;
97     } else {
98       this.storagePath = DEFAULT_OUTPUT_PATH;
99     }
100   }
101
102   /**
103    * Generate offline storage path from uri.
104    *
105    * @param link the link
106    * @return the string
107    */
108   private String generateOfflineStoragePathFromUri(String link) {
109
110     try {
111       URI uri = new URI(link);
112
113       String modHost = uri.getHost().replace(".", "_");
114
115       String[] tokens = uri.getPath().split("\\/");
116       List<String> resourcePathAndDomain = new ArrayList<String>();
117
118       if (tokens.length >= 4) {
119
120         int numElements = 0;
121         for (String w : tokens) {
122
123           if (numElements > 3) {
124             break;
125           }
126
127           if (w.length() > 0) {
128             resourcePathAndDomain.add(w);
129             numElements++;
130           }
131
132         }
133       } else {
134         return this.storagePath + "\\";
135       }
136
137       return this.storagePath + "\\" + modHost + "\\"
138           + NodeUtils.concatArray(resourcePathAndDomain, "_") + "\\";
139
140     } catch (Exception exc) {
141       LOG.error(AaiUiMsgs.OFFLINE_STORAGE_PATH_ERROR, link, exc.getMessage());
142     }
143
144     return this.storagePath + "\\";
145
146   }
147
148   /**
149    * Creates the dirs.
150    *
151    * @param directoryPath the directory path
152    */
153   private void createDirs(String directoryPath) {
154     if (directoryPath == null) {
155       return;
156     }
157
158     Path path = Paths.get(directoryPath);
159     // if directory exists?
160     if (!Files.exists(path)) {
161       try {
162         Files.createDirectories(path);
163       } catch (IOException exc) {
164         LOG.error(AaiUiMsgs.DISK_CREATE_DIR_IO_ERROR, exc.getMessage());
165       }
166     }
167
168   }
169
170   /* (non-Javadoc)
171    * @see org.openecomp.sparky.dal.cache.EntityCache#get(java.lang.String, java.lang.String)
172    */
173   @Override
174   public OperationResult get(String key, String link) {
175
176     final String storagePath = generateOfflineStoragePathFromUri(link);
177     createDirs(storagePath);
178     final String persistentFileName = storagePath + "\\" + key + ".json";
179
180     CompletableFuture<OperationResult> task = supplyAsync(
181         new RetrieveOperationResultFromDisk(persistentFileName, mapper, LOG), persistentExecutor);
182
183     try {
184       /*
185        * this will do a blocking get, but it will be blocking only on the thread that executed this
186        * method which should be one of the persistentWorker threads from the executor.
187        */
188       return task.get();
189     } catch (InterruptedException | ExecutionException exc) {
190       // TODO Auto-generated catch block
191       LOG.error(AaiUiMsgs.DISK_NAMED_DATA_READ_IO_ERROR, "txn", exc.getMessage());
192     }
193
194     return null;
195
196   }
197
198   /* (non-Javadoc)
199    * @see org.openecomp.sparky.dal.cache.EntityCache#put(java.lang.String, org.openecomp.sparky.dal.rest.OperationResult)
200    */
201   @Override
202   public void put(String key, OperationResult data) {
203
204     final String storagePath = generateOfflineStoragePathFromUri(data.getRequestLink());
205     createDirs(storagePath);
206     final String persistentFileName = storagePath + "\\" + key + ".json";
207
208     Path persistentFilePath = Paths.get(persistentFileName);
209
210     if (!Files.exists(persistentFilePath, LinkOption.NOFOLLOW_LINKS)) {
211
212       supplyAsync(new PersistOperationResultToDisk(persistentFileName, data, mapper, LOG),
213           persistentExecutor).whenComplete((opResult, error) -> {
214
215             if (error != null) {
216               LOG.error(AaiUiMsgs.DISK_DATA_WRITE_IO_ERROR, "entity", error.getMessage());
217             }
218
219           });
220     }
221
222   }
223
224   /**
225    * The main method.
226    *
227    * @param args the arguments
228    * @throws URISyntaxException the URI syntax exception
229    */
230   public static void main(String[] args) throws URISyntaxException {
231
232     OperationResult or = new OperationResult();
233     or.setResult("asdjashdkajsdhaksdj");
234     or.setResultCode(200);
235
236     String url1 = "https://aai-int1.dev.att.com:8443/aai/v8/search/nodes-query?"
237         + "search-node-type=tenant&filter=tenant-id:EXISTS";
238
239     or.setRequestLink(url1);
240
241     PersistentEntityCache pec = new PersistentEntityCache("e:\\my_special_folder", 5);
242     String k1 = NodeUtils.generateUniqueShaDigest(url1);
243     pec.put(k1, or);
244
245     String url2 =
246         "https://aai-int1.dev.att.com:8443/aai/v8/network/vnfcs/vnfc/trial-vnfc?nodes-only";
247     or.setRequestLink(url2);
248     String k2 = NodeUtils.generateUniqueShaDigest(url2);
249     pec.put(k2, or);
250
251     String url3 = "https://1.2.3.4:8443/aai/v8/network/vnfcs/vnfc/trial-vnfc?nodes-only";
252     or.setRequestLink(url3);
253     String k3 = NodeUtils.generateUniqueShaDigest(url3);
254     pec.put(k3, or);
255
256     pec.shutdown();
257
258     /*
259      * URI uri1 = new URI(url1);
260      * 
261      * System.out.println("schemea = " + uri1.getScheme()); System.out.println("host = " +
262      * uri1.getHost());
263      * 
264      * String host = uri1.getHost(); String[] tokens = host.split("\\.");
265      * System.out.println(Arrays.asList(tokens)); ArrayList<String> tokenList = new
266      * ArrayList(Arrays.asList(tokens)); //tokenList.remove(tokens.length-1); String
267      * hostAsPathElement = NodeUtils.concatArray(tokenList, "_");
268      * 
269      * System.out.println("hostAsPathElement = " + hostAsPathElement);
270      * 
271      * 
272      * System.out.println("port = " + uri1.getPort()); System.out.println("path = " +
273      * uri1.getPath()); System.out.println("query = " + uri1.getQuery()); System.out.println(
274      * "fragment = " + uri1.getFragment());
275      */
276
277
278   }
279
280   /* (non-Javadoc)
281    * @see org.openecomp.sparky.dal.cache.EntityCache#shutdown()
282    */
283   @Override
284   public void shutdown() {
285     if (persistentExecutor != null) {
286       persistentExecutor.shutdown();
287     }
288
289   }
290
291   /* (non-Javadoc)
292    * @see org.openecomp.sparky.dal.cache.EntityCache#clear()
293    */
294   @Override
295   public void clear() {
296     /*
297      * do nothing for this one, as it is not clear if we we really want to clear on the on-disk
298      * cache or not
299      */
300   }
301
302 }