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      public File getFrameworkBundleCache() {
42          return frameworkBundleCache;
43      }
44  
45      public File getOsgiBundleCache() {
46          return osgiBundleCache;
47      }
48  
49      public File getTransformedPluginCache() {
50          return transformedPluginCache;
51      }
52  
53      public void clear() throws OsgiContainerException {
54          try {
55              FileUtils.cleanDirectory(frameworkBundleCache);
56              FileUtils.cleanDirectory(osgiBundleCache);
57              FileUtils.cleanDirectory(transformedPluginCache);
58          } catch (final IOException e) {
59              throw new OsgiContainerException("Unable to clear OSGi caches", e);
60          }
61      }
62  
63      public void validate(final String cacheValidationKey) {
64          ensureDirectoryExists(frameworkBundleCache);
65          ensureDirectoryExists(osgiBundleCache);
66          ensureDirectoryExists(transformedPluginCache);
67  
68          try {
69              FileUtils.cleanDirectory(osgiBundleCache);
70          } catch (final IOException e) {
71              throw new OsgiContainerException("Unable to clean the cache directory: " + osgiBundleCache, e);
72          }
73  
74          if (cacheValidationKey != null) {
75              final String newHash = Hashing.sha1().hashString(cacheValidationKey, Charsets.UTF_8).toString();
76              final File versionFile = new File(transformedPluginCache, "cache.key");
77              if (versionFile.exists()) {
78                  String oldVersion = null;
79                  try {
80                      oldVersion = FileUtils.readFileToString(versionFile);
81                  } catch (final IOException e) {
82                      log.debug("Unable to read cache key file", e);
83                  }
84                  if (!newHash.equals(oldVersion)) {
85                      log.info("Application upgrade detected, clearing OSGi cache directories");
86                      clear();
87                  } else {
88                      return;
89                  }
90              }
91  
92              try {
93                  FileUtils.writeStringToFile(versionFile, newHash);
94              } catch (final IOException e) {
95                  log.warn("Unable to write cache key file, so will be unable to detect upgrades", e);
96              }
97          }
98      }
99  
100     private void ensureDirectoryExists(final File dir) {
101         if (dir.exists() && !dir.isDirectory()) {
102             throw new IllegalArgumentException("'" + dir + "' is not a directory");
103         }
104 
105         if (!dir.exists() && !dir.mkdir()) {
106             throw new IllegalArgumentException("Directory '" + dir + "' cannot be created");
107         }
108     }
109 }