/*
* Copyright (C) 2011 Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.
*/
package org.apache.aries.blueprint.ns.itests;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import nstest.LinkedListHandlerActivator;
import nstest.ListHandlerActivator;
import org.apache.aries.unittest.fixture.ArchiveFixture;
import org.apache.aries.unittest.fixture.ArchiveFixture.Fixture;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.blueprint.container.BlueprintContainer;
import org.osgi.util.tracker.ServiceTracker;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.Configuration;
import org.ops4j.pax.exam.junit.ExamReactorStrategy;
import org.ops4j.pax.exam.junit.JUnit4TestRunner;
import org.ops4j.pax.exam.spi.reactors.EagerSingleStagedReactorFactory;
import static org.ops4j.pax.exam.CoreOptions.*;
import static org.junit.Assert.*;
@RunWith( JUnit4TestRunner.class )
@ExamReactorStrategy( EagerSingleStagedReactorFactory.class )
public class SampleTest {
@Configuration()
public Option[] config()
{
return options(
junitBundles(),
equinox(),
// this is how you set the default log level when using pax logging (logProfile)
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("DEBUG"),
mavenBundle("org.ops4j.pax.logging", "pax-logging-api"),
mavenBundle("org.ops4j.pax.logging", "pax-logging-service"),
mavenBundle("org.ops4j.pax.url", "pax-url-mvn"),
mavenBundle("org.apache.aries", "org.apache.aries.util", "0.4-SNAPSHOT"),
mavenBundle("org.apache.aries.proxy", "org.apache.aries.proxy", "0.4-SNAPSHOT"),
mavenBundle("asm", "asm-all"),
mavenBundle("org.apache.aries.blueprint", "org.apache.aries.blueprint", "0.3.2-SNAPSHOT"),
mavenBundle("org.apache.aries.testsupport", "org.apache.aries.testsupport.unit")
);
}
private final Set<Bundle> installed = new HashSet<Bundle>();
/**
* This really should be @After but by the looks of it @After does not get invoked in the
* context of the running framework and so the installed member variable would be empty :(
*
* This is only really a problem with EagerSingleStagedReactorFactory as the ExamReactorStrategy because
* otherwise the framework will be recycled for every @Test.
*/
public void cleanup() {
for (Bundle b : installed) {
System.out.println("Clear out "+b.getSymbolicName()+"/"+b.getVersion());
if (b.getState() != Bundle.UNINSTALLED) {
try {
b.uninstall();
} catch (BundleException be) {
be.printStackTrace();
}
}
}
installed.clear();
}
@Test
public void testNamespace( BundleContext ctx ) throws Exception
{
try {
installBundle(ctx, "nstest.list", makeCollectionHandler(ListHandlerActivator.class, "1.0.0"));
installBundle(ctx, "nstest.sample", makeCollectionTestBundle("(version=1.0.0)"));
Object list = waitForBlueprint(ctx, "nstest.sample").getComponentInstance("mylist");
assertEquals(Arrays.asList("1", "2", "3", "4", "5"), list);
} finally {
cleanup();
}
}
@Test
public void testNamespaceByVersionDistinction( BundleContext ctx ) throws Exception
{
try {
installBundle(ctx, "nstest.list_1.0.0", makeCollectionHandler(ListHandlerActivator.class, "1.0.0"));
installBundle(ctx, "nstest.list_1.1.0", makeCollectionHandler(LinkedListHandlerActivator.class, "1.1.0"));
// version 1.0.0
Bundle b = installBundle(ctx, "nstest.sample", makeCollectionTestBundle("(version=1.0.0)"));
assertTrue(waitForBlueprint(ctx, "nstest.sample").getComponentInstance("mylist") instanceof ArrayList);
b.uninstall();
// version 1.1.0
b = installBundle(ctx, "nstest.sample", makeCollectionTestBundle("(version=1.1.0)"));
assertTrue(waitForBlueprint(ctx, "nstest.sample").getComponentInstance("mylist") instanceof LinkedList);
b.uninstall();
// Impossible version
try {
installBundle(ctx, "nstest.sample", makeCollectionTestBundle("5.0.0"));
fail("Expected BundleException");
} catch (BundleException be) { /* Good */ }
} finally {
cleanup();
}
}
@Test
@Ignore
// How could this actually work? Should it not be the one that it is wired to in the resolution?
public void namespace_usage_with_version_range_picks_highest_version( BundleContext ctx ) throws Exception {
try {
installBundle(ctx, "nstest.list_1.0.0", makeCollectionHandler(ListHandlerActivator.class, "1.0.0"));
installBundle(ctx, "nstest.list_1.0.1", makeCollectionHandler(ListHandlerActivator.class, "1.0.1"));
installBundle(ctx, "nstest.list_1.0.2", makeCollectionHandler(ListHandlerActivator.class, "1.0.2"));
installBundle(ctx, "nstest.list_1.1.0", makeCollectionHandler(LinkedListHandlerActivator.class, "1.1.0"));
installBundle(ctx, "nstest.list_1.0.3", makeCollectionHandler(ListHandlerActivator.class, "1.0.3"));
installBundle(ctx, "nstest.sample", makeCollectionTestBundle(""));
assertTrue(waitForBlueprint(ctx, "nstest.sample").getComponentInstance("mylist") instanceof LinkedList);
} finally {
cleanup();
}
}
@Test
public void namespace_usage_without_require_capability_picks_higest_version( BundleContext ctx ) throws Exception {
try {
installBundle(ctx, "nstest.list_1.0.0", makeCollectionHandler(ListHandlerActivator.class, "1.0.0"));
installBundle(ctx, "nstest.list_1.0.1", makeCollectionHandler(ListHandlerActivator.class, "1.0.1"));
installBundle(ctx, "nstest.list_1.0.2", makeCollectionHandler(ListHandlerActivator.class, "1.0.2"));
installBundle(ctx, "nstest.list_1.1.0", makeCollectionHandler(LinkedListHandlerActivator.class, "1.1.0"));
installBundle(ctx, "nstest.list_1.0.3", makeCollectionHandler(ListHandlerActivator.class, "1.0.3"));
installBundle(ctx, "nstest.sample", makePlainCollectionTestBundle());
assertTrue(waitForBlueprint(ctx, "nstest.sample").getComponentInstance("mylist") instanceof LinkedList);
} finally {
cleanup();
}
}
private BlueprintContainer waitForBlueprint(BundleContext ctx, String bundle) throws Exception {
return waitForBlueprint(ctx, bundle, 5000);
}
private BlueprintContainer waitForBlueprint(BundleContext ctx, String bundle, long timeout) throws Exception {
ServiceTracker tracker = new ServiceTracker(ctx, FrameworkUtil.createFilter("(osgi.blueprint.container.symbolicname="+bundle + ")"), null);
tracker.open();
return (BlueprintContainer) tracker.waitForService(timeout);
}
private Fixture makeCollectionHandler(Class<?> activator, String version) throws Exception {
return ArchiveFixture.newJar()
.manifest()
.symbolicName("nstest.list")
.version(version)
.attribute("Import-Package", "org.osgi.framework, org.osgi.service.blueprint.reflect, org.apache.aries.blueprint, org.apache.aries.blueprint.metadata, org.w3c.dom")
.attribute("Bundle-Activator", activator.getName())
.attribute("Provide-Capability", "org.apache.aries.blueprint.NamespaceHandler;osgi.service.blueprint.namespace:String=http://aries.apache.org/ns/test/list;version:Version=\""+version+"\"")
.end()
.binary("nstest/"+activator.getSimpleName()+".class",
SampleTest.class.getClassLoader().getResourceAsStream("nstest/"+activator.getSimpleName()+".class"))
.binary("nstest/CollectionNSHandler.class",
SampleTest.class.getClassLoader().getResourceAsStream("nstest/CollectionNSHandler.class"))
.binary("nstest/list.xsd", SampleTest.class.getClassLoader().getResourceAsStream("nstest/list.xsd"))
.end();
}
private Fixture makePlainCollectionTestBundle() {
return ArchiveFixture.newJar()
.manifest()
.symbolicName("nstest.sample")
.end()
.file("OSGI-INF/blueprint/test.xml",
"<blueprint xmlns=\"http://www.osgi.org/xmlns/blueprint/v1.0.0\" xmlns:list=\"http://aries.apache.org/ns/test/list\">" +
"<list:list id=\"mylist\">1,2,3,4,5</list:list>" +
"</blueprint>");
}
private Fixture makeCollectionTestBundle(String version) {
return ArchiveFixture.newJar()
.manifest()
.symbolicName("nstest.sample")
.attribute("Require-Capability", "org.apache.aries.blueprint.NamespaceHandler;filter:=\"(&(osgi.service.blueprint.namespace=http://aries.apache.org/ns/test/list)"+version+")")
.end()
.file("OSGI-INF/blueprint/test.xml",
"<blueprint xmlns=\"http://www.osgi.org/xmlns/blueprint/v1.0.0\" xmlns:list=\"http://aries.apache.org/ns/test/list\">" +
"<list:list id=\"mylist\">1,2,3,4,5</list:list>" +
"</blueprint>");
}
private Bundle installBundle(BundleContext ctx, String name, Fixture bundle) throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
bundle.writeOut(bout);
Bundle b = ctx.installBundle(name, new ByteArrayInputStream(bout.toByteArray()));
installed.add(b);
b.start();
return b;
}
}