Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Equinox » Any way to force P2 to install new packages?
Any way to force P2 to install new packages? [message #897617] Tue, 24 July 2012 14:44 Go to next message
abadamcd1 abadamcd1 is currently offline abadamcd1 abadamcd1
Messages: 40
Registered: December 2011
Member
So I'm making an RCP application and I would like my program to automatically install new features whenever they're put up. I'm not talking about updated, but specifically finding new features in the repo and automatically installing them.

Any easy ways to do this?
Re: Any way to force P2 to install new packages? [message #929601 is a reply to message #897617] Mon, 01 October 2012 11:49 Go to previous message
Erik Emanuelsson is currently offline Erik Emanuelsson
Messages: 4
Registered: October 2012
Junior Member
I do not know if this is still a problem for you, but as we recently implemented auto install and update functionality to our RCP app maybe I can contribute a bit in this area. The code is based on stuff from the org.eclipse.equinox.p2.examples.rcp-projects.

First we made it possible to get control of the available update sites by a help method.
	/**
	 * Sets the update site list. Both enabled and disabled update sites can be added and the method also provides a flag that if set removes all previous
	 * update sites.
	 * 
	 * @param enabledUpdateSites
	 * @param disabledUpdateSites
	 * @param clearExistingUpdateSites If set, all currently existing update sites are removed.
	 */
	public static void setUpdateSites( Collection<URI> enabledUpdateSites, List<URI> disabledUpdateSites, boolean clearExistingUpdateSites )
	{
		List<MetadataRepositoryElement> repositoryElements = new ArrayList<MetadataRepositoryElement>();
//		AviXPlugin.getLog4J().debug( "setUpdateSitesClear BEGIN" ); //$NON-NLS-1$

//		AviXPlugin.getLog4J().info( MessageFormat.format( "Clear existing update sites = {0}", clearExistingUpdateSites ) ); //$NON-NLS-1$
		ProvisioningUI provisioningUI = ProvisioningUI.getDefaultUI();
		if ( !clearExistingUpdateSites ) {
			// Add already known update sites
			IMetadataRepositoryManager metaManager = ProvUI.getMetadataRepositoryManager(provisioningUI.getSession());
			int visibilityFlags = provisioningUI.getRepositoryTracker().getMetadataRepositoryFlags();
			URI[] currentlyEnabled = metaManager.getKnownRepositories(visibilityFlags);
			URI[] currentlyDisabled = metaManager.getKnownRepositories(IRepositoryManager.REPOSITORIES_DISABLED | visibilityFlags);
//			AviXPlugin.getLog4J().info( "Adding existing enabled update sites..." ); //$NON-NLS-1$
			for ( URI uri : currentlyEnabled ) {
				MetadataRepositoryElement metadataRepositoryElement = new MetadataRepositoryElement( null, uri, true );
//				AviXPlugin.getLog4J().info( MessageFormat.format( "enabled: {0}", uri ) ); //$NON-NLS-1$
				repositoryElements.add( metadataRepositoryElement );
			}
//			AviXPlugin.getLog4J().info( "Adding existing disabled update sites..." ); //$NON-NLS-1$
			for ( URI uri : currentlyDisabled ) {
				MetadataRepositoryElement metadataRepositoryElement = new MetadataRepositoryElement( null, uri, false );
//				AviXPlugin.getLog4J().info( MessageFormat.format( "disabled: {0}", uri ) ); //$NON-NLS-1$
				repositoryElements.add( metadataRepositoryElement );
			}
		}

//		AviXPlugin.getLog4J().info( "Adding enabled update sites..." ); //$NON-NLS-1$
		if ( enabledUpdateSites != null ) {
			for ( URI uri : enabledUpdateSites ) {
				MetadataRepositoryElement metadataRepositoryElement = new MetadataRepositoryElement( null, uri, true );
//				AviXPlugin.getLog4J().info( MessageFormat.format( "enabled: {0}", uri ) ); //$NON-NLS-1$
				repositoryElements.add( metadataRepositoryElement );
			}
		}
//		AviXPlugin.getLog4J().info( "Adding disabled update sites..." ); //$NON-NLS-1$
		if ( disabledUpdateSites != null ) {
			for ( URI uri : disabledUpdateSites ) {
				MetadataRepositoryElement metadataRepositoryElement = new MetadataRepositoryElement( null, uri, false );
//				AviXPlugin.getLog4J().info( MessageFormat.format( "disabled: {0}", uri ) ); //$NON-NLS-1$
				repositoryElements.add( metadataRepositoryElement );
			}
		}

		// Set the update site list.
		MetadataRepositoryElement[] elements = repositoryElements.toArray( new MetadataRepositoryElement[repositoryElements.size()] );
		ElementUtils.updateRepositoryUsingElements( provisioningUI, elements, null );

//		AviXPlugin.getLog4J().debug( "setUpdateSitesClear END" ); //$NON-NLS-1$
	}

Sorry for the commented logging statements, but we have found it very good to log a lot during start of the application to help customers with support issues.

Then we have a help method that helps us filter out only the latest version of all currently non installed IUs available in all enabled update sites. As I am not that familiar with the Query-stuff, it only handles IUGroups and it does not check dependencies of found IUs.
	/**
	 * Tries to dig out all installable IU groups from the currently enabled update sites.<br>
	 * <br>
	 * Note: The IUs are not currently tested for dependencies so they may not be able to be installed. 
	 * @param agent
	 * @param monitor
	 * @return All {@link IInstallableUnit}s that are found in the enabled update sites that are of type "IUGroup" and are not already installed.
	 */
	public static List<IInstallableUnit> getNonInstalledInstallableUnits( IProvisioningAgent agent, IProgressMonitor monitor )
	{
		List<IInstallableUnit> result = Collections.emptyList();
		
		ProvisioningUI provisioningUI = ProvisioningUI.getDefaultUI();
		IMetadataRepositoryManager metaManager = ProvUI.getMetadataRepositoryManager(provisioningUI.getSession());
//		IQueryResult<IInstallableUnit> queryResultAll = metaManager.query( QueryUtil.createIUAnyQuery(), monitor );
//		Set<IInstallableUnit> allInstallableUnits = queryResultAll.toUnmodifiableSet();
//		int size = allInstallableUnits.size();
		IQueryResult<IInstallableUnit> queryResult = metaManager.query( QueryUtil.createIUGroupQuery(), monitor );
		Set<IInstallableUnit> installableUnits = queryResult.toUnmodifiableSet();
		List<IInstallableUnit> notInstalledInstallableUnits = new ArrayList<IInstallableUnit>();
		for ( IInstallableUnit installableUnit : installableUnits ) {
			if (isInstalled( agent, monitor, installableUnit ) ) {
				continue;
			}
			notInstalledInstallableUnits.add( installableUnit );
		}
		
		// Filter out only last version of the installable units
		Map<String, IInstallableUnit> installableUnitMap = new HashMap<String, IInstallableUnit>();
		for ( IInstallableUnit installableUnit : notInstalledInstallableUnits ) {
			String id = installableUnit.getId();
			Version iuVersion = installableUnit.getVersion();
			
			IInstallableUnit mapInstallableUnit = installableUnitMap.get( id );
			if ( mapInstallableUnit != null ) {
				Version mapIUVersion = mapInstallableUnit.getVersion();
				if ( mapIUVersion.compareTo( iuVersion ) < 0 ) {
					installableUnitMap.put( id, installableUnit );
				}
			}
			else {
				installableUnitMap.put( id, installableUnit );
			}
		}
		
		// TODO: Filter out IUs that cannot be installed due to dependencies
		
		if ( !installableUnitMap.isEmpty() ) {
			result = new ArrayList<IInstallableUnit>( installableUnitMap.values() );
		}
		
		return result;
	}


The installation of IUs are handled by another help method
	/**
	 * Installs installable units in a synchronous manner. It is up to the caller to run this in a job if a background job is desired.
	 * @param agent
	 * @param monitor
	 * @param installableUnits
	 * @return
	 * @throws OperationCanceledException
	 */
	public static IStatus installInstallableUnits(IProvisioningAgent agent, IProgressMonitor monitor, List<IInstallableUnit> installableUnits ) throws OperationCanceledException
	{
		ProvisioningSession session = new ProvisioningSession( agent );
		InstallOperation operation = new InstallOperation( session, installableUnits );
		SubMonitor sub = SubMonitor.convert( monitor, "Installing new software...", 200 );
		IStatus status = operation.resolveModal( sub.newChild( 100 ) );
		if ( status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE ) {
			return status;
		}
		if ( status.getSeverity() == IStatus.CANCEL )
			throw new OperationCanceledException();

		if ( status.getSeverity() != IStatus.ERROR ) {
			// More complex status handling might include showing the user what updates
			// are available if there are multiples, differentiating patches vs. updates, etc.
			// In this example, we simply update as suggested by the operation.
			ProvisioningJob job = operation.getProvisioningJob( null );
			status = job.runModal( sub.newChild( 100 ) );
			if ( status.getSeverity() == IStatus.CANCEL )
				throw new OperationCanceledException();
		}
		
		return status;
	}


and the update of IUs by yet another help method
	/**
	 * Checks for updates and performs updates synchronously. It is up to the caller to run this in a job if a background job is desired.<br>
	 * <br>
	 * Code stolen from the example RCPMail application with prestartupdate in P2.
	 * 
	 * @param agent
	 * @param monitor
	 * @return
	 * @throws OperationCanceledException
	 */
	public static IStatus checkForUpdates(IProvisioningAgent agent, IProgressMonitor monitor) throws OperationCanceledException
	{
		ProvisioningSession session = new ProvisioningSession( agent );
		// the default update operation looks for updates to the currently
		// running profile, using the default profile root marker. To change
		// which installable units are being updated, use the more detailed
		// constructors.
		UpdateOperation operation = new UpdateOperation( session );
		SubMonitor sub = SubMonitor.convert( monitor, "Checking for updates...", 200 );
		IStatus status = operation.resolveModal( sub.newChild( 100 ) );
		if ( status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE ) {
			return status;
		}
		if ( status.getSeverity() == IStatus.CANCEL )
			throw new OperationCanceledException();

		if ( status.getSeverity() != IStatus.ERROR ) {
			// More complex status handling might include showing the user what updates
			// are available if there are multiples, differentiating patches vs. updates, etc.
			// In this example, we simply update as suggested by the operation.
			ProvisioningJob job = operation.getProvisioningJob( null );
			status = job.runModal( sub.newChild( 100 ) );
			if ( status.getSeverity() == IStatus.CANCEL )
				throw new OperationCanceledException();
		}
		return status;
	}


The actual code that calls these help methods are in turn called via a startup extension point we have that is called from the WorkbenchAdvisor.preStartup(). The method that does the work look like this for us. There are some stuff that I have left out like the properties code that enables the functionality based on settings, but I am pretty sure you can work around that if you make your own version of the code.
	public void preStartup()
	{
		// Perform update related stuff on application startup.
		// - Add update sites from preferences
		// - If enabled, perform auto update
		
		// Initialize the update sites. This can add update sites specified in the preferences.
		UpdateManager.initializeUpdateSites();
		
		if ( UpdateManager.isInstallOnStartup() || UpdateManager.isUpdateOnStartup() ) {
			// The AviXPlugin.bundleContext used below is a public variable in the product plugin activator. It is initialized in AviXPlugin.start( BundleContext context ). Just make it available in your own activator and fix the code.
			final IProvisioningAgent agent = (IProvisioningAgent)ServiceHelper.getService( AviXPlugin.bundleContext, IProvisioningAgent.SERVICE_NAME );
			if (agent == null) {
//				AviXPlugin.getLog4J().warn("No provisioning agent found. Application is not setup to handle automatic installations." ); //$NON-NLS-1$
			}
			else if ( !UpdateManager.isJustUpdated() ) {

				final IRunnableWithProgress runnable = new IRunnableWithProgress() {
					public void run( IProgressMonitor monitor ) throws InvocationTargetException, InterruptedException
					{
						// Check for new things to install.
						boolean restart = false;
						if ( UpdateManager.isInstallOnStartup() ) {
//							AviXPlugin.getLog4J().info("Checking for installable IUs..." ); //$NON-NLS-1$
							List<IInstallableUnit> installableUnits = UpdateManager.getNonInstalledInstallableUnits( agent, monitor );
							if ( !installableUnits.isEmpty() ) {
								IStatus installStatus = UpdateManager.installInstallableUnits( agent, monitor, installableUnits );
								if ( installStatus.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE ) {
									PlatformUI.getWorkbench().getDisplay().asyncExec( new Runnable() {
										public void run()
										{
//											AviXPlugin.getLog4J().info("No new IUs to install were found." ); //$NON-NLS-1$
//											MessageDialog.openInformation( null, "Updates", "No updates were found" );
										}
									} );
								}
								else if ( installStatus.getSeverity() != IStatus.ERROR ) {
//									AviXPlugin.getLog4J().info("New IUs installed. Restarting workbench." ); //$NON-NLS-1$
									UpdateManager.setJustUpdated( true );
									restart = true;
								}
								else {
//									AviXPlugin.getLog4J().info("Error occured during install operation: " + installStatus.getMessage() ); //$NON-NLS-1$
//									AviXPlugin.getLog4J().info( installStatus );
								}
							}
						}
						if ( UpdateManager.isUpdateOnStartup() ) {
//							AviXPlugin.getLog4J().info("Checking for updates..." ); //$NON-NLS-1$
							IStatus updateStatus = UpdateManager.checkForUpdates( agent, monitor );
							if ( updateStatus.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE ) {
								PlatformUI.getWorkbench().getDisplay().asyncExec( new Runnable() {
									public void run()
									{
//										AviXPlugin.getLog4J().info("No new IUs to install were found." ); //$NON-NLS-1$
//										MessageDialog.openInformation( null, "Updates", "No updates were found" );
									}
								} );
							}
							else if ( updateStatus.getSeverity() != IStatus.ERROR ) {
//								AviXPlugin.getLog4J().info("Updates installed. Restarting workbench." ); //$NON-NLS-1$
								UpdateManager.setJustUpdated( true );
								restart = true;
							}
							else {
//								AviXPlugin.getLog4J().info("Error occured during update operation: " + updateStatus.getMessage() ); //$NON-NLS-1$
//								AviXPlugin.getLog4J().info( updateStatus );
							}
						}
						
						if ( restart ) {
							// Make sure the restart call is made by the UI thread.
							PlatformUI.getWorkbench().getDisplay().asyncExec( new Runnable() {
								@Override
								public void run()
								{
//									AviXPlugin.getLog4J().info("Waiting for user input to restart..." ); //$NON-NLS-1$
									MessageDialog.openInformation( null, "Updates", "Application will now restart to complete the installation of updates." );
//									AviXPlugin.getLog4J().info("Performing restart of workbench." ); //$NON-NLS-1$
									PlatformUI.getWorkbench().restart();
								}
							} );
						}
					}
				};

				// Execute in UI thread
				Display.getCurrent().asyncExec( new Runnable() {
					@Override
					public void run()
					{
						try {
//							AviXPlugin.getLog4J().info("Showing progress bar for update check." ); //$NON-NLS-1$
							// Gives thread access errors
							new ProgressMonitorDialog(null).run(true, true, runnable);
						} catch (InvocationTargetException e) {
							e.printStackTrace();
						} catch (InterruptedException e) {
						}
					}
				} );
			}
			else {
				UpdateManager.setJustUpdated( false );
//				AviXPlugin.getLog4J().info("Do not check for installable IUs or updates this time as application was just restarted after updates/installations were made. Application will check for updates again next time it is started." ); //$NON-NLS-1$
			}
		}
	}


If you got this far I hope it helped you a little.

Edits:
* Fixed a code error in the update site help method
* Added a code comment about AviXPlugin.bundleContext in the preStartup method
* Fixed some obvious spelling errors

[Updated on: Mon, 01 October 2012 13:35]

Report message to a moderator

Previous Topic:Loading to many bundles during startup
Next Topic:How do I update an application without losing customizations in config.ini?
Goto Forum:
  


Current Time: Fri Aug 01 12:16:36 EDT 2014

Powered by FUDForum. Page generated in 0.07880 seconds