/*
Copyright (c) 2009-2013 Olivier Chafik, All Rights Reserved
This file is part of JNAerator (http://jnaerator.googlecode.com/).
JNAerator is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JNAerator is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JNAerator. If not, see <http://www.gnu.org/licenses/>.
*/
package com.ochafik.lang.compiler;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import com.ochafik.io.IOUtils;
public class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
public final Map<String, MemoryJavaFile> inputs = new LinkedHashMap<String, MemoryJavaFile>();
public final Map<String, FileObject> outputs = new LinkedHashMap<String, FileObject>();
public void writeJar(File outputJar, boolean outputSources, Map<String, File> additionalFiles) throws IOException {
File jarDir = outputJar.getAbsoluteFile().getParentFile();
if (!jarDir.isDirectory()) {
jarDir.mkdirs();
}
writeJar(new FileOutputStream(outputJar), outputSources, additionalFiles);
}
public void writeJar(OutputStream out, boolean outputSources, Map<String, File> additionalFiles) throws IOException {
JarOutputStream jout = new JarOutputStream(out);
if (outputSources) {
for (Map.Entry<String, MemoryJavaFile> e : inputs.entrySet()) {
// if (e.getKey().contains(".class"))
// continue;
writeEntry(e.getKey(), e.getValue(), jout);
}
}
for (Map.Entry<String, FileObject> e : outputs.entrySet()) {
writeEntry(e.getKey(), e.getValue(), jout);
}
if (additionalFiles != null) {
for (Map.Entry<String, File> additionalFile : additionalFiles.entrySet()) {
String path = additionalFile.getKey();
if (path.startsWith("file:///")) {
path = path.substring("file:///".length());
}
FileInputStream in = new FileInputStream(additionalFile.getValue());
JarEntry e = new JarEntry(path);
jout.putNextEntry(e);
IOUtils.readWrite(in, jout);
in.close();
jout.closeEntry();
}
}
jout.close();
}
protected void writeEntry(String path, FileObject o, JarOutputStream jout) throws IOException {
if (path.startsWith("/")) {
path = path.substring(1);
}
if (path.startsWith("file:///")) {
path = path.substring("file:///".length());
}
if (o instanceof MemoryFileObject) {
MemoryFileObject mo = (MemoryFileObject) o;
byte[] c = mo.getContent();
if (c == null) {
return;
}
// String path = mo.getPath();
// if (path.startsWith("file:///"))
// path = path.substring("file:///".length());
JarEntry e = new JarEntry(path);
jout.putNextEntry(e);
jout.write(c);
jout.closeEntry();
} else if (o instanceof URLFileObject) {
URLFileObject uo = (URLFileObject) o;
// String path = uo.url.getFile();
// if (path.startsWith("/"))
// path = path.substring(1);
JarEntry e = new JarEntry(path);
jout.putNextEntry(e);
InputStream in = uo.url.openStream();
if (in == null) {
throw new FileNotFoundException(path);
}
IOUtils.readWrite(in, jout);
in.close();
jout.closeEntry();
} else {
throw new UnsupportedOperationException("Dunno how to deal with " + o);
}
}
public MemoryFileManager(JavaFileManager fm) {
super(fm);
}
public MemoryJavaFile addSourceInput(String path, String content) {
if (!path.startsWith("file:///")) {
path = "file:///" + path;
}
MemoryJavaFile mjf = new MemoryJavaFile(path, content, JavaFileObject.Kind.SOURCE);
inputs.put(path, mjf);
return mjf;
}
@Override
public boolean isSameFile(FileObject a, FileObject b) {
return a.toString().equals(b.toString());
}
public Iterable<? extends JavaFileObject> getJavaFileObjects() {
return new ArrayList<JavaFileObject>(inputs.values());
}
@Override
public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException {
// System.out.println("getJavaFileForInput(className = " + className + ", location = " + location + ", kind = " + kind + ")");
if (kind == JavaFileObject.Kind.SOURCE) {
return inputs.get(className);
}
return super.getJavaFileForInput(location, className, kind);
}
public static String getFullPathForClass(String className, String extension) {
return "file:///" + getSimplePathForClass(className, extension);
}
public static String getSimplePathForClass(String className, String extension) {
return className.replace('.', '/') + "." + extension;
}
@Override
public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
// System.out.println("getJavaFileForOutput(className = " + className + ", location = " + location + ", kind = " + kind + ")");
MemoryJavaFile jo = null;
if (kind == JavaFileObject.Kind.CLASS) {
outputs.put(getFullPathForClass(className, "class"), jo = new MemoryJavaFile(getFullPathForClass(className, "class"), null, kind));
} else if (kind == JavaFileObject.Kind.SOURCE) {
inputs.put(getFullPathForClass(className, "java"), jo = new MemoryJavaFile(getFullPathForClass(className, "java"), null, kind));
}
return jo == null ? super.getJavaFileForInput(location, className, kind) : jo;
}
@Override
public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
// System.out.println("getFileForOutput(relativeName = " + relativeName + ")");
if (relativeName.startsWith("file:///")) {
relativeName = relativeName.substring("file:///".length());
}
FileObject out = outputs.get(relativeName);
if (out == null) {
out = new MemoryFileObject(relativeName, (String) null);
outputs.put(relativeName, out);
}
return out;
}
}