View Javadoc
1   /*
2    * This file is part of dependency-check-core.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Copyright (c) 2019 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.data.cache;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.util.List;
24  import java.util.Properties;
25  import org.apache.commons.jcs3.JCS;
26  import org.apache.commons.jcs3.access.CacheAccess;
27  import org.apache.commons.jcs3.access.exception.CacheException;
28  import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
29  import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
30  import org.owasp.dependencycheck.data.nexus.MavenArtifact;
31  import org.owasp.dependencycheck.data.nodeaudit.Advisory;
32  import org.owasp.dependencycheck.utils.FileUtils;
33  import org.owasp.dependencycheck.utils.Settings;
34  import org.owasp.dependencycheck.xml.pom.Model;
35  import org.slf4j.Logger;
36  import org.slf4j.LoggerFactory;
37  
38  /**
39   * Factory to instantiate cache repositories.
40   *
41   * @author Jeremy Long
42   */
43  public class DataCacheFactory {
44  
45      /**
46       * The logger.
47       */
48      private static final Logger LOGGER = LoggerFactory.getLogger(DataCacheFactory.class);
49      /**
50       * The cache directory.
51       */
52      private static final String CACHE_DIRECTORY = "cache";
53      /**
54       * The cache properties.
55       */
56      private static final String CACHE_PROPERTIES = "dependencycheck-cache.properties";
57      /**
58       * Whether or not JCS has been initialized.
59       */
60      private static Boolean initialized = false;
61  
62      /**
63       * The types of caches that can be instantiated.
64       */
65      private enum CacheType {
66          /**
67           * Used to store node audit analysis.
68           */
69          NODEAUDIT,
70          /**
71           * Used to store the results of searching Maven Central.
72           */
73          CENTRAL,
74          /**
75           * Used to store POM files retrieved from central.
76           */
77          POM
78      }
79  
80      /**
81       * Creates the data cache factory.
82       *
83       * @param settings the configuration settings
84       */
85      public DataCacheFactory(Settings settings) {
86          synchronized (DataCacheFactory.class) {
87              if (!initialized) {
88                  final File cacheDirectory;
89                  try {
90                      cacheDirectory = new File(settings.getDataDirectory(), CACHE_DIRECTORY);
91                  } catch (IOException ex) {
92                      throw new CacheException("Unable to obtain disk cache directory path", ex);
93                  }
94                  if (!cacheDirectory.isDirectory() && !cacheDirectory.mkdirs()) {
95                      throw new CacheException("Unable to create disk cache: " + cacheDirectory);
96                  }
97                  try (InputStream in = FileUtils.getResourceAsStream(CACHE_PROPERTIES)) {
98                      if (in == null) {
99                          throw new RuntimeException("Cache properties `" + CACHE_PROPERTIES + "` could not be found");
100                     }
101 
102                     final Properties properties = new Properties();
103                     properties.load(in);
104                     properties.put("jcs.auxiliary.ODC.attributes.DiskPath", cacheDirectory.getCanonicalPath());
105                     for (CacheType t : CacheType.values()) {
106                         final File fp = new File(cacheDirectory, t.toString());
107                         properties.put("jcs.auxiliary." + t + ".attributes.DiskPath", fp.getCanonicalPath());
108                     }
109 
110                     JCS.setConfigProperties(properties);
111                     initialized = true;
112                 } catch (IOException ex) {
113                     throw new CacheException("Error creating disk cache", ex);
114                 }
115             }
116         }
117     }
118 
119     /**
120      * Returns the data cache for Node Audit.
121      *
122      * @return a references to the data cache for Node Audit
123      */
124     public DataCache<List<Advisory>> getNodeAuditCache() {
125         try {
126             final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
127             attr.setUseDisk(true);
128             attr.setUseLateral(false);
129             attr.setUseRemote(false);
130             final CacheAccess<String, List<Advisory>> ca = JCS.getInstance("NODEAUDIT", attr);
131             final DataCache<List<Advisory>> dc = new DataCache<>(ca);
132             return dc;
133         } catch (Throwable ex) {
134             //some reports of class not found exception, log and disable the cache.
135             if (ex instanceof CacheException) {
136                 throw ex;
137             }
138             //TODO we may want to instrument w/ jdiagnostics per #2509
139             LOGGER.debug("Error constructing cache for node audit files", ex);
140             throw new CacheException(ex);
141         }
142     }
143 
144     /**
145      * Returns the data cache for POM files.
146      *
147      * @return a references to the data cache for POM files
148      */
149     public DataCache<Model> getPomCache() {
150         try {
151             final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
152             attr.setUseDisk(true);
153             attr.setUseLateral(false);
154             attr.setUseRemote(false);
155             final CacheAccess<String, Model> ca = JCS.getInstance("POM", attr);
156             final DataCache<Model> dc = new DataCache<>(ca);
157             return dc;
158         } catch (Throwable ex) {
159             //some reports of class not found exception, log and disable the cache.
160             if (ex instanceof CacheException) {
161                 throw ex;
162             }
163             //TODO we may want to instrument w/ jdiagnostics per #2509
164             LOGGER.debug("Error constructing cache for POM files", ex);
165             throw new CacheException(ex);
166         }
167     }
168 
169     /**
170      * Returns the data cache for Central search.
171      *
172      * @return a references to the data cache for Central search
173      */
174     public DataCache<List<MavenArtifact>> getCentralCache() {
175         try {
176             final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
177             attr.setUseDisk(true);
178             attr.setUseLateral(false);
179             attr.setUseRemote(false);
180             final CacheAccess<String, List<MavenArtifact>> ca = JCS.getInstance("CENTRAL", attr);
181             final DataCache<List<MavenArtifact>> dc = new DataCache<>(ca);
182             return dc;
183         } catch (Throwable ex) {
184             //some reports of class not found exception, log and disable the cache.
185             if (ex instanceof CacheException) {
186                 throw ex;
187             }
188             //TODO we may want to instrument w/ jdiagnostics per #2509
189             LOGGER.debug("Error constructing cache for Central files", ex);
190             throw new CacheException(ex);
191         }
192     }
193 }