This is an automated email from the ASF dual-hosted git repository.
ghenzler pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-provider-installhook.git
The following commit(s) were added to refs/heads/master by this push:
new 9a95ab7 SLING-7790 use of InfoProvider, additional package properties
for configuration
9a95ab7 is described below
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;
+ }
}