1 package com.atlassian.plugin.test;
2
3 import org.apache.commons.io.IOUtils;
4 import org.codehaus.janino.ByteArrayClassLoader;
5 import org.codehaus.janino.SimpleCompiler;
6 import org.codehaus.janino.Parser;
7 import org.codehaus.janino.CompileException;
8
9 import java.util.Map;
10 import java.util.HashMap;
11 import java.util.Iterator;
12 import java.util.zip.ZipOutputStream;
13 import java.util.zip.ZipEntry;
14 import java.io.*;
15 import java.lang.reflect.Field;
16
17
18
19
20 public class PluginJarBuilder
21 {
22 private final Map<String, byte[]> jarContents;
23 private final String name;
24 private ClassLoader classLoader;
25
26
27
28
29 public PluginJarBuilder()
30 {
31 this("test");
32 }
33
34
35
36
37
38
39 public PluginJarBuilder(String name)
40 {
41 this(name, PluginJarBuilder.class.getClassLoader());
42 }
43
44
45
46
47
48
49 public PluginJarBuilder(String name, ClassLoader classLoader)
50 {
51 jarContents = new HashMap<String, byte[]>();
52 this.name = name;
53 this.classLoader = classLoader;
54 }
55
56 public PluginJarBuilder manifest(Map<String,String> manifest)
57 {
58 StringBuilder sb = new StringBuilder();
59 for (Map.Entry<String,String> entry : manifest.entrySet())
60 {
61 sb.append(entry.getKey()).append(": ").append(entry.getValue()).append('\n');
62 }
63 sb.append('\n');
64 return addResource("META-INF/MANIFEST.MF", sb.toString());
65 }
66
67 public PluginJarBuilder addClass(Class<?> aClass) throws IOException {
68 jarContents.put(
69 aClass.getName().replace('.', '/') + ".class",
70 IOUtils.toByteArray(aClass.getResourceAsStream(aClass.getSimpleName() + ".class")));
71 return this;
72 }
73
74 public PluginJarBuilder addFormattedJava(String className, String... lines) throws Exception
75 {
76 StringBuilder sb = new StringBuilder();
77 for (String line : lines)
78 {
79 sb.append(line.replace('\'', '"')).append('\n');
80 }
81 return addJava(className, sb.toString());
82 }
83
84
85
86
87
88
89
90
91
92 public PluginJarBuilder addJava(String className, String code) throws Exception
93 {
94 SimpleCompiler compiler = new SimpleCompiler();
95 compiler.setParentClassLoader(classLoader);
96 try
97 {
98 compiler.cook(new StringReader(code));
99 }
100 catch (Parser.ParseException ex)
101 {
102 throw new IllegalArgumentException("Unable to compile " + className, ex);
103 }
104 catch (CompileException ex)
105 {
106 throw new IllegalArgumentException("Unable to compile " + className, ex);
107 }
108 classLoader = compiler.getClassLoader();
109
110
111
112 jarContents.put(className.replace('.', '/') + ".class", getClassFile(className));
113 return this;
114 }
115
116 public byte[] getClassFile(String className) throws NoSuchFieldException, IllegalAccessException
117 {
118
119 ByteArrayClassLoader cl = (ByteArrayClassLoader) classLoader;
120 Field field = cl.getClass().getDeclaredField("classes");
121 field.setAccessible(true);
122 Map classes = (Map) field.get(cl);
123
124 return (byte[]) classes.get(className);
125 }
126
127
128
129
130
131
132
133
134 public PluginJarBuilder addResource(String path, String contents)
135 {
136 jarContents.put(path, contents.getBytes());
137 return this;
138 }
139
140
141
142
143
144
145
146
147 public PluginJarBuilder addFormattedResource(String path, String... lines)
148 {
149 StringBuilder sb = new StringBuilder();
150 for (String line : lines)
151 sb.append(line.replace('\'', '"')).append('\n');
152 jarContents.put(path, sb.toString().getBytes());
153 return this;
154 }
155
156 public PluginJarBuilder addPluginInformation(String key, String name, String version)
157 {
158 return addPluginInformation(key, name, version, 2);
159 }
160
161 public PluginJarBuilder addPluginInformation(String key, String name, String version, int pluginsVersion)
162 {
163 return addPluginInformation(key, name, version, pluginsVersion, null);
164 }
165
166 public PluginJarBuilder addPluginInformation(String key, String name, String version, int pluginsVersion, Map<String, String> params)
167 {
168 StringBuffer sb = new StringBuffer();
169 sb.append("<atlassian-plugin name=\"").append(name).append("\" key=\"").append(key).append("\" pluginsVersion=\"" + pluginsVersion + "\">\n");
170 sb.append(" <plugin-info>\n");
171 sb.append(" <description>This plugin descriptor is used for testing plugins!</description>\n");
172 sb.append(" <version>").append(version).append("</version>\n");
173 sb.append(" <vendor name=\"Atlassian Software Systems Pty Ltd\" url=\"http://www.atlassian.com\" />\n");
174 if (params != null)
175 for (Map.Entry<String, String> param : params.entrySet())
176 sb.append("<param name=\"").append(param.getKey()).append("\">").append(param.getValue()).append("</param>\n");
177 sb.append(" </plugin-info>");
178 sb.append("</atlassian-plugin>");
179 jarContents.put("atlassian-plugin.xml", sb.toString().getBytes());
180 return this;
181 }
182
183
184
185
186
187
188
189
190
191 public PluginJarBuilder addFile(String path, File file) throws IOException
192 {
193 FileInputStream in = new FileInputStream(file);
194 jarContents.put(path, IOUtils.toByteArray(in));
195 IOUtils.closeQuietly(in);
196 return this;
197 }
198
199
200
201
202
203
204
205
206 public File build() throws IOException
207 {
208 return build(createBaseDir());
209 }
210
211 private File createBaseDir()
212 {
213 File baseDir = new File("target");
214 if (!baseDir.exists())
215 baseDir = new File(System.getProperty("java.io.tmpdir"));
216 else
217 {
218 baseDir = new File(baseDir, "tmp");
219 if (!baseDir.exists())
220 baseDir.mkdir();
221 }
222 return baseDir;
223 }
224
225 public File buildWithNoManifest() throws IOException
226 {
227 return build(createBaseDir(), false);
228 }
229
230
231
232
233
234
235
236
237
238 public File build(File baseDir) throws IOException
239 {
240 return build(baseDir, true);
241 }
242
243 private File build(File baseDir, boolean createManifest) throws IOException
244 {
245
246 if (createManifest && !jarContents.containsKey("META-INF/MANIFEST.MF"))
247 {
248 jarContents.put("META-INF/MANIFEST.MF", "Manifest-Version: 1.0".getBytes());
249 }
250
251 File jarFile = File.createTempFile(name, ".jar", baseDir);
252 ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(jarFile));
253 for (Iterator i = jarContents.entrySet().iterator(); i.hasNext();)
254 {
255 Map.Entry entry = (Map.Entry) i.next();
256 zout.putNextEntry(new ZipEntry((String) entry.getKey()));
257 zout.write((byte[]) entry.getValue());
258 }
259 zout.close();
260 return jarFile;
261 }
262
263 public ClassLoader getClassLoader()
264 {
265 return classLoader;
266 }
267
268 }