You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by kw...@apache.org on 2019/02/25 12:38:28 UTC
[sling-org-apache-sling-installer-provider-installhook] 09/24:
SLING-7790 use of InfoProvider,
additional package properties for configuration
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 <ge...@netcentric.biz>
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;
+ }
}