org.netbeans.modules.uihandler.Installer Maven / Gradle / Ivy
/*
* 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.modules.uihandler;
import com.sun.management.HotSpotDiagnosticMXBean;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.text.MessageFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.prefs.BackingStoreException;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPOutputStream;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.swing.*;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkListener;
import javax.xml.parsers.ParserConfigurationException;
import org.netbeans.api.options.OptionsDisplayer;
import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory;
import org.netbeans.lib.uihandler.LogRecords;
import org.netbeans.lib.uihandler.PasswdEncryption;
import org.netbeans.modules.exceptions.ExceptionsSettings;
import org.netbeans.modules.exceptions.ReportPanel;
import org.netbeans.modules.exceptions.ReporterResultTopComponent;
import org.netbeans.modules.uihandler.api.Activated;
import org.netbeans.modules.uihandler.api.Deactivated;
import org.openide.DialogDescriptor;
import org.openide.DialogDisplayer;
import org.openide.NotifyDescriptor;
import org.openide.awt.HtmlBrowser;
import org.openide.awt.Mnemonics;
import org.openide.filesystems.FileLock;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.modules.ModuleInfo;
import org.openide.modules.ModuleInstall;
import org.openide.modules.Places;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.*;
import org.openide.util.io.NullOutputStream;
import org.openide.windows.WindowManager;
import org.xml.sax.SAXException;
/**
* Registers and unregisters loggers.
*/
public class Installer extends ModuleInstall implements Runnable {
static final String IDE_STARTUP = "IDE_STARTUP";
static final long serialVersionUID = 1L;
static final String USER_CONFIGURATION = "UI_USER_CONFIGURATION"; // NOI18N
private static UIHandler ui = new UIHandler(false);
private static UIHandler handler = new UIHandler(true);
private static MetricsHandler metrics = new MetricsHandler();
private static Logger uiLogger;
private static Logger allLogger;
private static Logger metricsLogger;
static final Logger LOG = Logger.getLogger(Installer.class.getName());
public static final RequestProcessor RP = new RequestProcessor("UI Gestures"); // NOI18N
public static final RequestProcessor RP_UI = new RequestProcessor("UI Gestures - Create Dialog"); // NOI18N
public static final RequestProcessor RP_SUBMIT = new RequestProcessor("UI Gestures - Submit Data", 2); // NOI18N
public static RequestProcessor RP_OPT = null;
private static final Preferences prefs = NbPreferences.forModule(Installer.class);
private static OutputStream logStream;
private static OutputStream logStreamMetrics;
private static int logsSize;
private static int logsSizeMetrics;
private static long logsFirstDateMetric;
private static URL hintURL;
private static Object[] selectedExcParams;
private static boolean logMetricsEnabled = false;
/** Flag to store status of last metrics upload */
private static boolean logMetricsUploadFailed = false;
/** Log records currently displaying/uploading */
private static final ThreadLocal> logRecords = new ThreadLocal<>();
private static final String USAGE_STATISTICS_ENABLED = "usageStatisticsEnabled"; // NOI18N
private static final String USAGE_STATISTICS_SET_BY_IDE = "usageStatisticsSetByIde"; // NOI18N
private static final String USAGE_STATISTICS_NB_OF_IDE_STARTS = "usageStatisticsNbOfIdeStarts"; // NOI18N
private static final String FIRST_DATE_METRICS_PROP = "firstDateMetric"; // NOI18N
private static final String CORE_PREF_NODE = "org/netbeans/core"; // NOI18N
private static final Preferences corePref = NbPreferences.root().node (CORE_PREF_NODE);
private static final String CMD_METRICS_ENABLE = "MetricsEnable"; // NOI18N
private static final String CMD_METRICS_CANCEL = "MetricsCancel"; // NOI18N
private static final String MIXED_CT_BOUNDARY = "--------konec<>bloku"; // NOI18N
// End of block pattern
private static final String END_OF_BLOCK = "--"+MIXED_CT_BOUNDARY; // NOI18N
// End of data block pattern
private static final String END_OF_DATA_BLOCK = "\n\n"+END_OF_BLOCK; // NOI18N
private final AtomicBoolean restored = new AtomicBoolean(false);
/** Action listener for Usage Statistics Reminder dialog */
private ActionListener l = new ActionListener () {
@Override
public void actionPerformed (ActionEvent ev) {
cmd = ev.getActionCommand();
if (CMD_METRICS_ENABLE.equals(cmd)) {
corePref.putBoolean(USAGE_STATISTICS_ENABLED, true);
} else if (CMD_METRICS_CANCEL.equals(cmd)) {
corePref.putBoolean(USAGE_STATISTICS_ENABLED, false);
}
corePref.putBoolean(USAGE_STATISTICS_SET_BY_IDE, true);
}
};
private String cmd;
static final String METRICS_LOGGER_NAME = NbBundle.getMessage(Installer.class, "METRICS_LOGGER_NAME");
static final String UI_LOGGER_NAME = NbBundle.getMessage(Installer.class, "UI_LOGGER_NAME");
static final String UI_PERFORMANCE_LOGGER_NAME = NbBundle.getMessage(Installer.class, "UI_PERFORMANCE_LOGGER_NAME");
private static Pattern ENCODING = Pattern.compile(
"", Pattern.CASE_INSENSITIVE
); // NOI18N
static boolean preferencesWritable = false;
static final String preferencesWritableKey = "uihandler.preferences.writable.check"; // NOI18N
static {
// #131128 - suppress repetitive exceptions when config/Preferences/org/netbeans/modules/uihandler.properties
// is not writable for some reason
long checkTime = System.currentTimeMillis();
try {
prefs.putLong(preferencesWritableKey, checkTime);
} catch (IllegalArgumentException iae) {
// #164580 - ignore IllegalArgumentException: Malformed \\uxxxx encoding.
// prefs are now empty, so put again and rewrite broken content.
prefs.putLong(preferencesWritableKey, checkTime);
}
try {
prefs.flush();
prefs.sync();
if(checkTime == prefs.getLong(preferencesWritableKey, 0)) { //NOI18N
preferencesWritable = true;
}
} catch (BackingStoreException e) {
// immediatelly show dialog with exception (usually Access is denied)
Exceptions.printStackTrace(e);
}
}
/**
* Used to synchronize access to ui log files to avoid writing to/deleting/renaming file
* which is being parsed in another thread.
*/
private static final Object UIGESTURE_LOG_LOCK = new Object();
/**
* Used to synchronize access to metrics log files to avoid writing to/deleting/renaming file
* which is being parsed in another thread.
*/
private static final Object METRICS_LOG_LOCK = new Object();
static enum DataType {
DATA_UIGESTURE,
DATA_METRICS
};
@Override
public void restored() {
EarlyHandler eh = Lookup.getDefault().lookup(EarlyHandler.class);
restored(eh.earlyRecords);
}
void restored(java.util.Queue earlyRecords) {
synchronized (restored) {
if (!restored.getAndSet(true)) {
restoredOnce(earlyRecords);
} else {
logEarlyRecords(earlyRecords);
}
}
}
private void restoredOnce(java.util.Queue earlyRecords) {
TimeToFailure.logAction();
Logger log = Logger.getLogger(UI_LOGGER_NAME);
log.setUseParentHandlers(false);
log.setLevel(Level.FINEST);
log.addHandler(ui);
uiLogger = log; // To prevent from GC
Logger all = Logger.getLogger("");
all.addHandler(handler);
allLogger = all; // To prevent from GC
logsSize = prefs.getInt("count", 0);
logsSizeMetrics = prefs.getInt("countMetrics", 0);
logsFirstDateMetric = prefs.getLong(FIRST_DATE_METRICS_PROP, -1);
logMetricsUploadFailed = prefs.getBoolean("metrics.upload.failed", false); // NOI18N
corePref.addPreferenceChangeListener(new PrefChangeListener());
if (!Boolean.getBoolean("netbeans.full.hack") && !Boolean.getBoolean("netbeans.close")) {
usageStatisticsReminder();
}
System.setProperty("nb.show.statistics.ui",USAGE_STATISTICS_ENABLED);
logMetricsEnabled = corePref.getBoolean(USAGE_STATISTICS_ENABLED, false);
if (logMetricsEnabled) {
//Handler for metrics
log = Logger.getLogger(METRICS_LOGGER_NAME);
log.setUseParentHandlers(true);
log.setLevel(Level.FINEST);
log.addHandler(metrics);
metricsLogger = log; // To prevent from GC
try {
LogRecord userData = getUserData(log);
LogRecords.write(logStreamMetrics(), userData);
List enabledRec = new ArrayList<>();
List disabledRec = new ArrayList<>();
getModuleList(log, enabledRec, disabledRec);
for (LogRecord rec : enabledRec) {
LogRecords.write(logStreamMetrics(), rec);
}
for (LogRecord rec : disabledRec) {
LogRecords.write(logStreamMetrics(), rec);
}
LogRecord clusterRec = EnabledModulesCollector.getClusterList(log);
LogRecords.write(logStreamMetrics(), clusterRec);
LogRecord userInstalledRec = EnabledModulesCollector.getUserInstalledModules(log);
LogRecords.write(logStreamMetrics(), userInstalledRec);
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
EarlyHandler.disable();
CPUInfo.logCPUInfo();
ScreenSize.logScreenSize();
logIdeStartup();
logEarlyRecords(earlyRecords);
for (Activated a : Lookup.getDefault().lookupAll(Activated.class)) {
a.activated(log);
}
if (logsSize >= UIHandler.MAX_LOGS) {
WindowManager.getDefault().invokeWhenUIReady(this);
}
}
private void logEarlyRecords(java.util.Queue earlyRecords) {
if (earlyRecords != null) {
List allRecords;
synchronized (earlyRecords) {
allRecords = new ArrayList<>(earlyRecords);
earlyRecords.clear();
}
List uiRecords = extractRecords(allRecords, UI_LOGGER_NAME);
ui.publishEarlyRecords(uiRecords);
handler.publishEarlyRecords(allRecords);
if (logMetricsEnabled) {
List metricsRecords = extractRecords(allRecords, METRICS_LOGGER_NAME);
metrics.publishEarlyRecords(metricsRecords);
}
}
}
private List extractRecords(List records, String logger) {
List records2 = new ArrayList<>();
for (LogRecord r : records) {
if (r.getLoggerName().startsWith(logger)) {
records2.add(r);
}
}
return records2;
}
/** Accessed from tests. */
static int getLogsSizeTest() {
return logsSize;
}
private void logIdeStartup() {
Logger.getLogger(UI_LOGGER_NAME).log(new LogRecord(Level.CONFIG, IDE_STARTUP));
}
private void usageStatisticsReminder () {
//Increment number of IDE starts, stop at 4 because we are interested at second start
long nbOfIdeStarts = corePref.getLong(USAGE_STATISTICS_NB_OF_IDE_STARTS, 0);
nbOfIdeStarts++;
if (nbOfIdeStarts < 4) {
corePref.putLong(USAGE_STATISTICS_NB_OF_IDE_STARTS, nbOfIdeStarts);
}
boolean setByIde = corePref.getBoolean(USAGE_STATISTICS_SET_BY_IDE, false);
boolean usageEnabled = corePref.getBoolean(USAGE_STATISTICS_ENABLED, false);
//If "usageStatisticsEnabled" was set by IDE do not ask again.
if (setByIde) {
return;
}
//If "usageStatisticsEnabled" was not set by IDE, it is false and it is second start ask again
if (!setByIde && !usageEnabled && (nbOfIdeStarts == 2)) {
WindowManager.getDefault().invokeWhenUIReady(new Runnable() {
@Override
public void run() {
showDialog();
}
});
}
}
private void showDialog () {
final JPanel panel = new ReminderPanel();
JButton metricsEnable = new JButton();
metricsEnable.addActionListener(l);
metricsEnable.setActionCommand(CMD_METRICS_ENABLE);
//registerNow.setText(NbBundle.getMessage(RegisterAction.class,"LBL_RegisterNow"));
Mnemonics.setLocalizedText(metricsEnable, NbBundle.getMessage(
Installer.class, "LBL_MetricsEnable"));
metricsEnable.getAccessibleContext().setAccessibleName(
NbBundle.getMessage(Installer.class,"ACSN_MetricsEnable"));
metricsEnable.getAccessibleContext().setAccessibleDescription(
NbBundle.getMessage(Installer.class,"ACSD_MetricsEnable"));
JButton metricsCancel = new JButton();
metricsCancel.addActionListener(l);
metricsCancel.setActionCommand(CMD_METRICS_CANCEL);
//registerLater.setText(NbBundle.getMessage(RegisterAction.class,"LBL_RegisterLater"));
Mnemonics.setLocalizedText(metricsCancel, NbBundle.getMessage(
Installer.class, "LBL_MetricsCancel"));
metricsCancel.getAccessibleContext().setAccessibleName(
NbBundle.getMessage(Installer.class,"ACSN_MetricsCancel"));
metricsCancel.getAccessibleContext().setAccessibleDescription(
NbBundle.getMessage(Installer.class,"ACSD_MetricsCancel"));
DialogDescriptor descriptor = new DialogDescriptor(
panel,
NbBundle.getMessage(Installer.class, "Metrics_title"),
true,
new Object[] {metricsEnable, metricsCancel},
null,
DialogDescriptor.DEFAULT_ALIGN,
null,
null);
Dialog dlg = null;
try {
dlg = DialogDisplayer.getDefault().createDialog(descriptor);
final Dialog d = dlg;
dlg.addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
BufferedImage offImg;
offImg = (BufferedImage) panel.createImage(1000,1000);
Graphics g = offImg.createGraphics();
panel.paint(g);
int height = d.getPreferredSize().height;
Dimension size = d.getSize();
size.height = height;
d.setSize(size);
}
});
dlg.setResizable(false);
dlg.setVisible(true);
} finally {
if (dlg != null) {
dlg.dispose();
}
}
//NbConnection.updateStatus(cmd,NbInstaller.PRODUCT_ID);
}
@Override
public void run() {
if (RP.isRequestProcessorThread()) {
displaySummary("INIT_URL", false, false, false); // NOI18N
} else {
RP.post(this);
}
}
@Override
public void uninstalled() {
doClose();
}
@Override
public final void close() {
UIHandler.flushImmediatelly();
closeLogStream();
MetricsHandler.flushImmediatelly();
closeLogStreamMetrics();
}
public final void doClose() {
Logger log = Logger.getLogger(UI_LOGGER_NAME);
log.removeHandler(ui);
uiLogger = null;
Logger all = Logger.getLogger(""); // NOI18N
all.removeHandler(handler);
allLogger = null;
log = Logger.getLogger(METRICS_LOGGER_NAME);
log.removeHandler(metrics);
metricsLogger = null;
closeLogStream();
closeLogStreamMetrics();
synchronized (restored) {
restored.set(false);
}
}
static boolean isImmediateWriteOut(LogRecord r) {
List preferredLog = logRecords.get();
if (preferredLog != null) {
preferredLog.add(r);
return true;
} else {
return false;
}
}
static void writeOut(LogRecord r) {
try {
boolean logOverflow;
boolean logSizeControl;
List logs = null;
synchronized (UIGESTURE_LOG_LOCK) {
LogRecords.write(logStream(), r);
logsSize++;
logOverflow = logsSize > UIHandler.MAX_LOGS;
if (preferencesWritable) {
if (logOverflow) {
prefs.putInt("count", UIHandler.MAX_LOGS);
} else if (prefs.getInt("count", 0) < logsSize) {
prefs.putInt("count", logsSize);
}
}
if (logOverflow) {
closeLogStream();
if (isHintsMode()) {
logs = new ArrayList<>(getLogs());
}
}
logSizeControl = (logsSize % 100) == 0 && !logOverflow;
}
if (logOverflow) {
if (isHintsMode()) {
final List recs = logs;
class Auto implements Runnable {
@Override
public void run() {
displaySummary("WELCOME_URL", true, true,true, DataType.DATA_UIGESTURE, recs, null);
}
}
RP.post(new Auto()).waitFinished();
}
synchronized (UIGESTURE_LOG_LOCK) {
File f = logFile(0);
File f1 = logFile(1);
if (f1.exists()) {
f1.delete();
}
f.renameTo(f1);
logsSize = 0;
}
}
if (logSizeControl) {
synchronized (UIGESTURE_LOG_LOCK) {
//This is fallback to avoid growing log file over any limit.
File f = logFile(0);
File f1 = logFile(1);
if (f.exists() && (f.length() > UIHandler.MAX_LOGS_SIZE)) {
LOG.log(Level.INFO, "UIGesture Collector log file size is over limit. It will be deleted."); // NOI18N
LOG.log(Level.INFO, "Log file:{0} Size:{1} Bytes", new Object[]{f, f.length()}); // NOI18N
closeLogStream();
logsSize = 0;
if (preferencesWritable) {
prefs.putInt("count", logsSize);
}
f.delete();
}
if (f1.exists() && (f1.length() > UIHandler.MAX_LOGS_SIZE)) {
LOG.log(Level.INFO, "UIGesture Collector backup log file size is over limit. It will be deleted."); // NOI18N
LOG.log(Level.INFO, "Log file:{0} Size:{1} Bytes", new Object[]{f1, f1.length()}); // NOI18N
f1.delete();
}
}
}
} catch (IOException ex) {
// bug #183331 don't log throwable here since it causes recursive writeOut invocation
LOG.log(Level.INFO, "UIGesture Collector logging has failed: {0}", ex.getMessage()); // NOI18N
}
}
private static LogRecord getUserData (Logger logger) {
LogRecord userData;
ArrayList params = new ArrayList<>();
params.add(Submit.getOS());
params.add(Submit.getVM());
params.add(Submit.getVersion());
List buildInfo = BuildInfo.logBuildInfo();
if (buildInfo != null) {
params.addAll(buildInfo);
}
userData = new LogRecord(Level.INFO, "USG_SYSTEM_CONFIG");
userData.setParameters(params.toArray());
userData.setLoggerName(logger.getName());
return userData;
}
private static boolean uploadMetricsTest() {
if (logsSizeMetrics >= MetricsHandler.MAX_LOGS) {
return true;
}
int daysSinceFirstMetric = (int) ((System.currentTimeMillis() - logsFirstDateMetric)/(1000*60*60*24));
if (daysSinceFirstMetric > MetricsHandler.MAX_DAYS) {
return true;
}
return false;
}
static void writeOutMetrics (LogRecord r) {
try {
boolean upload;
synchronized (METRICS_LOG_LOCK) {
LogRecords.write(logStreamMetrics(), r);
logsSizeMetrics++;
boolean firstDateMetric = logsFirstDateMetric < 0;
if (firstDateMetric) {
logsFirstDateMetric = System.currentTimeMillis();
}
if (preferencesWritable) {
prefs.putInt("countMetrics", logsSizeMetrics);
if (firstDateMetric) {
prefs.putLong(FIRST_DATE_METRICS_PROP, logsFirstDateMetric);
}
}
upload = uploadMetricsTest();
if (upload) {
MetricsHandler.waitFlushed();
closeLogStreamMetrics();
File f = logFileMetrics(0);
File f1 = logFileMetrics(1);
if (f1.exists()) {
if (logMetricsUploadFailed) {
//If last metrics upload failed first check size of backup file
if (f1.length() > MetricsHandler.MAX_LOGS_SIZE) {
//Size is over limit delete file
f1.delete();
if (!f.renameTo(f1)) {
LOG.log(Level.INFO, "Failed to rename file:{0} to:{1}", new Object[]{f, f1}); // NOI18N
}
} else {
//Size is below limit, append data
appendFile(f, f1);
}
} else {
f1.delete();
if (!f.renameTo(f1)) {
LOG.log(Level.INFO, "Failed to rename file:{0} to:{1}", new Object[]{f, f1}); // NOI18N
}
}
} else {
if (!f.renameTo(f1)) {
LOG.log(Level.INFO, "Failed to rename file:{0} to:{1}", new Object[]{f, f1}); // NOI18N
}
}
logsSizeMetrics = 0;
logsFirstDateMetric = System.currentTimeMillis();
if (preferencesWritable) {
prefs.putInt("countMetrics", logsSizeMetrics);
prefs.putLong(FIRST_DATE_METRICS_PROP, logsFirstDateMetric);
}
}
}
if (upload) {
//Task to upload metrics data
final List recs = null;
class Auto implements Runnable {
@Override
public void run() {
displaySummary("METRICS_URL", true, true, true, DataType.DATA_METRICS, recs, null);
}
}
//Must be performed out of lock because it calls getLogsMetrics
RP.post(new Auto()).waitFinished();
}
} catch (IOException ex) {
Exceptions.printStackTrace(ex);
}
}
/** Append content of source to target */
private static void appendFile (File source, File target) {
byte[] buf = new byte[8192];
FileInputStream is = null;
FileOutputStream os = null;
long targetSize = -1;
try {
is = new FileInputStream(source);
targetSize = target.length();
os = new FileOutputStream(target, true);
int l;
while ((l = is.read(buf)) != -1) {
os.write(buf, 0, l);
}
os.flush();
} catch (IOException ex) {
if (os != null) {
// Write failed, to assure consistency of data, truncate the file back to the original size:
DataConsistentFileOutputStream.truncateFileToConsistentSize(os, targetSize);
}
Exceptions.printStackTrace(ex);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException ex) {}
}
if (os != null) {
try {
os.close();
} catch (IOException ex) {}
}
}
}
static void getModuleList (Logger logger, List enabledRec, List disabledRec) {
List enabled = new ArrayList<>();
List disabled = new ArrayList<>();
for (ModuleInfo m : Lookup.getDefault().lookupAll(ModuleInfo.class)) {
if (m.isEnabled()) {
enabled.add(m);
} else {
disabled.add(m);
}
}
if (!enabled.isEmpty()) {
LogRecord rec = new LogRecord(Level.INFO, "USG_ENABLED_MODULES");
String[] enabledNames = EnabledModulesCollector.getModuleNames(enabled);
rec.setParameters(enabledNames);
rec.setLoggerName(logger.getName());
enabledRec.add(rec);
}
if (!disabled.isEmpty()) {
LogRecord rec = new LogRecord(Level.INFO, "USG_DISABLED_MODULES");
String[] disabledNames = EnabledModulesCollector.getModuleNames(disabled);
rec.setParameters(disabledNames);
rec.setLoggerName(logger.getName());
disabledRec.add(rec);
}
}
public static URL hintsURL() {
return hintURL;
}
public static boolean isHintsMode() {
return prefs.getBoolean("autoSubmitWhenFull", false);
}
static int timesSubmitted() {
return prefs.getInt("submitted", 0);
}
public static int getLogsSize() {
UIHandler.waitFlushed();
synchronized (UIGESTURE_LOG_LOCK) {
return prefs.getInt("count", 0); // NOI18N
}
}
static void readLogs(Handler handler){
UIHandler.waitFlushed();
synchronized (UIGESTURE_LOG_LOCK) {
File f = logFile(0);
if (f == null || !f.exists()) {
return ;
}
closeLogStream();
File f1 = logFile(1);
if (logsSize < UIHandler.MAX_LOGS && f1 != null && f1.exists()) {
scan(f1, handler);
}
scan(f, handler);
}
}
private static String reportFileContent(File f) {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(new FileInputStream(f), StandardCharsets.UTF_8));
StringWriter sw = new StringWriter();
String line;
while ((line = br.readLine()) != null) {
sw.write(line);
sw.write('\n');
}
sw.close();
return sw.toString();
} catch (IOException ioex) {
return ioex.toString();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException ex) {}
}
}
}
private static boolean fileContentReported;
private static void scan(File f, Handler handler){
try {
LogRecords.scan(f, handler);
} catch (IOException ex) {
LOG.log(Level.INFO, "Broken uilogs file, not all UI actions will be submitted", ex);
if (!fileContentReported) {
try {
if (LOG.isLoggable(Level.INFO)) {
LOG.log(Level.INFO, "Problematic file content = {0}", reportFileContent(f));
}
} finally {
fileContentReported = true;
}
}
}
}
static List getLogs() {
class H extends Handler {
List logs = new LinkedList<>();
@Override
public void publish(LogRecord r) {
logs.add(r);
if (logs.size() > UIHandler.MAX_LOGS) {
logs.remove(0);
}
}
@Override
public void flush() {
}
@Override
public void close() throws SecurityException {
}
}
H hndlr = new H();
readLogs(hndlr);
return hndlr.logs;
}
public static List getLogsMetrics() {
synchronized (METRICS_LOG_LOCK) {
class H extends Handler {
List logs = new LinkedList<>();
@Override
public void publish(LogRecord r) {
logs.add(r);
}
@Override
public void flush() {
}
@Override
public void close() throws SecurityException {
}
}
H hndlr = new H();
File f1 = logFileMetrics(1);
if ((f1 != null) && f1.exists()) {
try {
LogRecords.scan(f1, hndlr);
} catch (IOException ex) {
Exceptions.printStackTrace(
Exceptions.attachMessage(ex, "Broken metrics log file, not all metrics data will be submitted")
);
if (!fileContentReported) {
try {
if (LOG.isLoggable(Level.INFO)) {
LOG.log(Level.INFO, "Problematic file content = {0}", reportFileContent(f1));
}
} finally {
fileContentReported = true;
}
}
}
}
return hndlr.logs;
}
}
static File getDeadlockDumpFile(){
return new File(logsDirectory(), "deadlock.dump");
}
static File logsDirectory(){
File userDir = Places.getUserDirectory();
if (userDir != null) {
return new File(new File(userDir, "var"), "log"); // NOI18N
} else {
return null;
}
}
private static File logFile(int revision) {
File logDir = logsDirectory();
if (logDir == null){
return null;
}
String suffix = revision == 0 ? "" : "." + revision;
File logFile = new File(logDir, "uigestures" + suffix);
return logFile;
}
private static File logFileMetrics (int revision) {
File logDir = logsDirectory();
if (logDir == null){
return null;
}
String suffix = revision == 0 ? "" : "." + revision;
File logFile = new File(logDir, "metrics" + suffix); // NOI18N
return logFile;
}
private static OutputStream logStream() throws FileNotFoundException {
synchronized (Installer.class) {
if (logStream != null) {
return logStream;
}
}
OutputStream os;
File logFile = logFile(0);
if (logFile != null) {
logFile.getParentFile().mkdirs();
os = new DataConsistentFileOutputStream(logFile, true);
} else {
os = new NullOutputStream();
}
synchronized (Installer.class) {
if (logStream != null) {
try {
os.close();
} catch (IOException ex) {}
return logStream;
}
logStream = os;
return logStream;
}
}
private static OutputStream logStreamMetrics () throws FileNotFoundException {
synchronized (METRICS_LOG_LOCK) {
if (logStreamMetrics != null) {
return logStreamMetrics;
}
}
OutputStream os;
File logFile = logFileMetrics(0);
if (logFile != null) {
logFile.getParentFile().mkdirs();
os = new DataConsistentFileOutputStream(logFile, true);
} else {
os = new NullOutputStream();
}
synchronized (METRICS_LOG_LOCK) {
if (logStreamMetrics != null) {
try {
os.close();
} catch (IOException ex) {}
return logStreamMetrics;
}
logStreamMetrics = os;
return logStreamMetrics;
}
}
private static void closeLogStream() {
OutputStream os;
synchronized (Installer.class) {
os = logStream;
logStream = null;
}
if (os == null) {
return;
}
try {
os.close();
} catch (IOException ex) {}
}
private static void closeLogStreamMetrics() {
OutputStream os;
synchronized (METRICS_LOG_LOCK) {
os = logStreamMetrics;
logStreamMetrics = null;
}
if (os == null) {
return;
}
try {
os.close();
} catch (IOException ex) {}
}
static void clearLogs() {
synchronized (UIGESTURE_LOG_LOCK) {
closeLogStream();
for (int i = 0; ; i++) {
File f = logFile(i);
if (f == null || !f.exists()) {
break;
}
f.delete();
}
logsSize = 0;
if (preferencesWritable) {
prefs.putInt("count", 0);
}
}
UIHandler.SUPPORT.firePropertyChange(null, null, null);
}
@Override
public boolean closing() {
return true;
}
static void logDeactivated(){
Logger log = Logger.getLogger(UI_LOGGER_NAME);
for (Deactivated a : Lookup.getDefault().lookupAll(Deactivated.class)) {
a.deactivated(log);
}
}
private static AtomicReference DISPLAYING = new AtomicReference<>();
static boolean displaySummary(String msg, boolean explicit, boolean auto,
boolean connectDialog, DataType dataType,
List recs, SlownessData slownData) {
return displaySummary(msg, explicit, auto, connectDialog, dataType, recs, slownData, false);
}
static boolean displaySummary(String msg, boolean explicit, boolean auto,
boolean connectDialog, DataType dataType,
List recs, SlownessData slownData,
boolean isAfterRestart) {
if (!DISPLAYING.compareAndSet(null, msg)) {
return true;
}
boolean v = true;
try {
if (!explicit) {
boolean dontAsk = prefs.getBoolean("ask.never.again." + msg, false); // NOI18N
if (dontAsk) {
LOG.log(Level.INFO, "UI Gesture Collector's ask.never.again.{0} is true, exiting", msg); // NOI18N
return true;
}
}
Submit submit = auto ? new SubmitAutomatic(msg, Button.SUBMIT, dataType, recs) : new SubmitInteractive(msg, connectDialog, dataType, recs, slownData, isAfterRestart);
submit.doShow(dataType);
v = submit.okToExit;
} finally {
DISPLAYING.set(null);
}
return v;
}
public static boolean displaySummary(String msg, boolean explicit, boolean auto, boolean connectDialog) {
return displaySummary(msg, explicit, auto, connectDialog, DataType.DATA_UIGESTURE, null, null);
}
static boolean displaySummary(String msg, boolean explicit, boolean auto, boolean connectDialog, SlownessData slownessData) {
return displaySummary(msg, explicit, auto, connectDialog, DataType.DATA_UIGESTURE, null, slownessData);
}
/** used only in tests - low performance - should use read logs*/
static Throwable getThrown() {
return getThrown(getLogs());
}
private static Throwable getThrown(List recs) {
LogRecord log = getThrownLog(recs);
if (log == null){
return null;
}else{
return log.getThrown();
}
}
private static LogRecord getThrownLog(List list) {
String firstLine = null;
String message = null;
if (selectedExcParams != null){
if (selectedExcParams[0] instanceof String){
message = (String)selectedExcParams[0];
}
if (selectedExcParams[1] instanceof String){
firstLine = (String)selectedExcParams[1];
}
}
ListIterator it = list.listIterator(list.size());
Throwable thr = null;
LogRecord result;
while (it.hasPrevious()){
result = it.previous();
if (result != null &&
result.getLevel().intValue() >= Level.WARNING.intValue()) {
thr = result.getThrown();// ignore info messages
if ((thr != null) && (message != null)) {
if (!thr.getMessage().equals(message)){
thr = null;//different messages
}
}
if ((thr != null) && (firstLine != null)) {
StackTraceElement[] elems = thr.getStackTrace();
if (!(elems == null) && !(elems.length == 0)){
StackTraceElement elem = elems[0];
String thrLine = elem.getClassName() + "." + elem.getMethodName();
if (! thrLine.equals(firstLine)){
thr = null;//different first lines
}
}
}
}
// find first exception from end
if (thr != null) {
return result;
}
}
return null;// no throwable found
}
protected static void setSelectedExcParams(Object[] params){
selectedExcParams = params;
}
/** Tries to parse a list of buttons provided by given page.
* @param is the input stream to read the page from
* @param defaultButton the button to add always to the list
*/
static void parseButtons(InputStream is, final Object defaultButton, final DialogDescriptor dd)
throws IOException, ParserConfigurationException, SAXException, InterruptedException, InvocationTargetException {
final ButtonsHTMLParser bp = new ButtonsHTMLParser(is);
final IOException[] ioExPtr = new IOException[] { null };
Runnable buttonsCreation = new Runnable() {
@Override
public void run() {
try {
bp.parse();
} catch (IOException ioex) {
ioExPtr[0] = ioex;
return ;
}
bp.createButtons();
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy