Commit | Line | Data |
---|---|---|
f179d8ba FT |
1 | package dolda.jsvc.j2ee; |
2 | ||
3 | import java.util.*; | |
4 | import java.io.*; | |
5 | import java.net.*; | |
6 | import java.util.zip.*; | |
7 | import java.util.jar.*; | |
8 | ||
9 | public class Archive { | |
5f3753cb FT |
10 | private Properties props = defprops(); |
11 | private JarOutputStream zipout = null; | |
12 | private final OutputStream realout; | |
13 | ||
14 | public Archive(OutputStream out) { | |
15 | this.realout = out; | |
16 | } | |
17 | ||
18 | private void initzip() throws IOException { | |
19 | Manifest man = new Manifest(); | |
20 | man.getMainAttributes().put(new Attributes.Name("Manifest-Version"), "1.0"); | |
21 | man.getMainAttributes().put(new Attributes.Name("Created-By"), "jsvc"); | |
22 | JarOutputStream zip = new JarOutputStream(realout, man); | |
23 | zip.putNextEntry(new ZipEntry("WEB-INF/")); | |
24 | zip.putNextEntry(new ZipEntry("WEB-INF/lib/")); | |
25 | this.zipout = zip; | |
26 | } | |
27 | ||
28 | private ZipOutputStream zip() throws IOException { | |
29 | if(zipout == null) | |
30 | initzip(); | |
31 | return(this.zipout); | |
f179d8ba FT |
32 | } |
33 | ||
5f3753cb FT |
34 | public void putprop(String key, String val) { |
35 | props.put(key, val); | |
36 | } | |
37 | ||
38 | public void loadprops(InputStream in) throws IOException { | |
39 | props.load(in); | |
40 | } | |
41 | ||
17204d14 | 42 | public void jarprops(File[] jars, String propres) throws IOException { |
f179d8ba FT |
43 | URL[] urls = new URL[jars.length]; |
44 | try { | |
45 | for(int i = 0; i < jars.length; i++) | |
17204d14 | 46 | urls[i] = new URL("file", "", jars[i].toString()); |
f179d8ba FT |
47 | } catch(MalformedURLException e) { |
48 | throw(new Error(e)); | |
49 | } | |
50 | ClassLoader cl = new URLClassLoader(urls); | |
51 | InputStream in = cl.getResourceAsStream(propres); | |
52 | if(in != null) { | |
53 | try { | |
54 | props.load(in); | |
55 | } finally { | |
56 | in.close(); | |
57 | } | |
58 | } | |
59 | } | |
60 | ||
61 | private static Properties defprops() { | |
62 | Properties props = new Properties(); | |
63 | props.put("jsvc.j2ee.webxml.coding", "UTF-8"); | |
64 | return(props); | |
65 | } | |
66 | ||
67 | private static void cpstream(InputStream in, OutputStream out) throws IOException { | |
68 | byte[] buf = new byte[4096]; | |
69 | while(true) { | |
70 | int ret = in.read(buf, 0, buf.length); | |
71 | if(ret < 0) | |
72 | return; | |
73 | out.write(buf, 0, ret); | |
74 | } | |
75 | } | |
76 | ||
17204d14 FT |
77 | private static class MissingPropException extends RuntimeException { |
78 | public final String prop; | |
79 | ||
80 | private MissingPropException(String prop) { | |
81 | super("Missing required property " + prop); | |
82 | this.prop = prop; | |
83 | } | |
84 | } | |
85 | ||
f179d8ba FT |
86 | private static String subst(String ln, Properties props) { |
87 | int p = 0; | |
88 | while((p = ln.indexOf("${", p)) >= 0) { | |
89 | int p2 = ln.indexOf('}', p + 2); | |
90 | String pn = ln.substring(p + 2, p2); | |
91 | String pv = (String)props.get(pn); | |
92 | if(pv == null) | |
17204d14 | 93 | throw(new MissingPropException(pn)); |
f179d8ba FT |
94 | ln = ln.substring(0, p) + pv + ln.substring(p2 + 1); |
95 | p = p + pv.length(); | |
96 | } | |
97 | return(ln); | |
98 | } | |
99 | ||
5f3753cb FT |
100 | private void writewebxml() throws IOException { |
101 | zip().putNextEntry(new ZipEntry("WEB-INF/web.xml")); | |
f179d8ba FT |
102 | InputStream tmpl = Archive.class.getResourceAsStream("web.xml.template"); |
103 | String cs = (String)props.get("jsvc.j2ee.webxml.coding"); | |
104 | try { | |
105 | BufferedReader r = new BufferedReader(new InputStreamReader(tmpl, "US-ASCII")); | |
5f3753cb | 106 | BufferedWriter w = new BufferedWriter(new OutputStreamWriter(zip(), cs)); |
f179d8ba FT |
107 | String ln; |
108 | while((ln = r.readLine()) != null) { | |
109 | w.write(subst(ln, props)); | |
110 | w.write('\n'); | |
111 | } | |
112 | w.flush(); | |
113 | } finally { | |
114 | tmpl.close(); | |
115 | } | |
116 | } | |
117 | ||
5f3753cb FT |
118 | public void addcode(String name, InputStream in) throws IOException { |
119 | zip().putNextEntry(new ZipEntry("WEB-INF/classes/" + name)); | |
120 | cpstream(in, zip()); | |
121 | } | |
122 | ||
17204d14 | 123 | public void addjars(File[] jars) throws IOException { |
104fa785 | 124 | jarprops(jars, "jsvc.properties"); |
5f3753cb | 125 | ZipOutputStream zip = zip(); |
17204d14 FT |
126 | for(File jar : jars) { |
127 | zip.putNextEntry(new ZipEntry("WEB-INF/lib/" + jar.getName())); | |
f179d8ba FT |
128 | InputStream jarin = new FileInputStream(jar); |
129 | try { | |
130 | cpstream(jarin, zip); | |
131 | } finally { | |
132 | jarin.close(); | |
133 | } | |
134 | } | |
f179d8ba FT |
135 | } |
136 | ||
5f3753cb FT |
137 | public void finish() throws IOException { |
138 | zip().finish(); | |
139 | } | |
17204d14 FT |
140 | |
141 | public static class AntTask extends org.apache.tools.ant.Task { | |
142 | private org.apache.tools.ant.types.FileSet jars, code; | |
143 | private File props, outfile; | |
144 | private String appname; | |
145 | ||
146 | private static File[] getfiles(org.apache.tools.ant.types.FileSet fs) { | |
147 | org.apache.tools.ant.DirectoryScanner ds = fs.getDirectoryScanner(); | |
148 | ds.scan(); | |
149 | String[] nms = ds.getIncludedFiles(); | |
150 | File[] ret = new File[nms.length]; | |
151 | for(int i = 0; i < nms.length; i++) | |
152 | ret[i] = new File(ds.getBasedir(), nms[i]); | |
153 | return(ret); | |
154 | } | |
155 | ||
156 | private void rebuild(File[] jars, File[] code) throws IOException { | |
157 | OutputStream out = new FileOutputStream(outfile); | |
158 | ||
159 | System.out.println("Building " + outfile); | |
160 | ||
161 | try { | |
162 | Archive ar = new Archive(out); | |
163 | if(appname != null) | |
164 | ar.putprop("jsvc.j2ee.appname", appname); | |
165 | if(props != null) { | |
166 | InputStream in = new FileInputStream(props); | |
167 | try { | |
168 | ar.loadprops(in); | |
169 | } finally { | |
170 | in.close(); | |
171 | } | |
172 | } | |
173 | ||
174 | for(File f : code) { | |
175 | InputStream in = new FileInputStream(f); | |
176 | try { | |
177 | ar.addcode(f.getName(), in); | |
178 | } finally { | |
179 | in.close(); | |
180 | } | |
181 | } | |
182 | ||
183 | ar.addjars(jars); | |
184 | ar.writewebxml(); | |
185 | ||
186 | ar.finish(); | |
187 | } catch(MissingPropException e) { | |
188 | throw(new org.apache.tools.ant.BuildException(e.getMessage(), e)); | |
189 | } finally { | |
190 | out.close(); | |
191 | } | |
192 | } | |
193 | ||
194 | public void execute() { | |
195 | File[] jars = (this.jars != null)?getfiles(this.jars):new File[0]; | |
196 | File[] code = (this.code != null)?getfiles(this.code):new File[0]; | |
197 | if(jars.length < 1) | |
198 | throw(new org.apache.tools.ant.BuildException("Must have at least one JAR file", getLocation())); | |
199 | if(outfile == null) | |
200 | throw(new org.apache.tools.ant.BuildException("No output file specified", getLocation())); | |
201 | ||
202 | Collection<File> deps = new LinkedList<File>(); | |
203 | deps.addAll(Arrays.asList(jars)); | |
204 | deps.addAll(Arrays.asList(code)); | |
205 | if(props != null) | |
206 | deps.add(props); | |
207 | ||
208 | boolean rebuild = false; | |
209 | for(File dep : deps) { | |
210 | if(!dep.exists()) | |
211 | throw(new org.apache.tools.ant.BuildException(dep + " does not exist", getLocation())); | |
212 | if(dep.lastModified() > outfile.lastModified()) { | |
213 | rebuild = true; | |
214 | break; | |
215 | } | |
216 | } | |
217 | ||
218 | if(rebuild) { | |
219 | try { | |
220 | rebuild(jars, code); | |
221 | } catch(IOException e) { | |
222 | throw(new org.apache.tools.ant.BuildException(e)); | |
223 | } | |
224 | } | |
225 | } | |
226 | ||
227 | public void addJars(org.apache.tools.ant.types.FileSet path) { | |
228 | this.jars = path; | |
229 | } | |
230 | ||
231 | public void setJars(org.apache.tools.ant.types.FileSet path) { | |
232 | this.jars = path; | |
233 | } | |
234 | ||
235 | public void setCode(org.apache.tools.ant.types.FileSet path) { | |
236 | this.code = path; | |
237 | } | |
238 | ||
239 | public void setPropfile(File propfile) { | |
240 | this.props = propfile; | |
241 | } | |
242 | ||
243 | public void setDestfile(File outfile) { | |
244 | this.outfile = outfile; | |
245 | } | |
246 | ||
247 | public void setAppname(String name) { | |
248 | this.appname = name; | |
249 | } | |
250 | } | |
5f3753cb FT |
251 | |
252 | private static void usage(PrintStream out) { | |
253 | out.println("usage: dolda.jsvc.j2ee.Archive [-h] [-p PROPFILE] [-n DISPLAY-NAME] [(-c CODE-FILE)...] WAR-FILE JAR-FILE..."); | |
254 | } | |
255 | ||
f179d8ba | 256 | public static void main(String[] args) throws IOException { |
5f3753cb | 257 | PosixArgs opt = PosixArgs.getopt(args, "hp:n:c:"); |
f179d8ba FT |
258 | if(opt == null) { |
259 | usage(System.err); | |
260 | System.exit(1); | |
261 | } | |
262 | if(opt.rest.length < 2) { | |
263 | usage(System.err); | |
264 | System.exit(1); | |
265 | } | |
266 | String war = opt.rest[0]; | |
17204d14 FT |
267 | File[] jars = new File[opt.rest.length - 1]; |
268 | for(int i = 1; i < opt.rest.length; i++) | |
269 | jars[i - 1] = new File(opt.rest[i]); | |
f179d8ba | 270 | |
5f3753cb FT |
271 | OutputStream out = new FileOutputStream(war); |
272 | try { | |
273 | Archive ar = new Archive(out); | |
f179d8ba | 274 | |
5f3753cb FT |
275 | for(char c : opt.parsed()) { |
276 | switch(c) { | |
277 | case 'p': | |
278 | { | |
279 | InputStream in = new FileInputStream(opt.arg); | |
280 | try { | |
281 | ar.loadprops(in); | |
282 | } finally { | |
283 | in.close(); | |
284 | } | |
285 | } | |
286 | break; | |
287 | case 'n': | |
288 | ar.putprop("jsvc.j2ee.appname", opt.arg); | |
289 | break; | |
290 | case 'c': | |
291 | { | |
17204d14 FT |
292 | File f = new File(opt.arg); |
293 | InputStream in = new FileInputStream(f); | |
5f3753cb | 294 | try { |
17204d14 | 295 | ar.addcode(f.getName(), in); |
5f3753cb FT |
296 | } finally { |
297 | in.close(); | |
298 | } | |
f179d8ba | 299 | } |
5f3753cb FT |
300 | break; |
301 | case 'h': | |
302 | usage(System.out); | |
303 | return; | |
f179d8ba | 304 | } |
f179d8ba | 305 | } |
5f3753cb FT |
306 | |
307 | ar.addjars(jars); | |
308 | ar.writewebxml(); | |
309 | ||
310 | ar.finish(); | |
f179d8ba FT |
311 | } finally { |
312 | out.close(); | |
313 | } | |
314 | } | |
315 | } |