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                     if (in == null) {
108                         throw new RuntimeException("Cache properties `" + CACHE_PROPERTIES + "` could not be found");
109                     }
110 
111                     final Properties properties = new Properties();
112                     properties.load(in);
113                     properties.put("jcs.auxiliary.ODC.attributes.DiskPath", cacheDirectory.getCanonicalPath());
114                     for (CacheType t : CacheType.values()) {
115                         final File fp = new File(cacheDirectory, t.toString());
116                         properties.put("jcs.auxiliary." + t + ".attributes.DiskPath", fp.getCanonicalPath());
117                     }
118 
119                     JCS.setConfigProperties(properties);
120                     initialized = true;
121                 } catch (IOException ex) {
122                     throw new CacheException("Error creating disk cache", ex);
123                 }
124             }
125         }
126     }
127 
128     /**
129      * Returns the data cache for Node Audit.
130      *
131      * @return a references to the data cache for Node Audit
132      */
133     public DataCache<List<Advisory>> getNodeAuditCache() {
134         try {
135             final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
136             attr.setUseDisk(true);
137             attr.setUseLateral(false);
138             attr.setUseRemote(false);
139             final CacheAccess<String, List<Advisory>> ca = JCS.getInstance("NODEAUDIT", attr);
140             final DataCache<List<Advisory>> dc = new DataCache<>(ca);
141             return dc;
142         } catch (Throwable ex) {
143             //some reports of class not found exception, log and disable the cache.
144             if (ex instanceof CacheException) {
145                 throw ex;
146             }
147             //TODO we may want to instrument w/ jdiagnostics per #2509
148             LOGGER.debug("Error constructing cache for node audit files", ex);
149             throw new CacheException(ex);
150         }
151     }
152 
153     /**
154      * Returns the data cache for POM files.
155      *
156      * @return a references to the data cache for POM files
157      */
158     public DataCache<Model> getPomCache() {
159         try {
160             final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
161             attr.setUseDisk(true);
162             attr.setUseLateral(false);
163             attr.setUseRemote(false);
164             final CacheAccess<String, Model> ca = JCS.getInstance("POM", attr);
165             final DataCache<Model> dc = new DataCache<>(ca);
166             return dc;
167         } catch (Throwable ex) {
168             //some reports of class not found exception, log and disable the cache.
169             if (ex instanceof CacheException) {
170                 throw ex;
171             }
172             //TODO we may want to instrument w/ jdiagnostics per #2509
173             LOGGER.debug("Error constructing cache for POM files", ex);
174             throw new CacheException(ex);
175         }
176     }
177 
178     /**
179      * Returns the data cache for Central search.
180      *
181      * @return a references to the data cache for Central search
182      */
183     public DataCache<List<MavenArtifact>> getCentralCache() {
184         try {
185             final ICompositeCacheAttributes attr = new CompositeCacheAttributes();
186             attr.setUseDisk(true);
187             attr.setUseLateral(false);
188             attr.setUseRemote(false);
189             final CacheAccess<String, List<MavenArtifact>> ca = JCS.getInstance("CENTRAL", attr);
190             final DataCache<List<MavenArtifact>> dc = new DataCache<>(ca);
191             return dc;
192         } catch (Throwable ex) {
193             //some reports of class not found exception, log and disable the cache.
194             if (ex instanceof CacheException) {
195                 throw ex;
196             }
197             //TODO we may want to instrument w/ jdiagnostics per #2509
198             LOGGER.debug("Error constructing cache for Central files", ex);
199             throw new CacheException(ex);
200         }
201     }
202 }