1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package com.ochafik.lang.compiler;
20
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.OutputStream;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.jar.JarEntry;
32 import java.util.jar.JarOutputStream;
33
34 import javax.tools.FileObject;
35 import javax.tools.ForwardingJavaFileManager;
36 import javax.tools.JavaFileManager;
37 import javax.tools.JavaFileObject;
38
39 import com.ochafik.io.IOUtils;
40
41
42 public class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
43 public final Map<String, MemoryJavaFile> inputs = new HashMap<String, MemoryJavaFile>();
44 public final Map<String, FileObject> outputs = new HashMap<String, FileObject>();
45
46 public void writeJar(File outputJar, boolean outputSources, Map<String, File> additionalFiles) throws IOException {
47
48 File jarDir = outputJar.getAbsoluteFile().getParentFile();
49 if (!jarDir.isDirectory())
50 jarDir.mkdirs();
51 writeJar(new FileOutputStream(outputJar), outputSources, additionalFiles);
52 }
53 public void writeJar(OutputStream out, boolean outputSources, Map<String, File> additionalFiles) throws IOException {
54 JarOutputStream jout = new JarOutputStream(out);
55 if (outputSources)
56 for (Map.Entry<String, MemoryJavaFile> e : inputs.entrySet()) {
57
58
59 writeEntry(e.getKey(), e.getValue(), jout);
60 }
61 for (Map.Entry<String, FileObject> e : outputs.entrySet())
62 writeEntry(e.getKey(), e.getValue(), jout);
63
64 if (additionalFiles != null)
65 for (Map.Entry<String, File> additionalFile : additionalFiles.entrySet()) {
66 String path = additionalFile.getKey();
67 if (path.startsWith("file:///"))
68 path = path.substring("file:///".length());
69
70 FileInputStream in = new FileInputStream(additionalFile.getValue());
71 JarEntry e = new JarEntry(path);
72 jout.putNextEntry(e);
73 IOUtils.readWrite(in, jout);
74 in.close();
75 jout.closeEntry();
76 }
77 jout.close();
78 }
79 protected void writeEntry(String path, FileObject o, JarOutputStream jout) throws IOException {
80 if (path.startsWith("/"))
81 path = path.substring(1);
82 if (path.startsWith("file:///"))
83 path = path.substring("file:///".length());
84
85 if (o instanceof MemoryFileObject) {
86 MemoryFileObject mo = (MemoryFileObject)o;
87 byte[] c = mo.getContent();
88 if (c == null)
89 return;
90
91
92
93
94 JarEntry e = new JarEntry(path);
95 jout.putNextEntry(e);
96 jout.write(c);
97 jout.closeEntry();
98 } else if (o instanceof URLFileObject) {
99 URLFileObject uo = (URLFileObject)o;
100
101
102
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
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
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
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 }