package org.gcube.informationsystem.resourceregistry.api.contexts; import java.util.ArrayList; import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; import org.gcube.informationsystem.context.impl.entities.ContextImpl; import org.gcube.informationsystem.context.impl.relations.IsParentOfImpl; import org.gcube.informationsystem.context.reference.entities.Context; import org.gcube.informationsystem.context.reference.relations.IsParentOf; import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class ContextCache { private static Logger logger = LoggerFactory.getLogger(ContextCache.class); // in millisec public static final long DEFAULT_EXPIRING_TIMEOUT; public static int expiringTimeout; static { DEFAULT_EXPIRING_TIMEOUT = TimeUnit.HOURS.toMillis(6); expiringTimeout = (int) DEFAULT_EXPIRING_TIMEOUT; } public static void setExpiringTimeout(int expiringTimeout) { ContextCache.expiringTimeout = expiringTimeout; } protected static ContextCache singleton; public synchronized static ContextCache getInstance() { if(singleton==null) { singleton = new ContextCache(); } return singleton; } public void cleanCache() { cleanCache(Calendar.getInstance()); } private void cleanCache(Calendar now) { this.contexts = null; this.uuidToContext = new HashMap<>(); this.uuidToContextFullName = new HashMap<>(); this.contextFullNameToUUID = new HashMap<>(); this.creationTime = Calendar.getInstance(); this.creationTime.setTimeInMillis(now.getTimeInMillis()); this.expiringTime = Calendar.getInstance(); this.expiringTime.setTimeInMillis(now.getTimeInMillis()); this.expiringTime.add(Calendar.MILLISECOND, expiringTimeout); } protected ContextCacheRenewal contextCacheRenewal; // in millisec used for logging purposes only protected Calendar creationTime; // in millisec protected Calendar expiringTime; protected List contexts; protected Map uuidToContext; protected Map uuidToContextFullName; protected Map contextFullNameToUUID; public ContextCache() { Calendar now = Calendar.getInstance(); cleanCache(now); } public void setContextCacheRenewal(ContextCacheRenewal contextCacheRenewal) { if(this.contextCacheRenewal==null) { this.contextCacheRenewal = contextCacheRenewal; } } public void refreshContextsIfNeeded() throws ResourceRegistryException { Calendar now = Calendar.getInstance(); if(now.after(expiringTime) || (contexts==null && contextCacheRenewal!=null)) { try { List contexts = contextCacheRenewal.renew(); singleton.cleanCache(now); setContexts(contexts); } catch (ResourceRegistryException e) { logger.error("Unable to refresh Cache", e); if(contexts==null) { throw e; } } } } public synchronized List getContexts() throws ResourceRegistryException { refreshContextsIfNeeded(); return contexts; } private void setContexts(List contexts) { this.contexts = new ArrayList<>(); for(Context c : contexts) { UUID uuid = c.getHeader().getUUID(); Context context = new ContextImpl(c.getName()); context.setHeader(c.getHeader()); this.contexts.add(context); this.uuidToContext.put(uuid, context); } for(Context c : contexts) { UUID uuid = c.getHeader().getUUID(); Context context = this.uuidToContext.get(uuid); if(c.getParent()!=null) { IsParentOf ipo = c.getParent(); UUID parentUUID = ipo.getSource().getHeader().getUUID(); Context parent = this.uuidToContext.get(parentUUID); IsParentOf isParentOf = new IsParentOfImpl(parent, context); isParentOf.setHeader(ipo.getHeader()); parent.addChild(isParentOf); context.setParent(isParentOf); } } for(Context context : contexts) { UUID uuid = context.getHeader().getUUID(); String fullName = getContextFullName(context); this.uuidToContextFullName.put(uuid, fullName); this.contextFullNameToUUID.put(fullName, uuid); } } private String getContextFullName(Context context) { StringBuilder stringBuilder = new StringBuilder(); IsParentOf ipo = context.getParent(); if(ipo!=null) { Context c = ipo.getSource(); c = uuidToContext.get(c.getHeader().getUUID()); String parentFullName = getContextFullName(c); stringBuilder.append(parentFullName); } stringBuilder.append("/"); stringBuilder.append(context.getName()); return stringBuilder.toString(); } public synchronized String getContextFullNameByUUID(UUID uuid) throws ResourceRegistryException { refreshContextsIfNeeded(); return uuidToContextFullName.get(uuid); } public synchronized String getContextFullNameByUUID(String uuid) throws ResourceRegistryException { refreshContextsIfNeeded(); return uuidToContextFullName.get(UUID.fromString(uuid)); } public synchronized UUID getUUIDByFullName(String contextFullName) throws ResourceRegistryException { refreshContextsIfNeeded(); return contextFullNameToUUID.get(contextFullName); } public synchronized Context getContextByUUID(UUID uuid) throws ResourceRegistryException { refreshContextsIfNeeded(); return uuidToContext.get(uuid); } public synchronized Context getContextByUUID(String uuid) throws ResourceRegistryException { refreshContextsIfNeeded(); return uuidToContext.get(UUID.fromString(uuid)); } public synchronized Context getContextByFullName(String contextFullName) throws ResourceRegistryException { UUID uuid = getUUIDByFullName(contextFullName); return uuidToContext.get(uuid); } /** * @return an Map containing UUID to Context FullName association */ public synchronized Map getUUIDToContextFullNameAssociation() throws ResourceRegistryException { refreshContextsIfNeeded(); return new HashMap<>(uuidToContextFullName); } /** * @return an Map containing Context FullName to UUID association */ public synchronized Map getContextFullNameToUUIDAssociation() throws ResourceRegistryException { refreshContextsIfNeeded(); return new HashMap<>(contextFullNameToUUID); } }