1 17 package org.apache.ws.jaxme.js.util; 18 19 import java.io.BufferedInputStream ; 20 import java.io.File ; 21 import java.io.FileInputStream ; 22 import java.io.IOException ; 23 import java.io.InputStream ; 24 import java.io.InputStreamReader ; 25 import java.net.MalformedURLException ; 26 import java.net.URL ; 27 import java.util.ArrayList ; 28 import java.util.Enumeration ; 29 import java.util.HashMap ; 30 import java.util.Iterator ; 31 import java.util.List ; 32 import java.util.Map ; 33 34 import javax.swing.text.MutableAttributeSet ; 35 import javax.swing.text.html.HTML ; 36 import javax.swing.text.html.HTMLEditorKit ; 37 import javax.swing.text.html.parser.ParserDelegator ; 38 39 import org.apache.ws.jaxme.logging.Logger; 40 import org.apache.ws.jaxme.logging.LoggerAccess; 41 42 43 48 public class LinkChecker { 49 Logger logger = LoggerAccess.getLogger(LinkChecker.class); 50 private Map urls = new HashMap (); 51 private Map checkedUrls = new HashMap (); 52 private int severity = Event.ERROR; 53 private String proxyHost; 54 private String proxyPort; 55 private boolean haveErrors; 56 57 private class Event { 58 public static final int SUCCESS = 0; 59 public static final int WARNING = 1; 60 public static final int ERROR = 2; 61 int mySeverity; 62 private URL url; 63 private int pos = -1; 64 private String msg; 65 private Event(int pSeverity, URL pURL, int pPos, String pMsg) { 66 mySeverity = pSeverity; 67 url = pURL; 68 pos = pPos; 69 msg = pMsg; 70 } 71 public String getMsg() { 72 return msg; 73 } 74 public String toString() { 75 StringBuffer result = new StringBuffer (); 76 if (mySeverity == SUCCESS) { 77 result.append("SUCCESS"); 78 } else if (mySeverity == WARNING) { 79 result.append("WARNING"); 80 } else { 81 result.append(" ERROR"); 82 } 83 result.append(" at ").append(url); 84 if (pos != -1) { 85 result.append(", char ").append(pos); 86 } 87 result.append(": ").append(getMsg()); 88 return result.toString(); 89 } 90 } 91 92 private class RefEvent extends Event { 93 private URL referencedURL; 94 private RefEvent(int pSeverity, URL pURL, URL pRefURL, int pPos, String pMsg) { 95 super(pSeverity, pRefURL, pPos, pMsg); 96 referencedURL = pURL; 97 } 98 public String getMsg() { 99 return "Failed to reference " + referencedURL + ": " + super.getMsg(); 100 } 101 } 102 103 private class CheckedURL { 104 URL url; 105 URL referencingURL; 106 int referencingPos; 107 InputStream stream; 108 boolean checkExistsOnly; 109 boolean isExtern; 110 private List anchors; 111 private List refAnchors; 112 113 private class AnchorReference { 114 String name; 115 URL ref; 116 int pos; 117 } 118 119 private CheckedURL(URL pURL, URL pRefURL, int pPos) { 120 referencingURL = pRefURL; 121 referencingPos = pPos; 122 String ref = pURL.getRef(); 123 String anchor = null; 124 if (ref != null) { 125 String s = pURL.toString(); 126 try { 127 if (s.endsWith("#" + ref)) { 128 pURL = new URL (s.substring(0, s.length()-ref.length()-1)); 129 anchor = ref; 130 } else { 131 throw new MalformedURLException (); 132 } 133 } catch (MalformedURLException e) { 134 handleRefError(pURL, pRefURL, pPos, "Unable to parse URL: " + pURL); 135 } 136 } 137 url = pURL; 138 if (anchor != null && pRefURL != null) { 139 addAnchorRef(anchor, pRefURL, pPos); 140 } 141 } 142 143 public void addAnchor(String pName) { 144 if (anchors == null) { 145 anchors = new ArrayList (); 146 } 147 anchors.add(pName); 148 } 149 150 public void addAnchorRef(String pAnchor, URL pRefURL, int pPos) { 151 AnchorReference anchorReference = new AnchorReference(); 152 anchorReference.name = pAnchor; 153 anchorReference.ref = pRefURL; 154 anchorReference.pos = pPos; 155 if (refAnchors == null) { 156 refAnchors = new ArrayList (); 157 } 158 refAnchors.add(anchorReference); 159 } 160 161 public void validate() { 162 if (refAnchors != null) { 163 for (Iterator iter = refAnchors.iterator(); iter.hasNext(); ) { 164 AnchorReference anchorReference = (AnchorReference) iter.next(); 165 if (anchors == null || !anchors.contains(anchorReference.name)) { 166 handleRefError(url, anchorReference.ref, anchorReference.pos, 167 "Invalid anchor: " + anchorReference.name); 168 } 169 } 170 refAnchors.clear(); 171 } 172 } 173 } 174 175 protected void addEvent(Event pEvent) { 176 final String mName = "addEvent"; 177 logger.entering(mName, pEvent.toString()); 178 if (pEvent.mySeverity >= Event.ERROR) { 179 haveErrors = true; 180 } 181 if (pEvent.mySeverity >= getSeverity()) { 182 System.err.println(pEvent.toString()); 183 } 184 logger.exiting(mName); 185 } 186 187 protected void handleError(URL pURL, int pPos, String pMsg) { 188 addEvent(new Event(Event.ERROR, pURL, pPos, pMsg)); 189 } 190 191 protected void handleRefError(URL pURL, URL pRefURL, int pPos, String pMsg) { 192 if (pRefURL == null) { 193 handleError(pURL, pPos, pMsg); 194 } 195 addEvent(new RefEvent(Event.ERROR, pURL, pRefURL, pPos, pMsg)); 196 } 197 198 protected void handleWarning(URL pURL, int pPos, String pMsg) { 199 addEvent(new Event(Event.WARNING, pURL, pPos, pMsg)); 200 } 201 202 private class URLChecker extends HTMLEditorKit.ParserCallback { 203 CheckedURL url; 204 private URLChecker(CheckedURL pURL) { 205 url = pURL; 206 } 207 208 protected void addLink(String pTagName, String pAttributeName, 209 String pAttributeValue, int pPos, boolean pCheckExistsOnly) { 210 final String mName = "URLChecker.addLink"; 211 logger.finest(mName, "->", new Object []{pTagName, pAttributeName, pAttributeValue, 212 Integer.toString(pPos), pCheckExistsOnly ? Boolean.TRUE : Boolean.FALSE}); 213 logger.finest(mName, "My URL: " + this.url.url); 214 URL myUrl = null; 216 boolean isAbsolute = false; 217 try { 218 myUrl = new URL (pAttributeValue); 219 isAbsolute = true; 220 } catch (MalformedURLException e) { 221 } 222 223 if (!isAbsolute) { 224 try { 225 myUrl = new URL (this.url.url, pAttributeValue); 226 } catch (MalformedURLException e) { 227 228 LinkChecker.this.handleError(this.url.url, pPos, 229 "Failed to parse URL of attribute " + pAttributeName + " in tag " + pTagName); 230 return; 231 } 232 } 233 234 if ("mailto".equals(myUrl.getProtocol())) { 235 return; 236 } 237 238 CheckedURL checkedURL = new CheckedURL(myUrl, this.url.url, pPos); 239 checkedURL.checkExistsOnly = pCheckExistsOnly; 240 checkedURL.isExtern = isAbsolute; 241 addURL(checkedURL); 242 logger.finest(mName, "<-"); 243 } 244 245 protected void handleTag(HTML.Tag t, MutableAttributeSet a, int pPos) { 246 final String mName = "URLChecker.handleTag"; 247 logger.finest(mName, "->", new Object []{t, a, Integer.toString(pPos)}); 248 String tagName = t.toString().toLowerCase(); 249 for (Enumeration en = a.getAttributeNames(); en.hasMoreElements(); ) { 250 Object attributeNameObj = en.nextElement(); 251 String attributeName = attributeNameObj.toString().toLowerCase(); 252 Object o = a.getAttribute(attributeNameObj); 253 if (o instanceof String ) { 254 String attributeValue = (String ) o; 255 if (tagName.equals("a")) { 256 if (attributeName.equals("href")) { 257 addLink(tagName, attributeName, attributeValue, pPos, false); 258 } else if (attributeName.equals("name")) { 259 url.addAnchor(attributeValue); 260 } 261 } else if (tagName.equals("img")) { 262 if (attributeName.equals("src")) { 263 addLink(tagName, attributeName, attributeValue, pPos, true); 264 } 265 } 266 } else if (o instanceof Boolean ) { 267 } else { 269 handleWarning(url.url, pPos, "Unknown attribute type: " + (o == null ? "null" : o.getClass().getName())); 270 } 271 } 272 logger.finest(mName, "<-"); 273 } 274 public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pPos) { 275 super.handleSimpleTag(t, a, pPos); 276 handleTag(t, a, pPos); 277 } 278 public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pPos) { 279 super.handleStartTag(t, a, pPos); 280 handleTag(t, a, pPos); 281 } 282 public void handleError(String pErrorMsg, int pPos) { 283 super.handleError(pErrorMsg, pPos); 284 handleWarning(url.url, pPos, "Error reported by parser: " + pErrorMsg); 285 } 286 } 287 288 public Logger getLogger() { 289 return logger; 290 } 291 292 public void setLogger(Logger pLogger) { 293 logger = pLogger; 294 } 295 296 public void setSeverity(String pSeverity) { 297 if (pSeverity.equalsIgnoreCase("success")) { 298 severity = Event.SUCCESS; 299 } else if (pSeverity.equalsIgnoreCase("warning")) { 300 severity = Event.WARNING; 301 } else if (pSeverity.equalsIgnoreCase("error")) { 302 severity = Event.ERROR; 303 } else { 304 throw new IllegalArgumentException ("Invalid severity, neither of success|warning|error: " + pSeverity); 305 } 306 } 307 308 public int getSeverity() { 309 return severity; 310 } 311 312 public void setProxy(String pProxy) { 313 if (pProxy == null && "".equals(pProxy)) { 314 setProxyHost(null); 315 setProxyPort(null); 316 } else { 317 int offset = pProxy.indexOf(':'); 318 if (offset == -1) { 319 setProxyHost(pProxy); 320 setProxyPort(null); 321 } else { 322 setProxyHost(pProxy.substring(0, offset)); 323 setProxyPort(pProxy.substring(offset+1)); 324 } 325 } 326 } 327 328 public void setProxyHost(String pHost) { 329 if (pHost != null && "".equals(pHost)) { 330 pHost = null; 331 } 332 proxyHost = pHost; 333 } 334 335 public String getProxyHost() { 336 return proxyHost; 337 } 338 339 public void setProxyPort(String pPort) { 340 if (pPort != null && "".equals(pPort)) { 341 pPort = null; 342 } 343 proxyPort = pPort; 344 } 345 346 public String getProxyPort() { 347 return proxyPort; 348 } 349 350 public void addURL(URL pURL, InputStream pStream) { 351 CheckedURL url = new CheckedURL(pURL, null, -1); 352 url.stream = pStream; 353 addURL(url); 354 } 355 356 public void addURL(URL pURL) { 357 addURL(new CheckedURL(pURL, null, -1)); 358 } 359 360 public void addURL(CheckedURL pURL) { 361 final String mName = "addURL(URL)"; 362 logger.finest(mName, "->", new Object []{pURL.url, pURL.referencingURL, Integer.toString(pURL.referencingPos)}); 363 if (urls.containsKey(pURL.url) || checkedUrls.containsKey(pURL.url)) { 364 logger.exiting(mName, "Already registered"); 365 return; 366 } 367 urls.put(pURL.url, pURL); 368 logger.finest(mName, "<-", "New URL"); 369 } 370 371 public void parse(CheckedURL pURL) throws IOException { 372 final String mName = "parse(CheckedURL)"; 373 logger.finest(mName, "->", pURL.url); 374 logger.fine(mName, "Open", pURL.url); 375 InputStream stream = pURL.stream; 376 if (stream == null) { 377 try { 378 stream = pURL.url.openStream(); 379 } catch (IOException e) { 380 handleRefError(pURL.url, pURL.referencingURL, pURL.referencingPos, 381 "Failed to open URL: " + e.getMessage()); 382 return; 383 } 384 } 385 386 if (pURL.checkExistsOnly || pURL.isExtern) { 387 stream.close(); 388 } else { 389 BufferedInputStream bStream = new BufferedInputStream (stream, 4096); 390 ParserDelegator parser = new ParserDelegator (); 391 HTMLEditorKit.ParserCallback callback = new URLChecker(pURL); 392 parser.parse(new InputStreamReader (bStream), callback, false); 393 bStream.close(); 394 } 395 logger.finest(mName, "<-"); 396 } 397 398 public void parse() { 399 final String mName = "parse"; 400 logger.finest(mName, "->"); 401 haveErrors = false; 402 403 boolean isProxySetSet = System.getProperties().contains("http.proxySet"); 404 String proxySet = System.getProperty("http.proxySet"); 405 boolean isProxyHostSet = System.getProperties().contains("http.proxyHost"); 406 String myProxyHost = System.getProperty("http.proxyHost"); 407 boolean isProxyPortSet = System.getProperties().contains("http.proxyPort"); 408 String myProxyPort = System.getProperty("http.proxyPort"); 409 410 String host = getProxyHost(); 411 if (host != null) { 412 System.setProperty("http.proxySet", "true"); 413 System.setProperty("http.proxyHost", host); 414 String port = getProxyPort(); 415 if (port != null) { 416 System.setProperty("http.proxyPort", port); 417 } 418 } 419 420 try { 421 while (!urls.isEmpty()) { 422 Iterator iter = urls.values().iterator(); 423 CheckedURL checkedURL = (CheckedURL) iter.next(); 424 try { 425 parse(checkedURL); 426 } catch (IOException e) { 427 } finally { 428 urls.remove(checkedURL.url); 429 checkedUrls.put(checkedURL.url, checkedURL); 430 } 431 } 432 } finally { 433 if (host != null) { 434 if (isProxySetSet) { 435 System.setProperty("http.proxySet", proxySet); 436 } else { 437 System.getProperties().remove("http.proxySet"); 438 } 439 if (isProxyHostSet) { 440 System.setProperty("http.proxyHost", myProxyHost); 441 } else { 442 System.getProperties().remove("http.proxyHost"); 443 } 444 if (isProxyPortSet) { 445 System.setProperty("http.proxyPort", myProxyPort); 446 } else { 447 System.getProperties().remove("http.proxyPort"); 448 } 449 } 450 } 451 452 for (Iterator iter = checkedUrls.values().iterator(); iter.hasNext(); ) { 453 CheckedURL checkedURL = (CheckedURL) iter.next(); 454 checkedURL.validate(); 455 } 456 457 if (!haveErrors) { 458 System.out.println("No errors found."); 459 } 460 461 logger.finest(mName, "<-"); 462 } 463 464 public static void main(String [] args) { 465 LinkChecker checker = new LinkChecker(); 466 467 for (int i = 0; i < args.length; i++) { 468 URL url; 469 InputStream stream; 470 try { 471 url = new URL (args[i]); 472 stream = url.openStream(); 473 } catch (IOException e) { 474 try { 475 File f = new File (args[i]); 476 stream = new FileInputStream (f); 477 url = f.toURL(); 478 } catch (IOException f) { 479 System.err.println("Failed to open URL: " + args[i]); 480 continue; 481 } 482 } 483 checker.addURL(url, stream); 484 checker.parse(); 485 } 486 } 487 } 488 | Popular Tags |