/**
   * Loads the versioning information for the given project-information structure using the project
   * information's internal name as lookup key.
   *
   * @param projectInformation the project we load information for.
   */
  public VersionHelper(final ProjectInformation projectInformation) {
    if (projectInformation == null) {
      throw new NullPointerException();
    }

    this.projectInformation = projectInformation;

    Manifest manifest = manifestCache.get(projectInformation.getInternalName());
    if (manifest == null) {
      final ClassLoader loader = projectInformation.getClass().getClassLoader();
      try {
        final Enumeration resources = loader.getResources("META-INF/MANIFEST.MF");
        while (resources.hasMoreElements()) {
          final URL url = (URL) resources.nextElement();
          final String urlAsText = url.toURI().toString();
          Manifest maybeManifest = manifestCache.getByURL(urlAsText);
          if (maybeManifest == null) {
            final InputStream inputStream = url.openStream();
            try {
              maybeManifest = new Manifest(new BufferedInputStream(inputStream));
            } finally {
              inputStream.close();
            }
          }

          final Attributes attr =
              getAttributes(maybeManifest, projectInformation.getInternalName());
          final String maybeTitle = getValue(attr, "Implementation-ProductID", null);
          if (maybeTitle != null) {
            manifestCache.set(maybeTitle, urlAsText, maybeManifest);
            if (maybeTitle.equals(projectInformation.getInternalName())) {
              manifest = maybeManifest;
              break;
            }
          } else {
            manifestCache.set(maybeTitle, urlAsText, maybeManifest);
          }
        }

      } catch (Exception e) {
        // Ignore; Maybe log.
        e.printStackTrace();
      }
    }
    if (manifest != null) {
      init(manifest);
    } else {
      DebugLog.log(
          "Failed to create version information for " + projectInformation.getInternalName());
      version = "TRUNK.development";
      title = projectInformation.getInternalName();
      productId = projectInformation.getInternalName();
      releaseMajor = "0";
      releaseMinor = "0";
      releaseMilestone = "0";
      releaseCandidateToken = "snapshot";
      releaseBuildNumber = "0";
      releaseNumber = createReleaseVersion();
    }
  }
  /**
   * Initializes the instance, reaading the properties from the input stream.
   *
   * @param props the manifest.
   * @return true, if the manifest contains version information about this library, false otherwise.
   */
  private boolean init(final Manifest props) {
    try {
      final Attributes attr = getAttributes(props, projectInformation.getInternalName());
      final String maybeTitle = getValue(attr, "Implementation-ProductID", null);
      if (ObjectUtilities.equal(projectInformation.getInternalName(), maybeTitle) == false) {
        return false;
      }

      title = getValue(attr, "Implementation-Title", maybeTitle);
      version = getValue(attr, "Implementation-Version", "");
      if (version.length() == 0) {
        version = "TRUNK.development";
      }

      releaseMajor = "0";
      releaseMinor = "0";
      releaseMilestone = "0";
      releaseCandidateToken = "snapshot";
      releaseBuildNumber = "0";
      if (version.startsWith("TRUNK") == false) {
        // format is something like 3.8.0[.x]-GA.12345
        final int dashPos = version.indexOf('-');
        final String versionNumber;
        final String implIndicator;
        if (dashPos != -1) {
          versionNumber = version.substring(0, dashPos);
          implIndicator = version.substring(dashPos + 1);
        } else {
          versionNumber = version;
          implIndicator = "";
        }
        if (StringUtils.isEmpty(versionNumber) == false) {
          final StringTokenizer tokNum = new StringTokenizer(versionNumber, ".");
          if (tokNum.hasMoreTokens()) {
            releaseMajor = tokNum.nextToken();
          }
          if (tokNum.hasMoreTokens()) {
            releaseMinor = tokNum.nextToken();
          }
          if (tokNum.hasMoreTokens()) {
            releaseMilestone = tokNum.nextToken();
          }
          final StringTokenizer tokImpl = new StringTokenizer(implIndicator, ".");
          if (tokImpl.hasMoreTokens()) {
            releaseCandidateToken = tokImpl.nextToken();
          }
          if (tokImpl.hasMoreTokens()) {
            releaseBuildNumber = tokImpl.nextToken();
          }
        }
      }
      releaseNumber = createReleaseVersion();

      productId = maybeTitle;
      if (productId.length() == 0) {
        productId = createProductId();
      }

      return true;
    } catch (final Exception e) {
      return false;
    }
  }