Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Pingel2013-06-27 13:19:51 +0000
committerSteffen Pingel2013-06-28 11:46:53 +0000
commit7d54bbdcace41210385cab6463fae1f096231866 (patch)
tree761e62265f9e58da6073ecc78dca20b3e64bd792 /org.eclipse.mylyn.tasks.core
parent6f2fb1fab8edcec43f683dda4e5e96f722d3daa6 (diff)
downloadorg.eclipse.mylyn.tasks-7d54bbdcace41210385cab6463fae1f096231866.tar.gz
org.eclipse.mylyn.tasks-7d54bbdcace41210385cab6463fae1f096231866.tar.xz
org.eclipse.mylyn.tasks-7d54bbdcace41210385cab6463fae1f096231866.zip
408511: [api] provide an extension to dynamically contribute connectors
Change-Id: If0acbbd24a543d13414ed4bf862a145803b6121c Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=408511
Diffstat (limited to 'org.eclipse.mylyn.tasks.core')
-rw-r--r--org.eclipse.mylyn.tasks.core/META-INF/MANIFEST.MF1
-rw-r--r--org.eclipse.mylyn.tasks.core/plugin.xml1
-rw-r--r--org.eclipse.mylyn.tasks.core/schema/repositoryConnectorContributor.exsd102
-rw-r--r--org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/util/RepositoryConnectorExtensionReader.java98
-rw-r--r--org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/spi/RepositoryConnectorContributor.java35
-rw-r--r--org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/spi/RepositoryConnectorDescriptor.java (renamed from org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/RepositoryConnectorDescriptor.java)28
6 files changed, 244 insertions, 21 deletions
diff --git a/org.eclipse.mylyn.tasks.core/META-INF/MANIFEST.MF b/org.eclipse.mylyn.tasks.core/META-INF/MANIFEST.MF
index 6c8d85a3c..59f8a8698 100644
--- a/org.eclipse.mylyn.tasks.core/META-INF/MANIFEST.MF
+++ b/org.eclipse.mylyn.tasks.core/META-INF/MANIFEST.MF
@@ -25,5 +25,6 @@ Export-Package: org.eclipse.mylyn.internal.provisional.tasks.core;x-internal:=tr
org.eclipse.mylyn.tasks.core.activity,
org.eclipse.mylyn.tasks.core.context,
org.eclipse.mylyn.tasks.core.data,
+ org.eclipse.mylyn.tasks.core.spi,
org.eclipse.mylyn.tasks.core.sync
Bundle-Localization: plugin
diff --git a/org.eclipse.mylyn.tasks.core/plugin.xml b/org.eclipse.mylyn.tasks.core/plugin.xml
index 219b5e723..cb398f106 100644
--- a/org.eclipse.mylyn.tasks.core/plugin.xml
+++ b/org.eclipse.mylyn.tasks.core/plugin.xml
@@ -17,4 +17,5 @@
<extension-point id="taskActivationListeners" name="Task Activation Listeners" schema="schema/taskActivationListeners.exsd"/>
<extension-point id="activityMonitor" name="Task Activity Monitor" schema="schema/activityMonitor.exsd"/>
<extension-point id="contextStore" name="Task Context Store" schema="schema/contextStore.exsd"/>
+ <extension-point id="repositoryConnectorContributor" name="Repository Connector Contributor" schema="schema/repositoryConnectorContributor.exsd"/>
</plugin>
diff --git a/org.eclipse.mylyn.tasks.core/schema/repositoryConnectorContributor.exsd b/org.eclipse.mylyn.tasks.core/schema/repositoryConnectorContributor.exsd
new file mode 100644
index 000000000..1009f3f5e
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.core/schema/repositoryConnectorContributor.exsd
@@ -0,0 +1,102 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.mylyn.tasks.core" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="org.eclipse.mylyn.tasks.core" id="repositoryConnectorContributor" name="Repository Connector Contributor"/>
+ </appInfo>
+ <documentation>
+ An extension point for contributing repository connector instances at runtime.
+ </documentation>
+ </annotation>
+
+ <element name="extension">
+ <annotation>
+ <appInfo>
+ <meta.element />
+ </appInfo>
+ </annotation>
+ <complexType>
+ <choice>
+ <element ref="contributor"/>
+ </choice>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+
+ </documentation>
+ <appInfo>
+ <meta.attribute translatable="true"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="contributor">
+ <complexType>
+ <attribute name="class" type="string">
+ <annotation>
+ <documentation>
+ The class that contributes connector descriptors.
+ </documentation>
+ <appInfo>
+ <meta.attribute kind="java" basedOn="org.eclipse.mylyn.tasks.core.RepositoryConnectorDescriptor:"/>
+ </appInfo>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="since"/>
+ </appInfo>
+ <documentation>
+ 3.10
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="examples"/>
+ </appInfo>
+ <documentation>
+ [Enter extension point usage example here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiinfo"/>
+ </appInfo>
+ <documentation>
+ [Enter API information here.]
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+ [Enter information about supplied implementation of this extension point.]
+ </documentation>
+ </annotation>
+
+
+</schema>
diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/util/RepositoryConnectorExtensionReader.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/util/RepositoryConnectorExtensionReader.java
index d4103c7ec..2137fbf98 100644
--- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/util/RepositoryConnectorExtensionReader.java
+++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/internal/tasks/core/util/RepositoryConnectorExtensionReader.java
@@ -12,6 +12,7 @@
package org.eclipse.mylyn.internal.tasks.core.util;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
@@ -23,8 +24,11 @@ import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.Status;
import org.eclipse.mylyn.commons.core.StatusHandler;
import org.eclipse.mylyn.internal.tasks.core.ITasksCoreConstants;
@@ -33,7 +37,8 @@ import org.eclipse.mylyn.internal.tasks.core.externalization.TaskListExternalize
import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
import org.eclipse.mylyn.tasks.core.AbstractRepositoryMigrator;
import org.eclipse.mylyn.tasks.core.AbstractTaskListMigrator;
-import org.eclipse.mylyn.tasks.core.RepositoryConnectorDescriptor;
+import org.eclipse.mylyn.tasks.core.spi.RepositoryConnectorContributor;
+import org.eclipse.mylyn.tasks.core.spi.RepositoryConnectorDescriptor;
import org.eclipse.osgi.util.NLS;
public class RepositoryConnectorExtensionReader {
@@ -48,6 +53,9 @@ public class RepositoryConnectorExtensionReader {
public static final String ATTR_CLASS = "class"; //$NON-NLS-1$
+ private static final String EXTENSION_CONTRIBUTORS = ITasksCoreConstants.ID_PLUGIN
+ + ".repositoryConnectorContributor"; //$NON-NLS-1$
+
private static class ConnectorFactory {
private AbstractRepositoryConnector connector;
@@ -61,6 +69,8 @@ public class RepositoryConnectorExtensionReader {
private final String pluginId;
public ConnectorFactory(RepositoryConnectorDescriptor descriptor, String pluginId) {
+ Assert.isNotNull(pluginId);
+ Assert.isNotNull(pluginId);
this.descriptor = descriptor;
this.pluginId = pluginId;
}
@@ -196,6 +206,10 @@ public class RepositoryConnectorExtensionReader {
private final TaskRepositoryManager repositoryManager;
+ private final List<ConnectorFactory> factories = new ArrayList<ConnectorFactory>();
+
+ private MultiStatus result;
+
public RepositoryConnectorExtensionReader(TaskListExternalizer taskListExternalizer,
TaskRepositoryManager repositoryManager) {
this.taskListExternalizer = taskListExternalizer;
@@ -203,28 +217,69 @@ public class RepositoryConnectorExtensionReader {
}
public void registerConnectors(IExtensionPoint repositoriesExtensionPoint) {
- List<ConnectorFactory> descriptors = new ArrayList<ConnectorFactory>();
- MultiStatus result = new MultiStatus(ITasksCoreConstants.ID_PLUGIN, 0,
- "Repository connectors failed to load.", null); //$NON-NLS-1$
+ if (result != null) {
+ throw new IllegalStateException("registerConnectors may only be invoked once"); //$NON-NLS-1$
+ }
+
+ result = new MultiStatus(ITasksCoreConstants.ID_PLUGIN, 0, "Repository connectors failed to load.", null); //$NON-NLS-1$
+
+ Map<String, List<ConnectorFactory>> factoryById = readFromRepositoriesExtensionPoint(repositoriesExtensionPoint);
+ checkForConflicts(factoryById);
- Map<String, List<ConnectorFactory>> factoryById = readFromRepositoriesExtensionPoint(
- repositoriesExtensionPoint, descriptors);
- checkForConflicts(descriptors, result, factoryById);
+ readFromContributorsExtensionPoint();
- Map<String, List<ConnectorFactory>> factoryByConnectorKind = createConnectorInstances(descriptors, result);
- checkForConflicts(descriptors, result, factoryByConnectorKind);
+ Map<String, List<ConnectorFactory>> factoryByConnectorKind = createConnectorInstances();
+ checkForConflicts(factoryByConnectorKind);
- registerConnectorInstances(descriptors, result);
+ registerConnectorInstances();
if (!result.isOK()) {
StatusHandler.log(result);
}
}
- public Map<String, List<ConnectorFactory>> createConnectorInstances(List<ConnectorFactory> descriptors,
- MultiStatus result) {
+ private void readFromContributorsExtensionPoint() {
+ IExtensionPoint repositoriesExtensionPoint = Platform.getExtensionRegistry().getExtensionPoint(
+ EXTENSION_CONTRIBUTORS);
+ IExtension[] extensions = repositoriesExtensionPoint.getExtensions();
+ for (IExtension extension : extensions) {
+ IConfigurationElement[] elements = extension.getConfigurationElements();
+ for (IConfigurationElement element : elements) {
+ addDescriptorsFromContributor(element);
+ }
+ }
+ }
+
+ private void addDescriptorsFromContributor(final IConfigurationElement element) {
+ SafeRunner.run(new ISafeRunnable() {
+
+ @Override
+ public void run() throws Exception {
+ RepositoryConnectorContributor contributor = (RepositoryConnectorContributor) element.createExecutableExtension(ATTR_CLASS);
+ Collection<RepositoryConnectorDescriptor> descriptors = contributor.getDescriptors();
+ if (descriptors == null) {
+ result.add(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, NLS.bind(
+ "Could not load connectors contributed by ''{0}''", element.getContributor().getName()))); //$NON-NLS-1$
+ return;
+ }
+ for (RepositoryConnectorDescriptor descriptor : descriptors) {
+ if (descriptor != null) {
+ factories.add(new ConnectorFactory(descriptor, element.getContributor().getName()));
+ }
+ }
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // ignore
+
+ }
+ });
+ }
+
+ public Map<String, List<ConnectorFactory>> createConnectorInstances() {
Map<String, List<ConnectorFactory>> factoryByConnectorKind = new LinkedHashMap<String, List<ConnectorFactory>>();
- for (ConnectorFactory descriptor : descriptors) {
+ for (ConnectorFactory descriptor : factories) {
IStatus status = descriptor.createConnector();
if (status.isOK() && descriptor.getConnector() != null) {
add(factoryByConnectorKind, descriptor.getConnectorKind(), descriptor);
@@ -235,11 +290,11 @@ public class RepositoryConnectorExtensionReader {
return factoryByConnectorKind;
}
- private void registerConnectorInstances(List<ConnectorFactory> descriptors, MultiStatus result) {
+ private void registerConnectorInstances() {
List<AbstractTaskListMigrator> taskListmigrators = new ArrayList<AbstractTaskListMigrator>();
List<AbstractRepositoryMigrator> repositoryMigrators = new ArrayList<AbstractRepositoryMigrator>();
- for (ConnectorFactory descriptor : descriptors) {
+ for (ConnectorFactory descriptor : factories) {
if (descriptor.getConnector() != null) {
repositoryManager.addRepositoryConnector(descriptor.getConnector());
@@ -268,7 +323,7 @@ public class RepositoryConnectorExtensionReader {
}
private Map<String, List<ConnectorFactory>> readFromRepositoriesExtensionPoint(
- IExtensionPoint repositoriesExtensionPoint, List<ConnectorFactory> descriptors) {
+ IExtensionPoint repositoriesExtensionPoint) {
// read core and migrator extensions to check for id conflicts
Map<String, List<ConnectorFactory>> factoryById = new LinkedHashMap<String, List<ConnectorFactory>>();
@@ -291,7 +346,7 @@ public class RepositoryConnectorExtensionReader {
descriptor.taskListMigratorElement = tasklistMigratorElement;
descriptor.repositoryMigratorElement = repositoryMigratorElement;
ConnectorFactory factory = new ConnectorFactory(descriptor, descriptor.getPluginId());
- descriptors.add(factory);
+ factories.add(factory);
if (descriptor.getId() != null) {
add(factoryById, descriptor.getId(), factory);
}
@@ -300,8 +355,7 @@ public class RepositoryConnectorExtensionReader {
return factoryById;
}
- private void checkForConflicts(List<ConnectorFactory> descriptors, MultiStatus result,
- Map<String, List<ConnectorFactory>> descriptorById) {
+ private void checkForConflicts(Map<String, List<ConnectorFactory>> descriptorById) {
for (Map.Entry<String, List<ConnectorFactory>> entry : descriptorById.entrySet()) {
if (entry.getValue().size() > 1) {
MultiStatus status = new MultiStatus(ITasksCoreConstants.ID_PLUGIN, 0, NLS.bind(
@@ -310,7 +364,7 @@ public class RepositoryConnectorExtensionReader {
status.add(new Status(IStatus.ERROR, ITasksCoreConstants.ID_PLUGIN, NLS.bind(
"All extensions contributed by ''{0}'' have been disabled.", factory.getPluginId()), null)); //$NON-NLS-1$
disabledContributors.add(factory.getPluginId());
- descriptors.remove(factory);
+ factories.remove(factory);
}
result.add(status);
}
@@ -330,4 +384,8 @@ public class RepositoryConnectorExtensionReader {
return new HashSet<String>(disabledContributors);
}
+ public IStatus getResult() {
+ return result;
+ }
+
}
diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/spi/RepositoryConnectorContributor.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/spi/RepositoryConnectorContributor.java
new file mode 100644
index 000000000..de00d6f39
--- /dev/null
+++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/spi/RepositoryConnectorContributor.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2013 Tasktop Technologies 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:
+ * Tasktop Technologies - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.tasks.core.spi;
+
+import java.util.List;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
+
+/**
+ * Implementors of this class can contribute instances of {@link AbstractRepositoryConnector} at runtime.
+ *
+ * @since 3.10
+ */
+public abstract class RepositoryConnectorContributor {
+
+ /**
+ * Returns a list of descriptors for connectors that are to be contributed. This method is invoked when the tasks
+ * core framework is initialized.
+ *
+ * @return a list of descriptors
+ */
+ @NonNull
+ public abstract List<RepositoryConnectorDescriptor> getDescriptors();
+
+}
diff --git a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/RepositoryConnectorDescriptor.java b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/spi/RepositoryConnectorDescriptor.java
index f987dacf2..a0151d122 100644
--- a/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/RepositoryConnectorDescriptor.java
+++ b/org.eclipse.mylyn.tasks.core/src/org/eclipse/mylyn/tasks/core/spi/RepositoryConnectorDescriptor.java
@@ -9,17 +9,43 @@
* Tasktop Technologies - initial API and implementation
*******************************************************************************/
-package org.eclipse.mylyn.tasks.core;
+package org.eclipse.mylyn.tasks.core.spi;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.mylyn.tasks.core.AbstractRepositoryConnector;
+import org.eclipse.mylyn.tasks.core.AbstractRepositoryMigrator;
+import org.eclipse.mylyn.tasks.core.AbstractTaskListMigrator;
/**
+ * A descriptor for an {@link AbstractRepositoryConnector} instance.
+ *
* @since 3.10
*/
public abstract class RepositoryConnectorDescriptor {
+ /**
+ * Creates and returns a connector instance. Only invoked once.
+ *
+ * @return a connector instance
+ */
+ @NonNull
public abstract AbstractRepositoryConnector createRepositoryConnector();
+ /**
+ * Creates and returns a task list migrator instance. Only invoked once.
+ *
+ * @return a migrator or null if no migrator is provided
+ */
+ @Nullable
public abstract AbstractTaskListMigrator createTaskListMigrator();
+ /**
+ * Creates and returns a repository migrator instance. Only invoked once.
+ *
+ * @return a migrator or null if no migrator is provided
+ */
+ @Nullable
public abstract AbstractRepositoryMigrator createRepositoryMigrator();
}

Back to the top