All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.hhdev.ocelot.core.CacheManager Maven / Gradle / Ivy

The newest version!
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package fr.hhdev.ocelot.core;

import fr.hhdev.ocelot.Constants;
import fr.hhdev.ocelot.annotations.JsCacheRemove;
import fr.hhdev.ocelot.annotations.JsCacheRemoveAll;
import fr.hhdev.ocelot.annotations.JsCacheRemoves;
import fr.hhdev.ocelot.annotations.JsCacheResult;
import fr.hhdev.ocelot.messaging.CacheEvent;
import fr.hhdev.ocelot.messaging.MessageEvent;
import fr.hhdev.ocelot.messaging.MessageToClient;
import fr.hhdev.ocelot.messaging.MessageType;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.JsonValue;
import javax.json.stream.JsonParsingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Class managing frond-end ccache
 *
 * @author hhfrancois
 */
public class CacheManager {

	private static final Logger logger = LoggerFactory.getLogger(CacheManager.class);

	@Inject
	@MessageEvent
	Event wsEvent;

	@Inject
	@CacheEvent
	Event cacheEvent;

	/**
	 * Check if resultshould be cached in front-end
	 *
	 * @param nonProxiedMethod
	 * @return
	 */
	public boolean isJsCached(Method nonProxiedMethod) {
		boolean cached = nonProxiedMethod.isAnnotationPresent(JsCacheResult.class);
		logger.debug("The result of the method {} should be cached on client side {}.", nonProxiedMethod.getName(), cached);
		return cached;
	}

	/**
	 * Get deadline for cache if 0 : is 1 year cache
	 *
	 * @param jcr
	 * @return
	 */
	public long getJsCacheResultDeadline(JsCacheResult jcr) {
		Calendar deadline = Calendar.getInstance();
		if ((jcr.year() + jcr.month() + jcr.day() + jcr.hour() + jcr.minute() + jcr.second() + jcr.millisecond()) == 0) {
			deadline.add(Calendar.YEAR, 1);
		} else {
			deadline.add(Calendar.YEAR, jcr.year());
			deadline.add(Calendar.MONTH, jcr.month());
			deadline.add(Calendar.DATE, jcr.day());
			deadline.add(Calendar.HOUR, jcr.hour());
			deadline.add(Calendar.MINUTE, jcr.minute());
			deadline.add(Calendar.SECOND, jcr.second());
			deadline.add(Calendar.MILLISECOND, jcr.millisecond());
		}
		return deadline.getTime().getTime();
	}

	/**
	 * Process annotations JsCacheRemove and JsCacheRemoves
	 *
	 * @param nonProxiedMethod
	 * @param paramNames
	 * @param jsonArgs
	 */
	public void processCleanCacheAnnotations(Method nonProxiedMethod, List paramNames, List jsonArgs) {
		boolean cleanAllCache = nonProxiedMethod.isAnnotationPresent(JsCacheRemoveAll.class);
		if (cleanAllCache) {
			JsCacheRemoveAll jcra = nonProxiedMethod.getAnnotation(JsCacheRemoveAll.class);
			processJsCacheRemoveAll(jcra);
		}
		boolean simpleCleancache = nonProxiedMethod.isAnnotationPresent(JsCacheRemove.class);
		if (simpleCleancache) {
			JsCacheRemove jcr = nonProxiedMethod.getAnnotation(JsCacheRemove.class);
			processJsCacheRemove(jcr, paramNames, jsonArgs);
		}
		boolean multiCleancache = nonProxiedMethod.isAnnotationPresent(JsCacheRemoves.class);
		if (multiCleancache) {
			JsCacheRemoves jcrs = nonProxiedMethod.getAnnotation(JsCacheRemoves.class);
			for (JsCacheRemove jcr : jcrs.value()) {
				processJsCacheRemove(jcr, paramNames, jsonArgs);
			}
		}
		if (simpleCleancache || multiCleancache) {
			logger.debug("The method {} will remove cache{} entr{} on clients side.", nonProxiedMethod.getName(), multiCleancache ? "s" : "", multiCleancache ? "ies" : "y");
		}
	}

	/**
	 * Process annotation JsCacheRemoveAll and send message for suppress all the cache
	 *
	 * @param jcra : the annotation
	 */
	public void processJsCacheRemoveAll(JsCacheRemoveAll jcra) {
		logger.debug("Process JsCacheRemoveAll annotation : {}", jcra);
		MessageToClient messageToClient = new MessageToClient();
		messageToClient.setId(Constants.Cache.CLEANCACHE_TOPIC);
		messageToClient.setResponse("ALL");
		wsEvent.fire(messageToClient);
	}

	/**
	 * Process an annotation JsCacheRemove and send a removeCache message to all clients connected
	 *
	 * @param jcr : l'annotation
	 * @param paramNames : name of parameters
	 * @param jsonArgs : method arguments json format
	 */
	public void processJsCacheRemove(JsCacheRemove jcr, List paramNames, List jsonArgs) {
		logger.debug("Process JsCacheRemove annotation : {}", jcr);
		StringBuilder sb;
		MessageToClient messageToClient = new MessageToClient();
		if(logger.isDebugEnabled()) {
			logger.debug("JsonArgs from Call : {}", Arrays.toString(jsonArgs.toArray(new String[jsonArgs.size()])));
			logger.debug("ParamName from considerated method : {}", Arrays.toString(paramNames.toArray(new String[paramNames.size()])));
		}
		String[] keys = jcr.keys();
		if (keys.length == 0) {
			sb = new StringBuilder("");
		} else {
			if (Constants.Cache.USE_ALL_ARGUMENTS.equals(keys[0])) {
				sb = new StringBuilder(Arrays.toString(jsonArgs.toArray(new String[jsonArgs.size()])));
			} else {
				sb = new StringBuilder("[");
				for (int idKey = 0; idKey < keys.length; idKey++) {
					String key = keys[idKey];
					logger.debug("Process {} : ", key);
					String[] path = key.split("\\.");
					logger.debug("Process '{}' : token nb '{}'", key, path.length);
					String paramName = path[0];
					logger.debug("Looking for index of param '{}'", paramName);
					int idx = paramNames.indexOf("\"" + paramName + "\"");
					logger.debug("Index of param '{}' : '{}'", paramName, idx);
					String jsonArg = jsonArgs.get(idx);
					logger.debug("Param '{}' : '{}'", paramName, jsonArg);
					if (path.length > 1) {
						try (JsonReader reader = Json.createReader(new StringReader(jsonArg))) {
							JsonValue jsonObject = reader.readObject();
							for (int i = 1; i < path.length; i++) {
								String p = path[i];
								if (!(jsonObject instanceof JsonObject)) {
									logger.error("Impossible to get " + p + " on " + jsonObject.toString() + ". It's not an json objet.");
								}
								logger.debug("Access to '{}' for '{}'", p, jsonObject.toString());
								jsonObject = ((JsonObject) jsonObject).get(p);
							}
							jsonArg = jsonObject.toString();
						} catch (JsonParsingException exception) {
							logger.warn("Fail to access to field for '{}'", jsonArg);
						}
					}
					logger.debug("Add value for '{}' : '{}' to builder cache key", key, jsonArg);
					sb.append(jsonArg);
					if (idKey + 1 < keys.length) {
						sb.append(",");
					}
				}
				sb.append("]");
			}
		}
		messageToClient.setId(Constants.Cache.CLEANCACHE_TOPIC);
		String cachekey = getMd5(jcr.cls().getName() + "." + jcr.methodName());
		if (sb.length() > 0) {
			cachekey += "_" + getMd5(sb.toString());
		}
		messageToClient.setResponse(cachekey);
		logger.debug("CACHEID : {}.{}_{} = {}", jcr.cls().getName(), jcr.methodName(), sb.toString(), cachekey);
		wsEvent.fire(messageToClient);
		cacheEvent.fire(cachekey);
	}

	/**
	 * Create a md5 from string
	 *
	 * @param msg
	 * @return
	 */
	private String getMd5(String msg) {
		MessageDigest md;
		try {
			md = MessageDigest.getInstance("MD5");
			byte[] hash = md.digest(msg.getBytes(Constants.UTF_8));
			//converting byte array to Hexadecimal String
			StringBuilder sb = new StringBuilder(2 * hash.length);
			for (byte b : hash) {
				sb.append(String.format("%02x", b & 0xff));
			}
			return sb.toString();
		} catch (NoSuchAlgorithmException | UnsupportedEncodingException ex) {
			logger.error("Fail to get MD5 of String "+msg, ex);
		}
		return null;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy