All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.osgi.storage.NativeCodeFinder Maven / Gradle / Ivy

Go to download

AspectJ tools most notably contains the AspectJ compiler (AJC). AJC applies aspects to Java classes during compilation, fully replacing Javac for plain Java classes and also compiling native AspectJ or annotation-based @AspectJ syntax. Furthermore, AJC can weave aspects into existing class files in a post-compile binary weaving step. This library is a superset of AspectJ weaver and hence also of AspectJ runtime.

There is a newer version: 1.9.22.1
Show newest version
/*******************************************************************************
 * Copyright (c) 2005, 2016 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/

package org.eclipse.osgi.storage;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.eclipse.osgi.container.ModuleRevision;
import org.eclipse.osgi.container.ModuleWire;
import org.eclipse.osgi.container.ModuleWiring;
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"; //$NON-NLS-1$
	private static final String[] EMPTY_STRINGS = new String[0];
	public static final String EXTERNAL_LIB_PREFIX = "external:"; //$NON-NLS-1$
	private final Generation generation;
	private final Debug debug;
	// This is only used to keep track of when the same native library is loaded more than once
	private final Collection loadedNativeCode = new ArrayList<>(1);

	public NativeCodeFinder(Generation generation) {
		this.generation = generation;
		this.debug = generation.getBundleInfo().getStorage().getConfiguration().getDebug();
	}

	/*
	 * Maps an already mapped library name to additional library file extensions.
	 * This is needed on platforms like AIX where .a and .so can be used as library file
	 * extensions, but System.mapLibraryName only returns a single string.
	 */
	public String[] mapLibraryNames(String mappedLibName) {
		int extIndex = mappedLibName.lastIndexOf('.');
		List 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) {
					// we must copy the library to a temp space to allow another class loader to load the library
					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 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);

		// first check Bundle-NativeCode header
		path = findBundleNativeCode(libname, mappedName, altMappedNames);
		// next check eclipse specific support
		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 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;
				// see bug 88697 - HP requires libraries to have executable permissions
				if (org.eclipse.osgi.service.environment.Constants.OS_HPUX.equals(generation.getBundleInfo().getStorage().getConfiguration().getOS())) {
					try {
						// use the string array method in case there is a space in the path
						Runtime.getRuntime().exec(new String[] {"chmod", "755", libFile.getAbsolutePath()}).waitFor(); //$NON-NLS-1$ //$NON-NLS-2$
					} 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); //$NON-NLS-1$
		List 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); //$NON-NLS-1$
			path = findNativePath(nativePaths, libname);
		}
		if (debug.DEBUG_LOADER)
			Debug.println("  returning library: " + path); //$NON-NLS-1$
		return path;
	}

	private List getNativePaths() {
		ModuleRevision revision = generation.getRevision();
		ModuleWiring wiring = revision.getWiring();
		if (wiring == null) {
			// unresolved?  should not be possible
			return Collections.emptyList();
		}
		if ((revision.getTypes() & BundleRevision.TYPE_FRAGMENT) != 0) {
			List hosts = wiring.getRequiredModuleWires(HostNamespace.HOST_NAMESPACE);
			if (hosts == null) {
				// unresolved or invalid?  should not be possible
				return Collections.emptyList();
			}
			if (!hosts.isEmpty()) {
				// just use the first host wiring
				wiring = hosts.get(0).getProviderWiring();
			}
		}

		List nativeCode = wiring.getRequiredModuleWires(NativeNamespace.NATIVE_NAMESPACE);
		if (nativeCode == null || nativeCode.isEmpty()) {
			return Collections.emptyList();
		}

		// just taking the first paths for the revision, we sorted correctly when transforming to the requirement
		for (ModuleWire moduleWire : nativeCode) {
			if (moduleWire.getRequirement().getRevision().equals(revision)) {
				@SuppressWarnings("unchecked")
				List result = (List) moduleWire.getRequirement().getAttributes()
						.get(REQUIREMENT_NATIVE_PATHS_ATTRIBUTE);
				if (result != null)
					return result;
				// this must be a multi-clause Bundle-NativeCode header, need to check for the correct one in the index
				try {
					FilterImpl filter = FilterImpl.newInstance(moduleWire.getRequirement().getDirectives().get(NativeNamespace.REQUIREMENT_FILTER_DIRECTIVE));
					int index = -1;
					Map capabilityAttrs = moduleWire.getCapability().getAttributes();
					for (FilterImpl child : filter.getChildren()) {
						index++;
						if (child.matches(capabilityAttrs)) {
							break;
						}
					}
					if (index != -1) {
						@SuppressWarnings("unchecked")
						List indexResult = (List) moduleWire.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 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)) {
					// references an external library; do variable substitution
					String externalPath = generation.getBundleInfo().getStorage().getConfiguration().substituteVars(nativePath.substring(NativeCodeFinder.EXTERNAL_LIB_PREFIX.length()));
					File nativeFile = new File(externalPath);
					return nativeFile.getAbsolutePath();
				}
				// this is a normal library contained within the bundle
				File nativeFile = generation.getBundleFile().getFile(nativePath, true);
				if (nativeFile != null)
					return nativeFile.getAbsolutePath();
			}
		}
		return null;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy