Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Equinox » Using P2 profiles in a non-RCP application
Using P2 profiles in a non-RCP application [message #498152] Sun, 15 November 2009 00:43 Go to next message
Phil Denis is currently offline Phil Denis
Messages: 26
Registered: October 2009
Junior Member
I am running a standalone OSGi application (nonRCP, no eclipse.exe or product definition). I have equinox 3.5 SDK unzipped in a folder.

I'm starting the framework using the command:

java \
-Declipse.ignoreApp=true \
-Dosgi.noShutdown=true \
-Dosgi.install.area=/workspaces/equinox-3.5-sdk \
-Dosgi.configuration.area=/workspaces/equinox-3.5-sdk/config uration \
-Dfile.encoding=MacRoman \
-Declipse.p2.data.area=/workspaces/equinox-3.5-sdk/p2 \
-classpath ./plugins/org.eclipse.equinox.launcher_1.0.201.R35x_v2009071 5.jar \
org.eclipse.equinox.launcher.Main \
-os macosx -ws carbon -arch x86 -nl en_US \
-console \
-debug

Now, using the provisioning commands contributed to the console, I can add artifact and metadata repositories for my updatesite and use provinstall to install my feature into the "this" or "SELF" profile. provinstall downloads the bundles and feature jar files into the features/ and plugins/ folder, but none of the newly downloaded plugins are installed in the OSGi container.

I've also tried using provinstall to configure a MyProfile profile and again it will download and provision the bundles but none of them are added to the running OSGi environment. Furthermore, I cannot seem to find a way to "switch" or "load" a profile, but when I list its contents it confirms that the profile was properly configured.

How do you start up equinox with a given profile? Can you switch profiles at runtime? I don't want to use simpleconfigurator to list my bundles, I just want to fetch the provisioned profile and install all of those bundles in OSGi when I start up the framework. Can this be done? Basically I want to selfprovision .. ship a small set of p2 plugins that will fetch my application bundles and install them all into the running equinox ... then start my application bundle.

Thanks,
Phil
Re: Using P2 profiles in a non-RCP application [message #502565 is a reply to message #498152] Tue, 08 December 2009 15:05 Go to previous message
Phil Denis is currently offline Phil Denis
Messages: 26
Registered: October 2009
Junior Member
Well, to answer another one of my own questions, here's a class that can manage profiles, including starting profiles and switching profiles. It really seems odd to me that there is all this code in Equinox P2 for configuring profiles, but there's no code for starting/switching profiles.

Anyway, here's what I came up with. If anyone finds a better way, please let me know!

public interface ProfileManagerService {
	void createProfile(String profileId, Properties properties);
	void startProfile(String profileId);
}



public class ProfileManagerServiceImpl implements ProfileManagerService {
	private static final boolean DEBUG = true;

	/**
	 * @see ca.richer.equinox.provisioning.ProfileManagerService#createProfile(java.lang.String, java.util.Properties)
	 */
	public void createProfile(String profileId, Properties properties) {
		try {
			IProfileRegistry profileRegistry = (IProfileRegistry) ServiceHelper.getService(Activator.getContext(), IProfileRegistry.class.getName());
			if (profileRegistry == null)
				return;
			IProfile profile = profileRegistry.getProfile(profileId);
			if (profile != null)
				return;
			ProvisioningHelper.addProfile(profileId, properties);
		} catch (ProvisionException e) {
			System.out.println("add profile failed " + e.getMessage());
		}
		
	}

	/**
	 * @see ca.richer.equinox.provisioning.ProfileManagerService#startProfile(java.lang.String)
	 */
	public void startProfile(String profileId) {
		// Get the list of bundles that are expected in the profile
		final IProfile profile = ProvisioningHelper.getProfile(profileId);
		final Query query = new InstallableUnitQuery(null);
		final Collector collector = profile.query(query, new Collector(), new NullProgressMonitor());
		final List<BundleInfo> bundleInfoList = new ArrayList<BundleInfo>();
		for (Object o : collector.toCollection()) {
			final InstallableUnit unit = (InstallableUnit) o;
			try {
				if (unit.getId().equals("org.eclipse.osgi") || unit.getId().contains(".feature") || unit.getId().equals("a.jre")) continue; // Skip the system bundle (and features)
				final URI location = new URI("reference:file:plugins/" + unit.getId() + "_" + unit.getVersion().toString() + ".jar");
				final BundleInfo info = new BundleInfo(unit.getId(), unit.getVersion().toString(), location, 4, true);
				bundleInfoList.add(info);
			} catch (URISyntaxException uriException) {
				uriException.printStackTrace();
			}
		}

		BundleInfo[] expectedState = bundleInfoList.toArray(new BundleInfo[bundleInfoList.size()]);

		// check for an update to the system bundle
		String systemBundleSymbolicName = Activator.getContext().getBundle(0).getSymbolicName();
		org.osgi.framework.Version systemBundleVersion = Activator.getContext().getBundle(0).getVersion();
		if (systemBundleSymbolicName != null) {
			for (int i = 0; i < expectedState.length; i++) {
				String symbolicName = expectedState[i].getSymbolicName();
				if (!systemBundleSymbolicName.equals(symbolicName))
					continue;

				Version version = Version.parseVersion(expectedState[i].getVersion());
				if (!systemBundleVersion.equals(version))
					throw new IllegalStateException("The System Bundle was updated. The framework must be restarted to finalize the configuration change");
			}
		}

		final BundleInfo[] currentlyInstalledBundles = getCurrentlyInstalledBundles();
		final HashSet toUninstall = new HashSet(Arrays.asList(currentlyInstalledBundles));
		toUninstall.removeAll(Arrays.asList(expectedState));

		final PackageAdmin packageAdminService = (PackageAdmin) Activator.getService(PackageAdmin.class.getName());

		Collection prevouslyResolved = getResolvedBundles();
		Collection toRefresh = new ArrayList();
		Collection toStart = new ArrayList();
		toRefresh.addAll(installBundles(expectedState, toStart));
		toRefresh.addAll(uninstallBundles(expectedState, packageAdminService));
		refreshPackages((Bundle[]) toRefresh.toArray(new Bundle[toRefresh.size()]), Activator.getContext());
		if (toRefresh.size() > 0)
			try {
				Activator.getContext().getBundle().loadClass("org.eclipse.osgi.service.resolver.PlatformAdmin"); //$NON-NLS-1$
				// now see if there are any currently resolved bundles with option imports which could be resolved or
				// if there are fragments with additional constraints which conflict with an already resolved host
				Bundle[] additionalRefresh = StateResolverUtils.getAdditionalRefresh(prevouslyResolved, Activator.getContext());
				if (additionalRefresh.length > 0)
					refreshPackages(additionalRefresh, Activator.getContext());
			} catch (ClassNotFoundException cnfe) {
				// do nothing; no resolver package available
			}
		startBundles((Bundle[]) toStart.toArray(new Bundle[toStart.size()]));
	}
	
	private BundleInfo[] getCurrentlyInstalledBundles() {
		final List<BundleInfo> currentBundles = new ArrayList<BundleInfo>();
		for (Bundle bundle : Activator.getContext().getBundles()) {
			if (bundle.getSymbolicName().equals("org.eclipse.osgi")) continue;
			currentBundles.add(new BundleInfo(bundle.getSymbolicName(), bundle.getVersion().toString(), null, -1, (bundle.getState() & Bundle.ACTIVE) == 0));
		}
		return currentBundles.toArray(new BundleInfo[currentBundles.size()]);
	}
	
	private List<BundleInfo> getResolvedBundles() {
		final List<BundleInfo> resolvedBundles = new ArrayList<BundleInfo>();
		for (Bundle bundle : Activator.getContext().getBundles()) {
			if (bundle.getSymbolicName().equals("org.eclipse.osgi")) continue;
			resolvedBundles.add(new BundleInfo(bundle.getSymbolicName(), bundle.getVersion().toString(), null, -1, (bundle.getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED)) == 0));
		}
		return resolvedBundles;
	}
	
	private ArrayList installBundles(BundleInfo[] finalList, Collection toStart) {
		ArrayList toRefresh = new ArrayList();

		for (int i = 0; i < finalList.length; i++) {
			if (finalList[i] == null)
				continue;
			//TODO here we do not deal with bundles that don't have a symbolic id
			//TODO Need to handle the case where getBundles return multiple value

			String symbolicName = finalList[i].getSymbolicName();
			String version = finalList[i].getVersion();

			final PackageAdmin packageAdminService = (PackageAdmin) Activator.getService(PackageAdmin.class.getName());
			Bundle[] matches = null;
			if (symbolicName != null && version != null)
				matches = packageAdminService.getBundles(symbolicName, getVersionRange(version));

			String bundleLocation = finalList[i].getLocation().toString();

			Bundle current = matches == null ? null : (matches.length == 0 ? null : matches[0]);
			if (current == null) {
				try {
					current = Activator.getContext().installBundle(bundleLocation);
					if (DEBUG)
						System.out.println("installed bundle:" + finalList[i]); //$NON-NLS-1$
					toRefresh.add(current);
				} catch (BundleException e) {
					if (DEBUG) {
						System.err.println("Can't install " + symbolicName + '/' + version + " from location " + finalList[i].getLocation()); //$NON-NLS-1$ //$NON-NLS-2$
						e.printStackTrace();
					}
					continue;
				}
			}

			// Mark Started
			if (finalList[i].isMarkedAsStarted()) {
				toStart.add(current);
			}

			// Set Start Level
			int startLevel = finalList[i].getStartLevel();
			if (startLevel < 1)
				continue;
			if (current.getBundleId() == 0)
				continue;
			if (packageAdminService.getBundleType(current) == PackageAdmin.BUNDLE_TYPE_FRAGMENT)
				continue;

			try {
				final StartLevel startLevelService = (StartLevel) Activator.getService(StartLevel.class.getName());
				startLevelService.setBundleStartLevel(current, startLevel);
			} catch (IllegalArgumentException ex) {
				Utils.log(4, null, null, "Failed to set start level of Bundle:" + finalList[i], ex); //$NON-NLS-1$
			}
		}
		return toRefresh;
	}

	private void refreshPackages(Bundle[] bundles, BundleContext context) {
		final PackageAdmin packageAdminService = (PackageAdmin) Activator.getService(PackageAdmin.class.getName());
		if (bundles.length == 0 || packageAdminService == null)
			return;

		final boolean[] flag = new boolean[] {false};
		FrameworkListener listener = new FrameworkListener() {
			public void frameworkEvent(FrameworkEvent event) {
				if (event.getType() == FrameworkEvent.PACKAGES_REFRESHED) {
					synchronized (flag) {
						flag[0] = true;
						flag.notifyAll();
					}
				}
			}
		};
		context.addFrameworkListener(listener);
		packageAdminService.refreshPackages(bundles);
		synchronized (flag) {
			while (!flag[0]) {
				try {
					flag.wait();
				} catch (InterruptedException e) {
					//ignore
				}
			}
		}
		//		if (DEBUG) {
		//			for (int i = 0; i < bundles.length; i++) {
		//				System.out.println(SimpleConfiguratorUtils.getBundleStateString(bundles[i]));
		//			}
		//		}
		context.removeFrameworkListener(listener);
	}

	private void startBundles(Bundle[] bundles) {
		final PackageAdmin packageAdminService = (PackageAdmin) Activator.getService(PackageAdmin.class.getName());
		for (int i = 0; i < bundles.length; i++) {
			Bundle bundle = bundles[i];
			if (bundle.getState() == Bundle.UNINSTALLED) {
				System.err.println("Could not start: " + bundle.getSymbolicName() + '(' + bundle.getLocation() + ':' + bundle.getBundleId() + ')' + ". It's state is uninstalled.");
				continue;
			}
			if (bundle.getState() == Bundle.STARTING && (bundle == Activator.getContext().getBundle() || bundle == Activator.getContext().getBundle()))
				continue;
			if (packageAdminService.getBundleType(bundle) == PackageAdmin.BUNDLE_TYPE_FRAGMENT)
				continue;

			try {
				bundle.start();
				if (DEBUG)
					System.out.println("started Bundle:" + bundle.getSymbolicName() + '(' + bundle.getLocation() + ':' + bundle.getBundleId() + ')'); //$NON-NLS-1$
			} catch (BundleException e) {
				e.printStackTrace();
				//				FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, NLS.bind(EclipseAdaptorMsg.ECLIPSE_STARTUP_FAILED_START, bundle.getLocation()), 0, e, null);
				//				log.log(entry);
			}
		}
	}

	/**
	 * Uninstall bundles which are not listed on finalList.  
	 * 
	 * @param finalList bundles list not to be uninstalled.
	 * @param packageAdmin package admin service.
	 * @return Collection HashSet of bundles finally installed.
	 */
	private Collection uninstallBundles(BundleInfo[] finalList, PackageAdmin packageAdmin) {
		Bundle[] allBundles = Activator.getContext().getBundles();

		//Build a set with all the bundles from the system
		Set removedBundles = new HashSet(allBundles.length);
		//		configurator.setPrerequisiteBundles(allBundles);
		for (int i = 0; i < allBundles.length; i++) {
			if (allBundles[i].getBundleId() == 0)
				continue;
			removedBundles.add(allBundles[i]);
		}

		//Remove all the bundles appearing in the final list from the set of installed bundles
		for (int i = 0; i < finalList.length; i++) {
			if (finalList[i] == null)
				continue;
			Bundle[] toAdd = packageAdmin.getBundles(finalList[i].getSymbolicName(), getVersionRange(finalList[i].getVersion()));
			for (int j = 0; toAdd != null && j < toAdd.length; j++) {
				removedBundles.remove(toAdd[j]);
			}
		}

		for (Iterator iter = removedBundles.iterator(); iter.hasNext();) {
			try {
				Bundle bundle = ((Bundle) iter.next());
				bundle.uninstall();
			} catch (BundleException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return removedBundles;
	}

	private String getVersionRange(String version) {
		return version == null ? null : new StringBuffer().append('[').append(version).append(',').append(version).append(']').toString();
	}
}


Previous Topic:EclipseGenerator vs. FeaturesAndBundlesPublisher
Next Topic:Disconnect from OSGi console
Goto Forum:
  


Current Time: Thu Jul 31 09:31:55 EDT 2014

Powered by FUDForum. Page generated in 0.02055 seconds