View Javadoc
1   package com.atlassian.plugin.osgi.container.impl;
2   
3   import com.atlassian.plugin.osgi.container.OsgiContainerException;
4   import com.atlassian.plugin.osgi.container.OsgiPersistentCache;
5   import com.google.common.base.Charsets;
6   import com.google.common.hash.Hashing;
7   import org.apache.commons.io.FileUtils;
8   import org.slf4j.Logger;
9   import org.slf4j.LoggerFactory;
10  
11  import java.io.File;
12  import java.io.IOException;
13  
14  import static com.google.common.base.Preconditions.checkNotNull;
15  import static com.google.common.base.Preconditions.checkState;
16  
17  /**
18   * Default implementation of persistent cache.  Handles clearing of directories if an upgrade has been detected.
19   *
20   * @since 2.2.0
21   */
22  public class DefaultOsgiPersistentCache implements OsgiPersistentCache {
23      private final File osgiBundleCache;
24      private final File frameworkBundleCache;
25      private final File transformedPluginCache;
26      private final Logger log = LoggerFactory.getLogger(DefaultOsgiPersistentCache.class);
27  
28      /**
29       * Constructs a cache, using the passed file as the base directory for cache subdirectories
30       *
31       * @param baseDir The base directory
32       */
33      public DefaultOsgiPersistentCache(final File baseDir) {
34          checkState(checkNotNull(baseDir).exists(), "The base directory for OSGi persistent caches should exist, %s", baseDir);
35          osgiBundleCache = new File(baseDir, "felix");
36          frameworkBundleCache = new File(baseDir, "framework-bundles");
37          transformedPluginCache = new File(baseDir, "transformed-plugins");
38          validate(null);
39      }
40  
41      /**
42       * Constructor added in the 2.2.0 beta timeframe, but was made redundant later.  Application version is not used.
43       *
44       * @deprecated
45       */
46      @Deprecated
47      public DefaultOsgiPersistentCache(final File baseDir, final String applicationVersion) {
48          this(baseDir);
49      }
50  
51      public File getFrameworkBundleCache() {
52          return frameworkBundleCache;
53      }
54  
55      public File getOsgiBundleCache() {
56          return osgiBundleCache;
57      }
58  
59      public File getTransformedPluginCache() {
60          return transformedPluginCache;
61      }
62  
63      public void clear() throws OsgiContainerException {
64          try {
65              FileUtils.cleanDirectory(frameworkBundleCache);
66              FileUtils.cleanDirectory(osgiBundleCache);
67              FileUtils.cleanDirectory(transformedPluginCache);
68          } catch (final IOException e) {
69              throw new OsgiContainerException("Unable to clear OSGi caches", e);
70          }
71      }
72  
73      public void validate(final String cacheValidationKey) {
74          ensureDirectoryExists(frameworkBundleCache);
75          ensureDirectoryExists(osgiBundleCache);
76          ensureDirectoryExists(transformedPluginCache);
77  
78          try {
79              FileUtils.cleanDirectory(osgiBundleCache);
80          } catch (final IOException e) {
81              throw new OsgiContainerException("Unable to clean the cache directory: " + osgiBundleCache, e);
82          }
83  
84          if (cacheValidationKey != null) {
85              final String newHash = Hashing.sha1().hashString(cacheValidationKey, Charsets.UTF_8).toString();
86              final File versionFile = new File(transformedPluginCache, "cache.key");
87              if (versionFile.exists()) {
88                  String oldVersion = null;
89                  try {
90                      oldVersion = FileUtils.readFileToString(versionFile);
91                  } catch (final IOException e) {
92                      log.debug("Unable to read cache key file", e);
93                  }
94                  if (!newHash.equals(oldVersion)) {
95                      log.info("Application upgrade detected, clearing OSGi cache directories");
96                      clear();
97                  } else {
98                      return;
99                  }
100             }
101 
102             try {
103                 FileUtils.writeStringToFile(versionFile, newHash);
104             } catch (final IOException e) {
105                 log.warn("Unable to write cache key file, so will be unable to detect upgrades", e);
106             }
107         }
108     }
109 
110     private void ensureDirectoryExists(final File dir) {
111         if (dir.exists() && !dir.isDirectory()) {
112             throw new IllegalArgumentException("'" + dir + "' is not a directory");
113         }
114 
115         if (!dir.exists() && !dir.mkdir()) {
116             throw new IllegalArgumentException("Directory '" + dir + "' cannot be created");
117         }
118     }
119 }