/* 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; } }