001 /*
002 Copyright (c) 2009 Olivier Chafik, All Rights Reserved
003
004 This file is part of JNAerator (http://jnaerator.googlecode.com/).
005
006 JNAerator is free software: you can redistribute it and/or modify
007 it under the terms of the GNU General Public License as published by
008 the Free Software Foundation, either version 3 of the License, or
009 (at your option) any later version.
010
011 JNAerator is distributed in the hope that it will be useful,
012 but WITHOUT ANY WARRANTY; without even the implied warranty of
013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014 GNU General Public License for more details.
015
016 You should have received a copy of the GNU General Public License
017 along with JNAerator. If not, see <http://www.gnu.org/licenses/>.
018 */
019 package com.ochafik.lang.compiler;
020
021 import java.io.File;
022 import java.io.FileInputStream;
023 import java.io.FileNotFoundException;
024 import java.io.FileOutputStream;
025 import java.io.IOException;
026 import java.io.InputStream;
027 import java.io.OutputStream;
028 import java.util.ArrayList;
029 import java.util.HashMap;
030 import java.util.Map;
031 import java.util.jar.JarEntry;
032 import java.util.jar.JarOutputStream;
033
034 import javax.tools.FileObject;
035 import javax.tools.ForwardingJavaFileManager;
036 import javax.tools.JavaFileManager;
037 import javax.tools.JavaFileObject;
038
039 import com.ochafik.io.IOUtils;
040
041
042 public class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
043 public final Map<String, MemoryJavaFile> inputs = new HashMap<String, MemoryJavaFile>();
044 public final Map<String, FileObject> outputs = new HashMap<String, FileObject>();
045
046 public void writeJar(File outputJar, boolean outputSources, Map<String, File> additionalFiles) throws IOException {
047
048 File jarDir = outputJar.getAbsoluteFile().getParentFile();
049 if (!jarDir.isDirectory())
050 jarDir.mkdirs();
051 writeJar(new FileOutputStream(outputJar), outputSources, additionalFiles);
052 }
053 public void writeJar(OutputStream out, boolean outputSources, Map<String, File> additionalFiles) throws IOException {
054 JarOutputStream jout = new JarOutputStream(out);
055 if (outputSources)
056 for (Map.Entry<String, MemoryJavaFile> e : inputs.entrySet()) {
057 // if (e.getKey().contains(".class"))
058 // continue;
059 writeEntry(e.getKey(), e.getValue(), jout);
060 }
061 for (Map.Entry<String, FileObject> e : outputs.entrySet())
062 writeEntry(e.getKey(), e.getValue(), jout);
063
064 if (additionalFiles != null)
065 for (Map.Entry<String, File> additionalFile : additionalFiles.entrySet()) {
066 String path = additionalFile.getKey();
067 if (path.startsWith("file:///"))
068 path = path.substring("file:///".length());
069
070 FileInputStream in = new FileInputStream(additionalFile.getValue());
071 JarEntry e = new JarEntry(path);
072 jout.putNextEntry(e);
073 IOUtils.readWrite(in, jout);
074 in.close();
075 jout.closeEntry();
076 }
077 jout.close();
078 }
079 protected void writeEntry(String path, FileObject o, JarOutputStream jout) throws IOException {
080 if (path.startsWith("/"))
081 path = path.substring(1);
082 if (path.startsWith("file:///"))
083 path = path.substring("file:///".length());
084
085 if (o instanceof MemoryFileObject) {
086 MemoryFileObject mo = (MemoryFileObject)o;
087 byte[] c = mo.getContent();
088 if (c == null)
089 return;
090
091 // String path = mo.getPath();
092 // if (path.startsWith("file:///"))
093 // path = path.substring("file:///".length());
094 JarEntry e = new JarEntry(path);
095 jout.putNextEntry(e);
096 jout.write(c);
097 jout.closeEntry();
098 } else if (o instanceof URLFileObject) {
099 URLFileObject uo = (URLFileObject)o;
100 // String path = uo.url.getFile();
101 // if (path.startsWith("/"))
102 // path = path.substring(1);
103
104 JarEntry e = new JarEntry(path);
105 jout.putNextEntry(e);
106 InputStream in = uo.url.openStream();
107 if (in == null)
108 throw new FileNotFoundException(path);
109 IOUtils.readWrite(in, jout);
110 in.close();
111 jout.closeEntry();
112 } else
113 throw new UnsupportedOperationException("Dunno how to deal with " + o);
114 }
115 public MemoryFileManager(JavaFileManager fm) {
116 super(fm);
117 }
118
119 public MemoryJavaFile addSourceInput(String path, String content) {
120 if (!path.startsWith("file:///"))
121 path = "file:///" + path;
122
123 MemoryJavaFile mjf = new MemoryJavaFile(path, content, JavaFileObject.Kind.SOURCE);
124 inputs.put(path, mjf);
125 return mjf;
126 }
127 @Override
128 public boolean isSameFile(FileObject a, FileObject b) {
129 return a.toString().equals(b.toString());
130 }
131 public Iterable<? extends JavaFileObject> getJavaFileObjects() {
132 return new ArrayList<JavaFileObject>(inputs.values());
133 }
134
135 @Override
136 public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException {
137 // System.out.println("getJavaFileForInput(className = " + className + ", location = " + location + ", kind = " + kind + ")");
138 if (kind == JavaFileObject.Kind.SOURCE) {
139 return inputs.get(className);
140 }
141 return super.getJavaFileForInput(location, className, kind);
142 }
143
144 public static String getFullPathForClass(String className, String extension) {
145 return "file:///" + getSimplePathForClass(className, extension);
146 }
147 public static String getSimplePathForClass(String className, String extension) {
148 return className.replace('.', '/') + "." + extension;
149 }
150 @Override
151 public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
152 // System.out.println("getJavaFileForOutput(className = " + className + ", location = " + location + ", kind = " + kind + ")");
153 MemoryJavaFile jo = null;
154 if (kind == JavaFileObject.Kind.CLASS) {
155 outputs.put(getFullPathForClass(className, "class"), jo = new MemoryJavaFile(getFullPathForClass(className, "class"), null, kind));
156 } else if (kind == JavaFileObject.Kind.SOURCE) {
157 inputs.put(getFullPathForClass(className, "java"), jo = new MemoryJavaFile(getFullPathForClass(className, "java"), null, kind));
158 }
159
160 return jo == null ? super.getJavaFileForInput(location, className, kind) : jo;
161 }
162 @Override
163 public FileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) throws IOException {
164 // System.out.println("getFileForOutput(relativeName = " + relativeName + ")");
165 if (relativeName.startsWith("file:///"))
166 relativeName = relativeName.substring("file:///".length());
167
168 FileObject out = outputs.get(relativeName);
169 if (out == null) {
170 out = new MemoryFileObject(relativeName, (String)null);
171 outputs.put(relativeName, out);
172 }
173 return out;
174 }
175 }