blob: 81de6292694c7e642ddc7ea234fdfd28604f47d7 [file] [log] [blame]
package org.eclipse.fx.ide.css.cssext.resolver.pde;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.jar.Manifest;
import java.util.stream.Collectors;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.fx.core.Subscription;
import org.eclipse.fx.ide.css.cssext.extapi.registry.CssExtFileWatcher;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.service.resolver.State;
import org.eclipse.osgi.service.resolver.StateDelta;
import org.eclipse.pde.core.target.ITargetDefinition;
import org.eclipse.pde.core.target.TargetBundle;
import org.eclipse.pde.internal.core.IStateDeltaListener;
import org.eclipse.pde.internal.core.PDECore;
import org.eclipse.pde.internal.core.TargetPlatformHelper;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
@SuppressWarnings("restriction")
@Component(service=CssExtFileWatcher.class, immediate=true, property={"context=java.lang.Void"})
public class PDETargetCssExtResolver implements CssExtFileWatcher<Void> {
private Set<URI> cssExtURIs = new HashSet<>();
private List<Consumer<URI>> addListeners = Collections.synchronizedList(new ArrayList<>());
private List<Consumer<URI>> removeListeners = Collections.synchronizedList(new ArrayList<>());
@Override
public Subscription subscribe(Void context, Consumer<URI> onAdd, Consumer<URI> onRemove) {
if (onAdd != null) addListeners.add(onAdd);
if (onRemove != null) removeListeners.add(onRemove);
return new Subscription() {
@Override
public void dispose() {
if (onAdd != null) addListeners.remove(onAdd);
if (onRemove != null) removeListeners.remove(onRemove);
}
};
}
@Override
public String getId() {
return "pde-target";
}
private Set<BundleDescription> currentBundles = new HashSet<>();
private Set<URI> findCssExt(String bundleLocation) {
// System.err.println("find " + bundleLocation);
String baseLocation = (bundleLocation.endsWith(".jar") ? "jar:" : "") + (bundleLocation.startsWith("file:") ? "" : "file:") + bundleLocation + (bundleLocation.endsWith(".jar") ? "!" : "");
String manifestLocation = baseLocation + "/META-INF/MANIFEST.MF";
// System.err.println(manifestLocation);
String cssExtDefs = null;
try (InputStream in = new URI(manifestLocation).toURL().openStream()) {
Manifest mf = new Manifest(in);
cssExtDefs = mf.getMainAttributes().getValue("CssExt-Definition");
}
catch (URISyntaxException | IOException e) {
e.printStackTrace();
}
if (cssExtDefs != null) {
System.err.println("FOUND " + cssExtDefs + " in " + bundleLocation);
return Arrays.stream(cssExtDefs.split(","))
.map(cssExtDef -> URI.create(baseLocation + (bundleLocation.endsWith(".jar") ? "" : "/bin" ) + "/" + cssExtDef))
.filter(PDETargetCssExtResolver::notNull)
.collect(Collectors.toSet());
}
return Collections.emptySet();
}
private static boolean notNull(Object o) {
return o != null;
}
private void checkBundles(Set<BundleDescription> currentBundles) {
Set<BundleDescription> oldBundles = this.currentBundles;
Set<BundleDescription> removedBundles = new HashSet<>(oldBundles);
removedBundles.removeAll(currentBundles);
Set<BundleDescription> addedBundles = new HashSet<>(currentBundles);
addedBundles.removeAll(oldBundles);
for (BundleDescription b : addedBundles) {
for (URI cssExt : findCssExt(b.getLocation())) {
cssExtURIs.add(cssExt);
for (Consumer<URI> onAdd : addListeners) {
onAdd.accept(cssExt);
}
}
}
for (BundleDescription b : removedBundles) {
for (URI cssExt : findCssExt(b.getLocation())) {
cssExtURIs.remove(cssExt);
for (Consumer<URI> onRemove : removeListeners) {
onRemove.accept(cssExt);
}
}
}
this.currentBundles = currentBundles;
}
@Activate
protected void activate() {
try {
// install listener
PDECore.getDefault().getModelManager().addStateDeltaListener(new IStateDeltaListener() {
@Override
public void stateResolved(StateDelta delta) {
System.err.println("stateResolved " + delta);
}
@Override
public void stateChanged(State newState) {
System.err.println("stateChanged " + Arrays.toString(newState.getBundles()));
checkBundles(new HashSet<>(Arrays.asList(newState.getResolvedBundles())));
}
});
// initial load
ITargetDefinition target = TargetPlatformHelper.getWorkspaceTargetResolved(new NullProgressMonitor());
TargetBundle[] bundles = target.getBundles();
for (TargetBundle b : bundles) {
for (URI cssExt : findCssExt(b.getBundleInfo().getLocation().toString())) {
cssExtURIs.add(cssExt);
for (Consumer<URI> onAdd : addListeners) {
onAdd.accept(cssExt);
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Set<URI> getCurrent(Void context) {
return cssExtURIs;
}
}