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  
26  import io.github.jeremylong.jcs3.slf4j.Slf4jAdapter;
27  import org.apache.commons.jcs3.JCS;
28  import org.apache.commons.jcs3.access.CacheAccess;
29  import org.apache.commons.jcs3.access.exception.CacheException;
30  import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
31  import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
32  import org.owasp.dependencycheck.data.nexus.MavenArtifact;
33  import org.owasp.dependencycheck.data.nodeaudit.Advisory;
34  import org.owasp.dependencycheck.utils.FileUtils;
35  import org.owasp.dependencycheck.utils.Settings;
36  import org.owasp.dependencycheck.xml.pom.Model;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  /**
41   * Factory to instantiate cache repositories.
42   *
43   * @author Jeremy Long
44   */
45  public class DataCacheFactory {
46  
47      /**
48       * The logger.
49       */
50      private static final Logger LOGGER = LoggerFactory.getLogger(DataCacheFactory.class);
51      /**
52       * The cache directory.
53       */
54      private static final String CACHE_DIRECTORY = "cache";
55      /**
56       * The cache properties.
57       */
58      private static final String CACHE_PROPERTIES = "dependencycheck-cache.properties";
59      /**
60       * Whether or not JCS has been initialized.
61       */
62      private static Boolean initialized = false;
63  
64      /**
65       * The types of caches that can be instantiated.
66       */
67      private enum CacheType {
68          /**
69           * Used to store node audit analysis.
70           */
71          NODEAUDIT,
72          /**
73           * Used to store the results of searching Maven Central.
74           */
75          CENTRAL,
76          /**
77           * Used to store POM files retrieved from central.
78           */
79          POM
80      }
81  
82      static {
83          System.setProperty("jcs.logSystem", "slf4j");
84          if (!LOGGER.isTraceEnabled()) {
85              Slf4jAdapter.muteLogging(true);
86          }
87      }
88  
89      /**
90       * Creates the data cache factory.
91       *
92       * @param settings the configuration settings
93       */
94      public DataCacheFactory(Settings settings) {
95          synchronized (DataCacheFactory.class) {
96              if (!initialized) {
97                  final File cacheDirectory;
98                  try {
99                      cacheDirectory = new File(settings.getDataDirectory(), CACHE_DIRECTORY);
100                 } catch (IOException ex) {
101                     throw new CacheException("Unable to obtain disk cache directory path", ex);
102                 }
103                 if (!cacheDirectory.isDirectory() && !cacheDirectory.mkdirs()) {
104                     throw new CacheException("Unable to create disk cache: " + cacheDirectory);
105                 }
106                 try (InputStream in = FileUtils.getResourceAsStream(CACHE_PROPERTIES)) {
107                     final Properties properties = new Properties();
108                     properties.load(in);
109                     properties.put("jcs.auxiliary.ODC.attributes.DiskPath", cacheDirectory.getCanonicalPath());
110                     for (CacheType t : CacheType.values()) {
111                         final File fp = new File(cacheDirectory, t.toString());
112                         properties.put("jcs.auxiliary." + t + ".attributes.DiskPath", fp.getCanonicalPath());
113                     }
114 
115                     JCS.setConfigProperties(properties);
116                     initialized = true;
117                 } catch (IOException ex) {
118                     throw new CacheException("Error creating disk cache", ex);
119                 }
120             }
121         }
122     }
123 
124     /**
125      * Returns the data cache for Node Audit.
126      *
127      * @return a references to the data cache for Node Audit
128      */
129     public DataCache<List<Advisory>> getNodeAuditCache() {
130         try {
131             final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
132             attr.setUseDisk(true);
133             attr.setUseLateral(false);
134             attr.setUseRemote(false);
135             final CacheAccess<String, List<Advisory>> ca = JCS.getInstance("NODEAUDIT", attr);
136             final DataCache<List<Advisory>> dc = new DataCache<>(ca);
137             return dc;
138         } catch (Throwable ex) {
139             //some reports of class not found exception, log and disable the cache.
140             if (ex instanceof CacheException) {
141                 throw ex;
142             }
143             //TODO we may want to instrument w/ jdiagnostics per #2509
144             LOGGER.debug("Error constructing cache for node audit files", ex);
145             throw new CacheException(ex);
146         }
147     }
148 
149     /**
150      * Returns the data cache for POM files.
151      *
152      * @return a references to the data cache for POM files
153      */
154     public DataCache<Model> getPomCache() {
155         try {
156             final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
157             attr.setUseDisk(true);
158             attr.setUseLateral(false);
159             attr.setUseRemote(false);
160             final CacheAccess<String, Model> ca = JCS.getInstance("POM", attr);
161             final DataCache<Model> dc = new DataCache<>(ca);
162             return dc;
163         } catch (Throwable ex) {
164             //some reports of class not found exception, log and disable the cache.
165             if (ex instanceof CacheException) {
166                 throw ex;
167             }
168             //TODO we may want to instrument w/ jdiagnostics per #2509
169             LOGGER.debug("Error constructing cache for POM files", ex);
170             throw new CacheException(ex);
171         }
172     }
173 
174     /**
175      * Returns the data cache for Central search.
176      *
177      * @return a references to the data cache for Central search
178      */
179     public DataCache<List<MavenArtifact>> getCentralCache() {
180         try {
181             final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
182             attr.setUseDisk(true);
183             attr.setUseLateral(false);
184             attr.setUseRemote(false);
185             final CacheAccess<String, List<MavenArtifact>> ca = JCS.getInstance("CENTRAL", attr);
186             final DataCache<List<MavenArtifact>> dc = new DataCache<>(ca);
187             return dc;
188         } catch (Throwable ex) {
189             //some reports of class not found exception, log and disable the cache.
190             if (ex instanceof CacheException) {
191                 throw ex;
192             }
193             //TODO we may want to instrument w/ jdiagnostics per #2509
194             LOGGER.debug("Error constructing cache for Central files", ex);
195             throw new CacheException(ex);
196         }
197     }
198 }