Author: davidb Date: Tue Nov 18 16:27:47 2014 New Revision: 1640381 URL: http://svn.apache.org/r1640381 Log: FELIX-4579 Support Framework Extension Bundle Activators
Unit test included. Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java felix/trunk/framework/src/test/java/org/apache/felix/framework/ExtensionManagerTest.java Modified: felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java?rev=1640381&r1=1640380&r2=1640381&view=diff ============================================================================== --- felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java (original) +++ felix/trunk/framework/src/main/java/org/apache/felix/framework/ExtensionManager.java Tue Nov 18 16:27:47 2014 @@ -19,14 +19,15 @@ package org.apache.felix.framework; import java.io.IOException; -import java.net.InetAddress; import java.io.InputStream; +import java.net.InetAddress; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.security.AllPermission; import java.util.ArrayList; import java.util.Collections; +import java.util.Dictionary; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -36,12 +37,13 @@ import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; import java.util.Set; + +import org.apache.felix.framework.cache.Content; import org.apache.felix.framework.util.FelixConstants; import org.apache.felix.framework.util.ImmutableList; import org.apache.felix.framework.util.StringMap; import org.apache.felix.framework.util.Util; import org.apache.felix.framework.util.manifestparser.ManifestParser; -import org.apache.felix.framework.cache.Content; import org.apache.felix.framework.util.manifestparser.R4Library; import org.apache.felix.framework.wiring.BundleCapabilityImpl; import org.apache.felix.framework.wiring.BundleWireImpl; @@ -249,30 +251,30 @@ class ExtensionManager extends URLStream String osVersion = (String)m_configMap.get(FelixConstants.FRAMEWORK_OS_VERSION); String userLang = (String)m_configMap.get(FelixConstants.FRAMEWORK_LANGUAGE); Map<String, Object> attributes = new HashMap<String, Object>(); - - if( osArchitecture != null ) + + if( osArchitecture != null ) { attributes.put(NativeNamespace.CAPABILITY_PROCESSOR_ATTRIBUTE, osArchitecture); } - + if( osName != null) { attributes.put(NativeNamespace.CAPABILITY_OSNAME_ATTRIBUTE, osName); } - + if( osVersion != null) { attributes.put(NativeNamespace.CAPABILITY_OSVERSION_ATTRIBUTE, new Version(osVersion)); } - - if( userLang != null) + + if( userLang != null) { attributes.put(NativeNamespace.CAPABILITY_LANGUAGE_ATTRIBUTE, userLang); } - + return new BundleCapabilityImpl(getRevision(), NativeNamespace.NATIVE_NAMESPACE, Collections.<String, String> emptyMap(), attributes); } - + private static List<BundleCapability> aliasSymbolicName(List<BundleCapability> caps) { if (caps == null) @@ -463,9 +465,10 @@ class ExtensionManager extends URLStream */ void startExtensionBundle(Felix felix, BundleImpl bundle) { - String activatorClass = (String) - ((BundleRevisionImpl) bundle.adapt(BundleRevision.class)) - .getHeaders().get(FelixConstants.FELIX_EXTENSION_ACTIVATOR); + Dictionary<?,?> headers = bundle.getHeaders(); + String activatorClass = (String) headers.get(Constants.EXTENSION_BUNDLE_ACTIVATOR); + if (activatorClass == null) + activatorClass = (String) headers.get(FelixConstants.FELIX_EXTENSION_ACTIVATOR); if (activatorClass != null) { @@ -491,7 +494,7 @@ class ExtensionManager extends URLStream catch (Throwable ex) { m_logger.log(bundle, Logger.LOG_WARNING, - "Unable to start Felix Extension Activator", ex); + "Unable to start Extension Activator", ex); } } } Modified: felix/trunk/framework/src/test/java/org/apache/felix/framework/ExtensionManagerTest.java URL: http://svn.apache.org/viewvc/felix/trunk/framework/src/test/java/org/apache/felix/framework/ExtensionManagerTest.java?rev=1640381&r1=1640380&r2=1640381&view=diff ============================================================================== --- felix/trunk/framework/src/test/java/org/apache/felix/framework/ExtensionManagerTest.java (original) +++ felix/trunk/framework/src/test/java/org/apache/felix/framework/ExtensionManagerTest.java Tue Nov 18 16:27:47 2014 @@ -1,81 +1,189 @@ -/* - * 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.felix.framework; - -import static org.junit.Assert.*; - -import java.util.HashMap; -import java.util.Map; - -import org.apache.felix.framework.util.FelixConstants; -import org.junit.Test; -import org.osgi.framework.Version; -import org.osgi.framework.namespace.NativeNamespace; -import org.osgi.framework.wiring.BundleCapability; - -/** - * - * Test Classes for the ExtentionManager - * - */ -public class ExtensionManagerTest { - - /** - * - * - * Ensure Native Bundle Capabilities are properly formed based on - * Framework properties. - * - */ - @Test - public void testBuildNativeCapabilities() { - Logger logger = new Logger(); - Map<String, String> configMap = new HashMap<String, String>(); - configMap.put(FelixConstants.FELIX_VERSION_PROPERTY, "1.0"); - configMap.put(FelixConstants.FRAMEWORK_LANGUAGE, "en"); - configMap.put(FelixConstants.FRAMEWORK_PROCESSOR, "x86_64"); - configMap.put(FelixConstants.FRAMEWORK_OS_NAME, "windows8"); - configMap.put(FelixConstants.FRAMEWORK_OS_VERSION, "6.3"); - ExtensionManager extensionManager = new ExtensionManager(logger, - configMap, null); - BundleCapability nativeBundleCapability = extensionManager - .buildNativeCapabilites(); - assertEquals( - "Native Language should be same as framework Language", - "en", - nativeBundleCapability.getAttributes().get( - NativeNamespace.CAPABILITY_LANGUAGE_ATTRIBUTE)); - assertEquals( - "Native Processor should be same as framework Processor", - "x86_64", - nativeBundleCapability.getAttributes().get( - NativeNamespace.CAPABILITY_PROCESSOR_ATTRIBUTE)); - assertEquals( - "Native OS Name should be the same as the framework os name", - "windows8", - nativeBundleCapability.getAttributes().get( - NativeNamespace.CAPABILITY_OSNAME_ATTRIBUTE)); - assertEquals( - "Native OS Version should be the same as the framework OS Version", - new Version("6.3"), - nativeBundleCapability.getAttributes().get( - NativeNamespace.CAPABILITY_OSVERSION_ATTRIBUTE)); - } - -} +/* + * 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.felix.framework; + +import static org.junit.Assert.assertEquals; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.jar.JarOutputStream; +import java.util.jar.Manifest; +import java.util.zip.ZipEntry; + +import org.apache.felix.framework.util.FelixConstants; +import org.junit.Before; +import org.junit.Test; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.framework.Constants; +import org.osgi.framework.Version; +import org.osgi.framework.launch.Framework; +import org.osgi.framework.namespace.NativeNamespace; +import org.osgi.framework.wiring.BundleCapability; + +/** + * + * Test Classes for the ExtentionManager + * + */ +public class ExtensionManagerTest { + private int counter; + private File testDir; + + @Before + public void setUp() throws Exception { + String path = "/" + getClass().getName().replace('.', '/') + ".class"; + String url = getClass().getResource(path).getFile(); + String baseDir = url.substring(0, url.length() - path.length()); + String rndStr = Long.toString(System.nanoTime(), Character.MAX_RADIX); + rndStr = rndStr.substring(rndStr.length() - 6, rndStr.length() - 1); + testDir = new File(baseDir, getClass().getSimpleName() + "_" + rndStr); + } + + /** + * + * + * Ensure Native Bundle Capabilities are properly formed based on + * Framework properties. + * + */ + @Test + public void testBuildNativeCapabilities() { + Logger logger = new Logger(); + Map<String, String> configMap = new HashMap<String, String>(); + configMap.put(FelixConstants.FELIX_VERSION_PROPERTY, "1.0"); + configMap.put(FelixConstants.FRAMEWORK_LANGUAGE, "en"); + configMap.put(FelixConstants.FRAMEWORK_PROCESSOR, "x86_64"); + configMap.put(FelixConstants.FRAMEWORK_OS_NAME, "windows8"); + configMap.put(FelixConstants.FRAMEWORK_OS_VERSION, "6.3"); + ExtensionManager extensionManager = new ExtensionManager(logger, + configMap, null); + BundleCapability nativeBundleCapability = extensionManager + .buildNativeCapabilites(); + assertEquals( + "Native Language should be same as framework Language", + "en", + nativeBundleCapability.getAttributes().get( + NativeNamespace.CAPABILITY_LANGUAGE_ATTRIBUTE)); + assertEquals( + "Native Processor should be same as framework Processor", + "x86_64", + nativeBundleCapability.getAttributes().get( + NativeNamespace.CAPABILITY_PROCESSOR_ATTRIBUTE)); + assertEquals( + "Native OS Name should be the same as the framework os name", + "windows8", + nativeBundleCapability.getAttributes().get( + NativeNamespace.CAPABILITY_OSNAME_ATTRIBUTE)); + assertEquals( + "Native OS Version should be the same as the framework OS Version", + new Version("6.3"), + nativeBundleCapability.getAttributes().get( + NativeNamespace.CAPABILITY_OSVERSION_ATTRIBUTE)); + } + + @Test + public void testExtensionBundleActivator() throws Exception { + File cacheDir = new File(testDir, "cache"); + cacheDir.mkdirs(); + String cache = cacheDir.getAbsolutePath(); + + Map<String, Object> params = new HashMap<String, Object>(); + params.put("felix.cache.profiledir", cache); + params.put("felix.cache.dir", cache); + params.put(Constants.FRAMEWORK_STORAGE, cache); + + Framework framework = new Felix(params); + framework.init(); + framework.start(); + + try { + File ebf = createExtensionBundle(); + + assertEquals("Precondition", 0, activatorCalls.length()); + framework.getBundleContext().installBundle( + ebf.toURI().toURL().toExternalForm()); + + assertEquals("start", activatorCalls.toString()); + } finally { + framework.stop(); + } + + framework.waitForStop(10000); + assertEquals("startstop", activatorCalls.toString()); + } + + private File createExtensionBundle() throws IOException { + File f = File.createTempFile("felix-bundle" + counter++, ".jar", testDir); + + Manifest mf = new Manifest(); + mf.getMainAttributes().putValue("Manifest-Version", "1.0"); + mf.getMainAttributes().putValue(Constants.BUNDLE_SYMBOLICNAME, "extension-bundle"); + mf.getMainAttributes().putValue(Constants.BUNDLE_VERSION, "3.2.1"); + mf.getMainAttributes().putValue(Constants.FRAGMENT_HOST, "system.bundle;extension:=framework"); + mf.getMainAttributes().putValue(Constants.BUNDLE_MANIFESTVERSION, "2"); + mf.getMainAttributes().putValue(Constants.EXTENSION_BUNDLE_ACTIVATOR, TestActivator.class.getName()); + JarOutputStream os = new JarOutputStream(new FileOutputStream(f), mf); + + String path = TestActivator.class.getName().replace('.', '/') + ".class"; + os.putNextEntry(new ZipEntry(path)); + + InputStream is = TestActivator.class.getClassLoader().getResourceAsStream(path); + pumpStreams(is, os); + + is.close(); + os.close(); + return f; + } + + static void pumpStreams(InputStream is, OutputStream os) throws IOException { + byte[] bytes = new byte[16384]; + + int length = 0; + int offset = 0; + + while ((length = is.read(bytes, offset, bytes.length - offset)) != -1) { + offset += length; + + if (offset == bytes.length) { + os.write(bytes, 0, bytes.length); + offset = 0; + } + } + if (offset != 0) { + os.write(bytes, 0, offset); + } + } + + private static StringBuilder activatorCalls = new StringBuilder(); + public static class TestActivator implements BundleActivator { + public void start(BundleContext context) throws Exception { + activatorCalls.append("start"); + } + + public void stop(BundleContext context) throws Exception { + activatorCalls.append("stop"); + } + } +}