/*
* #%L
* Nazgul Project: nazgul-core-osgi-launcher-api
* %%
* Copyright (C) 2010 - 2017 jGuru Europe AB
* %%
* Licensed under the jGuru Europe AB license (the "License"), based
* on Apache License, Version 2.0; you may not use this file except
* in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.jguru.se/licenses/jguruCorporateSourceLicense-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*
*/
package se.jguru.nazgul.core.osgi.launcher.api;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.launch.Framework;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import se.jguru.nazgul.core.osgi.launcher.api.event.BundleContextHolder;
import se.jguru.nazgul.core.osgi.launcher.api.event.blueprint.MockBlueprintServiceEventAdapter;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
* @author <a href="mailto:lj@jguru.se">Lennart Jörelid</a>, jGuru Europe AB
*/
public class T_AbstractFrameworkEventListenerTest {
// Our log
private static final Logger log = LoggerFactory.getLogger(T_AbstractFrameworkEventListenerTest.class);
// Shared state
private MockBlueprintServiceEventAdapter listener;
private FelixFrameworkLauncher unitUnderTest;
private Map<String, String> configuration;
private File targetDirectory;
private File downloadedBundlesDirectory;
private boolean stopFramework;
private static int iteration = 0;
@Before
public void launchFelix() {
// Find the relevant directories
final URL origin = getClass().getClassLoader().getResource("test_origin.txt");
Assert.assertNotNull(origin);
targetDirectory = new File(origin.getPath()).getParentFile().getParentFile();
Assert.assertTrue(targetDirectory.isDirectory());
Assert.assertEquals("target", targetDirectory.getName());
downloadedBundlesDirectory = new File(targetDirectory, "downloadedBundles");
Assert.assertTrue(downloadedBundlesDirectory.isDirectory());
stopFramework = true;
// Create the embedder
unitUnderTest = new FelixFrameworkLauncher("testID_" + iteration++);
final File userDir = new File(targetDirectory, "userDir_" + iteration);
userDir.delete();
// Create base configuration properties
configuration = new TreeMap<String, String>();
configuration.put("felix.log.level", "3");
configuration.put("felix.cache.rootdir", new File(userDir, "felix-cache").getAbsolutePath());
// Create the ServiceEventAdapter
listener = new MockBlueprintServiceEventAdapter("testListener");
}
@After
public void shutdownFelix() throws Exception {
if (stopFramework) {
try {
unitUnderTest.stop();
unitUnderTest.getFramework().waitForStop(0);
} catch (Exception e) {
log.error("Could not properly stop Felix", e);
}
}
}
@Test
public void validateLifecycleOnAddingConsumersBeforeFrameworkIsLaunched()
throws BundleException, InvalidSyntaxException {
// Act
unitUnderTest.addConsumer(listener);
unitUnderTest.addConsumer(listener);
final int sizeBeforeInit = getMapOfPendingBundleContextHolders(true).size();
unitUnderTest.initialize(configuration);
unitUnderTest.start();
final int sizeAfterInit = getMapOfPendingBundleContextHolders(true).size();
final Framework felix = unitUnderTest.getFramework();
final BundleContext mainCtx = felix.getBundleContext();
installAllDownloadedBundles(downloadedBundlesDirectory, mainCtx, true);
/*
final DeploymentAdmin deploymentAdmin = getServiceInTheStupidWay(DeploymentAdmin.class, mainCtx);
for(DeploymentPackage current : deploymentAdmin.listDeploymentPackages()) {
log.info(" ==> " + current.getName() + " (" + current.getDisplayName() + ") -- ");
}
final ServiceReference packageAdminServiceReference = mainCtx.getServiceReference(PackageAdmin.class.getName());
final PackageAdmin packageAdmin = (PackageAdmin) felix.getBundleContext()
.getService(packageAdminServiceReference);
*/
for (ServiceReference current : mainCtx.getAllServiceReferences(null, null)) {
log.info("==> " + current + " from bundle [" + current.getBundle().getSymbolicName() + "]");
}
for (Bundle current : mainCtx.getBundles()) {
log.info("Bundle [" + current.getBundleId() + "]: " + current.getSymbolicName() + " (" + current
.getVersion() + ") -- " + getState(current.getState()));
}
// Assert
Assert.assertEquals(1, sizeBeforeInit);
Assert.assertEquals(0, sizeAfterInit);
}
@Test
public void validateLifecycleOnAddingListenersAfterFrameworkStart() throws Exception {
// Act
unitUnderTest.initialize(configuration);
unitUnderTest.start();
unitUnderTest.addConsumer(listener);
unitUnderTest.addConsumer(listener);
final int pendingListenersSize = getMapOfPendingBundleContextHolders(true).size();
final Framework felix = unitUnderTest.getFramework();
final BundleContext mainCtx = felix.getBundleContext();
installAllDownloadedBundles(downloadedBundlesDirectory, mainCtx, true);
// Assert
Assert.assertEquals(0, pendingListenersSize);
}
@Test
public void validateRemovingListenersBeforeFrameworkStart() throws Exception {
// Assemble
final MockBlueprintServiceEventAdapter listener1 = new MockBlueprintServiceEventAdapter("testListener1");
final MockBlueprintServiceEventAdapter listener2 = new MockBlueprintServiceEventAdapter("testListener2");
// Act
unitUnderTest.addConsumer(listener);
unitUnderTest.addConsumer(listener);
unitUnderTest.addConsumer(listener2);
unitUnderTest.removeConsumer("nonexistent");
unitUnderTest.removeConsumer(listener2.getClusterId());
final int toRegisterSizeBeforeInit = getMapOfPendingBundleContextHolders(true).size();
final int toDeregisterSizeBeforeInit = getMapOfPendingBundleContextHolders(false).size();
unitUnderTest.initialize(configuration);
unitUnderTest.start();
final int toRegisterSizeAfterInit = getMapOfPendingBundleContextHolders(true).size();
final int toDeregisterSizeAfterInit = getMapOfPendingBundleContextHolders(false).size();
final Framework felix = unitUnderTest.getFramework();
final BundleContext mainCtx = felix.getBundleContext();
installAllDownloadedBundles(downloadedBundlesDirectory, mainCtx, true);
/*
final DeploymentAdmin deploymentAdmin = getServiceInTheStupidWay(DeploymentAdmin.class, mainCtx);
for(DeploymentPackage current : deploymentAdmin.listDeploymentPackages()) {
log.info(" ==> " + current.getName() + " (" + current.getDisplayName() + ") -- ");
}
final ServiceReference packageAdminServiceReference = mainCtx.getServiceReference(PackageAdmin.class.getName());
final PackageAdmin packageAdmin = (PackageAdmin) felix.getBundleContext()
.getService(packageAdminServiceReference);
for (ServiceReference current : mainCtx.getAllServiceReferences(null, null)) {
System.out.println("==> " + current + " from bundle [" + current.getBundle().getSymbolicName() + "]");
}
for (Bundle current : mainCtx.getBundles()) {
log.info("Bundle [" + current.getBundleId() + "]: " + current.getSymbolicName() + " (" + current
.getVersion() + ") -- " + getState(current.getState()));
}
*/
// Assert
Assert.assertEquals(2, toRegisterSizeBeforeInit);
Assert.assertEquals(1, toDeregisterSizeBeforeInit);
Assert.assertEquals(0, toRegisterSizeAfterInit);
Assert.assertEquals(0, toDeregisterSizeAfterInit);
}
@Test
public void validateLifecycleOnAddingListenersWithoutFrameworkStart() throws Exception {
// Assemble
stopFramework = false;
// Act
unitUnderTest.initialize(configuration);
unitUnderTest.addConsumer(listener);
unitUnderTest.addConsumer(listener);
final Framework felix = unitUnderTest.getFramework();
// Assert
final BundleContext bundleContext = felix.getBundleContext();
Assert.assertNotNull(bundleContext);
Assert.assertEquals(Bundle.STARTING, felix.getState());
}
//
// Private helpers
//
private Map<String, BundleContextHolder> getMapOfPendingBundleContextHolders(boolean toRegister) {
final String fieldName = toRegister ? "toRegister" : "toDeregister";
try {
final Field theField = AbstractFrameworkLauncher.class.getDeclaredField(fieldName);
theField.setAccessible(true);
return (Map<String, BundleContextHolder>) theField.get(unitUnderTest);
} catch (Exception e) {
return null;
}
}
public static String getState(int bundleState) {
// UNINSTALLED,INSTALLED, RESOLVED,STARTING, STOPPING,ACTIVE.
String toReturn;
switch (bundleState) {
case Bundle.UNINSTALLED:
toReturn = "UNINSTALLED";
break;
case Bundle.INSTALLED:
toReturn = "INSTALLED";
break;
case Bundle.RESOLVED:
toReturn = "RESOLVED";
break;
case Bundle.STARTING:
toReturn = "STARTING";
break;
case Bundle.STOPPING:
toReturn = "STOPPING";
break;
case Bundle.ACTIVE:
toReturn = "ACTIVE";
break;
default:
toReturn = "<Unknown> (" + bundleState + ")";
break;
}
return toReturn;
}
public static <T> T getServiceInTheStupidWay(Class<T> apiType, BundleContext ctx) {
ServiceReference ref = ctx.getServiceReference(apiType.getName());
return (T) ctx.getService(ref);
}
public static void installAllDownloadedBundles(File downloadDirectory, BundleContext ctx, boolean start) {
List<Bundle> installed = new ArrayList<Bundle>();
for (File current : downloadDirectory.listFiles()) {
final String absolutePath = current.getAbsolutePath();
Bundle currentBundle = null;
try {
currentBundle = ctx.installBundle("file:/" + absolutePath, new FileInputStream(current));
installed.add(currentBundle);
} catch (Exception e) {
String bundleSymbolicName = currentBundle == null ? "<unknown>" : currentBundle.getSymbolicName();
log.error("Could not install bundle [" + bundleSymbolicName + "]", e);
}
}
if (start) {
for (Bundle current : installed) {
try {
current.start();
} catch (BundleException e) {
log.error("Could not start bundle [" + current.getSymbolicName() + "]", e);
}
}
}
}
}