1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.clirr.cli;
21
22 import net.sf.clirr.core.Checker;
23 import net.sf.clirr.core.CheckerException;
24 import net.sf.clirr.core.ClassSelector;
25 import net.sf.clirr.core.PlainDiffListener;
26 import net.sf.clirr.core.XmlDiffListener;
27 import net.sf.clirr.core.DiffListener;
28 import net.sf.clirr.core.internal.bcel.BcelTypeArrayBuilder;
29 import net.sf.clirr.core.spi.JavaType;
30 import net.sf.clirr.core.spi.Scope;
31
32 import org.apache.commons.cli.BasicParser;
33 import org.apache.commons.cli.CommandLine;
34 import org.apache.commons.cli.HelpFormatter;
35 import org.apache.commons.cli.Options;
36 import org.apache.commons.cli.ParseException;
37
38 import java.io.File;
39 import java.io.IOException;
40 import java.io.PrintWriter;
41 import java.net.MalformedURLException;
42 import java.net.URL;
43 import java.net.URLClassLoader;
44 import java.util.ArrayList;
45
46 /***
47 * Commandline interface for generating a difference report or checking
48 * for binary compatibility between two versions of the same application.
49 */
50
51 public class Clirr
52 {
53
54 public static void main(String[] args)
55 {
56 new Clirr().run(args);
57 }
58
59
60
61 private void run(String[] args)
62 {
63 Options options = defineOptions();
64
65 CommandLine cmdline = parseCommandLine(args, options);
66
67 String oldPath = cmdline.getOptionValue('o');
68 String newPath = cmdline.getOptionValue('n');
69 String oldClassPath = cmdline.getOptionValue("ocp");
70 String newClassPath = cmdline.getOptionValue("ncp");
71 String style = cmdline.getOptionValue('s', "text");
72 String outputFileName = cmdline.getOptionValue('f');
73 String[] includePkgs = cmdline.getOptionValues('i');
74 boolean showAll = cmdline.hasOption('a');
75 boolean showPkg = cmdline.hasOption('p');
76
77 if ((oldPath == null) || (newPath == null))
78 {
79 usage(options);
80 System.exit(-1);
81 }
82
83 Checker checker = new Checker();
84 if (showAll)
85 {
86 checker.getScopeSelector().setScope(Scope.PRIVATE);
87 }
88 else if (showPkg)
89 {
90 checker.getScopeSelector().setScope(Scope.PACKAGE);
91 }
92
93 ClassSelector classSelector;
94 if ((includePkgs != null) && (includePkgs.length > 0))
95 {
96 classSelector = new ClassSelector(ClassSelector.MODE_IF);
97 for (int i = 0; i < includePkgs.length; ++i)
98 {
99 classSelector.addPackageTree(includePkgs[i]);
100 }
101 }
102 else
103 {
104
105 classSelector = new ClassSelector(ClassSelector.MODE_UNLESS);
106 }
107
108 DiffListener diffListener = null;
109 if (style.equals("text"))
110 {
111 try
112 {
113 diffListener = new PlainDiffListener(outputFileName);
114 }
115 catch (IOException ex)
116 {
117 System.err.println("Invalid output file name.");
118 }
119 }
120 else if (style.equals("xml"))
121 {
122 try
123 {
124 diffListener = new XmlDiffListener(outputFileName);
125 }
126 catch (IOException ex)
127 {
128 System.err.println("Invalid output file name.");
129 }
130 }
131 else
132 {
133 System.err.println("Invalid style option. Must be one of 'text', 'xml'.");
134 usage(options);
135 System.exit(-1);
136 }
137
138
139 File[] origJars = pathToFileArray(oldPath);
140 File[] newJars = pathToFileArray(newPath);
141
142 checker.addDiffListener(diffListener);
143
144 try
145 {
146 ClassLoader loader1 = new URLClassLoader(convertFilesToURLs(pathToFileArray(oldClassPath)));
147 ClassLoader loader2 = new URLClassLoader(convertFilesToURLs(pathToFileArray(newClassPath)));
148
149 final JavaType[] origClasses =
150 BcelTypeArrayBuilder.createClassSet(origJars, loader1, classSelector);
151
152 final JavaType[] newClasses =
153 BcelTypeArrayBuilder.createClassSet(newJars, loader2, classSelector);
154
155 checker.reportDiffs(origClasses, newClasses);
156
157 System.exit(0);
158 }
159 catch (CheckerException ex)
160 {
161 System.err.println("Unable to complete checks:" + ex.getMessage());
162 System.exit(1);
163 }
164 catch (MalformedURLException ex)
165 {
166 System.err.println("Unable to create classloader for 3rd party classes:" + ex.getMessage());
167 System.err.println("old classpath: " + oldClassPath);
168 System.err.println("new classpath: " + newClassPath);
169 System.exit(1);
170 }
171 }
172
173 /***
174 * @param args
175 * @param parser
176 * @param options
177 * @return
178 */
179 private CommandLine parseCommandLine(String[] args, Options options)
180 {
181 BasicParser parser = new BasicParser();
182 CommandLine cmdline = null;
183 try
184 {
185 cmdline = parser.parse(options, args);
186 }
187 catch (ParseException ex)
188 {
189 System.err.println("Invalid command line arguments.");
190 usage(options);
191 System.exit(-1);
192 }
193 return cmdline;
194 }
195
196 /***
197 * @return
198 */
199 private Options defineOptions() {
200 Options options = new Options();
201 options.addOption("o", "old-version", true, "jar files of old version");
202 options.addOption("n", "new-version", true, "jar files of new version");
203 options.addOption("ocp", "orig-classpath", true, "3rd party classpath that is referenced by old-version");
204 options.addOption("ncp", "new-classpath", true, "3rd party classpath that is referenced by new-version");
205 options.addOption("s", "style", true, "output style [text|xml]");
206 options.addOption("i", "include-pkg", true,
207 "include only classes from this package and its subpackages");
208 options.addOption("p", "show-pkg-scope", false,
209 "show package scope classes");
210 options.addOption("a", "show-all-scopes", false,
211 "show private and package classes");
212 options.addOption("f", "output-file", true, "output file name");
213 return options;
214 }
215
216 private void usage(Options options)
217 {
218 HelpFormatter hf = new HelpFormatter();
219 PrintWriter out = new PrintWriter(System.err);
220 hf.printHelp(
221 75,
222 "java " + getClass().getName() + " -o path -n path [options]",
223 null, options, null);
224 }
225
226 private File[] pathToFileArray(String path)
227 {
228 if (path == null)
229 {
230 return new File[0];
231 }
232
233 ArrayList files = new ArrayList();
234
235 int pos = 0;
236 while (pos < path.length())
237 {
238 int colonPos = path.indexOf(pos, File.pathSeparatorChar);
239 if (colonPos == -1)
240 {
241 files.add(new File(path.substring(pos)));
242 break;
243 }
244
245 files.add(new File(path.substring(pos, colonPos)));
246 pos = colonPos + 1;
247 }
248
249 return (File[]) files.toArray(new File[files.size()]);
250 }
251
252 private URL[] convertFilesToURLs(File[] files) throws MalformedURLException
253 {
254 URL[] ret = new URL[files.length];
255 for (int i = 0; i < files.length; i++) {
256 ret[i] = files[i].toURL();
257 }
258 return ret;
259 }
260 }