blob: fb5e4dfff3cb82c2e52073a3e9d447a33b9592cf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2009 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.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;
}
}
public String toString() {
StringBuffer result = new StringBuffer(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 = new VersionRange(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<String, TouchpointEntry>(extensions.length);
for (int i = 0; i < extensions.length; i++) {
try {
IConfigurationElement[] elements = extensions[i].getConfigurationElements();
for (int j = 0; j < elements.length; j++) {
String elementName = elements[j].getName();
if (!ELEMENT_TOUCHPOINT.equalsIgnoreCase(elementName)) {
reportError(NLS.bind(Messages.TouchpointManager_Incorrectly_Named_Extension, elements[j].getName(), ELEMENT_TOUCHPOINT));
continue;
}
String id = elements[j].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(elements[j]));
} 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);
}
/* (non-Javadoc)
* @see org.eclipse.core.runtime.IRegistryChangeListener#registryChanged(org.eclipse.core.runtime.IRegistryChangeEvent)
*/
public synchronized void registryChanged(IRegistryChangeEvent event) {
// just flush the cache when something changed. It will be recomputed on demand.
touchpointEntries = null;
}
}