2 * ============LICENSE_START=======================================================
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23 package org.openecomp.sparky.dal.cache;
25 import static java.util.concurrent.CompletableFuture.supplyAsync;
27 import java.io.IOException;
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;
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;
49 import com.fasterxml.jackson.databind.ObjectMapper;
52 * The Class PersistentEntityCache.
54 public class PersistentEntityCache implements EntityCache {
56 private static final Logger LOG =
57 LoggerFactory.getInstance().getLogger(ActiveInventoryAdapter.class);
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)
64 private static final String DEFAULT_OUTPUT_PATH = "offlineEntityCache";
65 private ExecutorService persistentExecutor;
66 private ObjectMapper mapper;
67 private String storagePath;
70 * Instantiates a new persistent entity cache.
72 public PersistentEntityCache() {
77 * Instantiates a new persistent entity cache.
79 * @param numWorkers the num workers
81 public PersistentEntityCache(int numWorkers) {
82 this(null, numWorkers);
86 * Instantiates a new persistent entity cache.
88 * @param storageFolderOverride the storage folder override
89 * @param numWorkers the num workers
91 public PersistentEntityCache(String storageFolderOverride, int numWorkers) {
92 persistentExecutor = NodeUtils.createNamedExecutor("PEC", numWorkers, LOG);
93 mapper = new ObjectMapper();
95 if (storageFolderOverride != null && storageFolderOverride.length() > 0) {
96 this.storagePath = storageFolderOverride;
98 this.storagePath = DEFAULT_OUTPUT_PATH;
103 * Generate offline storage path from uri.
105 * @param link the link
108 private String generateOfflineStoragePathFromUri(String link) {
111 URI uri = new URI(link);
113 String modHost = uri.getHost().replace(".", "_");
115 String[] tokens = uri.getPath().split("\\/");
116 List<String> resourcePathAndDomain = new ArrayList<String>();
118 if (tokens.length >= 4) {
121 for (String w : tokens) {
123 if (numElements > 3) {
127 if (w.length() > 0) {
128 resourcePathAndDomain.add(w);
134 return this.storagePath + "\\";
137 return this.storagePath + "\\" + modHost + "\\"
138 + NodeUtils.concatArray(resourcePathAndDomain, "_") + "\\";
140 } catch (Exception exc) {
141 LOG.error(AaiUiMsgs.OFFLINE_STORAGE_PATH_ERROR, link, exc.getMessage());
144 return this.storagePath + "\\";
151 * @param directoryPath the directory path
153 private void createDirs(String directoryPath) {
154 if (directoryPath == null) {
158 Path path = Paths.get(directoryPath);
159 // if directory exists?
160 if (!Files.exists(path)) {
162 Files.createDirectories(path);
163 } catch (IOException exc) {
164 LOG.error(AaiUiMsgs.DISK_CREATE_DIR_IO_ERROR, exc.getMessage());
171 * @see org.openecomp.sparky.dal.cache.EntityCache#get(java.lang.String, java.lang.String)
174 public OperationResult get(String key, String link) {
176 final String storagePath = generateOfflineStoragePathFromUri(link);
177 createDirs(storagePath);
178 final String persistentFileName = storagePath + "\\" + key + ".json";
180 CompletableFuture<OperationResult> task = supplyAsync(
181 new RetrieveOperationResultFromDisk(persistentFileName, mapper, LOG), persistentExecutor);
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.
189 } catch (InterruptedException | ExecutionException exc) {
190 // TODO Auto-generated catch block
191 LOG.error(AaiUiMsgs.DISK_NAMED_DATA_READ_IO_ERROR, "txn", exc.getMessage());
199 * @see org.openecomp.sparky.dal.cache.EntityCache#put(java.lang.String, org.openecomp.sparky.dal.rest.OperationResult)
202 public void put(String key, OperationResult data) {
204 final String storagePath = generateOfflineStoragePathFromUri(data.getRequestLink());
205 createDirs(storagePath);
206 final String persistentFileName = storagePath + "\\" + key + ".json";
208 Path persistentFilePath = Paths.get(persistentFileName);
210 if (!Files.exists(persistentFilePath, LinkOption.NOFOLLOW_LINKS)) {
212 supplyAsync(new PersistOperationResultToDisk(persistentFileName, data, mapper, LOG),
213 persistentExecutor).whenComplete((opResult, error) -> {
216 LOG.error(AaiUiMsgs.DISK_DATA_WRITE_IO_ERROR, "entity", error.getMessage());
226 * @see org.openecomp.sparky.dal.cache.EntityCache#shutdown()
229 public void shutdown() {
230 if (persistentExecutor != null) {
231 persistentExecutor.shutdown();
237 * @see org.openecomp.sparky.dal.cache.EntityCache#clear()
240 public void clear() {
242 * do nothing for this one, as it is not clear if we we really want to clear on the on-disk