blob: c0a2754117efbb5dc0ce722b17f10f92642b9b51 [file] [log] [blame]
/*
* 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.searchpolicy;
import java.util.*;
import org.apache.felix.framework.FilterImpl;
import org.apache.felix.framework.Logger;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.framework.util.PropertyResolver;
import org.osgi.framework.*;
public class R4LibraryClause
{
private String[] m_libraryFiles = 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 R4LibraryClause(String[] libraryFiles, String[] osnames,
String[] processors, String[] osversions, String[] languages,
String selectionFilter)
{
m_libraryFiles = libraryFiles;
m_osnames = osnames;
m_processors = processors;
m_osversions = osversions;
m_languages = languages;
m_selectionFilter = selectionFilter;
}
public R4LibraryClause(R4LibraryClause library)
{
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[] getLibraryFiles()
{
return m_libraryFiles;
}
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;
}
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;
}
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
{
if ((s == null) || (s.length() == 0))
{
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 along with one set of associated
// properties.
StringTokenizer st = new StringTokenizer(s, ";");
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())
{
String token = st.nextToken().trim();
if (token.indexOf('=') < 0)
{
// Remove the slash, if necessary.
libFiles[libCount] = (token.charAt(0) == '/')
? token.substring(1)
: token;
libCount++;
}
else
{
// Check for valid native library properties; defined as
// a property name, an equal sign, and a value.
// 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);
}
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) == '"')
{
// This should always be true, otherwise the
// value wouldn't be properly quoted, but we
// will check for safety.
if (value.charAt(value.length() - 1) == '"')
{
value = value.substring(1, value.length() - 1);
}
else
{
value = value.substring(1);
}
}
// Add the value to its corresponding property list.
if (property.equals(Constants.BUNDLE_NATIVECODE_OSNAME))
{
osNameList.add(value);
}
else if (property.equals(Constants.BUNDLE_NATIVECODE_OSVERSION))
{
osVersionList.add(value);
}
else if (property.equals(Constants.BUNDLE_NATIVECODE_PROCESSOR))
{
processorList.add(value);
}
else if (property.equals(Constants.BUNDLE_NATIVECODE_LANGUAGE))
{
languageList.add(value);
}
else if (property.equals(Constants.SELECTION_FILTER_ATTRIBUTE))
{
// TODO: NATIVE - I believe we can have multiple selection filters too.
selectionFilter = value;
}
}
}
if (libCount == 0)
{
return null;
}
// 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)
{
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;
}
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";
}
else if (value.startsWith("x86-64") || value.startsWith("amd64"))
{
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 static String normalizeOSVersion(String value)
{
// 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;
}
}