/* * ------------------------------------------------------------------------ * * Copyright (C) 2003 - 2014 * University of Konstanz, Germany and * KNIME GmbH, Konstanz, Germany * Website: http://www.knime.org; Email: contact@knime.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, Version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses>. * * Additional permission under GNU GPL version 3 section 7: * * KNIME interoperates with ECLIPSE solely via ECLIPSE's plug-in APIs. * Hence, KNIME and ECLIPSE are both independent programs and are not * derived from each other. Should, however, the interpretation of the * GNU GPL Version 3 ("License") under any applicable laws result in * KNIME and ECLIPSE being a combined program, KNIME GMBH herewith grants * you the additional permission to use and propagate KNIME together with * ECLIPSE with only the license terms in place for ECLIPSE applying to * ECLIPSE and the GNU GPL Version 3 applying for KNIME, provided the * license terms of ECLIPSE themselves allow for the respective use and * propagation of ECLIPSE together with KNIME. * * Additional permission relating to nodes for KNIME that extend the Node * Extension (and in particular that are based on subclasses of NodeModel, * NodeDialog, and NodeView) and that only interoperate with KNIME through * standard APIs ("Nodes"): * Nodes are deemed to be separate and independent programs and to not be * covered works. Notwithstanding anything to the contrary in the * License, the License does not apply to Nodes, you are not required to * license Nodes under the License, and you are granted a license to * prepare and propagate Nodes, in each case even if such Nodes are * propagated with or for interoperation with KNIME. The owner of a Node * may freely choose the license terms applicable to such Node, including * when such Node is propagated with or for interoperation with KNIME. * --------------------------------------------------------------------- * * Created on Jun 5, 2014 by Christian Dietz */ package org.knime.knip.base.activators; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.ArrayList; import org.eclipse.core.runtime.FileLocator; import org.knime.core.node.NodeLogger; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; /** * BundleActivator to active bundles of windows, macosx and linux which require additional native (system-dependend) * libraries * * @author Christian Dietz (University of Konstanz) * @author Jonathan Hale (University of Konstanz) */ public abstract class NativeLibBundleActivator implements BundleActivator { private static final NodeLogger LOGGER = NodeLogger.getLogger(NativeLibBundleActivator.class); private boolean isLoaded = false; private final String projectName; private final ArrayList<SystemLibraryConfig> configs; private final boolean addToLibraryPath; /** * @param _projectName name of the project * @param _addToLibraryPath if true, the path of the project will be discovered and added to java.library.path and * jna.library.path */ public NativeLibBundleActivator(final String _projectName, final boolean _addToLibraryPath) { this.projectName = _projectName; this.addToLibraryPath = _addToLibraryPath; this.configs = new ArrayList<SystemLibraryConfig>(); } /** * {@inheritDoc} */ @Override public void start(final BundleContext context) throws Exception { init(); LOGGER.debug("Trying to load native libraries for " + projectName); for (final SystemLibraryConfig config : configs) { if (config.matchesOSName(System.getProperty("os.name"))) { if (addToLibraryPath) { final String arch = mapArch(System.getProperty("os.arch")); final String simpleOS = config.shortOSName(); LOGGER.debug("OS: " + simpleOS + ", ARCH: " + arch); final String additionalPath = getEclipsePath("platform:/fragment/" + projectName + ".bin." + simpleOS + "." + arch + "/lib/" + simpleOS + "/" + arch); final String path = additionalPath + File.pathSeparator + System.getProperty("java.library.path"); System.setProperty("java.library.path", path); System.setProperty("jna.library.path", path); } LOGGER.debug("System Path: " + System.getProperty("java.library.path")); try { loadLibs(config); LOGGER.debug(projectName + " libraries successfully loaded"); isLoaded = true; } catch (final UnsatisfiedLinkError error) { LOGGER.error(error.getMessage()); LOGGER.error("Could not load " + projectName); } break; } } } /** * Can be overriden. Will be called before anything is called in startup(). */ protected void init() { // override } /** * {@inheritDoc} */ @Override public void stop(final BundleContext context) throws Exception { // Nothing to do here } /** * @return true, if all libs were successfully loaded */ public final boolean isLoaded() { return isLoaded; } /** * This method trys to load all libs that are passed to it.<br> * * To ensure the libs are actually all loaded, the programmer has to make sure that the libs are in correct order. * * @param libs the system specific libs to load * * @throws UnsatisfiedLinkError if one or more libs could not be loaded at all */ private void loadLibs(final SystemLibraryConfig config) { for (final String s : config.libs()) { load(s); } } /** * Simply implement "return System.loadLibrary(lib)"! We can't do this is here in the super class, as we then get in * trouble with preloaded library paths, as we are working with the wrong classloader. * * @param lib to be loaded. */ protected abstract void load(String lib); /** * Adds a new configuration * * @param _config the {@link SystemLibraryConfig} to be added */ public void addConfig(final SystemLibraryConfig _config) { configs.add(_config); } /** * Eclipse can't handle "_" in project names when resolving platformURLs. That's why we need to transform "x86_64" * to "amd64". * * @param _arch to be mapped * @return mapped arch */ private String mapArch(final String _arch) { if (_arch.equalsIgnoreCase("x86_64")) { return "amd64"; } else { return _arch; } } /** * Helper Function to resolve platform urls * * @param _platformurl * @return the eclipse path */ protected String getEclipsePath(final String _platformurl) { try { final URL url = new URL(_platformurl); final File dir = new File(FileLocator.resolve(url).getFile()); return dir.getAbsolutePath(); } catch (final IOException e) { return null; } } }