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  94
     public Dependency() {
 129  94
         vendorEvidence = new EvidenceCollection();
 130  94
         productEvidence = new EvidenceCollection();
 131  94
         versionEvidence = new EvidenceCollection();
 132  94
         identifiers = new TreeSet<Identifier>();
 133  94
         vulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
 134  94
         suppressedIdentifiers = new TreeSet<Identifier>();
 135  94
         suppressedVulnerabilities = new TreeSet<Vulnerability>(new VulnerabilityComparator());
 136  94
     }
 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  73
         this();
 145  73
         this.actualFilePath = file.getAbsolutePath();
 146  73
         this.filePath = this.actualFilePath;
 147  73
         this.fileName = file.getName();
 148  73
         this.packagePath = filePath;
 149  73
         determineHashes(file);
 150  73
     }
 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  76
         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  73
         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  142
         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  94
     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  74
         this.md5sum = md5sum;
 282  74
     }
 283  
 
 284  
     /**
 285  
      * Returns the SHA1 Checksum of the dependency.
 286  
      *
 287  
      * @return the SHA1 Checksum
 288  
      */
 289  
     public String getSha1sum() {
 290  24
         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  112
         this.sha1sum = sha1sum;
 300  112
     }
 301  
 
 302  
     /**
 303  
      * Returns a List of Identifiers.
 304  
      *
 305  
      * @return an ArrayList of Identifiers
 306  
      */
 307  
     public Set<Identifier> getIdentifiers() {
 308  491
         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  4
         this.identifiers.add(identifier);
 393  4
     }
 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  213
         return this.productEvidence;
 502  
     }
 503  
 
 504  
     /**
 505  
      * Gets the Version Evidence.
 506  
      *
 507  
      * @return an EvidenceCollection.
 508  
      */
 509  
     public EvidenceCollection getVersionEvidence() {
 510  114
         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  15
         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  73
         String md5 = null;
 589  73
         String sha1 = null;
 590  
         try {
 591  73
             md5 = Checksum.getMD5Checksum(file);
 592  73
             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  73
         }
 600  73
         this.setMd5sum(md5);
 601  73
         this.setSha1sum(sha1);
 602  73
     }
 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  94
     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  94
     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  94
     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  12
         return new HashCodeBuilder(MAGIC_HASH_INIT_VALUE, MAGIC_HASH_MULTIPLIER)
 786  6
                 .append(actualFilePath)
 787  6
                 .append(filePath)
 788  6
                 .append(fileName)
 789  6
                 .append(md5sum)
 790  6
                 .append(sha1sum)
 791  6
                 .append(identifiers)
 792  6
                 .append(vendorEvidence)
 793  6
                 .append(productEvidence)
 794  6
                 .append(versionEvidence)
 795  6
                 .append(description)
 796  6
                 .append(license)
 797  6
                 .append(vulnerabilities)
 798  
                 //.append(relatedDependencies)
 799  6
                 .append(projectReferences)
 800  6
                 .append(availableVersions)
 801  6
                 .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  
 }