View Javadoc
1   /*
2    * This file is part of dependency-check-maven.
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) 2014 Jeremy Long. All Rights Reserved.
17   */
18  package org.owasp.dependencycheck.maven;
19  
20  import java.util.List;
21  import java.util.logging.Logger;
22  import org.apache.maven.project.MavenProject;
23  import org.owasp.dependencycheck.analyzer.Analyzer;
24  import org.owasp.dependencycheck.analyzer.CPEAnalyzer;
25  import org.owasp.dependencycheck.analyzer.FileTypeAnalyzer;
26  import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
27  import org.owasp.dependencycheck.utils.Settings;
28  
29  /**
30   * A modified version of the core engine specifically designed to persist some
31   * data between multiple executions of a multi-module Maven project.
32   *
33   * @author Jeremy Long <jeremy.long@owasp.org>
34   */
35  public class Engine extends org.owasp.dependencycheck.Engine {
36  
37      /**
38       * The logger.
39       */
40      private static final transient Logger LOGGER = Logger.getLogger(Engine.class.getName());
41      /**
42       * A key used to persist an object in the MavenProject.
43       */
44      private static final String CPE_ANALYZER_KEY = "dependency-check-CPEAnalyzer";
45      /**
46       * The current MavenProject.
47       */
48      private MavenProject currentProject;
49      /**
50       * The list of MavenProjects that are part of the current build.
51       */
52      private List<MavenProject> reactorProjects;
53      /**
54       * Key used in the MavenProject context values to note whether or not an
55       * update has been executed.
56       */
57      public static final String UPDATE_EXECUTED_FLAG = "dependency-check-update-executed";
58  
59      /**
60       * Creates a new Engine to perform anyalsis on dependencies.
61       *
62       * @param project the current Maven project
63       * @param reactorProjects the reactor projects for the current Maven
64       * execution
65       * @throws DatabaseException thrown if there is an issue connecting to the
66       * database
67       */
68      public Engine(MavenProject project, List<MavenProject> reactorProjects) throws DatabaseException {
69          this.currentProject = project;
70          this.reactorProjects = reactorProjects;
71          initializeEngine();
72      }
73  
74      /**
75       * Runs the analyzers against all of the dependencies.
76       */
77      @Override
78      public void analyzeDependencies() {
79          final MavenProject root = getExecutionRoot();
80          if (root != null) {
81              LOGGER.fine(String.format("Checking root project, %s, if updates have already been completed", root.getArtifactId()));
82          } else {
83              LOGGER.fine("Checking root project, null, if updates have already been completed");
84          }
85          if (root != null && root.getContextValue(UPDATE_EXECUTED_FLAG) != null) {
86              System.setProperty(Settings.KEYS.AUTO_UPDATE, Boolean.FALSE.toString());
87          }
88          super.analyzeDependencies();
89          if (root != null) {
90              root.setContextValue(UPDATE_EXECUTED_FLAG, Boolean.TRUE);
91          }
92      }
93  
94      /**
95       * This constructor should not be called. Use Engine(MavenProject) instead.
96       *
97       * @throws DatabaseException thrown if there is an issue connecting to the
98       * database
99       */
100     private Engine() throws DatabaseException {
101     }
102 
103     /**
104      * Initializes the given analyzer. This skips the initialization of the
105      * CPEAnalyzer if it has been initialized by a previous execution.
106      *
107      * @param analyzer the analyzer to initialize
108      * @return the initialized analyzer
109      */
110     @Override
111     protected Analyzer initializeAnalyzer(Analyzer analyzer) {
112         if ((analyzer instanceof CPEAnalyzer)) {
113             CPEAnalyzer cpe = getPreviouslyLoadedCPEAnalyzer();
114             if (cpe != null) {
115                 return cpe;
116             }
117             cpe = (CPEAnalyzer) super.initializeAnalyzer(analyzer);
118             storeCPEAnalyzer(cpe);
119         }
120         return super.initializeAnalyzer(analyzer);
121     }
122 
123     /**
124      * Releases resources used by the analyzers by calling close() on each
125      * analyzer.
126      */
127     @Override
128     public void cleanup() {
129         super.cleanup();
130         if (currentProject == null || reactorProjects == null) {
131             return;
132         }
133         if (this.currentProject == reactorProjects.get(reactorProjects.size() - 1)) {
134             final CPEAnalyzer cpe = getPreviouslyLoadedCPEAnalyzer();
135             if (cpe != null) {
136                 cpe.close();
137             }
138         }
139     }
140 
141     /**
142      * Closes the given analyzer. This skips closing the CPEAnalyzer.
143      *
144      * @param analyzer the analyzer to close
145      */
146     @Override
147     protected void closeAnalyzer(Analyzer analyzer) {
148         if ((analyzer instanceof CPEAnalyzer)) {
149             if (getPreviouslyLoadedCPEAnalyzer() == null) {
150                 super.closeAnalyzer(analyzer);
151             }
152         } else {
153             super.closeAnalyzer(analyzer);
154         }
155     }
156 
157     /**
158      * Gets the CPEAnalyzer from the root Maven Project.
159      *
160      * @return an initialized CPEAnalyzer
161      */
162     private CPEAnalyzer getPreviouslyLoadedCPEAnalyzer() {
163         CPEAnalyzer cpe = null;
164         final MavenProject project = getExecutionRoot();
165         if (project != null) {
166             final Object obj = project.getContextValue(CPE_ANALYZER_KEY);
167             if (obj != null && obj instanceof CPEAnalyzer) {
168                 cpe = (CPEAnalyzer) project.getContextValue(CPE_ANALYZER_KEY);
169             }
170         }
171         return cpe;
172     }
173 
174     /**
175      * Stores a CPEAnalyzer in the root Maven Project.
176      *
177      * @param cpe the CPEAnalyzer to store
178      */
179     private void storeCPEAnalyzer(CPEAnalyzer cpe) {
180         final MavenProject p = getExecutionRoot();
181         if (p != null) {
182             p.setContextValue(CPE_ANALYZER_KEY, cpe);
183         }
184     }
185 
186     /**
187      * Returns the root Maven Project.
188      *
189      * @return the root Maven Project
190      */
191     private MavenProject getExecutionRoot() {
192         if (reactorProjects == null) {
193             return null;
194         }
195         for (MavenProject p : reactorProjects) {
196             if (p.isExecutionRoot()) {
197                 return p;
198             }
199         }
200         //the following should  never run, but leaving it as a failsafe.
201         if (this.currentProject == null) {
202             return null;
203         }
204         MavenProject p = this.currentProject;
205         while (p.getParent() != null) {
206             p = p.getParent();
207         }
208         return p;
209     }
210 
211     /**
212      * Resets the file type analyzers so that they can be re-used to scan
213      * additional directories. Without the reset the analyzer might be disabled
214      * because the first scan/analyze did not identify any files that could be
215      * processed by the analyzer.
216      */
217     public void resetFileTypeAnalyzers() {
218         for (FileTypeAnalyzer a : getFileTypeAnalyzers()) {
219             a.reset();
220         }
221     }
222 }