1 package dolda.jsvc.j2ee;
6 import java.util.zip.*;
7 import java.util.jar.*;
10 private Properties props = defprops();
11 private JarOutputStream zipout = null;
12 private final OutputStream realout;
14 public Archive(OutputStream out) {
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/"));
28 private ZipOutputStream zip() throws IOException {
34 public void putprop(String key, String val) {
38 public void loadprops(InputStream in) throws IOException {
42 public void jarprops(File[] jars, String propres) throws IOException {
43 URL[] urls = new URL[jars.length];
45 for(int i = 0; i < jars.length; i++)
46 urls[i] = new URL("file", "", jars[i].toString());
47 } catch(MalformedURLException e) {
50 ClassLoader cl = new URLClassLoader(urls);
51 InputStream in = cl.getResourceAsStream(propres);
61 private static Properties defprops() {
62 Properties props = new Properties();
63 props.put("jsvc.j2ee.webxml.coding", "UTF-8");
67 private static void cpstream(InputStream in, OutputStream out) throws IOException {
68 byte[] buf = new byte[4096];
70 int ret = in.read(buf, 0, buf.length);
73 out.write(buf, 0, ret);
77 private static class MissingPropException extends RuntimeException {
78 public final String prop;
80 private MissingPropException(String prop) {
81 super("Missing required property " + prop);
86 private static String subst(String ln, Properties props) {
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);
93 throw(new MissingPropException(pn));
94 ln = ln.substring(0, p) + pv + ln.substring(p2 + 1);
100 private void writewebxml() throws IOException {
101 zip().putNextEntry(new ZipEntry("WEB-INF/web.xml"));
102 InputStream tmpl = Archive.class.getResourceAsStream("web.xml.template");
103 String cs = (String)props.get("jsvc.j2ee.webxml.coding");
105 BufferedReader r = new BufferedReader(new InputStreamReader(tmpl, "US-ASCII"));
106 BufferedWriter w = new BufferedWriter(new OutputStreamWriter(zip(), cs));
108 while((ln = r.readLine()) != null) {
109 w.write(subst(ln, props));
118 public void addcode(String name, InputStream in) throws IOException {
119 zip().putNextEntry(new ZipEntry("WEB-INF/classes/" + name));
123 public void addjars(File[] jars) throws IOException {
124 jarprops(jars, "jsvc.properties");
125 ZipOutputStream zip = zip();
126 for(File jar : jars) {
127 zip.putNextEntry(new ZipEntry("WEB-INF/lib/" + jar.getName()));
128 InputStream jarin = new FileInputStream(jar);
130 cpstream(jarin, zip);
137 public void finish() throws IOException {
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;
146 private static File[] getfiles(org.apache.tools.ant.types.FileSet fs) {
147 org.apache.tools.ant.DirectoryScanner ds = fs.getDirectoryScanner();
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]);
156 private void rebuild(File[] jars, File[] code) throws IOException {
157 OutputStream out = new FileOutputStream(outfile);
159 System.out.println("Building " + outfile);
162 Archive ar = new Archive(out);
164 ar.putprop("jsvc.j2ee.appname", appname);
166 InputStream in = new FileInputStream(props);
175 InputStream in = new FileInputStream(f);
177 ar.addcode(f.getName(), in);
187 } catch(MissingPropException e) {
188 throw(new org.apache.tools.ant.BuildException(e.getMessage(), e));
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];
198 throw(new org.apache.tools.ant.BuildException("Must have at least one JAR file", getLocation()));
200 throw(new org.apache.tools.ant.BuildException("No output file specified", getLocation()));
202 Collection<File> deps = new LinkedList<File>();
203 deps.addAll(Arrays.asList(jars));
204 deps.addAll(Arrays.asList(code));
208 boolean rebuild = false;
209 for(File dep : deps) {
211 throw(new org.apache.tools.ant.BuildException(dep + " does not exist", getLocation()));
212 if(dep.lastModified() > outfile.lastModified()) {
221 } catch(IOException e) {
222 throw(new org.apache.tools.ant.BuildException(e));
227 public void addJars(org.apache.tools.ant.types.FileSet path) {
231 public void setJars(org.apache.tools.ant.types.FileSet path) {
235 public void setCode(org.apache.tools.ant.types.FileSet path) {
239 public void setPropfile(File propfile) {
240 this.props = propfile;
243 public void setDestfile(File outfile) {
244 this.outfile = outfile;
247 public void setAppname(String name) {
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...");
256 public static void main(String[] args) throws IOException {
257 PosixArgs opt = PosixArgs.getopt(args, "hp:n:c:");
262 if(opt.rest.length < 2) {
266 String war = opt.rest[0];
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]);
271 OutputStream out = new FileOutputStream(war);
273 Archive ar = new Archive(out);
275 for(char c : opt.parsed()) {
279 InputStream in = new FileInputStream(opt.arg);
288 ar.putprop("jsvc.j2ee.appname", opt.arg);
292 File f = new File(opt.arg);
293 InputStream in = new FileInputStream(f);
295 ar.addcode(f.getName(), in);