1 package dolda.jsvc.j2ee;
3 import dolda.jsvc.util.*;
7 import java.util.zip.*;
8 import java.util.jar.*;
10 public class Archive {
11 private Properties props = defprops();
12 private JarOutputStream zipout = null;
13 private final OutputStream realout;
15 public Archive(OutputStream out) {
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/"));
29 private ZipOutputStream zip() throws IOException {
35 public void putprop(String key, String val) {
39 public void loadprops(InputStream in) throws IOException {
43 public void jarprops(File[] jars, String propres) throws IOException {
44 URL[] urls = new URL[jars.length];
46 for(int i = 0; i < jars.length; i++)
47 urls[i] = new URL("file", "", jars[i].toString());
48 } catch(MalformedURLException e) {
51 ClassLoader cl = new URLClassLoader(urls);
52 InputStream in = cl.getResourceAsStream(propres);
62 private static Properties defprops() {
63 Properties props = new Properties();
64 props.put("jsvc.j2ee.webxml.coding", "UTF-8");
68 private static class MissingPropException extends RuntimeException {
69 public final String prop;
71 private MissingPropException(String prop) {
72 super("Missing required property " + prop);
77 private static String subst(String ln, Properties props) {
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);
84 throw(new MissingPropException(pn));
85 ln = ln.substring(0, p) + pv + ln.substring(p2 + 1);
91 private void writewebxml() throws IOException {
92 zip().putNextEntry(new ZipEntry("WEB-INF/web.xml"));
93 InputStream tmpl = Archive.class.getResourceAsStream("web.xml.template");
94 String cs = (String)props.get("jsvc.j2ee.webxml.coding");
96 BufferedReader r = new BufferedReader(new InputStreamReader(tmpl, "US-ASCII"));
97 BufferedWriter w = new BufferedWriter(new OutputStreamWriter(zip(), cs));
99 while((ln = r.readLine()) != null) {
100 w.write(subst(ln, props));
109 public void addcode(String name, InputStream in) throws IOException {
110 zip().putNextEntry(new ZipEntry("WEB-INF/classes/" + name));
111 Misc.cpstream(in, zip());
114 public void addjars(File[] jars) throws IOException {
115 jarprops(jars, "jsvc.properties");
116 ZipOutputStream zip = zip();
117 for(File jar : jars) {
118 zip.putNextEntry(new ZipEntry("WEB-INF/lib/" + jar.getName()));
119 InputStream jarin = new FileInputStream(jar);
121 Misc.cpstream(jarin, zip);
128 public void finish() throws IOException {
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;
137 private static File[] getfiles(org.apache.tools.ant.types.FileSet fs) {
138 org.apache.tools.ant.DirectoryScanner ds = fs.getDirectoryScanner();
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]);
147 private void rebuild(File[] jars, File[] code) throws IOException {
148 OutputStream out = new FileOutputStream(outfile);
150 System.out.println("Building " + outfile);
153 Archive ar = new Archive(out);
155 ar.putprop("jsvc.j2ee.appname", appname);
157 InputStream in = new FileInputStream(props);
166 InputStream in = new FileInputStream(f);
168 ar.addcode(f.getName(), in);
178 } catch(MissingPropException e) {
179 throw(new org.apache.tools.ant.BuildException(e.getMessage(), e));
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];
189 throw(new org.apache.tools.ant.BuildException("Must have at least one JAR file", getLocation()));
191 throw(new org.apache.tools.ant.BuildException("No output file specified", getLocation()));
193 Collection<File> deps = new LinkedList<File>();
194 deps.addAll(Arrays.asList(jars));
195 deps.addAll(Arrays.asList(code));
199 boolean rebuild = false;
200 for(File dep : deps) {
202 throw(new org.apache.tools.ant.BuildException(dep + " does not exist", getLocation()));
203 if(dep.lastModified() > outfile.lastModified()) {
212 } catch(IOException e) {
213 throw(new org.apache.tools.ant.BuildException(e));
218 public void addJars(org.apache.tools.ant.types.FileSet path) {
222 public void setJars(org.apache.tools.ant.types.FileSet path) {
226 public void setCode(org.apache.tools.ant.types.FileSet path) {
230 public void setPropfile(File propfile) {
231 this.props = propfile;
234 public void setDestfile(File outfile) {
235 this.outfile = outfile;
238 public void setAppname(String name) {
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...");
247 public static void main(String[] args) throws IOException {
248 PosixArgs opt = PosixArgs.getopt(args, "hp:n:c:");
253 if(opt.rest.length < 2) {
257 String war = opt.rest[0];
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]);
262 OutputStream out = new FileOutputStream(war);
264 Archive ar = new Archive(out);
266 for(char c : opt.parsed()) {
270 InputStream in = new FileInputStream(opt.arg);
279 ar.putprop("jsvc.j2ee.appname", opt.arg);
283 File f = new File(opt.arg);
284 InputStream in = new FileInputStream(f);
286 ar.addcode(f.getName(), in);