@Override
  public ServiceName installBundle(
      Deployment dep, ServiceTarget serviceTarget, ServiceListener<XBundle> listener)
      throws BundleException {
    if (dep == null) throw MESSAGES.illegalArgumentNull("deployment");

    ServiceName serviceName;

    // If a bundle containing the same location identifier is already installed,
    // the Bundle object for that bundle is returned.
    XBundle bundle = getBundleByLocation(dep.getLocation());
    if (bundle instanceof AbstractBundleState) {
      LOGGER.debugf("Installing an already existing bundle: %s", dep);
      AbstractBundleState bundleState = AbstractBundleState.assertBundleState(bundle);
      serviceName = bundleState.getServiceName(Bundle.INSTALLED);
      VFSUtils.safeClose(dep.getRoot());
    } else {
      try {
        Long bundleId;
        String symbolicName = dep.getSymbolicName();
        XEnvironment env = injectedEnvironment.getValue();

        // The storage state exists when we re-create the bundle from persistent storage
        StorageState storageState = dep.getAttachment(StorageState.class);
        if (storageState != null) {
          LOGGER.debugf("Found storage state: %s", storageState);
          bundleId = env.nextResourceIdentifier(storageState.getBundleId(), symbolicName);
        } else {
          bundleId = env.nextResourceIdentifier(null, symbolicName);
        }
        dep.addAttachment(Long.class, bundleId);

        // Check that we have valid metadata
        OSGiMetaData metadata = dep.getAttachment(OSGiMetaData.class);
        if (metadata == null) {
          DeploymentFactoryPlugin plugin = getFrameworkState().getDeploymentFactoryPlugin();
          metadata = plugin.createOSGiMetaData(dep);
        }

        // Create the bundle services
        if (metadata.getFragmentHost() == null) {
          serviceName =
              HostBundleInstalledService.addService(
                  serviceTarget, getFrameworkState(), dep, listener);
        } else {
          serviceName =
              FragmentBundleInstalledService.addService(
                  serviceTarget, getFrameworkState(), dep, listener);
        }
      } catch (RuntimeException rte) {
        VFSUtils.safeClose(dep.getRoot());
        throw rte;
      } catch (BundleException ex) {
        VFSUtils.safeClose(dep.getRoot());
        throw ex;
      }
    }
    dep.addAttachment(ServiceName.class, serviceName);
    return serviceName;
  }
  private List<XPackageRequirement> findMatchingPatterns(String resName) {

    List<XPackageRequirement> dynamicRequirements = getDynamicPackageRequirements(hostRev);

    // Dynamic imports may not be used when the package is exported
    String pathName = VFSUtils.getPathFromClassName(resName);
    List<XPackageCapability> packageCapabilities = getPackageCapabilities(hostRev);
    for (XPackageCapability packageCap : packageCapabilities) {
      String packagePath = packageCap.getPackageName().replace('.', '/');
      if (pathName.equals(packagePath)) return Collections.emptyList();
    }

    List<XPackageRequirement> foundMatch = new ArrayList<XPackageRequirement>();
    for (XPackageRequirement dynreq : dynamicRequirements) {

      final String pattern = dynreq.getPackageName();
      if (pattern.equals("*")) {
        foundMatch.add(dynreq);
        continue;
      }

      String patternPath = getPatternPath(pattern);
      if (pathName.startsWith(patternPath)) {
        foundMatch.add(dynreq);
        continue;
      }
    }

    if (foundMatch.isEmpty() == false)
      log.tracef(
          "Found match for path [%s] with Dynamic-ImportPackage pattern: %s", resName, foundMatch);
    else log.tracef("Class [%s] does not match Dynamic-ImportPackage patterns", resName);

    return foundMatch;
  }
  BundleStorageState createStorageState(long bundleId, String location, VirtualFile rootFile)
      throws IOException {
    if (location == null) throw new IllegalArgumentException("Null location");

    // Make the bundle's storage dir
    String bundlePath = getStorageDir(bundleId).getAbsolutePath();
    File bundleDir = new File(bundlePath);
    bundleDir.mkdirs();

    Properties props = BundleStorageState.loadProperties(bundleDir);
    String previousRev = props.getProperty(BundleStorageState.PROPERTY_BUNDLE_REV);
    int revision = (previousRev != null ? Integer.parseInt(previousRev) + 1 : 0);

    if (rootFile != null) {
      File revFile = new File(bundlePath + "/bundle-" + bundleId + "-rev-" + revision + ".jar");
      FileOutputStream output = new FileOutputStream(revFile);
      InputStream input = rootFile.openStream();
      try {
        VFSUtils.copyStream(input, output);
      } finally {
        input.close();
        output.close();
      }
      props.put(BundleStorageState.PROPERTY_BUNDLE_FILE, revFile.getName());
    }

    // Write the bundle properties
    props.put(BundleStorageState.PROPERTY_BUNDLE_LOCATION, location);
    props.put(BundleStorageState.PROPERTY_BUNDLE_ID, new Long(bundleId).toString());
    props.put(BundleStorageState.PROPERTY_BUNDLE_REV, new Integer(revision).toString());
    props.put(
        BundleStorageState.PROPERTY_LAST_MODIFIED, new Long(System.currentTimeMillis()).toString());

    return BundleStorageState.createBundleStorageState(bundleDir, rootFile, props);
  }
  @Test
  public void testBundleStorageForExternalFile() throws Exception {

    BundleStoragePlugin storagePlugin = getFrameworkState().getBundleStoragePlugin();
    assertNotNull("BundleStoragePlugin not null", storagePlugin);

    File file = new File(storagePlugin.getStorageDir(0) + "/testBundleExternalFile.jar");
    FileOutputStream fos = new FileOutputStream(file);
    VFSUtils.copyStream(toInputStream(getArchive()), fos);
    fos.close();

    VirtualFile rootFile = AbstractVFS.toVirtualFile(file.toURI().toURL());
    InternalStorageState storageState =
        storagePlugin.createStorageState(1, file.getAbsolutePath(), 1, rootFile);
    assertStorageState(storageState);

    storagePlugin.deleteStorageState(storageState);
    File storageDir = storageState.getStorageDir();
    assertFalse("Storage dir deleted", storageDir.exists());
  }
 @After
 public void tearDown() throws Exception {
   VFSUtils.safeClose(virtualFileA);
 }
 void close() {
   VFSUtils.safeClose(storageState.getRootFile());
 }