blob: 6b29cc85aef2d8b556e43dce5105a05a5a09618d [file] [log] [blame]
/*******************************************************************************
* 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;
}
}