This is an automated email from the ASF dual-hosted git repository.

kwin pushed a commit to branch feature/SLING-8291_expose-error
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-provider-installhook.git

commit 9a95ab7d4f7325e64f792c5cea4bf6445d4f0c43
Author: georg.henzler <[email protected]>
AuthorDate: Thu Oct 4 23:59:10 2018 +0200

    SLING-7790 use of InfoProvider, additional package properties for
    configuration
---
 .../provider/installhook/OsgiInstallerHook.java    | 784 ++++++++++++---------
 .../installhook/OsgiInstallerListener.java         |  91 +--
 .../installhook/OsgiInstallerHookTest.java         | 159 +++--
 .../installhook/OsgiInstallerListenerTest.java     |  87 ++-
 4 files changed, 625 insertions(+), 496 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/installer/provider/installhook/OsgiInstallerHook.java
 
b/src/main/java/org/apache/sling/installer/provider/installhook/OsgiInstallerHook.java
index a8d910b..fd27716 100644
--- 
a/src/main/java/org/apache/sling/installer/provider/installhook/OsgiInstallerHook.java
+++ 
b/src/main/java/org/apache/sling/installer/provider/installhook/OsgiInstallerHook.java
@@ -50,357 +50,467 @@ import org.apache.jackrabbit.vault.packaging.VaultPackage;
 import org.apache.sling.installer.api.InstallableResource;
 import org.apache.sling.installer.api.OsgiInstaller;
 import org.apache.sling.installer.api.event.InstallationListener;
+import org.apache.sling.installer.api.info.InfoProvider;
+import org.apache.sling.installer.api.info.InstallationState;
+import org.apache.sling.installer.api.info.Resource;
+import org.apache.sling.installer.api.info.ResourceGroup;
+import org.apache.sling.installer.api.tasks.ResourceState;
 import org.apache.sling.settings.SlingSettingsService;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
-import org.osgi.service.cm.Configuration;
-import org.osgi.service.cm.ConfigurationAdmin;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class OsgiInstallerHook implements InstallHook {
 
-       private static final Logger LOG = 
LoggerFactory.getLogger(OsgiInstallerHook.class);
+    private static final Logger LOG = 
LoggerFactory.getLogger(OsgiInstallerHook.class);
 
-       private static final String PACKAGE_PROPERTY_MAX_WAIT_IN_SEC = 
"maxWaitForOsgiInstallerInSec";
-       private static final String PACKAGE_PROP_INSTALL_PATH_REGEX = 
"installPathRegex";
+    private static final String PACKAGE_PROP_INSTALL_PATH_REGEX = 
"installPathRegex";
+    private static final String PACKAGE_PROPERTY_MAX_WAIT_IN_SEC = 
"maxWaitForOsgiInstallerInSec";
+    private static final String PACKAGE_PROPERTY_INSTALL_PRIORITY = 
"osgiInstallerPriority";
+    private static final String 
PACKAGE_PROPERTY_WAIT_FOR_OSGI_EVENTS_QUIET_IN_SEC = 
"waitForOsgiEventsQuietInSec";
 
-       public static final int DEFAULT_PRIORITY_INSTALL_HOOK = 2000;
-       private static final int DEFAULT_MAX_WAIT_IN_SEC = 60;
+    public static final int DEFAULT_PRIORITY_INSTALL_HOOK = 2000;
+    private static final int DEFAULT_MAX_WAIT_IN_SEC = 60;
+    private static final int DEFAULT_WAIT_FOR_OSGI_EVENTS_QUIET_IN_SEC = 1;
 
-       public static final String URL_SCHEME = "jcrinstall";
-       public static final String CONFIG_SUFFIX = ".config";
-       public static final String JAR_SUFFIX = ".jar";
+    public static final String URL_SCHEME = "jcrinstall";
+    public static final String CONFIG_SUFFIX = ".config";
+    public static final String JAR_SUFFIX = ".jar";
+
+    private static final String ENTITY_ID_PREFIX_BUNDLE = "bundle:";
+
+    private static final String MANIFEST_BUNDLE_SYMBOLIC_NAME = 
"Bundle-SymbolicName";
+    private static final String MANIFEST_BUNDLE_VERSION = "Bundle-Version";
+    private static final String FOLDER_META_INF = "META-INF";
+
+    static final String JCR_CONTENT = "jcr:content";
+    static final String JCR_CONTENT_DATA = JCR_CONTENT + "/jcr:data";
+    static final String JCR_LAST_MODIFIED = "jcr:lastModified";
+    static final String JCR_CONTENT_LAST_MODIFIED = JCR_CONTENT + "/" + 
JCR_LAST_MODIFIED;
+
+    public static final String DOT = ".";
+
+    InstallHookLogger logger = new InstallHookLogger();
+
+    @Override
+    public void execute(InstallContext context) throws PackageException {
+
+        VaultPackage vaultPackage = context.getPackage();
+        PackageProperties packageProperties = vaultPackage.getProperties();
+        String installPathRegex = 
packageProperties.getProperty(PACKAGE_PROP_INSTALL_PATH_REGEX);
+
+        ServiceReference<OsgiInstaller> osgiInstallerServiceRef = null;
+        ServiceReference<SlingSettingsService> slingSettingsServiceRef = null;
+        ServiceRegistration<InstallationListener> 
hookInstallationListenerServiceRegistration = null;
+
+        ServiceReference<InfoProvider> infoProviderServiceRef = null;
+
+        try {
+            switch (context.getPhase()) {
+            case PREPARE:
+                if (StringUtils.isBlank(installPathRegex)) {
+                    throw new IllegalArgumentException(
+                            "When using OSGi installer install hook for 
synchronous installation, the package property "
+                                    + PACKAGE_PROP_INSTALL_PATH_REGEX + " has 
to be provided.");
+                }
+                break;
+            case INSTALLED:
+                ImportOptions options = context.getOptions();
+                logger.setOptions(options);
+
+                logger.log(getClass().getSimpleName() + " is active in " + 
vaultPackage.getId());
+
+                List<BundleInPackage> bundleResources = new ArrayList<>();
+                List<String> configResourcePaths = new ArrayList<>();
+                Archive archive = vaultPackage.getArchive();
+
+                infoProviderServiceRef = 
getBundleContext().getServiceReference(InfoProvider.class);
+                InfoProvider infoProvider = (InfoProvider) 
getBundleContext().getService(infoProviderServiceRef);
+                InstallationState installationState = 
infoProvider.getInstallationState();
+
+                slingSettingsServiceRef = 
getBundleContext().getServiceReference(SlingSettingsService.class);
+                SlingSettingsService slingSettingsService = 
(SlingSettingsService) getBundleContext().getService(slingSettingsServiceRef);
+                Set<String> runModes = slingSettingsService.getRunModes();
+
+                collectResources(archive, archive.getRoot(), "", 
bundleResources, configResourcePaths, installPathRegex,
+                        runModes);
+
+                logger.log("Bundles in package " + bundleResources);
+
+                Session session = context.getSession();
+
+                Map<String, InstallableResource> bundlesToInstallByUrl = 
getBundlesToInstall(bundleResources, session, installationState,
+                        packageProperties);
+                Map<String, InstallableResource> configsToInstallByUrl = 
getConfigsToInstall(configResourcePaths, session,
+                        installationState, packageProperties);
+
+                if (bundlesToInstallByUrl.isEmpty() && 
configsToInstallByUrl.isEmpty()) {
+                    logger.log("No installable resources that are not 
installed yet found.");
+                    return;
+                }
+
+                logger.log("Installing " + bundlesToInstallByUrl.size() + " 
bundles and "
+                        + configsToInstallByUrl.size() + " configs");
+                osgiInstallerServiceRef = 
getBundleContext().getServiceReference(OsgiInstaller.class);
+                OsgiInstaller osgiInstaller = 
getBundleContext().getService(osgiInstallerServiceRef);
+
+                OsgiInstallerListener hookInstallationListener = new 
OsgiInstallerListener(bundlesToInstallByUrl.keySet(),
+                        configsToInstallByUrl.keySet());
+                hookInstallationListenerServiceRegistration = 
getBundleContext()
+                        .registerService(InstallationListener.class, 
hookInstallationListener, null);
+
+                List<InstallableResource> resourcesToUpdate = new 
ArrayList<>();
+                resourcesToUpdate.addAll(bundlesToInstallByUrl.values());
+                resourcesToUpdate.addAll(configsToInstallByUrl.values());
+                logger.log("Updating resources " + resourcesToUpdate);
+                osgiInstaller.updateResources(URL_SCHEME, 
resourcesToUpdate.toArray(new InstallableResource[resourcesToUpdate.size()]),
+                        null);
+
+                int maxWaitForOsgiInstallerInSec = 
getNumericPackageProperty(packageProperties, PACKAGE_PROPERTY_MAX_WAIT_IN_SEC,
+                        DEFAULT_MAX_WAIT_IN_SEC);
+
+                long startTime = System.currentTimeMillis();
+                int bundlesLeftToInstall = 0;
+                int configsLeftToInstall = 0;
+                while ((bundlesLeftToInstall = 
hookInstallationListener.bundlesLeftToInstall()) > 0
+                        || (configsLeftToInstall = 
hookInstallationListener.configsLeftToInstall()) > 0) {
+                    if ((System.currentTimeMillis() - startTime) > 
maxWaitForOsgiInstallerInSec * 1000) {
+                        logger.log("Installable resources " + resourcesToUpdate
+                                + " could not be installed even after waiting 
" + maxWaitForOsgiInstallerInSec + "sec");
+                        break;
+                    }
+                    logger.log("Waiting for " + bundlesLeftToInstall + " 
bundles / " + configsLeftToInstall + " configs to be installed");
+                    Thread.sleep(1000);
+                }
+                if (bundlesLeftToInstall == 0 && configsLeftToInstall == 0) {
+                    logger.log("All " + bundlesToInstallByUrl.size() + " 
bundles / " + configsToInstallByUrl.size()
+                            + " configs have been successfully installed");
+                }
+
+                int waitForOsgiEventsQuietInSec = 
getNumericPackageProperty(packageProperties,
+                        PACKAGE_PROPERTY_WAIT_FOR_OSGI_EVENTS_QUIET_IN_SEC, 
DEFAULT_WAIT_FOR_OSGI_EVENTS_QUIET_IN_SEC);
+                waitForServiceChanges(waitForOsgiEventsQuietInSec);
+
+                break;
+            default:
+                break;
+            }
+        } catch (Exception e) {
+            throw new PackageException("Could not execute install hook to for 
synchronous installation: " + e, e);
+        } finally {
+            if (osgiInstallerServiceRef != null) {
+                getBundleContext().ungetService(osgiInstallerServiceRef);
+            }
+            if (slingSettingsServiceRef != null) {
+                getBundleContext().ungetService(slingSettingsServiceRef);
+            }
+            if (infoProviderServiceRef != null) {
+                getBundleContext().ungetService(infoProviderServiceRef);
+            }
+
+            if (hookInstallationListenerServiceRegistration != null) {
+                hookInstallationListenerServiceRegistration.unregister();
+            }
+        }
+    }
+
+    private int getNumericPackageProperty(PackageProperties packageProperties, 
String propertyName, int defaultVal) {
+        String strVal = packageProperties.getProperty(propertyName);
+        int intVal = strVal != null ? Integer.parseInt(strVal) : defaultVal;
+        return intVal;
+    }
+
+    private Map<String, InstallableResource> 
getBundlesToInstall(List<BundleInPackage> bundlesInPackage, Session session,
+            InstallationState installationState, PackageProperties 
packageProperties) throws RepositoryException, IOException {
+        Map<String, InstallableResource> installableResources = new 
HashMap<>();
+        Iterator<BundleInPackage> bundlesIt = bundlesInPackage.iterator();
+        while (bundlesIt.hasNext()) {
+            BundleInPackage bundle = bundlesIt.next();
+
+            List<Resource> currentInstallerBundleResources = 
getBundleResources(installationState, bundle.symbolicName);
+
+            boolean needsInstallation = false;
+            if (currentInstallerBundleResources.isEmpty()) {
+                needsInstallation = true;
+            } else if (currentInstallerBundleResources.size() == 1) {
+                Resource resource = currentInstallerBundleResources.get(0);
+
+                if (resource.getState() == ResourceState.INSTALLED) {
+                    String currentlyActiveBundleVersion = 
resource.getVersion().toString();
+                    if (!StringUtils.equals(currentlyActiveBundleVersion, 
bundle.version)) {
+                        logger.log("Bundle " + bundle.symbolicName + " is 
installed with version "
+                                + currentlyActiveBundleVersion + " but package 
contains version " + bundle.version);
+                        needsInstallation = true;
+                    } else {
+                        logger.log("Bundle " + bundle.symbolicName + " is 
already installed with version "
+                                + currentlyActiveBundleVersion + " that 
matches " + bundle.version + " as provided in package");
+                    }
+                } else {
+                    logger.log("Bundle " + bundle.symbolicName + " is not in 
state INSTALLED but in " + resource.getState());
+                    needsInstallation = true;
+                }
+
+            } else {
+                logger.log("Bundle " + bundle.symbolicName + " exists with 
multiple installer resources");
+                boolean installedBundleResourceFound = false;
+                for (Resource resource : currentInstallerBundleResources) {
+                    logger.log("Resource " + resource);
+                    if (resource.getState() == ResourceState.INSTALLED
+                            && 
StringUtils.equals(resource.getVersion().toString(), bundle.version)) {
+                        installedBundleResourceFound = true;
+                    }
+                }
+                if (!installedBundleResourceFound) {
+                    needsInstallation = true;
+                }
+
+            }
+
+            if (needsInstallation) {
+                logger.log("Bundle " + bundle.symbolicName + " requires 
installation");
+                Node node = session.getNode(bundle.path);
+                InstallableResource installableResource = convert(node, 
bundle.path, packageProperties);
+                String bundleUrl = URL_SCHEME + ":" + bundle.path;
+                installableResources.put(bundleUrl, installableResource);
+            }
+        }
+        return installableResources;
+    }
+
+    private List<Resource> getBundleResources(InstallationState 
installationState, String symbolicId) {
+
+        List<Resource> bundleResources = new ArrayList<Resource>();
+
+        List<ResourceGroup> allGroups = new ArrayList<ResourceGroup>();
+        allGroups.addAll(installationState.getInstalledResources());
+        allGroups.addAll(installationState.getActiveResources());
+        for (ResourceGroup resourceGroup : allGroups) {
+            List<Resource> resources = resourceGroup.getResources();
+            for (Resource resource : resources) {
+                if (StringUtils.equals(resource.getEntityId(), 
ENTITY_ID_PREFIX_BUNDLE + symbolicId)) {
+                    bundleResources.add(resource);
+                }
+            }
+        }
+        return bundleResources;
+    }
+
+    private Map<String, InstallableResource> getConfigsToInstall(List<String> 
configResourcePaths, Session session,
+            InstallationState installationState, PackageProperties 
packageProperties)
+            throws IOException, InvalidSyntaxException, RepositoryException {
+        Map<String, InstallableResource> configsToInstallByUrl = new 
HashMap<>();
+        for (String configResourcePath : configResourcePaths) {
+            boolean needsInstallation = false;
+
+            String configUrl = URL_SCHEME + ":" + configResourcePath;
+            boolean configFound = false;
+            List<ResourceGroup> installedResources = 
installationState.getInstalledResources();
+            for (ResourceGroup resourceGroup : installedResources) {
+                for (Resource resource : resourceGroup.getResources()) {
+                    if (StringUtils.equals(configUrl, resource.getURL())) {
+                        configFound = true;
+                        logger.log("Config " + configResourcePath + " is 
already installed");
+                    }
+                }
+            }
+            if (!configFound) {
+                logger.log("Config " + configResourcePath + " has not been 
installed");
+                needsInstallation = true;
+            }
+
+            if (needsInstallation) {
+
+                Node node = session.getNode(configResourcePath);
+                InstallableResource installableResource = convert(node, 
configResourcePath, packageProperties);
+
+                configsToInstallByUrl.put(configUrl, installableResource);
+            }
+        }
+        return configsToInstallByUrl;
+    }
+
+    void collectResources(Archive archive, Entry entry, String dirPath, 
List<BundleInPackage> bundleResources,
+            List<String> configResources, String installPathRegex, Set<String> 
actualRunmodes) {
+        String entryName = entry.getName();
+        if (entryName.equals(FOLDER_META_INF)) {
+            return;
+        }
+
+        String dirPathWithoutJcrRoot = StringUtils.substringAfter(dirPath, 
"/jcr_root");
+        String entryPath = dirPathWithoutJcrRoot + entryName;
+        String dirPathWithoutSlash = StringUtils.chomp(dirPathWithoutJcrRoot, 
"/");
+
+        boolean runmodesMatch;
+        if (dirPathWithoutSlash.contains(DOT)) {
+            String[] bits = dirPathWithoutSlash.split("\\" + DOT, 2);
+            List<String> runmodesOfResource = Arrays.asList(bits[1].split("\\" 
+ DOT));
+            Set<String> matchingRunmodes = new 
HashSet<String>(runmodesOfResource);
+            matchingRunmodes.retainAll(actualRunmodes);
+            LOG.debug("Entry with runmode(s): entryPath={} 
runmodesOfResource={} actualRunmodes={} matchingRunmodes={}",
+                    entryPath, runmodesOfResource, actualRunmodes, 
matchingRunmodes);
+            runmodesMatch = matchingRunmodes.size() == 
runmodesOfResource.size();
+            if (!runmodesMatch) {
+                logger.log("Skipping installation of  " + entryPath
+                        + " because the path is not matching all actual 
runmodes " + actualRunmodes);
+            }
+        } else {
+            runmodesMatch = true;
+        }
+
+        if (entryPath.matches(installPathRegex) && runmodesMatch) {
+
+            if (entryName.endsWith(CONFIG_SUFFIX)) {
+                configResources.add(entryPath);
+            } else if (entryName.endsWith(JAR_SUFFIX)) {
+                try (InputStream entryInputStream = 
archive.getInputSource(entry).getByteStream();
+                        JarInputStream jarInputStream = new 
JarInputStream(entryInputStream)) {
+                    Manifest manifest = jarInputStream.getManifest();
+                    String symbolicName = 
manifest.getMainAttributes().getValue(MANIFEST_BUNDLE_SYMBOLIC_NAME);
+                    String version = 
manifest.getMainAttributes().getValue(MANIFEST_BUNDLE_VERSION);
+
+                    bundleResources.add(new BundleInPackage(entryPath, 
symbolicName, version));
+                } catch (Exception e) {
+                    throw new IllegalStateException(
+                            "Could not read symbolic name and version from 
manifest of bundle " + entryName);
+                }
+            }
+
+        }
+
+        for (Entry child : entry.getChildren()) {
+            collectResources(archive, child, dirPath + entryName + "/", 
bundleResources, configResources,
+                    installPathRegex, actualRunmodes);
+        }
+    }
+
+    InstallableResource convert(final Node node, final String path, 
PackageProperties packageProperties)
+            throws IOException, RepositoryException {
+        LOG.trace("Converting {} at path {}", node, path);
+        final String digest = 
String.valueOf(node.getProperty(JCR_CONTENT_LAST_MODIFIED).getDate().getTimeInMillis());
+        final InputStream is = node.getProperty(JCR_CONTENT_DATA).getStream();
+        final Dictionary<String, Object> dict = new Hashtable<String, 
Object>();
+        dict.put(InstallableResource.INSTALLATION_HINT, 
node.getParent().getName());
+        int priority = getNumericPackageProperty(packageProperties, 
PACKAGE_PROPERTY_INSTALL_PRIORITY, DEFAULT_PRIORITY_INSTALL_HOOK);
+        return new InstallableResource(path, is, dict, digest, null, priority);
+    }
+
+    private void waitForServiceChanges(int waitForOsgiEventsQuietInSec) {
+        if (waitForOsgiEventsQuietInSec <= 0) {
+            return;
+        }
+        InstallerHookOsgiEventListener osgiListener = new 
InstallerHookOsgiEventListener();
+        BundleContext bundleContext = getBundleContext();
+        bundleContext.addServiceListener(osgiListener);
+        bundleContext.addBundleListener(osgiListener);
+
+        long waitStart = System.currentTimeMillis();
+        osgiListener.waitUntilQuiet(waitForOsgiEventsQuietInSec);
+        logger.log("Waited " + (System.currentTimeMillis() - waitStart) + "ms 
in total for OSGi events to become quiet (for at least "
+                + waitForOsgiEventsQuietInSec + "sec)");
+
+        bundleContext.removeServiceListener(osgiListener);
+        bundleContext.removeBundleListener(osgiListener);
+
+    }
+
+    // always get fresh bundle context to avoid "Dynamic class loader has 
already
+    // been deactivated" exceptions
+    private BundleContext getBundleContext() {
+        // use the vault bundle to hook into the OSGi world
+        Bundle currentBundle = FrameworkUtil.getBundle(InstallHook.class);
+        if (currentBundle == null) {
+            throw new IllegalStateException(
+                    "The class " + InstallHook.class + " was not loaded 
through a bundle classloader");
+        }
+        BundleContext bundleContext = currentBundle.getBundleContext();
+        if (bundleContext == null) {
+            throw new IllegalStateException("Could not get bundle context for 
bundle " + currentBundle);
+        }
+        return bundleContext;
+    }
+
+    class BundleInPackage {
+        final String path;
+        final String symbolicName;
+        final String version;
+
+        public BundleInPackage(String path, String symbolicName, String 
version) {
+            super();
+            this.path = path;
+            this.symbolicName = symbolicName;
+            this.version = version;
+        }
+
+        @Override
+        public String toString() {
+            return "BundleInPackage [path=" + path + ", symbolicId=" + 
symbolicName + ", version=" + version + "]";
+        }
+
+    }
+
+    static class InstallHookLogger {
+
+        private ProgressTrackerListener listener;
+
+        public void setOptions(ImportOptions options) {
+            this.listener = options.getListener();
+        }
+
+        public void logError(Logger logger, String message, Throwable 
throwable) {
+            if (listener != null) {
+                listener.onMessage(ProgressTrackerListener.Mode.TEXT, "ERROR: 
" + message, "");
+            }
+            logger.error(message, throwable);
+        }
+
+        public void log(String message) {
+            log(LOG, message);
+        }
+
+        public void log(Logger logger, String message) {
+            if (listener != null) {
+                listener.onMessage(ProgressTrackerListener.Mode.TEXT, message, 
"");
+                logger.debug(message);
+            } else {
+                logger.info(message);
+            }
+        }
+    }
+
+    static class InstallerHookOsgiEventListener implements ServiceListener, 
BundleListener {
+
+        private long lastEventTimestamp = System.currentTimeMillis();
+
+        @Override
+        public void serviceChanged(ServiceEvent event) {
+            lastEventTimestamp = System.currentTimeMillis();
+            LOG.trace("Service changed event {}", event);
+        }
+
+        @Override
+        public void bundleChanged(BundleEvent event) {
+            lastEventTimestamp = System.currentTimeMillis();
+            LOG.trace("Bundle changed event {}", event);
+        }
+
+        public void waitUntilQuiet(long waitInSec) {
+            try {
+                while (System.currentTimeMillis() - lastEventTimestamp < 
waitInSec * 1000) {
+                    Thread.sleep(100);
+                }
+            } catch (InterruptedException e) {
+                LOG.warn("Wait for OSGi events was interrupted");
+            }
+        }
+    }
 
-       private static final String MANIFEST_BUNDLE_SYMBOLIC_NAME = 
"Bundle-SymbolicName";
-       private static final String MANIFEST_BUNDLE_VERSION = "Bundle-Version";
-       private static final String FOLDER_META_INF = "META-INF";
-
-       static final String JCR_CONTENT = "jcr:content";
-       static final String JCR_CONTENT_DATA = JCR_CONTENT + "/jcr:data";
-       static final String JCR_LAST_MODIFIED = "jcr:lastModified";
-       static final String JCR_CONTENT_LAST_MODIFIED = JCR_CONTENT + "/" + 
JCR_LAST_MODIFIED;
-
-       public static final String DOT = ".";
-
-       InstallHookLogger logger = new InstallHookLogger();
-
-       @Override
-       public void execute(InstallContext context) throws PackageException {
-
-               VaultPackage vaultPackage = context.getPackage();
-               PackageProperties packageProperties = 
vaultPackage.getProperties();
-               String installPathRegex = 
packageProperties.getProperty(PACKAGE_PROP_INSTALL_PATH_REGEX);
-
-               ServiceReference<OsgiInstaller> osgiInstallerServiceRef = null;
-               ServiceReference<ConfigurationAdmin> configAdminServiceRef = 
null;
-               ServiceReference<SlingSettingsService> slingSettingsServiceRef 
= null;
-               ServiceRegistration<InstallationListener> 
hookInstallationListenerServiceRegistration = null;
-
-               try {
-                       switch (context.getPhase()) {
-                       case PREPARE:
-                               if (StringUtils.isBlank(installPathRegex)) {
-                                       throw new IllegalArgumentException(
-                                                       "When using OSGi 
installer install hook for synchronous installation, the package property "
-                                                                       + 
PACKAGE_PROP_INSTALL_PATH_REGEX + " has to be provided.");
-                               }
-                               break;
-                       case INSTALLED:
-                               ImportOptions options = context.getOptions();
-                               logger.setOptions(options);
-
-                               logger.log(getClass().getSimpleName() + " is 
active in " + vaultPackage.getId());
-
-                               List<BundleInPackage> bundleResources = new 
ArrayList<>();
-                               List<String> configResourcePaths = new 
ArrayList<>();
-                               Archive archive = vaultPackage.getArchive();
-
-                               configAdminServiceRef = 
getBundleContext().getServiceReference(ConfigurationAdmin.class);
-                               ConfigurationAdmin confAdmin = 
(ConfigurationAdmin) getBundleContext()
-                                               
.getService(configAdminServiceRef);
-
-                               slingSettingsServiceRef = 
getBundleContext().getServiceReference(SlingSettingsService.class);
-                               SlingSettingsService slingSettingsService = 
(SlingSettingsService) getBundleContext()
-                                               
.getService(slingSettingsServiceRef);
-                               Set<String> runModes = 
slingSettingsService.getRunModes();
-
-                               collectResources(archive, archive.getRoot(), 
"", bundleResources, configResourcePaths, installPathRegex,
-                                               runModes);
-
-                               logger.log("Bundles in package " + 
bundleResources);
-
-                               Map<String, String> bundleVersionsBySymbolicId 
= new HashMap<>();
-                               for (Bundle bundle : 
getBundleContext().getBundles()) {
-                                       
bundleVersionsBySymbolicId.put(bundle.getSymbolicName(), 
bundle.getVersion().toString());
-                               }
-
-                               Session session = context.getSession();
-
-                               List<InstallableResource> installableResources 
= new ArrayList<>();
-
-                               Set<String> bundleSymbolicNamesToInstall = 
getBundlesToInstall(bundleResources,
-                                               bundleVersionsBySymbolicId, 
session, installableResources);
-
-                               Set<String> configPidsToInstall = 
getConfigPidsToInstall(configResourcePaths, session,
-                                               installableResources, 
confAdmin);
-
-                               if (installableResources.isEmpty()) {
-                                       logger.log("No installable resources 
that are not installed yet found.");
-                                       return;
-                               }
-
-                               logger.log("Installing " + 
bundleSymbolicNamesToInstall.size() + " bundles and "
-                                               + configPidsToInstall.size() + 
" configs");
-                               osgiInstallerServiceRef = 
getBundleContext().getServiceReference(OsgiInstaller.class);
-                               OsgiInstaller osgiInstaller = 
getBundleContext().getService(osgiInstallerServiceRef);
-
-                               OsgiInstallerListener hookInstallationListener 
= new OsgiInstallerListener(bundleSymbolicNamesToInstall,
-                                               configPidsToInstall);
-                               hookInstallationListenerServiceRegistration = 
getBundleContext()
-                                               
.registerService(InstallationListener.class, hookInstallationListener, null);
-
-                               logger.log("Update resources " + 
installableResources);
-                               osgiInstaller.updateResources(URL_SCHEME,
-                                               
installableResources.toArray(new 
InstallableResource[installableResources.size()]), null);
-
-                               String maxWaitForOsgiInstallerInSecStr = 
packageProperties
-                                               
.getProperty(PACKAGE_PROPERTY_MAX_WAIT_IN_SEC);
-                               int maxWaitForOsgiInstallerInSec = 
maxWaitForOsgiInstallerInSecStr != null
-                                               ? 
Integer.parseInt(maxWaitForOsgiInstallerInSecStr)
-                                               : DEFAULT_MAX_WAIT_IN_SEC;
-
-                               long startTime = System.currentTimeMillis();
-                               while (!hookInstallationListener.isDone()) {
-                                       if ((System.currentTimeMillis() - 
startTime) > maxWaitForOsgiInstallerInSec * 1000) {
-                                               logger.log("Installable 
resources " + installableResources
-                                                               + " could not 
be installed even after waiting " + maxWaitForOsgiInstallerInSec + "sec");
-                                               break;
-                                       }
-                                       logger.log("Waiting for " + 
installableResources.size() + " to be installed");
-                                       Thread.sleep(1000);
-                               }
-
-                               break;
-                       default:
-                               break;
-                       }
-               } catch (Exception e) {
-                       throw new PackageException("Could not execute install 
hook to for synchronous installation: " + e, e);
-               } finally {
-                       if (osgiInstallerServiceRef != null) {
-                               
getBundleContext().ungetService(osgiInstallerServiceRef);
-                       }
-                       if (configAdminServiceRef != null) {
-                               
getBundleContext().ungetService(configAdminServiceRef);
-                       }
-                       if (slingSettingsServiceRef != null) {
-                               
getBundleContext().ungetService(slingSettingsServiceRef);
-                       }
-
-                       if (hookInstallationListenerServiceRegistration != 
null) {
-                               
hookInstallationListenerServiceRegistration.unregister();
-                       }
-               }
-       }
-
-       private Set<String> getConfigPidsToInstall(List<String> 
configResourcePaths, Session session,
-                       List<InstallableResource> installableResources, 
ConfigurationAdmin confAdmin)
-                       throws IOException, InvalidSyntaxException, 
RepositoryException {
-               Set<String> configIdsToInstall = new HashSet<>();
-               for (String configResourcePath : configResourcePaths) {
-                       boolean needsInstallation = false;
-                       String configIdToInstall = StringUtils
-                                       
.substringBefore(StringUtils.substringAfterLast(configResourcePath, "/"), 
CONFIG_SUFFIX);
-                       if (!configIdToInstall.contains("-")) {
-                               // non-factory configs
-                               Configuration[] activeConfigs = 
confAdmin.listConfigurations("(service.pid=" + configIdToInstall + ")");
-                               if (activeConfigs == null) {
-                                       logger.log("Config PID " + 
configIdToInstall + " requires installation");
-
-                                       needsInstallation = true;
-                               }
-                       } else {
-                               // non-factory configs
-                               String factoryPid = 
StringUtils.substringBefore(configIdToInstall, "-");
-                               Configuration[] activeConfigs = 
confAdmin.listConfigurations("(service.factoryPid=" + factoryPid + ")");
-                               if (activeConfigs == null) {
-                                       logger.log("There is not a single 
config for factory PID " + factoryPid + " in system, "
-                                                       + configIdToInstall + " 
requires installation");
-                                       needsInstallation = true;
-                               }
-                       }
-
-                       if (needsInstallation) {
-                               Node node = session.getNode(configResourcePath);
-                               InstallableResource installableResource = 
convert(node, configResourcePath);
-                               installableResources.add(installableResource);
-                               configIdsToInstall.add(configIdToInstall);
-                       }
-               }
-               return configIdsToInstall;
-       }
-
-       private Set<String> getBundlesToInstall(List<BundleInPackage> 
bundleResources,
-                       Map<String, String> bundleVersionsBySymbolicId, Session 
session,
-                       List<InstallableResource> installableResources) throws 
RepositoryException, IOException {
-               Set<String> bundleSymbolicNamesToInstall = new HashSet<>();
-               Iterator<BundleInPackage> bundlesIt = 
bundleResources.iterator();
-               while (bundlesIt.hasNext()) {
-                       BundleInPackage bundle = bundlesIt.next();
-
-                       String currentlyActiveBundleVersion = 
bundleVersionsBySymbolicId.get(bundle.symbolicName);
-                       boolean needsInstallation = false;
-                       if (currentlyActiveBundleVersion == null) {
-                               logger.log("Bundle " + bundle.symbolicName + " 
is not installed");
-                               needsInstallation = true;
-                       } else if 
(!currentlyActiveBundleVersion.equals(bundle.version)) {
-                               logger.log("Bundle " + bundle.symbolicName + " 
is installed with version "
-                                               + currentlyActiveBundleVersion 
+ " but package contains version " + bundle.version);
-                               needsInstallation = true;
-                       } else {
-                               logger.log("Bundle " + bundle.symbolicName + " 
is already installed with version "
-                                               + currentlyActiveBundleVersion);
-                       }
-                       if (needsInstallation) {
-                               logger.log("Bundle " + bundle.symbolicName + " 
requires installation");
-                               Node node = session.getNode(bundle.path);
-                               InstallableResource installableResource = 
convert(node, bundle.path);
-                               installableResources.add(installableResource);
-                               
bundleSymbolicNamesToInstall.add(bundle.symbolicName);
-                       }
-               }
-               return bundleSymbolicNamesToInstall;
-       }
-
-       void collectResources(Archive archive, Entry entry, String dirPath, 
List<BundleInPackage> bundleResources,
-                       List<String> configResources, String installPathRegex, 
Set<String> actualRunmodes) {
-               String entryName = entry.getName();
-               if (entryName.equals(FOLDER_META_INF)) {
-                       return;
-               }
-
-               String dirPathWithoutJcrRoot = 
StringUtils.substringAfter(dirPath, "/jcr_root");
-               String entryPath = dirPathWithoutJcrRoot + entryName;
-               String dirPathWithoutSlash = 
StringUtils.chomp(dirPathWithoutJcrRoot, "/");
-
-               boolean runmodesMatch;
-               if (dirPathWithoutSlash.contains(DOT)) {
-                       String[] bits = dirPathWithoutSlash.split("\\" + DOT, 
2);
-                       List<String> runmodesOfResource = 
Arrays.asList(bits[1].split("\\" + DOT));
-                       Set<String> matchingRunmodes = new 
HashSet<String>(runmodesOfResource);
-                       matchingRunmodes.retainAll(actualRunmodes);
-                       LOG.debug("Entry with runmode(s): entryPath={} 
runmodesOfResource={} actualRunmodes={} matchingRunmodes={}",
-                                       entryPath, runmodesOfResource, 
actualRunmodes, matchingRunmodes);
-                       runmodesMatch = matchingRunmodes.size() == 
runmodesOfResource.size();
-                       if (!runmodesMatch) {
-                               logger.log("Skipping installation of  " + 
entryPath
-                                               + " because the path is not 
matching all actual runmodes " + actualRunmodes);
-                       }
-               } else {
-                       runmodesMatch = true;
-               }
-
-               if (entryPath.matches(installPathRegex) && runmodesMatch) {
-
-                       if (entryName.endsWith(CONFIG_SUFFIX)) {
-                               configResources.add(entryPath);
-                       } else if (entryName.endsWith(JAR_SUFFIX)) {
-                               try (InputStream entryInputStream = 
archive.getInputSource(entry).getByteStream();
-                                               JarInputStream jarInputStream = 
new JarInputStream(entryInputStream)) {
-                                       Manifest manifest = 
jarInputStream.getManifest();
-                                       String symbolicName = 
manifest.getMainAttributes().getValue(MANIFEST_BUNDLE_SYMBOLIC_NAME);
-                                       String version = 
manifest.getMainAttributes().getValue(MANIFEST_BUNDLE_VERSION);
-
-                                       bundleResources.add(new 
BundleInPackage(entryPath, symbolicName, version));
-                               } catch (Exception e) {
-                                       throw new IllegalStateException(
-                                                       "Could not read 
symbolic name and version from manifest of bundle " + entryName);
-                               }
-                       }
-
-               }
-
-               for (Entry child : entry.getChildren()) {
-                       collectResources(archive, child, dirPath + entryName + 
"/", bundleResources, configResources,
-                                       installPathRegex, actualRunmodes);
-               }
-       }
-
-       InstallableResource convert(final Node node, final String path) throws 
IOException, RepositoryException {
-               logger.log("Converting " + node + " at path " + path);
-               final String digest = 
String.valueOf(node.getProperty(JCR_CONTENT_LAST_MODIFIED).getDate().getTimeInMillis());
-               final InputStream is = 
node.getProperty(JCR_CONTENT_DATA).getStream();
-               final Dictionary<String, Object> dict = new Hashtable<String, 
Object>();
-               dict.put(InstallableResource.INSTALLATION_HINT, 
node.getParent().getName());
-               return new InstallableResource(path, is, dict, digest, null, 
DEFAULT_PRIORITY_INSTALL_HOOK);
-       }
-
-       // always get fresh bundle context to avoid "Dynamic class loader has 
already
-       // been deactivated" exceptions
-       private BundleContext getBundleContext() {
-               // use the vault bundle to hook into the OSGi world
-               Bundle currentBundle = 
FrameworkUtil.getBundle(InstallHook.class);
-               if (currentBundle == null) {
-                       throw new IllegalStateException(
-                                       "The class " + InstallHook.class + " 
was not loaded through a bundle classloader");
-               }
-               BundleContext bundleContext = currentBundle.getBundleContext();
-               if (bundleContext == null) {
-                       throw new IllegalStateException("Could not get bundle 
context for bundle " + currentBundle);
-               }
-               return bundleContext;
-       }
-
-       class BundleInPackage {
-               final String path;
-               final String symbolicName;
-               final String version;
-
-               public BundleInPackage(String path, String symbolicName, String 
version) {
-                       super();
-                       this.path = path;
-                       this.symbolicName = symbolicName;
-                       this.version = version;
-               }
-
-               @Override
-               public String toString() {
-                       return "BundleInPackage [path=" + path + ", 
symbolicId=" + symbolicName + ", version=" + version + "]";
-               }
-
-       }
-
-       static class InstallHookLogger {
-
-               private ProgressTrackerListener listener;
-
-               public void setOptions(ImportOptions options) {
-                       this.listener = options.getListener();
-               }
-
-               public void logError(Logger logger, String message, Throwable 
throwable) {
-                       if (listener != null) {
-                               
listener.onMessage(ProgressTrackerListener.Mode.TEXT, "ERROR: " + message, "");
-                       }
-                       logger.error(message, throwable);
-               }
-
-               public void log(String message) {
-                       log(LOG, message);
-               }
-
-               public void log(Logger logger, String message) {
-                       if (listener != null) {
-                               
listener.onMessage(ProgressTrackerListener.Mode.TEXT, message, "");
-                               logger.debug(message);
-                       } else {
-                               logger.info(message);
-                       }
-               }
-       }
 }
diff --git 
a/src/main/java/org/apache/sling/installer/provider/installhook/OsgiInstallerListener.java
 
b/src/main/java/org/apache/sling/installer/provider/installhook/OsgiInstallerListener.java
index c0b1ace..4dd6b5a 100644
--- 
a/src/main/java/org/apache/sling/installer/provider/installhook/OsgiInstallerListener.java
+++ 
b/src/main/java/org/apache/sling/installer/provider/installhook/OsgiInstallerListener.java
@@ -18,10 +18,10 @@
 */
 package org.apache.sling.installer.provider.installhook;
 
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
-import org.apache.commons.lang.StringUtils;
 import org.apache.sling.installer.api.event.InstallationEvent;
 import org.apache.sling.installer.api.event.InstallationEvent.TYPE;
 import org.apache.sling.installer.api.event.InstallationListener;
@@ -31,57 +31,60 @@ import org.slf4j.LoggerFactory;
 
 public class OsgiInstallerListener implements InstallationListener {
 
-       private static final Logger LOG = 
LoggerFactory.getLogger(OsgiInstallerListener.class);
+    private static final Logger LOG = 
LoggerFactory.getLogger(OsgiInstallerListener.class);
 
-       static final String ENTITY_ID_PREFIX_BUNDLE = "bundle:";
-       static final String ENTITY_ID_PREFIX_CONFIG = "config:";
+    private final Set<String> initialBundleUrlsToInstall;
+    private final Set<String> initialConfigUrlsToInstall;
 
-       private final Set<String> requiredBundleSymbolicNames;
-       private final Set<String> requiredConfigPids;
-       private final Set<String> installedBundleSymbolicNames = new 
HashSet<>();
-       private final Set<String> installedConfigPids = new HashSet<>();
+    private final Set<String> bundleUrlsToInstall;
+    private final Set<String> configUrlsToInstall;
 
-       public OsgiInstallerListener(Set<String> requiredBundleSymbolicNames, 
Set<String> requiredConfigPids) {
-               this.requiredBundleSymbolicNames = requiredBundleSymbolicNames;
-               this.requiredConfigPids = requiredConfigPids;
-       }
+    public OsgiInstallerListener(Set<String> bundleUrlsToInstall, Set<String> 
configUrlsToInstall) {
+        this.initialBundleUrlsToInstall = bundleUrlsToInstall;
+        this.initialConfigUrlsToInstall = configUrlsToInstall;
 
-       @Override
-       public void onEvent(InstallationEvent installationEvent) {
-               if (installationEvent.getType() == TYPE.PROCESSED) {
-                       Object sourceRaw = installationEvent.getSource();
-                       if (!(sourceRaw instanceof TaskResource)) {
-                               throw new IllegalStateException("Expected 
source of type " + TaskResource.class.getName());
-                       }
-                       TaskResource source = (TaskResource) sourceRaw;
-                       String entityId = source.getEntityId();
+        this.bundleUrlsToInstall = Collections.synchronizedSet(new 
HashSet<>(initialBundleUrlsToInstall));
+        this.configUrlsToInstall = Collections.synchronizedSet(new 
HashSet<>(initialConfigUrlsToInstall));
+    }
 
-                       LOG.debug("Received event about processed entityId {}", 
entityId);
+    @Override
+    public void onEvent(InstallationEvent installationEvent) {
+        if (installationEvent.getType() == TYPE.PROCESSED) {
+            Object sourceRaw = installationEvent.getSource();
+            if (!(sourceRaw instanceof TaskResource)) {
+                throw new IllegalStateException("Expected source of type " + 
TaskResource.class.getName());
+            }
+            TaskResource source = (TaskResource) sourceRaw;
+            String entityId = source.getEntityId();
+            String url = source.getURL();
 
-                       if (entityId.startsWith(ENTITY_ID_PREFIX_BUNDLE)) {
-                               String installedBundleSymbolicName = 
StringUtils.substringAfter(entityId, ENTITY_ID_PREFIX_BUNDLE);
-                               
installedBundleSymbolicNames.add(installedBundleSymbolicName);
-                       } else if 
(entityId.startsWith(ENTITY_ID_PREFIX_CONFIG)) {
-                               String installedConfigPid = 
StringUtils.substringAfter(entityId, ENTITY_ID_PREFIX_CONFIG);
-                               installedConfigPids.add(installedConfigPid);
-                       }
-               }
-       }
+            LOG.trace("Received event about processed entityId={} url={}", 
entityId, url);
 
-       public boolean isDone() {
-               LOG.trace("requiredBundleSymbolicNames: {}", 
requiredBundleSymbolicNames);
-               LOG.trace("installedBundleSymbolicNames: {}", 
installedBundleSymbolicNames);
-               HashSet<String> bundlesLeftToInstall = new 
HashSet<String>(requiredBundleSymbolicNames);
-               bundlesLeftToInstall.removeAll(installedBundleSymbolicNames);
-               LOG.debug("bundlesLeftToInstall: {}", bundlesLeftToInstall);
+            if (bundleUrlsToInstall.contains(url)) {
+                LOG.debug("Received event for bundle installed with url={}", 
url);
+                bundleUrlsToInstall.remove(url);
+            }
+            if (configUrlsToInstall.contains(url)) {
+                LOG.debug("Received event for config installed with url={}", 
url);
+                configUrlsToInstall.remove(url);
+            }
+        }
+    }
 
-               LOG.trace("requiredConfigPids: {}", requiredConfigPids);
-               LOG.trace("installedConfigPids: {}", installedConfigPids);
-               HashSet<String> configsLeftToInstall = new 
HashSet<String>(requiredConfigPids);
-               configsLeftToInstall.removeAll(installedConfigPids);
-               LOG.debug("configsLeftToInstall: {}", configsLeftToInstall);
+    public int bundlesLeftToInstall() {
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("initialBundleUrlsToInstall: {}", 
initialBundleUrlsToInstall);
+            LOG.trace("bundleUrlsToInstall: {}", bundleUrlsToInstall);
+        }
+        return bundleUrlsToInstall.size();
+    }
 
-               return bundlesLeftToInstall.isEmpty() && 
configsLeftToInstall.isEmpty();
-       }
+    public int configsLeftToInstall() {
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("initialConfigUrlsToInstall: {}", 
initialConfigUrlsToInstall);
+            LOG.trace("configUrlsToInstall: {}", configUrlsToInstall);
+        }
+        return configUrlsToInstall.size();
+    }
 
 }
diff --git 
a/src/test/java/org/apache/sling/installer/provider/installhook/OsgiInstallerHookTest.java
 
b/src/test/java/org/apache/sling/installer/provider/installhook/OsgiInstallerHookTest.java
index 7d347d1..156fbfe 100644
--- 
a/src/test/java/org/apache/sling/installer/provider/installhook/OsgiInstallerHookTest.java
+++ 
b/src/test/java/org/apache/sling/installer/provider/installhook/OsgiInstallerHookTest.java
@@ -36,6 +36,7 @@ import javax.jcr.RepositoryException;
 
 import org.apache.jackrabbit.vault.fs.io.Archive;
 import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
+import org.apache.jackrabbit.vault.packaging.PackageProperties;
 import org.apache.sling.installer.api.InstallableResource;
 import 
org.apache.sling.installer.provider.installhook.OsgiInstallerHook.BundleInPackage;
 import org.junit.Before;
@@ -47,83 +48,85 @@ import org.mockito.junit.MockitoJUnitRunner;
 @RunWith(MockitoJUnitRunner.class)
 public class OsgiInstallerHookTest {
 
-       OsgiInstallerHook osgiInstallerHook;
-       
-       @Mock
-       Node node;
-
-       @Mock
-       Node parentNode;
-       
-       @Mock
-       Property lastModifiedProperty;
-       
-       @Mock
-       Property contentDataProperty;   
-
-       @Mock
-       Archive archive;        
-       
-       @Mock
-       Entry entry;    
-       
-       Calendar now;
-
-       @Before
-       public void setup() throws RepositoryException  {
-               osgiInstallerHook = new OsgiInstallerHook();
-               
-               now = Calendar.getInstance();
-               
when(node.getProperty(OsgiInstallerHook.JCR_CONTENT_LAST_MODIFIED)).thenReturn(lastModifiedProperty);
-               when(lastModifiedProperty.getDate()).thenReturn(now);
-               
when(node.getProperty(OsgiInstallerHook.JCR_CONTENT_DATA)).thenReturn(contentDataProperty);
-               when(node.getParent()).thenReturn(parentNode);
-               
-       }
-       
-       @Test
-       public void testConvert() throws IOException, RepositoryException {
-               
-               File pathToTest = new File("/apps/myproj/install/mybundle.jar");
-               
when(parentNode.getName()).thenReturn(pathToTest.getParentFile().getName());
-               
-               InstallableResource installableResource = 
osgiInstallerHook.convert(node, pathToTest.getAbsolutePath());
-
-               assertEquals(String.valueOf(now.getTimeInMillis()), 
installableResource.getDigest());
-               assertEquals(pathToTest.getParentFile().getName(), 
installableResource.getDictionary().get(InstallableResource.INSTALLATION_HINT));
-               
-       }
-       
-       public void testCollectResources() throws IOException, 
RepositoryException {
-               
-               File pathToTest = new 
File("/apps/myproj/install.author/myconfig.config");
-               String dirPath = "/jcr_root" + 
pathToTest.getParentFile().getPath() + "/";
-
-               when(entry.getName()).thenReturn(pathToTest.getName());
-               
-               List<BundleInPackage> bundleResources = new 
ArrayList<BundleInPackage>();
-               List<String> configResources = new ArrayList<String>();
-
-               osgiInstallerHook.collectResources(archive, entry, dirPath, 
bundleResources, configResources, 
-                               "/apps/other.*", new 
HashSet<String>(Arrays.asList("author", "dev")));
-                               
-               assertTrue(bundleResources.isEmpty());
-               assertTrue(configResources.isEmpty());
-
-               osgiInstallerHook.collectResources(archive, entry, dirPath, 
bundleResources, configResources, 
-                               "/apps/myproj.*", new 
HashSet<String>(Arrays.asList("publish", "dev")));
-                               
-               assertTrue(bundleResources.isEmpty());
-               assertTrue(configResources.isEmpty());
-               
-               
-               osgiInstallerHook.collectResources(archive, entry, dirPath, 
bundleResources, configResources, 
-                               "/apps/myproj.*", new 
HashSet<String>(Arrays.asList("author", "dev")));
-               
-               assertTrue(bundleResources.isEmpty());
-               assertEquals(1, configResources.size());
-               assertEquals(pathToTest.getAbsolutePath(), 
configResources.get(0));
-               
-       }
+    OsgiInstallerHook osgiInstallerHook;
+
+    @Mock
+    Node node;
+
+    @Mock
+    Node parentNode;
+
+    @Mock
+    Property lastModifiedProperty;
+
+    @Mock
+    Property contentDataProperty;
+
+    @Mock
+    Archive archive;
+
+    @Mock
+    PackageProperties packageProperties;
+
+    @Mock
+    Entry entry;
+
+    Calendar now;
+
+    @Before
+    public void setup() throws RepositoryException {
+        osgiInstallerHook = new OsgiInstallerHook();
+
+        now = Calendar.getInstance();
+        
when(node.getProperty(OsgiInstallerHook.JCR_CONTENT_LAST_MODIFIED)).thenReturn(lastModifiedProperty);
+        when(lastModifiedProperty.getDate()).thenReturn(now);
+        
when(node.getProperty(OsgiInstallerHook.JCR_CONTENT_DATA)).thenReturn(contentDataProperty);
+        when(node.getParent()).thenReturn(parentNode);
+
+    }
+
+    @Test
+    public void testConvert() throws IOException, RepositoryException {
+
+        File pathToTest = new File("/apps/myproj/install/mybundle.jar");
+        
when(parentNode.getName()).thenReturn(pathToTest.getParentFile().getName());
+
+        InstallableResource installableResource = 
osgiInstallerHook.convert(node, pathToTest.getAbsolutePath(), 
packageProperties);
+
+        assertEquals(String.valueOf(now.getTimeInMillis()), 
installableResource.getDigest());
+        assertEquals(pathToTest.getParentFile().getName(), 
installableResource.getDictionary().get(InstallableResource.INSTALLATION_HINT));
+
+    }
+
+    public void testCollectResources() throws IOException, RepositoryException 
{
+
+        File pathToTest = new 
File("/apps/myproj/install.author/myconfig.config");
+        String dirPath = "/jcr_root" + pathToTest.getParentFile().getPath() + 
"/";
+
+        when(entry.getName()).thenReturn(pathToTest.getName());
+
+        List<BundleInPackage> bundleResources = new 
ArrayList<BundleInPackage>();
+        List<String> configResources = new ArrayList<String>();
+
+        osgiInstallerHook.collectResources(archive, entry, dirPath, 
bundleResources, configResources,
+                "/apps/other.*", new HashSet<String>(Arrays.asList("author", 
"dev")));
+
+        assertTrue(bundleResources.isEmpty());
+        assertTrue(configResources.isEmpty());
+
+        osgiInstallerHook.collectResources(archive, entry, dirPath, 
bundleResources, configResources,
+                "/apps/myproj.*", new HashSet<String>(Arrays.asList("publish", 
"dev")));
+
+        assertTrue(bundleResources.isEmpty());
+        assertTrue(configResources.isEmpty());
+
+        osgiInstallerHook.collectResources(archive, entry, dirPath, 
bundleResources, configResources,
+                "/apps/myproj.*", new HashSet<String>(Arrays.asList("author", 
"dev")));
+
+        assertTrue(bundleResources.isEmpty());
+        assertEquals(1, configResources.size());
+        assertEquals(pathToTest.getAbsolutePath(), configResources.get(0));
+
+    }
 
 }
diff --git 
a/src/test/java/org/apache/sling/installer/provider/installhook/OsgiInstallerListenerTest.java
 
b/src/test/java/org/apache/sling/installer/provider/installhook/OsgiInstallerListenerTest.java
index 6cd02ea..90c755b 100644
--- 
a/src/test/java/org/apache/sling/installer/provider/installhook/OsgiInstallerListenerTest.java
+++ 
b/src/test/java/org/apache/sling/installer/provider/installhook/OsgiInstallerListenerTest.java
@@ -18,12 +18,10 @@
 */
 package org.apache.sling.installer.provider.installhook;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
-import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
 
@@ -34,39 +32,54 @@ import org.junit.Test;
 
 public class OsgiInstallerListenerTest {
 
-       private OsgiInstallerListener osgiInstallerListener;
-       
-       @Test
-       public void testOsgiInstallerListener() {
-               
-               String bundleSymbolicId1 = "org.prj.bundle1";
-               String bundleSymbolicId2 = "org.prj.bundle2";
-               Set<String> requiredBundleSymbolicNames = new 
HashSet<String>(Arrays.asList(bundleSymbolicId1, bundleSymbolicId2));
-               String configPid1 = "org.prj.config1";
-               String configPid2 = "org.prj.config2";
-               Set<String> requiredConfigPids = new 
HashSet<String>(Arrays.asList(configPid1, configPid2));
-
-               osgiInstallerListener = new 
OsgiInstallerListener(requiredBundleSymbolicNames, requiredConfigPids);
-
-               assertFalse(osgiInstallerListener.isDone());
-               
osgiInstallerListener.onEvent(getInstallationEventMock(OsgiInstallerListener.ENTITY_ID_PREFIX_BUNDLE
 + bundleSymbolicId1));
-               assertFalse(osgiInstallerListener.isDone());
-               
osgiInstallerListener.onEvent(getInstallationEventMock(OsgiInstallerListener.ENTITY_ID_PREFIX_BUNDLE
 + bundleSymbolicId2));
-               assertFalse(osgiInstallerListener.isDone());
-               
osgiInstallerListener.onEvent(getInstallationEventMock(OsgiInstallerListener.ENTITY_ID_PREFIX_CONFIG
 + configPid1));
-               assertFalse(osgiInstallerListener.isDone());
-               
osgiInstallerListener.onEvent(getInstallationEventMock(OsgiInstallerListener.ENTITY_ID_PREFIX_CONFIG
 + configPid2));
-               assertTrue(osgiInstallerListener.isDone());
-               
-       }
-       
-       public InstallationEvent getInstallationEventMock(String entityId) {
-               InstallationEvent event = mock(InstallationEvent.class);
-               when(event.getType()).thenReturn(TYPE.PROCESSED);
-               TaskResource taskResource = mock(TaskResource.class);
-               when(event.getSource()).thenReturn(taskResource);
-               when(taskResource.getEntityId()).thenReturn(entityId);
-               return event;
-       }
+    private OsgiInstallerListener osgiInstallerListener;
+
+    @Test
+    public void testOsgiInstallerListener() {
+
+        Set<String> bundleUrlsToInstall = new HashSet<String>();
+        String bundleUrl1 = "jcrinstall:/apps/myproj/install/mybundle1.jar";
+        bundleUrlsToInstall.add(bundleUrl1);
+        String bundleUrl2 = "jcrinstall:/apps/myproj/install/mybundle2.jar";
+        bundleUrlsToInstall.add(bundleUrl2);
+
+        Set<String> configUrlsToInstall = new HashSet<String>();
+        String configUrl1 = "jcrinstall:/apps/myproj/config/conf1.config";
+        configUrlsToInstall.add(configUrl1);
+        String configUrl2 = "jcrinstall:/apps/myproj/config/conf2.config";
+        configUrlsToInstall.add(configUrl2);
+
+        osgiInstallerListener = new OsgiInstallerListener(bundleUrlsToInstall, 
configUrlsToInstall);
+
+        assertEquals(2, osgiInstallerListener.bundlesLeftToInstall());
+        assertEquals(2, osgiInstallerListener.configsLeftToInstall());
+
+        osgiInstallerListener.onEvent(getInstallationEventMock(bundleUrl1));
+        assertEquals(1, osgiInstallerListener.bundlesLeftToInstall());
+        assertEquals(2, osgiInstallerListener.configsLeftToInstall());
+
+        osgiInstallerListener.onEvent(getInstallationEventMock(bundleUrl2));
+        assertEquals(0, osgiInstallerListener.bundlesLeftToInstall());
+        assertEquals(2, osgiInstallerListener.configsLeftToInstall());
+
+        osgiInstallerListener.onEvent(getInstallationEventMock(configUrl1));
+        assertEquals(0, osgiInstallerListener.bundlesLeftToInstall());
+        assertEquals(1, osgiInstallerListener.configsLeftToInstall());
+
+        osgiInstallerListener.onEvent(getInstallationEventMock(configUrl2));
+        assertEquals(0, osgiInstallerListener.bundlesLeftToInstall());
+        assertEquals(0, osgiInstallerListener.configsLeftToInstall());
+
+    }
+
+    public InstallationEvent getInstallationEventMock(String url) {
+        InstallationEvent event = mock(InstallationEvent.class);
+        when(event.getType()).thenReturn(TYPE.PROCESSED);
+        TaskResource taskResource = mock(TaskResource.class);
+        when(event.getSource()).thenReturn(taskResource);
+        when(taskResource.getURL()).thenReturn(url);
+        when(taskResource.getEntityId()).thenReturn("dummyEntityId");
+        return event;
+    }
 
 }

Reply via email to