Moved WAR making to an explicit function.
authorFredrik Tolf <fredrik@dolda2000.com>
Mon, 12 Oct 2009 15:54:44 +0000 (17:54 +0200)
committerFredrik Tolf <fredrik@dolda2000.com>
Mon, 12 Oct 2009 15:54:44 +0000 (17:54 +0200)
build.xml
etc/web.xml.template [moved from www/web.xml with 79% similarity]
src/dolda/jsvc/j2ee/Archive.java [new file with mode: 0644]
src/dolda/jsvc/j2ee/PosixArgs.java [new file with mode: 0644]

index 0e6d4e6..43314b9 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -13,8 +13,6 @@
    <target name="build-env">
       <mkdir dir="build" />
       <mkdir dir="build/classes" />
-      <mkdir dir="build/webapp" />
-      <mkdir dir="build/webapp/WEB-INF/classes" />
     </target>
 
     <target name="jsvc" depends="build-env">
        <!-- <classpath refid="classpath" /> -->
         <compilerarg value="-Xlint:unchecked" />
       </javac>
+      <copy todir="build/classes/dolda/jsvc/j2ee" file="etc/web.xml.template" />
     </target>
     
     <target name="jsvc-jar" depends="build-env, jsvc">
         <jar destfile="build/jsvc.jar" basedir="build/classes" />
     </target>
     
-    <target name="webapp" depends="build-env">
-       <mkdir dir="build/webapp/WEB-INF/lib" />
-       <copy file="build/jsvc.jar" tofile="build/webapp/WEB-INF/lib/jsvc.jar" />
-       <copy todir="build/webapp/WEB-INF/lib">
-         <fileset dir="lib" />
-       </copy>
-    </target>
-
-    <target name="war" depends="build-env, jsvc-jar, webapp">
-       <war destfile="build/jsvc.war"
-           basedir="build/webapp"
-           webxml="www/web.xml"
-           />
-    </target>
-
     <target name="clean">
        <delete dir="build" />
     </target>
similarity index 79%
rename from www/web.xml
rename to etc/web.xml.template
index e2e5908..487cdd8 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0" encoding="${jsvc.j2ee.webxml.coding}"?>
 
 <!DOCTYPE web-app
           PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
@@ -6,7 +6,7 @@
 
 <web-app>
 
-  <display-name>JSvc-wrapping</display-name>
+  <display-name>${jsvc.j2ee.appname}</display-name>
 
   <servlet>
     <servlet-name>jsvc</servlet-name>
diff --git a/src/dolda/jsvc/j2ee/Archive.java b/src/dolda/jsvc/j2ee/Archive.java
new file mode 100644 (file)
index 0000000..ee9f26e
--- /dev/null
@@ -0,0 +1,149 @@
+package dolda.jsvc.j2ee;
+
+import java.util.*;
+import java.io.*;
+import java.net.*;
+import java.util.zip.*;
+import java.util.jar.*;
+
+public class Archive {
+    private static void usage(PrintStream out) {
+       out.println("usage: dolda.jsvc.j2ee.Archive [-h] [-p PROPFILE] [-n DISPLAY-NAME] WAR-FILE JAR-FILE...");
+    }
+    
+    private static void jarprops(String[] jars, String propres, Properties props) throws IOException {
+       URL[] urls = new URL[jars.length];
+       try {
+           for(int i = 0; i < jars.length; i++)
+               urls[i] = new URL("file", "", jars[i]);
+       } catch(MalformedURLException e) {
+           throw(new Error(e));
+       }
+       ClassLoader cl = new URLClassLoader(urls);
+       InputStream in = cl.getResourceAsStream(propres);
+       if(in != null) {
+           try {
+               props.load(in);
+           } finally {
+               in.close();
+           }
+       }
+    }
+
+    private static Properties defprops() {
+       Properties props = new Properties();
+       props.put("jsvc.j2ee.webxml.coding", "UTF-8");
+       return(props);
+    }
+
+    private static void cpstream(InputStream in, OutputStream out) throws IOException {
+        byte[] buf = new byte[4096];
+        while(true) {
+           int ret = in.read(buf, 0, buf.length);
+            if(ret < 0)
+                return;
+           out.write(buf, 0, ret);
+        }
+    }
+
+    private static String subst(String ln, Properties props) {
+       int p = 0;
+       while((p = ln.indexOf("${", p)) >= 0) {
+           int p2 = ln.indexOf('}', p + 2);
+           String pn = ln.substring(p + 2, p2);
+           String pv = (String)props.get(pn);
+           if(pv == null)
+               throw(new RuntimeException("Missing required property " + pn));
+           ln = ln.substring(0, p) + pv + ln.substring(p2 + 1);
+           p = p + pv.length();
+       }
+       return(ln);
+    }
+
+    private static void writewebxml(Properties props, OutputStream out) throws IOException {
+       InputStream tmpl = Archive.class.getResourceAsStream("web.xml.template");
+       String cs = (String)props.get("jsvc.j2ee.webxml.coding");
+       try {
+           BufferedReader r = new BufferedReader(new InputStreamReader(tmpl, "US-ASCII"));
+           BufferedWriter w = new BufferedWriter(new OutputStreamWriter(out, cs));
+           String ln;
+           while((ln = r.readLine()) != null) {
+               w.write(subst(ln, props));
+               w.write('\n');
+           }
+           w.flush();
+       } finally {
+           tmpl.close();
+       }
+    }
+    
+    public static void makewar(String[] jars, Properties props, OutputStream out) throws IOException {
+       Manifest man = new Manifest();
+       man.getMainAttributes().put(new Attributes.Name("Manifest-Version"), "1.0");
+       man.getMainAttributes().put(new Attributes.Name("Created-By"), "jsvc");
+       JarOutputStream zip = new JarOutputStream(out, man);
+       zip.putNextEntry(new ZipEntry("WEB-INF/"));
+       zip.putNextEntry(new ZipEntry("WEB-INF/lib/"));
+       for(String jar : jars) {
+           String bn = jar;
+           int p = bn.lastIndexOf('/');
+           if(p >= 0)
+               bn = bn.substring(p + 1);
+           zip.putNextEntry(new ZipEntry("WEB-INF/lib/" + bn));
+           InputStream jarin = new FileInputStream(jar);
+           try {
+               cpstream(jarin, zip);
+           } finally {
+               jarin.close();
+           }
+       }
+       zip.putNextEntry(new ZipEntry("WEB-INF/web.xml"));
+       writewebxml(props, zip);
+       zip.finish();
+    }
+
+    public static void main(String[] args) throws IOException {
+       PosixArgs opt = PosixArgs.getopt(args, "hp:n:");
+       if(opt == null) {
+           usage(System.err);
+           System.exit(1);
+       }
+       if(opt.rest.length < 2) {
+           usage(System.err);
+           System.exit(1);
+       }
+       String war = opt.rest[0];
+       String[] jars = Arrays.copyOfRange(opt.rest, 1, opt.rest.length);
+       
+       Properties props = defprops();
+       jarprops(jars, "/jsvc.properties", props);
+       
+       for(char c : opt.parsed()) {
+           switch(c) {
+           case 'p':
+               {
+                   InputStream in = new FileInputStream(opt.arg);
+                   try {
+                       props.load(in);
+                   } finally {
+                       in.close();
+                   }
+               }
+               break;
+           case 'n':
+               props.put("jsvc.j2ee.appname", opt.arg);
+               break;
+           case 'h':
+               usage(System.out);
+               return;
+           }
+       }
+       
+       OutputStream out = new FileOutputStream(war);
+       try {
+           makewar(jars, props, out);
+       } finally {
+           out.close();
+       }
+    }
+}
diff --git a/src/dolda/jsvc/j2ee/PosixArgs.java b/src/dolda/jsvc/j2ee/PosixArgs.java
new file mode 100644 (file)
index 0000000..4a23941
--- /dev/null
@@ -0,0 +1,100 @@
+package dolda.jsvc.j2ee;
+
+import java.util.*;
+
+public class PosixArgs {
+    private List<Arg> parsed;
+    public String[] rest;
+    public String arg = null;
+    
+    private static class Arg {
+       private char ch;
+       private String arg;
+       
+       private Arg(char ch, String arg) {
+           this.ch = ch;
+           this.arg = arg;
+       }
+    }
+    
+    private PosixArgs() {
+       parsed = new ArrayList<Arg>();
+    }
+
+    public static PosixArgs getopt(String[] argv, int start, String desc) {
+       PosixArgs ret = new PosixArgs();
+       List<Character> fl = new ArrayList<Character>(), fla = new ArrayList<Character>();
+       List<String> rest = new ArrayList<String>();
+       for(int i = 0; i < desc.length();) {
+           char ch = desc.charAt(i++);
+           if((i < desc.length()) && (desc.charAt(i) == ':')) {
+               i++;
+               fla.add(ch);
+           } else {
+               fl.add(ch);
+           }
+       }
+       boolean acc = true;
+       for(int i = start; i < argv.length;) {
+           String arg = argv[i++];
+           if(acc && arg.equals("--")) {
+               acc = false;
+           } if(acc && (arg.charAt(0) == '-')) {
+               for(int o = 1; o < arg.length();) {
+                   char ch = arg.charAt(o++);
+                   if(fl.contains(ch)) {
+                       ret.parsed.add(new Arg(ch, null));
+                   } else if(fla.contains(ch)) {
+                       if(o < arg.length()) {
+                           ret.parsed.add(new Arg(ch, arg.substring(o)));
+                           break;
+                       } else if(i < argv.length) {
+                           ret.parsed.add(new Arg(ch, argv[i++]));
+                           break;
+                       } else {
+                           System.err.println("option requires an argument -- '" + ch + "'");
+                           return(null);
+                       }
+                   } else {
+                       System.err.println("invalid option -- '" + ch + "'");
+                       return(null);
+                   }
+               }
+           } else {
+               rest.add(arg);
+           }
+       }
+       ret.rest = rest.toArray(new String[0]);
+       return(ret);
+    }
+    
+    public static PosixArgs getopt(String[] argv, String desc) {
+       return(getopt(argv, 0, desc));
+    }
+    
+    public Iterable<Character> parsed() {
+       return(new Iterable<Character>() {
+               public Iterator<Character> iterator() {
+                   return(new Iterator<Character>() {
+                           private int i = 0;
+                           
+                           public boolean hasNext() {
+                               return(i < parsed.size());
+                           }
+                           
+                           public Character next() {
+                               if(i >= parsed.size())
+                                   throw(new NoSuchElementException());
+                               Arg a = parsed.get(i++);
+                               arg = a.arg;
+                               return(a.ch);
+                           }
+                           
+                           public void remove() {
+                               throw(new UnsupportedOperationException());
+                           }
+                       });
+               }
+           });
+    }
+}