Added a test responder.
[jsvc.git] / src / dolda / jsvc / j2ee / Archive.java
CommitLineData
f179d8ba
FT
1package dolda.jsvc.j2ee;
2
3import java.util.*;
4import java.io.*;
5import java.net.*;
6import java.util.zip.*;
7import java.util.jar.*;
8
9public 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
42 public void jarprops(String[] 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++)
46 urls[i] = new URL("file", "", jars[i]);
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
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)
84 throw(new RuntimeException("Missing required property " + pn));
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));
111 cpstream(in, zip());
112 }
113
114 private static String basename(String fn) {
115 int p = fn.lastIndexOf('/');
116 if(p >= 0)
117 return(fn.substring(p + 1));
118 return(fn);
119 }
120
121 public void addjars(String[] jars) throws IOException {
122 jarprops(jars, "/jsvc.properties");
123 ZipOutputStream zip = zip();
f179d8ba 124 for(String jar : jars) {
5f3753cb 125 zip.putNextEntry(new ZipEntry("WEB-INF/lib/" + basename(jar)));
f179d8ba
FT
126 InputStream jarin = new FileInputStream(jar);
127 try {
128 cpstream(jarin, zip);
129 } finally {
130 jarin.close();
131 }
132 }
f179d8ba
FT
133 }
134
5f3753cb
FT
135 public void finish() throws IOException {
136 zip().finish();
137 }
138
139 private static void usage(PrintStream out) {
140 out.println("usage: dolda.jsvc.j2ee.Archive [-h] [-p PROPFILE] [-n DISPLAY-NAME] [(-c CODE-FILE)...] WAR-FILE JAR-FILE...");
141 }
142
f179d8ba 143 public static void main(String[] args) throws IOException {
5f3753cb 144 PosixArgs opt = PosixArgs.getopt(args, "hp:n:c:");
f179d8ba
FT
145 if(opt == null) {
146 usage(System.err);
147 System.exit(1);
148 }
149 if(opt.rest.length < 2) {
150 usage(System.err);
151 System.exit(1);
152 }
153 String war = opt.rest[0];
154 String[] jars = Arrays.copyOfRange(opt.rest, 1, opt.rest.length);
155
5f3753cb
FT
156 OutputStream out = new FileOutputStream(war);
157 try {
158 Archive ar = new Archive(out);
f179d8ba 159
5f3753cb
FT
160 for(char c : opt.parsed()) {
161 switch(c) {
162 case 'p':
163 {
164 InputStream in = new FileInputStream(opt.arg);
165 try {
166 ar.loadprops(in);
167 } finally {
168 in.close();
169 }
170 }
171 break;
172 case 'n':
173 ar.putprop("jsvc.j2ee.appname", opt.arg);
174 break;
175 case 'c':
176 {
177 InputStream in = new FileInputStream(opt.arg);
178 try {
179 ar.addcode(basename(opt.arg), in);
180 } finally {
181 in.close();
182 }
f179d8ba 183 }
5f3753cb
FT
184 break;
185 case 'h':
186 usage(System.out);
187 return;
f179d8ba 188 }
f179d8ba 189 }
5f3753cb
FT
190
191 ar.addjars(jars);
192 ar.writewebxml();
193
194 ar.finish();
f179d8ba
FT
195 } finally {
196 out.close();
197 }
198 }
199}