Return-Path: X-Original-To: apmail-aries-commits-archive@www.apache.org Delivered-To: apmail-aries-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id A0B18115DA for ; Mon, 30 Jun 2014 16:56:50 +0000 (UTC) Received: (qmail 56415 invoked by uid 500); 30 Jun 2014 16:56:50 -0000 Delivered-To: apmail-aries-commits-archive@aries.apache.org Received: (qmail 56338 invoked by uid 500); 30 Jun 2014 16:56:50 -0000 Mailing-List: contact commits-help@aries.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@aries.apache.org Delivered-To: mailing list commits@aries.apache.org Received: (qmail 56327 invoked by uid 99); 30 Jun 2014 16:56:50 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 30 Jun 2014 16:56:50 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 30 Jun 2014 16:56:40 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 244632388CA1; Mon, 30 Jun 2014 16:55:27 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1606837 [19/27] - in /aries/branches/subsystemsR6: ./ application/ application/application-api/ application/application-bundle/ application/application-converters/ application/application-default-local-platform/ application/application-dep... Date: Mon, 30 Jun 2014 16:55:06 -0000 To: commits@aries.apache.org From: tjwatson@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20140630165527.244632388CA1@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Modified: aries/branches/subsystemsR6/samples/twitter/twitter-itests/src/test/java/org/apache/aries/sample/twitter/itest/TwitterTest.java URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/samples/twitter/twitter-itests/src/test/java/org/apache/aries/sample/twitter/itest/TwitterTest.java?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/samples/twitter/twitter-itests/src/test/java/org/apache/aries/sample/twitter/itest/TwitterTest.java (original) +++ aries/branches/subsystemsR6/samples/twitter/twitter-itests/src/test/java/org/apache/aries/sample/twitter/itest/TwitterTest.java Mon Jun 30 16:54:57 2014 @@ -17,151 +17,188 @@ * under the License. */ package org.apache.aries.sample.twitter.itest; -import static junit.framework.Assert.assertEquals; + +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.ops4j.pax.exam.CoreOptions.equinox; +import static org.ops4j.pax.exam.CoreOptions.composite; +import static org.ops4j.pax.exam.CoreOptions.junitBundles; +import static org.ops4j.pax.exam.CoreOptions.maven; +import static org.ops4j.pax.exam.CoreOptions.mavenBundle; import static org.ops4j.pax.exam.CoreOptions.systemProperty; -import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.vmOption; -import static org.apache.aries.itest.ExtraOptions.testOptions; +import static org.ops4j.pax.exam.CoreOptions.vmOption; +import static org.ops4j.pax.exam.CoreOptions.when; import java.io.BufferedReader; import java.io.File; import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import javax.inject.Inject; + import org.apache.aries.application.DeploymentContent; import org.apache.aries.application.DeploymentMetadata; import org.apache.aries.application.management.AriesApplication; import org.apache.aries.application.management.AriesApplicationContext; import org.apache.aries.application.management.AriesApplicationManager; import org.apache.aries.application.utils.AppConstants; +import org.apache.aries.itest.AbstractIntegrationTest; import org.apache.felix.bundlerepository.Repository; import org.apache.felix.bundlerepository.RepositoryAdmin; import org.junit.Test; import org.junit.runner.RunWith; +import org.ops4j.pax.exam.Configuration; +import org.ops4j.pax.exam.CoreOptions; import org.ops4j.pax.exam.Option; -import org.ops4j.pax.exam.junit.JUnit4TestRunner; -@RunWith(JUnit4TestRunner.class) +import org.ops4j.pax.exam.junit.PaxExam; +import org.ops4j.pax.exam.options.MavenArtifactUrlReference; + +@RunWith(PaxExam.class) public class TwitterTest extends AbstractIntegrationTest { - public static final String CORE_BUNDLE_BY_VALUE = "core.bundle.by.value"; - public static final String CORE_BUNDLE_BY_REFERENCE = "core.bundle.by.reference"; - public static final String TRANSITIVE_BUNDLE_BY_VALUE = "transitive.bundle.by.value"; - public static final String TRANSITIVE_BUNDLE_BY_REFERENCE = "transitive.bundle.by.reference"; - public static final String USE_BUNDLE_BY_REFERENCE = "use.bundle.by.reference"; - public static final String REPO_BUNDLE = "aries.bundle1"; - public static final String HELLO_WORLD_CLIENT_BUNDLE="hello.world.client.bundle"; - public static final String HELLO_WORLD_SERVICE_BUNDLE1="hello.world.service.bundle1"; - public static final String HELLO_WORLD_SERVICE_BUNDLE2="hello.world.service.bundle2"; - - //Test for JIRA-461 which currently fails. - @Test - public void testTwitter() throws Exception - { - // provision against the local runtime - System.setProperty(AppConstants.PROVISON_EXCLUDE_LOCAL_REPO_SYSPROP, "false"); - RepositoryAdmin repositoryAdmin = getOsgiService(RepositoryAdmin.class); - Repository[] repos = repositoryAdmin.listRepositories(); - for (Repository repo : repos) { - repositoryAdmin.removeRepository(repo.getURI()); - } - - - // Use the superclasses' getUrlToEba() method instead of the pax-exam mavenBundle() method because pax-exam is running in a - // diffference bundle which doesn't have visibility to the META-INF/maven/dependencies.properties file used to figure out the - // version of the maven artifact. - URL twitterEbaUrl = getUrlToEba("org.apache.aries.samples.twitter", - "org.apache.aries.samples.twitter.eba"); - URL twitterCommonLangJar_url = getUrlToBundle("commons-lang", "commons-lang"); - URL twitterJar_url = getUrlToBundle("org.apache.aries.samples.twitter", "org.apache.aries.samples.twitter.twitter4j"); - - // add the repository xml to the repository admin - StringBuilder repositoryXML = new StringBuilder(); - BufferedReader reader = new BufferedReader(new InputStreamReader(this.getClass().getResourceAsStream("/obr/twitter/TwitterRepository.xml"))); - String line; - while ((line = reader.readLine()) != null) { - repositoryXML.append(line); - repositoryXML.append("\r\n"); - } - //replace the jar file url with the real url related to the environment - String repo = repositoryXML.toString().replaceAll("commons.lang.location", twitterCommonLangJar_url.toExternalForm()); - repo = repo.replaceAll("twitter4j.location", twitterJar_url.toExternalForm()); - - FileWriter writer = new FileWriter("twitterRepo.xml"); - writer.write(repo); - writer.close(); - repositoryAdmin.addRepository(new File("twitterRepo.xml").toURI().toURL()); - AriesApplicationManager manager = getOsgiService(AriesApplicationManager.class); - AriesApplication app = manager.createApplication(twitterEbaUrl); - app = manager.resolve(app); - DeploymentMetadata depMeta = app.getDeploymentMetadata(); - List provision = depMeta.getApplicationProvisionBundles(); - Collection useBundles = depMeta.getDeployedUseBundle(); - Collection appContent = depMeta.getApplicationDeploymentContents(); - // We cannot be sure whether there are two or three provision bundles pulled in by Felix OBR as there is an outstanding defect - // https://issues.apache.org/jira/browse/FELIX-2672 - // The workaround is to check we get the two bundles we are looking for, instead of insisting on just having two bundles. - - List provisionBundleSymbolicNames = new ArrayList(); - for (DeploymentContent dep : provision) { - provisionBundleSymbolicNames.add(dep.getContentName()); - } - String provision_bundle1 = "org.apache.commons.lang"; - String provision_bundle2 = "twitter4j"; - assertTrue("Bundle " + provision_bundle1 + " not found.", provisionBundleSymbolicNames.contains(provision_bundle1)); - assertTrue("Bundle " + provision_bundle2 + " not found.", provisionBundleSymbolicNames.contains(provision_bundle2)); - assertEquals(useBundles.toString(), 0, useBundles.size()); - assertEquals(appContent.toString(), 1, appContent.size()); - AriesApplicationContext ctx = manager.install(app); - ctx.start(); - } - - @org.ops4j.pax.exam.junit.Configuration - public static Option[] configuration() { - Option[] options = testOptions( - // Log - mavenBundle("org.ops4j.pax.logging", "pax-logging-api"), - mavenBundle("org.ops4j.pax.logging", "pax-logging-service"), - // Felix Config Admin - mavenBundle("org.apache.felix", "org.apache.felix.configadmin"), - // Felix mvn url handler - mavenBundle("org.ops4j.pax.url", "pax-url-mvn"), - - // this is how you set the default log level when using pax - // logging (logProfile) - systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("DEBUG"), - - // Bundles - mavenBundle("org.apache.aries.application", "org.apache.aries.application.api"), - mavenBundle("org.apache.aries.application", "org.apache.aries.application.utils"), - mavenBundle("org.apache.aries.application", "org.apache.aries.application.management"), - mavenBundle("org.apache.aries.application", "org.apache.aries.application.default.local.platform"), - mavenBundle("org.apache.aries.application", "org.apache.aries.application.runtime"), - mavenBundle("org.apache.aries.application", "org.apache.aries.application.resolver.obr"), - mavenBundle("org.apache.aries.application", "org.apache.aries.application.deployment.management"), - mavenBundle("org.apache.aries.application", "org.apache.aries.application.modeller"), - mavenBundle("org.apache.felix", "org.apache.felix.bundlerepository"), - mavenBundle("org.apache.aries.application", "org.apache.aries.application.runtime.itest.interfaces"), - mavenBundle("org.apache.aries", "org.apache.aries.util"), - mavenBundle("org.apache.aries.blueprint", "org.apache.aries.blueprint"), - mavenBundle("org.ow2.asm", "asm-all"), - mavenBundle("org.apache.aries.proxy", "org.apache.aries.proxy"), - mavenBundle("org.osgi", "org.osgi.compendium"), - mavenBundle("org.apache.aries.testsupport", "org.apache.aries.testsupport.unit"), - /* For debugging, uncomment the next two lines */ - /*vmOption ("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5010"), - waitForFrameworkStartup(), */ -// vmOption ("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5010"), - /* For debugging, add these imports: - import static org.ops4j.pax.exam.CoreOptions.waitForFrameworkStartup; - import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.vmOption; - */ - - equinox().version("3.5.0")); - return options; - } + public static final String CORE_BUNDLE_BY_VALUE = "core.bundle.by.value"; + public static final String CORE_BUNDLE_BY_REFERENCE = "core.bundle.by.reference"; + public static final String TRANSITIVE_BUNDLE_BY_VALUE = "transitive.bundle.by.value"; + public static final String TRANSITIVE_BUNDLE_BY_REFERENCE = "transitive.bundle.by.reference"; + public static final String USE_BUNDLE_BY_REFERENCE = "use.bundle.by.reference"; + public static final String REPO_BUNDLE = "aries.bundle1"; + public static final String HELLO_WORLD_CLIENT_BUNDLE="hello.world.client.bundle"; + public static final String HELLO_WORLD_SERVICE_BUNDLE1="hello.world.service.bundle1"; + public static final String HELLO_WORLD_SERVICE_BUNDLE2="hello.world.service.bundle2"; + + @Inject + RepositoryAdmin repositoryAdmin; + + @Inject + AriesApplicationManager manager; + + /** + * Test for ARIES-461 + * Application that bring in dependency bundles from a bundle repository doesn't deploy + * + * @throws Exception + */ + @Test + public void testTwitter() throws Exception + { + // provision against the local runtime + System.setProperty(AppConstants.PROVISON_EXCLUDE_LOCAL_REPO_SYSPROP, "false"); + + deleteRepos(); + + MavenArtifactUrlReference twitterEbaUrl = maven("org.apache.aries.samples.twitter", "org.apache.aries.samples.twitter.eba").versionAsInProject().type("eba"); + MavenArtifactUrlReference twitterCommonLangJar = maven("commons-lang", "commons-lang").versionAsInProject(); + MavenArtifactUrlReference twitterJar = maven("org.apache.aries.samples.twitter", "org.apache.aries.samples.twitter.twitter4j").versionAsInProject(); + + // add the repository xml to the repository admin + String repositoryXML = getRepoContent("/obr/twitter/TwitterRepository.xml"); + // replace the jar file url with the real url related to the environment + String repo = repositoryXML + .replaceAll("commons.lang.location", twitterCommonLangJar.getURL()) + .replaceAll("twitter4j.location", twitterJar.getURL()); + + URL url = getRepoUrl(repo); + repositoryAdmin.addRepository(url); + + AriesApplication app = manager.createApplication(new URL(twitterEbaUrl.getURL())); + app = manager.resolve(app); + DeploymentMetadata depMeta = app.getDeploymentMetadata(); + List provision = depMeta.getApplicationProvisionBundles(); + Collection useBundles = depMeta.getDeployedUseBundle(); + Collection appContent = depMeta.getApplicationDeploymentContents(); + // We cannot be sure whether there are two or three provision bundles pulled in by Felix OBR as there is an outstanding defect + // https://issues.apache.org/jira/browse/FELIX-2672 + // The workaround is to check we get the two bundles we are looking for, instead of insisting on just having two bundles. + + List provisionBundleSymbolicNames = new ArrayList(); + for (DeploymentContent dep : provision) { + provisionBundleSymbolicNames.add(dep.getContentName()); + } + String provision_bundle1 = "org.apache.commons.lang"; + String provision_bundle2 = "twitter4j"; + assertTrue("Bundle " + provision_bundle1 + " not found.", provisionBundleSymbolicNames.contains(provision_bundle1)); + assertTrue("Bundle " + provision_bundle2 + " not found.", provisionBundleSymbolicNames.contains(provision_bundle2)); + assertEquals(useBundles.toString(), 0, useBundles.size()); + assertEquals(appContent.toString(), 1, appContent.size()); + AriesApplicationContext ctx = manager.install(app); + ctx.start(); + } + + private URL getRepoUrl(String repo) throws IOException, + MalformedURLException { + File repoFile = File.createTempFile("twitterRepo", "xml"); + FileWriter writer = new FileWriter(repoFile); + writer.write(repo); + writer.close(); + return repoFile.toURI().toURL(); + } + + private void deleteRepos() { + Repository[] repos = repositoryAdmin.listRepositories(); + for (Repository repo : repos) { + repositoryAdmin.removeRepository(repo.getURI()); + } + } + + private String getRepoContent(String path) throws IOException { + StringBuilder repositoryXML = new StringBuilder(); + InputStream resourceAsStream = this.getClass().getResourceAsStream(path); + BufferedReader reader = new BufferedReader(new InputStreamReader(resourceAsStream)); + String line; + while ((line = reader.readLine()) != null) { + repositoryXML.append(line); + repositoryXML.append("\r\n"); + } + return repositoryXML.toString(); + } + + protected Option baseOptions() { + String localRepo = System.getProperty("maven.repo.local"); + + if (localRepo == null) { + localRepo = System.getProperty("org.ops4j.pax.url.mvn.localRepository"); + } + return composite( + junitBundles(), + mavenBundle("org.ops4j.pax.logging", "pax-logging-api", "1.7.2"), + mavenBundle("org.ops4j.pax.logging", "pax-logging-service", "1.7.2"), + mavenBundle("org.apache.aries.testsupport", "org.apache.aries.testsupport.unit").versionAsInProject(), + // this is how you set the default log level when using pax + // logging (logProfile) + systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"), + when(localRepo != null).useOptions(vmOption("-Dorg.ops4j.pax.url.mvn.localRepository=" + localRepo)) + ); + } + + @Configuration + public Option[] configuration() { + return CoreOptions.options( + baseOptions(), + mavenBundle("org.osgi", "org.osgi.compendium").versionAsInProject(), + mavenBundle("org.apache.aries.application", "org.apache.aries.application.api").versionAsInProject(), + mavenBundle("org.apache.aries.application", "org.apache.aries.application.utils").versionAsInProject(), + mavenBundle("org.apache.aries.application", "org.apache.aries.application.management").versionAsInProject(), + mavenBundle("org.apache.aries.application", "org.apache.aries.application.default.local.platform").versionAsInProject(), + mavenBundle("org.apache.aries.application", "org.apache.aries.application.runtime").versionAsInProject(), + mavenBundle("org.apache.aries.application", "org.apache.aries.application.resolver.obr").versionAsInProject(), + mavenBundle("org.apache.aries.application", "org.apache.aries.application.deployment.management").versionAsInProject(), + mavenBundle("org.apache.aries.application", "org.apache.aries.application.modeller").versionAsInProject(), + mavenBundle("org.apache.felix", "org.apache.felix.bundlerepository").versionAsInProject(), + mavenBundle("org.apache.aries.application", "org.apache.aries.application.runtime.itest.interfaces").versionAsInProject(), + mavenBundle("org.apache.aries", "org.apache.aries.util").versionAsInProject(), + mavenBundle("org.apache.aries.blueprint", "org.apache.aries.blueprint").versionAsInProject(), + mavenBundle("org.ow2.asm", "asm-all").versionAsInProject(), + mavenBundle("org.apache.aries.proxy", "org.apache.aries.proxy").versionAsInProject(), + mavenBundle("org.apache.aries.samples.twitter", "org.apache.aries.samples.twitter.twitter4j").versionAsInProject() + + // For debugging + //vmOption ("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5010"), + ); + } } Modified: aries/branches/subsystemsR6/samples/twitter/twitter-twitter4j/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/samples/twitter/twitter-twitter4j/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/samples/twitter/twitter-twitter4j/pom.xml (original) +++ aries/branches/subsystemsR6/samples/twitter/twitter-twitter4j/pom.xml Mon Jun 30 16:54:57 2014 @@ -35,34 +35,21 @@ twitter4j - - - - org.apache.felix - maven-bundle-plugin - 1.4.0 - true - - - ${project.artifactId} - ${project.name} - ${project.version} - *;scope=compile|runtime;inline=true - com.sun.syndication.feed.synd;resolution:=optional,com.sun.syndication.io;resolution:=optional,javax.crypto,javax.crypto.spec,javax.xml.parsers,javax.xml.transform,javax.xml.transform.dom,javax.xml.transform.stream,org.slf4j,org.w3c.dom,org.xml.sax,twitter4j;version="2.0.8" - twitter4j;version=2.0.8 - - - bundle-manifest - process-classes - - manifest - - - - - - - + + + + org.apache.felix + maven-bundle-plugin + 2.3.5 + true + + + dalvik.system;resolution:=optional,* + !twitter4j.examples,* + + + + Modified: aries/branches/subsystemsR6/sandbox/samples/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/sandbox/samples/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/sandbox/samples/pom.xml (original) +++ aries/branches/subsystemsR6/sandbox/samples/pom.xml Mon Jun 30 16:54:57 2014 @@ -19,8 +19,9 @@ org.apache.aries - java5-parent - 0.4-SNAPSHOT + parent + 1.0.1-SNAPSHOT + ../../parent/pom.xml 4.0.0 Modified: aries/branches/subsystemsR6/spi-fly/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/pom.xml Mon Jun 30 16:54:57 2014 @@ -10,8 +10,6 @@ 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 @@ -19,13 +17,15 @@ specific language governing permissions and limitations under the License. --> - + + 4.0.0 + org.apache.aries - java6-parent - 1.0.0 + parent + 2.0.0-SNAPSHOT + ../parent/pom.xml org.apache.aries.spifly @@ -33,11 +33,10 @@ Apache Aries SPI Fly 1.0.0-SNAPSHOT pom - SPI support for OSGi - + scm:svn:http://svn.apache.org/repos/asf/aries/trunk/spi-fly scm:svn:https://svn.apache.org/repos/asf/aries/trunk/spi-fly @@ -52,4 +51,5 @@ spi-fly-static-bundle spi-fly-examples + Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-core/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-core/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-core/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-core/pom.xml Mon Jun 30 16:54:57 2014 @@ -1,5 +1,5 @@ - +--> + 4.0.0 + org.apache.aries - java6-parent - 1.0.0 + parent + 2.0.0-SNAPSHOT + ../../parent/pom.xml org.apache.aries.spifly @@ -31,11 +34,11 @@ jar Apache Aries SPI Fly Core (internal module) -This bundle contains an extender that facilitates the use -of JRE SPI providers (components typically plugged in to the -JRE through META-INF/services resources). + This bundle contains an extender that facilitates the use + of JRE SPI providers (components typically plugged in to the + JRE through META-INF/services resources). - + scm:svn:http://svn.apache.org/repos/asf/aries/trunk/spi-fly/spi-fly-core scm:svn:https://svn.apache.org/repos/asf/aries/trunk/spi-fly/spi-fly-core @@ -53,7 +56,7 @@ JRE through META-INF/services resources) org.osgi org.osgi.compendium provided - + org.apache.aries @@ -70,8 +73,9 @@ JRE through META-INF/services resources) org.easymock easymock - 3.0 + 3.2 test + Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/Util.java URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/Util.java?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/Util.java (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/main/java/org/apache/aries/spifly/Util.java Mon Jun 30 16:54:57 2014 @@ -72,6 +72,11 @@ public class Util { } public static void fixContextClassloader(String cls, String method, Class clsArg, ClassLoader bundleLoader) { + if (BaseActivator.activator == null) { + // The system is not yet initialized. We can't do anything. + return; + } + if (!(bundleLoader instanceof BundleReference)) { BaseActivator.activator.log(LogService.LOG_WARNING, "Classloader of consuming bundle doesn't implement BundleReference: " + bundleLoader); return; Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerGenericCapabilityTest.java URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerGenericCapabilityTest.java?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerGenericCapabilityTest.java (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/ProviderBundleTrackerCustomizerGenericCapabilityTest.java Mon Jun 30 16:54:57 2014 @@ -43,7 +43,10 @@ import org.apache.aries.spifly.impl4.MyS import org.apache.aries.spifly.impl4.MySPIImpl4c; import org.easymock.EasyMock; import org.easymock.IAnswer; +import org.easymock.IExpectationSetters; + import org.junit.Test; + import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; @@ -441,18 +444,21 @@ public class ProviderBundleTrackerCustom private BundleContext mockSPIBundleContext4() { BundleContext implBC = EasyMock.createNiceMock(BundleContext.class); - EasyMock.expect(implBC.registerService((String) EasyMock.anyObject(), EasyMock.anyObject(), (Dictionary)EasyMock.anyObject())). - andAnswer(new IAnswer() { - @Override - public ServiceRegistration answer() throws Throwable { - final String className = (String) EasyMock.getCurrentArguments()[0]; - final Object serviceObject = EasyMock.getCurrentArguments()[1]; - final Dictionary registrationProps = - (Dictionary) EasyMock.getCurrentArguments()[2]; - return new ServiceRegistrationImpl(className, serviceObject, registrationProps); - } - }).anyTimes(); - EasyMock.expect(implBC.getService(EasyMock.anyObject(ServiceReference.class))). + implBC.registerService(EasyMock.anyString(), + EasyMock.anyObject(), + (Dictionary)EasyMock.anyObject()); + EasyMock.expectLastCall().andAnswer(new IAnswer>() { + @Override + public ServiceRegistration answer() throws Throwable { + final String className = (String) EasyMock.getCurrentArguments()[0]; + final Object serviceObject = EasyMock.getCurrentArguments()[1]; + final Dictionary registrationProps = + (Dictionary) EasyMock.getCurrentArguments()[2]; + return new ServiceRegistrationImpl(className, serviceObject, registrationProps); + } + }).anyTimes(); + implBC.getService(EasyMock.anyObject(ServiceReference.class)); + EasyMock.expectLastCall(). andAnswer(new IAnswer() { @Override public Object answer() throws Throwable { @@ -499,7 +505,7 @@ public class ProviderBundleTrackerCustom return implBundle; } - private static class ServiceRegistrationImpl implements ServiceRegistration, ServiceReference { + private static class ServiceRegistrationImpl implements ServiceRegistration, ServiceReference { private final Object serviceObject; private final Dictionary properties; @@ -514,12 +520,12 @@ public class ProviderBundleTrackerCustom } @Override - public ServiceReference getReference() { + public ServiceReference getReference() { return this; } @Override - public void setProperties(@SuppressWarnings("rawtypes") Dictionary properties) { + public void setProperties(Dictionary properties) { throw new UnsupportedOperationException(); } Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/UtilTest.java URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/UtilTest.java?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/UtilTest.java (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-core/src/test/java/org/apache/aries/spifly/UtilTest.java Mon Jun 30 16:54:57 2014 @@ -78,13 +78,15 @@ public class UtilTest { Bundle providerBundle = EasyMock.createMock(Bundle.class); final ClassLoader providerCL = new TestBundleClassLoader(new URL [] {url}, getClass().getClassLoader(), providerBundle); + EasyMock.expect(providerBundle.getBundleContext()).andThrow(new IllegalStateException("Disable getBundleClassLoaderViaAdapt")); EasyMock.expect(providerBundle.getBundleId()).andReturn(42L).anyTimes(); EasyMock.expect(providerBundle.getEntryPaths((String) EasyMock.anyObject())).andReturn(null).anyTimes(); Dictionary providerHeaders = new Hashtable(); providerHeaders.put(Constants.BUNDLE_CLASSPATH, ".,embedded3.jar"); EasyMock.expect(providerBundle.getHeaders()).andReturn(providerHeaders).anyTimes(); EasyMock.expect(providerBundle.getResource("embedded3.jar")).andReturn(url).anyTimes(); - EasyMock.expect(providerBundle.loadClass((String) EasyMock.anyObject())).andAnswer(new IAnswer>() { + providerBundle.loadClass((String) EasyMock.anyObject()); + EasyMock.expectLastCall().andAnswer(new IAnswer>() { @Override public Class answer() throws Throwable { return providerCL.loadClass((String) EasyMock.getCurrentArguments()[0]); @@ -102,6 +104,40 @@ public class UtilTest { assertSame(providerCL, Thread.currentThread().getContextClassLoader()); } + @Test + public void testNotInitialized() throws Exception { + BaseActivator.activator = null; + + URL url = getClass().getResource("/embedded3.jar"); + assertNotNull("precondition", url); + + Bundle providerBundle = EasyMock.createMock(Bundle.class); + final ClassLoader providerCL = new TestBundleClassLoader(new URL [] {url}, getClass().getClassLoader(), providerBundle); + EasyMock.expect(providerBundle.getBundleId()).andReturn(42L).anyTimes(); + EasyMock.expect(providerBundle.getEntryPaths((String) EasyMock.anyObject())).andReturn(null).anyTimes(); + Dictionary providerHeaders = new Hashtable(); + providerHeaders.put(Constants.BUNDLE_CLASSPATH, ".,embedded3.jar"); + EasyMock.expect(providerBundle.getHeaders()).andReturn(providerHeaders).anyTimes(); + EasyMock.expect(providerBundle.getResource("embedded3.jar")).andReturn(url).anyTimes(); + providerBundle.loadClass((String) EasyMock.anyObject()); + EasyMock.expectLastCall().andAnswer(new IAnswer>() { + @Override + public Class answer() throws Throwable { + return providerCL.loadClass((String) EasyMock.getCurrentArguments()[0]); + } + }).anyTimes(); + EasyMock.replay(providerBundle); + + Bundle clientBundle = EasyMock.createMock(Bundle.class); + EasyMock.replay(clientBundle); + ClassLoader clientCL = new TestBundleClassLoader(new URL [] {}, getClass().getClassLoader(), clientBundle); + + Thread.currentThread().setContextClassLoader(null); + Util.fixContextClassloader(ServiceLoader.class.getName(), "load", MySPI.class, clientCL); + assertSame("The system is not yet initialized, so the TCCL should not be set", + null, Thread.currentThread().getContextClassLoader()); + } + private static class TestBundleClassLoader extends URLClassLoader implements BundleReference { private final Bundle bundle; Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-dynamic-bundle/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-dynamic-bundle/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-dynamic-bundle/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-dynamic-bundle/pom.xml Mon Jun 30 16:54:57 2014 @@ -1,5 +1,5 @@ - +--> + 4.0.0 + org.apache.aries - java6-parent - 1.0.0 - + parent + 2.0.0-SNAPSHOT + ../../parent/pom.xml org.apache.aries.spifly @@ -32,23 +34,25 @@ bundle Apache Aries SPI Fly Dynamic Weaving Bundle -This bundle contains an extender that facilitates the use -of JRE SPI providers (components typically plugged in to the -JRE through META-INF/services resources). + This bundle contains an extender that facilitates the use + of JRE SPI providers (components typically plugged in to the + JRE through META-INF/services resources). - - + scm:svn:http://svn.apache.org/repos/asf/aries/trunk/spi-fly/spi-fly-dynamic-bundle scm:svn:https://svn.apache.org/repos/asf/aries/trunk/spi-fly/spi-fly-dynamic-bundle http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-dynamic-bundle + + 1.0.0 + org.ow2.asm - asm-all - 4.0 + asm-debug-all + 5.0.3 @@ -58,12 +62,12 @@ JRE through META-INF/services resources) org.osgi - org.osgi.core + org.osgi.core org.osgi - org.osgi.compendium + org.osgi.compendium @@ -73,11 +77,10 @@ JRE through META-INF/services resources) org.apache.aries.spifly.weaver-internal 1.0.1-SNAPSHOT - + org.osgi org.osgi.core - 4.3.0 provided @@ -85,7 +88,7 @@ JRE through META-INF/services resources) org.osgi org.osgi.compendium provided - + junit @@ -119,14 +122,15 @@ JRE through META-INF/services resources) org.apache.aries.spifly.dynamic org.apache.aries.spifly.*;scope=compile;inline=true - osgi.extender;osgi.extender=osgi.serviceloader.registrar,osgi.extender;osgi.extender=osgi.serviceloader.processor + + osgi.extender;osgi.extender=osgi.serviceloader.registrar;version:Version=1.0,osgi.extender;osgi.extender=osgi.serviceloader.processor;version:Version=1.0 + org.apache.aries.versioning org.apache.aries.versioning.plugin - 0.1.0 default-verify @@ -134,12 +138,10 @@ JRE through META-INF/services resources) version-check - - org.apache.aries.spifly:org.apache.aries.spifly.dynamic.bundle:1.0.0 - + Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-examples/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-examples/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-examples/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-examples/pom.xml Mon Jun 30 16:54:57 2014 @@ -10,8 +10,6 @@ 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 @@ -20,12 +18,14 @@ under the License. --> + 4.0.0 + org.apache.aries - java6-parent - 1.0.0 - + parent + 2.0.0-SNAPSHOT + ../../parent/pom.xml org.apache.aries.spifly.examples @@ -33,10 +33,10 @@ Apache Aries SPI Fly Examples 1.0.1-SNAPSHOT pom - SPI examples + scm:svn:http://svn.apache.org/repos/asf/aries/trunk/spi-fly/spi-fly-examples scm:svn:https://svn.apache.org/repos/asf/aries/trunk/spi-fly/spi-fly-examples @@ -51,7 +51,9 @@ spi-fly-example-client1-jar spi-fly-example-client1-bundle spi-fly-example-client2-bundle + spi-fly-example-provider-consumer-bundle spi-fly-example-resource-provider-bundle spi-fly-example-resource-client-bundle + Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-client1-bundle/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-client1-bundle/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-client1-bundle/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-client1-bundle/pom.xml Mon Jun 30 16:54:57 2014 @@ -63,6 +63,7 @@ + 1.0.0 Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-client2-bundle/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-client2-bundle/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-client2-bundle/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-client2-bundle/pom.xml Mon Jun 30 16:54:57 2014 @@ -51,6 +51,7 @@ + 1.0.0 Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-provider1-bundle/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-provider1-bundle/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-provider1-bundle/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-provider1-bundle/pom.xml Mon Jun 30 16:54:57 2014 @@ -52,6 +52,7 @@ + 1.0.0 Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-provider2-bundle/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-provider2-bundle/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-provider2-bundle/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-provider2-bundle/pom.xml Mon Jun 30 16:54:57 2014 @@ -45,6 +45,7 @@ + 1.0.0 Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-resource-client-bundle/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-resource-client-bundle/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-resource-client-bundle/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-resource-client-bundle/pom.xml Mon Jun 30 16:54:57 2014 @@ -44,6 +44,7 @@ + 1.0.0 Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-resource-provider-bundle/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-resource-provider-bundle/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-resource-provider-bundle/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-resource-provider-bundle/pom.xml Mon Jun 30 16:54:57 2014 @@ -38,6 +38,7 @@ + 1.0.0 Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-spi-bundle/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-spi-bundle/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-spi-bundle/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-examples/spi-fly-example-spi-bundle/pom.xml Mon Jun 30 16:54:57 2014 @@ -36,6 +36,7 @@ + 1.0.0 Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-static-bundle/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-static-bundle/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-static-bundle/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-static-bundle/pom.xml Mon Jun 30 16:54:57 2014 @@ -1,5 +1,5 @@ - +--> + 4.0.0 + org.apache.aries - java6-parent - 1.0.0 - + parent + 2.0.0-SNAPSHOT + ../../parent/pom.xml org.apache.aries.spifly @@ -36,12 +38,15 @@ woven using the static weaving done through the org.apache.aries.spifly.static component. - + scm:svn:http://svn.apache.org/repos/asf/aries/trunk/spi-fly/spi-fly-static-bundle scm:svn:https://svn.apache.org/repos/asf/aries/trunk/spi-fly/spi-fly-static-bundle http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static-bundle + + 1.0.0 + @@ -49,18 +54,18 @@ org.apache.aries.spifly.core-internal 1.0.1-SNAPSHOT - + org.osgi org.osgi.core provided - + org.osgi org.osgi.compendium provided - + @@ -80,14 +85,14 @@ org.apache.aries.spifly.staticbundle org.apache.aries.spifly.staticbundle.StaticWeavingActivator - osgi.extender;osgi.extender=osgi.serviceloader.registrar + osgi.extender;osgi.extender=osgi.serviceloader.registrar;version:Version=1.0 + org.apache.aries.versioning org.apache.aries.versioning.plugin - 0.1.0 default-verify @@ -95,12 +100,10 @@ version-check - - org.apache.aries.spifly:org.apache.aries.spifly.static.bundle:1.0.0 - + Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/pom.xml URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/pom.xml?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/pom.xml (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/pom.xml Mon Jun 30 16:54:57 2014 @@ -1,5 +1,5 @@ - +--> + 4.0.0 + org.apache.aries - java6-parent - 1.0.0 - + parent + 2.0.0-SNAPSHOT + ../../parent/pom.xml org.apache.aries.spifly @@ -35,18 +37,17 @@ This tool does the weaving to support SPI ServiceLoader statically. - scm:svn:http://svn.apache.org/repos/asf/aries/trunk/spi-fly/spi-fly-static-tool scm:svn:https://svn.apache.org/repos/asf/aries/trunk/spi-fly/spi-fly-static-tool http://svn.apache.org/viewvc/aries/trunk/spi-fly/spi-fly-static-tool - + org.ow2.asm - asm-all - 4.0 + asm-debug-all + 5.0.3 @@ -65,14 +66,14 @@ org.osgi org.osgi.core - + junit junit test - + - + @@ -95,7 +96,8 @@ - + + Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/Main.java URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/Main.java?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/Main.java (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/src/main/java/org/apache/aries/spifly/statictool/Main.java Mon Jun 30 16:54:57 2014 @@ -1,341 +1,348 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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.spifly.statictool; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Properties; -import java.util.Set; -import java.util.jar.Attributes; -import java.util.jar.JarEntry; -import java.util.jar.JarInputStream; -import java.util.jar.JarOutputStream; -import java.util.jar.Manifest; - -import org.apache.aries.spifly.ConsumerHeaderProcessor; -import org.apache.aries.spifly.SpiFlyConstants; -import org.apache.aries.spifly.Streams; -import org.apache.aries.spifly.Util; -import org.apache.aries.spifly.WeavingData; -import org.apache.aries.spifly.weaver.TCCLSetterVisitor; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassWriter; -import org.osgi.framework.Constants; -import org.osgi.framework.Version; - -public class Main { - private static final String MODIFIED_BUNDLE_SUFFIX = "_spifly.jar"; - private static final String IMPORT_PACKAGE = "Import-Package"; - - public static void usage() { - System.err.println("This tool processes OSGi Bundles that use java.util.ServiceLoader.load() to"); - System.err.println("obtain implementations via META-INF/services. The byte code in the bundles is"); - System.err.println("modified so that the ThreadContextClassLoader is set appropriately for the "); - System.err.println("duration of the java.util.ServiceLoader.load() call."); - System.err.println("To opt-in to this process, bundles need to have the following MANIFEST.MF"); - System.err.println("header set:"); - System.err.println(" " + SpiFlyConstants.SPI_CONSUMER_HEADER + ": *"); - System.err.println("Modified bundles are written out under the following name:"); - System.err.println(" " + MODIFIED_BUNDLE_SUFFIX); - System.err.println(); - System.err.println("Usage: java " + Main.class.getName() + " bundle1.jar bundle2.jar ..."); - System.exit(-1); - } - - public static void main(String ... args) throws Exception { - if (args.length < 1) - usage(); - - for (String arg : args) { - weaveJar(arg); - } - } - - private static void weaveJar(String jarPath) throws Exception { - System.out.println("[SPI Fly Static Tool] Processing: " + jarPath); - - File jarFile = new File(jarPath); - File tempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + jarFile.getName() + "_" + System.currentTimeMillis()); - Manifest manifest = unJar(jarFile, tempDir); - String consumerHeaderVal = manifest.getMainAttributes().getValue(SpiFlyConstants.SPI_CONSUMER_HEADER); - String consumerHeaderKey = null; - if (consumerHeaderVal != null) { - consumerHeaderKey = SpiFlyConstants.SPI_CONSUMER_HEADER; - } else { - consumerHeaderVal = manifest.getMainAttributes().getValue(SpiFlyConstants.REQUIRE_CAPABILITY); - if (consumerHeaderVal != null) { - consumerHeaderKey = SpiFlyConstants.REQUIRE_CAPABILITY; - } - } - - if (consumerHeaderVal != null) { - String bcp = manifest.getMainAttributes().getValue(Constants.BUNDLE_CLASSPATH); - weaveDir(tempDir, consumerHeaderKey, consumerHeaderVal, bcp); - - if (SpiFlyConstants.SPI_CONSUMER_HEADER.equals(consumerHeaderKey)) { - manifest.getMainAttributes().remove(new Attributes.Name(SpiFlyConstants.SPI_CONSUMER_HEADER)); - } else { - // It's SpiFlyConstants.REQUIRE_CAPABILITY - - // Take out the processor requirement, this probably needs to be improved a little bit - String newConsumerHeaderVal = consumerHeaderVal.replaceAll( - "osgi[.]extender;\\s*filter[:][=][\"]?[(]osgi[.]extender[=]osgi[.]serviceloader[.]processor[)][\"]?", ""); - manifest.getMainAttributes().putValue(SpiFlyConstants.REQUIRE_CAPABILITY, newConsumerHeaderVal); - } - manifest.getMainAttributes().putValue(SpiFlyConstants.PROCESSED_SPI_CONSUMER_HEADER, consumerHeaderVal); - - // TODO if new packages needed then... - extendImportPackage(manifest); - - File newJar = getNewJarFile(jarFile); - jar(newJar, tempDir, manifest); - } else { - System.out.println("[SPI Fly Static Tool] This file is not marked as an SPI Consumer."); - } - delTree(tempDir); - } - - private static void extendImportPackage(Manifest manifest) throws IOException { - String utilPkgVersion = getPackageVersion(Util.class); - - Version osgiVersion = Version.parseVersion(utilPkgVersion); - - Version minVersion = new Version(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro()); - Version maxVersion = new Version(osgiVersion.getMajor(), osgiVersion.getMinor() + 1, 0); - - String ip = manifest.getMainAttributes().getValue(IMPORT_PACKAGE); - if (ip == null) - ip = ""; - - StringBuilder sb = new StringBuilder(ip); - if (ip.length() > 0) - sb.append(","); - sb.append(Util.class.getPackage().getName()); - sb.append(";version=\"["); - sb.append(minVersion); - sb.append(","); - sb.append(maxVersion); - sb.append(")\""); - manifest.getMainAttributes().putValue(IMPORT_PACKAGE, sb.toString()); - } - - private static String getPackageVersion(Class clazz) throws IOException { - URL url = clazz.getResource("packageinfo"); - if (url == null) { - throw new RuntimeException("'packageinfo' file with version information not found for package: " - + clazz.getPackage().getName()); - } - - byte[] bytes = Streams.suck(url.openStream()); - Properties p = new Properties(); - p.load(new ByteArrayInputStream(bytes)); - return p.getProperty("version"); - } - - private static File getNewJarFile(File jarFile) { - String s = jarFile.getAbsolutePath(); - int idx = s.lastIndexOf('.'); - s = s.substring(0, idx); - s += MODIFIED_BUNDLE_SUFFIX; - return new File(s); - } - - private static void weaveDir(File dir, String consumerHeaderKey, String consumerHeaderValue, String bundleClassPath) throws Exception { - Set wd = ConsumerHeaderProcessor.processHeader(consumerHeaderKey, consumerHeaderValue); - - URLClassLoader cl = new URLClassLoader(new URL [] {dir.toURI().toURL()}, Main.class.getClassLoader()); - String dirName = dir.getAbsolutePath(); - - DirTree dt = new DirTree(dir); - for (File f : dt.getFiles()) { - if (!f.getName().endsWith(".class")) - continue; - - String className = f.getAbsolutePath().substring(dirName.length()); - if (className.startsWith(File.separator)) - className = className.substring(1); - className = className.substring(0, className.length() - ".class".length()); - className = className.replace(File.separator, "."); - - InputStream is = new FileInputStream(f); - byte[] b; - try { - ClassReader cr = new ClassReader(is); - ClassWriter cw = new StaticToolClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES, cl); - TCCLSetterVisitor cv = new TCCLSetterVisitor(cw, className, wd); - cr.accept(cv, ClassReader.SKIP_FRAMES); - if (cv.isWoven()) { - b = cw.toByteArray(); - } else { - // if not woven, store the original bytes - b = Streams.suck(new FileInputStream(f)); - } - } finally { - is.close(); - } - - OutputStream os = new FileOutputStream(f); - try { - os.write(b); - } finally { - os.close(); - } - } - - if (bundleClassPath != null) { - for (String entry : bundleClassPath.split(",")) { - File jarFile = new File(dir, entry.trim()); - if (jarFile.isFile()) { - weaveBCPJar(jarFile, consumerHeaderKey, consumerHeaderValue); - } - } - } - } - - private static void weaveBCPJar(File jarFile, String consumerHeaderKey, String consumerHeaderVal) throws Exception { - File tempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + jarFile.getName() + "_" + System.currentTimeMillis()); - try { - Manifest manifest = unJar(jarFile, tempDir); - weaveDir(tempDir, consumerHeaderKey, consumerHeaderVal, null); - if (!jarFile.delete()) { - throw new IOException("Could not replace file: " + jarFile); - } - - jar(jarFile, tempDir, manifest); - } finally { - delTree(tempDir); - } - } - - static Manifest unJar(File jarFile, File tempDir) throws IOException { - ensureDirectory(tempDir); - - JarInputStream jis = new JarInputStream(new FileInputStream(jarFile)); - JarEntry je = null; - while((je = jis.getNextJarEntry()) != null) { - if (je.isDirectory()) { - File outDir = new File(tempDir, je.getName()); - ensureDirectory(outDir); - - continue; - } - - File outFile = new File(tempDir, je.getName()); - File outDir = outFile.getParentFile(); - ensureDirectory(outDir); - - OutputStream out = new FileOutputStream(outFile); - try { - Streams.pump(jis, out); - } finally { - out.flush(); - out.close(); - jis.closeEntry(); - } - outFile.setLastModified(je.getTime()); - } - - Manifest manifest = jis.getManifest(); - if (manifest != null) { - File mf = new File(tempDir, "META-INF/MANIFEST.MF"); - File mfDir = mf.getParentFile(); - ensureDirectory(mfDir); - - OutputStream out = new FileOutputStream(mf); - try { - manifest.write(out); - } finally { - out.flush(); - out.close(); - } - } - - jis.close(); - return manifest; - } - - static void jar(File jarFile, File rootFile, Manifest manifest) throws IOException { - JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile), manifest); - try { - addToJarRecursively(jos, rootFile.getAbsoluteFile(), rootFile.getAbsolutePath()); - } finally { - jos.close(); - } - } - - static void addToJarRecursively(JarOutputStream jar, File source, String rootDirectory) throws IOException { - String sourceName = source.getAbsolutePath().replace("\\", "/"); - sourceName = sourceName.substring(rootDirectory.length()); - - if (sourceName.startsWith("/")) { - sourceName = sourceName.substring(1); - } - - if ("META-INF/MANIFEST.MF".equals(sourceName)) - return; - - if (source.isDirectory()) { - /* Is there any point in adding a directory beyond just taking up space? - if (!sourceName.isEmpty()) { - if (!sourceName.endsWith("/")) { - sourceName += "/"; - } - JarEntry entry = new JarEntry(sourceName); - jar.putNextEntry(entry); - jar.closeEntry(); - } - */ - for (File nested : source.listFiles()) { - addToJarRecursively(jar, nested, rootDirectory); - } - return; - } - - JarEntry entry = new JarEntry(sourceName); - jar.putNextEntry(entry); - InputStream is = new FileInputStream(source); - try { - Streams.pump(is, jar); - } finally { - jar.closeEntry(); - is.close(); - } - } - - static void delTree(File tempDir) throws IOException { - for (File f : new DirTree(tempDir).getFiles()) { - if (!f.delete()) - throw new IOException("Problem deleting file: " + tempDir.getAbsolutePath()); - } - } - - private static void ensureDirectory(File outDir) throws IOException { - if (!outDir.isDirectory()) - if (!outDir.mkdirs()) - throw new IOException("Unable to create directory " + outDir.getAbsolutePath()); - } -} - +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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.spifly.statictool; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Properties; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; + +import org.apache.aries.spifly.ConsumerHeaderProcessor; +import org.apache.aries.spifly.SpiFlyConstants; +import org.apache.aries.spifly.Streams; +import org.apache.aries.spifly.Util; +import org.apache.aries.spifly.WeavingData; +import org.apache.aries.spifly.weaver.TCCLSetterVisitor; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.osgi.framework.Constants; +import org.osgi.framework.Version; + +public class Main { + private static final String MODIFIED_BUNDLE_SUFFIX = "_spifly.jar"; + private static final String IMPORT_PACKAGE = "Import-Package"; + + public static void usage() { + System.err.println("This tool processes OSGi Bundles that use java.util.ServiceLoader.load() to"); + System.err.println("obtain implementations via META-INF/services. The byte code in the bundles is"); + System.err.println("modified so that the ThreadContextClassLoader is set appropriately for the "); + System.err.println("duration of the java.util.ServiceLoader.load() call."); + System.err.println("To opt-in to this process, bundles need to have the following MANIFEST.MF"); + System.err.println("header set:"); + System.err.println(" " + SpiFlyConstants.SPI_CONSUMER_HEADER + ": *"); + System.err.println("Modified bundles are written out under the following name:"); + System.err.println(" " + MODIFIED_BUNDLE_SUFFIX); + System.err.println(); + System.err.println("Usage: java " + Main.class.getName() + " bundle1.jar bundle2.jar ..."); + System.exit(-1); + } + + public static void main(String ... args) throws Exception { + if (args.length < 1) + usage(); + + for (String arg : args) { + weaveJar(arg); + } + } + + private static void weaveJar(String jarPath) throws Exception { + System.out.println("[SPI Fly Static Tool] Processing: " + jarPath); + + File jarFile = new File(jarPath); + File tempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + jarFile.getName() + "_" + System.currentTimeMillis()); + Manifest manifest = unJar(jarFile, tempDir); + String consumerHeaderVal = manifest.getMainAttributes().getValue(SpiFlyConstants.SPI_CONSUMER_HEADER); + String consumerHeaderKey = null; + if (consumerHeaderVal != null) { + consumerHeaderKey = SpiFlyConstants.SPI_CONSUMER_HEADER; + } else { + consumerHeaderVal = manifest.getMainAttributes().getValue(SpiFlyConstants.REQUIRE_CAPABILITY); + if (consumerHeaderVal != null) { + consumerHeaderKey = SpiFlyConstants.REQUIRE_CAPABILITY; + } + } + + if (consumerHeaderVal != null) { + String bcp = manifest.getMainAttributes().getValue(Constants.BUNDLE_CLASSPATH); + weaveDir(tempDir, consumerHeaderKey, consumerHeaderVal, bcp); + + if (SpiFlyConstants.SPI_CONSUMER_HEADER.equals(consumerHeaderKey)) { + manifest.getMainAttributes().remove(new Attributes.Name(SpiFlyConstants.SPI_CONSUMER_HEADER)); + manifest.getMainAttributes().putValue(SpiFlyConstants.PROCESSED_SPI_CONSUMER_HEADER, consumerHeaderVal); + } else { + // It's SpiFlyConstants.REQUIRE_CAPABILITY + + // Take out the processor requirement, this probably needs to be improved a little bit + String newConsumerHeaderVal = consumerHeaderVal.replaceAll( + "osgi[.]extender;\\s*filter[:][=][\"]?[(]osgi[.]extender[=]osgi[.]serviceloader[.]processor[)][\"]?", ""). + trim(); + if (newConsumerHeaderVal.startsWith(",")) + newConsumerHeaderVal = newConsumerHeaderVal.substring(1); + + if (newConsumerHeaderVal.endsWith(",")) + newConsumerHeaderVal = newConsumerHeaderVal.substring(0, newConsumerHeaderVal.length()-1); + manifest.getMainAttributes().putValue(SpiFlyConstants.REQUIRE_CAPABILITY, newConsumerHeaderVal); + manifest.getMainAttributes().putValue("X-SpiFly-Processed-Require-Capability", consumerHeaderVal); + } + + // TODO if new packages needed then... + extendImportPackage(manifest); + + File newJar = getNewJarFile(jarFile); + jar(newJar, tempDir, manifest); + } else { + System.out.println("[SPI Fly Static Tool] This file is not marked as an SPI Consumer."); + } + delTree(tempDir); + } + + private static void extendImportPackage(Manifest manifest) throws IOException { + String utilPkgVersion = getPackageVersion(Util.class); + + Version osgiVersion = Version.parseVersion(utilPkgVersion); + + Version minVersion = new Version(osgiVersion.getMajor(), osgiVersion.getMinor(), osgiVersion.getMicro()); + Version maxVersion = new Version(osgiVersion.getMajor(), osgiVersion.getMinor() + 1, 0); + + String ip = manifest.getMainAttributes().getValue(IMPORT_PACKAGE); + if (ip == null) + ip = ""; + + StringBuilder sb = new StringBuilder(ip); + if (ip.length() > 0) + sb.append(","); + sb.append(Util.class.getPackage().getName()); + sb.append(";version=\"["); + sb.append(minVersion); + sb.append(","); + sb.append(maxVersion); + sb.append(")\""); + manifest.getMainAttributes().putValue(IMPORT_PACKAGE, sb.toString()); + } + + private static String getPackageVersion(Class clazz) throws IOException { + URL url = clazz.getResource("packageinfo"); + if (url == null) { + throw new RuntimeException("'packageinfo' file with version information not found for package: " + + clazz.getPackage().getName()); + } + + byte[] bytes = Streams.suck(url.openStream()); + Properties p = new Properties(); + p.load(new ByteArrayInputStream(bytes)); + return p.getProperty("version"); + } + + private static File getNewJarFile(File jarFile) { + String s = jarFile.getAbsolutePath(); + int idx = s.lastIndexOf('.'); + s = s.substring(0, idx); + s += MODIFIED_BUNDLE_SUFFIX; + return new File(s); + } + + private static void weaveDir(File dir, String consumerHeaderKey, String consumerHeaderValue, String bundleClassPath) throws Exception { + Set wd = ConsumerHeaderProcessor.processHeader(consumerHeaderKey, consumerHeaderValue); + + URLClassLoader cl = new URLClassLoader(new URL [] {dir.toURI().toURL()}, Main.class.getClassLoader()); + String dirName = dir.getAbsolutePath(); + + DirTree dt = new DirTree(dir); + for (File f : dt.getFiles()) { + if (!f.getName().endsWith(".class")) + continue; + + String className = f.getAbsolutePath().substring(dirName.length()); + if (className.startsWith(File.separator)) + className = className.substring(1); + className = className.substring(0, className.length() - ".class".length()); + className = className.replace(File.separator, "."); + + InputStream is = new FileInputStream(f); + byte[] b; + try { + ClassReader cr = new ClassReader(is); + ClassWriter cw = new StaticToolClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES, cl); + TCCLSetterVisitor cv = new TCCLSetterVisitor(cw, className, wd); + cr.accept(cv, ClassReader.SKIP_FRAMES); + if (cv.isWoven()) { + b = cw.toByteArray(); + } else { + // if not woven, store the original bytes + b = Streams.suck(new FileInputStream(f)); + } + } finally { + is.close(); + } + + OutputStream os = new FileOutputStream(f); + try { + os.write(b); + } finally { + os.close(); + } + } + + if (bundleClassPath != null) { + for (String entry : bundleClassPath.split(",")) { + File jarFile = new File(dir, entry.trim()); + if (jarFile.isFile()) { + weaveBCPJar(jarFile, consumerHeaderKey, consumerHeaderValue); + } + } + } + } + + private static void weaveBCPJar(File jarFile, String consumerHeaderKey, String consumerHeaderVal) throws Exception { + File tempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + jarFile.getName() + "_" + System.currentTimeMillis()); + try { + Manifest manifest = unJar(jarFile, tempDir); + weaveDir(tempDir, consumerHeaderKey, consumerHeaderVal, null); + if (!jarFile.delete()) { + throw new IOException("Could not replace file: " + jarFile); + } + + jar(jarFile, tempDir, manifest); + } finally { + delTree(tempDir); + } + } + + static Manifest unJar(File jarFile, File tempDir) throws IOException { + ensureDirectory(tempDir); + + JarInputStream jis = new JarInputStream(new FileInputStream(jarFile)); + JarEntry je = null; + while((je = jis.getNextJarEntry()) != null) { + if (je.isDirectory()) { + File outDir = new File(tempDir, je.getName()); + ensureDirectory(outDir); + + continue; + } + + File outFile = new File(tempDir, je.getName()); + File outDir = outFile.getParentFile(); + ensureDirectory(outDir); + + OutputStream out = new FileOutputStream(outFile); + try { + Streams.pump(jis, out); + } finally { + out.flush(); + out.close(); + jis.closeEntry(); + } + outFile.setLastModified(je.getTime()); + } + + Manifest manifest = jis.getManifest(); + if (manifest != null) { + File mf = new File(tempDir, "META-INF/MANIFEST.MF"); + File mfDir = mf.getParentFile(); + ensureDirectory(mfDir); + + OutputStream out = new FileOutputStream(mf); + try { + manifest.write(out); + } finally { + out.flush(); + out.close(); + } + } + + jis.close(); + return manifest; + } + + static void jar(File jarFile, File rootFile, Manifest manifest) throws IOException { + JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile), manifest); + try { + addToJarRecursively(jos, rootFile.getAbsoluteFile(), rootFile.getAbsolutePath()); + } finally { + jos.close(); + } + } + + static void addToJarRecursively(JarOutputStream jar, File source, String rootDirectory) throws IOException { + String sourceName = source.getAbsolutePath().replace("\\", "/"); + sourceName = sourceName.substring(rootDirectory.length()); + + if (sourceName.startsWith("/")) { + sourceName = sourceName.substring(1); + } + + if ("META-INF/MANIFEST.MF".equals(sourceName)) + return; + + if (source.isDirectory()) { + /* Is there any point in adding a directory beyond just taking up space? + if (!sourceName.isEmpty()) { + if (!sourceName.endsWith("/")) { + sourceName += "/"; + } + JarEntry entry = new JarEntry(sourceName); + jar.putNextEntry(entry); + jar.closeEntry(); + } + */ + for (File nested : source.listFiles()) { + addToJarRecursively(jar, nested, rootDirectory); + } + return; + } + + JarEntry entry = new JarEntry(sourceName); + jar.putNextEntry(entry); + InputStream is = new FileInputStream(source); + try { + Streams.pump(is, jar); + } finally { + jar.closeEntry(); + is.close(); + } + } + + static void delTree(File tempDir) throws IOException { + for (File f : new DirTree(tempDir).getFiles()) { + if (!f.delete()) + throw new IOException("Problem deleting file: " + tempDir.getAbsolutePath()); + } + } + + private static void ensureDirectory(File outDir) throws IOException { + if (!outDir.isDirectory()) + if (!outDir.mkdirs()) + throw new IOException("Unable to create directory " + outDir.getAbsolutePath()); + } +} + Modified: aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/spifly/statictool/RequirementTest.java URL: http://svn.apache.org/viewvc/aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/spifly/statictool/RequirementTest.java?rev=1606837&r1=1606836&r2=1606837&view=diff ============================================================================== --- aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/spifly/statictool/RequirementTest.java (original) +++ aries/branches/subsystemsR6/spi-fly/spi-fly-static-tool/src/test/java/org/apache/aries/spifly/statictool/RequirementTest.java Mon Jun 30 16:54:57 2014 @@ -58,7 +58,7 @@ public class RequirementTest { mainAttributes.putValue("Foo", "Bar Bar"); mainAttributes.putValue("Import-Package", "org.foo.bar"); mainAttributes.putValue(SpiFlyConstants.REQUIRE_CAPABILITY, - "osgi.serviceloader; filter:=\"(osgi.serviceloader=org.apache.aries.spifly.mysvc.SPIProvider)\";cardinality:=multiple," + + "osgi.serviceloader; filter:=\"(osgi.serviceloader=org.apache.aries.spifly.mysvc.SPIProvider)\";cardinality:=multiple, " + "osgi.extender; filter:=\"(osgi.extender=osgi.serviceloader.processor)\""); JarOutputStream jos = new JarOutputStream(new FileOutputStream(jarFile), mf); @@ -76,14 +76,16 @@ public class RequirementTest { Assert.assertTrue("A processed separate bundle should have been created", expectedFile.exists()); // Check manifest in generated bundle. JarFile transformedJarFile = new JarFile(expectedFile); - Manifest expectedMF = transformedJarFile.getManifest(); - Assert.assertEquals("1.0", expectedMF.getMainAttributes().getValue("Manifest-Version")); - Assert.assertEquals("2.0", expectedMF.getMainAttributes().getValue("Bundle-ManifestVersion")); - Assert.assertEquals("testbundle", expectedMF.getMainAttributes().getValue("Bundle-SymbolicName")); - Assert.assertEquals("Bar Bar", expectedMF.getMainAttributes().getValue("Foo")); - Assert.assertEquals("osgi.serviceloader; filter:=\"(osgi.serviceloader=org.apache.aries.spifly.mysvc.SPIProvider)\";cardinality:=multiple,", - expectedMF.getMainAttributes().getValue(SpiFlyConstants.REQUIRE_CAPABILITY)); - String importPackage = expectedMF.getMainAttributes().getValue("Import-Package"); + Manifest actualMF = transformedJarFile.getManifest(); + Assert.assertEquals("1.0", actualMF.getMainAttributes().getValue("Manifest-Version")); + Assert.assertEquals("2.0", actualMF.getMainAttributes().getValue("Bundle-ManifestVersion")); + Assert.assertEquals("testbundle", actualMF.getMainAttributes().getValue("Bundle-SymbolicName")); + Assert.assertEquals("Bar Bar", actualMF.getMainAttributes().getValue("Foo")); + Assert.assertEquals("osgi.serviceloader; filter:=\"(osgi.serviceloader=org.apache.aries.spifly.mysvc.SPIProvider)\";cardinality:=multiple", + actualMF.getMainAttributes().getValue(SpiFlyConstants.REQUIRE_CAPABILITY)); + Assert.assertNull("Should not generate this header when processing Require-Capability", + actualMF.getMainAttributes().getValue(SpiFlyConstants.PROCESSED_SPI_CONSUMER_HEADER)); + String importPackage = actualMF.getMainAttributes().getValue("Import-Package"); Assert.assertTrue( "org.foo.bar,org.apache.aries.spifly;version=\"[1.0.0,1.1.0)\"".equals(importPackage) || "org.apache.aries.spifly;version=\"[1.0.0,1.1.0)\",org.foo.bar".equals(importPackage));