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 io.github.jeremylong.jcs3.slf4j.Slf4jAdapter;
21  import org.apache.commons.jcs3.JCS;
22  import org.apache.commons.jcs3.access.CacheAccess;
23  import org.apache.commons.jcs3.access.exception.CacheException;
24  import org.apache.commons.jcs3.engine.CompositeCacheAttributes;
25  import org.apache.commons.jcs3.engine.behavior.ICompositeCacheAttributes;
26  import org.owasp.dependencycheck.data.nexus.MavenArtifact;
27  import org.owasp.dependencycheck.data.nodeaudit.Advisory;
28  import org.owasp.dependencycheck.utils.FileUtils;
29  import org.owasp.dependencycheck.utils.Settings;
30  import org.owasp.dependencycheck.xml.pom.Model;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  import java.io.File;
35  import java.io.IOException;
36  import java.io.InputStream;
37  import java.util.List;
38  import java.util.Properties;
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             LOGGER.debug("Error constructing cache for node audit files", ex);
144             throw new CacheException(ex);
145         }
146     }
147 
148     /**
149      * Returns the data cache for POM files.
150      *
151      * @return a references to the data cache for POM files
152      */
153     public DataCache<Model> getPomCache() {
154         try {
155             final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
156             attr.setUseDisk(true);
157             attr.setUseLateral(false);
158             attr.setUseRemote(false);
159             final CacheAccess<String, Model> ca = JCS.getInstance("POM", attr);
160             final DataCache<Model> dc = new DataCache<>(ca);
161             return dc;
162         } catch (Throwable ex) {
163             //some reports of class not found exception, log and disable the cache.
164             if (ex instanceof CacheException) {
165                 throw ex;
166             }
167             LOGGER.debug("Error constructing cache for POM files", ex);
168             throw new CacheException(ex);
169         }
170     }
171 
172     /**
173      * Returns the data cache for Central search.
174      *
175      * @return a references to the data cache for Central search
176      */
177     public DataCache<List<MavenArtifact>> getCentralCache() {
178         try {
179             final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
180             attr.setUseDisk(true);
181             attr.setUseLateral(false);
182             attr.setUseRemote(false);
183             final CacheAccess<String, List<MavenArtifact>> ca = JCS.getInstance("CENTRAL", attr);
184             final DataCache<List<MavenArtifact>> dc = new DataCache<>(ca);
185             return dc;
186         } catch (Throwable ex) {
187             //some reports of class not found exception, log and disable the cache.
188             if (ex instanceof CacheException) {
189                 throw ex;
190             }
191             LOGGER.debug("Error constructing cache for Central files", ex);
192             throw new CacheException(ex);
193         }
194     }
195 }