PageRenderTime 51ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/projects/netbeans-7.3/debugger.jpda.visual/src/org/netbeans/modules/debugger/jpda/visual/models/EventsModel.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 976 lines | 784 code | 82 blank | 110 comment | 163 complexity | d6a48a2864f5977dcfd2779d95edabe0 MD5 | raw file
  1. /*
  2. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3. *
  4. * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
  5. *
  6. * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  7. * Other names may be trademarks of their respective owners.
  8. *
  9. * The contents of this file are subject to the terms of either the GNU
  10. * General Public License Version 2 only ("GPL") or the Common
  11. * Development and Distribution License("CDDL") (collectively, the
  12. * "License"). You may not use this file except in compliance with the
  13. * License. You can obtain a copy of the License at
  14. * http://www.netbeans.org/cddl-gplv2.html
  15. * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  16. * specific language governing permissions and limitations under the
  17. * License. When distributing the software, include this License Header
  18. * Notice in each file and include the License file at
  19. * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
  20. * particular file as subject to the "Classpath" exception as provided
  21. * by Oracle in the GPL Version 2 section of the License file that
  22. * accompanied this code. If applicable, add the following below the
  23. * License Header, with the fields enclosed by brackets [] replaced by
  24. * your own identifying information:
  25. * "Portions Copyrighted [year] [name of copyright owner]"
  26. *
  27. * If you wish your version of this file to be governed by only the CDDL
  28. * or only the GPL Version 2, indicate your decision by adding
  29. * "[Contributor] elects to include this software in this distribution
  30. * under the [CDDL or GPL Version 2] license." If you do not indicate a
  31. * single choice of license, a recipient has the option to distribute
  32. * your version of this file under either the CDDL, the GPL Version 2 or
  33. * to extend the choice of license to its licensees as provided above.
  34. * However, if you add GPL Version 2 code and therefore, elected the GPL
  35. * Version 2 license, then the option applies only if the new code is
  36. * made subject to such option by the copyright holder.
  37. *
  38. * Contributor(s):
  39. *
  40. * Portions Copyrighted 2011 Sun Microsystems, Inc.
  41. */
  42. package org.netbeans.modules.debugger.jpda.visual.models;
  43. import com.sun.jdi.AbsentInformationException;
  44. import com.sun.jdi.ClassObjectReference;
  45. import com.sun.jdi.ObjectReference;
  46. import com.sun.jdi.ReferenceType;
  47. import com.sun.jdi.VirtualMachine;
  48. import java.awt.event.ActionEvent;
  49. import java.beans.PropertyVetoException;
  50. import java.lang.ref.Reference;
  51. import java.lang.ref.WeakReference;
  52. import java.util.ArrayList;
  53. import java.util.Arrays;
  54. import java.util.Collection;
  55. import java.util.HashMap;
  56. import java.util.HashSet;
  57. import java.util.List;
  58. import java.util.Map;
  59. import java.util.Set;
  60. import java.util.TreeMap;
  61. import java.util.concurrent.CopyOnWriteArraySet;
  62. import javax.swing.AbstractAction;
  63. import javax.swing.Action;
  64. import javax.swing.JList;
  65. import javax.swing.JScrollPane;
  66. import javax.swing.SwingUtilities;
  67. import org.netbeans.api.debugger.jpda.JPDADebugger;
  68. import org.netbeans.modules.debugger.jpda.EditorContextBridge;
  69. import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl;
  70. import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper;
  71. import org.netbeans.modules.debugger.jpda.jdi.ObjectCollectedExceptionWrapper;
  72. import org.netbeans.modules.debugger.jpda.jdi.ObjectReferenceWrapper;
  73. import org.netbeans.modules.debugger.jpda.jdi.ReferenceTypeWrapper;
  74. import org.netbeans.modules.debugger.jpda.jdi.UnsupportedOperationExceptionWrapper;
  75. import org.netbeans.modules.debugger.jpda.jdi.VMDisconnectedExceptionWrapper;
  76. import org.netbeans.modules.debugger.jpda.jdi.VirtualMachineWrapper;
  77. import org.netbeans.modules.debugger.jpda.visual.JavaComponentInfo;
  78. import org.netbeans.modules.debugger.jpda.visual.RemoteAWTScreenshot.AWTComponentInfo;
  79. import org.netbeans.modules.debugger.jpda.visual.RemoteServices;
  80. import org.netbeans.modules.debugger.jpda.visual.RemoteServices.RemoteListener;
  81. import org.netbeans.modules.debugger.jpda.visual.actions.GoToSourceAction;
  82. import org.netbeans.modules.debugger.jpda.visual.spi.ComponentInfo;
  83. import org.netbeans.modules.debugger.jpda.visual.spi.ScreenshotUIManager;
  84. import org.netbeans.spi.debugger.ContextProvider;
  85. import org.netbeans.spi.debugger.DebuggerServiceRegistration;
  86. import org.netbeans.spi.viewmodel.ModelEvent;
  87. import org.netbeans.spi.viewmodel.ModelListener;
  88. import org.netbeans.spi.viewmodel.NodeActionsProvider;
  89. import org.netbeans.spi.viewmodel.NodeModel;
  90. import org.netbeans.spi.viewmodel.TableModel;
  91. import org.netbeans.spi.viewmodel.TreeExpansionModel;
  92. import org.netbeans.spi.viewmodel.TreeExpansionModelFilter;
  93. import org.netbeans.spi.viewmodel.TreeModel;
  94. import org.netbeans.spi.viewmodel.UnknownTypeException;
  95. import org.openide.DialogDescriptor;
  96. import org.openide.DialogDisplayer;
  97. import org.openide.NotifyDescriptor;
  98. import org.openide.nodes.Node;
  99. import org.openide.util.Exceptions;
  100. import org.openide.util.Lookup.Result;
  101. import org.openide.util.LookupEvent;
  102. import org.openide.util.LookupListener;
  103. import org.openide.util.NbBundle;
  104. import org.openide.util.Utilities;
  105. /**
  106. *
  107. * @author Martin Entlicher
  108. */
  109. @DebuggerServiceRegistration(path="netbeans-JPDASession/EventsView", types={ TreeModel.class, NodeModel.class, TableModel.class, NodeActionsProvider.class, TreeExpansionModelFilter.class })
  110. public class EventsModel implements TreeModel, NodeModel, TableModel, NodeActionsProvider, TreeExpansionModelFilter {
  111. private static final String customListeners = "customListeners"; // NOI18N
  112. private static final String swingListeners = "swingListeners"; // NOI18N
  113. private static final String eventsLog = "eventsLog"; // NOI18N
  114. private Set<ModelListener> listeners = new CopyOnWriteArraySet<ModelListener>();
  115. private JavaComponentInfo selectedCI = null;
  116. private final List<RemoteEvent> events = new ArrayList<RemoteEvent>();
  117. private volatile List<RemoteListener> customListenersList;
  118. private volatile List<RemoteListener> swingListenersList;
  119. private JPDADebugger debugger;
  120. private final Map<ObjectReference, Set<LoggingEventListener>> loggingListeners =
  121. new HashMap<ObjectReference, Set<LoggingEventListener>>();
  122. public EventsModel(ContextProvider contextProvider) {
  123. debugger = contextProvider.lookupFirst(null, JPDADebugger.class);
  124. ScreenshotUIManager uiManager = ScreenshotUIManager.getActive();
  125. if (uiManager != null) {
  126. ComponentInfo ci = uiManager.getSelectedComponent();
  127. if (ci instanceof JavaComponentInfo) {
  128. selectedCI = (JavaComponentInfo) ci;
  129. }
  130. }
  131. /*Node[] nodes = ComponentHierarchy.getInstance().getExplorerManager().getSelectedNodes();
  132. if (nodes.length > 0) {
  133. selectedCI = nodes[0].getLookup().lookup(AWTComponentInfo.class);
  134. }*/
  135. final Result<Node> nodeLookupResult = Utilities.actionsGlobalContext().lookupResult(Node.class);
  136. LookupListener ll = new LookupListener() {
  137. @Override
  138. public void resultChanged(LookupEvent ev) {
  139. Collection<? extends Node> nodeInstances = nodeLookupResult.allInstances();
  140. for (Node n : nodeInstances) {
  141. JavaComponentInfo ci = n.getLookup().lookup(JavaComponentInfo.class);
  142. if (ci != null) {
  143. if (!ci.equals(selectedCI)) {
  144. selectedCI = ci;
  145. if (ev != null) {
  146. fireModelChanged();
  147. }
  148. }
  149. break;
  150. }
  151. }
  152. }
  153. };
  154. nodeLookupResult.addLookupListener(ll);
  155. ll.resultChanged(null); // To initialize
  156. }
  157. @Override
  158. public Object getRoot() {
  159. return ROOT;
  160. }
  161. @Override
  162. public Object[] getChildren(Object parent, int from, int to) throws UnknownTypeException {
  163. if (parent == ROOT) {
  164. JavaComponentInfo ci = selectedCI;
  165. if (ci != null) {
  166. String componentName = ci.getDisplayName();
  167. List<RemoteListener> componentListeners;
  168. try {
  169. componentListeners = RemoteServices.getAttachedListeners(ci, true);
  170. //System.err.println("ALL Component Listeners = "+componentListeners);
  171. } catch (PropertyVetoException pvex) {
  172. Exceptions.printStackTrace(pvex);
  173. return new Object[] {};
  174. }
  175. Set<LoggingEventListener> lls = null;
  176. synchronized (loggingListeners) {
  177. lls = loggingListeners.get(ci.getComponent());
  178. if (lls != null) {
  179. lls = new HashSet<LoggingEventListener>(lls);
  180. }
  181. }
  182. //Map<String, ListenerCategory> listenerCategories;
  183. //customListenersMap = new TreeMap<String, ListenerCategory>();
  184. //swingListenersMap = new TreeMap<String, ListenerCategory>();
  185. List<RemoteListener> cll = new ArrayList<RemoteListener>(componentListeners.size());
  186. List<RemoteListener> sll = new ArrayList<RemoteListener>(componentListeners.size());
  187. for (RemoteListener rl : componentListeners) {
  188. ObjectReference listener = rl.getListener();
  189. if (lls != null) {
  190. boolean isLogging = false;
  191. for (LoggingEventListener ll : lls) {
  192. if (listener.equals(ll.getListenerObject())) {
  193. isLogging = true;
  194. break;
  195. }
  196. }
  197. if (isLogging) {
  198. continue; // Ignore the logging listener.
  199. }
  200. }
  201. try {
  202. String type = ReferenceTypeWrapper.name(ObjectReferenceWrapper.referenceType(listener));
  203. if (JavaComponentInfo.isCustomType(type)) {
  204. //listenerCategories = customListenersMap;
  205. cll.add(rl);
  206. } else {
  207. sll.add(rl);
  208. //listenerCategories = swingListenersMap;
  209. }
  210. } catch (InternalExceptionWrapper iex) {
  211. } catch (ObjectCollectedExceptionWrapper ocex) {
  212. } catch (VMDisconnectedExceptionWrapper vmdex) {
  213. }
  214. /*
  215. ListenerCategory lc = listenerCategories.get(type);
  216. if (lc == null) {
  217. lc = new ListenerCategory(type);
  218. listenerCategories.put(type, lc);
  219. }
  220. lc.addListener(rl); */
  221. }
  222. customListenersList = cll;
  223. swingListenersList = sll;
  224. return new Object[] { componentName, customListeners, swingListeners, eventsLog };
  225. } else {
  226. customListenersList = null;
  227. swingListenersList = null;
  228. }
  229. return new Object[] {};
  230. }
  231. if (parent == customListeners) {
  232. return customListenersList.toArray();
  233. }
  234. if (parent == swingListeners) {
  235. return swingListenersList.toArray();
  236. }
  237. /*
  238. if (parent == customListeners || parent == swingListeners) {
  239. AWTComponentInfo ci = selectedCI;
  240. if (ci != null) {
  241. //ObjectReference component = ci.getComponent();
  242. List<RemoteListener> componentListeners;
  243. try {
  244. componentListeners = RemoteServices.getAttachedListeners(ci);
  245. } catch (PropertyVetoException pvex) {
  246. Exceptions.printStackTrace(pvex);
  247. return new Object[] {};
  248. }
  249. Map<String, ListenerCategory> listenerCategories = new TreeMap<String, ListenerCategory>();
  250. for (RemoteListener rl : componentListeners) {
  251. String type = rl.getType();
  252. if ((parent == customListeners) == JavaComponentInfo.isCustomType(type)) {
  253. ListenerCategory lc = listenerCategories.get(type);
  254. if (lc == null) {
  255. lc = new ListenerCategory(type);
  256. listenerCategories.put(type, lc);
  257. }
  258. lc.addListener(rl);
  259. }
  260. }
  261. return listenerCategories.values().toArray();
  262. }
  263. }
  264. */
  265. /*if (parent instanceof RemoteListener) {
  266. return ((RemoteListener) parent).getListener();
  267. }*/
  268. if (parent instanceof ListenerCategory) {
  269. return ((ListenerCategory) parent).getListeners().toArray();
  270. }
  271. if (parent == eventsLog) {
  272. synchronized (events) {
  273. return events.toArray();
  274. }
  275. }
  276. if (parent instanceof RemoteEvent) {
  277. return ((RemoteEvent) parent).getPropertiesWithStackNode();
  278. }
  279. if (parent instanceof Stack) {
  280. return ((Stack) parent).getStackElements();
  281. }
  282. return new Object[] {};
  283. }
  284. @Override
  285. public boolean isLeaf(Object node) throws UnknownTypeException {
  286. if (node == ROOT || node == eventsLog) {
  287. return false;
  288. }
  289. if (node == customListeners) {
  290. //List<RemoteListener> l = customListenersList;
  291. //return (l == null || l.isEmpty());
  292. return false; // To have the expand sign visible always so that it's
  293. // clear that the listeners would be listed under this node.
  294. }
  295. if (node == swingListeners) {
  296. //List<RemoteListener> l = swingListenersList;
  297. //return (l == null || l.isEmpty());
  298. return false; // To have the expand sign visible always so that it's
  299. // clear that the listeners would be listed under this node.
  300. }
  301. if (node instanceof RemoteListener) {
  302. return true;
  303. }
  304. if (node instanceof Stack.Element) {
  305. return true;
  306. }
  307. if (node instanceof String) {
  308. return true;
  309. }
  310. return false;
  311. }
  312. @Override
  313. public int getChildrenCount(Object node) throws UnknownTypeException {
  314. return Integer.MAX_VALUE;
  315. }
  316. @Override
  317. public void addModelListener(ModelListener l) {
  318. listeners.add(l);
  319. }
  320. @Override
  321. public void removeModelListener(ModelListener l) {
  322. listeners.remove(l);
  323. }
  324. private void fireModelChanged() {
  325. ModelEvent me = new ModelEvent.TreeChanged(this);
  326. for (ModelListener l : listeners) {
  327. l.modelChanged(me);
  328. }
  329. }
  330. private void fireNodeChanged(Object node) {
  331. ModelEvent me = new ModelEvent.NodeChanged(this, node);
  332. for (ModelListener l : listeners) {
  333. l.modelChanged(me);
  334. }
  335. }
  336. private void addEvent(RemoteEvent re) {
  337. synchronized (events) {
  338. events.add(re);
  339. }
  340. fireNodeChanged(eventsLog);
  341. }
  342. @Override
  343. public String getDisplayName(Object node) throws UnknownTypeException {
  344. if (node == ROOT) {
  345. return "Events";
  346. }
  347. if (node == customListeners) {
  348. return NbBundle.getMessage(EventsModel.class, "CTL_CustomListeners");
  349. }
  350. if (node == swingListeners) {
  351. return NbBundle.getMessage(EventsModel.class, "CTL_InternalListeners");
  352. }
  353. if (node == eventsLog) {
  354. return NbBundle.getMessage(EventsModel.class, "CTL_EventLog");
  355. }
  356. if (node instanceof ListenerCategory) {
  357. return ((ListenerCategory) node).getType();
  358. }
  359. if (node instanceof RemoteListener) {
  360. return ((RemoteListener) node).getListener().referenceType().name();
  361. }
  362. if (node instanceof RemoteEvent) {
  363. RemoteEvent re = (RemoteEvent) node;
  364. String toString = re.getEventToString();
  365. int end = toString.indexOf('[');
  366. if (end < 0) end = toString.length();
  367. return re.getListenerMethod()+" ("+toString.substring(0, end)+')';
  368. }
  369. if (node instanceof Stack) {
  370. return NbBundle.getMessage(EventsModel.class, "CTL_CalledFrom");
  371. }
  372. if (node instanceof Stack.Element) {
  373. Stack.Element e = (Stack.Element) node;
  374. return "<html>"+e.getClassName()+".<b>"+e.getMethodName()+"</b>(<font color=\"#0000FF\">"+e.getFileName()+":"+e.getLineNumber()+"</font>)</html>";
  375. }
  376. return String.valueOf(node);
  377. }
  378. @Override
  379. public String getIconBase(Object node) throws UnknownTypeException {
  380. return null;
  381. }
  382. @Override
  383. public String getShortDescription(Object node) throws UnknownTypeException {
  384. if (node instanceof RemoteListener) {
  385. try {
  386. return ReferenceTypeWrapper.sourceName(ObjectReferenceWrapper.referenceType(((RemoteListener) node).getListener()));
  387. } catch (InternalExceptionWrapper ex) {
  388. return ex.getLocalizedMessage();
  389. } catch (VMDisconnectedExceptionWrapper ex) {
  390. return "";
  391. } catch (ObjectCollectedExceptionWrapper ex) {
  392. return ex.getLocalizedMessage();
  393. } catch (AbsentInformationException ex) {
  394. return "";
  395. }
  396. }
  397. if (node instanceof RemoteEvent) {
  398. RemoteEvent re = (RemoteEvent) node;
  399. return re.getEventToString();
  400. }
  401. return "";
  402. }
  403. @Override
  404. public void performDefaultAction(Object node) throws UnknownTypeException {
  405. if (node == eventsLog) {
  406. new SetLoggingEvents().actionPerformed(null);
  407. }
  408. if (node instanceof Stack.Element) {
  409. final Stack.Element e = (Stack.Element) node;
  410. String type = e.getClassName();
  411. type = EditorContextBridge.getRelativePath (type);
  412. final String url = ((JPDADebuggerImpl) debugger).getEngineContext().getURL(type, true);
  413. if (url != null) {
  414. SwingUtilities.invokeLater (new Runnable () {
  415. public void run () {
  416. EditorContextBridge.getContext().showSource(url, e.getLineNumber(), null);
  417. }
  418. });
  419. }
  420. }
  421. }
  422. @Override
  423. public Action[] getActions(Object node) throws UnknownTypeException {
  424. if (selectedCI != null) {
  425. if (node == customListeners) {
  426. return new Action[] { new SetLoggingEvents() };//new AddLoggingListenerAction(null) };
  427. }
  428. if (node == eventsLog) {
  429. return new Action[] {
  430. new SetLoggingEvents(),
  431. null,
  432. new ClearEventsAction() };
  433. }
  434. if (node instanceof ListenerCategory) {
  435. return new Action[] { new AddLoggingListenerAction((ListenerCategory) node) };
  436. }
  437. if (node instanceof RemoteListener) {
  438. return new Action[] { GoToSourceAction.get(GoToSourceAction.class) };
  439. }
  440. }
  441. return new Action[] {};
  442. }
  443. private boolean customListenersExpanded = true;
  444. private boolean eventsExpanded = true;
  445. @Override
  446. public boolean isExpanded(TreeExpansionModel original, Object node) throws UnknownTypeException {
  447. if (node == customListeners) {
  448. return customListenersExpanded;
  449. } else if (node == eventsLog) {
  450. return eventsExpanded;
  451. } else {
  452. return original.isExpanded(node);
  453. }
  454. }
  455. @Override
  456. public void nodeExpanded(Object node) {
  457. if (node == customListeners) {
  458. customListenersExpanded = true;
  459. } else if (node == eventsLog) {
  460. eventsExpanded = true;
  461. }
  462. }
  463. @Override
  464. public void nodeCollapsed(Object node) {
  465. if (node == customListeners) {
  466. customListenersExpanded = false;
  467. } else if (node == eventsLog) {
  468. eventsExpanded = false;
  469. }
  470. }
  471. @Override
  472. public Object getValueAt(Object node, String columnID) throws UnknownTypeException {
  473. if (EventTypesColumnModel.ID.equals(columnID)) {
  474. if (node instanceof RemoteListener) {
  475. String[] types = ((RemoteListener) node).getTypes();
  476. if (types.length == 1) {
  477. return types[0];
  478. } else {
  479. StringBuilder sb = new StringBuilder(types[0]);
  480. for (int i = 1; i < types.length; i++) {
  481. sb.append(", ");
  482. sb.append(types[i]);
  483. }
  484. return sb.toString();
  485. }
  486. } else {
  487. return "";
  488. }
  489. } else {
  490. throw new UnknownTypeException("Unknown column: "+columnID);
  491. }
  492. }
  493. @Override
  494. public boolean isReadOnly(Object node, String columnID) throws UnknownTypeException {
  495. return true;
  496. }
  497. @Override
  498. public void setValueAt(Object node, String columnID, Object value) throws UnknownTypeException {
  499. throw new IllegalStateException("Is read only.");
  500. }
  501. private static class ListenerCategory {
  502. private String type;
  503. private List<RemoteListener> listeners = new ArrayList<RemoteListener>();
  504. public ListenerCategory(String type) {
  505. this.type = type;
  506. }
  507. public String getType() {
  508. return type;
  509. }
  510. public void addListener(RemoteListener l) {
  511. listeners.add(l);
  512. }
  513. public List<RemoteListener> getListeners() {
  514. return listeners;
  515. }
  516. }
  517. private class SetLoggingEvents extends AbstractAction {
  518. public SetLoggingEvents() {}
  519. @Override
  520. public Object getValue(String key) {
  521. if (Action.NAME.equals(key)) {
  522. return NbBundle.getMessage(EventsModel.class, "CTL_SetLoggingEvents");
  523. }
  524. return super.getValue(key);
  525. }
  526. @Override
  527. public void actionPerformed(ActionEvent e) {
  528. final JavaComponentInfo ci = selectedCI;
  529. if (ci == null) return ;
  530. final ReferenceType[] listenerClasses;
  531. final List<LoggingEventListener> listenersToRemove = new ArrayList<LoggingEventListener>();
  532. listenerClasses = selectListenerClass(ci, listenersToRemove);
  533. if (listenerClasses == null) {
  534. return;
  535. }
  536. ci.getThread().getDebugger().getRequestProcessor().post(new Runnable() {
  537. @Override
  538. public void run() {
  539. boolean fire = false;
  540. for (ReferenceType rt : listenerClasses) {
  541. ObjectReference l;
  542. try {
  543. LoggingEventListener listener = new LoggingEventListener(EventsModel.this);
  544. ClassObjectReference cor = ReferenceTypeWrapper.classObject(rt);
  545. l = RemoteServices.attachLoggingListener(ci, cor, listener);
  546. listener.setListenerObject(l, cor);
  547. synchronized (loggingListeners) {
  548. Set<LoggingEventListener> listeners = loggingListeners.get(ci.getComponent());
  549. if (listeners == null) {
  550. listeners = new HashSet<LoggingEventListener>();
  551. loggingListeners.put(ci.getComponent(), listeners);
  552. }
  553. listeners.add(listener);
  554. }
  555. } catch (PropertyVetoException pvex) {
  556. Exceptions.printStackTrace(pvex);
  557. return ;
  558. } catch (InternalExceptionWrapper iex) {
  559. return ;
  560. } catch (ObjectCollectedExceptionWrapper ocex) {
  561. Exceptions.printStackTrace(ocex);
  562. return ;
  563. } catch (UnsupportedOperationExceptionWrapper uex) {
  564. Exceptions.printStackTrace(uex);
  565. return ;
  566. } catch (VMDisconnectedExceptionWrapper vmdex) {
  567. return ;
  568. }
  569. if (l != null) {
  570. fire = true;
  571. }
  572. }
  573. for (LoggingEventListener ll : listenersToRemove) {
  574. try {
  575. boolean detached = RemoteServices.detachLoggingListener(ci, ll.getListenerClass(), ll.getListenerObject());
  576. synchronized (loggingListeners) {
  577. Set<LoggingEventListener> listeners = loggingListeners.get(ci.getComponent());
  578. if (listeners != null) {
  579. listeners.remove(ll);
  580. if (listeners.isEmpty()) {
  581. loggingListeners.remove(ci.getComponent());
  582. }
  583. }
  584. }
  585. } catch (PropertyVetoException ex) {
  586. Exceptions.printStackTrace(ex);
  587. return;
  588. }
  589. }
  590. if (fire) {
  591. fireNodeChanged(customListeners);
  592. }
  593. }
  594. });
  595. }
  596. private ReferenceType[] selectListenerClass(JavaComponentInfo ci, Collection<LoggingEventListener> listenersToRemove) {
  597. List<ReferenceType> attachableListeners = RemoteServices.getAttachableListeners(ci);
  598. //System.err.println("Attachable Listeners = "+attachableListeners);
  599. Set<LoggingEventListener> currentLoggingListeners = null;
  600. synchronized (loggingListeners) {
  601. Set<LoggingEventListener> listeners = loggingListeners.get(ci.getComponent());
  602. if (listeners != null) {
  603. currentLoggingListeners = new HashSet<LoggingEventListener>(listeners);
  604. }
  605. }
  606. String[] listData = new String[attachableListeners.size()];
  607. boolean[] logging = new boolean[listData.length];
  608. LoggingEventListener[] loggingListeners = null;
  609. if (currentLoggingListeners != null) {
  610. loggingListeners = new LoggingEventListener[listData.length];
  611. }
  612. for (int i = 0; i < listData.length; i++) {
  613. ReferenceType rt = attachableListeners.get(i);
  614. listData[i] = rt.name();
  615. if (currentLoggingListeners != null) {
  616. for (LoggingEventListener ll : currentLoggingListeners) {
  617. if (rt.equals(ll.getListenerClass().reflectedType())) {
  618. logging[i] = true;
  619. loggingListeners[i] = ll;
  620. }
  621. }
  622. }
  623. }
  624. SelectEventsPanel sep = new SelectEventsPanel();
  625. sep.setData(listData, logging);
  626. NotifyDescriptor nd = new DialogDescriptor(sep,
  627. NbBundle.getMessage(EventsModel.class, "TTL_SelectListener"),
  628. true, null);
  629. Object res = DialogDisplayer.getDefault().notify(nd);
  630. if (DialogDescriptor.OK_OPTION.equals(res)) {
  631. boolean[] loggingData = sep.getLoggingData();
  632. int na = 0;
  633. for (int i = 0; i < loggingData.length; i++) {
  634. if (loggingData[i] && !logging[i]) na++;
  635. //if (!loggingData[i] && logging[i]) nr++;
  636. }
  637. ReferenceType[] listenersToAdd = new ReferenceType[na];
  638. int lai = 0;
  639. for (int i = 0; i < listData.length; i++) {
  640. if (loggingData[i] && !logging[i]) {
  641. listenersToAdd[lai++] = attachableListeners.get(i);
  642. }
  643. if (!loggingData[i] && logging[i]) {
  644. listenersToRemove.add(loggingListeners[i]);
  645. }
  646. }
  647. return listenersToAdd;
  648. } else {
  649. return null;
  650. }
  651. }
  652. }
  653. private class AddLoggingListenerAction extends AbstractAction {
  654. private ListenerCategory lc;
  655. public AddLoggingListenerAction(ListenerCategory lc) {
  656. this.lc = lc;
  657. }
  658. @Override
  659. public Object getValue(String key) {
  660. if (Action.NAME.equals(key)) {
  661. return "Add Logging Listener" + ((lc == null) ? "..." : "" );
  662. }
  663. return super.getValue(key);
  664. }
  665. @Override
  666. public void actionPerformed(ActionEvent e) {
  667. final JavaComponentInfo ci = selectedCI;
  668. if (ci == null) return ;
  669. String listenerClass;
  670. if (lc != null) {
  671. listenerClass = lc.getType();
  672. } else {
  673. listenerClass = selectListenerClass(ci);
  674. if (listenerClass == null) {
  675. return;
  676. }
  677. }
  678. final ReferenceType rt = getReferenceType(ci.getComponent().virtualMachine(), listenerClass);
  679. if (rt == null) {
  680. System.err.println("No class "+listenerClass);
  681. return ;
  682. }
  683. ci.getThread().getDebugger().getRequestProcessor().post(new Runnable() {
  684. @Override
  685. public void run() {
  686. ObjectReference l;
  687. try {
  688. ClassObjectReference cor = ReferenceTypeWrapper.classObject(rt);
  689. l = RemoteServices.attachLoggingListener(ci, cor, new LoggingEventListener(EventsModel.this));
  690. } catch (PropertyVetoException pvex) {
  691. Exceptions.printStackTrace(pvex);
  692. return ;
  693. } catch (InternalExceptionWrapper iex) {
  694. return ;
  695. } catch (ObjectCollectedExceptionWrapper ocex) {
  696. Exceptions.printStackTrace(ocex);
  697. return ;
  698. } catch (UnsupportedOperationExceptionWrapper uex) {
  699. Exceptions.printStackTrace(uex);
  700. return ;
  701. } catch (VMDisconnectedExceptionWrapper vmdex) {
  702. return ;
  703. }
  704. if (l != null) {
  705. if (lc != null) {
  706. String name;
  707. try {
  708. name = ReferenceTypeWrapper.name(ObjectReferenceWrapper.referenceType(l));
  709. } catch (InternalExceptionWrapper ex) {
  710. return ;
  711. } catch (VMDisconnectedExceptionWrapper ex) {
  712. return ;
  713. } catch (ObjectCollectedExceptionWrapper ex) {
  714. Exceptions.printStackTrace(ex);
  715. return ;
  716. }
  717. lc.addListener(new RemoteListener(name, l));
  718. fireNodeChanged(lc);
  719. } else {
  720. fireNodeChanged(customListeners);
  721. }
  722. }
  723. }
  724. });
  725. }
  726. private ReferenceType getReferenceType(VirtualMachine vm, String name) {
  727. ReferenceType clazz = null;
  728. try {
  729. List<ReferenceType> classList = VirtualMachineWrapper.classesByName(vm, name);
  730. for (ReferenceType c : classList) {
  731. clazz = c;
  732. if (ReferenceTypeWrapper.classLoader(c) == null) {
  733. break;
  734. }
  735. }
  736. } catch (ObjectCollectedExceptionWrapper ocex) {
  737. } catch (InternalExceptionWrapper ex) {
  738. } catch (VMDisconnectedExceptionWrapper ex) {
  739. }
  740. return clazz;
  741. }
  742. private String selectListenerClass(JavaComponentInfo ci) {
  743. List<ReferenceType> attachableListeners = RemoteServices.getAttachableListeners(ci);
  744. //System.err.println("Attachable Listeners = "+attachableListeners);
  745. String[] listData = new String[attachableListeners.size()];
  746. for (int i = 0; i < listData.length; i++) {
  747. listData[i] = attachableListeners.get(i).name();
  748. }
  749. JList jl = new JList(listData);
  750. JScrollPane jsp = new JScrollPane(jl);
  751. NotifyDescriptor nd = new DialogDescriptor(jsp,
  752. NbBundle.getMessage(EventsModel.class, "TTL_SelectListener"),
  753. true, null);
  754. Object res = DialogDisplayer.getDefault().notify(nd);
  755. if (DialogDescriptor.OK_OPTION.equals(res)) {
  756. String clazz = (String) jl.getSelectedValue();
  757. return clazz;
  758. } else {
  759. return null;
  760. }
  761. }
  762. }
  763. private class ClearEventsAction extends AbstractAction {
  764. @Override
  765. public Object getValue(String key) {
  766. if (Action.NAME.equals(key)) {
  767. return NbBundle.getMessage(EventsModel.class, "CTL_ClearEvents");
  768. }
  769. return super.getValue(key);
  770. }
  771. @Override
  772. public void actionPerformed(ActionEvent e) {
  773. synchronized (events) {
  774. events.clear();
  775. }
  776. fireNodeChanged(eventsLog);
  777. }
  778. }
  779. private static class LoggingEventListener implements RemoteServices.LoggingListenerCallBack {
  780. private ObjectReference listener;
  781. private ClassObjectReference listenerClass;
  782. private final Reference<EventsModel> modelRef;
  783. public LoggingEventListener(EventsModel model) {
  784. modelRef = new WeakReference<EventsModel>(model);
  785. }
  786. @Override
  787. public void eventsData(/*JavaComponentInfo ci,*/ String[] data, String[] stack) {
  788. RemoteEvent re = new RemoteEvent(data, stack);
  789. /*
  790. System.err.println("Have data about "+ci.getType()+":");//\n "+Arrays.toString(data));
  791. System.err.println(" Method: "+data[0]+", event toString() = "+data[1]);
  792. for (int j = 2; j < data.length; j += 2) {
  793. System.err.println(" "+data[j]+" = "+data[j+1]);
  794. }
  795. */
  796. EventsModel model = modelRef.get();
  797. if (model != null) {
  798. model.addEvent(re);
  799. }
  800. }
  801. private void setListenerObject(ObjectReference listener, ClassObjectReference listenerClass) {
  802. this.listener = listener;
  803. this.listenerClass = listenerClass;
  804. }
  805. public ObjectReference getListenerObject() {
  806. return listener;
  807. }
  808. public ClassObjectReference getListenerClass() {
  809. return listenerClass;
  810. }
  811. }
  812. private static class RemoteEvent {
  813. private String[] data;
  814. private Stack stack;
  815. public RemoteEvent(String[] data, String[] stack) {
  816. this.data = data;
  817. this.stack = new Stack(stack);
  818. }
  819. public String getListenerMethod() {
  820. return data[0];
  821. }
  822. public String getEventToString() {
  823. return data[1];
  824. }
  825. public Object[] getPropertiesWithStackNode() {
  826. int propertiesLength = data.length/2 - 1;
  827. Object[] properties = new Object[propertiesLength + 1];
  828. for (int i = 0; i < propertiesLength; i++) {
  829. properties[i + 1] = data[2 + 2*i] + " = "+data[3 + 2*i];
  830. }
  831. properties[0] = stack;
  832. return properties;
  833. }
  834. public Stack getStack() {
  835. return stack;
  836. }
  837. }
  838. private static class Stack {
  839. private String[] stack;
  840. private String listener = null;
  841. private Element[] elements = null;
  842. public Stack(String[] stack) {
  843. this.stack = stack;
  844. }
  845. public synchronized Element[] getStackElements() {
  846. if (elements == null) {
  847. elements = new Element[stack.length - 1];
  848. for (int i = 1; i < stack.length; i++) {
  849. elements[i - 1] = new Element(stack[i]);
  850. }
  851. }
  852. return elements;
  853. }
  854. static class Element {
  855. private String line;
  856. private boolean parsed = false;
  857. private String className;
  858. private String methodName;
  859. private String fileName;
  860. private int lineNumber;
  861. // <class name>.<method>(<file name>:<line number>)
  862. public Element(String line) {
  863. this.line = line;
  864. }
  865. private synchronized void parse() {
  866. if (parsed) return;
  867. int i = line.indexOf('(');
  868. int mi = line.substring(0, i).lastIndexOf('.');
  869. int ci = line.lastIndexOf(':');
  870. className = line.substring(0, mi);
  871. methodName = line.substring(mi + 1, i);
  872. fileName = line.substring(i + 1, ci);
  873. String lineStr = line.substring(ci + 1, line.length() - 1);
  874. lineNumber = Integer.parseInt(lineStr);
  875. }
  876. public String getClassName() {
  877. parse();
  878. return className;
  879. }
  880. public String getMethodName() {
  881. parse();
  882. return methodName;
  883. }
  884. public String getFileName() {
  885. parse();
  886. return fileName;
  887. }
  888. public int getLineNumber() {
  889. parse();
  890. return lineNumber;
  891. }
  892. }
  893. }
  894. }