2 * ============LICENSE_START===================================================
3 * SPARKY (AAI UI service)
4 * ============================================================================
5 * Copyright © 2017 AT&T Intellectual Property.
6 * Copyright © 2017 Amdocs
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=====================================================
22 * ECOMP and OpenECOMP are trademarks
23 * and service marks of AT&T Intellectual Property.
26 package org.openecomp.sparky.dal.cache;
28 import static java.util.concurrent.CompletableFuture.supplyAsync;
30 import java.io.IOException;
32 import java.net.URISyntaxException;
33 import java.nio.file.Files;
34 import java.nio.file.LinkOption;
35 import java.nio.file.Path;
36 import java.nio.file.Paths;
37 import java.util.ArrayList;
38 import java.util.List;
39 import java.util.concurrent.CompletableFuture;
40 import java.util.concurrent.ExecutionException;
41 import java.util.concurrent.ExecutorService;
43 import org.openecomp.cl.api.Logger;
44 import org.openecomp.cl.eelf.LoggerFactory;
45 import org.openecomp.sparky.dal.aai.ActiveInventoryAdapter;
46 import org.openecomp.sparky.dal.rest.OperationResult;
47 import org.openecomp.sparky.logging.AaiUiMsgs;
48 import org.openecomp.sparky.synchronizer.task.PersistOperationResultToDisk;
49 import org.openecomp.sparky.synchronizer.task.RetrieveOperationResultFromDisk;
50 import org.openecomp.sparky.util.NodeUtils;
52 import com.fasterxml.jackson.databind.ObjectMapper;
55 * The Class PersistentEntityCache.
57 public class PersistentEntityCache implements EntityCache {
59 private static final Logger LOG =
60 LoggerFactory.getInstance().getLogger(ActiveInventoryAdapter.class);
63 * TODO: <li>implement time-to-live on the cache, maybe pull in one of Guava's eviction caches?
64 * <li>implement abstract-base-cache to hold common cach-y things (like ttl)
67 private static final String DEFAULT_OUTPUT_PATH = "offlineEntityCache";
68 private ExecutorService persistentExecutor;
69 private ObjectMapper mapper;
70 private String storagePath;
73 * Instantiates a new persistent entity cache.
75 public PersistentEntityCache() {
80 * Instantiates a new persistent entity cache.
82 * @param numWorkers the num workers
84 public PersistentEntityCache(int numWorkers) {
85 this(null, numWorkers);
89 * Instantiates a new persistent entity cache.
91 * @param storageFolderOverride the storage folder override
92 * @param numWorkers the num workers
94 public PersistentEntityCache(String storageFolderOverride, int numWorkers) {
95 persistentExecutor = NodeUtils.createNamedExecutor("PEC", numWorkers, LOG);
96 mapper = new ObjectMapper();
98 if (storageFolderOverride != null && storageFolderOverride.length() > 0) {
99 this.storagePath = storageFolderOverride;
101 this.storagePath = DEFAULT_OUTPUT_PATH;
106 * Generate offline storage path from uri.
108 * @param link the link
111 private String generateOfflineStoragePathFromUri(String link) {
114 URI uri = new URI(link);
116 String modHost = uri.getHost().replace(".", "_");
118 String[] tokens = uri.getPath().split("\\/");
119 List<String> resourcePathAndDomain = new ArrayList<String>();
121 if (tokens.length >= 4) {
124 for (String w : tokens) {
126 if (numElements > 3) {
130 if (w.length() > 0) {
131 resourcePathAndDomain.add(w);
137 return this.storagePath + "\\";
140 return this.storagePath + "\\" + modHost + "\\"
141 + NodeUtils.concatArray(resourcePathAndDomain, "_") + "\\";
143 } catch (Exception exc) {
144 LOG.error(AaiUiMsgs.OFFLINE_STORAGE_PATH_ERROR, link, exc.getMessage());
147 return this.storagePath + "\\";
154 * @param directoryPath the directory path
156 private void createDirs(String directoryPath) {
157 if (directoryPath == null) {
161 Path path = Paths.get(directoryPath);
162 // if directory exists?
163 if (!Files.exists(path)) {
165 Files.createDirectories(path);
166 } catch (IOException exc) {
167 LOG.error(AaiUiMsgs.DISK_CREATE_DIR_IO_ERROR, exc.getMessage());
174 * @see org.openecomp.sparky.dal.cache.EntityCache#get(java.lang.String, java.lang.String)
177 public OperationResult get(String key, String link) {
179 final String storagePath = generateOfflineStoragePathFromUri(link);
180 createDirs(storagePath);
181 final String persistentFileName = storagePath + "\\" + key + ".json";
183 CompletableFuture<OperationResult> task = supplyAsync(
184 new RetrieveOperationResultFromDisk(persistentFileName, mapper, LOG), persistentExecutor);
188 * this will do a blocking get, but it will be blocking only on the thread that executed this
189 * method which should be one of the persistentWorker threads from the executor.
192 } catch (InterruptedException | ExecutionException exc) {
193 // TODO Auto-generated catch block
194 LOG.error(AaiUiMsgs.DISK_NAMED_DATA_READ_IO_ERROR, "txn", exc.getMessage());
202 * @see org.openecomp.sparky.dal.cache.EntityCache#put(java.lang.String, org.openecomp.sparky.dal.rest.OperationResult)
205 public void put(String key, OperationResult data) {
207 final String storagePath = generateOfflineStoragePathFromUri(data.getRequestLink());
208 createDirs(storagePath);
209 final String persistentFileName = storagePath + "\\" + key + ".json";
211 Path persistentFilePath = Paths.get(persistentFileName);
213 if (!Files.exists(persistentFilePath, LinkOption.NOFOLLOW_LINKS)) {
215 supplyAsync(new PersistOperationResultToDisk(persistentFileName, data, mapper, LOG),
216 persistentExecutor).whenComplete((opResult, error) -> {
219 LOG.error(AaiUiMsgs.DISK_DATA_WRITE_IO_ERROR, "entity", error.getMessage());
230 * @param args the arguments
231 * @throws URISyntaxException the URI syntax exception
233 public static void main(String[] args) throws URISyntaxException {
235 OperationResult or = new OperationResult();
236 or.setResult("asdjashdkajsdhaksdj");
237 or.setResultCode(200);
239 String url1 = "https://aai-int1.dev.att.com:8443/aai/v8/search/nodes-query?"
240 + "search-node-type=tenant&filter=tenant-id:EXISTS";
242 or.setRequestLink(url1);
244 PersistentEntityCache pec = new PersistentEntityCache("e:\\my_special_folder", 5);
245 String k1 = NodeUtils.generateUniqueShaDigest(url1);
249 "https://aai-int1.dev.att.com:8443/aai/v8/network/vnfcs/vnfc/trial-vnfc?nodes-only";
250 or.setRequestLink(url2);
251 String k2 = NodeUtils.generateUniqueShaDigest(url2);
254 String url3 = "https://1.2.3.4:8443/aai/v8/network/vnfcs/vnfc/trial-vnfc?nodes-only";
255 or.setRequestLink(url3);
256 String k3 = NodeUtils.generateUniqueShaDigest(url3);
262 * URI uri1 = new URI(url1);
264 * System.out.println("schemea = " + uri1.getScheme()); System.out.println("host = " +
267 * String host = uri1.getHost(); String[] tokens = host.split("\\.");
268 * System.out.println(Arrays.asList(tokens)); ArrayList<String> tokenList = new
269 * ArrayList(Arrays.asList(tokens)); //tokenList.remove(tokens.length-1); String
270 * hostAsPathElement = NodeUtils.concatArray(tokenList, "_");
272 * System.out.println("hostAsPathElement = " + hostAsPathElement);
275 * System.out.println("port = " + uri1.getPort()); System.out.println("path = " +
276 * uri1.getPath()); System.out.println("query = " + uri1.getQuery()); System.out.println(
277 * "fragment = " + uri1.getFragment());
284 * @see org.openecomp.sparky.dal.cache.EntityCache#shutdown()
287 public void shutdown() {
288 if (persistentExecutor != null) {
289 persistentExecutor.shutdown();
295 * @see org.openecomp.sparky.dal.cache.EntityCache#clear()
298 public void clear() {
300 * do nothing for this one, as it is not clear if we we really want to clear on the on-disk