blob: bad76521f65a668db7d4d5ff39ccd5d62a9d77cc [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.test.ide;
import com.sun.management.HotSpotDiagnosticMXBean;
import java.awt.*;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import junit.framework.Assert;
import junit.framework.AssertionFailedError;
import org.netbeans.api.java.source.ui.ScanDialog;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ui.OpenProjects;
import org.netbeans.junit.Log;
import org.openide.cookies.EditorCookie;
import org.openide.explorer.view.TreeView;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions;
import org.openide.util.Lookup;
import org.openide.windows.TopComponent;
/**
*
* @author Jaroslav Tulach <jtulach@netbeans.org>
*/
public final class WatchProjects {
private static Logger LOG = Logger.getLogger(WatchProjects.class.getName());
private WatchProjects() {
}
public static void initialize() throws Exception {
Log.enableInstances(Logger.getLogger("TIMER"), "Project", Level.FINEST);
}
private static void cleanWellKnownStaticFields() throws Exception {
Object o;
// resetJTreeUIs(Frame.getFrames());
tryCloseNavigator();
StringSelection ss = new StringSelection("");
Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss, ss);
// Toolkit.getDefaultToolkit().getSystemSelection().setContents(ss, ss);
// fix for Issue 146901
Clipboard clipBoard = Toolkit.getDefaultToolkit().getSystemSelection();
if (clipBoard != null) {
clipBoard.setContents(ss, ss);
}
Clipboard cc = Lookup.getDefault().lookup(Clipboard.class);
Assert.assertNotNull("There is a clipboard in lookup", cc);
cc.setContents(ss, ss);
for (Frame f : Frame.getFrames()) {
clearInstanceField( f, "java.awt.Container", "dispatcher" );
}
// XXX: uncommented because of the csl.api & related changes
JFrame empty = new JFrame("Clear");
empty.getContentPane().setLayout(new FlowLayout());
empty.getContentPane().add(new JEditorPane());
empty.pack();
empty.setVisible(true);
empty.requestFocusInWindow();
// --------------------------------------------------------
clearField("sun.awt.im.InputContext", "previousInputMethod");
clearField("sun.awt.im.InputContext", "inputMethodWindowContext");
clearField("sun.awt.im.CompositionAreaHandler", "compositionAreaOwner");
// clearField("sun.awt.AppContext", "mainAppContext");
// clearField("org.netbeans.modules.beans.BeanPanel", "INSTANCE");
clearField("java.awt.KeyboardFocusManager", "focusedWindow");
clearField("java.awt.KeyboardFocusManager", "activeWindow");
clearField("java.awt.KeyboardFocusManager", "focusOwner");
clearField("java.awt.KeyboardFocusManager", "permanentFocusOwner");
clearField("java.awt.KeyboardFocusManager", "newFocusOwner");
clearField("java.awt.KeyboardFocusManager", "currentFocusCycleRoot");
// clearField("org.netbeans.jemmy.EventTool", "listenerSet");
clearField("sun.awt.X11.XKeyboardFocusManagerPeer", "currentFocusOwner");
clearField("sun.awt.X11.XKeyboardFocusManagerPeer", "currentFocusedWindow");
// clearField("org.netbeans.modules.java.navigation.CaretListeningFactory", "INSATNCE");
// clearField("org.netbeans.modules.editor.hints.HintsUI", "INSTANCE");
// clearField("org.netbeans.modules.websvc.core.ProjectWebServiceView", "views");
// clearField("org.netbeans.api.java.source.support.OpenedEditors", "DEFAULT");
// clearField("org.netbeans.spi.palette.PaletteSwitch", "theInstance");
// clearField("org.netbeans.core.NbMainExplorer$MainTab", "lastActivated");
// clearField("org.netbeans.core.NbMainExplorer$MainTab", "DEFAULT");
/*
o = getFieldValue("org.netbeans.api.java.source.JavaSource", "toRemove");
if (o instanceof Collection) {
Collection c = (Collection) o;
c.clear();
}
o = getFieldValue("org.netbeans.api.java.source.JavaSource", "requests");
if (o instanceof Collection) {
Collection c = (Collection) o;
c.clear();
}
*/
clearField("sun.awt.im.InputContext", "previousInputMethod");
clearField("sun.awt.im.InputContext", "inputMethodWindowContext");
}
public static void assertTextDocuments() throws Exception {
for (TopComponent tc : new ArrayList<TopComponent>(TopComponent.getRegistry().getOpened())) {
final EditorCookie ec = tc.getLookup().lookup(EditorCookie.class);
if (ec != null) {
ec.close();
}
}
EventQueue.invokeAndWait(new Runnable() {
public void run() {
TopComponent tc = new TopComponent();
tc.setLayout(new FlowLayout());
tc.add(new JTextArea());
tc.open();
tc.requestVisible();
tc.requestActive();
String jVMversion = System.getProperty("java.specification.version");
System.out.println("Java.specification.version="+jVMversion);
if (!("1.8".equals(jVMversion))) {
try {
System.out.println("Cleaning well known static fields");
cleanWellKnownStaticFields();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
System.setProperty("assertgc.paths", "5");
try {
Thread.sleep(4000);
} catch (InterruptedException exc) {
Exceptions.printStackTrace(exc);
}
try {
Log.assertInstances("Are all documents GCed?", "TextDocument");
} finally {
dumpHeap(null);
}
}
});
}
public static void assertProjects() throws Exception {
Object o;
OpenProjects.getDefault().close(
OpenProjects.getDefault().getOpenProjects()
);
Project p = new Project() {
public FileObject getProjectDirectory() {
return FileUtil.getConfigRoot();
}
public Lookup getLookup() {
return Lookup.EMPTY;
}
};
try {
OpenProjects.getDefault().open(new Project[] { p }, false);
} catch (AssertionError ae) {
System.out.println("Excepton during creation of fake project:");
ae.printStackTrace();
}
try {
OpenProjects.getDefault().setMainProject(p);
} catch (AssertionError ae) {
System.out.println("Excepton during setting of fake project as main:");
ae.printStackTrace();
}
for (int i = 0; i < 10; i++) {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
}
}
});
}
EventQueue.invokeAndWait(new Runnable() {
public void run() {
try {
cleanWellKnownStaticFields();
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
if (Boolean.getBoolean("ignore.random.failures")) {
// remove the if we don't care about random failures
// reported as #
//removeTreeView(Frame.getFrames());
}
System.setProperty("assertgc.paths", "5");
try {
Log.assertInstances("Checking if all projects are really garbage collected", "Project");
} catch (AssertionFailedError t) {
Logger.getLogger(WatchProjects.class.getName()).warning(t.getMessage());
if (!Boolean.getBoolean("ignore.random.failures")) {
throw t;
}
} finally {
dumpHeap(null);
try {
Thread.sleep(4000);
} catch (InterruptedException exc) {
Exceptions.printStackTrace(exc);
}
try {
printTreeView(Frame.getFrames());
} catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
}
});
}
private static int printTreeView(Component[] arr) throws Exception {
int cnt = 0;
StringBuilder str = new StringBuilder();
for (Component c : arr) {
if (c instanceof TreeView) {
Set<?> set = (Set<?>) getField(TreeView.class, "visHolder").get(c);
if (!set.isEmpty()) {
cnt += set.size();
str.append("visHolder for TreeView in '" + c.getParent().getName() + "':");
for (Object o : set) {
str.append(o);
}
}
continue;
}
if (c instanceof Container) {
Container o = (Container)c;
cnt += printTreeView(o.getComponents());
}
}
if (str.length() > 0) {
Logger.getLogger(WatchProjects.class.getName()).warning(str.toString());
}
return cnt;
}
private static void removeTreeView(Component[] arr) throws Exception {
for (Component c : arr) {
if (c instanceof TreeView) {
Set<?> set = (Set<?>) getField(TreeView.class, "visHolder").get(c);
set.clear();
continue;
}
if (c instanceof Container) {
Container o = (Container)c;
removeTreeView(o.getComponents());
}
}
}
private static void resetJTreeUIs(Component[] arr) {
for (Component c : arr) {
if (c instanceof JTree) {
JTree jt = (JTree)c;
jt.updateUI();
}
if (c instanceof Container) {
Container o = (Container)c;
resetJTreeUIs(o.getComponents());
}
}
}
/**
* #124061 workaround - close navigator before tests
*/
private static void tryCloseNavigator() throws Exception {
for (TopComponent c : new ArrayList<TopComponent>(TopComponent.getRegistry().getOpened())) {
LOG.fine("Processing TC " + c.getDisplayName() + "class " + c.getClass().getName());
if (c.getClass().getName().equals("org.netbeans.modules.navigator.NavigatorTC")) {
final TopComponent navigator = c;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
navigator.close();
}
});
LOG.fine("tryCloseNavigator: Navigator closed, OK!");
break;
}
}
clearField("org.netbeans.modules.navigator.NavigatorTC", "instance");
clearField("org.netbeans.modules.navigator.ProviderRegistry","instance");
}
private static Object clearField(String clazz, String... name) throws Exception {
return clearInstanceField(null, clazz, name);
}
private static Object getFieldValue(String clazz, String... name) throws Exception {
Object ret = null;
for (int i = 0; i < name.length; i++) {
Field f = i == 0 ? getField(clazz, name[0]) : getField(ret.getClass(), name[i]);
ret = f.get(ret);
}
return ret;
}
private static Field getField(String clazz, String name) throws NoSuchFieldException, ClassNotFoundException {
ClassLoader l = Thread.currentThread().getContextClassLoader();
if (l == null) {
l = WatchProjects.class.getClassLoader();
}
Class<?> c = Class.forName(clazz, true, l);
return getField(c, name);
}
private static Field getField(Class<?> clazz, String name) throws NoSuchFieldException {
Field f = clazz.getDeclaredField(name);
f.setAccessible(true);
return f;
}
private static Object clearInstanceField(Object obj, String clazz, String... name) throws Exception {
Object ret = obj;
for (int i = 0; i < name.length; i++) {
Field f;
try {
f = i == 0 ? getField(clazz, name[0]) : getField(ret.getClass(), name[i]);
} catch (NoSuchFieldException ex) {
LOG.log(Level.WARNING, "Cannot get " + name[i]);
continue;
} catch (ClassNotFoundException ex) {
LOG.log(Level.WARNING, "Cannot class " + clazz);
continue;
}
Object now = ret;
ret = f.get(now);
for (int tryHarder = 0;; tryHarder++) {
f.set(now, null);
if (f.get(now) == null) {
break;
}
if (tryHarder == 10) {
Assert.fail("Field is really cleared " + f + " but was: " + f.get(now));
}
Thread.sleep(100);
}
if (ret == null) {
LOG.info("Getting " + f + " from " + now + " returned null");
break;
}
}
return ret;
}
private static void dumpHeap(String path) {
System.out.println("DUMPING HEAP");
Method m = null;
Class c = null;
HotSpotDiagnosticMXBean hdmxb=null;
try {
c = Class.forName("sun.management.ManagementFactoryHelper");//NOI18N
} catch (ClassNotFoundException exc) {
System.out.println(exc.getMessage());
try {
c = Class.forName("sun.management.ManagementFactory");//NOI18N
} catch (ClassNotFoundException ex1) {
System.out.println(ex1.getMessage());
}
}
if (c!=null) {
try {
m= c.getMethod("getDiagnosticMXBean");//NOI18N
} catch (NoSuchMethodException exc) {
System.out.println(exc.getMessage());
} catch (SecurityException exc) {
System.out.println(exc.getMessage());
}
}
if (m!=null) {
try {
hdmxb= (HotSpotDiagnosticMXBean)m.invoke(null);
} catch (IllegalAccessException ex) {
Exceptions.printStackTrace(ex);
} catch (IllegalArgumentException ex) {
Exceptions.printStackTrace(ex);
} catch (InvocationTargetException ex) {
Exceptions.printStackTrace(ex);
}
long i = System.currentTimeMillis();
if (path==null || "".equals(path)) {
path=System.getProperty("nbjunit.workdir")+File.separator+"Heapdump"+i+".hprof";
}
System.out.println("Creating heap dump, target directory="+path);
try {
hdmxb.dumpHeap(path, true);
System.out.println("Heap dump successfully created in: "+path);
} catch (IOException ioe) {
System.out.println(ioe.getMessage());
}
}
}
public static void waitScanFinished() {
try {
class Wait implements Runnable {
boolean initialized;
boolean ok;
public void run() {
if (initialized) {
ok = true;
return;
}
initialized = true;
boolean canceled = ScanDialog.runWhenScanFinished(this, "tests");
Assert.assertFalse("Dialog really finished", canceled);
Assert.assertTrue("Runnable run", ok);
}
}
Wait wait = new Wait();
SwingUtilities.invokeAndWait(wait);
} catch (Exception ex) {
throw (AssertionFailedError)new AssertionFailedError().initCause(ex);
}
}
}