1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 package org.osjava.jardiff;
40
41 import java.io.File;
42 import java.io.FileOutputStream;
43 import java.io.IOException;
44 import java.io.InputStream;
45 import java.io.OutputStream;
46 import java.net.URL;
47 import java.util.HashSet;
48 import java.util.Set;
49
50 import javax.xml.transform.ErrorListener;
51 import javax.xml.transform.Transformer;
52 import javax.xml.transform.TransformerException;
53 import javax.xml.transform.TransformerFactory;
54 import javax.xml.transform.sax.SAXTransformerFactory;
55 import javax.xml.transform.sax.TransformerHandler;
56 import javax.xml.transform.stream.StreamResult;
57 import javax.xml.transform.stream.StreamSource;
58
59 import org.apache.commons.cli.CommandLine;
60 import org.apache.commons.cli.GnuParser;
61 import org.apache.commons.cli.HelpFormatter;
62 import org.apache.commons.cli.Option;
63 import org.apache.commons.cli.Parser;
64 import org.apache.commons.cli.ParseException;
65 import org.apache.commons.cli.Options;
66
67 /***
68 * A static entry point for use from the command line.
69 */
70 public class Main {
71
72 /***
73 * Private constructor to prevent this class being instantiated.
74 */
75 private Main() {
76 }
77
78 /***
79 * Define set of valid formats.
80 * This is here to make maintenance more easy.
81 */
82 private final static Set FORMATS = new HashSet();
83
84 /***
85 * Can you javadoc static code, I think not, but lets try anyway.
86 */
87 static {
88 FORMATS.add("html");
89 FORMATS.add("xhtml");
90 FORMATS.add("text");
91 }
92
93 /***
94 * Utility function for showing help using commons-cli.
95 * @param options Command line options.
96 * @param msg Optional message to show.
97 */
98 private static void showHelp(Options options, String msg) {
99 if(msg != null) {
100 System.out.println(msg);
101 }
102 HelpFormatter hf = new HelpFormatter();
103 hf.printHelp("JarDiff -f <from jar> -t <to jar> [-F <from name>] [-T <to name>] [[-o <xml|html|xhtml|text>]|[-x <xsl file>]] [-O <file>] [-s <href>] [-fa <href>] [-ta <href>]", options);
104 }
105
106 /***
107 * Main method to allow this to be run from the command line.
108 * This needs work, currently only takes two arguments, which are
109 * the old jar file and the new jar file.
110 *
111 * @param args A string array of length two containing the filenames of
112 * two jar files, the first of which being the older of the
113 * two.
114 * @throws Exception when there is an underlying exception, e.g.
115 * writing to a file caused an IOException
116 */
117 public static void main(String[] args) throws Exception {
118 try {
119 Options options = new Options();
120 Option tmp;
121 tmp = new Option("f","from",true,"from jar file");
122 options.addOption(tmp);
123 tmp = new Option("t","to",true,"to jar file");
124 options.addOption(tmp);
125 tmp = new Option("F","from-name",true,"from name");
126 options.addOption(tmp);
127 tmp = new Option("T","to-name",true,"to name");
128 options.addOption(tmp);
129
130
131 tmp = new Option("o","output-format",true,"output format, xml or html");
132 options.addOption(tmp);
133 tmp = new Option("O","out",true,"output file");
134 options.addOption(tmp);
135 tmp = new Option("h","help",false,"print help on command line arguments");
136 options.addOption(tmp);
137 tmp = new Option("x","xsl",true,"custom xsl sheet to format output with");
138 options.addOption(tmp);
139 tmp = new Option("s","stylesheet",true,"stylesheet to link to when generating html");
140 options.addOption(tmp);
141 tmp = new Option("fa","from-api",true,"relative location of from api");
142 options.addOption(tmp);
143 tmp = new Option("ta","to-api",true,"relative location of to api");
144 options.addOption(tmp);
145 Parser parser = new GnuParser();
146 CommandLine cli = null;
147 try {
148 cli = parser.parse(options, args);
149 } catch (ParseException pe) {
150 showHelp(options, pe.getMessage());
151 return;
152 }
153 args = cli.getArgs();
154 if(cli.hasOption('h'))
155 {
156 showHelp(options, null);
157 return;
158 }
159 if(args.length > 0) {
160 showHelp(options, "Additional arguments specified");
161 return;
162 }
163 if(!cli.hasOption('f')) {
164 showHelp(options, "Missing required argument: -f");
165 return;
166 }
167 if(!cli.hasOption('t')) {
168 showHelp(options, "Missing required argument: -t");
169 return;
170 }
171
172 TransformerFactory tf = TransformerFactory.newInstance();
173 tf.setErrorListener(
174 new ErrorListener() {
175 public void warning(TransformerException te) {
176 System.err.println("xslt warning: "+te.getMessageAndLocation());
177 }
178 public void error(TransformerException te) {
179 System.err.println("xslt error: "+te.getMessageAndLocation());
180 }
181 public void fatalError(TransformerException te) {
182 System.err.println("xslt fatal error: "+te.getMessageAndLocation());
183 }
184 });
185 Transformer ot;
186 if(cli.hasOption('o')) {
187 if(cli.hasOption('x')) {
188 showHelp(options, "Cannot use both -x and -o");
189 return;
190 }
191 String val = cli.getOptionValue('o');
192 if("xml".equals(val)) {
193 ot = tf.newTransformer();
194 } else if(FORMATS.contains(val)) {
195 URL url = JarDiff.class.getClassLoader()
196 .getResource("style/jardiff-"+val+".xsl");
197 ot = tf.newTransformer(
198 new StreamSource( url.toString() )
199 );
200 } else {
201 showHelp(options, "Invalid output format: "+val);
202 return;
203 }
204 } else if(cli.hasOption('x')) {
205 File xsl = new File(cli.getOptionValue('x'));
206 ot = tf.newTransformer(new StreamSource(xsl));
207 } else {
208 ot = tf.newTransformer();
209 }
210 if(cli.hasOption("s")) {
211 ot.setParameter("stylesheet", cli.getOptionValue("s"));
212 }
213 if(cli.hasOption("fa")) {
214 ot.setParameter("from-api", cli.getOptionValue("fa"));
215 }
216 if(cli.hasOption("ta")) {
217 ot.setParameter("to-api", cli.getOptionValue("ta"));
218 }
219 OutputStream out;
220 if(cli.hasOption('O')) {
221 out = new FileOutputStream(cli.getOptionValue('O'));
222 } else {
223 out = System.out;
224 }
225 JarDiff jd = new JarDiff();
226 File oldFile = new File(cli.getOptionValue('f'));
227 File newFile = new File(cli.getOptionValue('t'));
228 if(cli.hasOption('F')) {
229 jd.setOldVersion(cli.getOptionValue('F'));
230 } else {
231 jd.setOldVersion(oldFile.getName());
232 }
233 if(cli.hasOption('T')) {
234 jd.setNewVersion(cli.getOptionValue('T'));
235 } else {
236 jd.setNewVersion(newFile.getName());
237 }
238 jd.loadOldClasses(oldFile);
239 jd.loadNewClasses(newFile);
240 jd.diff(
241 new DOMDiffHandler(ot, new StreamResult(out)),
242 new SimpleDiffCriteria()
243 );
244 out.close();
245 } catch (Exception e) {
246 e.printStackTrace(System.err);
247 }
248 }
249 }