/**
  * Deletes the given ITD, either now or later.
  *
  * @param metadataId the ITD's metadata ID
  * @param itdFilename the ITD's filename
  * @param reason the reason for deletion; ignored if now is <code>false</code>
  * @param now whether to delete the ITD immediately; <code>false</code> schedules it for later
  *     deletion; this is preferable when it's possible that the ITD might need to be re-created in
  *     the meantime (e.g. because some ancestor metadata has changed to that effect), otherwise
  *     there will be spurious console messages about the ITD being deleted and created
  */
 private void deleteItd(
     final String metadataId, final String itdFilename, final String reason, final boolean now) {
   if (now) {
     fileManager.delete(itdFilename, reason);
   } else {
     fileManager.createOrUpdateTextFileIfRequired(itdFilename, "", false);
   }
   itdDiscoveryService.removeItdTypeDetails(metadataId);
   // TODO do we need to notify downstream dependencies that this ITD has gone away?
 }
  public final MetadataItem get(final String metadataIdentificationString) {
    Assert.isTrue(
        MetadataIdentificationUtils.getMetadataClass(metadataIdentificationString)
            .equals(MetadataIdentificationUtils.getMetadataClass(getProvidesType())),
        "Unexpected request for '"
            + metadataIdentificationString
            + "' to this provider (which uses '"
            + getProvidesType()
            + "'");

    // Remove the upstream dependencies for this instance (we'll be recreating them later, if
    // needed)
    metadataDependencyRegistry.deregisterDependencies(metadataIdentificationString);

    // Compute the identifier for the Physical Type Metadata we're correlated with
    String governorPhysicalTypeIdentifier =
        getGovernorPhysicalTypeIdentifier(metadataIdentificationString);

    // Obtain the physical type
    PhysicalTypeMetadata governorPhysicalTypeMetadata =
        (PhysicalTypeMetadata) metadataService.get(governorPhysicalTypeIdentifier);
    if (governorPhysicalTypeMetadata == null || !governorPhysicalTypeMetadata.isValid()) {
      // We can't get even basic information about the physical type, so abort (the ITD will be
      // deleted by ItdFileDeletionService)
      return null;
    }

    // Flag to indicate whether we'll even try to create this metadata
    boolean produceMetadata = false;

    // Determine if we should generate the metadata on the basis of it containing a trigger
    // annotation
    ClassOrInterfaceTypeDetails cid = null;
    if (governorPhysicalTypeMetadata.getMemberHoldingTypeDetails()
        instanceof ClassOrInterfaceTypeDetails) {
      cid =
          (ClassOrInterfaceTypeDetails) governorPhysicalTypeMetadata.getMemberHoldingTypeDetails();
      // Only create metadata if the type is annotated with one of the metadata triggers
      for (JavaType trigger : metadataTriggers) {
        if (cid.getAnnotation(trigger) != null) {
          produceMetadata = true;
          break;
        }
      }
    }

    // Fall back to ignoring trigger annotations
    if (ignoreTriggerAnnotations) {
      produceMetadata = true;
    }

    // Cancel production if the governor type details are required, but aren't available
    if (dependsOnGovernorTypeDetailAvailability && cid == null) {
      produceMetadata = false;
    }

    // Cancel production if the governor is not a class, and the subclass only wants to know about
    // classes
    if (cid != null
        && dependsOnGovernorBeingAClass
        && cid.getPhysicalTypeCategory() != PhysicalTypeCategory.CLASS) {
      produceMetadata = false;
    }

    String itdFilename = governorPhysicalTypeMetadata.getItdCanonicalPath(this);
    if (!produceMetadata && isGovernor(cid) && fileManager.exists(itdFilename)) {
      // We don't seem to want metadata anymore, yet the ITD physically exists, so get rid of it
      // This might be because the trigger annotation has been removed, the governor is missing a
      // class declaration, etc.
      deleteItd(
          metadataIdentificationString,
          itdFilename,
          "not required for governor " + cid.getName(),
          true);
      return null;
    }

    if (produceMetadata) {
      // This type contains an annotation we were configured to detect, or there is an ITD (which
      // may need deletion), so we need to produce the metadata
      JavaType aspectName = governorPhysicalTypeMetadata.getItdJavaType(this);
      ItdTypeDetailsProvidingMetadataItem metadata =
          getMetadata(
              metadataIdentificationString, aspectName, governorPhysicalTypeMetadata, itdFilename);

      // There is no requirement to register a direct connection with the physical type and this
      // metadata because changes will
      // trickle down via the class-level notification registered by convention by
      // AbstractItdMetadataProvider subclasses (BPA 10 Dec 2010)

      if (metadata == null || !metadata.isValid()) {
        // The metadata couldn't be created properly
        deleteItd(metadataIdentificationString, itdFilename, "", false);
        return null;
      }

      // By this point we have a valid MetadataItem, but it might not contain any members for the
      // resulting ITD etc

      // Handle the management of the ITD file
      boolean deleteItdFile = false;
      ItdTypeDetails itdTypeDetails = metadata.getMemberHoldingTypeDetails();

      if (itdTypeDetails == null) {
        // The ITD has no members
        deleteItdFile = true;
      }

      if (!deleteItdFile) {
        // We have some members in the ITD, so decide if we're to write something to disk
        ItdSourceFileComposer itdSourceFileComposer =
            new ItdSourceFileComposer(metadata.getMemberHoldingTypeDetails());

        // Decide whether the get an ITD on-disk based on whether there is physical content to write
        if (itdSourceFileComposer.isContent()) {
          // We have content to write
          itdDiscoveryService.addItdTypeDetails(itdTypeDetails);
          String itd = itdSourceFileComposer.getOutput();
          fileManager.createOrUpdateTextFileIfRequired(itdFilename, itd, false);
        } else {
          // We don't have content to write
          deleteItdFile = true;
        }
      }

      if (deleteItdFile) {
        deleteItd(metadataIdentificationString, itdFilename, null, false);
      }

      // Eagerly notify that the metadata has been updated; this also registers the metadata hash
      // code in the superclass' cache to avoid
      // unnecessary subsequent notifications if it hasn't changed
      notifyIfRequired(metadata);

      return metadata;
    }
    return null;
  }