| /******************************************************************************* |
| * Copyright (c) 2007, 2017 IBM Corporation and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.equinox.internal.p2.engine; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import org.eclipse.core.runtime.*; |
| import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; |
| import org.eclipse.equinox.p2.engine.spi.Touchpoint; |
| import org.eclipse.equinox.p2.metadata.*; |
| import org.eclipse.osgi.util.NLS; |
| |
| //TODO This needs to support multiple version of each touchpoint and have a lookup that supports version semantics |
| public class TouchpointManager implements IRegistryChangeListener { |
| |
| private static final String PT_TOUCHPOINTS = "touchpoints"; //$NON-NLS-1$ |
| private static final String ELEMENT_TOUCHPOINT = "touchpoint"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_CLASS = "class"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_TYPE = "type"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_VERSION = "version"; //$NON-NLS-1$ |
| |
| private class TouchpointEntry { |
| |
| private IConfigurationElement element; |
| private boolean createdExtension = false; |
| private Touchpoint touchpoint = null; |
| |
| public TouchpointEntry(IConfigurationElement element) { |
| this.element = element; |
| } |
| |
| public Touchpoint getTouchpoint() { |
| if (!createdExtension) { |
| String id = getType(); |
| try { |
| Touchpoint touchpointInstance = (Touchpoint) element.createExecutableExtension(ATTRIBUTE_CLASS); |
| if (touchpointInstance != null) { |
| this.touchpoint = touchpointInstance; |
| } else { |
| String errorMsg = NLS.bind(Messages.TouchpointManager_Null_Creating_Touchpoint_Extension, id); |
| throw new CoreException(new Status(IStatus.ERROR, EngineActivator.ID, 1, errorMsg, null)); |
| } |
| } catch (CoreException cexcpt) { |
| LogHelper.log(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.TouchpointManager_Exception_Creating_Touchpoint_Extension, id), cexcpt)); |
| } catch (ClassCastException ccexcpt) { |
| LogHelper.log(new Status(IStatus.ERROR, EngineActivator.ID, NLS.bind(Messages.TouchpointManager_Exception_Creating_Touchpoint_Extension, id), ccexcpt)); |
| } |
| // Mark as created even in error cases, |
| // so exceptions are not logged multiple times |
| createdExtension = true; |
| } |
| return this.touchpoint; |
| } |
| |
| public Version getVersion() { |
| try { |
| return Version.create(element.getAttribute(ATTRIBUTE_VERSION)); |
| } catch (InvalidRegistryObjectException e) { |
| return null; |
| } |
| } |
| |
| public String getType() { |
| try { |
| return element.getAttribute(ATTRIBUTE_TYPE); |
| } catch (InvalidRegistryObjectException e) { |
| return null; |
| } |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder result = new StringBuilder(element.toString()); |
| if (createdExtension) { |
| String touchpointString = touchpoint != null ? touchpoint.toString() : "not created"; //$NON-NLS-1$ |
| result.append(" => " + touchpointString); //$NON-NLS-1$ |
| } |
| return result.toString(); |
| } |
| } |
| |
| // TODO: Do we really want to store the touchpoints? The danger is |
| // that if two installations are performed simultaneously, then... |
| // TODO: Figure out locking, concurrency requirements for touchpoints. |
| private Map<String, TouchpointEntry> touchpointEntries; |
| |
| public TouchpointManager() { |
| RegistryFactory.getRegistry().addRegistryChangeListener(this, EngineActivator.ID); |
| } |
| |
| /* |
| * Return the touchpoint which is registered for the given type, |
| * or <code>null</code> if none are registered. |
| */ |
| public synchronized Touchpoint getTouchpoint(ITouchpointType type) { |
| if (type == null) |
| throw new IllegalArgumentException(Messages.TouchpointManager_Null_Touchpoint_Type_Argument); |
| return getTouchpoint(type.getId(), type.getVersion().toString()); |
| } |
| |
| /* |
| * Return the touchpoint which is registered for the given type and optionally version, |
| * or <code>null</code> if none are registered. |
| */ |
| public Touchpoint getTouchpoint(String typeId, String versionRange) { |
| if (typeId == null || typeId.length() == 0) |
| throw new IllegalArgumentException(Messages.TouchpointManager_Null_Touchpoint_Type_Argument); |
| |
| TouchpointEntry entry = getTouchpointEntries().get(typeId); |
| if (entry == null) |
| return null; |
| if (versionRange != null) { |
| VersionRange range = VersionRange.create(versionRange); |
| if (!range.isIncluded(entry.getVersion())) |
| return null; |
| } |
| |
| return entry.getTouchpoint(); |
| } |
| |
| /* |
| * Construct a map of the extensions that implement the touchpoints extension point. |
| */ |
| private synchronized Map<String, TouchpointEntry> getTouchpointEntries() { |
| if (touchpointEntries != null) |
| return touchpointEntries; |
| |
| IExtensionPoint point = RegistryFactory.getRegistry().getExtensionPoint(EngineActivator.ID, PT_TOUCHPOINTS); |
| IExtension[] extensions = point.getExtensions(); |
| touchpointEntries = new HashMap<>(extensions.length); |
| for (IExtension extension : extensions) { |
| try { |
| IConfigurationElement[] elements = extension.getConfigurationElements(); |
| for (IConfigurationElement element : elements) { |
| String elementName = element.getName(); |
| if (!ELEMENT_TOUCHPOINT.equalsIgnoreCase(elementName)) { |
| reportError(NLS.bind(Messages.TouchpointManager_Incorrectly_Named_Extension, element.getName(), ELEMENT_TOUCHPOINT)); |
| continue; |
| } |
| String id = element.getAttribute(ATTRIBUTE_TYPE); |
| if (id == null) { |
| reportError(NLS.bind(Messages.TouchpointManager_Attribute_Not_Specified, ATTRIBUTE_TYPE)); |
| continue; |
| } |
| if (touchpointEntries.get(id) == null) { |
| touchpointEntries.put(id, new TouchpointEntry(element)); |
| } else { |
| reportError(NLS.bind(Messages.TouchpointManager_Conflicting_Touchpoint_Types, id)); |
| } |
| } |
| }catch (InvalidRegistryObjectException e) { |
| //skip this extension |
| } |
| } |
| return touchpointEntries; |
| } |
| |
| static void reportError(String errorMsg) { |
| Status errorStatus = new Status(IStatus.ERROR, EngineActivator.ID, 1, errorMsg, null); |
| LogHelper.log(errorStatus); |
| } |
| |
| @Override |
| public synchronized void registryChanged(IRegistryChangeEvent event) { |
| // just flush the cache when something changed. It will be recomputed on demand. |
| touchpointEntries = null; |
| } |
| } |