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