code: private static void populateFeatureNameFromManifest(File esa, Map<String, String> shortNameMap) throws IOException {
          String esaLocation = esa.getCanonicalPath();
          ZipFile zip = null;
          try {
              zip = new ZipFile(esaLocation);
              Enumeration<? extends ZipEntry> zipEntries = zip.entries();
              ZipEntry subsystemEntry = null;
              while (zipEntries.hasMoreElements()) {
                  ZipEntry nextEntry = zipEntries.nextElement();
                  if ("OSGI-INF/SUBSYSTEM.MF".equalsIgnoreCase(nextEntry.getName())) {
                      subsystemEntry = nextEntry;
                      break;
                  }
              }
              if (subsystemEntry != null) {
                  Manifest m = ManifestProcessor.parseManifest(zip.getInputStream(subsystemEntry));
                  Attributes manifestAttrs = m.getMainAttributes();
                  String featureName = manifestAttrs.getValue(SHORTNAME_HEADER_NAME);
                  if (featureName == null) {
                      // Symbolic name field has ";" as delimiter between the actual symbolic name and other tokens such as visibility
                      featureName = manifestAttrs.getValue(SYMBOLICNAME_HEADER_NAME).split(";")[0];
                  }
                  shortNameMap.put(esa.getCanonicalPath(), featureName);
              }
          } finally {
              if (zip != null) {
                  zip.close();
              }
          }
      }
docs: Populate the feature name (short name if available, otherwise symbolic name) from the ESA's manifest into the shortNameMap.
  
  @param esa ESA file
  @param shortNameMap Map to populate with keys being ESA canonical paths and values being feature names (short name or symbolic name)
  @throws IOException If the ESA's canonical path cannot be resolved or the ESA cannot be read