Return-Path: Delivered-To: apmail-incubator-felix-commits-archive@www.apache.org Received: (qmail 10261 invoked from network); 1 Sep 2006 19:23:53 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 1 Sep 2006 19:23:53 -0000 Received: (qmail 92869 invoked by uid 500); 1 Sep 2006 19:23:53 -0000 Delivered-To: apmail-incubator-felix-commits-archive@incubator.apache.org Received: (qmail 92822 invoked by uid 500); 1 Sep 2006 19:23:53 -0000 Mailing-List: contact felix-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: felix-dev@incubator.apache.org Delivered-To: mailing list felix-commits@incubator.apache.org Received: (qmail 92811 invoked by uid 99); 1 Sep 2006 19:23:53 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 01 Sep 2006 12:23:53 -0700 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 01 Sep 2006 12:23:51 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id DDF731A981A; Fri, 1 Sep 2006 12:23:30 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r439429 - in /incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework: ./ searchpolicy/ util/ Date: Fri, 01 Sep 2006 19:23:29 -0000 To: felix-commits@incubator.apache.org From: rickhall@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20060901192330.DDF731A981A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: rickhall Date: Fri Sep 1 12:23:28 2006 New Revision: 439429 URL: http://svn.apache.org/viewvc?rev=439429&view=rev Log: Applied patch (FELIX-26) from Arnaud Quiblier to improve the native library selection algorithm. In doing so I realized that there were other issues in our approach, namely that native library verfication was only being performed at execution time but the spec requires some checking at installation time. As a result, I moved a few things around and tried to improve the overall structure in this area of the framework. It is a little better now, but far from perfect. The changes do appear to have improved our score with the TCK, but we are still missing some things that I will document in the JIRA issue. Added: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryClause.java - copied, changed from r439358, incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryHeader.java Removed: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryHeader.java Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Library.java incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/FelixConstants.java incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java?rev=439429&r1=439428&r2=439429&view=diff ============================================================================== --- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java (original) +++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/Felix.java Fri Sep 1 12:23:28 2006 @@ -17,8 +17,10 @@ package org.apache.felix.framework; import java.io.*; -import java.net.*; -import java.security.*; +import java.net.URL; +import java.net.URLStreamHandler; +import java.security.CodeSource; +import java.security.ProtectionDomain; import java.util.*; import org.apache.felix.framework.cache.*; @@ -2573,7 +2575,7 @@ private IModule createModule(long targetId, int revision, Map headerMap) throws Exception { - ManifestParser mp = new ManifestParser(m_logger, headerMap); + ManifestParser mp = new ManifestParser(m_logger, m_config, headerMap); // Verify that the bundle symbolic name and version is unique. if (mp.getVersion().equals("2")) @@ -2610,12 +2612,7 @@ mp.getExports(), mp.getImports(), mp.getDynamicImports(), - mp.getLibraries( - m_cache, - targetId, - revision, - m_config.get(Constants.FRAMEWORK_OS_NAME), - m_config.get(Constants.FRAMEWORK_PROCESSOR))); + mp.getLibraries(m_cache.getArchive(targetId).getRevision(revision))); // Create the module using the module definition. IModule module = m_factory.createModule( @@ -2828,13 +2825,9 @@ System.getProperty("os.version")); String s = null; - s = R4Library.normalizePropertyValue( - FelixConstants.FRAMEWORK_OS_NAME, - System.getProperty("os.name")); + s = R4LibraryClause.normalizeOSName(System.getProperty("os.name")); m_configMutable.put(FelixConstants.FRAMEWORK_OS_NAME, s); - s = R4Library.normalizePropertyValue( - FelixConstants.FRAMEWORK_PROCESSOR, - System.getProperty("os.arch")); + s = R4LibraryClause.normalizeProcessor(System.getProperty("os.arch")); m_configMutable.put(FelixConstants.FRAMEWORK_PROCESSOR, s); m_configMutable.put( FelixConstants.FELIX_VERSION_PROPERTY, getFrameworkVersion()); Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Library.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Library.java?rev=439429&r1=439428&r2=439429&view=diff ============================================================================== --- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Library.java (original) +++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4Library.java Fri Sep 1 12:23:28 2006 @@ -17,142 +17,127 @@ package org.apache.felix.framework.searchpolicy; import org.apache.felix.framework.Logger; -import org.apache.felix.framework.cache.BundleCache; +import org.apache.felix.framework.cache.BundleRevision; +import org.osgi.framework.BundleException; import org.osgi.framework.Constants; public class R4Library { private Logger m_logger = null; - private BundleCache m_cache = null; - private long m_bundleId = -1; - private int m_revision = -1; - private String m_os = null; - private String m_processor = null; - private R4LibraryHeader m_header = null; - - public R4Library( - Logger logger, BundleCache cache, long bundleId, int revision, - String os, String processor, R4LibraryHeader header) + private BundleRevision m_revision = null; + private String m_libraryFile = null; + private String[] m_osnames = null; + private String[] m_processors = null; + private String[] m_osversions = null; + private String[] m_languages = null; + private String m_selectionFilter = null; + + public R4Library(Logger logger, BundleRevision revision, + String libraryFile, String[] osnames, String[] processors, String[] osversions, + String[] languages, String selectionFilter) { m_logger = logger; - m_cache = cache; - m_bundleId = bundleId; m_revision = revision; - m_os = normalizePropertyValue(Constants.FRAMEWORK_OS_NAME, os); - m_processor = normalizePropertyValue(Constants.FRAMEWORK_PROCESSOR, processor); - m_header = header; + m_libraryFile = libraryFile; + m_osnames = osnames; + m_processors = processors; + m_osversions = osversions; + m_languages = languages; + m_selectionFilter = selectionFilter; + } + + public String[] getOSNames() + { + return m_osnames; + } + + public String[] getProcessors() + { + return m_processors; + } + + public String[] getOSVersions() + { + return m_osversions; + } + + public String[] getLanguages() + { + return m_languages; + } + + public String getSelectionFilter() + { + return m_selectionFilter; } /** *

* Returns a file system path to the specified library. *

+ * * @param name the name of the library that is being requested. * @return a file system path to the specified library. - **/ + */ public String getPath(String name) { - if (m_header != null) + String libname = System.mapLibraryName(name); + if (m_libraryFile.indexOf(libname) >= 0) { - String libname = System.mapLibraryName(name); - - // Check to see if the library matches. - boolean osOkay = checkOS(m_header.getOSNames()); - boolean procOkay = checkProcessor(m_header.getProcessors()); - if (m_header.getName().endsWith(libname) && osOkay && procOkay) - { - try { - return m_cache.getArchive(m_bundleId) - .getRevision(m_revision).findLibrary(m_header.getName()); - } catch (Exception ex) { - m_logger.log(Logger.LOG_ERROR, "R4Library: Error finding library.", ex); - } + try + { + return m_revision.findLibrary(m_libraryFile); } - } - - return null; - } - - private boolean checkOS(String[] osnames) - { - for (int i = 0; (osnames != null) && (i < osnames.length); i++) - { - String osname = - normalizePropertyValue(Constants.FRAMEWORK_OS_NAME, osnames[i]); - if (m_os.equals(osname)) + catch (Exception ex) { - return true; + m_logger.log(Logger.LOG_ERROR, "R4Library: Finding library '" + + name + "'.", new BundleException( + "Unable to find native library '" + name + "'.")); } } - return false; + return null; } - private boolean checkProcessor(String[] processors) + public String toString() { - for (int i = 0; (processors != null) && (i < processors.length); i++) + if (m_libraryFile != null) { - String processor = - normalizePropertyValue(Constants.FRAMEWORK_PROCESSOR, processors[i]); - if (m_processor.equals(processor)) + StringBuffer sb = new StringBuffer(); + sb.append(m_libraryFile); + sb.append(';'); + for (int i = 0; (m_osnames != null) && (i < m_osnames.length); i++) { - return true; + sb.append(Constants.BUNDLE_NATIVECODE_OSNAME); + sb.append('='); + sb.append(m_osnames[i]); + sb.append(';'); } - } - return false; - } - - /** - * This is simply a hack to try to create some standardized - * property values, since there seems to be many possible - * values for each JVM implementation. Currently, this - * focuses on Windows and Linux and will certainly need - * to be changed in the future or at least edited. - **/ - public static String normalizePropertyValue(String prop, String value) - { - prop = prop.toLowerCase(); - value = value.toLowerCase(); - - if (prop.equals(Constants.FRAMEWORK_OS_NAME)) - { - if (value.startsWith("linux")) + for (int i = 0; (m_processors != null) && (i < m_processors.length); i++) { - return "linux"; + sb.append(Constants.BUNDLE_NATIVECODE_PROCESSOR); + sb.append(m_processors[i]); + sb.append(';'); } - else if (value.startsWith("win")) + for (int i = 0; (m_osversions != null) && (i < m_osversions.length); i++) { - String os = "win"; - if (value.indexOf("95") >= 0) - { - os = "win95"; - } - else if (value.indexOf("98") >= 0) - { - os = "win98"; - } - else if (value.indexOf("NT") >= 0) - { - os = "winnt"; - } - else if (value.indexOf("2000") >= 0) - { - os = "win2000"; - } - else if (value.indexOf("xp") >= 0) - { - os = "winxp"; - } - return os; + sb.append(Constants.BUNDLE_NATIVECODE_OSVERSION); + sb.append(m_osversions[i]); + sb.append(';'); } - } - else if (prop.equals(Constants.FRAMEWORK_PROCESSOR)) - { - if (value.endsWith("86")) + for (int i = 0; (m_languages != null) && (i < m_languages.length); i++) { - return "x86"; + sb.append(Constants.BUNDLE_NATIVECODE_LANGUAGE); + sb.append(m_languages[i]); + sb.append(';'); } - } + sb.append(Constants.SELECTION_FILTER_ATTRIBUTE); + sb.append('='); + sb.append('\''); + sb.append(m_selectionFilter); + sb.append('\''); - return value; + return sb.toString(); + } + return "*"; } } Copied: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryClause.java (from r439358, incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryHeader.java) URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryClause.java?p2=incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryClause.java&p1=incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryHeader.java&r1=439358&r2=439429&rev=439429&view=diff ============================================================================== --- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryHeader.java (original) +++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4LibraryClause.java Fri Sep 1 12:23:28 2006 @@ -18,39 +18,46 @@ import java.util.*; +import org.apache.felix.framework.FilterImpl; import org.apache.felix.framework.Logger; -import org.osgi.framework.Constants; +import org.apache.felix.framework.util.FelixConstants; +import org.apache.felix.framework.util.PropertyResolver; +import org.osgi.framework.*; -public class R4LibraryHeader +public class R4LibraryClause { - private String m_name = null; + private String[] m_libraryFiles = null; private String[] m_osnames = null; - private String[] m_osversions = null; private String[] m_processors = null; + private String[] m_osversions = null; private String[] m_languages = null; + private String m_selectionFilter = null; - public R4LibraryHeader(String name, String[] osnames, String[] osversions, - String[] processors, String[] languages) + public R4LibraryClause(String[] libraryFiles, String[] osnames, + String[] processors, String[] osversions, String[] languages, + String selectionFilter) { - m_name = name; + m_libraryFiles = libraryFiles; m_osnames = osnames; - m_osversions = osversions; m_processors = processors; + m_osversions = osversions; m_languages = languages; + m_selectionFilter = selectionFilter; } - public R4LibraryHeader(R4LibraryHeader library) + public R4LibraryClause(R4LibraryClause library) { - m_name = library.m_name; + m_libraryFiles = library.m_libraryFiles; m_osnames = library.m_osnames; m_osversions = library.m_osversions; m_processors = library.m_processors; m_languages = library.m_languages; + m_selectionFilter = library.m_selectionFilter; } - public String getName() + public String[] getLibraryFiles() { - return m_name; + return m_libraryFiles; } public String[] getOSNames() @@ -58,17 +65,154 @@ return m_osnames; } + public String[] getProcessors() + { + return m_processors; + } + public String[] getOSVersions() { return m_osversions; } - public String[] getProcessors() + public String[] getLanguages() { - return m_processors; + return m_languages; + } + + public String getSelectionFilter() + { + return m_selectionFilter; + } + + public boolean match(PropertyResolver config) throws BundleException + { + String normal_osname = normalizeOSName(config.get(Constants.FRAMEWORK_OS_NAME)); + String normal_processor = normalizeProcessor(config.get(Constants.FRAMEWORK_PROCESSOR)); + String normal_osversion = normalizeOSVersion(config.get(Constants.FRAMEWORK_OS_VERSION)); + String normal_language = config.get(Constants.FRAMEWORK_LANGUAGE); + + // Check library's osname. + if (!checkOSNames(normal_osname, getOSNames())) + { + return false; + } + + // Check library's processor. + if (!checkProcessors(normal_processor, getProcessors())) + { + return false; + } + + // Check library's osversion if specified. + if ((getOSVersions() != null) && + (getOSVersions().length > 0) && + !checkOSVersions(normal_osversion, getOSVersions())) + { + return false; + } + + // Check library's language if specified. + if ((getLanguages() != null) && + (getLanguages().length > 0) && + !checkLanguages(normal_language, getLanguages())) + { + return false; + } + + // Check library's selection-filter if specified. + if ((getSelectionFilter() != null) && + (getSelectionFilter().length() >= 0) && + !checkSelectionFilter(config, getSelectionFilter())) + { + return false; + } + + return true; + } + + private boolean checkOSNames(String currentOSName, String[] osnames) + { + for (int i = 0; (osnames != null) && (i < osnames.length); i++) + { + if (osnames[i].equals(currentOSName)) + { + return true; + } + } + return false; + } + + private boolean checkProcessors(String currentProcessor, String[] processors) + { + for (int i = 0; (processors != null) && (i < processors.length); i++) + { + if (processors[i].equals(currentProcessor)) + { + return true; + } + } + return false; + } + + private boolean checkOSVersions(String currentOSVersion, String[] osversions) + throws BundleException + { + for (int i = 0; (osversions != null) && (i < osversions.length); i++) + { + try + { + VersionRange range = VersionRange.parse(osversions[i]); + if (range.isInRange(new Version(currentOSVersion))) + { + return true; + } + } + catch (Exception ex) + { + throw new BundleException( + "Error evaluating osversion: " + osversions[i], ex); + } + } + return false; + } + + private boolean checkLanguages(String currentLanguage, String[] languages) + { + for (int i = 0; (languages != null) && (i < languages.length); i++) + { + if (languages[i].equals(currentLanguage)) + { + return true; + } + } + return false; } - public static R4LibraryHeader[] parse(Logger logger, String s) + private boolean checkSelectionFilter(PropertyResolver config, String expr) + throws BundleException + { + // Get all framework properties + Dictionary dict = new Hashtable(); + String[] keys = config.getKeys(); + for (int i = 0; i < keys.length; i++) + { + dict.put(keys[i], config.get(keys[i])); + } + // Compute expression + try + { + FilterImpl filter = new FilterImpl(expr); + return filter.match(dict); + } + catch (Exception ex) + { + throw new BundleException( + "Error evaluating filter expression: " + expr, ex); + } + } + + public static R4LibraryClause parse(Logger logger, String s) { try { @@ -77,15 +221,21 @@ return null; } + if (s.equals(FelixConstants.BUNDLE_NATIVECODE_OPTIONAL)) + { + return new R4LibraryClause(null, null, null, null, null, null); + } + // The tokens are separated by semicolons and may include - // any number of libraries (whose name starts with a "/") - // along with one set of associated properties. + // any number of libraries along with one set of associated + // properties. StringTokenizer st = new StringTokenizer(s, ";"); - String[] libs = new String[st.countTokens()]; + String[] libFiles = new String[st.countTokens()]; List osNameList = new ArrayList(); List osVersionList = new ArrayList(); List processorList = new ArrayList(); List languageList = new ArrayList(); + String selectionFilter = null; int libCount = 0; while (st.hasMoreTokens()) { @@ -93,7 +243,7 @@ if (token.indexOf('=') < 0) { // Remove the slash, if necessary. - libs[libCount] = (token.charAt(0) == '/') + libFiles[libCount] = (token.charAt(0) == '/') ? token.substring(1) : token; libCount++; @@ -102,15 +252,24 @@ { // Check for valid native library properties; defined as // a property name, an equal sign, and a value. - StringTokenizer stProp = new StringTokenizer(token, "="); - if (stProp.countTokens() != 2) + // NOTE: StringTokenizer can not be used here because + // a value can contain one or more "=" too, e.g., + // selection-filter="(org.osgi.framework.windowing.system=gtk)" + String property = null; + String value = null; + if (!(token.indexOf("=") > 1)) { throw new IllegalArgumentException( "Bundle manifest native library entry malformed: " + token); } - String property = stProp.nextToken().trim().toLowerCase(); - String value = stProp.nextToken().trim(); - + else + { + property = (token.substring(0, token.indexOf("="))) + .trim().toLowerCase(); + value = (token.substring(token.indexOf("=") + 1, token + .length())).trim(); + } + // Values may be quoted, so remove quotes if present. if (value.charAt(0) == '"') { @@ -143,6 +302,11 @@ { languageList.add(value); } + else if (property.equals(Constants.SELECTION_FILTER_ATTRIBUTE)) + { +// TODO: NATIVE - I believe we can have multiple selection filters too. + selectionFilter = value; + } } } @@ -151,33 +315,207 @@ return null; } - R4LibraryHeader[] libraries = new R4LibraryHeader[libCount]; - for (int i = 0; i < libCount; i++) + // Shrink lib file array. + String[] actualLibFiles = new String[libCount]; + System.arraycopy(libFiles, 0, actualLibFiles, 0, libCount); + return new R4LibraryClause( + actualLibFiles, + (String[]) osNameList.toArray(new String[0]), + (String[]) processorList.toArray(new String[0]), + (String[]) osVersionList.toArray(new String[0]), + (String[]) languageList.toArray(new String[0]), + selectionFilter); + } + catch (RuntimeException ex) + { + logger.log(Logger.LOG_ERROR, + "Error parsing native library header.", ex); + throw ex; + } + } + + public static String normalizeOSName(String value) + { + if (value.startsWith("win")) + { + String os = "win"; + if (value.indexOf("32") >= 0 || value.indexOf("*") >= 0) { - libraries[i] = - new R4LibraryHeader( - libs[i], - (String[]) osNameList.toArray(new String[0]), - (String[]) osVersionList.toArray(new String[0]), - (String[]) processorList.toArray(new String[0]), - (String[]) languageList.toArray(new String[0])); + os = "win32"; } + else if (value.indexOf("95") >= 0) + { + os = "windows95"; + } + else if (value.indexOf("98") >= 0) + { + os = "windows98"; + } + else if (value.indexOf("nt") >= 0) + { + os = "windowsnt"; + } + else if (value.indexOf("2000") >= 0) + { + os = "windows2000"; + } + else if (value.indexOf("xp") >= 0) + { + os = "windowsxp"; + } + else if (value.indexOf("ce") >= 0) + { + os = "windowsce"; + } + return os; + } + else if (value.startsWith("linux")) + { + return "linux"; + } + else if (value.startsWith("aix")) + { + return "aix"; + } + else if (value.startsWith("digitalunix")) + { + return "digitalunix"; + } + else if (value.startsWith("hpux")) + { + return "hpux"; + } + else if (value.startsWith("irix")) + { + return "irix"; + } + else if (value.startsWith("macos")) + { + return "macos"; + } + else if (value.startsWith("netware")) + { + return "netware"; + } + else if (value.startsWith("openbsd")) + { + return "openbsd"; + } + else if (value.startsWith("netbsd")) + { + return "netbsd"; + } + else if (value.startsWith("os2") || value.startsWith("os/2")) + { + return "os2"; + } + else if (value.startsWith("qnx") || value.startsWith("procnto")) + { + return "qnx"; + } + else if (value.startsWith("solaris")) + { + return "solaris"; + } + else if (value.startsWith("sunos")) + { + return "sunos"; + } + else if (value.startsWith("vxworks")) + { + return "vxworks"; + } + return value; + } - return libraries; - + public static String normalizeProcessor(String value) + { + if (value.startsWith("x86") || value.startsWith("pentium") + || value.startsWith("i386") || value.startsWith("i486") + || value.startsWith("i586") || value.startsWith("i686")) + { + return "x86"; } - catch (RuntimeException ex) + else if (value.startsWith("x86-64") || value.startsWith("amd64")) { - logger.log( - Logger.LOG_ERROR, - "Error parsing native library header.", - ex); - throw ex; + return "x86-64"; + } + else if (value.startsWith("68k")) + { + return "68k"; + } + else if (value.startsWith("arm")) + { + return "arm"; + } + else if (value.startsWith("alpha")) + { + return "alpha"; + } + else if (value.startsWith("ignite") || value.startsWith("psc1k")) + { + return "ignite"; + } + else if (value.startsWith("mips")) + { + return "mips"; + } + else if (value.startsWith("parisc")) + { + return "parisc"; + } + else if (value.startsWith("powerpc") || value.startsWith("power") + || value.startsWith("ppc")) + { + return "powerpc"; } + else if (value.startsWith("sparc")) + { + return "sparc"; + } + return value; } - public String toString() + public static String normalizeOSVersion(String value) { - return m_name; + // Header: 'Bundle-NativeCode', Parameter: 'osversion' + // Standardized 'osversion': major.minor.micro, only digits + String VERSION_DELIM = "."; + String QUALIFIER_DELIM = "-"; + int major = 0; + int minor = 0; + int micro = 0; + try + { + StringTokenizer st = new StringTokenizer(value, VERSION_DELIM, true); + major = Integer.parseInt(st.nextToken()); + + if (st.hasMoreTokens()) + { + st.nextToken(); // consume delimiter + minor = Integer.parseInt(st.nextToken()); + + if (st.hasMoreTokens()) + { + st.nextToken(); // consume delimiter + String microStr = st.nextToken(); + if (microStr.indexOf(QUALIFIER_DELIM) < 0) + { + micro = Integer.parseInt(microStr); + } + else + { + micro = Integer.parseInt(microStr.substring(0, microStr + .indexOf(QUALIFIER_DELIM))); + } + } + } + } + catch (Exception ex) + { + return Version.emptyVersion.toString(); + } + + return major + "." + minor + "." + micro; } } Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java?rev=439429&r1=439428&r2=439429&view=diff ============================================================================== --- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java (original) +++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/searchpolicy/R4SearchPolicyCore.java Fri Sep 1 12:23:28 2006 @@ -23,9 +23,7 @@ import org.apache.felix.framework.Logger; import org.apache.felix.framework.util.*; import org.apache.felix.moduleloader.*; -import org.osgi.framework.Constants; -import org.osgi.framework.PackagePermission; -import org.osgi.framework.Version; +import org.osgi.framework.*; public class R4SearchPolicyCore implements ModuleListener { @@ -505,18 +503,15 @@ name = name.substring(1); } - // TODO: This "matching" algorithm does not fully - // match the spec and should be improved. R4Library[] libs = module.getDefinition().getLibraries(); for (int i = 0; (libs != null) && (i < libs.length); i++) { - String path = libs[i].getPath(name); - if (path != null) + String lib = libs[i].getPath(name); + if (lib != null) { - return path; + return lib; } } - return null; } Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/FelixConstants.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/FelixConstants.java?rev=439429&r1=439428&r2=439429&view=diff ============================================================================== --- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/FelixConstants.java (original) +++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/FelixConstants.java Fri Sep 1 12:23:28 2006 @@ -33,6 +33,7 @@ public static final String PACKAGE_SEPARATOR = ";"; public static final String VERSION_SEGMENT_SEPARATOR = "."; public static final int VERSION_SEGMENT_COUNT = 3; + public static final String BUNDLE_NATIVECODE_OPTIONAL = "*"; // Miscellaneous OSGi constants. public static final String BUNDLE_URL_PROTOCOL = "bundle"; @@ -56,4 +57,4 @@ // Miscellaneous properties values. public static final String FAKE_URL_PROTOCOL_VALUE = "location:"; -} +} \ No newline at end of file Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java?rev=439429&r1=439428&r2=439429&view=diff ============================================================================== --- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java (original) +++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/ManifestParser.java Fri Sep 1 12:23:28 2006 @@ -16,26 +16,29 @@ */ package org.apache.felix.framework.util; -import java.util.HashMap; -import java.util.Map; +import java.util.*; import org.apache.felix.framework.Logger; -import org.apache.felix.framework.cache.BundleCache; +import org.apache.felix.framework.cache.BundleRevision; import org.apache.felix.framework.searchpolicy.*; import org.osgi.framework.*; public class ManifestParser { private Logger m_logger = null; + private PropertyResolver m_config = null; private Map m_headerMap = null; private R4Export[] m_exports = null; private R4Import[] m_imports = null; private R4Import[] m_dynamics = null; - private R4LibraryHeader[] m_libraryHeaders = null; + private R4LibraryClause[] m_libraryHeaders = null; + private boolean m_libraryHeadersOptional = false; - public ManifestParser(Logger logger, Map headerMap) throws BundleException + public ManifestParser(Logger logger, PropertyResolver config, Map headerMap) + throws BundleException { m_logger = logger; + m_config = config; m_headerMap = headerMap; // Verify that only manifest version 2 is specified. @@ -152,6 +155,17 @@ m_logger, Util.parseDelimitedString(get(Constants.BUNDLE_NATIVECODE), ",")); + // Check to see if there was an optional native library clause, which is + // represented by a null library header; if so, record it and remove it. + if ((m_libraryHeaders.length > 0) && + (m_libraryHeaders[m_libraryHeaders.length - 1].getLibraryFiles() == null)) + { + m_libraryHeadersOptional = true; + R4LibraryClause[] tmp = new R4LibraryClause[m_libraryHeaders.length - 1]; + System.arraycopy(m_libraryHeaders, 0, tmp, 0, m_libraryHeaders.length - 1); + m_libraryHeaders = tmp; + } + // Do final checks and normalization of manifest. if (getVersion().equals("2")) { @@ -189,21 +203,183 @@ return m_dynamics; } - public R4LibraryHeader[] getLibraryHeaders() + public R4LibraryClause[] getLibraryClauses() { return m_libraryHeaders; } - public R4Library[] getLibraries( - BundleCache cache, long id, int revision, String osName, String processor) + /** + *

+ * This method returns the selected native library metadata from + * the manifest. The information is not the raw metadata from the + * manifest, but is native library metadata clause selected according + * to the OSGi native library clause selection policy. The metadata + * returned by this method will be attached directly to a module and + * used for finding its native libraries at run time. To inspect the + * raw native library metadata refer to getLibraryClauses(). + *

+ * @param revision the bundle revision for the module. + * @return an array of selected library metadata objects from the manifest. + * @throws BundleException if any problems arise. + */ + public R4Library[] getLibraries(BundleRevision revision) throws BundleException { - R4Library[] libraries = new R4Library[m_libraryHeaders.length]; - for (int i = 0; i < libraries.length; i++) + R4LibraryClause clause = getSelectedLibraryClause(); + + if (clause != null) + { + R4Library[] libraries = new R4Library[clause.getLibraryFiles().length]; + for (int i = 0; i < libraries.length; i++) + { + libraries[i] = new R4Library( + m_logger, revision, clause.getLibraryFiles()[i], + clause.getOSNames(), clause.getProcessors(), clause.getOSVersions(), + clause.getLanguages(), clause.getSelectionFilter()); + } + return libraries; + } + return null; + } + + private R4LibraryClause getSelectedLibraryClause() throws BundleException + { + if ((m_libraryHeaders != null) && (m_libraryHeaders.length > 0)) + { + List clauseList = new ArrayList(); + + // Search for matching native clauses. + for (int i = 0; i < m_libraryHeaders.length; i++) + { + if (m_libraryHeaders[i].match(m_config)) + { + clauseList.add(m_libraryHeaders[i]); + } + } + + // Select the matching native clause. + int selected = 0; + if (clauseList.size() == 0) + { + // If optional clause exists, no error thrown. + if (m_libraryHeadersOptional) + { + return null; + } + else + { + throw new BundleException("Unable to select a native library clause."); + } + } + else if (clauseList.size() == 1) + { + selected = 0; + } + else if (clauseList.size() > 1) + { + selected = firstSortedClause(clauseList); + } + return ((R4LibraryClause) clauseList.get(selected)); + } + + return null; + } + + private int firstSortedClause(List clauseList) + { + ArrayList indexList = new ArrayList(); + ArrayList selection = new ArrayList(); + + // Init index list + for (int i = 0; i < clauseList.size(); i++) + { + indexList.add("" + i); + } + + // Select clause with 'osversion' range declared + // and get back the max floor of 'osversion' ranges. + Version osVersionRangeMaxFloor = new Version(0, 0, 0); + for (int i = 0; i < indexList.size(); i++) + { + int index = Integer.parseInt(indexList.get(i).toString()); + String[] osversions = ((R4LibraryClause) clauseList.get(index)).getOSVersions(); + if (osversions != null) + { + selection.add("" + indexList.get(i)); + } + for (int k = 0; (osversions != null) && (k < osversions.length); k++) + { + VersionRange range = VersionRange.parse(osversions[k]); + if ((range.getLow()).compareTo(osVersionRangeMaxFloor) >= 0) + { + osVersionRangeMaxFloor = range.getLow(); + } + } + } + + if (selection.size() == 1) + { + return Integer.parseInt(selection.get(0).toString()); + } + else if (selection.size() > 1) + { + // Keep only selected clauses with an 'osversion' + // equal to the max floor of 'osversion' ranges. + indexList = selection; + selection = new ArrayList(); + for (int i = 0; i < indexList.size(); i++) + { + int index = Integer.parseInt(indexList.get(i).toString()); + String[] osversions = ((R4LibraryClause) clauseList.get(index)).getOSVersions(); + for (int k = 0; k < osversions.length; k++) + { + VersionRange range = VersionRange.parse(osversions[k]); + if ((range.getLow()).compareTo(osVersionRangeMaxFloor) >= 0) + { + selection.add("" + indexList.get(i)); + } + } + } + } + + if (selection.size() == 0) + { + // Re-init index list. + selection.clear(); + indexList.clear(); + for (int i = 0; i < clauseList.size(); i++) + { + indexList.add("" + i); + } + } + else if (selection.size() == 1) + { + return Integer.parseInt(selection.get(0).toString()); + } + else + { + indexList = selection; + selection.clear(); + } + + // Keep only clauses with 'language' declared. + for (int i = 0; i < indexList.size(); i++) + { + int index = Integer.parseInt(indexList.get(i).toString()); + if (((R4LibraryClause) clauseList.get(index)).getLanguages() != null) + { + selection.add("" + indexList.get(i)); + } + } + + // Return the first sorted clause + if (selection.size() == 0) + { + return 0; + } + else { - libraries[i] = new R4Library( - m_logger, cache, id, revision, osName, processor, m_libraryHeaders[i]); + return Integer.parseInt(selection.get(0).toString()); } - return libraries; } private void checkAndNormalizeR3() throws BundleException Modified: incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java URL: http://svn.apache.org/viewvc/incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java?rev=439429&r1=439428&r2=439429&view=diff ============================================================================== --- incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java (original) +++ incubator/felix/trunk/framework/src/main/java/org/apache/felix/framework/util/Util.java Fri Sep 1 12:23:28 2006 @@ -303,28 +303,23 @@ * @return an array of LibraryInfo objects for the * passed in strings. **/ - public static R4LibraryHeader[] parseLibraryStrings(Logger logger, String[] libStrs) + public static R4LibraryClause[] parseLibraryStrings(Logger logger, String[] libStrs) throws IllegalArgumentException { if (libStrs == null) { - return new R4LibraryHeader[0]; + return new R4LibraryClause[0]; } List libList = new ArrayList(); for (int i = 0; i < libStrs.length; i++) { - R4LibraryHeader[] libs = R4LibraryHeader.parse(logger, libStrs[i]); - for (int libIdx = 0; - (libs != null) && (libIdx < libs.length); - libIdx++) - { - libList.add(libs[libIdx]); - } + R4LibraryClause clause = R4LibraryClause.parse(logger, libStrs[i]); + libList.add(clause); } - return (R4LibraryHeader[]) libList.toArray(new R4LibraryHeader[libList.size()]); + return (R4LibraryClause[]) libList.toArray(new R4LibraryClause[libList.size()]); } private static final byte encTab[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,