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