package org.eclipse.osgi.storage;
import java.io.File;
import java.util.*;
import org.eclipse.osgi.container.*;
import org.eclipse.osgi.internal.debug.Debug;
import org.eclipse.osgi.internal.framework.FilterImpl;
import org.eclipse.osgi.internal.hookregistry.ClassLoaderHook;
import org.eclipse.osgi.storage.BundleInfo.Generation;
import org.eclipse.osgi.storage.bundlefile.BundleEntry;
import org.eclipse.osgi.storage.bundlefile.BundleFile;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.namespace.HostNamespace;
import org.osgi.framework.namespace.NativeNamespace;
import org.osgi.framework.wiring.BundleRevision;
public class NativeCodeFinder {
public static final String REQUIREMENT_NATIVE_PATHS_ATTRIBUTE = "native.paths";
private static final String[] EMPTY_STRINGS = new String[0];
public static final String EXTERNAL_LIB_PREFIX = "external:";
private final Generation generation;
private final Debug debug;
private final Collection<String> loadedNativeCode = new ArrayList<>(1);
public NativeCodeFinder(Generation generation) {
this.generation = generation;
this.debug = generation.getBundleInfo().getStorage().getConfiguration().getDebug();
}
public String[] mapLibraryNames(String mappedLibName) {
int extIndex = mappedLibName.lastIndexOf('.');
List<String> LIB_EXTENSIONS = generation.getBundleInfo().getStorage().getConfiguration().LIB_EXTENSIONS;
if (LIB_EXTENSIONS.isEmpty() || extIndex < 0)
return EMPTY_STRINGS;
String libNameBase = mappedLibName.substring(0, extIndex);
String[] results = new String[LIB_EXTENSIONS.size()];
for (int i = 0; i < results.length; i++)
results[i] = libNameBase + LIB_EXTENSIONS.get(i);
return results;
}
String findLibrary(String libname) {
String path = findLibrary0(libname);
if (path != null) {
synchronized (loadedNativeCode) {
if (loadedNativeCode.contains(path) || generation.getBundleInfo().getStorage().getConfiguration().COPY_NATIVES) {
String temp = generation.getBundleInfo().getStorage().copyToTempLibrary(generation, path);
if (temp != null)
path = temp;
} else {
loadedNativeCode.add(path);
}
}
}
return path;
}
private String findLibrary0(String libname) {
String path = null;
List<ClassLoaderHook> hooks = generation.getBundleInfo().getStorage().getConfiguration().getHookRegistry().getClassLoaderHooks();
for (ClassLoaderHook hook : hooks) {
path = hook.findLocalLibrary(generation, libname);
if (path != null) {
return path;
}
}
String mappedName = System.mapLibraryName(libname);
String[] altMappedNames = mapLibraryNames(mappedName);
path = findBundleNativeCode(libname, mappedName, altMappedNames);
return path != null ? path : findEclipseNativeCode(libname, mappedName, altMappedNames);
}
private String findEclipseNativeCode(String libname, String mappedName, String[] altMappedNames) {
if (libname.length() == 0)
return null;
if (libname.charAt(0) == '/' || libname.charAt(0) == '\\')
libname = libname.substring(1);
String result = searchEclipseVariants(mappedName);
if (result != null)
return result;
for (int i = 0; i < altMappedNames.length && result == null; i++)
result = searchEclipseVariants(altMappedNames[i]);
return result;
}
private String searchEclipseVariants(String path) {
List<String> ECLIPSE_LIB_VARIANTS = generation.getBundleInfo().getStorage().getConfiguration().ECLIPSE_LIB_VARIANTS;
for (String variant : ECLIPSE_LIB_VARIANTS) {
BundleFile baseBundleFile = generation.getBundleFile();
BundleEntry libEntry = baseBundleFile.getEntry(variant + path);
if (libEntry != null) {
File libFile = baseBundleFile.getFile(variant + path, true);
if (libFile == null)
return null;
if (org.eclipse.osgi.service.environment.Constants.OS_HPUX.equals(generation.getBundleInfo().getStorage().getConfiguration().getOS())) {
try {
Runtime.getRuntime().exec(new String[] {"chmod", "755", libFile.getAbsolutePath()}).waitFor();
} catch (Exception e) {
e.printStackTrace();
}
}
return libFile.getAbsolutePath();
}
}
return null;
}
private String findBundleNativeCode(String libname, String mappedName, String[] altMappedNames) {
String path = null;
if (debug.DEBUG_LOADER)
Debug.println(" mapped library name: " + mappedName);
List<String> nativePaths = getNativePaths();
if (nativePaths.isEmpty()) {
return null;
}
path = findNativePath(nativePaths, mappedName);
if (path == null) {
for (int i = 0; i < altMappedNames.length && path == null; i++)
path = findNativePath(nativePaths, altMappedNames[i]);
}
if (path == null) {
if (debug.DEBUG_LOADER)
Debug.println(" library does not exist: " + mappedName);
path = findNativePath(nativePaths, libname);
}
if (debug.DEBUG_LOADER)
Debug.println(" returning library: " + path);
return path;
}
private List<String> getNativePaths() {
ModuleRevision revision = generation.getRevision();
ModuleWiring wiring = revision.getWiring();
if (wiring == null) {
return Collections.emptyList();
}
if ((revision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) {
List<ModuleWire> hosts = wiring.getRequiredModuleWires(HostNamespace.HOST_NAMESPACE);
if (hosts == null) {
return Collections.emptyList();
}
if (!hosts.isEmpty()) {
wiring = hosts.get(0).getProviderWiring();
}
}
List<ModuleWire> nativeCode = wiring.getRequiredModuleWires(NativeNamespace.NATIVE_NAMESPACE);
if (nativeCode.isEmpty()) {
return Collections.emptyList();
}
for (ModuleWire moduleWire : nativeCode) {
if (moduleWire.getRequirement().getRevision().equals(revision)) {
@SuppressWarnings("unchecked")
List<String> result = (List<String>) nativeCode.get(0).getRequirement().getAttributes().get(REQUIREMENT_NATIVE_PATHS_ATTRIBUTE);
if (result != null)
return result;
try {
FilterImpl filter = FilterImpl.newInstance(moduleWire.getRequirement().getDirectives().get(NativeNamespace.REQUIREMENT_FILTER_DIRECTIVE));
int index = -1;
Map<String, Object> capabilityAttrs = moduleWire.getCapability().getAttributes();
for (FilterImpl child : filter.getChildren()) {
index++;
if (child.matches(capabilityAttrs)) {
break;
}
}
if (index != -1) {
@SuppressWarnings("unchecked")
List<String> indexResult = (List<String>) nativeCode.get(0).getRequirement().getAttributes().get(REQUIREMENT_NATIVE_PATHS_ATTRIBUTE + '.' + index);
if (indexResult != null)
return indexResult;
}
} catch (InvalidSyntaxException e) {
throw new RuntimeException(e);
}
}
}
return Collections.emptyList();
}
private String findNativePath(List<String> nativePaths, String libname) {
int slash = libname.lastIndexOf('/');
if (slash >= 0)
libname = libname.substring(slash + 1);
for (String nativePath : nativePaths) {
slash = nativePath.lastIndexOf('/');
String path = slash < 0 ? nativePath : nativePath.substring(slash + 1);
if (path.equals(libname)) {
if (nativePath.startsWith(NativeCodeFinder.EXTERNAL_LIB_PREFIX)) {
String externalPath = generation.getBundleInfo().getStorage().getConfiguration().substituteVars(nativePath.substring(NativeCodeFinder.EXTERNAL_LIB_PREFIX.length()));
File nativeFile = new File(externalPath);
return nativeFile.getAbsolutePath();
}
File nativeFile = generation.getBundleFile().getFile(nativePath, true);
if (nativeFile != null)
return nativeFile.getAbsolutePath();
}
}
return null;
}
}