1/* 2 * Copyright (C) 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.google.doclava.apicheck; 18 19import java.io.FileInputStream; 20import java.io.FileNotFoundException; 21import java.io.IOException; 22import java.io.InputStream; 23import java.io.PrintStream; 24import java.net.URL; 25import java.util.ArrayList; 26import java.util.Set; 27import java.util.Stack; 28 29import com.google.doclava.Errors; 30import com.google.doclava.Errors.ErrorMessage; 31import com.google.doclava.Stubs; 32 33public class ApiCheck { 34 // parse out and consume the -whatever command line flags 35 private static ArrayList<String[]> parseFlags(ArrayList<String> allArgs) { 36 ArrayList<String[]> ret = new ArrayList<String[]>(); 37 38 int i; 39 for (i = 0; i < allArgs.size(); i++) { 40 // flags with one value attached 41 String flag = allArgs.get(i); 42 if (flag.equals("-error") || flag.equals("-warning") || flag.equals("-hide")) { 43 String[] arg = new String[2]; 44 arg[0] = flag; 45 arg[1] = allArgs.get(++i); 46 ret.add(arg); 47 } else { 48 // we've consumed all of the -whatever args, so we're done 49 break; 50 } 51 } 52 53 // i now points to the first non-flag arg; strip what came before 54 for (; i > 0; i--) { 55 allArgs.remove(0); 56 } 57 return ret; 58 } 59 60 public static void main(String[] originalArgs) { 61 if (originalArgs.length == 3 && "-convert".equals(originalArgs[0])) { 62 System.exit(convertToApi(originalArgs[1], originalArgs[2])); 63 } else if (originalArgs.length == 3 && "-convert2xml".equals(originalArgs[0])) { 64 System.exit(convertToXml(originalArgs[1], originalArgs[2])); 65 } else { 66 ApiCheck acheck = new ApiCheck(); 67 Report report = acheck.checkApi(originalArgs); 68 69 Errors.printErrors(report.errors()); 70 System.exit(report.code); 71 } 72 } 73 74 /** 75 * Compares two api xml files for consistency. 76 */ 77 public Report checkApi(String[] originalArgs) { 78 // translate to an ArrayList<String> for munging 79 ArrayList<String> args = new ArrayList<String>(originalArgs.length); 80 for (String a : originalArgs) { 81 args.add(a); 82 } 83 84 ArrayList<String[]> flags = ApiCheck.parseFlags(args); 85 for (String[] a : flags) { 86 if (a[0].equals("-error") || a[0].equals("-warning") || a[0].equals("-hide")) { 87 try { 88 int level = -1; 89 if (a[0].equals("-error")) { 90 level = Errors.ERROR; 91 } else if (a[0].equals("-warning")) { 92 level = Errors.WARNING; 93 } else if (a[0].equals("-hide")) { 94 level = Errors.HIDDEN; 95 } 96 Errors.setErrorLevel(Integer.parseInt(a[1]), level); 97 } catch (NumberFormatException e) { 98 System.err.println("Bad argument: " + a[0] + " " + a[1]); 99 return new Report(2, Errors.getErrors()); 100 } 101 } 102 } 103 104 ApiInfo oldApi; 105 ApiInfo newApi; 106 107 try { 108 oldApi = parseApi(args.get(0)); 109 newApi = parseApi(args.get(1)); 110 } catch (ApiParseException e) { 111 e.printStackTrace(); 112 System.err.println("Error parsing API"); 113 return new Report(1, Errors.getErrors()); 114 } 115 116 // only run the consistency check if we haven't had XML parse errors 117 if (!Errors.hadError) { 118 oldApi.isConsistent(newApi); 119 } 120 121 return new Report(Errors.hadError ? 1 : 0, Errors.getErrors()); 122 } 123 124 public static ApiInfo parseApi(String filename) throws ApiParseException { 125 InputStream stream = null; 126 Throwable textParsingError = null; 127 // try it as our format 128 try { 129 stream = new FileInputStream(filename); 130 } catch (IOException e) { 131 throw new ApiParseException("Could not open file for parsing: " + filename, e); 132 } 133 try { 134 return ApiFile.parseApi(filename, stream); 135 } catch (ApiParseException ignored) { 136 textParsingError = ignored; 137 if (false) { 138 return null; 139 } 140 } finally { 141 try { 142 stream.close(); 143 } catch (IOException ignored) {} 144 } 145 // try it as xml 146 try { 147 stream = new FileInputStream(filename); 148 } catch (IOException e) { 149 throw new ApiParseException("Could not open file for parsing: " + filename, e); 150 } 151 try { 152 return XmlApiFile.parseApi(stream); 153 } catch (ApiParseException ignored) { 154 System.out.println("Couldn't parse API file \"" + filename + "\""); 155 System.out.println(" ...as text: " + textParsingError.toString()); 156 System.out.println(" ...as XML: " + ignored.toString()); 157 if (false) { 158 if (textParsingError != null) textParsingError.printStackTrace(); 159 ignored.printStackTrace(); 160 return null; 161 } 162 } finally { 163 try { 164 stream.close(); 165 } catch (IOException ignored) {} 166 } 167 return null; 168 } 169 170 public ApiInfo parseApi(URL url) throws ApiParseException { 171 InputStream stream = null; 172 // try it as our format 173 try { 174 stream = url.openStream(); 175 } catch (IOException e) { 176 throw new ApiParseException("Could not open stream for parsing: " + url, e); 177 } 178 try { 179 return ApiFile.parseApi(url.toString(), stream); 180 } catch (ApiParseException ignored) { 181 } finally { 182 try { 183 stream.close(); 184 } catch (IOException ignored) {} 185 } 186 // try it as xml 187 try { 188 stream = url.openStream(); 189 } catch (IOException e) { 190 throw new ApiParseException("Could not open stream for parsing: " + url, e); 191 } 192 try { 193 return XmlApiFile.parseApi(stream); 194 } finally { 195 try { 196 stream.close(); 197 } catch (IOException ignored) {} 198 } 199 } 200 201 public class Report { 202 private int code; 203 private Set<ErrorMessage> errors; 204 205 private Report(int code, Set<ErrorMessage> errors) { 206 this.code = code; 207 this.errors = errors; 208 } 209 210 public int code() { 211 return code; 212 } 213 214 public Set<ErrorMessage> errors() { 215 return errors; 216 } 217 } 218 219 static int convertToApi(String src, String dst) { 220 ApiInfo api; 221 try { 222 api = parseApi(src); 223 } catch (ApiParseException e) { 224 e.printStackTrace(); 225 System.err.println("Error parsing API: " + src); 226 return 1; 227 } 228 229 PrintStream apiWriter = null; 230 try { 231 apiWriter = new PrintStream(dst); 232 } catch (FileNotFoundException ex) { 233 System.err.println("can't open file: " + dst); 234 } 235 236 Stubs.writeApi(apiWriter, api.getPackages().values()); 237 238 return 0; 239 } 240 241 static int convertToXml(String src, String dst) { 242 ApiInfo api; 243 try { 244 api = parseApi(src); 245 } catch (ApiParseException e) { 246 e.printStackTrace(); 247 System.err.println("Error parsing API: " + src); 248 return 1; 249 } 250 251 PrintStream apiWriter = null; 252 try { 253 apiWriter = new PrintStream(dst); 254 } catch (FileNotFoundException ex) { 255 System.err.println("can't open file: " + dst); 256 } 257 258 Stubs.writeXml(apiWriter, api.getPackages().values()); 259 260 return 0; 261 } 262 263} 264