/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.util.annotation; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.PrintWriter; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.threeten.bp.Instant; import com.google.common.collect.ImmutableList; import com.opengamma.util.ArgumentChecker; /** * Caches a set of annotated classes. The cache can be written to disk, and reloaded to survive a JVM restart. */ public final class AnnotationCache { private static final Logger s_logger = LoggerFactory.getLogger(AnnotationCache.class); /** * The cache path property name */ public static final String CACHE_PATH_PROPERTY = "opengamma.annotationCachePath"; private final Instant _timestamp; private final Collection<String> _classNames = new LinkedList<String>(); private final Class<? extends Annotation> _annotationClass; private final String _cacheFileName; private AnnotationCache(final Instant timestamp, Class<? extends Annotation> annotationClass) { _timestamp = timestamp; _annotationClass = annotationClass; _cacheFileName = "." + annotationClass.getSimpleName(); } private void add(final String className) { _classNames.add(className); } private void addAll(final Collection<String> classNames) { _classNames.addAll(classNames); } /** * Returns the last modification timestamp. * * @return the timestamp, not null */ public Instant getTimestamp() { return _timestamp; } /** * Gets the classNames. * @return the classNames */ public Collection<String> getClassNames() { return ImmutableList.copyOf(_classNames); } /** * Gets the annotationClass. * @return the annotationClass */ public Class<? extends Annotation> getAnnotationClass() { return _annotationClass; } /** * Gets the cacheFileName. * @return the cacheFileName */ public String getCacheFileName() { return _cacheFileName; } /** * Returns the classes from the cache that contain function annotations. * * @return the classes */ public Collection<Class<?>> getClasses() { if (getClassNames().isEmpty()) { return Collections.emptyList(); } final Collection<Class<?>> classes = new ArrayList<Class<?>>(getClassNames().size()); for (String className : getClassNames()) { try { classes.add(Class.forName(className)); } catch (ClassNotFoundException e) { s_logger.info("Class not found", e); } } return classes; } protected static String getCacheFileName(Class<? extends Annotation> annotationClass) { return "." + annotationClass.getSimpleName(); } /** * Loads the function cache from disk (if available). * * @param annotationClass the annotation class, not null * @return the cache object, not null */ public static AnnotationCache load(Class<? extends Annotation> annotationClass) { ArgumentChecker.notNull(annotationClass, "annotation class"); final String path = System.getProperty(CACHE_PATH_PROPERTY); if (path == null) { s_logger.warn("No cache path set in system property {}", CACHE_PATH_PROPERTY); return new AnnotationCache(Instant.EPOCH, annotationClass); } final File cacheFile = new File(new File(path), getCacheFileName(annotationClass)); try { final BufferedReader br = new BufferedReader(new FileReader(cacheFile)); String str = br.readLine(); final AnnotationCache cache = new AnnotationCache(Instant.ofEpochMilli(Long.parseLong(str.trim())), annotationClass); while ((str = br.readLine()) != null) { str = str.trim(); if (str.length() > 0) { cache.add(str); } } br.close(); return cache; } catch (Throwable t) { s_logger.warn("Couldn't read cache file", t); return new AnnotationCache(Instant.EPOCH, annotationClass); } } /** * Saves the function cache to disk (if possible). */ public void save() { final String path = System.getProperty(CACHE_PATH_PROPERTY); if (path == null) { s_logger.warn("No cache path set in system property {}", CACHE_PATH_PROPERTY); return; } final File cacheFile = new File(new File(path), getCacheFileName()); try { final PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(cacheFile))); pw.println(getTimestamp().toEpochMilli()); for (String className : getClassNames()) { pw.println(className); } pw.flush(); pw.close(); } catch (Throwable t) { s_logger.warn("Couldn't write cache file", t); } } /** * Creates a function cache from a set of class names * * @param timestamp the cache timestamp, not null * @param annotationClass the annotation class, not null * @param classNames the class names, not null * @return the cache object, not null */ public static AnnotationCache create( final Instant timestamp, final Class<? extends Annotation> annotationClass, final Collection<String> classNames) { final AnnotationCache cache = new AnnotationCache(timestamp, annotationClass); cache.addAll(classNames); return cache; } }