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.io.BufferedOutputStream;
21  import java.io.File;
22  import java.io.FileInputStream;
23  import java.io.FileNotFoundException;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.InputStream;
27  import java.io.ObjectOutputStream;
28  import java.util.List;
29  import java.util.Locale;
30  import org.eclipse.aether.artifact.Artifact;
31  import org.apache.maven.doxia.sink.Sink;
32  import org.apache.maven.plugin.AbstractMojo;
33  import org.apache.maven.plugin.MojoExecutionException;
34  import org.apache.maven.plugin.MojoFailureException;
35  import org.apache.maven.plugins.annotations.Component;
36  import org.apache.maven.plugins.annotations.Parameter;
37  import org.apache.maven.project.MavenProject;
38  import org.apache.maven.reporting.MavenReport;
39  import org.apache.maven.reporting.MavenReportException;
40  import org.apache.maven.settings.Proxy;
41  import org.apache.maven.settings.Server;
42  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilder;
43  import org.apache.maven.shared.dependency.graph.DependencyGraphBuilderException;
44  import org.apache.maven.shared.dependency.graph.DependencyNode;
45  import org.eclipse.aether.RepositorySystem;
46  import org.eclipse.aether.RepositorySystemSession;
47  import org.eclipse.aether.artifact.DefaultArtifact;
48  import org.eclipse.aether.repository.RemoteRepository;
49  import org.eclipse.aether.resolution.ArtifactRequest;
50  import org.eclipse.aether.resolution.ArtifactResolutionException;
51  import org.eclipse.aether.resolution.ArtifactResult;
52  import org.owasp.dependencycheck.data.nexus.MavenArtifact;
53  import org.owasp.dependencycheck.data.nvdcve.CveDB;
54  import org.owasp.dependencycheck.data.nvdcve.DatabaseException;
55  import org.owasp.dependencycheck.data.nvdcve.DatabaseProperties;
56  import org.owasp.dependencycheck.dependency.Confidence;
57  import org.owasp.dependencycheck.dependency.Dependency;
58  import org.owasp.dependencycheck.dependency.Identifier;
59  import org.owasp.dependencycheck.dependency.Vulnerability;
60  import org.owasp.dependencycheck.exception.ExceptionCollection;
61  import org.owasp.dependencycheck.exception.ReportException;
62  import org.owasp.dependencycheck.reporting.ReportGenerator;
63  import org.owasp.dependencycheck.utils.ExpectedOjectInputStream;
64  import org.owasp.dependencycheck.utils.Settings;
65  import org.sonatype.plexus.components.sec.dispatcher.DefaultSecDispatcher;
66  import org.sonatype.plexus.components.sec.dispatcher.SecDispatcher;
67  import org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException;
68  
69  /**
70   *
71   * @author Jeremy Long
72   */
73  public abstract class BaseDependencyCheckMojo extends AbstractMojo implements MavenReport {
74  
75      //<editor-fold defaultstate="collapsed" desc="Private fields">
76      /**
77       * The properties file location.
78       */
79      private static final String PROPERTIES_FILE = "mojo.properties";
80      /**
81       * System specific new line character.
82       */
83      private static final String NEW_LINE = System.getProperty("line.separator", "\n").intern();
84      //</editor-fold>
85      // <editor-fold defaultstate="collapsed" desc="Maven bound parameters and components">
86      /**
87       * Sets whether or not the external report format should be used.
88       */
89      @Parameter(property = "metaFileName", defaultValue = "dependency-check.ser", required = true)
90      private String dataFileName;
91      /**
92       * Sets whether or not the external report format should be used.
93       */
94      @Parameter(property = "failOnError", defaultValue = "true", required = true)
95      private boolean failOnError;
96  
97      /**
98       * Returns if the mojo should fail the build if an exception occurs.
99       *
100      * @return whether or not the mojo should fail the build
101      */
102     protected boolean isFailOnError() {
103         return failOnError;
104     }
105 
106     /**
107      * The Maven Project Object.
108      */
109     @Parameter(property = "project", required = true, readonly = true)
110     private MavenProject project;
111     /**
112      * List of Maven project of the current build
113      */
114     @Parameter(readonly = true, required = true, property = "reactorProjects")
115     private List<MavenProject> reactorProjects;
116     /**
117      * The entry point to Aether, i.e. the component doing all the work.
118      */
119     @Component
120     private RepositorySystem repoSystem;
121 
122     /**
123      * The current repository/network configuration of Maven.
124      */
125     @Parameter(defaultValue = "${repositorySystemSession}", readonly = true)
126     private RepositorySystemSession repoSession;
127 
128     /**
129      * The project's remote repositories to use for the resolution of plug-ins
130      * and their dependencies.
131      */
132     @Parameter(defaultValue = "${project.remotePluginRepositories}", readonly = true)
133     private List<RemoteRepository> remoteRepos;
134 
135     /**
136      * Component within Maven to build the dependency graph.
137      */
138     @Component
139     private DependencyGraphBuilder dependencyGraphBuilder;
140 
141     /**
142      * The output directory. This generally maps to "target".
143      */
144     @Parameter(defaultValue = "${project.build.directory}", required = true)
145     private File outputDirectory;
146     /**
147      * Specifies the destination directory for the generated Dependency-Check
148      * report. This generally maps to "target/site".
149      */
150     @Parameter(property = "project.reporting.outputDirectory", required = true)
151     private File reportOutputDirectory;
152     /**
153      * Specifies if the build should be failed if a CVSS score above a specified
154      * level is identified. The default is 11 which means since the CVSS scores
155      * are 0-10, by default the build will never fail.
156      */
157     @SuppressWarnings("CanBeFinal")
158     @Parameter(property = "failBuildOnCVSS", defaultValue = "11", required = true)
159     private float failBuildOnCVSS = 11;
160     /**
161      * Sets whether auto-updating of the NVD CVE/CPE data is enabled. It is not
162      * recommended that this be turned to false. Default is true.
163      */
164     @Parameter(property = "autoUpdate")
165     private Boolean autoUpdate;
166     /**
167      * Sets whether Experimental analyzers are enabled. Default is false.
168      */
169     @Parameter(property = "enableExperimental")
170     private Boolean enableExperimental;
171     /**
172      * Generate aggregate reports in multi-module projects.
173      *
174      * @deprecated use the aggregate goal instead
175      */
176     @Parameter(property = "aggregate")
177     @Deprecated
178     private Boolean aggregate;
179     /**
180      * The report format to be generated (HTML, XML, VULN, ALL). This
181      * configuration option has no affect if using this within the Site plug-in
182      * unless the externalReport is set to true. Default is HTML.
183      */
184     @SuppressWarnings("CanBeFinal")
185     @Parameter(property = "format", defaultValue = "HTML", required = true)
186     private String format = "HTML";
187     /**
188      * The Maven settings.
189      */
190     @Parameter(property = "mavenSettings", defaultValue = "${settings}", required = false)
191     private org.apache.maven.settings.Settings mavenSettings;
192 
193     /**
194      * The maven settings proxy id.
195      */
196     @Parameter(property = "mavenSettingsProxyId", required = false)
197     private String mavenSettingsProxyId;
198 
199     /**
200      * The Connection Timeout.
201      */
202     @Parameter(property = "connectionTimeout", defaultValue = "", required = false)
203     private String connectionTimeout;
204     /**
205      * The path to the suppression file.
206      */
207     @Parameter(property = "suppressionFile", defaultValue = "", required = false)
208     private String suppressionFile;
209     /**
210      * Flag indicating whether or not to show a summary in the output.
211      */
212     @SuppressWarnings("CanBeFinal")
213     @Parameter(property = "showSummary", defaultValue = "true", required = false)
214     private boolean showSummary = true;
215 
216     /**
217      * Whether or not the Jar Analyzer is enabled.
218      */
219     @Parameter(property = "jarAnalyzerEnabled", required = false)
220     private Boolean jarAnalyzerEnabled;
221 
222     /**
223      * Whether or not the Archive Analyzer is enabled.
224      */
225     @Parameter(property = "archiveAnalyzerEnabled", required = false)
226     private Boolean archiveAnalyzerEnabled;
227 
228     /**
229      * Sets whether the Python Distribution Analyzer will be used.
230      */
231     @Parameter(property = "pyDistributionAnalyzerEnabled", required = false)
232     private Boolean pyDistributionAnalyzerEnabled;
233     /**
234      * Sets whether the Python Package Analyzer will be used.
235      */
236     @Parameter(property = "pyPackageAnalyzerEnabled", required = false)
237     private Boolean pyPackageAnalyzerEnabled;
238     /**
239      * Sets whether the Ruby Gemspec Analyzer will be used.
240      */
241     @Parameter(property = "rubygemsAnalyzerEnabled", required = false)
242     private Boolean rubygemsAnalyzerEnabled;
243     /**
244      * Sets whether or not the openssl Analyzer should be used.
245      */
246     @Parameter(property = "opensslAnalyzerEnabled", required = false)
247     private Boolean opensslAnalyzerEnabled;
248     /**
249      * Sets whether or not the CMake Analyzer should be used.
250      */
251     @Parameter(property = "cmakeAnalyzerEnabled", required = false)
252     private Boolean cmakeAnalyzerEnabled;
253     /**
254      * Sets whether or not the autoconf Analyzer should be used.
255      */
256     @Parameter(property = "autoconfAnalyzerEnabled", required = false)
257     private Boolean autoconfAnalyzerEnabled;
258     /**
259      * Sets whether or not the PHP Composer Lock File Analyzer should be used.
260      */
261     @Parameter(property = "composerAnalyzerEnabled", required = false)
262     private Boolean composerAnalyzerEnabled;
263     /**
264      * Sets whether or not the Node.js Analyzer should be used.
265      */
266     @Parameter(property = "nodeAnalyzerEnabled", required = false)
267     private Boolean nodeAnalyzerEnabled;
268 
269     /**
270      * Whether or not the .NET Assembly Analyzer is enabled.
271      */
272     @Parameter(property = "assemblyAnalyzerEnabled", required = false)
273     private Boolean assemblyAnalyzerEnabled;
274 
275     /**
276      * Whether or not the .NET Nuspec Analyzer is enabled.
277      */
278     @Parameter(property = "nuspecAnalyzerEnabled", required = false)
279     private Boolean nuspecAnalyzerEnabled;
280 
281     /**
282      * Whether or not the Central Analyzer is enabled.
283      */
284     @Parameter(property = "centralAnalyzerEnabled", required = false)
285     private Boolean centralAnalyzerEnabled;
286 
287     /**
288      * Whether or not the Nexus Analyzer is enabled.
289      */
290     @Parameter(property = "nexusAnalyzerEnabled", required = false)
291     private Boolean nexusAnalyzerEnabled;
292 
293     /**
294      * The URL of a Nexus server's REST API end point
295      * (http://domain/nexus/service/local).
296      */
297     @Parameter(property = "nexusUrl", required = false)
298     private String nexusUrl;
299     /**
300      * Whether or not the configured proxy is used to connect to Nexus.
301      */
302     @Parameter(property = "nexusUsesProxy", required = false)
303     private Boolean nexusUsesProxy;
304     /**
305      * The database connection string.
306      */
307     @Parameter(property = "connectionString", defaultValue = "", required = false)
308     private String connectionString;
309 
310     /**
311      * Returns the connection string.
312      *
313      * @return the connection string
314      */
315     protected String getConnectionString() {
316         return connectionString;
317     }
318     /**
319      * The database driver name. An example would be org.h2.Driver.
320      */
321     @Parameter(property = "databaseDriverName", defaultValue = "", required = false)
322     private String databaseDriverName;
323     /**
324      * The path to the database driver if it is not on the class path.
325      */
326     @Parameter(property = "databaseDriverPath", defaultValue = "", required = false)
327     private String databaseDriverPath;
328     /**
329      * The server id in the settings.xml; used to retrieve encrypted passwords
330      * from the settings.xml.
331      */
332     @Parameter(property = "serverId", defaultValue = "", required = false)
333     private String serverId;
334     /**
335      * A reference to the settings.xml settings.
336      */
337     @Parameter(defaultValue = "${settings}", readonly = true, required = true)
338     private org.apache.maven.settings.Settings settingsXml;
339     /**
340      * The security dispatcher that can decrypt passwords in the settings.xml.
341      */
342     @Component(role = SecDispatcher.class, hint = "default")
343     private SecDispatcher securityDispatcher;
344     /**
345      * The database user name.
346      */
347     @Parameter(property = "databaseUser", defaultValue = "", required = false)
348     private String databaseUser;
349     /**
350      * The password to use when connecting to the database.
351      */
352     @Parameter(property = "databasePassword", defaultValue = "", required = false)
353     private String databasePassword;
354     /**
355      * A comma-separated list of file extensions to add to analysis next to jar,
356      * zip, ....
357      */
358     @Parameter(property = "zipExtensions", required = false)
359     private String zipExtensions;
360     /**
361      * Skip Dependency Check altogether.
362      */
363     @SuppressWarnings("CanBeFinal")
364     @Parameter(property = "dependency-check.skip", defaultValue = "false", required = false)
365     private boolean skip = false;
366     /**
367      * Skip Analysis for Test Scope Dependencies.
368      */
369     @SuppressWarnings("CanBeFinal")
370     @Parameter(property = "skipTestScope", defaultValue = "true", required = false)
371     private boolean skipTestScope = true;
372     /**
373      * Skip Analysis for Runtime Scope Dependencies.
374      */
375     @SuppressWarnings("CanBeFinal")
376     @Parameter(property = "skipRuntimeScope", defaultValue = "false", required = false)
377     private boolean skipRuntimeScope = false;
378     /**
379      * Skip Analysis for Provided Scope Dependencies.
380      */
381     @SuppressWarnings("CanBeFinal")
382     @Parameter(property = "skipProvidedScope", defaultValue = "false", required = false)
383     private boolean skipProvidedScope = false;
384     /**
385      * The data directory, hold DC SQL DB.
386      */
387     @Parameter(property = "dataDirectory", defaultValue = "", required = false)
388     private String dataDirectory;
389     /**
390      * Data Mirror URL for CVE 1.2.
391      */
392     @Parameter(property = "cveUrl12Modified", defaultValue = "", required = false)
393     private String cveUrl12Modified;
394     /**
395      * Data Mirror URL for CVE 2.0.
396      */
397     @Parameter(property = "cveUrl20Modified", defaultValue = "", required = false)
398     private String cveUrl20Modified;
399     /**
400      * Base Data Mirror URL for CVE 1.2.
401      */
402     @Parameter(property = "cveUrl12Base", defaultValue = "", required = false)
403     private String cveUrl12Base;
404     /**
405      * Data Mirror URL for CVE 2.0.
406      */
407     @Parameter(property = "cveUrl20Base", defaultValue = "", required = false)
408     private String cveUrl20Base;
409     /**
410      * Optionally skip excessive CVE update checks for a designated duration in
411      * hours.
412      */
413     @Parameter(property = "cveValidForHours", defaultValue = "", required = false)
414     private Integer cveValidForHours;
415 
416     /**
417      * The path to mono for .NET Assembly analysis on non-windows systems.
418      */
419     @Parameter(property = "pathToMono", defaultValue = "", required = false)
420     private String pathToMono;
421 
422     /**
423      * The Proxy URL.
424      *
425      * @deprecated Please use mavenSettings instead
426      */
427     @SuppressWarnings("CanBeFinal")
428     @Parameter(property = "proxyUrl", defaultValue = "", required = false)
429     @Deprecated
430     private String proxyUrl = null;
431     /**
432      * Sets whether or not the external report format should be used.
433      *
434      * @deprecated the internal report is no longer supported
435      */
436     @SuppressWarnings("CanBeFinal")
437     @Parameter(property = "externalReport")
438     @Deprecated
439     private String externalReport = null;
440     // </editor-fold>
441     //<editor-fold defaultstate="collapsed" desc="Base Maven implementation">
442 
443     /**
444      * Executes dependency-check.
445      *
446      * @throws MojoExecutionException thrown if there is an exception executing
447      * the mojo
448      * @throws MojoFailureException thrown if dependency-check failed the build
449      */
450     @Override
451     public void execute() throws MojoExecutionException, MojoFailureException {
452         generatingSite = false;
453         if (skip) {
454             getLog().info("Skipping " + getName(Locale.US));
455         } else {
456             validateAggregate();
457             project.setContextValue(getOutputDirectoryContextKey(), this.outputDirectory);
458             runCheck();
459         }
460     }
461 
462     /**
463      * Checks if the aggregate configuration parameter has been set to true. If
464      * it has a MojoExecutionException is thrown because the aggregate
465      * configuration parameter is no longer supported.
466      *
467      * @throws MojoExecutionException thrown if aggregate is set to true
468      */
469     private void validateAggregate() throws MojoExecutionException {
470         if (aggregate != null && aggregate) {
471             final String msg = "Aggregate configuration detected - as of dependency-check 1.2.8 this no longer supported. "
472                     + "Please use the aggregate goal instead.";
473             throw new MojoExecutionException(msg);
474         }
475     }
476 
477     /**
478      * Generates the Dependency-Check Site Report.
479      *
480      * @param sink the sink to write the report to
481      * @param locale the locale to use when generating the report
482      * @throws MavenReportException if a maven report exception occurs
483      * @deprecated use
484      * {@link #generate(org.apache.maven.doxia.sink.Sink, java.util.Locale)}
485      * instead.
486      */
487     @Override
488     @Deprecated
489     public final void generate(@SuppressWarnings("deprecation") org.codehaus.doxia.sink.Sink sink, Locale locale) throws MavenReportException {
490         generate((Sink) sink, locale);
491     }
492 
493     /**
494      * A flag indicating whether or not the maven site is being generated.
495      */
496     private boolean generatingSite = false;
497 
498     /**
499      * Returns true if the Maven site is being generated.
500      *
501      * @return true if the Maven site is being generated
502      */
503     protected boolean isGeneratingSite() {
504         return generatingSite;
505     }
506 
507     /**
508      * Generates the Dependency-Check Site Report.
509      *
510      * @param sink the sink to write the report to
511      * @param locale the locale to use when generating the report
512      * @throws MavenReportException if a maven report exception occurs
513      */
514     public void generate(Sink sink, Locale locale) throws MavenReportException {
515         generatingSite = true;
516         try {
517             validateAggregate();
518         } catch (MojoExecutionException ex) {
519             throw new MavenReportException(ex.getMessage());
520         }
521         project.setContextValue(getOutputDirectoryContextKey(), getReportOutputDirectory());
522         try {
523             runCheck();
524         } catch (MojoExecutionException ex) {
525             throw new MavenReportException(ex.getMessage(), ex);
526         } catch (MojoFailureException ex) {
527             getLog().warn("Vulnerabilities were identifies that exceed the CVSS threshold for failing the build");
528         }
529     }
530 
531     /**
532      * Returns the correct output directory depending on if a site is being
533      * executed or not.
534      *
535      * @return the directory to write the report(s)
536      * @throws MojoExecutionException thrown if there is an error loading the
537      * file path
538      */
539     protected File getCorrectOutputDirectory() throws MojoExecutionException {
540         return getCorrectOutputDirectory(this.project);
541     }
542 
543     /**
544      * Returns the correct output directory depending on if a site is being
545      * executed or not.
546      *
547      * @param current the Maven project to get the output directory from
548      * @return the directory to write the report(s)
549      */
550     protected File getCorrectOutputDirectory(MavenProject current) {
551         final Object obj = current.getContextValue(getOutputDirectoryContextKey());
552         if (obj != null && obj instanceof File) {
553             return (File) obj;
554         }
555         File target = new File(current.getBuild().getDirectory());
556         if (target.getParentFile() != null && "target".equals(target.getParentFile().getName())) {
557             target = target.getParentFile();
558         }
559         return target;
560     }
561 
562     /**
563      * Returns the correct output directory depending on if a site is being
564      * executed or not.
565      *
566      * @param current the Maven project to get the output directory from
567      * @return the directory to write the report(s)
568      */
569     protected File getDataFile(MavenProject current) {
570         if (getLog().isDebugEnabled()) {
571             getLog().debug(String.format("Getting data filefor %s using key '%s'", current.getName(), getDataFileContextKey()));
572         }
573         final Object obj = current.getContextValue(getDataFileContextKey());
574         if (obj != null) {
575             if (obj instanceof String) {
576                 final File f = new File((String) obj);
577                 return f;
578             }
579         } else if (getLog().isDebugEnabled()) {
580             getLog().debug("Context value not found");
581         }
582         return null;
583     }
584 
585     /**
586      * Scans the project's artifacts and adds them to the engine's dependency
587      * list.
588      *
589      * @param project the project to scan the dependencies of
590      * @param engine the engine to use to scan the dependencies
591      * @return a collection of exceptions that may have occurred while resolving
592      * and scanning the dependencies
593      */
594     protected ExceptionCollection scanArtifacts(MavenProject project, MavenEngine engine) {
595         // <editor-fold defaultstate="collapsed" desc="old implementation">
596         /*
597             for (Artifact a : project.getArtifacts()) {
598             if (excludeFromScan(a)) {
599             continue;
600             }
601             final List<Dependency> deps = engine.scan(a.getFile().getAbsoluteFile());
602             if (deps != null) {
603             if (deps.size() == 1) {
604             final Dependency d = deps.get(0);
605             if (d != null) {
606             final MavenArtifact ma = new MavenArtifact(a.getGroupId(), a.getArtifactId(), a.getVersion());
607             d.addAsEvidence("pom", ma, Confidence.HIGHEST);
608             d.addProjectReference(project.getName());
609             if (getLog().isDebugEnabled()) {
610             getLog().debug(String.format("Adding project reference %s on dependency %s", project.getName(),
611             d.getDisplayFileName()));
612             }
613             }
614             } else if (getLog().isDebugEnabled()) {
615             final String msg = String.format("More then 1 dependency was identified in first pass scan of '%s:%s:%s'",
616             a.getGroupId(), a.getArtifactId(), a.getVersion());
617             getLog().debug(msg);
618             }
619             }
620             }
621          */
622         // </editor-fold>
623         try {
624             final DependencyNode dn = dependencyGraphBuilder.buildDependencyGraph(project, null, reactorProjects);
625             return collectDependencies(engine, project, dn.getChildren());
626         } catch (DependencyGraphBuilderException ex) {
627             final String msg = String.format("Unable to build dependency graph on project %s", project.getName());
628             getLog().debug(msg, ex);
629             return new ExceptionCollection(msg, ex);
630         }
631     }
632 
633     /**
634      * Resolves the projects artifacts using Aether and scans the resulting
635      * dependencies.
636      *
637      * @param engine the core dependency-check engine
638      * @param project the project being scanned
639      * @param nodes the list of dependency nodes, generally obtained via the
640      * DependencyGraphBuilder
641      * @return a collection of exceptions that may have occurred while resolving
642      * and scanning the dependencies
643      */
644     private ExceptionCollection collectDependencies(MavenEngine engine, MavenProject project, List<DependencyNode> nodes) {
645         ExceptionCollection exCol = null;
646         for (DependencyNode dependencyNode : nodes) {
647             exCol = collectDependencies(engine, project, dependencyNode.getChildren());
648             if (excludeFromScan(dependencyNode.getArtifact().getScope())) {
649                 continue;
650             }
651             final ArtifactRequest request = new ArtifactRequest();
652             request.setArtifact(new DefaultArtifact(dependencyNode.getArtifact().getId()));
653             request.setRepositories(remoteRepos);
654             try {
655                 final ArtifactResult result = repoSystem.resolveArtifact(repoSession, request);
656                 if (result.isResolved() && result.getArtifact() != null && result.getArtifact().getFile() != null) {
657                     final List<Dependency> deps = engine.scan(result.getArtifact().getFile().getAbsoluteFile());
658                     if (deps != null) {
659                         if (deps.size() == 1) {
660                             final Dependency d = deps.get(0);
661                             if (d != null) {
662                                 final Artifact a = result.getArtifact();
663                                 final MavenArtifact ma = new MavenArtifact(a.getGroupId(), a.getArtifactId(), a.getVersion());
664                                 d.addAsEvidence("pom", ma, Confidence.HIGHEST);
665                                 d.addProjectReference(project.getName() + ":" + dependencyNode.getArtifact().getScope());
666                                 if (getLog().isDebugEnabled()) {
667                                     getLog().debug(String.format("Adding project reference %s on dependency %s",
668                                             project.getName(), d.getDisplayFileName()));
669                                 }
670                             }
671                         } else if (getLog().isDebugEnabled()) {
672                             final String msg = String.format("More then 1 dependency was identified in first pass scan of '%s' in project %s",
673                                     dependencyNode.getArtifact().getId(), project.getName());
674                             getLog().debug(msg);
675                         }
676                     } else {
677                         final String msg = String.format("Error resolving '%s' in project %s",
678                                 dependencyNode.getArtifact().getId(), project.getName());
679                         if (exCol == null) {
680                             exCol = new ExceptionCollection();
681                         }
682                         getLog().error(msg);
683                         for (Exception ex : result.getExceptions()) {
684                             exCol.addException(ex);
685                         }
686                     }
687                 } else {
688                     final String msg = String.format("Unable to resolve '%s' in project %s",
689                             dependencyNode.getArtifact().getId(), project.getName());
690                     getLog().debug(msg);
691                     if (exCol == null) {
692                         exCol = new ExceptionCollection();
693                     }
694                     for (Exception ex : result.getExceptions()) {
695                         exCol.addException(ex);
696                     }
697                 }
698             } catch (ArtifactResolutionException ex) {
699                 if (exCol == null) {
700                     exCol = new ExceptionCollection();
701                 }
702                 exCol.addException(ex);
703             }
704         }
705         return exCol;
706     }
707 
708     /**
709      * Executes the dependency-check scan and generates the necassary report.
710      *
711      * @throws MojoExecutionException thrown if there is an exception running
712      * the scan
713      * @throws MojoFailureException thrown if dependency-check is configured to
714      * fail the build
715      */
716     public abstract void runCheck() throws MojoExecutionException, MojoFailureException;
717 
718     /**
719      * Sets the Reporting output directory.
720      *
721      * @param directory the output directory
722      */
723     @Override
724     public void setReportOutputDirectory(File directory) {
725         reportOutputDirectory = directory;
726     }
727 
728     /**
729      * Returns the report output directory.
730      *
731      * @return the report output directory
732      */
733     @Override
734     public File getReportOutputDirectory() {
735         return reportOutputDirectory;
736     }
737 
738     /**
739      * Returns the output directory.
740      *
741      * @return the output directory
742      */
743     public File getOutputDirectory() {
744         return outputDirectory;
745     }
746 
747     /**
748      * Returns whether this is an external report. This method always returns
749      * true.
750      *
751      * @return <code>true</code>
752      */
753     @Override
754     public final boolean isExternalReport() {
755         return true;
756     }
757 
758     /**
759      * Returns the output name.
760      *
761      * @return the output name
762      */
763     @Override
764     public String getOutputName() {
765         if ("HTML".equalsIgnoreCase(this.format) || "ALL".equalsIgnoreCase(this.format)) {
766             return "dependency-check-report";
767         } else if ("XML".equalsIgnoreCase(this.format)) {
768             return "dependency-check-report.xml#";
769         } else if ("VULN".equalsIgnoreCase(this.format)) {
770             return "dependency-check-vulnerability";
771         } else {
772             getLog().warn("Unknown report format used during site generation.");
773             return "dependency-check-report";
774         }
775     }
776 
777     /**
778      * Returns the category name.
779      *
780      * @return the category name
781      */
782     @Override
783     public String getCategoryName() {
784         return MavenReport.CATEGORY_PROJECT_REPORTS;
785     }
786     //</editor-fold>
787 
788     /**
789      * Initializes a new <code>MavenEngine</code> that can be used for scanning.
790      *
791      * @return a newly instantiated <code>MavenEngine</code>
792      * @throws DatabaseException thrown if there is a database exception
793      */
794     protected MavenEngine initializeEngine() throws DatabaseException {
795         populateSettings();
796         return new MavenEngine(this.project, this.reactorProjects);
797     }
798 
799     /**
800      * Takes the properties supplied and updates the dependency-check settings.
801      * Additionally, this sets the system properties required to change the
802      * proxy url, port, and connection timeout.
803      */
804     protected void populateSettings() {
805         Settings.initialize();
806         InputStream mojoProperties = null;
807         try {
808             mojoProperties = this.getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE);
809             Settings.mergeProperties(mojoProperties);
810         } catch (IOException ex) {
811             getLog().warn("Unable to load the dependency-check ant task.properties file.");
812             if (getLog().isDebugEnabled()) {
813                 getLog().debug("", ex);
814             }
815         } finally {
816             if (mojoProperties != null) {
817                 try {
818                     mojoProperties.close();
819                 } catch (IOException ex) {
820                     if (getLog().isDebugEnabled()) {
821                         getLog().debug("", ex);
822                     }
823                 }
824             }
825         }
826         Settings.setBooleanIfNotNull(Settings.KEYS.AUTO_UPDATE, autoUpdate);
827 
828         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_EXPERIMENTAL_ENABLED, enableExperimental);
829 
830         if (externalReport != null) {
831             getLog().warn("The 'externalReport' option was set; this configuration option has been removed. "
832                     + "Please update the dependency-check-maven plugin's configuration");
833         }
834 
835         if (proxyUrl != null && !proxyUrl.isEmpty()) {
836             getLog().warn("Deprecated configuration detected, proxyUrl will be ignored; use the maven settings " + "to configure the proxy instead");
837         }
838         final Proxy proxy = getMavenProxy();
839         if (proxy != null) {
840             Settings.setString(Settings.KEYS.PROXY_SERVER, proxy.getHost());
841             Settings.setString(Settings.KEYS.PROXY_PORT, Integer.toString(proxy.getPort()));
842             final String userName = proxy.getUsername();
843             final String password = proxy.getPassword();
844             Settings.setStringIfNotNull(Settings.KEYS.PROXY_USERNAME, userName);
845             Settings.setStringIfNotNull(Settings.KEYS.PROXY_PASSWORD, password);
846             Settings.setStringIfNotNull(Settings.KEYS.PROXY_NON_PROXY_HOSTS, proxy.getNonProxyHosts());
847         }
848 
849         Settings.setStringIfNotEmpty(Settings.KEYS.CONNECTION_TIMEOUT, connectionTimeout);
850         Settings.setStringIfNotEmpty(Settings.KEYS.SUPPRESSION_FILE, suppressionFile);
851 
852         //File Type Analyzer Settings
853         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_JAR_ENABLED, jarAnalyzerEnabled);
854         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NUSPEC_ENABLED, nuspecAnalyzerEnabled);
855         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_CENTRAL_ENABLED, centralAnalyzerEnabled);
856         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_ENABLED, nexusAnalyzerEnabled);
857         Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_NEXUS_URL, nexusUrl);
858         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NEXUS_USES_PROXY, nexusUsesProxy);
859         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ASSEMBLY_ENABLED, assemblyAnalyzerEnabled);
860         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_ARCHIVE_ENABLED, archiveAnalyzerEnabled);
861         Settings.setStringIfNotEmpty(Settings.KEYS.ADDITIONAL_ZIP_EXTENSIONS, zipExtensions);
862         Settings.setStringIfNotEmpty(Settings.KEYS.ANALYZER_ASSEMBLY_MONO_PATH, pathToMono);
863 
864         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_PYTHON_DISTRIBUTION_ENABLED, pyDistributionAnalyzerEnabled);
865         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_PYTHON_PACKAGE_ENABLED, pyPackageAnalyzerEnabled);
866         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_RUBY_GEMSPEC_ENABLED, rubygemsAnalyzerEnabled);
867         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_OPENSSL_ENABLED, opensslAnalyzerEnabled);
868         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_CMAKE_ENABLED, cmakeAnalyzerEnabled);
869         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_AUTOCONF_ENABLED, autoconfAnalyzerEnabled);
870         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_COMPOSER_LOCK_ENABLED, composerAnalyzerEnabled);
871         Settings.setBooleanIfNotNull(Settings.KEYS.ANALYZER_NODE_PACKAGE_ENABLED, nodeAnalyzerEnabled);
872 
873         //Database configuration
874         Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_NAME, databaseDriverName);
875         Settings.setStringIfNotEmpty(Settings.KEYS.DB_DRIVER_PATH, databaseDriverPath);
876         Settings.setStringIfNotEmpty(Settings.KEYS.DB_CONNECTION_STRING, connectionString);
877 
878         if (databaseUser == null && databasePassword == null && serverId != null) {
879             final Server server = settingsXml.getServer(serverId);
880             if (server != null) {
881                 databaseUser = server.getUsername();
882                 try {
883                     //The following fix was copied from:
884                     //   https://github.com/bsorrentino/maven-confluence-plugin/blob/master/maven-confluence-reporting-plugin/src/main/java/org/bsc/maven/confluence/plugin/AbstractBaseConfluenceMojo.java
885                     //
886                     // FIX to resolve
887                     // org.sonatype.plexus.components.sec.dispatcher.SecDispatcherException:
888                     // java.io.FileNotFoundException: ~/.settings-security.xml (No such file or directory)
889                     //
890                     if (securityDispatcher instanceof DefaultSecDispatcher) {
891                         ((DefaultSecDispatcher) securityDispatcher).setConfigurationFile("~/.m2/settings-security.xml");
892                     }
893 
894                     databasePassword = securityDispatcher.decrypt(server.getPassword());
895                 } catch (SecDispatcherException ex) {
896                     if (ex.getCause() instanceof FileNotFoundException
897                             || (ex.getCause() != null && ex.getCause().getCause() instanceof FileNotFoundException)) {
898                         //maybe its not encrypted?
899                         final String tmp = server.getPassword();
900                         if (tmp.startsWith("{") && tmp.endsWith("}")) {
901                             getLog().error(String.format(
902                                     "Unable to decrypt the server password for server id '%s' in settings.xml%n\tCause: %s",
903                                     serverId, ex.getMessage()));
904                         } else {
905                             databasePassword = tmp;
906                         }
907                     } else {
908                         getLog().error(String.format(
909                                 "Unable to decrypt the server password for server id '%s' in settings.xml%n\tCause: %s",
910                                 serverId, ex.getMessage()));
911                     }
912                 }
913             } else {
914                 getLog().error(String.format("Server '%s' not found in the settings.xml file", serverId));
915             }
916         }
917 
918         Settings.setStringIfNotEmpty(Settings.KEYS.DB_USER, databaseUser);
919         Settings.setStringIfNotEmpty(Settings.KEYS.DB_PASSWORD, databasePassword);
920         Settings.setStringIfNotEmpty(Settings.KEYS.DATA_DIRECTORY, dataDirectory);
921 
922         Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_12_URL, cveUrl12Modified);
923         Settings.setStringIfNotEmpty(Settings.KEYS.CVE_MODIFIED_20_URL, cveUrl20Modified);
924         Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_1_2, cveUrl12Base);
925         Settings.setStringIfNotEmpty(Settings.KEYS.CVE_SCHEMA_2_0, cveUrl20Base);
926         Settings.setIntIfNotNull(Settings.KEYS.CVE_CHECK_VALID_FOR_HOURS, cveValidForHours);
927 
928     }
929 
930     /**
931      * Returns the maven proxy.
932      *
933      * @return the maven proxy
934      */
935     private Proxy getMavenProxy() {
936         if (mavenSettings != null) {
937             final List<Proxy> proxies = mavenSettings.getProxies();
938             if (proxies != null && !proxies.isEmpty()) {
939                 if (mavenSettingsProxyId != null) {
940                     for (Proxy proxy : proxies) {
941                         if (mavenSettingsProxyId.equalsIgnoreCase(proxy.getId())) {
942                             return proxy;
943                         }
944                     }
945                 } else if (proxies.size() == 1) {
946                     return proxies.get(0);
947                 } else {
948                     getLog().warn("Multiple proxy definitions exist in the Maven settings. In the dependency-check "
949                             + "configuration set the mavenSettingsProxyId so that the correct proxy will be used.");
950                     throw new IllegalStateException("Ambiguous proxy definition");
951                 }
952             }
953         }
954         return null;
955     }
956 
957     /**
958      * Tests is the artifact should be included in the scan (i.e. is the
959      * dependency in a scope that is being scanned).
960      *
961      * @param scope the scope of the artifact to test
962      * @return <code>true</code> if the artifact is in an excluded scope;
963      * otherwise <code>false</code>
964      */
965     protected boolean excludeFromScan(String scope) {
966         if (skipTestScope && org.apache.maven.artifact.Artifact.SCOPE_TEST.equals(scope)) {
967             return true;
968         }
969         if (skipProvidedScope && org.apache.maven.artifact.Artifact.SCOPE_PROVIDED.equals(scope)) {
970             return true;
971         }
972         if (skipRuntimeScope && !org.apache.maven.artifact.Artifact.SCOPE_RUNTIME.equals(scope)) {
973             return true;
974         }
975         return false;
976     }
977 
978     /**
979      * Returns a reference to the current project. This method is used instead
980      * of auto-binding the project via component annotation in concrete
981      * implementations of this. If the child has a
982      * <code>@Component MavenProject project;</code> defined then the abstract
983      * class (i.e. this class) will not have access to the current project (just
984      * the way Maven works with the binding).
985      *
986      * @return returns a reference to the current project
987      */
988     protected MavenProject getProject() {
989         return project;
990     }
991 
992     /**
993      * Returns the list of Maven Projects in this build.
994      *
995      * @return the list of Maven Projects in this build
996      */
997     protected List<MavenProject> getReactorProjects() {
998         return reactorProjects;
999     }
1000 
1001     /**
1002      * Returns the report format.
1003      *
1004      * @return the report format
1005      */
1006     protected String getFormat() {
1007         return format;
1008     }
1009 
1010     /**
1011      * Generates the reports for a given dependency-check engine.
1012      *
1013      * @param engine a dependency-check engine
1014      * @param p the Maven project
1015      * @param outputDir the directory path to write the report(s)
1016      * @throws ReportException thrown if there is an error writing the report
1017      */
1018     protected void writeReports(MavenEngine engine, MavenProject p, File outputDir) throws ReportException {
1019         DatabaseProperties prop = null;
1020         CveDB cve = null;
1021         try {
1022             cve = new CveDB();
1023             cve.open();
1024             prop = cve.getDatabaseProperties();
1025         } catch (DatabaseException ex) {
1026             if (getLog().isDebugEnabled()) {
1027                 getLog().debug("Unable to retrieve DB Properties", ex);
1028             }
1029         } finally {
1030             if (cve != null) {
1031                 cve.close();
1032             }
1033         }
1034         final ReportGenerator r = new ReportGenerator(p.getName(), engine.getDependencies(), engine.getAnalyzers(), prop);
1035         try {
1036             r.generateReports(outputDir.getAbsolutePath(), format);
1037         } catch (ReportException ex) {
1038             final String msg = String.format("Error generating the report for %s", p.getName());
1039             throw new ReportException(msg, ex);
1040         }
1041 
1042     }
1043 
1044     //<editor-fold defaultstate="collapsed" desc="Methods to fail build or show summary">
1045     /**
1046      * Checks to see if a vulnerability has been identified with a CVSS score
1047      * that is above the threshold set in the configuration.
1048      *
1049      * @param dependencies the list of dependency objects
1050      * @throws MojoFailureException thrown if a CVSS score is found that is
1051      * higher then the threshold set
1052      */
1053     protected void checkForFailure(List<Dependency> dependencies) throws MojoFailureException {
1054         if (failBuildOnCVSS <= 10) {
1055             final StringBuilder ids = new StringBuilder();
1056             for (Dependency d : dependencies) {
1057                 boolean addName = true;
1058                 for (Vulnerability v : d.getVulnerabilities()) {
1059                     if (v.getCvssScore() >= failBuildOnCVSS) {
1060                         if (addName) {
1061                             addName = false;
1062                             ids.append(NEW_LINE).append(d.getFileName()).append(": ");
1063                             ids.append(v.getName());
1064                         } else {
1065                             ids.append(", ").append(v.getName());
1066                         }
1067                     }
1068                 }
1069             }
1070             if (ids.length() > 0) {
1071                 final String msg = String.format("%n%nDependency-Check Failure:%n"
1072                         + "One or more dependencies were identified with vulnerabilities that have a CVSS score greater then '%.1f': %s%n"
1073                         + "See the dependency-check report for more details.%n%n", failBuildOnCVSS, ids.toString());
1074                 throw new MojoFailureException(msg);
1075             }
1076         }
1077     }
1078 
1079     /**
1080      * Generates a warning message listing a summary of dependencies and their
1081      * associated CPE and CVE entries.
1082      *
1083      * @param mp the Maven project for which the summary is shown
1084      * @param dependencies a list of dependency objects
1085      */
1086     protected void showSummary(MavenProject mp, List<Dependency> dependencies) {
1087         if (showSummary) {
1088             final StringBuilder summary = new StringBuilder();
1089             for (Dependency d : dependencies) {
1090                 boolean firstEntry = true;
1091                 final StringBuilder ids = new StringBuilder();
1092                 for (Vulnerability v : d.getVulnerabilities()) {
1093                     if (firstEntry) {
1094                         firstEntry = false;
1095                     } else {
1096                         ids.append(", ");
1097                     }
1098                     ids.append(v.getName());
1099                 }
1100                 if (ids.length() > 0) {
1101                     summary.append(d.getFileName()).append(" (");
1102                     firstEntry = true;
1103                     for (Identifier id : d.getIdentifiers()) {
1104                         if (firstEntry) {
1105                             firstEntry = false;
1106                         } else {
1107                             summary.append(", ");
1108                         }
1109                         summary.append(id.getValue());
1110                     }
1111                     summary.append(") : ").append(ids).append(NEW_LINE);
1112                 }
1113             }
1114             if (summary.length() > 0) {
1115                 final String msg = String.format("%n%n" + "One or more dependencies were identified with known vulnerabilities in %s:%n%n%s"
1116                         + "%n%nSee the dependency-check report for more details.%n%n", mp.getName(), summary.toString());
1117                 getLog().warn(msg);
1118             }
1119         }
1120     }
1121 
1122     //</editor-fold>
1123     //<editor-fold defaultstate="collapsed" desc="Methods to read/write the serialized data file">
1124     /**
1125      * Returns the key used to store the path to the data file that is saved by
1126      * <code>writeDataFile()</code>. This key is used in the
1127      * <code>MavenProject.(set|get)ContextValue</code>.
1128      *
1129      * @return the key used to store the path to the data file
1130      */
1131     protected String getDataFileContextKey() {
1132         return "dependency-check-path-" + dataFileName;
1133     }
1134 
1135     /**
1136      * Returns the key used to store the path to the output directory. When
1137      * generating the report in the <code>executeAggregateReport()</code> the
1138      * output directory should be obtained by using this key.
1139      *
1140      * @return the key used to store the path to the output directory
1141      */
1142     protected String getOutputDirectoryContextKey() {
1143         return "dependency-output-dir-" + dataFileName;
1144     }
1145 
1146     /**
1147      * Writes the scan data to disk. This is used to serialize the scan data
1148      * between the "check" and "aggregate" phase.
1149      *
1150      * @param mp the mMven project for which the data file was created
1151      * @param writeTo the directory to write the data file
1152      * @param dependencies the list of dependencies to serialize
1153      */
1154     protected void writeDataFile(MavenProject mp, File writeTo, List<Dependency> dependencies) {
1155         File file;
1156         //check to see if this was already written out
1157         if (mp.getContextValue(this.getDataFileContextKey()) == null) {
1158             if (writeTo == null) {
1159                 file = new File(mp.getBuild().getDirectory());
1160                 file = new File(file, dataFileName);
1161             } else {
1162                 file = new File(writeTo, dataFileName);
1163             }
1164             final File parent = file.getParentFile();
1165             if (!parent.isDirectory() && !parent.mkdirs()) {
1166                 getLog().error(String.format("Directory '%s' does not exist and cannot be created; unable to write data file.",
1167                         parent.getAbsolutePath()));
1168             }
1169 
1170             ObjectOutputStream out = null;
1171             try {
1172                 if (dependencies != null) {
1173                     out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
1174                     out.writeObject(dependencies);
1175                 }
1176                 if (getLog().isDebugEnabled()) {
1177                     getLog().debug(String.format("Serialized data file written to '%s' for %s, referenced by key %s",
1178                             file.getAbsolutePath(), mp.getName(), this.getDataFileContextKey()));
1179                 }
1180                 mp.setContextValue(this.getDataFileContextKey(), file.getAbsolutePath());
1181             } catch (IOException ex) {
1182                 getLog().warn("Unable to create data file used for report aggregation; "
1183                         + "if report aggregation is being used the results may be incomplete.");
1184                 if (getLog().isDebugEnabled()) {
1185                     getLog().debug(ex.getMessage(), ex);
1186                 }
1187             } finally {
1188                 if (out != null) {
1189                     try {
1190                         out.close();
1191                     } catch (IOException ex) {
1192                         if (getLog().isDebugEnabled()) {
1193                             getLog().debug("ignore", ex);
1194                         }
1195                     }
1196                 }
1197             }
1198         }
1199     }
1200 
1201     /**
1202      * Reads the serialized scan data from disk. This is used to serialize the
1203      * scan data between the "check" and "aggregate" phase.
1204      *
1205      * @param project the Maven project to read the data file from
1206      * @return a <code>MavenEngine</code> object populated with dependencies if
1207      * the serialized data file exists; otherwise <code>null</code> is returned
1208      */
1209     protected List<Dependency> readDataFile(MavenProject project) {
1210         final Object oPath = project.getContextValue(this.getDataFileContextKey());
1211         if (oPath == null) {
1212             return null;
1213         }
1214         List<Dependency> ret = null;
1215         final String path = (String) oPath;
1216         //ObjectInputStream ois = null;
1217         ExpectedOjectInputStream ois = null;
1218         try {
1219             //ois = new ObjectInputStream(new FileInputStream(path));
1220             ois = new ExpectedOjectInputStream(new FileInputStream(path),
1221                     "java.util.ArrayList",
1222                     "java.util.HashSet",
1223                     "java.util.TreeSet",
1224                     "java.lang.AbstractSet",
1225                     "java.lang.AbstractCollection",
1226                     "java.lang.Enum",
1227                     "org.owasp.dependencycheck.dependency.Confidence",
1228                     "org.owasp.dependencycheck.dependency.Dependency",
1229                     "org.owasp.dependencycheck.dependency.Evidence",
1230                     "org.owasp.dependencycheck.dependency.EvidenceCollection",
1231                     "org.owasp.dependencycheck.dependency.Identifier",
1232                     "org.owasp.dependencycheck.dependency.Reference",
1233                     "org.owasp.dependencycheck.dependency.Vulnerability",
1234                     "org.owasp.dependencycheck.dependency.VulnerabilityComparator",
1235                     "org.owasp.dependencycheck.dependency.VulnerableSoftware",
1236                     "org.owasp.dependencycheck.data.cpe.IndexEntry");
1237             @SuppressWarnings("unchecked")
1238             final List<Dependency> depList = (List<Dependency>) ois.readObject();
1239             ret = depList;
1240         } catch (FileNotFoundException ex) {
1241             //TODO fix logging
1242             getLog().error("", ex);
1243         } catch (IOException ex) {
1244             getLog().error("", ex);
1245         } catch (ClassNotFoundException ex) {
1246             getLog().error("", ex);
1247         } finally {
1248             if (ois != null) {
1249                 try {
1250                     ois.close();
1251                 } catch (IOException ex) {
1252                     getLog().error("", ex);
1253                 }
1254             }
1255         }
1256         return ret;
1257     }
1258     //</editor-fold>
1259 
1260 }