private void performPlaceHolderSubstitution(
      ManifestInfo manifestInfo,
      XmlDocument xmlDocument,
      MergingReport.Builder mergingReportBuilder) {

    // check for placeholders presence, switch first the packageName and application id if
    // it is not explicitly set.
    Map<String, Object> finalPlaceHolderValues = mPlaceHolderValues;
    if (!mPlaceHolderValues.containsKey("applicationId")) {
      String packageName =
          manifestInfo.getMainManifestPackageName().isPresent()
              ? manifestInfo.getMainManifestPackageName().get()
              : xmlDocument.getPackageName();
      // add all existing placeholders except package name that will be swapped.
      ImmutableMap.Builder<String, Object> builder = ImmutableMap.<String, Object>builder();
      for (Map.Entry<String, Object> entry : mPlaceHolderValues.entrySet()) {
        if (!entry.getKey().equals(PlaceholderHandler.PACKAGE_NAME)) {
          builder.put(entry);
        }
      }
      finalPlaceHolderValues =
          builder
              .put(PlaceholderHandler.PACKAGE_NAME, packageName)
              .put(PlaceholderHandler.APPLICATION_ID, packageName)
              .build();
    }

    KeyBasedValueResolver<String> placeHolderValueResolver =
        new MapBasedKeyBasedValueResolver<String>(finalPlaceHolderValues);
    PlaceholderHandler placeholderHandler = new PlaceholderHandler();
    placeholderHandler.visit(
        mMergeType, xmlDocument, placeHolderValueResolver, mergingReportBuilder);
  }
  /**
   * Load an xml file and perform placeholder substitution
   *
   * @param manifestInfo the android manifest information like if it is a library, an overlay or a
   *     main manifest file.
   * @param selectors all the libraries selectors
   * @param mergingReportBuilder the merging report to store events and errors.
   * @return a loaded manifest info.
   * @throws MergeFailureException
   */
  private LoadedManifestInfo load(
      ManifestInfo manifestInfo,
      KeyResolver<String> selectors,
      MergingReport.Builder mergingReportBuilder)
      throws MergeFailureException {

    XmlDocument xmlDocument;
    try {
      xmlDocument =
          XmlLoader.load(
              selectors,
              mSystemPropertyResolver,
              manifestInfo.mName,
              manifestInfo.mLocation,
              manifestInfo.getType(),
              manifestInfo.getMainManifestPackageName());
    } catch (Exception e) {
      throw new MergeFailureException(e);
    }

    String originalPackageName = xmlDocument.getPackageName();
    MergingReport.Builder builder =
        manifestInfo.getType() == XmlDocument.Type.MAIN
            ? mergingReportBuilder
            : new MergingReport.Builder(mergingReportBuilder.getLogger());

    builder.getActionRecorder().recordDefaultNodeAction(xmlDocument.getRootNode());

    // perform place holder substitution, this is necessary to do so early in case placeholders
    // are used in key attributes.
    performPlaceHolderSubstitution(manifestInfo, xmlDocument, builder);

    return new LoadedManifestInfo(
        manifestInfo, Optional.fromNullable(originalPackageName), xmlDocument);
  }
 private LoadedManifestInfo(
     @NonNull ManifestInfo manifestInfo,
     @NonNull Optional<String> originalPackageName,
     @NonNull XmlDocument xmlDocument) {
   super(
       manifestInfo.mName,
       manifestInfo.mLocation,
       manifestInfo.mType,
       manifestInfo.getMainManifestPackageName());
   mXmlDocument = xmlDocument;
   mOriginalPackageName = originalPackageName;
 }