Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: d2d5b9176a7c098d7a7f4f7e64c3b176938be5a1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*******************************************************************************
 * Copyright (c) 2021 Christoph Läubrich 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:
 * Christoph Läubrich - Inital API and implementation
 *******************************************************************************/
package org.eclipse.ui.internal.genericeditor;

import java.util.Collection;
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.internal.genericeditor.ContentTypeRelatedExtensionTracker.LazyServiceSupplier;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;

/**
 * {@link ServiceTrackerCustomizer} that maps OSGi-Services to
 * ContentTypeRelatedExtensions
 *
 * @param <T> the type of extension to map
 */
final class ContentTypeRelatedExtensionTracker<T> implements ServiceTrackerCustomizer<T, LazyServiceSupplier<T>> {

	private BundleContext bundleContext;
	private ServiceTracker<T, LazyServiceSupplier<T>> serviceTracker;
	private Consumer<LazyServiceSupplier<T>> addAction;
	private Consumer<LazyServiceSupplier<T>> removeAction;
	private Display display;

	ContentTypeRelatedExtensionTracker(BundleContext bundleContext, Class<T> serviceType, Display display) {
		this.bundleContext = bundleContext;
		this.display = display;
		serviceTracker = new ServiceTracker<>(bundleContext, serviceType, this);
	}

	public void stopTracking() {
		serviceTracker.close();
	}

	@Override
	public LazyServiceSupplier<T> addingService(ServiceReference<T> reference) {
		LazyServiceSupplier<T> supplier = new LazyServiceSupplier<>(bundleContext, reference);
		if (addAction != null) {
			display.asyncExec(() -> addAction.accept(supplier));
		}
		return supplier;
	}

	@Override
	public void modifiedService(ServiceReference<T> reference, LazyServiceSupplier<T> service) {
		service.update();
	}

	@Override
	public void removedService(ServiceReference<T> reference, LazyServiceSupplier<T> service) {
		service.dispose();
		if (removeAction != null) {
			display.asyncExec(() -> removeAction.accept(service));
		}
	}

	public void onAdd(Consumer<LazyServiceSupplier<T>> action) {
		this.addAction = action;
	}

	public void onRemove(Consumer<LazyServiceSupplier<T>> action) {
		this.removeAction = action;
	}

	public void startTracking() {
		serviceTracker.open();
	}

	public Collection<LazyServiceSupplier<T>> getTracked() {
		return serviceTracker.getTracked().values();
	}

	public static final class LazyServiceSupplier<S> implements Supplier<S> {
		private ServiceReference<S> reference;
		private BundleContext bundleContext;
		private boolean disposed;
		private S serviceObject;
		private IContentType contentType;

		LazyServiceSupplier(BundleContext bundleContext, ServiceReference<S> reference) {
			this.reference = reference;
			this.bundleContext = bundleContext;
			update();
		}

		private String getProperty(String attribute) {
			return (String) reference.getProperty(attribute);
		}

		synchronized void update() {
			contentType = Platform.getContentTypeManager()
					.getContentType(getProperty(GenericContentTypeRelatedExtension.CONTENT_TYPE_ATTRIBUTE));
		}

		public synchronized IContentType getContentType() {
			return contentType;
		}

		synchronized void dispose() {
			disposed = true;
			if (serviceObject != null) {
				bundleContext.ungetService(reference);
			}
		}

		@Override
		public synchronized S get() {
			if (!disposed && serviceObject == null) {
				serviceObject = bundleContext.getService(reference);
			}
			return serviceObject;
		}

		public synchronized boolean isPresent() {
			return serviceObject != null;
		}
	}

}

Back to the top