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