blob: 97a058f56ceb381cd14e9e85c6d1b60095cb75c4 [file] [log] [blame]
package org.eclipse.fx.ide.css.cssext.resolver.jdt;
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.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.jar.Manifest;
import java.util.stream.Collectors;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.URIUtil;
import org.eclipse.fx.core.Subscription;
import org.eclipse.fx.ide.css.cssext.extapi.registry.CssExtFileWatcher;
import org.eclipse.jdt.core.ElementChangedEvent;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaElementDelta;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.JavaCore;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
@Component(service=CssExtFileWatcher.class, immediate=true, property={"context=org.eclipse.core.resources.IProject"})
public class JDTClasspathCssExtResolver implements CssExtFileWatcher<IProject> {
private Map<IProject, List<Consumer<URI>>> addListener = new HashMap<>();
private Map<IProject, List<Consumer<URI>>> removeListener = new HashMap<>();
private Map<IProject, Set<URI>> cssExtURIs = new HashMap<>();
@Override
public String getId() {
return "jdt-classpath";
}
private Set<URI> findAllCssExtFiles(IProject context) {
Set<URI> result = new HashSet<>();
try {
if (context.hasNature(JavaCore.NATURE_ID)) {
IJavaProject project = JavaCore.create(context);
IClasspathEntry[] resolvedClasspath = project.getResolvedClasspath(true);
for (IClasspathEntry e : resolvedClasspath) {
System.err.println("entry " + e.getPath());
if (e.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
System.err.println("CPE_LIBRARY -> jar?");
System.err.println(" -> " + e.getPath());
if (!e.getPath().toString().endsWith(".jar")) {
System.err.println("not supported.");
continue;
}
try {
URI jarURI = URIUtil.fromString("file:" + e.getPath().toString());
String baseURI = e.getPath().toString().endsWith(".jar") ? "jar:" + jarURI.toString() + "!" : jarURI.toString();
URI manifestURI = new URI(baseURI + "/META-INF/MANIFEST.MF");
Manifest mf = null;
String cssExtDefs = null;
try (InputStream data = manifestURI.toURL().openStream()) {
mf = new Manifest(data);
cssExtDefs = mf.getMainAttributes().getValue("CssExt-Definition");
}
catch (IOException ex) {
ex.printStackTrace();
}
if (cssExtDefs != null) {
System.err.println("FOUND " + cssExtDefs);
for (String cssExtDef : cssExtDefs.split(",")) {
try {
URI extURI = new URI(baseURI + "/" + cssExtDef.trim());
System.err.println(" -> " + extURI);
result.add(extURI);
}
catch (URISyntaxException ex) {
ex.printStackTrace();
}
}
}
}
catch (URISyntaxException ex) {
ex.printStackTrace();
}
}
else if (e.getEntryKind() == IClasspathEntry.CPE_PROJECT) {
System.err.println("CPE_PROJECT");
System.err.println(" -> " + e.getOutputLocation());
}
}
}
}
catch (CoreException e) {
e.printStackTrace();
}
return result;
}
private void onElementChange(ElementChangedEvent event) {
System.err.println("on catchall change " + event);
IJavaElementDelta delta = event.getDelta();
for (IJavaElementDelta child : delta.getAffectedChildren()) {
if (child.getElement() instanceof IJavaProject) {
IJavaProject p = (IJavaProject) child.getElement();
IProject project = p.getProject();
System.err.println("Project " + p.getElementName() + " Change");
if ((child.getFlags() & IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED) == IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED) {
System.err.println(" -> classpath change");
for (IJavaElementDelta cc : child.getAffectedChildren()) {
if ((cc.getFlags() & IJavaElementDelta.F_ADDED_TO_CLASSPATH) == IJavaElementDelta.F_ADDED_TO_CLASSPATH ||
cc.getKind() == IJavaElementDelta.ADDED) {
System.err.println(" added " + cc.getElement());
if (cc.getElement() instanceof IPackageFragmentRoot) {
IPackageFragmentRoot f = (IPackageFragmentRoot) cc.getElement();
for (URI uri : findCssExt(f)) {
Set<URI> set = cssExtURIs.get(project);
if (set != null) {
set.add(uri);
for (Consumer<URI> l : addListener.get(project)) {
l.accept(uri);
}
}
}
}
}
if ((cc.getFlags() & IJavaElementDelta.F_REMOVED_FROM_CLASSPATH) == IJavaElementDelta.F_REMOVED_FROM_CLASSPATH ||
cc.getKind() == IJavaElementDelta.REMOVED) {
System.err.println(" removed " + cc.getElement());
if (cc.getElement() instanceof IPackageFragmentRoot) {
IPackageFragmentRoot f = (IPackageFragmentRoot) cc.getElement();
for (URI uri : findCssExt(f)) {
Set<URI> set = cssExtURIs.get(project);
if (set != null) {
set.remove(uri);
for (Consumer<URI> l : removeListener.get(project)) {
l.accept(uri);
}
}
}
}
}
}
}
}
}
}
private Set<URI> findCssExt(IPackageFragmentRoot f) {
System.err.println("external: " + f.isExternal());
System.err.println("path: " + f.getPath());
String baseURI;
if (f.isExternal()) {
baseURI = "file:" + f.getPath().toString();
}
else {
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IResource res = root.findMember(f.getPath());
baseURI = "file:" + res.getLocation().toString();
}
if (f.isArchive()) {
baseURI = "jar:" + baseURI.toString() + "!";
}
final String fBaseURI = baseURI;
System.err.println("baseURI = " + baseURI);
String manifestURI = baseURI + "/META-INF/MANIFEST.MF";
System.err.println("manifestURI = " + manifestURI);
String cssExtDefs = null;
try (InputStream in = new URI(manifestURI).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 " + manifestURI);
return Arrays.stream(cssExtDefs.split(","))
.map(cssExtDef -> URI.create(fBaseURI + (f.isArchive() ? "" : "/bin" ) + "/" + cssExtDef))
.collect(Collectors.toSet());
}
return Collections.emptySet();
}
@Activate
protected void activate() {
JavaCore.addElementChangedListener(this::onElementChange);
}
@Deactivate
protected void deactivate() {
JavaCore.removeElementChangedListener(this::onElementChange);
}
private void init(IProject context) {
if (!cssExtURIs.containsKey(context)) {
try {
if (context.hasNature(JavaCore.NATURE_ID)) {
addListener.put(context, new ArrayList<>());
removeListener.put(context, new ArrayList<>());
cssExtURIs.put(context, new HashSet<>());
// populate
cssExtURIs.get(context).addAll(findAllCssExtFiles(context));
}
}
catch (CoreException e) {
e.printStackTrace();
}
}
}
@Override
public Subscription subscribe(IProject context, Consumer<URI> onAdd, Consumer<URI> onRemove) {
init(context);
addListener.get(context).add(onAdd);
removeListener.get(context).add(onRemove);
return new Subscription() {
@Override
public void dispose() {
addListener.get(context).remove(onAdd);
removeListener.get(context).remove(onRemove);
}
};
}
@Override
public Set<URI> getCurrent(IProject context) {
init(context);
return cssExtURIs.get(context);
}
}