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