/******************************************************************************* * Copyright (c) 2008, 2015 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.equinox.internal.p2.touchpoint.eclipse.actions; import java.net.URI; import java.net.URISyntaxException; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.equinox.internal.p2.touchpoint.eclipse.Util; import org.eclipse.equinox.internal.provisional.p2.repository.RepositoryEvent; import org.eclipse.equinox.p2.core.IAgentLocation; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.engine.*; import org.eclipse.equinox.p2.engine.spi.ProvisioningAction; import org.eclipse.equinox.p2.repository.IRepository; import org.eclipse.equinox.p2.repository.IRepositoryManager; import org.eclipse.equinox.p2.repository.artifact.IArtifactRepositoryManager; import org.eclipse.equinox.p2.repository.metadata.IMetadataRepositoryManager; import org.eclipse.osgi.util.NLS; import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.Preferences; /** * Helper base class for dealing with repositories associated with profiles. Repositories * are associated with a profile by encoding the repository locations in a comma-delimited * list in a profile property. * @see AddRepositoryAction * @see RemoveRepositoryAction */ abstract class RepositoryAction extends ProvisioningAction { private static final String METADATA_REPOSITORY = "org.eclipse.equinox.p2.metadata.repository"; //$NON-NLS-1$ private static final String ARTIFACT_REPOSITORY = "org.eclipse.equinox.p2.artifact.repository"; //$NON-NLS-1$ private static final String NODE_REPOSITORIES = "repositories"; //$NON-NLS-1$ private static final String REPOSITORY_COUNT = "count"; //$NON-NLS-1$ private static final String KEY_URI = "uri"; //$NON-NLS-1$ private static final String KEY_ENABLED = "enabled"; //$NON-NLS-1$ private static final String KEY_NICKNAME = "nickname"; //$NON-NLS-1$ /** * Returns the repository manager of the given type, or <code>null</code> * if not available. */ private static IRepositoryManager<?> getRepositoryManager(IProvisioningAgent agent, int type) { if (type == IRepository.TYPE_METADATA) { return (IRepositoryManager<?>) agent.getService(IMetadataRepositoryManager.SERVICE_NAME); } else if (type == IRepository.TYPE_ARTIFACT) { return (IRepositoryManager<?>) agent.getService(IArtifactRepositoryManager.SERVICE_NAME); } return null; } /** * Associates the repository described by the given event with the given profile. * Has no effect if the repository is already associated with this profile. */ protected void addRepositoryToProfile(IAgentLocation agentLocation, IProfile profile, URI location, String nickname, int type, boolean enabled) { Preferences node = getRepositoryPreferenceNode(agentLocation, profile, location, type); int count = 0; if (repositoryExists(node)) { count = getRepositoryCount(node); // If a user has added a repository we need to set the initial count manually if (count == 0) count = 1; } node.put(KEY_URI, location.toString()); node.put(KEY_ENABLED, Boolean.toString(enabled)); if (nickname != null) node.put(KEY_NICKNAME, nickname); count++; setRepositoryCount(node, count); try { node.flush(); } catch (BackingStoreException e) { // TODO: perhaps an Exception should be passed backwards and associated with State } } /** * Adds the repository corresponding to the given event to the currently running instance. */ protected void addToSelf(IProvisioningAgent agent, IAgentLocation agentLocation, RepositoryEvent event) { IRepositoryManager<?> manager = getRepositoryManager(agent, event.getRepositoryType()); final URI location = event.getRepositoryLocation(); Preferences node = getRepositoryPreferenceNode(agentLocation, null, location, event.getRepositoryType()); int count = getRepositoryCount(node); if (manager.contains(location)) { // If a user as added a repository we need to set the initial count manually if (count == 0) count = 1; } else { if (manager != null) manager.addRepository(location); } // increment the counter & send to preferences count++; setRepositoryCount(node, count); if (!event.isRepositoryEnabled()) manager.setEnabled(location, false); final String name = event.getRepositoryNickname(); if (name != null) manager.setRepositoryProperty(location, IRepository.PROP_NICKNAME, name); } protected RepositoryEvent createEvent(Map<String, Object> parameters) throws CoreException { String parm = (String) parameters.get(ActionConstants.PARM_REPOSITORY_LOCATION); if (parm == null) throw new CoreException(Util.createError(NLS.bind(Messages.parameter_not_set, ActionConstants.PARM_REPOSITORY_LOCATION, getId()))); URI location = null; try { location = new URI(parm); } catch (URISyntaxException e) { throw new CoreException(Util.createError(NLS.bind(Messages.parameter_not_set, ActionConstants.PARM_REPOSITORY_LOCATION, getId()), e)); } parm = (String) parameters.get(ActionConstants.PARM_REPOSITORY_TYPE); if (parm == null) throw new CoreException(Util.createError(NLS.bind(Messages.parameter_not_set, ActionConstants.PARM_REPOSITORY_TYPE, getId()))); int type = 0; try { type = Integer.parseInt(parm); } catch (NumberFormatException e) { throw new CoreException(Util.createError(NLS.bind(Messages.parameter_not_set, ActionConstants.PARM_REPOSITORY_TYPE, getId()), e)); } String name = (String) parameters.get(ActionConstants.PARM_REPOSITORY_NICKNAME); //default is to be enabled String enablement = (String) parameters.get(ActionConstants.PARM_REPOSITORY_ENABLEMENT); boolean enabled = enablement == null ? true : Boolean.parseBoolean(enablement); return RepositoryEvent.newDiscoveryEvent(location, name, type, enabled); } /** * Returns the id of this action. */ protected abstract String getId(); /** * Return <code>true</code> if the given profile is the currently running profile, * and <code>false</code> otherwise. */ protected boolean isSelfProfile(IProfileRegistry registry, IProfile profile) { //if we can't determine the current profile, assume we are running on self if (profile == null) return true; if (registry == null) return false; final IProfile selfProfile = registry.getProfile(IProfileRegistry.SELF); //if we can't determine the self profile, assume we are running on self if (selfProfile == null) return true; return profile.getProfileId().equals(selfProfile.getProfileId()); } /** * Removes the repository corresponding to the given event from the currently running instance. */ protected void removeFromSelf(IProvisioningAgent agent, IAgentLocation agentLocation, RepositoryEvent event) { IRepositoryManager<?> manager = getRepositoryManager(agent, event.getRepositoryType()); Preferences node = getRepositoryPreferenceNode(agentLocation, null, event.getRepositoryLocation(), event.getRepositoryType()); int count = getRepositoryCount(node); // modify the repository count before (potentially) removing the preference node setRepositoryCount(node, --count); if (count < 1 && manager != null) manager.removeRepository(event.getRepositoryLocation()); } /** * Removes the association between the repository described by the given event * and the given profile. Has no effect if the location is not already associated with * this profile. */ protected void removeRepositoryFromProfile(IAgentLocation agentLocation, IProfile profile, URI location, int type) { Preferences node = getRepositoryPreferenceNode(agentLocation, profile, location, type); int count = getRepositoryCount(node); if (--count < 1) { // TODO: Remove all associated values try { String[] keys = node.keys(); for (int i = 0; i < keys.length; i++) node.remove(keys[i]); } catch (BackingStoreException e) { // TODO: Should this be passed back to be associated with State? } } else setRepositoryCount(node, count); try { node.flush(); } catch (BackingStoreException e) { // TODO: perhaps an Exception should be passed backwards and associated with State } } /* * Get the counter associated with a repository */ protected int getRepositoryCount(Preferences node) { return node.getInt(REPOSITORY_COUNT, 0); } /* * Sets the counter associated with this repository to a specific value */ protected void setRepositoryCount(Preferences node, int count) { if (count < 1) node.remove(REPOSITORY_COUNT); else node.putInt(REPOSITORY_COUNT, count); } /* * Determine if a repository is already known */ protected boolean repositoryExists(Preferences node) { if (node.get(KEY_URI, null) == null) return false; return true; } /* * Get the preference node associated with profile & location */ protected Preferences getRepositoryPreferenceNode(IAgentLocation agentLocation, IProfile profile, URI location, int type) { String key = type == IRepository.TYPE_METADATA ? METADATA_REPOSITORY : ARTIFACT_REPOSITORY; String profileId = profile == null ? IProfileRegistry.SELF : profile.getProfileId(); return new ProfileScope(agentLocation, profileId).getNode(key + '/' + NODE_REPOSITORIES + '/' + getKey(location)); } /* * Copied from AbstractRepositoryManager */ private String getKey(URI location) { String key = location.toString().replace('/', '_'); //remove trailing slash if (key.endsWith("_")) //$NON-NLS-1$ key = key.substring(0, key.length() - 1); return key; } protected IProvisioningAgent getAgent(Map<String, Object> parameters) throws CoreException { //We shouldn't really know about the session parameter IProvisioningAgent agent = (IProvisioningAgent) parameters.get("agent"); //$NON-NLS-1$ if (agent == null) throw new CoreException(Util.createError(NLS.bind(Messages.parameter_not_set, "agent", getId()))); //$NON-NLS-1$ return agent; } }