1 19 20 package org.netbeans.modules.autoupdate; 21 22 import java.io.BufferedInputStream ; 23 import java.io.File ; 24 import java.io.IOException ; 25 import java.net.URL ; 26 import java.util.ArrayList ; 27 import java.util.Collection ; 28 import java.util.Date ; 29 import java.text.SimpleDateFormat ; 30 import java.text.ParsePosition ; 31 import java.util.HashMap ; 32 import java.util.Iterator ; 33 import java.util.Map ; 34 import java.util.logging.Level ; 35 import java.util.logging.Logger ; 36 import java.util.zip.GZIPInputStream ; 37 import javax.swing.SwingUtilities ; 38 import org.openide.util.Exceptions; 39 import org.openide.util.RequestProcessor; 40 41 import org.w3c.dom.*; 42 import org.xml.sax.*; 43 import org.xml.sax.SAXException ; 44 45 46 49 class XMLUpdates extends Updates { 50 51 52 private static final String TAG_MODULE_UPDATES = "module_updates"; private static final String TAG_MODULE = "module"; private static final String TAG_MODULE_GROUP = "module_group"; private static final String TAG_NOTIFICATION = "notification"; private static final String ATTR_NOTIFICATION_URL = "url"; private static final String TAG_ERROR = "error"; private static final String TAG_AUTH_ERROR = "auth_error"; private static final String TAG_OTHER_ERROR = "other_error"; private static final String ATTR_MESSAGE_ERROR = "message"; 62 private static final Logger err = Logger.getLogger("org.netbeans.modules.autoupdate.XMLUpdates"); 64 65 private ArrayList modules; 66 private HashMap checkOnceMore; 67 68 69 private ModuleGroup rootGroup; 70 71 private int pError = NO_ERROR; 72 73 private String errorMess = null; 74 75 76 private Date timeStamp = null; 77 78 79 private String notificationText = null; 80 81 82 private URL notificationURL = null; 83 84 85 private URL xmlURL; 86 87 88 private File [] files; 89 90 91 private static ArrayList groupFiles = new ArrayList (); 92 93 private static boolean timerSet = false; 94 95 private static boolean groupStarted = false; 96 private static int oldGroupSize = 0; 97 98 99 101 private InputSource xmlInputSource = null; 102 103 private AutoupdateType currentAT = null; 104 105 private static String GZIP_EXTENSION = ".gz"; 107 109 XMLUpdates(URL xmlURL) { 110 this.xmlURL = xmlURL; 111 } 112 113 116 XMLUpdates(File [] files) { 117 this.files = files; 118 } 119 120 124 static void startGroupUpdates( File file ) { 125 if ( groupStarted ) 126 new XMLUpdates( new File []{ file } ).go(); 127 else { 128 groupFiles.add( file ); 129 setTimer(); 130 } 131 } 132 133 private static void setTimer() { 134 if ( ! timerSet ) { 135 timerSet = true; 136 oldGroupSize = groupFiles.size(); 137 org.openide.util.RequestProcessor.getDefault().post( new Runnable () { 138 public void run() { 139 if (! SwingUtilities.isEventDispatchThread ()) { 140 SwingUtilities.invokeLater (this); 141 return ; 142 } 143 if ( oldGroupSize < groupFiles.size() ) { 144 oldGroupSize = groupFiles.size(); 145 org.openide.util.RequestProcessor.getDefault().post( 146 this, 147 500 148 ); 149 } 150 else { 151 timerSet = false; 152 groupStarted = true; 153 File [] arrFiles = new File [ groupFiles.size() ]; 154 Iterator it = groupFiles.iterator(); 155 for ( int j = 0; it.hasNext(); j++ ) { 156 File fn = (File )it.next(); 157 if ( fn != null ) { 158 arrFiles[j] = fn; 159 } 160 } 161 groupFiles.clear(); 162 groupStarted = false; 163 new XMLUpdates( arrFiles ).go(); 164 } 165 } 166 }, 167 500); 168 } 169 } 170 171 private void go() { 172 HashMap allUpdates = new HashMap (); 173 allUpdates.put(this, this); 174 Wizard wiz = Wizard.go( allUpdates, 1 ); 175 if ( wiz != null ) { 176 checkDownloadedModules(); 177 wiz.refreshUpdatePanel(); 178 } 179 } 180 181 183 public void checkUpdates( final Wizard.Validator validator ) { 184 checkUpdates(validator, ""); } 186 187 189 public void checkUpdates( final Wizard.Validator validator, String ucname ) { 190 checkUpdates( validator, AutoupdateType.find( ucname ) ); 191 } 192 193 public void checkUpdates( final Wizard.Validator validator, final AutoupdateType at ) { 194 checkUpdates (validator, at, false); 195 } 196 197 199 public void checkUpdates (final Wizard.Validator validator, final AutoupdateType at, boolean hidden) { 200 201 currentAT = at; 202 pError = NO_ERROR; 203 checkCanceled = false; 204 205 final java.awt.Dialog connDialog = ConnectingDialog.getDialog( at != null ? at.getName() : null ); 206 Runnable runConnect = new Runnable () { 207 208 public void run() { 209 try { 210 Document document = parseDocument(); 211 212 if (pError == NO_ERROR && document != null) { 213 buildStructures(document); 214 if (!checkCanceled) { 215 Settings.getShared().setLastCheck(new Date ()); 216 } 217 } else { 218 if (pError == NO_ERROR) { 219 assert document != null || checkCanceled : "Document is not null or connecting is canceled if no error caught."; 220 } 221 } 222 validator.setValid(true); 223 int countOfAvailableModules = 0; 224 225 if (getModules() != null) 226 countOfAvailableModules = getModules().size(); 227 if (countOfAvailableModules == 0 && pError == NO_ERROR) { 228 errorMess = at.getName(); 230 pError = NO_AVAILABLE_MODULES; 231 } 232 } 233 catch (Exception x) { 234 pError = NO_NETWORK; 236 err.log(Level.INFO, null, x); 237 } 238 finally { 239 if (connDialog != null) { 240 ConnectingDialog.closeDialog(connDialog); 241 } 242 } 243 } 244 }; 245 RequestProcessor.Task task = RequestProcessor.getDefault ().post (runConnect); 246 if (!hidden) { 247 connDialog.setVisible (true); 248 if (ConnectingDialog.isCanceled()) { 249 cancelCheck(); 250 } 251 } else { 252 task.waitFinished (); 253 } 254 } 255 256 public void cancelCheck() { 257 checkCanceled = true; 258 if ( xmlInputSource != null) { 259 try { 260 if (xmlInputSource.getByteStream() != null) 261 xmlInputSource.getByteStream().close(); 262 } catch (java.io.IOException e) { 263 } 264 } 265 } 266 267 268 271 public ModuleGroup getRootGroup() { 272 return rootGroup; 273 } 274 275 277 public Collection getModules() { 278 return modules; 279 } 280 281 282 public boolean isError() { 283 return ( pError > NO_ERROR ); 284 } 285 286 287 public int getError() { 288 return pError; 289 } 290 291 292 public String getErrorMessage() { 293 return errorMess; 294 } 295 296 297 public Date getTimeStamp() { 298 return timeStamp; 299 } 300 301 302 public String getNotificationText() { 303 return notificationText; 304 } 305 306 307 public URL getNotificationURL() { 308 return notificationURL; 309 } 310 311 314 void checkDownloadedModules() { 315 modules = new ArrayList (); 316 rootGroup = new ModuleGroup(); 317 checkOnceMore = new HashMap (); 318 319 for ( int i = 0; i < files.length; i++ ) { 320 ModuleUpdate update = ModuleUpdate.getModuleUpdate( files[i] ); 321 322 if ( update != null ) { 323 324 if ( update.isUpdateAvailable() ) { 325 modules.add( update ); 326 rootGroup.addItem( update ); 327 } 328 else if ( update instanceof L10NUpdate ) { 329 checkOnceMore.put( update, rootGroup ); 330 } 331 } 332 } 333 checkAvailablesOnceMore(); 334 } 335 336 void checkAvailablesOnceMore() { 337 Iterator it = checkOnceMore.entrySet().iterator(); 338 while ( it.hasNext() ) { 339 Map.Entry entry = (Map.Entry ) it.next(); 340 L10NUpdate update = (L10NUpdate) entry.getKey(); 341 if ( update.isRemoteModuleAvailable( modules ) ) { 342 modules.add( update ); 343 ( (ModuleGroup) entry.getValue() ).addItem( update ); 344 } 345 } 346 } 347 348 351 private Document parseDocument() { 352 Document document = null; 353 354 if ( checkCanceled ) 355 return null; 356 357 String showStr = System.getProperty("autoupdate.show.url"); if ( showStr != null && Boolean.valueOf( showStr ).booleanValue() ) 359 System.out.println("URL: " + xmlURL ); 361 try { 362 document = parseDocumentImpl (); 363 } catch ( SAXException e ) { 364 pError = PARSE_ERROR; 365 showParseError(e); 366 } catch ( IOException e ) { 367 pError = NO_NETWORK; 368 369 if (!checkCanceled) { 370 showParseError (e); 371 } 372 373 } 374 375 return document; 376 } 377 378 private Document parseDocumentImpl() throws SAXException , IOException { 379 Document document = null; 380 java.net.HttpURLConnection.setFollowRedirects( true ); 381 382 err.log(Level.FINE, "Processing URL: " + xmlURL); 384 URL urlToGZip = null; 385 386 try { 387 388 String gzipFile = xmlURL.getPath () + GZIP_EXTENSION; 389 String query = xmlURL.getQuery (); 390 if (query != null && query.trim ().length () > 0) { 391 gzipFile = gzipFile + '?' + query; } 393 urlToGZip = new URL (xmlURL.getProtocol (), xmlURL.getHost (), xmlURL.getPort (), gzipFile); 394 395 xmlInputSource = new InputSource(new BufferedInputStream (new GZIPInputStream (urlToGZip.openStream()))); 396 err.log(Level.FINE, "Successfully read URL " + urlToGZip); 398 } catch (IOException ioe) { 399 err.log(Level.FINE, 400 "Reading GZIP URL " + urlToGZip + " failed (" + ioe + 401 "). Try read XML directly " + xmlURL); xmlInputSource = new InputSource( xmlURL.toExternalForm() ); 403 err.log(Level.FINE, "Successfully read URL " + xmlURL); } 405 406 if ( checkCanceled ) { 407 err.log(Level.FINE, "Connection canceled on user\'s demand."); return null; 409 } 410 411 document = org.netbeans.updater.XMLUtil.parse( xmlInputSource, false, false, new ErrorCatcher(), org.netbeans.updater.XMLUtil.createAUResolver () ); 412 413 assert document != null : "Parser in XMLUtil return not null document for input " + xmlInputSource; 414 415 return document; 416 } 417 418 private void showParseError(Throwable t) { 419 Exceptions.attachMessage(t, "URL: " + xmlURL); err.log(Level.INFO, null, t); 421 } 422 423 425 private void buildStructures (Document document) { 426 427 if ( checkCanceled ) 428 return; 429 430 if ( document.getDocumentElement() == null ) { 431 } 433 else { 434 modules = new ArrayList (); 435 rootGroup = new ModuleGroup(); 436 checkOnceMore = new HashMap (); 437 438 if ( detectErrorType (document) ) 440 return; 441 442 NodeList allModules = document.getElementsByTagName( TAG_MODULE ); 443 444 processElement( document, document.getDocumentElement(), rootGroup ); 445 446 Node attr = document.getDocumentElement().getAttributes().getNamedItem( "timestamp" ); if ( attr != null ) { 449 String timeString = attr.getNodeValue() + "/GMT"; SimpleDateFormat formatter = new SimpleDateFormat ( "ss/mm/HH/dd/MM/yyyy/zzz" ); ParsePosition pos = new ParsePosition (0); 452 timeStamp = formatter.parse(timeString, pos); 453 } 454 checkAvailablesOnceMore(); 455 } 456 } 457 458 private boolean detectErrorType (Document document) { 459 NodeList errors = document.getElementsByTagName(TAG_ERROR); 460 461 if ( errors.getLength() > 0 ) { 463 NodeList auth_errors = document.getElementsByTagName(TAG_AUTH_ERROR); 464 if ( auth_errors.getLength() > 0 ) { 465 pError = AUTH_ERROR; 466 assert false : "Unexcepted " + TAG_AUTH_ERROR + " in document " + document; 467 } else { 468 pError = PARSE_ERROR; 469 NodeList other_errors = document.getElementsByTagName(TAG_OTHER_ERROR); 470 if ( other_errors.getLength() > 0 ) 471 errorMess = other_errors.item( 0 ).getAttributes(). 472 getNamedItem(ATTR_MESSAGE_ERROR).getNodeValue(); 473 } 474 } 475 return ( pError > NO_ERROR ); 476 } 477 478 482 private void processElement( Document document, Element element, ModuleGroup moduleGroup ) { 483 484 NodeList nodeList = element.getChildNodes(); 485 for( int i = 0; i < nodeList.getLength(); i++ ) { 486 487 if ( checkCanceled ) 488 return; 489 490 Node node = nodeList.item( i ); 491 492 if ( node.getNodeType() != Node.ELEMENT_NODE ) { 493 continue; 494 } 495 496 if ( ((Element)node).getTagName().equals( TAG_MODULE ) ) { 497 ModuleUpdate update = ModuleUpdate.getModuleUpdate( xmlURL, node, document.getDocumentElement(), currentAT ); 498 499 if ( update != null ) { 500 if ( update.isUpdateAvailable() ) { 501 modules.add( update ); 502 moduleGroup.addItem( update ); 503 } 504 else if ( update instanceof L10NUpdate ) { 505 checkOnceMore.put( update, moduleGroup ); 506 } 507 } 508 } 509 else if ( ((Element)node).getTagName().equals( TAG_MODULE_GROUP ) ) { 510 ModuleGroup group = new ModuleGroup( node ); 511 moduleGroup.addItem( group ); 512 processElement( document, (Element)node, group ); 513 } 514 else if ( ((Element)node).getTagName().equals( TAG_NOTIFICATION ) ) { 515 readNotification( node ); 516 } 517 } 518 } 519 520 521 private void readNotification( Node node ) { 522 523 if ( getNotificationText() != null ) { 524 return; 525 } 526 527 try { 528 Node attr = node.getAttributes().getNamedItem( ATTR_NOTIFICATION_URL ); 529 String textURL = attr == null ? null : attr.getNodeValue(); 530 531 if ( textURL != null ) 532 notificationURL = new URL ( textURL ); 533 } 534 catch ( java.net.MalformedURLException e ) { 535 } 538 539 StringBuffer sb = new StringBuffer (); 540 541 NodeList innerList = node.getChildNodes(); 542 543 for( int i = 0; i < innerList.getLength(); i++ ) { 544 if ( innerList.item( i ).getNodeType() == Node.TEXT_NODE ) { 545 sb.append( innerList.item( i ).getNodeValue() ); 546 } 547 } 548 549 if ( sb.length() > 0 ) 550 notificationText = sb.toString(); 551 else 552 notificationText = null; 553 554 } 555 556 557 class ErrorCatcher implements org.xml.sax.ErrorHandler { 558 559 public void error (SAXParseException e) throws SAXParseException { 560 throw e; 562 } 563 564 public void warning (SAXParseException e) throws SAXParseException { 565 showParseError(e); 566 } 568 569 public void fatalError (SAXParseException e) throws SAXParseException { 570 throw e; 571 } 572 573 } 575 } 576 | Popular Tags |