Coverage Report - org.owasp.dependencycheck.dependency.Dependency
 
Classes in this File Line Coverage Branch Coverage Complexity
Dependency
64%
117/182
47%
17/36
1.393
 
 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) 2012 Jeremy Long. All Rights Reserved.
 17  
  */
 18  
 package org.owasp.dependencycheck.dependency;
 19  
 
 20  
 import java.io.File;
 21  
 import java.io.IOException;
 22  
 import java.io.Serializable;
 23  
 import java.security.NoSuchAlgorithmException;
 24  
 import java.util.ArrayList;
 25  
 import java.util.HashSet;
 26  
 import java.util.List;
 27  
 import java.util.Set;
 28  
 import java.util.SortedSet;
 29  
 import java.util.TreeSet;
 30  
 
 31  
 import org.apache.commons.lang3.builder.EqualsBuilder;
 32  
 import org.apache.commons.lang3.builder.HashCodeBuilder;
 33  
 import org.owasp.dependencycheck.data.nexus.MavenArtifact;
 34  
 import org.owasp.dependencycheck.utils.Checksum;
 35  
 import org.slf4j.Logger;
 36  
 import org.slf4j.LoggerFactory;
 37  
 
 38  
 /**
 39  
  * A program dependency. This object is one of the core components within DependencyCheck. It is used to collect information about
 40  
  * the dependency in the form of evidence. The Evidence is then used to determine if there are any known, published,
 41  
  * vulnerabilities associated with the program dependency.
 42  
  *
 43  
  * @author Jeremy Long
 44  
  */
 45  2
 public class Dependency implements Serializable, Comparable<Dependency> {
 46  
 
 47  
     /**
 48  
      * The serial version UID for serialization.
 49  
      */
 50  
     private static final long serialVersionUID = 1L;
 51  
     /**
 52  
      * The logger.
 53  
      */
 54  1
     private static final Logger LOGGER = LoggerFactory.getLogger(Dependency.class);
 55  
     /**
 56  
      * Used as starting point for generating the value in {@link #hashCode()}.
 57  
      */
 58  
     private static final int MAGIC_HASH_INIT_VALUE = 3;
 59  
     /**
 60  
      * Used as a multiplier for generating the value in {@link #hashCode()}.
 61  
      */
 62  
     private static final int MAGIC_HASH_MULTIPLIER = 47;
 63  
     /**
 64  
      * The actual file path of the dependency on disk.
 65  
      */
 66  
     private String actualFilePath;
 67  
     /**
 68  
      * The file path to display.
 69  
      */
 70  
     private String filePath;
 71  
     /**
 72  
      * The file name of the dependency.
 73  
      */
 74  
     private String fileName;
 75  
     /**
 76  
      * The md5 hash of the dependency.
 77  
      */
 78  
     private String md5sum;
 79  
     /**
 80  
      * The SHA1 hash of the dependency.
 81  
      */
 82  
     private String sha1sum;
 83  
     /**
 84  
      * A list of Identifiers.
 85  
      */
 86  
     private Set<Identifier> identifiers;
 87  
     /**
 88  
      * A collection of vendor evidence.
 89  
      */
 90  
     private final EvidenceCollection vendorEvidence;
 91  
     /**
 92  
      * A collection of product evidence.
 93  
      */
 94  
     private final EvidenceCollection productEvidence;
 95  
     /**
 96  
      * A collection of version evidence.
 97  
      */
 98  
     private final EvidenceCollection versionEvidence;
 99  
 
 100  
     /**
 101  
      * Constructs a new Dependency object.
 102  
      */
 103  88
     public Dependency() {
 104  88
         vendorEvidence = new EvidenceCollection();
 105  88
         productEvidence = new EvidenceCollection();
 106  88
         versionEvidence = new EvidenceCollection();
 107  88
         identifiers = new TreeSet<Identifier>();
 108  88
         vulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
 109  88
         suppressedIdentifiers = new TreeSet<Identifier>();
 110  88
         suppressedVulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
 111  88
     }
 112  
 
 113  
     /**
 114  
      * Constructs a new Dependency object.
 115  
      *
 116  
      * @param file the File to create the dependency object from.
 117  
      */
 118  
     public Dependency(File file) {
 119  67
         this();
 120  67
         this.actualFilePath = file.getAbsolutePath();
 121  67
         this.filePath = this.actualFilePath;
 122  67
         this.fileName = file.getName();
 123  67
         determineHashes(file);
 124  67
     }
 125  
 
 126  
     /**
 127  
      * Returns the file name of the dependency.
 128  
      *
 129  
      * @return the file name of the dependency
 130  
      */
 131  
     public String getFileName() {
 132  36
         return this.fileName;
 133  
     }
 134  
 
 135  
     /**
 136  
      * Returns the file name of the dependency with the backslash escaped for use in JavaScript. This is a complete hack as I
 137  
      * could not get the replace to work in the template itself.
 138  
      *
 139  
      * @return the file name of the dependency with the backslash escaped for use in JavaScript
 140  
      */
 141  
     public String getFileNameForJavaScript() {
 142  0
         return this.fileName.replace("\\", "\\\\");
 143  
     }
 144  
 
 145  
     /**
 146  
      * Sets the file name of the dependency.
 147  
      *
 148  
      * @param fileName the file name of the dependency
 149  
      */
 150  
     public void setFileName(String fileName) {
 151  7
         this.fileName = fileName;
 152  7
     }
 153  
 
 154  
     /**
 155  
      * Sets the actual file path of the dependency on disk.
 156  
      *
 157  
      * @param actualFilePath the file path of the dependency
 158  
      */
 159  
     public void setActualFilePath(String actualFilePath) {
 160  2
         this.actualFilePath = actualFilePath;
 161  2
         if (this.sha1sum == null) {
 162  0
             final File file = new File(this.actualFilePath);
 163  0
             determineHashes(file);
 164  
         }
 165  2
     }
 166  
 
 167  
     /**
 168  
      * Gets the file path of the dependency.
 169  
      *
 170  
      * @return the file path of the dependency
 171  
      */
 172  
     public String getActualFilePath() {
 173  51
         return this.actualFilePath;
 174  
     }
 175  
 
 176  
     /**
 177  
      * Gets a reference to the File object.
 178  
      *
 179  
      * @return the File object
 180  
      */
 181  
     public File getActualFile() {
 182  93
         return new File(this.actualFilePath);
 183  
     }
 184  
 
 185  
     /**
 186  
      * Sets the file path of the dependency.
 187  
      *
 188  
      * @param filePath the file path of the dependency
 189  
      */
 190  
     public void setFilePath(String filePath) {
 191  37
         this.filePath = filePath;
 192  37
     }
 193  
 
 194  
     /**
 195  
      * The file name to display in reports.
 196  
      */
 197  88
     private String displayName = null;
 198  
 
 199  
     /**
 200  
      * Sets the file name to display in reports.
 201  
      *
 202  
      * @param displayName the name to display
 203  
      */
 204  
     public void setDisplayFileName(String displayName) {
 205  47
         this.displayName = displayName;
 206  47
     }
 207  
 
 208  
     /**
 209  
      * Returns the file name to display in reports; if no display file name has been set it will default to the actual file name.
 210  
      *
 211  
      * @return the file name to display
 212  
      */
 213  
     public String getDisplayFileName() {
 214  40
         if (displayName == null) {
 215  30
             return this.fileName;
 216  
         }
 217  10
         return this.displayName;
 218  
     }
 219  
 
 220  
     /**
 221  
      * <p>
 222  
      * Gets the file path of the dependency.</p>
 223  
      * <p>
 224  
      * <b>NOTE:</b> This may not be the actual path of the file on disk. The actual path of the file on disk can be obtained via
 225  
      * the getActualFilePath().</p>
 226  
      *
 227  
      * @return the file path of the dependency
 228  
      */
 229  
     public String getFilePath() {
 230  70
         return this.filePath;
 231  
     }
 232  
 
 233  
     /**
 234  
      * Returns the MD5 Checksum of the dependency file.
 235  
      *
 236  
      * @return the MD5 Checksum
 237  
      */
 238  
     public String getMd5sum() {
 239  2
         return this.md5sum;
 240  
     }
 241  
 
 242  
     /**
 243  
      * Sets the MD5 Checksum of the dependency.
 244  
      *
 245  
      * @param md5sum the MD5 Checksum
 246  
      */
 247  
     public void setMd5sum(String md5sum) {
 248  68
         this.md5sum = md5sum;
 249  68
     }
 250  
 
 251  
     /**
 252  
      * Returns the SHA1 Checksum of the dependency.
 253  
      *
 254  
      * @return the SHA1 Checksum
 255  
      */
 256  
     public String getSha1sum() {
 257  9
         return this.sha1sum;
 258  
     }
 259  
 
 260  
     /**
 261  
      * Sets the SHA1 Checksum of the dependency.
 262  
      *
 263  
      * @param sha1sum the SHA1 Checksum
 264  
      */
 265  
     public void setSha1sum(String sha1sum) {
 266  106
         this.sha1sum = sha1sum;
 267  106
     }
 268  
 
 269  
     /**
 270  
      * Returns a List of Identifiers.
 271  
      *
 272  
      * @return an ArrayList of Identifiers
 273  
      */
 274  
     public Set<Identifier> getIdentifiers() {
 275  194
         return this.identifiers;
 276  
     }
 277  
 
 278  
     /**
 279  
      * Sets a List of Identifiers.
 280  
      *
 281  
      * @param identifiers A list of Identifiers
 282  
      */
 283  
     public void setIdentifiers(Set<Identifier> identifiers) {
 284  1
         this.identifiers = identifiers;
 285  1
     }
 286  
 
 287  
     /**
 288  
      * Adds an entry to the list of detected Identifiers for the dependency file.
 289  
      *
 290  
      * @param type the type of identifier (such as CPE)
 291  
      * @param value the value of the identifier
 292  
      * @param url the URL of the identifier
 293  
      */
 294  
     public void addIdentifier(String type, String value, String url) {
 295  11
         final Identifier i = new Identifier(type, value, url);
 296  11
         this.identifiers.add(i);
 297  11
     }
 298  
 
 299  
     /**
 300  
      * Adds an entry to the list of detected Identifiers for the dependency file.
 301  
      *
 302  
      * @param type the type of identifier (such as CPE)
 303  
      * @param value the value of the identifier
 304  
      * @param url the URL of the identifier
 305  
      * @param confidence the confidence in the Identifier being accurate
 306  
      */
 307  
     public void addIdentifier(String type, String value, String url, Confidence confidence) {
 308  2
         final Identifier i = new Identifier(type, value, url);
 309  2
         i.setConfidence(confidence);
 310  2
         this.identifiers.add(i);
 311  2
     }
 312  
 
 313  
     /**
 314  
      * Adds the maven artifact as evidence.
 315  
      *
 316  
      * @param source The source of the evidence
 317  
      * @param mavenArtifact The maven artifact
 318  
      * @param confidence The confidence level of this evidence
 319  
      */
 320  
     public void addAsEvidence(String source, MavenArtifact mavenArtifact, Confidence confidence) {
 321  2
         if (mavenArtifact.getGroupId() != null && !mavenArtifact.getGroupId().isEmpty()) {
 322  1
             this.getVendorEvidence().addEvidence(source, "groupid", mavenArtifact.getGroupId(), confidence);
 323  
         }
 324  2
         if (mavenArtifact.getArtifactId() != null && !mavenArtifact.getArtifactId().isEmpty()) {
 325  1
             this.getProductEvidence().addEvidence(source, "artifactid", mavenArtifact.getArtifactId(), confidence);
 326  
         }
 327  2
         if (mavenArtifact.getVersion() != null && !mavenArtifact.getVersion().isEmpty()) {
 328  1
             this.getVersionEvidence().addEvidence(source, "version", mavenArtifact.getVersion(), confidence);
 329  
         }
 330  2
         if (mavenArtifact.getArtifactUrl() != null && !mavenArtifact.getArtifactUrl().isEmpty()) {
 331  1
             boolean found = false;
 332  1
             for (Identifier i : this.getIdentifiers()) {
 333  0
                 if ("maven".equals(i.getType()) && i.getValue().equals(mavenArtifact.toString())) {
 334  0
                     found = true;
 335  0
                     i.setConfidence(Confidence.HIGHEST);
 336  0
                     final String url = "http://search.maven.org/#search|ga|1|1%3A%22" + this.getSha1sum() + "%22";
 337  0
                     i.setUrl(url);
 338  
                     //i.setUrl(mavenArtifact.getArtifactUrl());
 339  0
                     LOGGER.debug("Already found identifier {}. Confidence set to highest", i.getValue());
 340  0
                     break;
 341  
                 }
 342  0
             }
 343  1
             if (!found) {
 344  1
                 LOGGER.debug("Adding new maven identifier {}", mavenArtifact);
 345  1
                 this.addIdentifier("maven", mavenArtifact.toString(), mavenArtifact.getArtifactUrl(), Confidence.HIGHEST);
 346  
             }
 347  
         }
 348  2
     }
 349  
 
 350  
     /**
 351  
      * Adds an entry to the list of detected Identifiers for the dependency file.
 352  
      *
 353  
      * @param identifier the identifier to add
 354  
      */
 355  
     public void addIdentifier(Identifier identifier) {
 356  3
         this.identifiers.add(identifier);
 357  3
     }
 358  
 
 359  
     /**
 360  
      * A set of identifiers that have been suppressed.
 361  
      */
 362  
     private Set<Identifier> suppressedIdentifiers;
 363  
 
 364  
     /**
 365  
      * Get the value of suppressedIdentifiers.
 366  
      *
 367  
      * @return the value of suppressedIdentifiers
 368  
      */
 369  
     public Set<Identifier> getSuppressedIdentifiers() {
 370  5
         return suppressedIdentifiers;
 371  
     }
 372  
 
 373  
     /**
 374  
      * Set the value of suppressedIdentifiers.
 375  
      *
 376  
      * @param suppressedIdentifiers new value of suppressedIdentifiers
 377  
      */
 378  
     public void setSuppressedIdentifiers(Set<Identifier> suppressedIdentifiers) {
 379  0
         this.suppressedIdentifiers = suppressedIdentifiers;
 380  0
     }
 381  
 
 382  
     /**
 383  
      * Adds an identifier to the list of suppressed identifiers.
 384  
      *
 385  
      * @param identifier an identifier that was suppressed.
 386  
      */
 387  
     public void addSuppressedIdentifier(Identifier identifier) {
 388  4
         this.suppressedIdentifiers.add(identifier);
 389  4
     }
 390  
 
 391  
     /**
 392  
      * A set of vulnerabilities that have been suppressed.
 393  
      */
 394  
     private SortedSet<Vulnerability> suppressedVulnerabilities;
 395  
 
 396  
     /**
 397  
      * Get the value of suppressedVulnerabilities.
 398  
      *
 399  
      * @return the value of suppressedVulnerabilities
 400  
      */
 401  
     public SortedSet<Vulnerability> getSuppressedVulnerabilities() {
 402  3
         return suppressedVulnerabilities;
 403  
     }
 404  
 
 405  
     /**
 406  
      * Set the value of suppressedVulnerabilities.
 407  
      *
 408  
      * @param suppressedVulnerabilities new value of suppressedVulnerabilities
 409  
      */
 410  
     public void setSuppressedVulnerabilities(SortedSet<Vulnerability> suppressedVulnerabilities) {
 411  0
         this.suppressedVulnerabilities = suppressedVulnerabilities;
 412  0
     }
 413  
 
 414  
     /**
 415  
      * Adds a vulnerability to the set of suppressed vulnerabilities.
 416  
      *
 417  
      * @param vulnerability the vulnerability that was suppressed
 418  
      */
 419  
     public void addSuppressedVulnerability(Vulnerability vulnerability) {
 420  3
         this.suppressedVulnerabilities.add(vulnerability);
 421  3
     }
 422  
 
 423  
     /**
 424  
      * Returns the evidence used to identify this dependency.
 425  
      *
 426  
      * @return an EvidenceCollection.
 427  
      */
 428  
     public EvidenceCollection getEvidence() {
 429  11
         return EvidenceCollection.merge(this.productEvidence, this.vendorEvidence, this.versionEvidence);
 430  
     }
 431  
 
 432  
     /**
 433  
      * Returns the evidence used to identify this dependency.
 434  
      *
 435  
      * @return an EvidenceCollection.
 436  
      */
 437  
     public Set<Evidence> getEvidenceForDisplay() {
 438  0
         return EvidenceCollection.mergeForDisplay(this.productEvidence, this.vendorEvidence, this.versionEvidence);
 439  
     }
 440  
 
 441  
     /**
 442  
      * Returns the evidence used to identify this dependency.
 443  
      *
 444  
      * @return an EvidenceCollection.
 445  
      */
 446  
     public EvidenceCollection getEvidenceUsed() {
 447  1
         return EvidenceCollection.mergeUsed(this.productEvidence, this.vendorEvidence, this.versionEvidence);
 448  
     }
 449  
 
 450  
     /**
 451  
      * Gets the Vendor Evidence.
 452  
      *
 453  
      * @return an EvidenceCollection.
 454  
      */
 455  
     public EvidenceCollection getVendorEvidence() {
 456  135
         return this.vendorEvidence;
 457  
     }
 458  
 
 459  
     /**
 460  
      * Gets the Product Evidence.
 461  
      *
 462  
      * @return an EvidenceCollection.
 463  
      */
 464  
     public EvidenceCollection getProductEvidence() {
 465  223
         return this.productEvidence;
 466  
     }
 467  
 
 468  
     /**
 469  
      * Gets the Version Evidence.
 470  
      *
 471  
      * @return an EvidenceCollection.
 472  
      */
 473  
     public EvidenceCollection getVersionEvidence() {
 474  103
         return this.versionEvidence;
 475  
     }
 476  
 
 477  
     /**
 478  
      * The description of the JAR file.
 479  
      */
 480  
     private String description;
 481  
 
 482  
     /**
 483  
      * Get the value of description.
 484  
      *
 485  
      * @return the value of description
 486  
      */
 487  
     public String getDescription() {
 488  9
         return description;
 489  
     }
 490  
 
 491  
     /**
 492  
      * Set the value of description.
 493  
      *
 494  
      * @param description new value of description
 495  
      */
 496  
     public void setDescription(String description) {
 497  18
         this.description = description;
 498  18
     }
 499  
 
 500  
     /**
 501  
      * The license that this dependency uses.
 502  
      */
 503  
     private String license;
 504  
 
 505  
     /**
 506  
      * Get the value of license.
 507  
      *
 508  
      * @return the value of license
 509  
      */
 510  
     public String getLicense() {
 511  2
         return license;
 512  
     }
 513  
 
 514  
     /**
 515  
      * Set the value of license.
 516  
      *
 517  
      * @param license new value of license
 518  
      */
 519  
     public void setLicense(String license) {
 520  2
         this.license = license;
 521  2
     }
 522  
 
 523  
     /**
 524  
      * A list of vulnerabilities for this dependency.
 525  
      */
 526  
     private SortedSet<Vulnerability> vulnerabilities;
 527  
 
 528  
     /**
 529  
      * Get the list of vulnerabilities.
 530  
      *
 531  
      * @return the list of vulnerabilities
 532  
      */
 533  
     public SortedSet<Vulnerability> getVulnerabilities() {
 534  14
         return vulnerabilities;
 535  
     }
 536  
 
 537  
     /**
 538  
      * Set the value of vulnerabilities.
 539  
      *
 540  
      * @param vulnerabilities new value of vulnerabilities
 541  
      */
 542  
     public void setVulnerabilities(SortedSet<Vulnerability> vulnerabilities) {
 543  0
         this.vulnerabilities = vulnerabilities;
 544  0
     }
 545  
 
 546  
     /**
 547  
      * Determines the sha1 and md5 sum for the given file.
 548  
      *
 549  
      * @param file the file to create checksums for
 550  
      */
 551  
     private void determineHashes(File file) {
 552  67
         String md5 = null;
 553  67
         String sha1 = null;
 554  
         try {
 555  67
             md5 = Checksum.getMD5Checksum(file);
 556  66
             sha1 = Checksum.getSHA1Checksum(file);
 557  1
         } catch (IOException ex) {
 558  1
             LOGGER.warn("Unable to read '{}' to determine hashes.", file.getName());
 559  1
             LOGGER.debug("", ex);
 560  0
         } catch (NoSuchAlgorithmException ex) {
 561  0
             LOGGER.warn("Unable to use MD5 of SHA1 checksums.");
 562  0
             LOGGER.debug("", ex);
 563  67
         }
 564  67
         this.setMd5sum(md5);
 565  67
         this.setSha1sum(sha1);
 566  67
     }
 567  
 
 568  
     /**
 569  
      * Adds a vulnerability to the dependency.
 570  
      *
 571  
      * @param vulnerability a vulnerability outlining a vulnerability.
 572  
      */
 573  
     public void addVulnerability(Vulnerability vulnerability) {
 574  3
         this.vulnerabilities.add(vulnerability);
 575  3
     }
 576  
 
 577  
     /**
 578  
      * A collection of related dependencies.
 579  
      */
 580  88
     private Set<Dependency> relatedDependencies = new TreeSet<Dependency>();
 581  
 
 582  
     /**
 583  
      * Get the value of {@link #relatedDependencies}. This field is used to collect other dependencies which really represent the
 584  
      * same dependency, and may be presented as one item in reports.
 585  
      *
 586  
      * @return the value of relatedDependencies
 587  
      */
 588  
     public Set<Dependency> getRelatedDependencies() {
 589  0
         return relatedDependencies;
 590  
     }
 591  
 
 592  
     /**
 593  
      * A list of projects that reference this dependency.
 594  
      */
 595  88
     private Set<String> projectReferences = new HashSet<String>();
 596  
 
 597  
     /**
 598  
      * Get the value of projectReferences.
 599  
      *
 600  
      * @return the value of projectReferences
 601  
      */
 602  
     public Set<String> getProjectReferences() {
 603  0
         return projectReferences;
 604  
     }
 605  
 
 606  
     /**
 607  
      * Set the value of projectReferences.
 608  
      *
 609  
      * @param projectReferences new value of projectReferences
 610  
      */
 611  
     public void setProjectReferences(Set<String> projectReferences) {
 612  0
         this.projectReferences = projectReferences;
 613  0
     }
 614  
 
 615  
     /**
 616  
      * Adds a project reference.
 617  
      *
 618  
      * @param projectReference a project reference
 619  
      */
 620  
     public void addProjectReference(String projectReference) {
 621  0
         this.projectReferences.add(projectReference);
 622  0
     }
 623  
 
 624  
     /**
 625  
      * Add a collection of project reference.
 626  
      *
 627  
      * @param projectReferences a set of project references
 628  
      */
 629  
     public void addAllProjectReferences(Set<String> projectReferences) {
 630  0
         this.projectReferences.addAll(projectReferences);
 631  0
     }
 632  
 
 633  
     /**
 634  
      * Set the value of relatedDependencies.
 635  
      *
 636  
      * @param relatedDependencies new value of relatedDependencies
 637  
      */
 638  
     public void setRelatedDependencies(Set<Dependency> relatedDependencies) {
 639  0
         this.relatedDependencies = relatedDependencies;
 640  0
     }
 641  
 
 642  
     /**
 643  
      * Adds a related dependency. The internal collection is normally a {@link java.util.TreeSet}, which relies on
 644  
      * {@link #compareTo(Dependency)}. A consequence of this is that if you attempt to add a dependency with the same file path
 645  
      * (modulo character case) as one that is already in the collection, it won't get added.
 646  
      *
 647  
      * @param dependency a reference to the related dependency
 648  
      */
 649  
     public void addRelatedDependency(Dependency dependency) {
 650  0
         if (this == dependency) {
 651  0
             LOGGER.warn("Attempted to add a circular reference - please post the log file to issue #172 here "
 652  
                     + "https://github.com/jeremylong/DependencyCheck/issues/172");
 653  0
             LOGGER.debug("this: {}", this);
 654  0
             LOGGER.debug("dependency: {}", dependency);
 655  0
         } else if (!relatedDependencies.add(dependency)) {
 656  0
             LOGGER.debug("Failed to add dependency, likely due to referencing the same file as another dependency in the set.");
 657  0
             LOGGER.debug("this: {}", this);
 658  0
             LOGGER.debug("dependency: {}", dependency);
 659  
         }
 660  0
     }
 661  
 
 662  
     /**
 663  
      * A list of available versions.
 664  
      */
 665  88
     private List<String> availableVersions = new ArrayList<String>();
 666  
 
 667  
     /**
 668  
      * Get the value of availableVersions.
 669  
      *
 670  
      * @return the value of availableVersions
 671  
      */
 672  
     public List<String> getAvailableVersions() {
 673  0
         return availableVersions;
 674  
     }
 675  
 
 676  
     /**
 677  
      * Set the value of availableVersions.
 678  
      *
 679  
      * @param availableVersions new value of availableVersions
 680  
      */
 681  
     public void setAvailableVersions(List<String> availableVersions) {
 682  0
         this.availableVersions = availableVersions;
 683  0
     }
 684  
 
 685  
     /**
 686  
      * Adds a version to the available version list.
 687  
      *
 688  
      * @param version the version to add to the list
 689  
      */
 690  
     public void addAvailableVersion(String version) {
 691  0
         this.availableVersions.add(version);
 692  0
     }
 693  
 
 694  
     /**
 695  
      * Implementation of the Comparable&lt;Dependency&gt; interface. The comparison is solely based on the file path.
 696  
      *
 697  
      * @param o a dependency to compare
 698  
      * @return an integer representing the natural ordering
 699  
      */
 700  
     @Override
 701  
     public int compareTo(Dependency o) {
 702  2
         return this.getFilePath().compareToIgnoreCase(o.getFilePath());
 703  
     }
 704  
 
 705  
     /**
 706  
      * Implementation of the equals method.
 707  
      *
 708  
      * @param obj the object to compare
 709  
      * @return true if the objects are equal, otherwise false
 710  
      */
 711  
     @Override
 712  
     public boolean equals(Object obj) {
 713  0
         if (obj == null || getClass() != obj.getClass()) {
 714  0
             return false;
 715  
         }
 716  0
         final Dependency other = (Dependency) obj;
 717  0
         return new EqualsBuilder()
 718  0
                 .appendSuper(super.equals(obj))
 719  0
                 .append(this.actualFilePath, other.actualFilePath)
 720  0
                 .append(this.filePath, other.filePath)
 721  0
                 .append(this.fileName, other.fileName)
 722  0
                 .append(this.md5sum, other.md5sum)
 723  0
                 .append(this.sha1sum, other.sha1sum)
 724  0
                 .append(this.identifiers, other.identifiers)
 725  0
                 .append(this.vendorEvidence, other.vendorEvidence)
 726  0
                 .append(this.productEvidence, other.productEvidence)
 727  0
                 .append(this.versionEvidence, other.versionEvidence)
 728  0
                 .append(this.description, other.description)
 729  0
                 .append(this.license, other.license)
 730  0
                 .append(this.vulnerabilities, other.vulnerabilities)
 731  
                 //.append(this.relatedDependencies, other.relatedDependencies)
 732  0
                 .append(this.projectReferences, other.projectReferences)
 733  0
                 .append(this.availableVersions, other.availableVersions)
 734  0
                 .isEquals();
 735  
     }
 736  
 
 737  
     /**
 738  
      * Generates the HashCode.
 739  
      *
 740  
      * @return the HashCode
 741  
      */
 742  
     @Override
 743  
     public int hashCode() {
 744  49
         return new HashCodeBuilder(MAGIC_HASH_INIT_VALUE, MAGIC_HASH_MULTIPLIER)
 745  49
                 .append(actualFilePath)
 746  49
                 .append(filePath)
 747  49
                 .append(fileName)
 748  49
                 .append(md5sum)
 749  49
                 .append(sha1sum)
 750  49
                 .append(identifiers)
 751  49
                 .append(vendorEvidence)
 752  49
                 .append(productEvidence)
 753  49
                 .append(versionEvidence)
 754  49
                 .append(description)
 755  49
                 .append(license)
 756  49
                 .append(vulnerabilities)
 757  
                 //.append(relatedDependencies)
 758  49
                 .append(projectReferences)
 759  49
                 .append(availableVersions)
 760  49
                 .toHashCode();
 761  
     }
 762  
 
 763  
     /**
 764  
      * Standard toString() implementation showing the filename, actualFilePath, and filePath.
 765  
      *
 766  
      * @return the string representation of the file
 767  
      */
 768  
     @Override
 769  
     public String toString() {
 770  30
         return "Dependency{ fileName='" + fileName + "', actualFilePath='" + actualFilePath + "', filePath='" + filePath + "'}";
 771  
     }
 772  
 }