aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/org/onap/aai/cacher/service/helper/CacheHelperService.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/onap/aai/cacher/service/helper/CacheHelperService.java')
-rw-r--r--src/main/java/org/onap/aai/cacher/service/helper/CacheHelperService.java545
1 files changed, 545 insertions, 0 deletions
diff --git a/src/main/java/org/onap/aai/cacher/service/helper/CacheHelperService.java b/src/main/java/org/onap/aai/cacher/service/helper/CacheHelperService.java
new file mode 100644
index 0000000..8b85174
--- /dev/null
+++ b/src/main/java/org/onap/aai/cacher/service/helper/CacheHelperService.java
@@ -0,0 +1,545 @@
+/**
+ * ============LICENSE_START=======================================================
+ * org.onap.aai
+ * ================================================================================
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.aai.cacher.service.helper;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.google.common.collect.Lists;
+import com.google.gson.*;
+import com.mongodb.*;
+import org.onap.aai.cacher.common.MongoHelperSingleton;
+import org.onap.aai.cacher.egestion.printer.PayloadPrinterService;
+import org.onap.aai.cacher.injestion.parser.PayloadParserService;
+import org.onap.aai.cacher.model.CacheEntry;
+import org.onap.aai.cacher.model.CacheKey;
+import org.onap.aai.cacher.util.AAIConstants;
+import org.onap.aai.exceptions.AAIException;
+import org.onap.aai.logging.ErrorLogHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import java.lang.reflect.Field;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@Service
+public class CacheHelperService {
+
+ private final static EELFLogger EELF_LOGGER = EELFManager.getInstance().getLogger(CacheHelperService.class);
+ private Gson gson = new GsonBuilder().create();
+
+ @Autowired
+ private MongoHelperSingleton mongoHelper;
+
+ @Autowired
+ private RestClientHelperService rchs;
+
+ @Autowired
+ private PayloadParserService payloadParserService;
+
+ @Autowired
+ private PayloadPrinterService payloadPrinterService;
+
+ public void setMongoHelper(MongoHelperSingleton mongoHelper) {
+ this.mongoHelper = mongoHelper;
+ }
+
+ public void setRchs(RestClientHelperService rchs) {
+ this.rchs = rchs;
+ }
+
+ public void setPayloadParserService(PayloadParserService payloadParserService) {
+ this.payloadParserService = payloadParserService;
+ }
+
+ public void setPayloadPrinterService(PayloadPrinterService payloadPrinterService) {
+ this.payloadPrinterService = payloadPrinterService;
+ }
+
+ public CacheKey retrieveCacheKeyObject(CacheKey ck) {
+ String ckString = retrieveCollectionString(ck, AAIConstants.COLLECTION_CACHEKEY);
+ if (ckString.equals("")) {
+ EELF_LOGGER.error("Could not retrieve cache key");
+ return null;
+ }
+ JsonParser parser = new JsonParser();
+ JsonObject ckJson = (JsonObject) parser.parse(ckString);
+ return CacheKey.fromJson(ckJson);
+ }
+
+ public String retrieveCollectionString(CacheKey ck, String collectionName) {
+ StringBuilder result = new StringBuilder("");
+ try {
+ DBCollection collection = mongoHelper.getDb().getCollection(collectionName);
+ BasicDBObject whereQuery = new BasicDBObject();
+ whereQuery.put("_id", ck.getCacheKey());
+ DBCursor cursor = collection.find(whereQuery);
+ while (cursor.hasNext()) {
+ result.append(cursor.next());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ ErrorLogHelper.logException(new AAIException("AAI_4000", e));
+ }
+ return result.toString();
+ }
+
+ public boolean isCollectionPresent(String collectionName) {
+ if (collectionName != null && !collectionName.isEmpty()) {
+ try {
+ DBCollection collection = mongoHelper.getDb().getCollection(collectionName);
+ DBCursor cursor = collection.find();
+ if (cursor.count() > 0) {
+ return true;
+ }
+ } catch (Exception e) {
+ ErrorLogHelper.logException(new AAIException("AAI_4000", e));
+ }
+ }
+ return false;
+ }
+
+ public String retrieveCollectionString(CacheKey ck) {
+ JsonArray jsonArray = new JsonArray();
+ try {
+ DBCollection collection = mongoHelper.getDb().getCollection(ck.getCacheKey());
+ DBCursor cursor = collection.find();
+ if (cursor.count() > 0) {
+ while (cursor.hasNext()) {
+ // remove "_id" property from cache response
+ JsonParser parser = new JsonParser();
+ JsonObject jsonObj = (JsonObject) parser.parse(cursor.next().toString());
+ jsonObj.remove("_id");
+ jsonArray.add(jsonObj);
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ ErrorLogHelper.logException(new AAIException("AAI_4000", e));
+ }
+ JsonObject jsonObject = payloadPrinterService.createJson(ck.getCacheKey(), jsonArray, ck.getParserStrategy());
+ if (jsonObject != null) {
+ return jsonObject.toString();
+ }
+ return "";
+ }
+
+ public boolean isKeyPresent(CacheKey ck, String collectionName) {
+ return !retrieveCollectionString(ck, collectionName).equals("");
+ }
+
+ public boolean isCurrentlyRunning(CacheKey ck) {
+ CacheKey ckPopulated = retrieveCacheKeyObject(ck);
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss.SSSZ");
+ Long syncStartTimeInMillis = -1L;
+ Long syncLastEndInMillis = -1L;
+ if (ckPopulated != null && !ckPopulated.getLastSyncStartTime().equals("-1")) {
+ try {
+ syncStartTimeInMillis = sdf.parse(ckPopulated.getLastSyncStartTime()).getTime();
+ } catch (Exception e) {
+ // TODO handle exceptions
+ }
+ }
+ if (ckPopulated != null && !ckPopulated.getLastSyncEndTime().equals("-1")) {
+ try {
+ syncLastEndInMillis = sdf.parse(ckPopulated.getLastSyncEndTime()).getTime();
+ } catch (Exception e) {
+ // TODO handle exceptions
+ }
+ }
+ return ckPopulated != null && syncLastEndInMillis < syncStartTimeInMillis;
+ }
+
+ public Response getData(CacheKey ck) {
+ if (ck == null) {
+ AAIException aaiException = new AAIException("AAI_3014", "Cache key provided does not exist");
+ return buildExceptionResponse(aaiException);
+ } else if (isCurrentlyRunning(ck)) {
+ AAIException aaiException = new AAIException("AAI_4000", "Sync is currently running from another process.");
+ return buildExceptionResponse(aaiException);
+ } else if (isKeyPresent(ck, AAIConstants.COLLECTION_CACHEKEY)) {
+ if (isCollectionPresent(ck.getCacheKey())) {
+ return retrieveCollectionByKey(ck);
+ } else {
+ ResponseEntity resp = rchs.triggerRestCall(ck);
+ if (!resp.getStatusCode().is2xxSuccessful()) {
+ // TODO log/return accordingly
+ }
+ Response response = populateCache(ck, (String) resp.getBody());
+ if (response.getStatus() == 201) {
+ return retrieveCollectionByKey(ck);
+ } else {
+ AAIException aaiException = new AAIException("AAI_5105");
+ return buildExceptionResponse(aaiException);
+ }
+ }
+ } else {
+ AAIException aaiException = new AAIException("AAI_3014", "Cache key provided does not exist");
+ return buildExceptionResponse(aaiException);
+ }
+ }
+
+ public Response forceSync(CacheKey ck) {
+ if (isCurrentlyRunning(ck)) {
+ AAIException aaiException = new AAIException("AAI_4000", "Sync is currently running from another process.");
+ return buildExceptionResponse(aaiException);
+ } else if (isKeyPresent(ck, AAIConstants.COLLECTION_CACHEKEY)) {
+ // populate cache and return status on sync
+ ResponseEntity resp = rchs.triggerRestCall(ck);
+ if (!resp.getStatusCode().is2xxSuccessful()) {
+ // TODO unsure if this is correct behavior
+ return Response.noContent().build();
+ }
+ return populateCache(ck, (String) resp.getBody());
+ } else {
+ AAIException aaiException = new AAIException("AAI_3014", "Cache key provided does not exist");
+ return buildExceptionResponse(aaiException);
+ }
+ }
+
+ public Response retrieveCollectionByKey(CacheKey ck, String collection) {
+ Status status = Status.OK;
+ String result = "";
+ try {
+ result = this.retrieveCollectionString(ck, collection);
+
+ if (result.equals("")) {
+ status = Status.NOT_FOUND;
+ EELF_LOGGER.error("Cannot not found the cache key from mongodb");
+ }
+ return this.buildResponse(status, result);
+ } catch (Exception e) {
+ AAIException aaiException = new AAIException("AAI_4000", e);
+ return buildExceptionResponse(aaiException);
+
+ }
+ }
+
+ public Response retrieveCollectionByKey(CacheKey ck) {
+ Status status = Status.OK;
+ String result = "";
+ try {
+ result = this.retrieveCollectionString(ck);
+ if (result.equals("")) {
+ status = Status.NOT_FOUND;
+ EELF_LOGGER.error("Cannot not found the cache key from mongodb");
+ }
+ return this.buildResponse(status, result);
+ } catch (Exception e) {
+ AAIException aaiException = new AAIException("AAI_4000", e);
+ return buildExceptionResponse(aaiException);
+
+ }
+ }
+
+ public boolean addCacheKey(CacheKey ck) {
+ return mongoHelper.addToMongo(AAIConstants.COLLECTION_CACHEKEY, ck.toDBObject());
+ }
+
+ public Response getAllKeys() {
+ Status status = Status.OK;
+ StringBuilder result = new StringBuilder();
+ try {
+ DBCollection collection = mongoHelper.getDb().getCollection(AAIConstants.COLLECTION_CACHEKEY);
+ DBCursor cursor = collection.find();
+ if (cursor.count() > 1) {
+ result.append("[");
+ while (cursor.hasNext()) {
+ result.append(cursor.next());
+ if (cursor.numSeen() != cursor.count()) {
+ result.append(",");
+ }
+ }
+ result.append("]");
+
+ } else if (cursor.count() == 1) {
+ while (cursor.hasNext()) {
+ result.append(cursor.next());
+ }
+ } else {
+ status = Status.NOT_FOUND;
+ }
+ return buildResponse(status, result.toString());
+ } catch (Exception e) {
+ AAIException aaiException = new AAIException("AAI_4000", e);
+ return buildExceptionResponse(aaiException);
+ }
+ }
+
+ public Response updateCacheKey(CacheKey ck) {
+ DBCollection collection = mongoHelper.getDb().getCollection(AAIConstants.COLLECTION_CACHEKEY);
+ Status status;
+
+ BasicDBObject updateFields = new BasicDBObject();
+
+ for (Field field : ck.getClass().getDeclaredFields()) {
+ try {
+ String name = field.getName();
+ Object value = field.get(ck);
+ if (!name.equals(AAIConstants.COLLECTION_CACHEKEY) && !value.equals("-1")) {
+ updateFields.append(name, value);
+ }
+ } catch (Exception e) {
+ EELF_LOGGER.warn("Could not retrieve updatable field from the class", e);
+ }
+ }
+
+ BasicDBObject setQuery = new BasicDBObject();
+ setQuery.append("$set", updateFields);
+
+ BasicDBObject searchQuery = new BasicDBObject("_id", ck.getCacheKey());
+ try {
+ WriteResult result = collection.update(searchQuery, setQuery);
+ if (result.getN() > 0) {
+ status = Status.OK;
+ } else {
+ // TODO set proper status for no results updated meaning it didn't find the key
+ status = Status.NOT_FOUND;
+ }
+ return buildResponse(status, "{}");
+ } catch (MongoException ex) {
+ AAIException aaiException = new AAIException("AAI_5105", ex);
+ return buildExceptionResponse(aaiException);
+ }
+ }
+
+ public boolean bulkAddCacheKeys(List<CacheKey> ckList) {
+ try {
+ List<BasicDBObject> documents = new ArrayList<BasicDBObject>();
+ for (CacheKey ck : ckList) {
+ documents.add(ck.toDBObject());
+ }
+ return mongoHelper.addToMongo(AAIConstants.COLLECTION_CACHEKEY, documents);
+ } catch (Exception e) {
+ AAIException aaiException = new AAIException("AAI_4000", e);
+ ErrorLogHelper.logException(aaiException);
+ return false;
+ }
+ }
+
+ public Response deleteCacheKeyAndAssociatedCache(String id) {
+ String cacheDelete = deleteFromCollection(null, id);
+ dropCollection(id);
+ String cacheKeyDelete = deleteFromCollection(id, AAIConstants.COLLECTION_CACHEKEY);
+ Status status;
+ if (cacheKeyDelete.equals("DELETED") && (cacheDelete.equals("DELETED") || cacheDelete.equals("NOT_FOUND"))) {
+ status = Status.NO_CONTENT;
+ return buildResponse(status, "{}");
+ } else if (cacheKeyDelete.equals("NOT_FOUND")) {
+ status = Status.NOT_FOUND;
+ return buildResponse(status, "{}");
+ } else {
+ AAIException aaiException = new AAIException("AAI_5105");
+ return buildExceptionResponse(aaiException);
+ }
+ }
+
+ public Response deleteCache(String id, String collection) {
+ String cacheDelete = deleteFromCollection(id, collection);
+ Status status;
+ if (cacheDelete.equals("DELETED")) {
+ status = Status.NO_CONTENT;
+ return buildResponse(status, "{}");
+ } else if (cacheDelete.equals("NOT_FOUND")) {
+ status = Status.NOT_FOUND;
+ return buildResponse(status, "{}");
+ } else {
+ AAIException aaiException = new AAIException("AAI_5105");
+ return buildExceptionResponse(aaiException);
+ }
+ }
+
+ public String deleteFromCollection(String id, String collection) {
+ Map<String, String> whereClause = new HashMap<>();
+ if (id != null) {
+ whereClause.put("_id", id);
+ }
+ return mongoHelper.deleteFromMongo(collection, whereClause);
+ }
+
+ public void dropCollection(String collection) {
+ mongoHelper.dropCollection(collection);
+ }
+
+ public Response populateCache(CacheKey ck, String responseBody) {
+ // Check to see if the cache key object is fully populated or an empty
+ // identifier object
+ // if it's an empty identifier object pull the entire object
+ if (ck.getBaseUrl().equals("-1")) {
+ ck = retrieveCacheKeyObject(ck);
+ }
+ DateFormat formatter = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss.SSSZ");
+
+ List<CacheEntry> cacheEntries = payloadParserService.doParse(ck.getCacheKey(), responseBody,
+ ck.getParserStrategy());
+ for (CacheEntry cacheEntry : cacheEntries) {
+ boolean success = false;
+
+ switch (cacheEntry.getDbAction()) {
+ case DELETE:
+ success = mongoHelper.delete(cacheEntry);
+ break;
+ case UPDATE:
+ success = mongoHelper.insertReplace(cacheEntry);
+ break;
+ case INSERT_REPLACE:
+ success = mongoHelper.insertReplace(cacheEntry);
+ break;
+ }
+
+ if (!success) {
+ ck.setLastSyncEndTime(formatter.format(System.currentTimeMillis()));
+ updateCacheKey(ck);
+ AAIException aaiException = new AAIException("AAI_4000", "Unable to populate the cache");
+ return buildExceptionResponse(aaiException);
+ }
+ }
+ ck.setLastSyncSuccessTime(formatter.format(System.currentTimeMillis()));
+ ck.setLastSyncEndTime(formatter.format(System.currentTimeMillis()));
+ updateCacheKey(ck);
+ return buildResponse(Status.CREATED, "{}");
+ }
+
+ public Response buildResponse(Status status, String result) {
+ return Response.status(status).type(MediaType.APPLICATION_JSON).entity(result).build();
+ }
+
+ public Response buildValidationResponse(List<String> issues) {
+ AAIException aaiException = new AAIException("AAI_3014");
+ ArrayList<String> templateVars = new ArrayList<>();
+
+ if (templateVars.isEmpty()) {
+ templateVars.add(issues.toString());
+ }
+ ErrorLogHelper.logException(aaiException);
+ return Response.status(aaiException.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponseWithLogging(
+ Lists.newArrayList(MediaType.APPLICATION_JSON_TYPE), aaiException, templateVars))
+ .build();
+ }
+
+ public Response buildExceptionResponse(AAIException aaiException) {
+ ErrorLogHelper.logException(aaiException);
+ return Response.status(aaiException.getErrorObject().getHTTPResponseCode())
+ .entity(ErrorLogHelper.getRESTAPIErrorResponseWithLogging(
+ Lists.newArrayList(MediaType.APPLICATION_JSON_TYPE), aaiException, new ArrayList<>()))
+ .build();
+ }
+
+ public List<CacheKey> getScheduledCaches() {
+ List<CacheKey> cks = new ArrayList<>();
+ EELF_LOGGER.info("Retrieving scheduled cache keys");
+ DBCollection collection = mongoHelper.getDb().getCollection(AAIConstants.COLLECTION_CACHEKEY);
+ BasicDBObject whereQuery = new BasicDBObject();
+ whereQuery.put("timingIndicator", "scheduled");
+ DBCursor cursor = collection.find(whereQuery);
+ while (cursor.hasNext()) {
+ JsonObject ckJson = (JsonObject) new JsonParser().parse((cursor.next().toString()));
+ CacheKey ck = CacheKey.fromJson(ckJson);
+ cks.add(ck);
+ }
+ return cks;
+ }
+
+ public void checkAndInitTasks() {
+ List<CacheKey> ckList = this.getScheduledCaches();
+ int numOfThread = 10;
+ ExecutorService taskExecutor = Executors.newFixedThreadPool(numOfThread);
+ try {
+ List<Callable<Void>> tasks = new ArrayList<>();
+ for (CacheKey ck : ckList) {
+
+ boolean shouldTrigger = isShouldTrigger(ck);
+
+ if (shouldTrigger) {
+ Callable<Void> task = new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ long startTimeV = System.currentTimeMillis();
+ ResponseEntity respEntity = rchs.triggerRestCall(ck);
+ if (respEntity.getStatusCode().is2xxSuccessful()) {
+ populateCache(ck, (String) respEntity.getBody());
+ long endTimeV = System.currentTimeMillis();
+ EELF_LOGGER.info("Elapsed time in seconds: " + (endTimeV - startTimeV) / 1000);
+ } else {
+ // TODO: cache update failed
+ }
+ return null;
+ }
+ };
+ if (task != null) {
+ tasks.add(task);
+ }
+ }
+ }
+ if (!tasks.isEmpty()) {
+ taskExecutor.invokeAll(tasks);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ // TODO throw exception
+ } finally {
+ taskExecutor.shutdown();
+ }
+ }
+
+ protected boolean isShouldTrigger(CacheKey ck) {
+
+ // convert minutes to milliseconds for the interval
+ int interval = Integer.parseInt(ck.getSyncInterval()) * 60000;
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss.SSSZ");
+ long syncStartTimeInMillis = Integer.MAX_VALUE;
+ long syncLastEndInMillis = Integer.MIN_VALUE;
+
+ if ("-1".equals(ck.getLastSyncStartTime())) {
+ return true;
+ } else {
+ try {
+ syncStartTimeInMillis = sdf.parse(ck.getLastSyncStartTime()).getTime();
+ } catch (Exception e) {
+ e.printStackTrace();
+ // TODO handle exceptions
+ }
+ }
+
+ if (!"-1".equals(ck.getLastSyncEndTime())) {
+ try {
+ syncLastEndInMillis = sdf.parse(ck.getLastSyncEndTime()).getTime();
+ } catch (Exception e) {
+ e.printStackTrace();
+ // TODO handle exceptions
+ }
+ }
+
+ return ((System.currentTimeMillis() - syncStartTimeInMillis) > interval)
+ && (syncStartTimeInMillis < syncLastEndInMillis);
+ }
+}