diff --git a/ui/org.eclipse.pde.core/.settings/.api_filters b/ui/org.eclipse.pde.core/.settings/.api_filters index f26c3f1cfb..8d60950802 100644 --- a/ui/org.eclipse.pde.core/.settings/.api_filters +++ b/ui/org.eclipse.pde.core/.settings/.api_filters @@ -1,5 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui/org.eclipse.pde.core/META-INF/MANIFEST.MF b/ui/org.eclipse.pde.core/META-INF/MANIFEST.MF index 898c1c96cf..604ef4b871 100644 --- a/ui/org.eclipse.pde.core/META-INF/MANIFEST.MF +++ b/ui/org.eclipse.pde.core/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %name Bundle-SymbolicName: org.eclipse.pde.core; singleton:=true -Bundle-Version: 3.19.100.qualifier +Bundle-Version: 3.20.0.qualifier Bundle-Activator: org.eclipse.pde.internal.core.PDECore Bundle-Vendor: %provider-name Bundle-Localization: plugin @@ -101,6 +101,7 @@ Import-Package: aQute.bnd.build;version="[4.4.0,5.0.0)", org.eclipse.equinox.internal.p2.publisher.eclipse, org.eclipse.equinox.p2.publisher, org.eclipse.equinox.p2.publisher.eclipse, + org.osgi.service.event;version="[1.4.0,2.0.0)";resolution:=optional, org.osgi.service.repository;version="[1.1.0,2.0.0)", org.osgi.util.promise;version="[1.3.0,2.0.0)" Require-Bundle: diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/target/TargetEvents.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/target/TargetEvents.java index 23cdcaa935..da74c97df5 100644 --- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/target/TargetEvents.java +++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/core/target/TargetEvents.java @@ -12,28 +12,119 @@ ********************************************************************************/ package org.eclipse.pde.core.target; +import org.eclipse.e4.core.services.events.IEventBroker; +import org.osgi.service.event.EventHandler; + /** - * Target events and event topic definitions + * Target events and event topic definitions. Can be used as follows: + * + *
+ * EventHandler eventHandler = event -> {
+ * 	Object data = event.getProperty(IEventBroker.DATA);
+ * 	if (data instanceof ITargetHandle) {
+ * 		ITargetHandle handle = (ITargetHandle) data;
+ * 		// Work with the target handle...
+ * 	}
+ * };
  *
+ * IEclipseContext context = EclipseContextFactory.getServiceContext(bundleContext);
+ * IEventBroker broker = context.get(IEventBroker.class);
+ * if (broker != null) {
+ * 	broker.subscribe(TargetEvents.TOPIC_TARGET_SAVED, eventHandler);
+ * 	// Do not forget to unsubscribe later!
+ * }
+ * 
+ * + * @see ITargetPlatformService + * @see IEventBroker#subscribe(String, EventHandler) + * @see IEventBroker#subscribe(String, String, EventHandler, boolean) + * @see IEventBroker#unsubscribe(EventHandler) * @since 3.13 */ public class TargetEvents { /** - * Base topic for all Target events + * Base topic for all target events. */ public static final String TOPIC_BASE = "org/eclipse/pde/core/target/TargetEvents"; //$NON-NLS-1$ /** - * Topic for all Target events + * Topic for all target events. */ public static final String TOPIC_ALL = TOPIC_BASE + "/*"; //$NON-NLS-1$ /** - * Sent when workspace target definition is changed + * Sent when workspace target definition is changed. Can be used as follows: + * + *
+	 * EventHandler eventHandler = event -> {
+	 * 	Object data = event.getProperty(IEventBroker.DATA);
+	 * 	if (data instanceof ITargetDefinition) {
+	 * 		ITargetDefinition definition = (ITargetDefinition) data;
+	 * 		// Work with the target definition...
+	 * 	}
+	 * };
+	 *
+	 * IEclipseContext context = EclipseContextFactory.getServiceContext(bundleContext);
+	 * IEventBroker broker = context.get(IEventBroker.class);
+	 * if (broker != null) {
+	 * 	broker.subscribe(TargetEvents.TOPIC_WORKSPACE_TARGET_CHANGED, eventHandler);
+	 * 	// Do not forget to unsubscribe later!
+	 * }
+	 * 
* * @see ITargetPlatformService#getWorkspaceTargetDefinition() */ public static final String TOPIC_WORKSPACE_TARGET_CHANGED = TOPIC_BASE + "/workspaceTargetChanged"; //$NON-NLS-1$ + /** + * Sent when a target is saved. Can be used as follows: + * + *
+	 * EventHandler eventHandler = event -> {
+	 * 	Object data = event.getProperty(IEventBroker.DATA);
+	 * 	if (data instanceof ITargetHandle) {
+	 * 		ITargetHandle handle = (ITargetHandle) data;
+	 * 		// Work with the target handle...
+	 * 	}
+	 * };
+	 *
+	 * IEclipseContext context = EclipseContextFactory.getServiceContext(bundleContext);
+	 * IEventBroker broker = context.get(IEventBroker.class);
+	 * if (broker != null) {
+	 * 	broker.subscribe(TargetEvents.TOPIC_TARGET_SAVED, eventHandler);
+	 * 	// Do not forget to unsubscribe later!
+	 * }
+	 * 
+ * + * @see ITargetPlatformService#saveTargetDefinition(ITargetDefinition) + * @see IEventBroker + * @since 3.20 + */ + public static final String TOPIC_TARGET_SAVED = TOPIC_BASE + "/targetSaved"; //$NON-NLS-1$ + + /** + * Sent when a target is deleted. Can be used as follows: + * + *
+	 * EventHandler eventHandler = event -> {
+	 * 	Object data = event.getProperty(IEventBroker.DATA);
+	 * 	if (data instanceof ITargetHandle) {
+	 * 		ITargetHandle handle = (ITargetHandle) data;
+	 * 		// Work with the target handle...
+	 * 	}
+	 * };
+	 *
+	 * IEclipseContext context = EclipseContextFactory.getServiceContext(bundleContext);
+	 * IEventBroker broker = context.get(IEventBroker.class);
+	 * if (broker != null) {
+	 * 	broker.subscribe(TargetEvents.TOPIC_TARGET_DELETED, eventHandler);
+	 * 	// Do not forget to unsubscribe later!
+	 * }
+	 * 
+ * + * @see ITargetPlatformService#deleteTarget(ITargetHandle) + * @since 3.20 + */ + public static final String TOPIC_TARGET_DELETED = TOPIC_BASE + "/targetDeleted"; //$NON-NLS-1$ } diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/AbstractTargetHandle.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/AbstractTargetHandle.java index 9fd550a693..6bb76bddc6 100644 --- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/AbstractTargetHandle.java +++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/AbstractTargetHandle.java @@ -20,6 +20,7 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.pde.core.target.ITargetDefinition; import org.eclipse.pde.core.target.ITargetHandle; +import org.eclipse.pde.core.target.TargetEvents; /** * Common implementation of target handles. @@ -53,11 +54,18 @@ public ITargetDefinition getTargetDefinition() throws CoreException { */ abstract void delete() throws CoreException; + public final void save(ITargetDefinition definition) throws CoreException { + doSave(definition); + + TargetPlatformService service = (TargetPlatformService) TargetPlatformService.getDefault(); + service.scheduleEvent(TargetEvents.TOPIC_TARGET_SAVED, definition.getHandle()); + } + /** * Saves the definition to underlying storage. * * @param definition target to save * @throws CoreException on failure */ - abstract void save(ITargetDefinition definition) throws CoreException; + abstract void doSave(ITargetDefinition definition) throws CoreException; } diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/ExternalFileTargetHandle.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/ExternalFileTargetHandle.java index 92dff3e733..ed2cda5460 100644 --- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/ExternalFileTargetHandle.java +++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/ExternalFileTargetHandle.java @@ -81,7 +81,7 @@ protected InputStream getInputStream() throws CoreException { @Override - void save(ITargetDefinition definition) throws CoreException { + void doSave(ITargetDefinition definition) throws CoreException { try (OutputStream stream = new BufferedOutputStream(new FileOutputStream(fFile))) { ((TargetDefinition) definition).write(stream); } catch (IOException e) { diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/LocalTargetHandle.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/LocalTargetHandle.java index 35396814ff..64237b274b 100644 --- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/LocalTargetHandle.java +++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/LocalTargetHandle.java @@ -193,7 +193,7 @@ protected OutputStream getOutputStream() throws CoreException { } @Override - void save(ITargetDefinition definition) throws CoreException { + void doSave(ITargetDefinition definition) throws CoreException { try (OutputStream stream = getOutputStream()) { ((TargetDefinition) definition).write(stream); } catch (IOException e) { diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetPlatformService.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetPlatformService.java index a63ae635e6..8644e095b8 100644 --- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetPlatformService.java +++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/TargetPlatformService.java @@ -77,6 +77,7 @@ import org.eclipse.pde.internal.core.TargetDefinitionManager; import org.eclipse.pde.internal.core.TargetPlatformHelper; import org.eclipse.pde.internal.core.target.IUBundleContainer.UnitDeclaration; +import org.osgi.framework.BundleContext; import org.osgi.service.prefs.BackingStoreException; /** @@ -160,6 +161,7 @@ public void deleteTarget(ITargetHandle handle) throws CoreException { } ((AbstractTargetHandle) handle).delete(); TargetPlatformHelper.getTargetDefinitionMap().remove(handle); + scheduleEvent(TargetEvents.TOPIC_TARGET_DELETED, handle); } @Override @@ -305,7 +307,8 @@ public ITargetDefinition newTarget() { @Override public void saveTargetDefinition(ITargetDefinition definition) throws CoreException { - ((AbstractTargetHandle) definition.getHandle()).save(definition); + ITargetHandle handle = definition.getHandle(); + ((AbstractTargetHandle) handle).save(definition); } @Override @@ -364,24 +367,30 @@ public void setWorkspaceTargetDefinition(ITargetDefinition target, boolean async boolean changed = !Objects.equals(oldTarget, target); if (changed) { if (asyncEvents) { - eventSendingJob.schedule(target); + scheduleEvent(TargetEvents.TOPIC_WORKSPACE_TARGET_CHANGED, target); } else { - notifyTargetChanged(target); + notifyEvent(TargetEvents.TOPIC_WORKSPACE_TARGET_CHANGED, target); } } } - static void notifyTargetChanged(ITargetDefinition target) { - IEclipseContext context = EclipseContextFactory.getServiceContext(PDECore.getDefault().getBundleContext()); + public final void scheduleEvent(String topic, Object data) { + eventSendingJob.schedule(topic, data); + } + + private static void notifyEvent(String topic, Object data) { + BundleContext bundleContext = PDECore.getDefault().getBundleContext(); + IEclipseContext context = EclipseContextFactory.getServiceContext(bundleContext); + IEventBroker broker = context.get(IEventBroker.class); if (broker != null) { - broker.send(TargetEvents.TOPIC_WORKSPACE_TARGET_CHANGED, target); + broker.send(topic, data); } } - static class EventDispatcher extends Job { + private static final class EventDispatcher extends Job { - private final ConcurrentLinkedQueue queue; + private final ConcurrentLinkedQueue queue; private final Object myFamily; /** @@ -405,9 +414,9 @@ public boolean belongsTo(Object family) { @Override protected IStatus run(IProgressMonitor monitor) { - ITargetDefinition target; - while ((target = queue.poll()) != null && !monitor.isCanceled()) { - notifyTargetChanged(target); + EventInfo eventInfo; + while ((eventInfo = queue.poll()) != null && !monitor.isCanceled()) { + notifyEvent(eventInfo.topic, eventInfo.data); } if (!queue.isEmpty() && !monitor.isCanceled()) { // in case actions got faster scheduled then processed @@ -423,10 +432,20 @@ protected IStatus run(IProgressMonitor monitor) { /** * Enqueue a task asynchronously. **/ - public void schedule(ITargetDefinition target) { - queue.offer(target); + public void schedule(String topic, Object data) { + queue.offer(new EventInfo(topic, data)); schedule(); // will reschedule if already running } + + private static final class EventInfo { + final String topic; + final Object data; + + EventInfo(String topic, Object data) { + this.topic = topic; + this.data = data; + } + } } /** diff --git a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/WorkspaceFileTargetHandle.java b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/WorkspaceFileTargetHandle.java index 57e1ba08a6..34a003631d 100644 --- a/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/WorkspaceFileTargetHandle.java +++ b/ui/org.eclipse.pde.core/src/org/eclipse/pde/internal/core/target/WorkspaceFileTargetHandle.java @@ -76,7 +76,7 @@ public String getMemento() throws CoreException { } @Override - public void save(ITargetDefinition definition) throws CoreException { + void doSave(ITargetDefinition definition) throws CoreException { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); ((TargetDefinition) definition).write(outputStream); ByteArrayInputStream stream = new ByteArrayInputStream(outputStream.toByteArray()); diff --git a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/targetdefinition/TargetEditor.java b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/targetdefinition/TargetEditor.java index 3ac514f8bf..a8e535a566 100644 --- a/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/targetdefinition/TargetEditor.java +++ b/ui/org.eclipse.pde.ui/src/org/eclipse/pde/internal/ui/editor/targetdefinition/TargetEditor.java @@ -65,6 +65,7 @@ import org.eclipse.pde.internal.core.PDEPreferencesManager; import org.eclipse.pde.internal.core.target.P2TargetUtils; import org.eclipse.pde.internal.core.target.TargetDefinitionPersistenceHelper; +import org.eclipse.pde.internal.core.target.TargetPlatformService; import org.eclipse.pde.internal.core.target.WorkspaceFileTargetHandle; import org.eclipse.pde.internal.ui.IHelpContextIds; import org.eclipse.pde.internal.ui.PDEPlugin; @@ -175,6 +176,7 @@ protected void pageChange(int newPageIndex) { @Override public void doSave(IProgressMonitor monitor) { + ITargetHandle handle = fInputHandler.getTarget().getHandle(); fInputHandler.setSaving(true); if (!isActiveTabTextualEditor()) { markStale(); @@ -184,6 +186,9 @@ public void doSave(IProgressMonitor monitor) { fDirty = false; editorDirtyStateChanged(); fInputHandler.setSaving(false); + + TargetPlatformService service = (TargetPlatformService) TargetPlatformService.getDefault(); + service.scheduleEvent(TargetEvents.TOPIC_TARGET_SAVED, handle); } @Override @@ -286,6 +291,17 @@ public void dispose() { super.dispose(); } + @Override + public T getAdapter(Class adapter) { + if (adapter.equals(ITargetHandle.class)) { + ITargetDefinition target = getTarget(); + if (target != null) { + return adapter.cast(target.getHandle()); + } + } + + return super.getAdapter(adapter); + } /** * Returns the target model backing this editor * @return target model