/*******************************************************************************
* Copyright (c) 2004, 2013 BREDEX GmbH.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* BREDEX GmbH - initial API and implementation and/or initial documentation
*******************************************************************************/
package org.eclipse.jubula.rc.rcp.installer;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
/**
* This bundle activator installs the Jubula RCP accessor.
* All embedded bundles are installed and only the specialized
* bundles depending on Eclipse e3 or e4 are starting correctly.
*/
public class BundleInstaller implements BundleActivator {
/** An bundle name to identify a pure e4 application. */
private static final String E4_SPECIFIC_BUNDLE =
"org.eclipse.e4.core.services"; //$NON-NLS-1$
/** An bundle name to identify a pure e4 application. */
private static final String SWT_SPECIFIC_BUNDLE =
"org.eclipse.swt"; //$NON-NLS-1$
/** The suffixes of the bundles used in Eclipse RCP e3. */
private static final String BUNDLE_FOLDER_SUFFIX_SWT = ".swt"; //$NON-NLS-1$
/** The suffixes of the bundles used in Eclipse RCP e3. */
private static final String BUNDLE_FOLDER_SUFFIX_E3 = ".e3"; //$NON-NLS-1$
/** The suffixes of the bundles used in Eclipse RCP e4. */
private static final String BUNDLE_FOLDER_SUFFIX_E4 = ".e4"; //$NON-NLS-1$
/** The suffixes of the bundles used in Eclipse RCP e4. */
private static final String BUNDLE_FOLDER_SUFFIX_E4_SWT = ".e4.swt"; //$NON-NLS-1$
/** The suffixes of the external extension bundles */
private static final String BUNDLE_FOLDER_SUFFIX_EXT = ".ext"; //$NON-NLS-1$
/**
* Install embedded bundles, if they have not been already installed.
* @param context The bundle context.
* @throws Exception
* @see #installBundles(BundleContext)
* @see #startBundles(List)
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
*/
public void start(BundleContext context) throws Exception {
// install and start the bundles for the RCP accessor
List<String> bundleFolderSuffixes = getBundleFolderSuffixes(context);
try {
List<Bundle> installedBundles = installAllBundles(
context, bundleFolderSuffixes);
startBundles(installedBundles);
} catch (Throwable t) {
t.printStackTrace(); // unexpected exception
}
}
/**
* @param context The bundle context.
* @return The bundle folder suffix depending on the RCP version
* identified by the existence of {@link #E4_SPECIFIC_BUNDLE},
* i.e. {@link #BUNDLE_FOLDER_SUFFIX_E3} or {@link #BUNDLE_FOLDER_SUFFIX_E4_SWT}.
*/
private static List<String> getBundleFolderSuffixes(
BundleContext context) {
List<String> bundleFolderSuffixes = new ArrayList<String>();
bundleFolderSuffixes.add(""); //$NON-NLS-1$
Bundle[] installedBundles = context.getBundles();
if (isBundleInstalled(installedBundles, E4_SPECIFIC_BUNDLE)) {
bundleFolderSuffixes.add(BUNDLE_FOLDER_SUFFIX_E4);
if (isBundleInstalled(installedBundles, SWT_SPECIFIC_BUNDLE)) {
// e4 with SWT has been found
bundleFolderSuffixes.add(BUNDLE_FOLDER_SUFFIX_SWT);
bundleFolderSuffixes.add(BUNDLE_FOLDER_SUFFIX_E4_SWT);
}
} else {
// e3 has been found (only with SWT)
bundleFolderSuffixes.add(BUNDLE_FOLDER_SUFFIX_SWT);
bundleFolderSuffixes.add(BUNDLE_FOLDER_SUFFIX_E3);
}
bundleFolderSuffixes.add(BUNDLE_FOLDER_SUFFIX_EXT);
return bundleFolderSuffixes;
}
/**
* @param installedBundles The array of installed bundles.
* @param bundleName The bundle name searching for.
* @return True, if the given array contains the given bundle name.
*/
private static boolean isBundleInstalled(Bundle[] installedBundles,
String bundleName) {
for (int i = 0; i < installedBundles.length; i++) {
if (bundleName.compareTo(
installedBundles[i].getSymbolicName()) == 0) {
return true;
}
}
return false;
}
/**
* Calls {@link #installBundlesWithSuffix(BundleContext, String)} with all suffixes.
* @param context The bundle context.
* @param bundleFolderSuffixes A string list of the bundle folder suffixes.
* @return A list of all newly installed bundles.
* @throws BundleException
* @throws IOException
* @see BundleIterator#installBundle()
*/
private static List<Bundle> installAllBundles(
BundleContext context, List<String> bundleFolderSuffixes)
throws BundleException, IOException {
List<Bundle> bundles = new ArrayList<Bundle>();
Iterator<String> suffixes = bundleFolderSuffixes.iterator();
while (suffixes.hasNext()) {
bundles.addAll(installBundlesWithSuffix(
context, suffixes.next()));
}
return bundles;
}
/**
* Install all bundles located in the directory named "bundles",
* if they are not already installed.
* <p>Attention:
* One bundle is randomly chosen out of a set of bundles with the same name
* and with different versions located in the "bundles/" directory, but this
* situation should normally not appear.
* @param context The bundle context.
* @param suffix The string defining the suffix of the bundle folder.
* @return The newly installed bundles.
*/
private static List<Bundle> installBundlesWithSuffix(BundleContext context,
String suffix)
throws IOException, BundleException,
SecurityException, IllegalArgumentException {
List<Bundle> bundles = new ArrayList<Bundle>();
BundleIterator it = new BundleIterator(context, suffix);
while (it.hasNext()) {
it.next(); // move to next bundle in bundle folder
Bundle newBundle = it.installBundle();
if (newBundle != null) {
// remember all newly installed bundles
bundles.add(newBundle);
}
}
return bundles;
}
/**
* Start the given bundles (only newly installed).
* Attention:
* <ul>
* <li>Newly installed bundles must be started to activate them in the first application invocation.</li>
* <li>Newly installed bundles must be started <i>after</i> all necessary bundles are installed.
* Otherwise the OSGI framework may fail with unresolved dependencies.</li>
* <li>If the bundles are already installed by a previous application invocation, the bundles are
* started automatically by the OSGI framework and are not started by this method.</li>
* </ul>
* @param bundles The list of bundles to start.
* @throws BundleException
*/
private static void startBundles(List<Bundle> bundles)
throws BundleException {
for (Bundle bundle : bundles) {
bundle.start();
}
}
/**
* Stop all currently running bundles installed by this activator.
* @param context The bundle context.
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
*/
public void stop(BundleContext context) throws Exception {
stopAllBundles(context, getBundleFolderSuffixes(context));
}
/**
* @param context The bundle context.
* @param bundleFolderSuffixes The string list of bundle folder suffixes,
* which defines the bundles to stop.
*/
private static void stopAllBundles(
BundleContext context, List<String> bundleFolderSuffixes) {
Iterator<String> itSuffixes = bundleFolderSuffixes.iterator();
while (itSuffixes.hasNext()) {
BundleIterator it = new BundleIterator(
context, itSuffixes.next());
while (it.hasNext()) {
it.next();
try {
it.uninstallBundle();
} catch (Throwable t) {
t.printStackTrace();
}
}
}
}
}