package org.xpect.util;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.apache.log4j.Logger;
import org.eclipse.emf.common.util.URI;
import org.eclipse.xtext.util.Strings;
import org.xpect.util.IBundleInfo.Context;
import com.google.common.base.Objects;
import com.google.common.base.Objects.ToStringHelper;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
public class ResourceAccess {
public static class ArchivedResourceInfo extends ResourceInfo {
public static final Logger LOG = Logger.getLogger(ArchivedResourceInfo.class);
public ArchivedResourceInfo(URI location) {
super(location);
}
@Override
public List<URI> find(Context context) {
return Collections.singletonList(location);
}
@Override
public URI find(Context context, String fileName) {
return resolve(fileName);
}
@Override
public List<URI> find(Context context, String path, Predicate<String> matcher, String... fileExtensions) {
String archiveFileName = URI.createURI(location.authority().substring(0, location.authority().length() - 1)).toFileString();
List<URI> result = Lists.newArrayList();
try {
JarFile jarFile = new JarFile(new File(archiveFileName));
try {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry next = entries.nextElement();
String name = next.getName();
if (!Strings.isEmpty(path) && !name.startsWith(path))
continue;
if (matches(name, fileExtensions) && matcher.apply(name)) {
URI resolved = URI.createURI(name).resolve(location);
result.add(resolved);
}
}
} finally {
if (jarFile != null)
jarFile.close();
}
} catch (IOException e) {
LOG.error(e.getMessage(), e);
}
return result;
}
@Override
public String toString() {
return Objects.toStringHelper(this).add("location", location.toString()).toString();
}
}
public static class GeneralProjectInfo extends ResourceInfo {
public GeneralProjectInfo(URI location) {
super(location);
}
@Override
public List<URI> find(Context context) {
return Collections.singletonList(location);
}
@Override
public URI find(Context context, String fileName) {
return resolve(fileName);
}
@Override
public List<URI> find(Context context, String path, Predicate<String> matcher, String... fileExtensions) {
File root = new File(location.toFileString());
List<URI> result = Lists.newArrayList();
collect(root, root, result, matcher, fileExtensions);
return result;
}
@Override
public String toString() {
return Objects.toStringHelper(this).add("location", location.toString()).toString();
}
}
public static class JavaProjectInfo extends ResourceInfo {
private final String output;
private final List<String> sourceFolders;
public JavaProjectInfo(URI location, List<String> sourceFolders, String output) {
super(location);
this.sourceFolders = sourceFolders;
this.output = output;
}
@Override
public List<URI> find(Context context) {
switch (context) {
case CLASSPATH:
return Collections.singletonList(resolve(output));
case ROOT:
return Collections.singletonList(location);
case SOURCE:
List<URI> result = Lists.newArrayList();
for (String src : sourceFolders)
result.add(resolve(src));
return result;
}
return Collections.emptyList();
}
@Override
public URI find(Context context, String fileName) {
for (URI uri : find(context)) {
File parent = new File(uri.toFileString());
if (new File(parent, fileName).exists())
return URI.createURI(fileName).resolve(uri.hasTrailingPathSeparator() ? uri : uri.appendSegment(""));
}
return null;
}
@Override
public List<URI> find(Context context, String path, Predicate<String> matcher, String... fileExtensions) {
List<URI> result = Lists.newArrayList();
for (URI uri : find(context)) {
File folder = new File(new File(uri.toFileString()), path);
if (folder.isDirectory()) {
collect(folder, folder, result, matcher, fileExtensions);
}
}
return result;
}
@Override
public String toString() {
ToStringHelper helper = Objects.toStringHelper(this);
helper.add("location", location.toString());
helper.add("classpath", output);
helper.add("source", sourceFolders);
return helper.toString();
}
}
public abstract static class ResourceInfo {
protected final URI location;
public ResourceInfo(URI location) {
super();
this.location = location;
}
protected void collect(File root, File file, List<URI> result, Predicate<String> matcher, String... fileExtensions) {
if (file.isFile()) {
if (matches(file.getName(), fileExtensions)) {
URI uri = URI.createFileURI(file.getAbsolutePath());
URI name = uri.deresolve(URI.createURI(root.toString()));
if (matcher.apply(name.toString())) {
result.add(uri);
}
}
} else if (file.isDirectory()) {
for (File child : file.listFiles())
collect(root, child, result, matcher, fileExtensions);
}
}
public abstract List<URI> find(Context context);
public abstract URI find(Context context, String fileName);
public abstract List<URI> find(Context context, String path, Predicate<String> matcher, String... fileExtensions);
public URI getLocation() {
return location;
}
protected boolean matches(String name, String... fileExtensions) {
if (fileExtensions.length == 0)
return true;
int index = name.lastIndexOf('.');
if (index < 0)
return false;
String ext = name.substring(index + 1, name.length());
for (int i = 0; i < fileExtensions.length; i++)
if (ext.equals(fileExtensions[i]))
return true;
return false;
}
protected URI resolve(String fileName) {
return URI.createURI(fileName).resolve(location);
}
}
public static ResourceInfo create(URI uri) {
if (uri.isArchive())
return new ArchivedResourceInfo(uri);
else {
File dot = new File(uri.toFileString() + ".classpath");
if (dot.isFile()) {
DotClasspath dotClasspath = new DotClasspath(dot);
return new JavaProjectInfo(uri, dotClasspath.getSources(), dotClasspath.getOutput());
}
return new GeneralProjectInfo(uri);
}
}
}