1 19 package org.netbeans.modules.uihandler; 20 21 import java.awt.Dialog ; 22 import java.awt.Dimension ; 23 import java.awt.event.ActionEvent ; 24 import java.awt.event.ActionListener ; 25 import java.io.BufferedInputStream ; 26 import java.io.BufferedOutputStream ; 27 import java.io.DataOutputStream ; 28 import java.io.File ; 29 import java.io.FileInputStream ; 30 import java.io.FileOutputStream ; 31 import java.io.FileWriter ; 32 import java.io.IOException ; 33 import java.io.InputStream ; 34 import java.io.OutputStream ; 35 import java.io.PrintStream ; 36 import java.net.MalformedURLException ; 37 import java.net.NoRouteToHostException ; 38 import java.net.URL ; 39 import java.net.URLConnection ; 40 import java.net.UnknownHostException ; 41 import java.text.MessageFormat ; 42 import java.util.ArrayList ; 43 import java.util.Collections ; 44 import java.util.Date ; 45 import java.util.LinkedList ; 46 import java.util.List ; 47 import java.util.ListIterator ; 48 import java.util.Map ; 49 import java.util.Queue ; 50 import java.util.concurrent.atomic.AtomicReference ; 51 import java.util.logging.Level ; 52 import java.util.logging.LogRecord ; 53 import java.util.logging.Logger ; 54 import java.util.prefs.Preferences ; 55 import java.util.regex.Matcher ; 56 import java.util.regex.Pattern ; 57 import java.util.zip.GZIPInputStream ; 58 import java.util.zip.GZIPOutputStream ; 59 import javax.swing.AbstractButton ; 60 import javax.swing.JButton ; 61 import javax.xml.parsers.DocumentBuilder ; 62 import javax.xml.parsers.DocumentBuilderFactory ; 63 import javax.xml.parsers.ParserConfigurationException ; 64 import org.netbeans.lib.uihandler.LogRecords; 65 import org.netbeans.modules.exceptions.ReportPanel; 66 import org.netbeans.modules.exceptions.ExceptionsSettings; 67 import org.netbeans.modules.uihandler.api.Activated; 68 import org.netbeans.modules.uihandler.api.Deactivated; 69 import org.openide.DialogDescriptor; 70 import org.openide.DialogDisplayer; 71 import org.openide.awt.HtmlBrowser; 72 import org.openide.awt.Mnemonics; 73 import org.openide.filesystems.FileUtil; 74 import org.openide.modules.ModuleInstall; 75 import org.openide.nodes.AbstractNode; 76 import org.openide.nodes.Children; 77 import org.openide.nodes.Node; 78 import org.openide.util.Lookup; 79 import org.openide.util.Mutex; 80 import org.openide.util.NbBundle; 81 import org.openide.util.NbPreferences; 82 import org.openide.util.RequestProcessor; 83 import org.w3c.dom.Document ; 84 import org.w3c.dom.NodeList ; 85 import org.xml.sax.SAXException ; 86 87 90 public class Installer extends ModuleInstall { 91 94 static final String USER_CONFIGURATION = "UI_USER_CONFIGURATION"; private static Queue <LogRecord > logs = new LinkedList <LogRecord >(); 96 private static UIHandler ui = new UIHandler(logs, false); 97 private static UIHandler handler = new UIHandler(logs, true); 98 static final Logger LOG = Logger.getLogger(Installer.class.getName()); 99 static final RequestProcessor RP = new RequestProcessor("UI Gestures"); 101 @Override 102 public void restored() { 103 File logFile = logFile(); 104 if (logFile != null && logFile.canRead()) { 105 InputStream is = null; 106 try { 107 is = new GZIPInputStream (new BufferedInputStream (new FileInputStream (logFile))); 108 LogRecords.scan(is, ui); 109 } catch (IOException ex) { 110 LOG.log(Level.INFO, "Cannot read " + logFile, ex); 111 } finally { 112 if (is != null) { 113 try { 114 is.close(); 115 } catch (Exception ex) { 116 LOG.log(Level.INFO, "Cannot read " + logFile, ex); 117 } 118 } 119 } 120 } 121 122 Logger log = Logger.getLogger("org.netbeans.ui"); log.setUseParentHandlers(false); 124 log.setLevel(Level.FINEST); 125 log.addHandler(ui); 126 Logger all = Logger.getLogger(""); 127 all.addHandler(handler); 128 129 for (Activated a : Lookup.getDefault().lookupAll(Activated.class)) { 130 a.activated(log); 131 } 132 142 } 143 144 @Override 145 public void uninstalled() { 146 close(); 147 } 148 149 @Override 150 public void close() { 151 Logger log = Logger.getLogger("org.netbeans.ui"); log.removeHandler(ui); 153 Logger all = Logger.getLogger(""); all.removeHandler(handler); 155 156 File logFile = logFile(); 157 if (logFile != null) { 158 try { 159 logFile.getParentFile().mkdirs(); 160 OutputStream os = new GZIPOutputStream (new BufferedOutputStream (new FileOutputStream (logFile))); 162 for (LogRecord r : getLogs()) { 163 LogRecords.write(os, r); 164 } 165 os.close(); 166 } catch (IOException ex) { 167 LOG.log(Level.INFO, "Cannot write " + logFile, ex); 168 } 169 } 170 } 171 172 public static int getLogsSize() { 173 return logs.size(); 174 } 175 176 public static List <LogRecord > getLogs() { 177 synchronized (UIHandler.class) { 178 return new ArrayList <LogRecord >(logs); 179 } 180 } 181 182 private static File logFile() { 183 String ud = System.getProperty("netbeans.user"); if (ud == null || "memory".equals(ud)) { return null; 186 } 187 188 File userDir = new File (ud); File logFile = new File (new File (new File (userDir, "var"), "log"), "uigestures.gz"); 190 return logFile; 191 } 192 193 static void clearLogs() { 194 synchronized (UIHandler.class) { 195 logs.clear(); 196 } 197 UIHandler.SUPPORT.firePropertyChange(null, null, null); 198 } 199 200 public boolean closing() { 201 if (getLogsSize() == 0) { 202 return true; 203 } 204 205 return displaySummary("EXIT_URL", false); } 207 208 private static AtomicReference <String > DISPLAYING = new AtomicReference <String >(); 209 static boolean displaySummary(String msg, boolean explicit) { 210 if (!DISPLAYING.compareAndSet(null, msg)) { 211 return true; 212 } 213 214 boolean v = true; 215 try { 216 if (!explicit) { 217 boolean dontAsk = NbPreferences.forModule(Installer.class).getBoolean("ask.never.again." + msg, false); if (dontAsk) { 219 LOG.log(Level.INFO, "UI Gesture Collector's ask.never.again.{0} is true, exiting", msg); return true; 221 } 222 } 223 224 v = doDisplaySummary(msg); 225 } finally { 226 DISPLAYING.set(null); 227 } 228 return v; 229 } 230 231 protected static Throwable getThrown(){ 232 List <LogRecord > list = getLogs(); 233 ListIterator <LogRecord > it = list.listIterator(list.size()); 234 while (it.hasPrevious()){ 235 Throwable t = it.previous().getThrown(); 236 if (t != null) return t; 238 } 239 return null; } 241 242 private static boolean doDisplaySummary(String msg) { 243 Submit submit = new Submit(msg); 244 submit.doShow(); 245 return submit.okToExit; 246 } 247 248 249 private static boolean isChild(org.w3c.dom.Node child, org.w3c.dom.Node parent) { 250 while (child != null) { 251 if (child == parent) { 252 return true; 253 } 254 child = child.getParentNode(); 255 } 256 return false; 257 } 258 259 private static String attrValue(org.w3c.dom.Node in, String attrName) { 260 org.w3c.dom.Node n = in.getAttributes().getNamedItem(attrName); 261 return n == null ? null : n.getNodeValue(); 262 } 263 264 268 static void parseButtons(InputStream is, Object defaultButton, DialogDescriptor dd) 269 throws IOException , ParserConfigurationException , SAXException { 270 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 271 factory.setValidating(false); 272 factory.setIgnoringComments(true); 273 DocumentBuilder builder = factory.newDocumentBuilder(); 274 Document doc = builder.parse(is); 275 276 List <Object > buttons = new ArrayList <Object >(); 277 List <Object > left = new ArrayList <Object >(); 278 279 NodeList forms = doc.getElementsByTagName("form"); 280 for (int i = 0; i < forms.getLength(); i++) { 281 Form f = new Form(forms.item(i).getAttributes().getNamedItem("action").getNodeValue()); 282 NodeList inputs = doc.getElementsByTagName("input"); 283 for (int j = 0; j < inputs.getLength(); j++) { 284 if (isChild(inputs.item(j), forms.item(i))) { 285 org.w3c.dom.Node in = inputs.item(j); 286 String type = attrValue(in, "type"); 287 String name = attrValue(in, "name"); 288 String value = attrValue(in, "value"); 289 String align = attrValue(in, "align"); 290 String alt = attrValue(in, "alt"); 291 292 List <Object > addTo = "left".equals(align) ? left : buttons; 293 294 if ("hidden".equals(type) && "submit".equals(name)) { f.submitValue = value; 296 JButton b = new JButton (); 297 Mnemonics.setLocalizedText(b, f.submitValue); 298 b.setActionCommand("submit"); b.putClientProperty("url", f.url); b.setDefaultCapable(addTo.isEmpty() && addTo == buttons); 301 b.putClientProperty("alt", alt); b.putClientProperty("now", f.submitValue); addTo.add(b); 304 continue; 305 } 306 307 308 if ("hidden".equals(type)) { JButton b = new JButton (); 310 Mnemonics.setLocalizedText(b, value); 311 b.setActionCommand(name); 312 b.setDefaultCapable(addTo.isEmpty() && addTo == buttons); 313 b.putClientProperty("alt", alt); b.putClientProperty("now", value); addTo.add(b); 316 if ("exit".equals(name)) { defaultButton = null; 318 } 319 } 320 } 321 } 322 } 323 if (defaultButton != null) { 324 buttons.add(defaultButton); 325 } 326 dd.setOptions(buttons.toArray()); 327 dd.setAdditionalOptions(left.toArray()); 328 } 329 330 static String decodeButtons(Object res, URL [] url) { 331 if (res instanceof JButton ) { 332 JButton b = (JButton )res; 333 Object post = b.getClientProperty("url"); if (post instanceof String ) { 335 String replace = System.getProperty("org.netbeans.modules.uihandler.Submit"); if (replace != null) { 337 post = replace; 338 } 339 try { 340 url[0] = new URL ((String ) post); 341 } catch (MalformedURLException ex) { 342 url[0] = null; 343 } 344 } 345 return b.getActionCommand(); 346 } 347 return res instanceof String ? (String )res : null; 348 } 349 350 static URL uploadLogs(URL postURL, String id, Map <String ,String > attrs, List <LogRecord > recs) throws IOException { 351 URLConnection conn = postURL.openConnection(); 352 353 conn.setReadTimeout(20000); 354 conn.setDoOutput(true); 355 conn.setDoInput(true); 356 conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=--------konec<>bloku"); 357 conn.setRequestProperty("Pragma", "no-cache"); 358 conn.setRequestProperty("Cache-control", "no-cache"); 359 360 PrintStream os = new PrintStream (conn.getOutputStream()); 361 368 for (Map.Entry <String , String > en : attrs.entrySet()) { 369 os.println("----------konec<>bloku"); 370 os.println("Content-Disposition: form-data; name=\"" + en.getKey() + "\""); 371 os.println(); 372 os.println(en.getValue().getBytes()); 373 } 374 375 os.println("----------konec<>bloku"); 376 377 if (id == null) { 378 id = "uigestures"; } 380 381 os.println("Content-Disposition: form-data; name=\"logs\"; filename=\"" + id + "\""); 382 os.println("Content-Type: x-application/gzip"); 383 os.println(); 384 GZIPOutputStream gzip = new GZIPOutputStream (os); 385 DataOutputStream data = new DataOutputStream (gzip); 386 data.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n".getBytes("utf-8")); data.write("<uigestures version='1.0'>\n".getBytes("utf-8")); for (LogRecord r : recs) { 389 LogRecords.write(data, r); 390 } 391 data.write("</uigestures>\n".getBytes("utf-8")); data.flush(); 393 gzip.finish(); 394 os.println("----------konec<>bloku--"); 395 os.close(); 396 397 398 InputStream is = conn.getInputStream(); 399 StringBuffer redir = new StringBuffer (); 400 for (;;) { 401 int ch = is.read(); 402 if (ch == -1) { 403 break; 404 } 405 redir.append((char)ch); 406 } 407 is.close(); 408 409 LOG.fine("Reply from uploadLogs:"); 410 LOG.fine(redir.toString()); 411 412 Pattern p = Pattern.compile("<meta\\s*http-equiv=.Refresh.\\s*content.*url=['\"]?([^'\" ]*)\\s*['\"]", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL); 413 Matcher m = p.matcher(redir); 414 415 if (m.find()) { 416 return new URL (m.group(1)); 417 } else { 418 File f = File.createTempFile("uipage", "html"); 419 FileWriter w = new FileWriter (f); 420 w.write(redir.toString()); 421 w.close(); 422 return f.toURI().toURL(); 423 } 424 } 425 426 private static String findIdentity() { 427 Preferences p = NbPreferences.root().node("org/netbeans/modules/autoupdate"); String id = p.get("ideIdentity", null); 429 LOG.log(Level.INFO, "findIdentity: {0}", id); 430 return id; 431 } 432 433 static final class Form extends Object { 434 final String url; 435 String submitValue; 436 437 public Form(String u) { 438 url = u; 439 } 440 } 441 442 private static final class Submit implements ActionListener , Mutex.Action<Void > { 443 private String msg; 444 boolean okToExit; 445 private DialogDescriptor dd; 446 private Dialog d; 447 private SubmitPanel panel; 448 private HtmlBrowser browser; 449 private URL url; 450 private String exitMsg; 451 private boolean report; private ReportPanel reportPanel; 453 454 public Submit(String msg) { 455 this.msg = msg; 456 if ("ERROR_URL".equals(msg)) report = true; else report = false; 458 } 459 460 private LogRecord getUserData(){ 461 LogRecord userData; 462 ExceptionsSettings settings = new ExceptionsSettings(); 463 ArrayList <String > params = new ArrayList <String >(6); 464 params.add(getOS()); 465 params.add(getVM()); 466 params.add(getVersion()); 467 if (reportPanel != null) reportPanel.saveUserName(); 468 params.add(settings.getUserName()); 469 if (reportPanel != null){ 470 params.add(reportPanel.getSummary()); 471 params.add(reportPanel.getComment()); 472 } 473 userData = new LogRecord (Level.CONFIG, USER_CONFIGURATION); 474 userData.setResourceBundle(NbBundle.getBundle(Installer.class)); 475 userData.setResourceBundleName(Installer.class.getPackage().getName()+".Bundle"); 476 userData.setParameters(params.toArray()); 477 return userData; 478 } 479 480 private String getOS(){ 481 String unknown = "unknown"; String str = System.getProperty("os.name", unknown)+", "+ System.getProperty("os.version", unknown)+", "+ System.getProperty("os.arch", unknown); return str; 486 } 487 488 private String getVersion(){ 489 String str = MessageFormat.format( 490 NbBundle.getBundle("org.netbeans.core.startup.Bundle").getString("currentVersion"), new Object [] {System.getProperty("netbeans.buildnumber")}); return str; 493 } 494 495 private String getVM(){ 496 return System.getProperty("java.vm.name", "unknown") + ", " + System.getProperty("java.vm.version", ""); } 498 499 public void doShow() { 500 Logger log = Logger.getLogger("org.netbeans.ui"); for (Deactivated a : Lookup.getDefault().lookupAll(Deactivated.class)) { 502 a.deactivated(log); 503 } 504 if (report) { 505 dd = new DialogDescriptor(null, NbBundle.getMessage(Installer.class, "ErrorDialogTitle")); 506 } else { 507 dd = new DialogDescriptor(null, NbBundle.getMessage(Installer.class, "MSG_SubmitDialogTitle")); 508 } 509 510 exitMsg = NbBundle.getMessage(Installer.class, "MSG_" + msg + "_EXIT"); for (;;) { 512 try { 513 if (url == null) { 514 String uri = NbBundle.getMessage(Installer.class, msg); 515 if (uri == null || uri.length() == 0) { 516 okToExit = true; 517 return; 518 } 519 url = new URL (uri); } 521 522 URLConnection conn = url.openConnection(); 523 File tmp = File.createTempFile("uigesture", ".html"); 524 tmp.deleteOnExit(); 525 FileOutputStream os = new FileOutputStream (tmp); 526 FileUtil.copy(conn.getInputStream(), os); 527 os.close(); 528 conn.getInputStream().close(); 529 InputStream is = new FileInputStream (tmp); 530 parseButtons(is, exitMsg, dd); 531 is.close(); 532 url = tmp.toURI().toURL(); 533 } catch (ParserConfigurationException ex) { 534 LOG.log(Level.WARNING, null, ex); 535 } catch (SAXException ex) { 536 LOG.log(Level.WARNING, url.toExternalForm(), ex); 537 } catch (java.net.SocketTimeoutException ex) { 538 LOG.log(Level.INFO, url.toExternalForm(), ex); 539 url = getClass().getResource("UnknownHostException.html"); 540 msg = null; 541 continue; 542 } catch (UnknownHostException ex) { 543 LOG.log(Level.INFO, url.toExternalForm(), ex); 544 url = getClass().getResource("UnknownHostException.html"); 545 msg = null; 546 continue; 547 } catch (NoRouteToHostException ex) { 548 LOG.log(Level.INFO, url.toExternalForm(), ex); 549 url = getClass().getResource("UnknownHostException.html"); 550 msg = null; 551 continue; 552 } catch (IOException ex) { 553 LOG.log(Level.WARNING, url.toExternalForm(), ex); 554 } 555 break; 556 } 557 Mutex.EVENT.readAccess(this); 558 } 559 560 public Void run() { 561 if ("ERROR_URL".equals(msg)){ if (reportPanel==null) reportPanel = new ReportPanel(); 563 Throwable t = getThrown(); 564 assert t!= null : "NO THROWABLE FOUND"; String summary = t.getClass().getName(); 566 String [] pieces = summary.split("\\."); 567 if (pieces.length > 0) summary = pieces[pieces.length-1]; if (t.getMessage()!= null)summary = summary.concat(" : " + t.getMessage()); reportPanel.setSummary(summary); 570 dd.setMessage(reportPanel); 571 }else{ 572 browser = new HtmlBrowser(); 573 browser.setURL(url); 574 browser.setEnableLocation(false); 575 browser.setEnableHome(false); 576 browser.setStatusLineVisible(false); 577 browser.setToolbarVisible(false); 578 browser.setPreferredSize(new Dimension (640, 480)); 579 dd.setMessage(browser); 580 581 591 } 592 dd.setClosingOptions(new Object [] { exitMsg }); 593 dd.setButtonListener(this); 594 dd.setModal(true); 595 d = DialogDisplayer.getDefault().createDialog(dd); 596 d.setVisible(true); 597 598 Object res = dd.getValue(); 599 600 if (res == exitMsg) { 601 okToExit = true; 602 } 603 604 return null; 605 } 606 607 private void uploadAndPost(List <LogRecord > recs, URL u) { 608 URL nextURL = null; 609 try { 610 nextURL = uploadLogs(u, findIdentity(), Collections.<String ,String >emptyMap(), recs); 611 } catch (IOException ex) { 612 LOG.log(Level.INFO, null, ex); 613 } 614 if (nextURL != null) { 615 clearLogs(); 616 HtmlBrowser.URLDisplayer.getDefault().showURL(nextURL); 617 } 618 } 619 620 public void actionPerformed(ActionEvent e) { 621 final URL [] url = new URL [1]; 622 String actionURL = decodeButtons(e.getSource(), url); 623 624 if ("submit".equals(e.getActionCommand())) { final List <LogRecord > recs = getLogs(); 626 if (report) reportPanel.saveUserName(); 627 recs.add(getUserData()); 628 RP.post (new Runnable () { 629 public void run() { 630 uploadAndPost(recs, url[0]); 631 } 632 }); 633 okToExit = false; 634 dd.setValue(DialogDescriptor.CLOSED_OPTION); 636 d.setVisible(false); 637 return; 638 } 639 640 if ("view-data".equals(e.getActionCommand())) { if (panel == null) { 642 panel = new SubmitPanel(); 643 AbstractNode root = new AbstractNode(new Children.Array()); 644 root.setName("root"); List <LogRecord > recs = getLogs(); 646 recs.add(getUserData()); 647 root.setDisplayName(NbBundle.getMessage(Installer.class, "MSG_RootDisplayName", recs.size(), new Date ())); 648 root.setIconBaseWithExtension("org/netbeans/modules/uihandler/logs.gif"); 649 LinkedList <Node> reverted = new LinkedList <Node>(); 650 for (LogRecord r : recs) { 651 reverted.addFirst(UINode.create(r)); 652 panel.addRecord(r); 653 } 654 root.getChildren().add(reverted.toArray(new Node[0])); 655 panel.getExplorerManager().setRootContext(root); 656 } 657 658 if (report) { 659 if (dd.getMessage() == reportPanel) { 660 dd.setMessage(panel); 661 } else { 662 dd.setMessage(reportPanel); 663 } 664 } else { 665 if (dd.getMessage() == browser) { 666 dd.setMessage(panel); 667 } else { 668 dd.setMessage(browser); 669 } 670 } 671 if (e.getSource() instanceof AbstractButton ) { 672 AbstractButton abut = (AbstractButton )e.getSource(); 673 String alt = (String ) abut.getClientProperty("alt"); if (alt != null) { 675 String now = (String )abut.getClientProperty("now"); Mnemonics.setLocalizedText(abut, alt); 677 abut.putClientProperty("alt", now); abut.putClientProperty("now", alt); } 680 } 681 return; 682 } 683 684 if ("never-again".equals(e.getActionCommand())) { LOG.log(Level.FINE, "Assigning ask.never.again.{0} to true", msg); NbPreferences.forModule(Installer.class).putBoolean("ask.never.again." + msg, true); okToExit = true; 688 dd.setValue(DialogDescriptor.CLOSED_OPTION); 690 d.setVisible(false); 691 return; 692 } 693 694 if ("exit".equals(e.getActionCommand())) { 695 dd.setValue(DialogDescriptor.CLOSED_OPTION); 697 d.setVisible(false); 698 return; 699 } 700 701 } 702 } } 704 | Popular Tags |