Java tutorial
/* * Lilith - a log event viewer. * Copyright (C) 2007-2014 Joern Huxhorn * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.huxhorn.lilith.swing; import de.huxhorn.lilith.Lilith; import de.huxhorn.lilith.LilithBuffer; import de.huxhorn.lilith.LilithSounds; import de.huxhorn.lilith.VersionBundle; import de.huxhorn.lilith.data.access.logback.LogbackAccessConverter; import de.huxhorn.lilith.data.converter.ConverterRegistry; import de.huxhorn.lilith.data.logging.logback.LogbackLoggingConverter; import de.huxhorn.lilith.engine.impl.eventproducer.LoggingEventSourceIdentifierUpdater; import de.huxhorn.lilith.engine.impl.sourceproducer.ConvertingServerSocketEventSourceProducer; import de.huxhorn.lilith.engine.json.sourceproducer.LilithJsonMessageLoggingServerSocketEventSourceProducer; import de.huxhorn.lilith.engine.json.sourceproducer.LilithJsonStreamLoggingServerSocketEventSourceProducer; import de.huxhorn.lilith.engine.jul.sourceproducer.JulXmlStreamLoggingServerSocketEventSourceProducer; import de.huxhorn.lilith.eventhandlers.AlarmSoundAccessEventHandler; import de.huxhorn.lilith.eventhandlers.AlarmSoundLoggingEventHandler; import de.huxhorn.lilith.eventhandlers.FileDumpEventHandler; import de.huxhorn.lilith.eventhandlers.RrdLoggingEventHandler; import de.huxhorn.lilith.data.eventsource.LoggerContext; import de.huxhorn.lilith.debug.DebugDialog; import de.huxhorn.lilith.appender.InternalLilithAppender; import de.huxhorn.lilith.eventhandlers.FileSplitterEventHandler; import de.huxhorn.lilith.data.access.AccessEvent; import de.huxhorn.lilith.data.access.HttpStatus; import de.huxhorn.lilith.data.eventsource.EventWrapper; import de.huxhorn.lilith.data.eventsource.SourceIdentifier; import de.huxhorn.lilith.data.logging.LoggingEvent; import de.huxhorn.lilith.engine.AccessFileBufferFactory; import de.huxhorn.lilith.engine.EventHandler; import de.huxhorn.lilith.engine.EventSource; import de.huxhorn.lilith.engine.EventSourceListener; import de.huxhorn.lilith.engine.FileBufferFactory; import de.huxhorn.lilith.api.FileConstants; import de.huxhorn.lilith.engine.LogFileFactory; import de.huxhorn.lilith.engine.LoggingFileBufferFactory; import de.huxhorn.lilith.engine.SourceManager; import de.huxhorn.lilith.engine.impl.EventSourceImpl; import de.huxhorn.lilith.engine.impl.LogFileFactoryImpl; import de.huxhorn.lilith.engine.impl.sourcemanager.SourceManagerImpl; import de.huxhorn.lilith.engine.impl.sourceproducer.AccessEventProtobufServerSocketEventSourceProducer; import de.huxhorn.lilith.engine.impl.sourceproducer.LoggingEventProtobufServerSocketEventSourceProducer; import de.huxhorn.lilith.engine.xml.sourceproducer.LilithXmlMessageLoggingServerSocketEventSourceProducer; import de.huxhorn.lilith.engine.xml.sourceproducer.LilithXmlStreamLoggingServerSocketEventSourceProducer; import de.huxhorn.lilith.jul.xml.JulImportCallable; import de.huxhorn.lilith.log4j.producer.Log4jLoggingConverter; import de.huxhorn.lilith.log4j.xml.Log4jImportCallable; import de.huxhorn.lilith.log4j2.producer.Log4j2LoggingConverter; import de.huxhorn.lilith.logback.appender.AccessMultiplexSocketAppender; import de.huxhorn.lilith.logback.appender.ClassicJsonMultiplexSocketAppender; import de.huxhorn.lilith.logback.appender.ClassicMultiplexSocketAppender; import de.huxhorn.lilith.logback.appender.ClassicXmlMultiplexSocketAppender; import de.huxhorn.lilith.logback.appender.ZeroDelimitedClassicJsonMultiplexSocketAppender; import de.huxhorn.lilith.logback.appender.ZeroDelimitedClassicXmlMultiplexSocketAppender; import de.huxhorn.lilith.prefs.LilithPreferences; import de.huxhorn.lilith.services.details.GroovyEventWrapperHtmlFormatter; import de.huxhorn.lilith.services.details.ThymeleafEventWrapperHtmlFormatter; import de.huxhorn.lilith.services.gotosrc.GoToSource; import de.huxhorn.lilith.services.gotosrc.SerializingGoToSource; import de.huxhorn.lilith.services.sender.EventSender; import de.huxhorn.lilith.services.sender.SenderService; import de.huxhorn.lilith.swing.callables.CheckFileChangeCallable; import de.huxhorn.lilith.swing.callables.CleanAllInactiveCallable; import de.huxhorn.lilith.swing.callables.CleanObsoleteCallable; import de.huxhorn.lilith.swing.callables.ExportCallable; import de.huxhorn.lilith.swing.callables.IndexingCallable; import de.huxhorn.lilith.swing.filefilters.DirectoryFilter; import de.huxhorn.lilith.swing.filefilters.LilithFileFilter; import de.huxhorn.lilith.swing.filefilters.LogFileFilter; import de.huxhorn.lilith.swing.filefilters.RrdFileFilter; import de.huxhorn.lilith.swing.filefilters.XmlImportFileFilter; import de.huxhorn.lilith.swing.preferences.PreferencesDialog; import de.huxhorn.lilith.swing.preferences.SavedCondition; import de.huxhorn.lilith.swing.table.ColorScheme; import de.huxhorn.lilith.swing.table.Colors; import de.huxhorn.lilith.swing.taskmanager.TaskManagerInternalFrame; import de.huxhorn.lilith.swing.transfer.MainFrameTransferHandler; import de.huxhorn.lilith.swing.transfer.MainFrameTransferHandler16; import de.huxhorn.lilith.swing.uiprocessors.ConditionNamesActionsProcessor; import de.huxhorn.lilith.swing.uiprocessors.ConditionNamesContainerProcessor; import de.huxhorn.lilith.swing.uiprocessors.PreviousSearchStringsContainerProcessor; import de.huxhorn.lilith.swing.uiprocessors.ResetContainerProcessor; import de.huxhorn.lilith.swing.uiprocessors.UpdateRecentFilesProcessor; import de.huxhorn.lilith.swing.uiprocessors.UpdateScaleContainerProcessor; import de.huxhorn.lilith.swing.uiprocessors.UpdateViewsContainerProcessor; import de.huxhorn.lilith.swing.uiprocessors.UpdateWindowMenuProcessor; import de.huxhorn.lilith.swing.uiprocessors.ViewActionsProcessor; import de.huxhorn.lilith.swing.uiprocessors.ViewContainerProcessor; import de.huxhorn.lilith.swing.uiprocessors.VisibleContainerProcessor; import de.huxhorn.lilith.tray.TraySupport; import de.huxhorn.sulky.buffers.AppendOperation; import de.huxhorn.sulky.buffers.BlockingCircularBuffer; import de.huxhorn.sulky.buffers.Buffer; import de.huxhorn.sulky.buffers.FileBuffer; import de.huxhorn.sulky.codec.filebuffer.CodecFileBuffer; import de.huxhorn.sulky.codec.filebuffer.DefaultFileHeaderStrategy; import de.huxhorn.sulky.codec.filebuffer.FileHeader; import de.huxhorn.sulky.codec.filebuffer.FileHeaderStrategy; import de.huxhorn.sulky.codec.filebuffer.MetaData; import de.huxhorn.sulky.conditions.Condition; import de.huxhorn.sulky.conditions.Or; import de.huxhorn.sulky.sounds.Sounds; import de.huxhorn.sulky.swing.MemoryStatus; import de.huxhorn.sulky.swing.Windows; import de.huxhorn.sulky.tasks.Task; import de.huxhorn.sulky.tasks.TaskListener; import de.huxhorn.sulky.tasks.TaskManager; import de.huxhorn.sulky.io.IOUtilities; import org.apache.commons.lang3.SystemUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.apache.http.util.EntityUtils; import org.simplericity.macify.eawt.Application; import org.simplericity.macify.eawt.ApplicationEvent; import org.simplericity.macify.eawt.ApplicationListener; import org.simplericity.macify.eawt.DefaultApplication; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.*; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyVetoException; import java.io.BufferedReader; import java.io.File; import java.io.FileFilter; import java.io.FileInputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Serializable; import java.net.URI; import java.net.URL; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.zip.GZIPInputStream; import javax.swing.*; import javax.swing.border.EtchedBorder; public class MainFrame extends JFrame { private static final long serialVersionUID = 6138189654024239738L; private final Logger logger = LoggerFactory.getLogger(MainFrame.class); private final File startupApplicationPath; private final GroovyEventWrapperHtmlFormatter groovyFormatter; private final ThymeleafEventWrapperHtmlFormatter thymeleafFormatter; private GoToSource gotoSource; private LogFileFactory loggingFileFactory; private SourceManager<LoggingEvent> loggingEventSourceManager; private FileBufferFactory<LoggingEvent> loggingFileBufferFactory; private EventSourceListener<LoggingEvent> loggingSourceListener; private LoggingEventViewManager loggingEventViewManager; private LogFileFactory accessFileFactory; private SourceManager<AccessEvent> accessEventSourceManager; private FileBufferFactory<AccessEvent> accessFileBufferFactory; private EventSourceListener<AccessEvent> accessSourceListener; private AccessEventViewManager accessEventViewManager; private Sounds sounds; private JDesktopPane desktop; private PreferencesDialog preferencesDialog; private JDialog aboutDialog; private JLabel statusLabel; private ApplicationPreferences applicationPreferences; private DebugDialog debugDialog; private RrdFileFilter rrdFileFilter; private StatisticsDialog statisticsDialog; private TaskManager<Long> longTaskManager; private ViewActions viewActions; private OpenPreviousDialog openInactiveLogsDialog; private HelpFrame helpFrame; private Application application; private int activeCounter; private List<AutostartRunnable> autostartProcesses; private SenderService senderService; private boolean enableBonjour; private static final boolean isMac; private static final boolean isWindows; private List<SavedCondition> activeConditions; private Map<LoggingEvent.Level, Colors> levelColors; private Map<HttpStatus.Type, Colors> statusColors; private SplashScreen splashScreen; private TaskManagerInternalFrame taskManagerFrame; private JLabel taskStatusLabel; private int previousNumberOfTasks; private ImageIcon smallProgressIcon; public static final String LOGS_SUBDIRECTORY = "logs"; public static final String LOGGING_FILE_SUBDIRECTORY = LOGS_SUBDIRECTORY + "/logging"; public static final String ACCESS_FILE_SUBDIRECTORY = LOGS_SUBDIRECTORY + "/access"; private JFileChooser openFileChooser; private JFileChooser importFileChooser; private JFileChooser exportFileChooser; private boolean coloringWholeRow; private static final double SCALE_FACTOR = 0.05d; private JToolBar toolbar; private JPanel statusBar; private TipOfTheDayDialog tipOfTheDayDialog; private CheckForUpdateDialog checkForUpdateDialog; private FileDumpEventHandler<LoggingEvent> loggingFileDump; private FileDumpEventHandler<AccessEvent> accessFileDump; private RrdLoggingEventHandler rrdLoggingEventHandler; private static final int EXPORT_WARNING_SIZE = 20000; private Condition findActiveCondition; private TraySupport traySupport; // may be null static { DefaultApplication app = new DefaultApplication(); isMac = app.isMac(); if (!isMac) { String osName = System.getProperty("os.name").toLowerCase(); isWindows = osName.startsWith("windows"); } else { isWindows = false; } } private static final ViewContainerProcessor UPDATE_VIEWS_CONTAINER_PROCESSOR = new UpdateViewsContainerProcessor(); private static final ViewActionsProcessor UPDATE_RECENT_FILES_ACTIONS_PROCESSOR = new UpdateRecentFilesProcessor(); private static final ViewActionsProcessor UPDATE_WINDOW_MENU_ACTIONS_PROCESSOR = new UpdateWindowMenuProcessor(); private static final ViewContainerProcessor RESET_CONTAINER_PROCESSOR = new ResetContainerProcessor(); private final ViewContainerProcessor sourceTitleContainerProcessor = new SourceTitleContainerProcessor(); private boolean usingThymeleaf; /* * Need to use ConcurrentMap because it's accessed by both the EventDispatchThread and the CleanupThread. */ //private ConcurrentMap<EventIdentifier, SoftColorsReference> colorsCache; //private ReferenceQueue<Colors> colorsReferenceQueue; public AccessEventViewManager getAccessEventViewManager() { return accessEventViewManager; } public LoggingEventViewManager getLoggingEventViewManager() { return loggingEventViewManager; } public PreferencesDialog getPreferencesDialog() { return preferencesDialog; } public ViewActions getViewActions() { return viewActions; } public JDesktopPane getDesktop() { return desktop; } public MainFrame(ApplicationPreferences applicationPreferences, SplashScreen splashScreen, String appName, boolean enableBonjour) { super(appName); this.applicationPreferences = applicationPreferences; this.coloringWholeRow = this.applicationPreferences.isColoringWholeRow(); this.splashScreen = splashScreen; setSplashStatusText("Creating main frame."); groovyFormatter = new GroovyEventWrapperHtmlFormatter(applicationPreferences); thymeleafFormatter = new ThymeleafEventWrapperHtmlFormatter(applicationPreferences); smallProgressIcon = new ImageIcon(MainFrame.class.getResource("/otherGraphics/Progress16.gif")); ImageIcon frameIcon = new ImageIcon(MainFrame.class.getResource("/otherGraphics/Lilith16.jpg")); setIconImage(frameIcon.getImage()); //colorsReferenceQueue=new ReferenceQueue<Colors>(); //colorsCache=new ConcurrentHashMap<EventIdentifier, SoftColorsReference>(); application = new DefaultApplication(); autostartProcesses = new ArrayList<AutostartRunnable>(); addWindowListener(new MainWindowListener()); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); // fixes ticket #79 Runtime runtime = Runtime.getRuntime(); Thread shutdownHook = new Thread(new ShutdownRunnable()); runtime.addShutdownHook(shutdownHook); senderService = new SenderService(this); this.enableBonjour = enableBonjour; /* if(application.isMac()) { setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); } else { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } */ longTaskManager = new TaskManager<Long>(); longTaskManager.setUsingEventQueue(true); longTaskManager.startUp(); longTaskManager.addTaskListener(new MainTaskListener()); startupApplicationPath = this.applicationPreferences.getStartupApplicationPath(); loggingFileFactory = new LogFileFactoryImpl(new File(startupApplicationPath, LOGGING_FILE_SUBDIRECTORY)); accessFileFactory = new LogFileFactoryImpl(new File(startupApplicationPath, ACCESS_FILE_SUBDIRECTORY)); Map<String, String> loggingMetaData = new HashMap<String, String>(); loggingMetaData.put(FileConstants.CONTENT_TYPE_KEY, FileConstants.CONTENT_TYPE_VALUE_LOGGING); loggingMetaData.put(FileConstants.CONTENT_FORMAT_KEY, FileConstants.CONTENT_FORMAT_VALUE_PROTOBUF); loggingMetaData.put(FileConstants.COMPRESSION_KEY, FileConstants.COMPRESSION_VALUE_GZIP); // TODO: configurable format and compressed loggingFileBufferFactory = new LoggingFileBufferFactory(loggingFileFactory, loggingMetaData); Map<String, String> accessMetaData = new HashMap<String, String>(); accessMetaData.put(FileConstants.CONTENT_TYPE_KEY, FileConstants.CONTENT_TYPE_VALUE_ACCESS); accessMetaData.put(FileConstants.CONTENT_FORMAT_KEY, FileConstants.CONTENT_FORMAT_VALUE_PROTOBUF); accessMetaData.put(FileConstants.COMPRESSION_KEY, FileConstants.COMPRESSION_VALUE_GZIP); // TODO: configurable format and compressed accessFileBufferFactory = new AccessFileBufferFactory(accessFileFactory, accessMetaData); rrdFileFilter = new RrdFileFilter(); loggingEventViewManager = new LoggingEventViewManager(this); accessEventViewManager = new AccessEventViewManager(this); this.applicationPreferences.addPropertyChangeListener(new PreferencesChangeListener()); loggingSourceListener = new LoggingEventSourceListener(); accessSourceListener = new AccessEventSourceListener(); // this.cleanupWindowChangeListener = new CleanupWindowChangeListener(); desktop = new JDesktopPane(); statusBar = new JPanel(new GridBagLayout()); GridBagConstraints gbc = new GridBagConstraints(); statusLabel = new JLabel(); statusLabel.setText("Starting..."); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.gridx = 0; gbc.gridy = 0; gbc.weightx = 0.0; gbc.anchor = GridBagConstraints.CENTER; gbc.insets = new Insets(0, 5, 0, 0); statusBar.add(statusLabel, gbc); taskStatusLabel = new JLabel(); taskStatusLabel.setText(""); taskStatusLabel.setForeground(Color.BLUE); taskStatusLabel.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent mouseEvent) { showTaskManager(); } @Override public void mouseEntered(MouseEvent mouseEvent) { taskStatusLabel.setForeground(Color.RED); } @Override public void mouseExited(MouseEvent mouseEvent) { taskStatusLabel.setForeground(Color.BLUE); } }); gbc.gridx = 1; gbc.gridy = 0; gbc.weightx = 1.0; gbc.anchor = GridBagConstraints.CENTER; gbc.insets = new Insets(0, 5, 0, 0); statusBar.add(taskStatusLabel, gbc); MemoryStatus memoryStatus = new MemoryStatus(); memoryStatus.setBackground(Color.WHITE); memoryStatus.setOpaque(true); memoryStatus.setUsingBinaryUnits(true); memoryStatus.setUsingTotal(false); memoryStatus.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); gbc.fill = GridBagConstraints.NONE; gbc.gridx = 2; gbc.gridy = 0; gbc.weightx = 0.0; gbc.anchor = GridBagConstraints.CENTER; gbc.insets = new Insets(0, 0, 0, 0); statusBar.add(memoryStatus, gbc); add(desktop, BorderLayout.CENTER); add(statusBar, BorderLayout.SOUTH); if (SystemUtils.IS_JAVA_1_6) { setSplashStatusText("Creating statistics dialog."); if (logger.isDebugEnabled()) logger.debug("Before creation of statistics-dialog..."); statisticsDialog = new StatisticsDialog(this); if (logger.isDebugEnabled()) logger.debug("After creation of statistics-dialog..."); } setSplashStatusText("Creating about dialog."); aboutDialog = new AboutDialog(this, "About " + appName + "...", appName); setSplashStatusText("Creating update dialog."); checkForUpdateDialog = new CheckForUpdateDialog(this); setSplashStatusText("Creating debug dialog."); debugDialog = new DebugDialog(this, this); setSplashStatusText("Creating preferences dialog."); if (logger.isDebugEnabled()) logger.debug("Before creation of preferences-dialog..."); preferencesDialog = new PreferencesDialog(this); if (logger.isDebugEnabled()) logger.debug("After creation of preferences-dialog..."); setSplashStatusText("Creating \"Open inactive\" dialog."); openInactiveLogsDialog = new OpenPreviousDialog(MainFrame.this); setSplashStatusText("Creating help frame."); helpFrame = new HelpFrame(this); helpFrame.setTitle("Help Topics"); openFileChooser = new JFileChooser(); openFileChooser.setFileFilter(new LilithFileFilter()); openFileChooser.setFileHidingEnabled(false); openFileChooser.setCurrentDirectory(this.applicationPreferences.getPreviousOpenPath()); importFileChooser = new JFileChooser(); importFileChooser.setFileFilter(new XmlImportFileFilter()); importFileChooser.setFileHidingEnabled(false); importFileChooser.setCurrentDirectory(this.applicationPreferences.getPreviousImportPath()); exportFileChooser = new JFileChooser(); exportFileChooser.setFileFilter(new LilithFileFilter()); exportFileChooser.setFileHidingEnabled(false); exportFileChooser.setCurrentDirectory(this.applicationPreferences.getPreviousExportPath()); setSplashStatusText("Creating task manager frame."); taskManagerFrame = new TaskManagerInternalFrame(this); taskManagerFrame.setTitle("Task Manager"); taskManagerFrame.setDefaultCloseOperation(JInternalFrame.HIDE_ON_CLOSE); taskManagerFrame.setBounds(0, 0, 320, 240); desktop.add(taskManagerFrame); desktop.validate(); // the following code must be executed after desktop has been initialized... try { // try to use the 1.6 transfer handler... new MainFrameTransferHandler16(this).attach(); } catch (Throwable t) { // ... and use the basic 1.5 transfer handler if this fails. new MainFrameTransferHandler(this).attach(); } setSplashStatusText("Creating Tip of the Day dialog."); tipOfTheDayDialog = new TipOfTheDayDialog(this); setSplashStatusText("Creating actions and menus."); viewActions = new ViewActions(this, null); viewActions.getPopupMenu(); // initialize popup once in main frame only. JMenuBar menuBar = viewActions.getMenuBar(); toolbar = viewActions.getToolbar(); add(toolbar, BorderLayout.NORTH); setJMenuBar(menuBar); setShowingToolbar(applicationPreferences.isShowingToolbar()); setShowingStatusbar(applicationPreferences.isShowingStatusbar()); } public boolean isUsingThymeleaf() { return usingThymeleaf; } public void setUsingThymeleaf(boolean usingThymeleaf) { this.usingThymeleaf = usingThymeleaf; } /** * To be called after setVisible(true)... */ public void startUp() { //Thread referenceCollection=new Thread(new ColorsCollectionRunnable(), "ColorCacheCleanupThread"); //referenceCollection.setDaemon(true); //referenceCollection.start(); setSplashStatusText("Executing autostart items."); // Autostart { File autostartDir = new File(startupApplicationPath, "autostart"); if (autostartDir.mkdirs()) { if (logger.isDebugEnabled()) logger.debug("Created '{}'.", autostartDir.getAbsolutePath()); } File[] autoFiles = autostartDir.listFiles(new FileFilter() { public boolean accept(File file) { return file.isFile(); } }); if (autoFiles != null && autoFiles.length > 0) { Arrays.sort(autoFiles, new Comparator<File>() { public int compare(File o1, File o2) { return o1.getAbsolutePath().compareTo(o2.getAbsolutePath()); } }); for (File current : autoFiles) { AutostartRunnable r = new AutostartRunnable(current); autostartProcesses.add(r); Thread t = new Thread(r, current.getAbsolutePath()); t.setDaemon(true); t.start(); } } else { if (logger.isInfoEnabled()) { logger.info("No autostart files defined in '{}'.", autostartDir.getAbsolutePath()); } } } // go to source { gotoSource = new SerializingGoToSource(); //gotoSource.start() started when needed... } setSplashStatusText("Creating global views."); SourceIdentifier globalSourceIdentifier = new SourceIdentifier("global", null); loggingFileDump = new FileDumpEventHandler<LoggingEvent>(globalSourceIdentifier, loggingFileBufferFactory); accessFileDump = new FileDumpEventHandler<AccessEvent>(globalSourceIdentifier, accessFileBufferFactory); setGlobalLoggingEnabled(applicationPreferences.isGlobalLoggingEnabled()); BlockingCircularBuffer<EventWrapper<LoggingEvent>> loggingEventQueue = new LilithBuffer<LoggingEvent>( applicationPreferences, 1000); BlockingCircularBuffer<EventWrapper<AccessEvent>> accessEventQueue = new LilithBuffer<AccessEvent>( applicationPreferences, 1000); SourceManagerImpl<LoggingEvent> lsm = new SourceManagerImpl<LoggingEvent>(loggingEventQueue); // add global view EventSource<LoggingEvent> globalLoggingEventSource = new EventSourceImpl<LoggingEvent>( globalSourceIdentifier, loggingFileDump.getBuffer(), true); lsm.addSource(globalLoggingEventSource); setSplashStatusText("Creating internal view."); // add internal lilith logging EventSource<LoggingEvent> lilithLoggingEventSource = new EventSourceImpl<LoggingEvent>( InternalLilithAppender.getSourceIdentifier(), InternalLilithAppender.getBuffer(), false); lsm.addSource(lilithLoggingEventSource); setLoggingEventSourceManager(lsm); SourceManagerImpl<AccessEvent> asm = new SourceManagerImpl<AccessEvent>(accessEventQueue); // add global view EventSource<AccessEvent> globalAccessEventSource = new EventSourceImpl<AccessEvent>(globalSourceIdentifier, accessFileDump.getBuffer(), true); asm.addSource(globalAccessEventSource); setAccessEventSourceManager(asm); ConverterRegistry<LoggingEvent> loggingConverterRegistry = new ConverterRegistry<LoggingEvent>(); loggingConverterRegistry.addConverter(new LogbackLoggingConverter()); loggingConverterRegistry.addConverter(new Log4jLoggingConverter()); loggingConverterRegistry.addConverter(new Log4j2LoggingConverter()); ConverterRegistry<AccessEvent> accessConverterRegistry = new ConverterRegistry<AccessEvent>(); accessConverterRegistry.addConverter(new LogbackAccessConverter()); setSplashStatusText("Starting event receivers."); try { ConvertingServerSocketEventSourceProducer<LoggingEvent> producer = new ConvertingServerSocketEventSourceProducer<LoggingEvent>( 4560, loggingConverterRegistry, new LoggingEventSourceIdentifierUpdater()); loggingEventSourceManager.addEventSourceProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { ConvertingServerSocketEventSourceProducer<LoggingEvent> producer = new ConvertingServerSocketEventSourceProducer<LoggingEvent>( 4445, loggingConverterRegistry, new LoggingEventSourceIdentifierUpdater()); loggingEventSourceManager.addEventSourceProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { LoggingEventProtobufServerSocketEventSourceProducer producer = new LoggingEventProtobufServerSocketEventSourceProducer( ClassicMultiplexSocketAppender.COMPRESSED_DEFAULT_PORT, true); loggingEventSourceManager.addEventSourceProducer(producer); // TODO: senderService.addLoggingProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { LoggingEventProtobufServerSocketEventSourceProducer producer = new LoggingEventProtobufServerSocketEventSourceProducer( ClassicMultiplexSocketAppender.UNCOMPRESSED_DEFAULT_PORT, false); loggingEventSourceManager.addEventSourceProducer(producer); // TODO: senderService.addLoggingProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { LilithXmlMessageLoggingServerSocketEventSourceProducer producer = new LilithXmlMessageLoggingServerSocketEventSourceProducer( ClassicXmlMultiplexSocketAppender.UNCOMPRESSED_DEFAULT_PORT, false); loggingEventSourceManager.addEventSourceProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { LilithXmlMessageLoggingServerSocketEventSourceProducer producer = new LilithXmlMessageLoggingServerSocketEventSourceProducer( ClassicXmlMultiplexSocketAppender.COMPRESSED_DEFAULT_PORT, true); loggingEventSourceManager.addEventSourceProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { LilithJsonMessageLoggingServerSocketEventSourceProducer producer = new LilithJsonMessageLoggingServerSocketEventSourceProducer( ClassicJsonMultiplexSocketAppender.UNCOMPRESSED_DEFAULT_PORT, false); loggingEventSourceManager.addEventSourceProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { LilithJsonMessageLoggingServerSocketEventSourceProducer producer = new LilithJsonMessageLoggingServerSocketEventSourceProducer( ClassicJsonMultiplexSocketAppender.COMPRESSED_DEFAULT_PORT, true); loggingEventSourceManager.addEventSourceProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { LilithXmlStreamLoggingServerSocketEventSourceProducer producer = new LilithXmlStreamLoggingServerSocketEventSourceProducer( ZeroDelimitedClassicXmlMultiplexSocketAppender.DEFAULT_PORT); loggingEventSourceManager.addEventSourceProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { LilithJsonStreamLoggingServerSocketEventSourceProducer producer = new LilithJsonStreamLoggingServerSocketEventSourceProducer( ZeroDelimitedClassicJsonMultiplexSocketAppender.DEFAULT_PORT); loggingEventSourceManager.addEventSourceProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { JulXmlStreamLoggingServerSocketEventSourceProducer producer = new JulXmlStreamLoggingServerSocketEventSourceProducer( 11020); loggingEventSourceManager.addEventSourceProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { ConvertingServerSocketEventSourceProducer<AccessEvent> producer = new ConvertingServerSocketEventSourceProducer<AccessEvent>( 4570, accessConverterRegistry, null); accessEventSourceManager.addEventSourceProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { AccessEventProtobufServerSocketEventSourceProducer producer = new AccessEventProtobufServerSocketEventSourceProducer( AccessMultiplexSocketAppender.COMPRESSED_DEFAULT_PORT, true); accessEventSourceManager.addEventSourceProducer(producer); // TODO: senderService.addAccessProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } try { AccessEventProtobufServerSocketEventSourceProducer producer = new AccessEventProtobufServerSocketEventSourceProducer( AccessMultiplexSocketAppender.UNCOMPRESSED_DEFAULT_PORT, false); accessEventSourceManager.addEventSourceProducer(producer); // TODO: senderService.addAccessProducer(producer); } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while creating event producer!", ex); } setSplashStatusText("Setting up event handlers."); rrdLoggingEventHandler = new RrdLoggingEventHandler(); rrdLoggingEventHandler.setBasePath(new File(startupApplicationPath, "statistics")); setStatisticsEnabled(applicationPreferences.isLoggingStatisticEnabled()); AlarmSoundLoggingEventHandler loggingEventAlarmSound = new AlarmSoundLoggingEventHandler(); loggingEventAlarmSound.setSounds(sounds); FileSplitterEventHandler<LoggingEvent> fileSplitterLoggingEventHandler = new FileSplitterEventHandler<LoggingEvent>( loggingFileBufferFactory, loggingEventSourceManager); List<EventHandler<LoggingEvent>> loggingHandlers = new ArrayList<EventHandler<LoggingEvent>>(); loggingHandlers.add(rrdLoggingEventHandler); loggingHandlers.add(loggingEventAlarmSound); loggingHandlers.add(fileSplitterLoggingEventHandler); loggingHandlers.add(loggingFileDump); // crashes the app using j2se 6 //if(application.isMac()) //{ // UserNotificationLoggingEventHandler notification = new UserNotificationLoggingEventHandler(application); // loggingHandlers.add(notification); //} loggingEventSourceManager.setEventHandlers(loggingHandlers); loggingEventSourceManager.start(); List<EventHandler<AccessEvent>> accessHandlers = new ArrayList<EventHandler<AccessEvent>>(); FileSplitterEventHandler<AccessEvent> fileSplitterAccessEventHandler = new FileSplitterEventHandler<AccessEvent>( accessFileBufferFactory, accessEventSourceManager); AlarmSoundAccessEventHandler accessEventAlarmSound = new AlarmSoundAccessEventHandler(); accessEventAlarmSound.setSounds(sounds); accessHandlers.add(accessEventAlarmSound); accessHandlers.add(fileSplitterAccessEventHandler); accessHandlers.add(accessFileDump); // crashes the app using j2se 6 //if(application.isMac()) //{ // UserNotificationAccessEventHandler notification = new UserNotificationAccessEventHandler(application); // accessHandlers.add(notification); //} accessEventSourceManager.setEventHandlers(accessHandlers); accessEventSourceManager.start(); viewActions.updateWindowMenu(); application.setEnabledAboutMenu(true); application.setEnabledPreferencesMenu(true); application.addApplicationListener(new MyApplicationListener()); if (enableBonjour) { senderService.start(); } if (applicationPreferences.isCheckingForUpdate()) { checkForUpdate(false); } updateConditions(); // to initialize active conditions. if (applicationPreferences.isShowingTipOfTheDay()) { showTipOfTheDayDialog(); } cleanObsoleteFiles(); traySupport = TraySupport.getInstance(); if (traySupport != null) { traySupport.setMainFrame(this); } setSplashStatusText("Finished."); // viewActions.requestMenuBarFocus(); } public void showTipOfTheDayDialog() { Windows.showWindow(tipOfTheDayDialog, this, true); } private void updateTaskStatus() { int numberOfTasks = longTaskManager.getNumberOfTasks(); if (numberOfTasks != previousNumberOfTasks) { previousNumberOfTasks = numberOfTasks; String text = ""; Icon icon = null; if (numberOfTasks == 1) { text = "1 active task."; icon = smallProgressIcon; } else if (numberOfTasks > 1) { text = "" + numberOfTasks + " active tasks."; icon = smallProgressIcon; } taskStatusLabel.setText(text); taskStatusLabel.setIcon(icon); } } private void setSplashStatusText(String text) { if (splashScreen != null) { splashScreen.setStatusText(text); } } public Application getApplication() { return application; } // /** // * Returns a sorted map containing resolved source name mapped to sender. If there is both a compressed // * and uncompressed sender the compressed one will be used. // * @param senders a map of all senders // * @return a map of senders. // */ // private <T extends Serializable> Map<String, EventSender<T>> getEventSenders(Map<String, EventSender<T>> senders) // { // Map<String, EventSender<T>> serviceNameSenderMapping; // synchronized(senders) // { // serviceNameSenderMapping =new HashMap<String, EventSender<T>>(senders); // } // // SortedMap<String, EventSender<T>> result=new TreeMap<String, EventSender<T>>(); // for(Map.Entry<String, EventSender<T>> current: serviceNameSenderMapping.entrySet()) // { // EventSender<T> value = current.getValue(); // String hostName = value.getHostAddress(); // hostName = getPrimarySourceTitle(hostName); // EventSender<T> prevValue = result.get(hostName); // if(prevValue == null) // { // result.put(hostName, value); // } // else // { // if(value instanceof AbstractEventSender) // { // AbstractEventSender aes = (AbstractEventSender) value; // if(aes.isCompressing()) // { // result.put(hostName, value); // if(logger.isDebugEnabled()) logger.debug("Replaced previous sender with compressing one."); // } // } // } // } // if(logger.isDebugEnabled()) logger.debug("EventSenders: {}", result); // return result; // } public Map<String, EventSender<LoggingEvent>> getLoggingEventSenders() { return senderService.getLoggingEventSenders();//getEventSenders(loggingEventSenders); } public Map<String, EventSender<AccessEvent>> getAccessEventSenders() { return senderService.getAccessEventSenders();//getEventSenders(accessEventSenders); } public void updateWindowMenus() { processViewActions(UPDATE_WINDOW_MENU_ACTIONS_PROCESSOR); JInternalFrame selected = desktop.getSelectedFrame(); if (logger.isDebugEnabled()) logger.debug("Selected IFrame: {}", selected); if (selected instanceof ViewContainerInternalFrame) { ViewContainerInternalFrame iframe = (ViewContainerInternalFrame) selected; viewActions.setViewContainer(iframe.getViewContainer()); } else { viewActions.setViewContainer(null); // no frame or task manager } } public void closeLoggingConnection(SourceIdentifier id) { loggingEventSourceManager.removeEventProducer(id); } public void closeAccessConnection(SourceIdentifier id) { accessEventSourceManager.removeEventProducer(id); } public void goToSource(StackTraceElement ste) { /* String className=ste.getClassName(); int dollarIndex = className.indexOf("$"); if(dollarIndex>=0) { String parentClassName=className.substring(0, dollarIndex); if(logger.isWarnEnabled()) logger.warn("parentClassName: {}", parentClassName); } */ if (gotoSource != null) { gotoSource.goToSource(ste); } } public void setActiveConnectionsCounter(int activeCounter) { this.activeCounter = activeCounter; updateStatus(); } public void copyHtml(String html) { Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable transferableText = new HtmlTransferable(html); systemClipboard.setContents(transferableText, null); } public void checkForUpdate(boolean showAlways) { Thread t = new Thread( new CheckForUpdateRunnable(showAlways, applicationPreferences.isCheckingForSnapshot())); t.start(); } public Colors getColors(HttpStatus.Type status) { if (statusColors == null) { initStatusColors(); } Colors c = statusColors.get(status); if (c != null) { try { c = c.clone(); } catch (CloneNotSupportedException e) { if (logger.isErrorEnabled()) logger.error("Exception while cloning Colors!!", e); } } return c; } public Colors getColors(LoggingEvent.Level level) { if (levelColors == null) { initLevelColors(); } Colors c = levelColors.get(level); if (c != null) { try { c = c.clone(); } catch (CloneNotSupportedException e) { if (logger.isErrorEnabled()) logger.error("Exception while cloning Colors!!", e); } } return c; } public Colors getColors(EventWrapper eventWrapper) { if (!SwingUtilities.isEventDispatchThread()) { if (logger.isErrorEnabled()) logger.error("Not on EventDispatchThread!"); } ColorScheme result = null; if (activeConditions != null) { for (SavedCondition current : activeConditions) { Condition condition = current.getCondition(); if (condition != null && condition.isTrue(eventWrapper)) { if (result == null) { result = current.getColorScheme(); if (result != null) { try { result = result.clone(); } catch (CloneNotSupportedException e) { if (logger.isErrorEnabled()) logger.error("Exception while cloning ColorScheme!!", e); } } } else { result.mergeWith(current.getColorScheme()); } } if (result != null && result.isAbsolute()) { return new Colors(result, false); } } } if (coloringWholeRow) { Object eventObj = eventWrapper.getEvent(); if (eventObj instanceof LoggingEvent) { Colors c = getColors(((LoggingEvent) eventObj).getLevel()); if (result != null) { return new Colors(result.mergeWith(c.getColorScheme()), false); } return c; } if (eventObj instanceof AccessEvent) { Colors c = getColors(HttpStatus.getType(((AccessEvent) eventObj).getStatusCode())); if (result != null) { return new Colors(result.mergeWith(c.getColorScheme()), false); } return c; } } // return the previously found ColorScheme even though it's not absolute if (result != null) { return new Colors(result, false); } return null; } public void open() { int returnVal = openFileChooser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { open(openFileChooser.getSelectedFile()); } } public void importFile() { int returnVal = importFileChooser.showOpenDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { File importFile = importFileChooser.getSelectedFile(); String fileName = importFile.getAbsolutePath(); if (fileName.toLowerCase().endsWith(FileConstants.FILE_EXTENSION)) { open(importFile); return; } importFile(importFile); } } public void exportFile(EventWrapperViewPanel view) { long size = view.getEventSource().getBuffer().getSize(); if (size == 0) { return; } int returnVal = exportFileChooser.showSaveDialog(this); if (returnVal == JFileChooser.APPROVE_OPTION) { if (size > EXPORT_WARNING_SIZE) { String dialogTitle = "Large export! Are you sure?"; String message = "You are about to export " + size + " events. This could take some time.\nAre you sure you want to export?"; int result = JOptionPane.showConfirmDialog(this, message, dialogTitle, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (JOptionPane.OK_OPTION != result) { return; } } File file = exportFileChooser.getSelectedFile(); String fileName = file.getAbsolutePath(); String baseName; if (fileName.toLowerCase().endsWith(FileConstants.FILE_EXTENSION)) { baseName = fileName.substring(0, fileName.length() - FileConstants.FILE_EXTENSION.length()); } else { baseName = fileName; } File dataFile = new File(baseName + FileConstants.FILE_EXTENSION); File indexFile = new File(baseName + FileConstants.INDEX_FILE_EXTENSION); if (dataFile.isFile()) { String dialogTitle = "Overwrite file?"; String message = "Data file does already exist!\nOverwrite data file?"; int result = JOptionPane.showConfirmDialog(this, message, dialogTitle, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (JOptionPane.OK_OPTION != result) { return; } if (!dataFile.delete()) { if (logger.isWarnEnabled()) logger.warn("Couldn't delete existing file {}!", dataFile.getAbsolutePath()); } if (indexFile.isFile() && !indexFile.delete()) { if (logger.isWarnEnabled()) logger.warn("Couldn't delete existing file {}!", indexFile.getAbsolutePath()); } } if (view instanceof AccessEventViewPanel) { exportFile(dataFile, indexFile, (AccessEventViewPanel) view); } else if (view instanceof LoggingEventViewPanel) { exportFile(dataFile, indexFile, (LoggingEventViewPanel) view); } } } private void exportFile(File dataFile, File indexFile, AccessEventViewPanel viewPanel) { Map<String, String> metaData = new HashMap<String, String>(); metaData.put(FileConstants.CONTENT_FORMAT_KEY, FileConstants.CONTENT_FORMAT_VALUE_PROTOBUF); metaData.put(FileConstants.CONTENT_TYPE_KEY, FileConstants.CONTENT_TYPE_VALUE_ACCESS); metaData.put(FileConstants.COMPRESSION_KEY, FileConstants.COMPRESSION_VALUE_GZIP); FileBuffer<EventWrapper<AccessEvent>> outputBuffer = accessFileBufferFactory.createBuffer(dataFile, indexFile, metaData); Buffer<EventWrapper<AccessEvent>> inputBuffer = viewPanel.getEventSource().getBuffer(); String name = "Export to " + dataFile.getName(); String description = "Exporting " + inputBuffer.getSize() + " access events into file '" + dataFile.getAbsolutePath() + "'."; Task<Long> task = longTaskManager.startTask(new ExportCallable<AccessEvent>(inputBuffer, outputBuffer), name, description); if (logger.isInfoEnabled()) logger.info("Task-Name: {}", task.getName()); } private void exportFile(File dataFile, File indexFile, LoggingEventViewPanel viewPanel) { Map<String, String> metaData = new HashMap<String, String>(); metaData.put(FileConstants.CONTENT_FORMAT_KEY, FileConstants.CONTENT_FORMAT_VALUE_PROTOBUF); metaData.put(FileConstants.CONTENT_TYPE_KEY, FileConstants.CONTENT_TYPE_VALUE_LOGGING); metaData.put(FileConstants.COMPRESSION_KEY, FileConstants.COMPRESSION_VALUE_GZIP); FileBuffer<EventWrapper<LoggingEvent>> outputBuffer = loggingFileBufferFactory.createBuffer(dataFile, indexFile, metaData); Buffer<EventWrapper<LoggingEvent>> inputBuffer = viewPanel.getEventSource().getBuffer(); String name = "Export to " + dataFile.getName(); String description = "Exporting " + inputBuffer.getSize() + " logging events into file '" + dataFile.getAbsolutePath() + "'."; Task<Long> task = longTaskManager.startTask(new ExportCallable<LoggingEvent>(inputBuffer, outputBuffer), name, description); if (logger.isInfoEnabled()) logger.info("Task-Name: {}", task.getName()); } public void open(File dataFile) { if (logger.isInfoEnabled()) logger.info("Open file: {}", dataFile.getAbsolutePath()); if (!dataFile.isFile()) { String message = "'" + dataFile.getAbsolutePath() + "' is not a file!"; JOptionPane.showMessageDialog(this, message, "Can't open file...", JOptionPane.ERROR_MESSAGE); return; } if (!dataFile.canRead()) { String message = "Can't read from '" + dataFile.getAbsolutePath() + "'!"; JOptionPane.showMessageDialog(this, message, "Can't open file...", JOptionPane.ERROR_MESSAGE); return; } ViewContainer<?> viewContainer = resolveViewContainer(dataFile); if (viewContainer != null) { showView(viewContainer); String message = "File '" + dataFile.getAbsolutePath() + "' is already open."; JOptionPane.showMessageDialog(this, message, "File is already open...", JOptionPane.INFORMATION_MESSAGE); return; } String fileName = dataFile.getAbsolutePath(); String indexFileName; if (fileName.toLowerCase().endsWith(FileConstants.FILE_EXTENSION)) { indexFileName = fileName.substring(0, fileName.length() - FileConstants.FILE_EXTENSION.length()); } else { indexFileName = fileName; } indexFileName = indexFileName + FileConstants.INDEX_FILE_EXTENSION; long dataModified = dataFile.lastModified(); File indexFile = new File(indexFileName); if (!indexFile.isFile()) { // Index file does not exist. Ask if it should be indexed. String dialogTitle = "Index file?"; String message = "Index file does not exist!\nIndex data file right now?"; int result = JOptionPane.showConfirmDialog(this, message, dialogTitle, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (JOptionPane.OK_OPTION != result) { // file will not be opened. return; } String name = "Indexing Lilith file"; String description = "Indexing '" + dataFile.getAbsolutePath() + "'..."; Task<Long> task = longTaskManager.startTask(new IndexingCallable(dataFile, indexFile), name, description); if (logger.isInfoEnabled()) logger.info("Task-Name: {}", task.getName()); // opening of view will be done by the task return; } // Previous index file was found long indexModified = indexFile.lastModified(); if (indexModified < dataModified) { // Index file is outdated. Ask if it should be reindexed. String dialogTitle = "Index outdated. Reindex file?"; String message = "The index file is older than the data file!\nReindex data file right now?"; int result = JOptionPane.showConfirmDialog(this, message, dialogTitle, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (JOptionPane.OK_OPTION == result) { if (indexFile.delete()) { if (logger.isInfoEnabled()) logger.info("Deleted previous index file {}.", indexFile.getAbsolutePath()); String name = "Reindexing Lilith file"; String description = "Reindexing '" + dataFile.getAbsolutePath() + "'..."; Task<Long> task = longTaskManager.startTask(new IndexingCallable(dataFile, indexFile), name, description); if (logger.isInfoEnabled()) logger.info("Task-Name: {}", task.getName()); // opening of view will be done by the task return; } } // It's fine to use the outdated index. } // use existing index file createViewFor(dataFile, indexFile, true); } public void importFile(File importFile) { if (logger.isInfoEnabled()) logger.info("Import file: {}", importFile.getAbsolutePath()); File parentFile = importFile.getParentFile(); String inputName = importFile.getName(); if (!importFile.isFile()) { String message = "'" + importFile.getAbsolutePath() + "' is not a file!"; JOptionPane.showMessageDialog(this, message, "Can't import file...", JOptionPane.ERROR_MESSAGE); return; } if (!importFile.canRead()) { String message = "Can't read from '" + importFile.getAbsolutePath() + "'!"; JOptionPane.showMessageDialog(this, message, "Can't import file...", JOptionPane.ERROR_MESSAGE); return; } File dataFile = new File(parentFile, inputName + FileConstants.FILE_EXTENSION); File indexFile = new File(parentFile, inputName + FileConstants.INDEX_FILE_EXTENSION); // check if file exists and warn in that case if (dataFile.isFile()) { // check if file is already open ViewContainer<?> viewContainer = resolveViewContainer(dataFile); if (viewContainer != null) { showView(viewContainer); String message = "File '" + dataFile.getAbsolutePath() + "' is already open."; JOptionPane.showMessageDialog(this, message, "File is already open...", JOptionPane.INFORMATION_MESSAGE); return; } String dialogTitle = "Reimport file?"; String message = "Data file does already exist!\nReimport data file right now?"; int result = JOptionPane.showConfirmDialog(this, message, dialogTitle, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (JOptionPane.OK_OPTION != result) { return; } if (dataFile.delete()) { if (logger.isInfoEnabled()) logger.info("Deleted file '{}'.", dataFile.getAbsolutePath()); } } if (indexFile.isFile()) { if (indexFile.delete()) { if (logger.isInfoEnabled()) logger.info("Deleted file '{}'.", indexFile.getAbsolutePath()); } } Map<String, String> metaData = new HashMap<String, String>(); metaData.put(FileConstants.CONTENT_FORMAT_KEY, FileConstants.CONTENT_FORMAT_VALUE_PROTOBUF); metaData.put(FileConstants.CONTENT_TYPE_KEY, FileConstants.CONTENT_TYPE_VALUE_LOGGING); metaData.put(FileConstants.COMPRESSION_KEY, FileConstants.COMPRESSION_VALUE_GZIP); FileBuffer<EventWrapper<LoggingEvent>> buffer = loggingFileBufferFactory.createBuffer(dataFile, indexFile, metaData); ImportType type = resolveType(importFile); if (type == ImportType.LOG4J) { String name = "Importing Log4J XML file"; String description = "Importing Log4J XML file '" + importFile.getAbsolutePath() + "'..."; Task<Long> task = longTaskManager.startTask(new Log4jImportCallable(importFile, buffer), name, description); if (logger.isInfoEnabled()) logger.info("Task-Name: {}", task.getName()); return; } if (type == ImportType.JUL) { String name = "Importing java.util.logging XML file"; String description = "Importing java.util.logging XML file '" + importFile.getAbsolutePath() + "'..."; Task<Long> task = longTaskManager.startTask(new JulImportCallable(importFile, buffer), name, description); if (logger.isInfoEnabled()) logger.info("Task-Name: {}", task.getName()); return; } // show warning "Unknown type" String message = "Couldn't detect type of file '" + importFile.getAbsolutePath() + "'.\nFile is unsupported."; JOptionPane.showMessageDialog(this, message, "Unknown file type...", JOptionPane.WARNING_MESSAGE); } private ImportType resolveType(File inputFile) { BufferedReader br = null; try { FileInputStream fis = new FileInputStream(inputFile); String fileName = inputFile.getName().toLowerCase(); if (fileName.endsWith(".gz")) { br = new BufferedReader(new InputStreamReader(new GZIPInputStream(fis), "UTF-8")); } else { br = new BufferedReader(new InputStreamReader(fis, "UTF-8")); } for (int i = 0; i < 5; i++) { String line = br.readLine(); if (line == null) { break; } if (line.contains("<log4j:")) { return ImportType.LOG4J; } if (line.contains("<log>") || line.contains("<record>")) { return ImportType.JUL; } } } catch (IOException ex) { if (logger.isWarnEnabled()) logger.warn("Exception while resolving type of file!", ex); } finally { if (br != null) { try { br.close(); } catch (IOException e) { // ignore } } } return null; } public void zoomOut() { double scale = applicationPreferences.getScaleFactor() - SCALE_FACTOR; if (scale < 0.1d) { scale = 0.1d; } applicationPreferences.setScaleFactor(scale); } public void zoomIn() { double scale = applicationPreferences.getScaleFactor() + SCALE_FACTOR; applicationPreferences.setScaleFactor(scale); } public void resetZoom() { applicationPreferences.setScaleFactor(1.0d); } public void troubleshooting() { preferencesDialog.showPane(PreferencesDialog.Panes.Troubleshooting); } public void openHelp(String help) { /* String helpFile=help; String helpAnchor=null; int hashIndex = helpFile.indexOf('#'); if(hashIndex > -1) { helpFile=help.substring(0, hashIndex); helpAnchor = help.substring(hashIndex); } String resourceName="/help/"+helpFile; URL url = MainFrame.class.getResource(resourceName); if(url == null) { if(logger.isWarnEnabled()) logger.warn("Couldn't find help resource '{}'!", resourceName); return; } if(helpAnchor != null) { String urlString = url.toString()+helpAnchor; try { url=new URL(urlString); } catch(MalformedURLException e) { if(logger.isWarnEnabled()) logger.warn("Couldn't create help URL for '{}'!", urlString); } } if(logger.isInfoEnabled()) logger.info("Opening help: {}", url); helpFrame.setHelpUrl(url); */ if (logger.isInfoEnabled()) logger.info("Opening help: {}", help); helpFrame.setHelpUrl(help); if (!helpFrame.isVisible()) { Windows.showWindow(helpFrame, this, false); } helpFrame.toFront(); } public void openPreferences(String panelName) { try { PreferencesDialog.Panes pane = PreferencesDialog.Panes.valueOf(panelName); preferencesDialog.showPane(pane); } catch (IllegalArgumentException ex) { if (logger.isWarnEnabled()) logger.warn("Couldn't resolve preferences pane '{}'!", panelName); } } public void deleteAllLogs() { processViewContainers(RESET_CONTAINER_PROCESSOR); cleanAllInactiveLogs(); } public enum ImportType { LOG4J, JUL } public ViewContainer<?> resolveViewContainer(File dataFile) { { // logging Map<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> views = loggingEventViewManager.getViews(); for (Map.Entry<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> current : views.entrySet()) { ViewContainer<LoggingEvent> view = current.getValue(); EventWrapperViewPanel<LoggingEvent> defaultView = view.getDefaultView(); EventSource<LoggingEvent> es = defaultView.getEventSource(); if (es != null) { Buffer<EventWrapper<LoggingEvent>> buffer = es.getBuffer(); if (buffer instanceof CodecFileBuffer) { CodecFileBuffer cfb = (CodecFileBuffer) buffer; if (dataFile.equals(cfb.getDataFile())) { return view; } } } } } { // access Map<EventSource<AccessEvent>, ViewContainer<AccessEvent>> views = accessEventViewManager.getViews(); for (Map.Entry<EventSource<AccessEvent>, ViewContainer<AccessEvent>> current : views.entrySet()) { ViewContainer<AccessEvent> view = current.getValue(); EventWrapperViewPanel<AccessEvent> defaultView = view.getDefaultView(); EventSource<AccessEvent> es = defaultView.getEventSource(); if (es != null) { Buffer<EventWrapper<AccessEvent>> buffer = es.getBuffer(); if (buffer instanceof CodecFileBuffer) { CodecFileBuffer cfb = (CodecFileBuffer) buffer; if (dataFile.equals(cfb.getDataFile())) { return view; } } } } } return null; } private void createViewFor(File dataFile, File indexFile, boolean keepUpdating) { // create view for dataFile and indexFile. if (logger.isInfoEnabled()) { logger.info("Create view for dataFile '{}' and indexFile '{}'.", dataFile.getAbsolutePath(), indexFile.getAbsolutePath()); } FileHeaderStrategy fileHeaderStrategy = new DefaultFileHeaderStrategy(); try { FileHeader header = fileHeaderStrategy.readFileHeader(dataFile); if (header == null) { if (logger.isWarnEnabled()) { logger.warn("Couldn't read file header from '{}'!", dataFile.getAbsolutePath()); } return; } if (header.getMagicValue() != FileConstants.MAGIC_VALUE) { if (logger.isWarnEnabled()) { logger.warn("Invalid magic value! ", Integer.toHexString(header.getMagicValue())); } return; } MetaData metaData = header.getMetaData(); if (metaData == null || metaData.getData() == null) { if (logger.isWarnEnabled()) { logger.warn("Couldn't read meta data from '{}'!", dataFile.getAbsolutePath()); } return; } Map<String, String> data = metaData.getData(); String contentType = data.get(FileConstants.CONTENT_TYPE_KEY); Map<String, String> usedMetaData = new HashMap<String, String>(); SourceIdentifier si = new SourceIdentifier(dataFile.getAbsolutePath()); if (FileConstants.CONTENT_TYPE_VALUE_LOGGING.equals(contentType)) { FileBuffer<EventWrapper<LoggingEvent>> buffer = loggingFileBufferFactory.createBuffer(dataFile, indexFile, usedMetaData); EventSource<LoggingEvent> eventSource = new EventSourceImpl<LoggingEvent>(si, buffer, false); ViewContainer<LoggingEvent> viewContainer = loggingEventViewManager .retrieveViewContainer(eventSource); EventWrapperViewPanel<LoggingEvent> panel = viewContainer.getDefaultView(); if (keepUpdating) { panel.setState(LoggingViewState.UPDATING_FILE); viewContainer .setUpdateCallable(new CheckFileChangeCallable(dataFile, indexFile, viewContainer)); } else { panel.setState(LoggingViewState.STALE_FILE); } showLoggingView(eventSource); applicationPreferences.addRecentFile(dataFile); } else if (FileConstants.CONTENT_TYPE_VALUE_ACCESS.equals(contentType)) { FileBuffer<EventWrapper<AccessEvent>> buffer = accessFileBufferFactory.createBuffer(dataFile, indexFile, usedMetaData); EventSource<AccessEvent> eventSource = new EventSourceImpl<AccessEvent>(si, buffer, false); ViewContainer<AccessEvent> viewContainer = accessEventViewManager .retrieveViewContainer(eventSource); EventWrapperViewPanel<AccessEvent> panel = viewContainer.getDefaultView(); if (keepUpdating) { panel.setState(LoggingViewState.UPDATING_FILE); viewContainer .setUpdateCallable(new CheckFileChangeCallable(dataFile, indexFile, viewContainer)); } else { panel.setState(LoggingViewState.STALE_FILE); } showAccessView(eventSource); applicationPreferences.addRecentFile(dataFile); } else { if (logger.isWarnEnabled()) logger.warn("Unexpected content type {}.", contentType); applicationPreferences.removeRecentFile(dataFile); } } catch (IOException e) { if (logger.isWarnEnabled()) logger.warn("Exception while creating view form file!", e); } } /* // implement cache? private static class SoftColorsReference extends SoftReference<Colors> { private static final Colors NULL_COLORS = new Colors(); private EventIdentifier id; public SoftColorsReference(EventIdentifier id, Colors o, ReferenceQueue<Colors> referenceQueue) { super(o != null ? o : new Colors(), referenceQueue); this.id = id; } public EventIdentifier getId() { return id; } public Colors getColors() { Colors result = get(); if(NULL_COLORS.equals(result)) { return null; } return result; } } */ private void initStatusColors() { Map<HttpStatus.Type, ColorScheme> prefValue = applicationPreferences.getStatusColors(); Map<HttpStatus.Type, Colors> colors = new HashMap<HttpStatus.Type, Colors>(); for (Map.Entry<HttpStatus.Type, ColorScheme> current : prefValue.entrySet()) { colors.put(current.getKey(), new Colors(current.getValue(), false)); } statusColors = colors; } private void initLevelColors() { Map<LoggingEvent.Level, ColorScheme> prefValue = applicationPreferences.getLevelColors(); Map<LoggingEvent.Level, Colors> colors = new HashMap<LoggingEvent.Level, Colors>(); for (Map.Entry<LoggingEvent.Level, ColorScheme> current : prefValue.entrySet()) { colors.put(current.getKey(), new Colors(current.getValue(), false)); } levelColors = colors; } public class MyApplicationListener implements ApplicationListener { private final Logger logger = LoggerFactory.getLogger(MyApplicationListener.class); public void handleAbout(ApplicationEvent applicationEvent) { //application.requestUserAttention(Application.REQUEST_USER_ATTENTION_TYPE_INFORMATIONAL); if (logger.isDebugEnabled()) logger.debug("handleAbout: {}", applicationEvent); viewActions.getAboutAction().actionPerformed(null); applicationEvent.setHandled(true); } public void handleOpenApplication(ApplicationEvent applicationEvent) { if (logger.isDebugEnabled()) logger.debug("handleOpenApplication: {}", applicationEvent); } public void handleOpenFile(ApplicationEvent applicationEvent) { if (logger.isDebugEnabled()) logger.debug("handleOpenFile: {}\n\tfilename: {}", applicationEvent, applicationEvent.getFilename()); open(new File(applicationEvent.getFilename())); } public void handlePreferences(ApplicationEvent applicationEvent) { if (logger.isDebugEnabled()) logger.debug("handlePreferences: {}", applicationEvent); viewActions.getPreferencesAction().actionPerformed(null); } public void handlePrintFile(ApplicationEvent applicationEvent) { if (logger.isDebugEnabled()) logger.debug("handlePrintFile: {}", applicationEvent); } public void handleQuit(ApplicationEvent applicationEvent) { exit(); } public void handleReOpenApplication(ApplicationEvent applicationEvent) { if (logger.isDebugEnabled()) logger.debug("handleReOpenApplication: {}", applicationEvent); setVisible(true); } } private void setLoggingEventSourceManager(SourceManager<LoggingEvent> loggingEventSourceManager) { if (this.loggingEventSourceManager != null) { this.loggingEventSourceManager.removeEventSourceListener(loggingSourceListener); } this.loggingEventSourceManager = loggingEventSourceManager; if (this.loggingEventSourceManager != null) { this.loggingEventSourceManager.addEventSourceListener(loggingSourceListener); List<EventSource<LoggingEvent>> sources = this.loggingEventSourceManager.getSources(); for (EventSource<LoggingEvent> source : sources) { loggingEventViewManager.retrieveViewContainer(source); } } } public SourceManager<LoggingEvent> getLoggingEventSourceManager() { return loggingEventSourceManager; } private void setAccessEventSourceManager(SourceManager<AccessEvent> accessEventSourceManager) { if (this.accessEventSourceManager != null) { this.accessEventSourceManager.removeEventSourceListener(accessSourceListener); } this.accessEventSourceManager = accessEventSourceManager; if (this.accessEventSourceManager != null) { this.accessEventSourceManager.addEventSourceListener(accessSourceListener); List<EventSource<AccessEvent>> sources = this.accessEventSourceManager.getSources(); for (EventSource<AccessEvent> source : sources) { accessEventViewManager.retrieveViewContainer(source); } } } public SourceManager<AccessEvent> getAccessEventSourceManager() { return accessEventSourceManager; } public Sounds getSounds() { return sounds; } public void setSounds(Sounds sounds) { if (sounds != null) { sounds.setSoundLocations(applicationPreferences.getSoundLocations()); sounds.setMute(applicationPreferences.isMute()); } this.sounds = sounds; } private ViewContainer<LoggingEvent> retrieveLoggingViewContainer(EventSource<LoggingEvent> eventSource) { return loggingEventViewManager.retrieveViewContainer(eventSource); } private ViewContainer<AccessEvent> retrieveAccessViewContainer(EventSource<AccessEvent> eventSource) { return accessEventViewManager.retrieveViewContainer(eventSource); } public ApplicationPreferences getApplicationPreferences() { return applicationPreferences; } /* public EventWrapperViewPanel<LoggingEvent> createLoggingViewPanel(EventSource<LoggingEvent> eventSource) { EventWrapperViewPanel<LoggingEvent> result = new LoggingEventViewPanel(this, eventSource); result.setScrollingToBottom(applicationPreferences.isScrollingToBottom()); return result; } */ public SortedMap<String, SourceIdentifier> getAvailableStatistics() { File statisticsPath = new File(applicationPreferences.getStartupApplicationPath(), "statistics"); File[] files = statisticsPath.listFiles(rrdFileFilter); SortedMap<String, SourceIdentifier> sources = new TreeMap<String, SourceIdentifier>(); if (files != null) { for (File f : files) { String name = f.getName(); name = name.substring(0, name.length() - 4); // we are sure about .rrd here... if (!name.equalsIgnoreCase("global")) { SourceIdentifier si = new SourceIdentifier(name); sources.put(getSourceTitle(si, null), si); } } } return sources; } public void showStatistics(SourceIdentifier sourceIdentifier) { if (statisticsDialog != null) { statisticsDialog.setSourceIdentifier(sourceIdentifier); Windows.showWindow(statisticsDialog, MainFrame.this, true); } } public TaskManager<Long> getLongWorkManager() { return longTaskManager; } public LogFileFactory getAccessFileFactory() { return accessFileFactory; } public LogFileFactory getLoggingFileFactory() { return loggingFileFactory; } public void showLoggingView(EventSource<LoggingEvent> eventSource) { ViewContainer<LoggingEvent> container = retrieveLoggingViewContainer(eventSource); showView(container); } public void showAccessView(EventSource<AccessEvent> eventSource) { ViewContainer<AccessEvent> container = retrieveAccessViewContainer(eventSource); showView(container); } public void showView(ViewContainer<?> container) { // we need this since this method might also be called by a different thread ShowViewRunnable runnable = new ShowViewRunnable(container); if (SwingUtilities.isEventDispatchThread()) { runnable.run(); } else { SwingUtilities.invokeLater(runnable); } } public void openPreviousLogging(SourceIdentifier si) { FileBuffer<EventWrapper<LoggingEvent>> buffer = loggingFileBufferFactory.createBuffer(si); EventSource<LoggingEvent> eventSource = new EventSourceImpl<LoggingEvent>(si, buffer, false); ViewContainer<LoggingEvent> container = retrieveLoggingViewContainer(eventSource); EventWrapperViewPanel<LoggingEvent> panel = container.getDefaultView(); panel.setState(LoggingViewState.INACTIVE); showLoggingView(eventSource); } public void openPreviousAccess(SourceIdentifier si) { FileBuffer<EventWrapper<AccessEvent>> buffer = accessFileBufferFactory.createBuffer(si); EventSource<AccessEvent> eventSource = new EventSourceImpl<AccessEvent>(si, buffer, false); ViewContainer<AccessEvent> container = retrieveAccessViewContainer(eventSource); EventWrapperViewPanel<AccessEvent> panel = container.getDefaultView(); panel.setState(LoggingViewState.INACTIVE); showAccessView(eventSource); } public void updateStatus() { StringBuilder statusText = new StringBuilder(); LilithPreferences.SourceFiltering filtering = applicationPreferences.getSourceFiltering(); switch (filtering) { case BLACKLIST: statusText.append("Blacklisting on '"); statusText.append(applicationPreferences.getBlackListName()); statusText.append("'. "); break; case WHITELIST: statusText.append("Whitelisting on '"); statusText.append(applicationPreferences.getWhiteListName()); statusText.append("'. "); break; } if (activeCounter == 0) { statusText.append("No active connections."); } else if (activeCounter == 1) { statusText.append("One active connection."); } else if (activeCounter > 1) { statusText.append(activeCounter).append(" active connections."); } String status = statusText.toString(); statusLabel.setText(status); if (traySupport != null) { traySupport.setToolTip(status); } } public String createMessage(EventWrapper wrapper) { String result; if (usingThymeleaf) { result = thymeleafFormatter.toString(wrapper); } else { result = groovyFormatter.toString(wrapper); } if (result == null) { if (logger.isWarnEnabled()) logger.warn("createMessage with usingThymeleaf={} failed for {}!", usingThymeleaf, wrapper); return "<html><body>Failed to create message!</body></html>"; } return result; } public SortedMap<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> getSortedLoggingViews() { EventSourceComparator<LoggingEvent> loggingComparator = new EventSourceComparator<LoggingEvent>(); SortedMap<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> sortedLoggingViews; sortedLoggingViews = new TreeMap<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>>(loggingComparator); if (loggingEventViewManager != null) { sortedLoggingViews.putAll(loggingEventViewManager.getViews()); } return sortedLoggingViews; } public SortedMap<EventSource<AccessEvent>, ViewContainer<AccessEvent>> getSortedAccessViews() { EventSourceComparator<AccessEvent> accessComparator = new EventSourceComparator<AccessEvent>(); SortedMap<EventSource<AccessEvent>, ViewContainer<AccessEvent>> sortedAccessViews; sortedAccessViews = new TreeMap<EventSource<AccessEvent>, ViewContainer<AccessEvent>>(accessComparator); if (accessEventViewManager != null) { sortedAccessViews.putAll(accessEventViewManager.getViews()); } return sortedAccessViews; } public void closeAllViews(ViewContainer beside) { { /*List<ViewContainer<LoggingEvent>> closed = */ loggingEventViewManager.closeAllViews(beside); } { /*List<ViewContainer<AccessEvent>> closed = */ accessEventViewManager.closeAllViews(beside); } } public void minimizeAllViews(ViewContainer beside) { { /*List<ViewContainer<LoggingEvent>> closed = */ loggingEventViewManager.minimizeAllViews(beside); } { /*List<ViewContainer<AccessEvent>> closed = */ accessEventViewManager.minimizeAllViews(beside); } } public void removeInactiveViews(boolean onlyClosed, boolean clean) { { List<ViewContainer<LoggingEvent>> removed = loggingEventViewManager.removeInactiveViews(onlyClosed); if (clean) { for (ViewContainer current : removed) { EventWrapperViewPanel panel = current.getDefaultView(); panel.clear(); } } } { List<ViewContainer<AccessEvent>> removed = accessEventViewManager.removeInactiveViews(onlyClosed); if (clean) { for (ViewContainer current : removed) { EventWrapperViewPanel panel = current.getDefaultView(); panel.clear(); } } } } public void toggleVisible() { setFramesVisible(!isVisible()); } public void setFramesVisible(boolean visible) { setVisible(visible); processViewContainers(new VisibleContainerProcessor(visible)); } public void openInactiveLogs() { if (logger.isInfoEnabled()) logger.info("Open inactive log..."); Windows.showWindow(openInactiveLogsDialog, this, true); } public void showDebugDialog() { Windows.showWindow(debugDialog, MainFrame.this, true); } public void showPreferencesDialog() { Windows.showWindow(preferencesDialog, MainFrame.this, true); } public void showHelp() { openHelp("index.xhtml"); } public void showAboutDialog() { Windows.showWindow(aboutDialog, MainFrame.this, true); // if(!applicationPreferences.isMute() && sounds != null) // { // sounds.play(LilithSounds.ABOUT_SOUND); // } } public void cleanAllInactiveLogs() { loggingEventViewManager.removeInactiveViews(false); accessEventViewManager.removeInactiveViews(false); longTaskManager.startTask(new CleanAllInactiveCallable(this), "Clean all inactive..."); updateWindowMenus(); } class LoggingEventSourceListener implements EventSourceListener<LoggingEvent> { public void eventSourceAdded(EventSource<LoggingEvent> eventSource) { SwingUtilities.invokeLater(new LoggingSourceAddedRunnable(eventSource)); } public void eventSourceRemoved(EventSource<LoggingEvent> eventSource) { SwingUtilities.invokeLater(new LoggingSourceRemovedRunnable(eventSource)); } private class LoggingSourceAddedRunnable implements Runnable { EventSource<LoggingEvent> eventSource; public LoggingSourceAddedRunnable(EventSource<LoggingEvent> eventSource) { this.eventSource = eventSource; } public void run() { ViewContainer<LoggingEvent> container = retrieveLoggingViewContainer(eventSource); EventWrapperViewPanel<LoggingEvent> panel = container.getDefaultView(); panel.setState(LoggingViewState.ACTIVE); if (!applicationPreferences.isMute() && sounds != null) { sounds.play(LilithSounds.SOURCE_ADDED); } String primary = eventSource.getSourceIdentifier().getIdentifier(); Map<String, String> sourceNames = applicationPreferences.getSourceNames(); if (!sourceNames.containsKey(primary)) { sourceNames = new HashMap<String, String>(sourceNames); sourceNames.put(primary, primary); applicationPreferences.setSourceNames(sourceNames); } if (applicationPreferences.isAutoOpening()) { showLoggingView(eventSource); } else { updateWindowMenus(); } } } private class LoggingSourceRemovedRunnable implements Runnable { EventSource<LoggingEvent> eventSource; public LoggingSourceRemovedRunnable(EventSource<LoggingEvent> eventSource) { this.eventSource = eventSource; } public void run() { ViewContainer<LoggingEvent> container = retrieveLoggingViewContainer(eventSource); EventWrapperViewPanel<LoggingEvent> panel = container.getDefaultView(); panel.setState(LoggingViewState.INACTIVE); if (!applicationPreferences.isMute() && sounds != null) { sounds.play(LilithSounds.SOURCE_REMOVED); } if (applicationPreferences.isAutoClosing()) { loggingEventViewManager.closeViewContainer(container); } loggingEventSourceManager.removeEventProducer(eventSource.getSourceIdentifier()); updateWindowMenus(); } } } class AccessEventSourceListener implements EventSourceListener<AccessEvent> { public void eventSourceAdded(EventSource<AccessEvent> eventSource) { SwingUtilities.invokeLater(new AccessSourceAddedRunnable(eventSource)); } public void eventSourceRemoved(EventSource<AccessEvent> eventSource) { SwingUtilities.invokeLater(new AccessSourceRemovedRunnable(eventSource)); } private class AccessSourceAddedRunnable implements Runnable { EventSource<AccessEvent> eventSource; public AccessSourceAddedRunnable(EventSource<AccessEvent> eventSource) { this.eventSource = eventSource; } public void run() { ViewContainer<AccessEvent> container = retrieveAccessViewContainer(eventSource); EventWrapperViewPanel<AccessEvent> panel = container.getDefaultView(); panel.setState(LoggingViewState.ACTIVE); if (!applicationPreferences.isMute() && sounds != null) { sounds.play(LilithSounds.SOURCE_ADDED); } String primary = eventSource.getSourceIdentifier().getIdentifier(); Map<String, String> sourceNames = applicationPreferences.getSourceNames(); if (!sourceNames.containsKey(primary)) { sourceNames = new HashMap<String, String>(sourceNames); sourceNames.put(primary, primary); applicationPreferences.setSourceNames(sourceNames); } if (applicationPreferences.isAutoOpening()) { showAccessView(eventSource); } else { updateWindowMenus(); } } } private class AccessSourceRemovedRunnable implements Runnable { EventSource<AccessEvent> eventSource; public AccessSourceRemovedRunnable(EventSource<AccessEvent> eventSource) { this.eventSource = eventSource; } public void run() { ViewContainer<AccessEvent> container = retrieveAccessViewContainer(eventSource); EventWrapperViewPanel<AccessEvent> panel = container.getDefaultView(); panel.setState(LoggingViewState.INACTIVE); if (!applicationPreferences.isMute() && sounds != null) { sounds.play(LilithSounds.SOURCE_REMOVED); } if (applicationPreferences.isAutoClosing()) { accessEventViewManager.closeViewContainer(container); } accessEventSourceManager.removeEventProducer(eventSource.getSourceIdentifier()); updateWindowMenus(); } } } public String getPrimarySourceTitle(String primary) { if (primary == null) { return null; } Map<String, String> sourceNames = applicationPreferences.getSourceNames(); String resolvedName = sourceNames.get(primary); if (resolvedName != null && !resolvedName.equals(primary)) { if (applicationPreferences.isShowingIdentifier()) { return resolvedName + " [" + primary + "]"; } else { return resolvedName; } } return primary; } public String getPrimarySourceTitle(SourceIdentifier identifier) { return getPrimarySourceTitle(identifier.getIdentifier()); } public String getSourceTitle(SourceIdentifier identifier, String name) { String primary = getPrimarySourceTitle(identifier); String secondary = identifier.getSecondaryIdentifier(); if (secondary == null) { if (name == null) { return primary; } return primary + " - " + name; } if (name == null) { return primary + " - " + secondary; } return primary + " - " + name + " - " + secondary; } public String getLoggingSourceTitle(SourceIdentifier identifier, String name) { return getSourceTitle(identifier, name) + " (Logging)"; } public String getAccessSourceTitle(SourceIdentifier identifier, String name) { return getSourceTitle(identifier, name) + " (Access)"; } String resolveSourceTitle(ViewContainer container) { EventWrapperViewPanel defaultView = container.getDefaultView(); EventSource eventSource = defaultView.getEventSource(); boolean global = eventSource.isGlobal(); String name = null; if (!global) { Buffer buffer = defaultView.getSourceBuffer(); Object event = null; if (buffer != null) { event = buffer.get(0); } name = resolveName(event); } SourceIdentifier si = eventSource.getSourceIdentifier(); Class clazz = container.getWrappedClass(); String title; if (clazz == LoggingEvent.class) { title = getLoggingSourceTitle(si, name); } else { title = getAccessSourceTitle(si, name); } return title; } private static String resolveName(Object eventWrapperObj) { String name; String appId = null; if (eventWrapperObj instanceof EventWrapper) { EventWrapper wrapper = (EventWrapper) eventWrapperObj; Serializable evtObject = wrapper.getEvent(); LoggerContext context = null; if (evtObject instanceof LoggingEvent) { context = ((LoggingEvent) evtObject).getLoggerContext(); } else if (evtObject instanceof AccessEvent) { context = ((AccessEvent) evtObject).getLoggerContext(); } if (context != null) { name = context.getName(); if ("default".equals(name) || "".equals(name)) { name = null; } Map<String, String> props = context.getProperties(); if (props != null) { appId = props.get(LoggerContext.APPLICATION_IDENTIFIER_PROPERTY_NAME); } if (name != null) { if (appId == null || name.equals(appId)) { return name; } return name + "/" + appId; } return appId; } } return null; } public static void openUrl(URL url) { final Logger logger = LoggerFactory.getLogger(MainFrame.class); if (logger.isInfoEnabled()) logger.info("Opening URL {}. ", url); if (url == null) { return; } String[] cmdArray = resolveOpenCommandArray(url.toString()); if (cmdArray == null) { if (logger.isInfoEnabled()) logger.info("Can't open URL {} because no open command is defined for the current system.", url); return; } executeCommand(cmdArray); } public static void openUri(URI uri) { final Logger logger = LoggerFactory.getLogger(MainFrame.class); if (logger.isInfoEnabled()) logger.info("Opening URI {}. ", uri); if (uri == null) { return; } String[] cmdArray = resolveOpenCommandArray(uri.toString()); if (cmdArray == null) { if (logger.isInfoEnabled()) logger.info("Can't open URI {} because no open command is defined for the current system.", uri); return; } executeCommand(cmdArray); } private static void executeCommand(String[] cmdArray) { final Logger logger = LoggerFactory.getLogger(MainFrame.class); if (cmdArray == null) { return; } Runtime runtime = Runtime.getRuntime(); String commandString = Arrays.asList(cmdArray).toString(); try { Process process = runtime.exec(cmdArray); ProcessConsumerRunnable consumer = new ProcessConsumerRunnable(process); Thread t = new Thread(consumer, "Consuming command: " + commandString); t.setDaemon(true); t.start(); } catch (IOException e) { if (logger.isWarnEnabled()) logger.warn("Exception while trying to execute command {}!", commandString, e); } } // Windows: cmd /C start http://www.heise.de // Mac: open http://www.heise.de private static final String[] MAC_OPEN_URL_ARRAY = { "open", null }; private static final String[] WINDOWS_OPEN_URL_ARRAY = { "cmd", "/C", "start", null }; private static String[] resolveOpenCommandArray(String value) { if (value == null) { return null; } String[] result = null; if (isWindows) { result = new String[WINDOWS_OPEN_URL_ARRAY.length]; System.arraycopy(WINDOWS_OPEN_URL_ARRAY, 0, result, 0, WINDOWS_OPEN_URL_ARRAY.length); } else if (isMac) { result = new String[MAC_OPEN_URL_ARRAY.length]; System.arraycopy(MAC_OPEN_URL_ARRAY, 0, result, 0, MAC_OPEN_URL_ARRAY.length); } if (result != null) { for (int i = 0; i < result.length; i++) { if (result[i] == null) { result[i] = value; } } } return result; } void showFrame(ViewContainer container) { String title = resolveSourceTitle(container); ViewContainerFrame frame = new ViewContainerFrame(this, container); frame.setShowingToolbar(applicationPreferences.isShowingToolbar()); frame.setShowingStatusbar(applicationPreferences.isShowingStatusbar()); frame.setTitle(title); frame.setSize(800, 600); Windows.showWindow(frame, null, false); executeScrollToBottom(frame); } void showInternalFrame(ViewContainer container) { String title = resolveSourceTitle(container); ViewContainerInternalFrame frame = new ViewContainerInternalFrame(this, container); frame.setShowingStatusbar(applicationPreferences.isShowingStatusbar()); frame.setTitle(title); int count = desktop.getComponentCount(); final int titleBarHeight = resolveInternalTitlebarHeight(/*frame*/); frame.setBounds(titleBarHeight * (count % 10), titleBarHeight * (count % 10), 640, 480); // set bounds in any case desktop.add(frame); boolean maximize = applicationPreferences.isMaximizingInternalFrames(); if (maximize) { try { // must call after adding to the desktop frame.setMaximum(true); } catch (PropertyVetoException ex) { if (logger.isErrorEnabled()) logger.error("Vetoed maximizing!", ex); } } viewActions.setViewContainer(container); frame.setVisible(true); executeScrollToBottom(frame); } public void showTaskManager() { // don't add twice if (taskManagerFrame.isClosed()) { desktop.add(taskManagerFrame); desktop.validate(); } if (taskManagerFrame.isIcon()) { try { taskManagerFrame.setIcon(false); } catch (PropertyVetoException e) { // ignore } } if (!taskManagerFrame.isVisible()) { taskManagerFrame.setVisible(true); } taskManagerFrame.moveToFront(); try { taskManagerFrame.setSelected(true); } catch (PropertyVetoException e) { // ignore } } /** * Initial scroll to bottom must be executed slightly after making it visible so * it's using invokeLater, now. * * @param window the window that should scrollt to bottom is configured that way. */ private void executeScrollToBottom(ViewWindow window) { if (window != null) { ScrollToBottomRunnable runnable = new ScrollToBottomRunnable(window); SwingUtilities.invokeLater(runnable); } } private static class ScrollToBottomRunnable implements Runnable { private ViewWindow window; private ScrollToBottomRunnable(ViewWindow window) { this.window = window; } public void run() { ViewContainer viewContainer = window.getViewContainer(); if (viewContainer != null) { viewContainer.scrollToEvent(); } } } /** * This is only a heuristic and probably won't be correct for non-metal l&f... * * @return the height of the internal frames titlebar... */ private int resolveInternalTitlebarHeight(/*JInternalFrame frame*/) { int result = 24; /* InternalFrameUI ui = frame.getUI(); if(ui instanceof BasicInternalFrameUI) { BasicInternalFrameUI bui=(BasicInternalFrameUI) ui; result=bui.getNorthPane().getPreferredSize().height; if(logger.isDebugEnabled()) logger.debug("Resolved height of titlebar: {}", result); } */ if (logger.isDebugEnabled()) logger.debug("Height of titlebar: {}", result); return result; } private void showApplicationPathChangedDialog() { if (logger.isInfoEnabled()) logger.info("showApplicationPathChangedDialog()"); final Object[] options = { "Exit", "Cancel" }; Icon icon = null; { URL url = MainFrame.class.getResource("/tango/32x32/status/dialog-warning.png"); if (url != null) { icon = new ImageIcon(url); } } int result = JOptionPane.showOptionDialog(this, "You have changed the application path.\n" + "You need to restart for this change to take effect.\n\n" + "Exit now?", "Exit now?", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, icon, options, options[0]); if (result == 0) { exit(); } } private void showLookAndFeelChangedDialog() { if (logger.isInfoEnabled()) logger.info("showLookAndFeelChangedDialog()"); final Object[] options = { "Exit", "Cancel" }; Icon icon = null; { URL url = MainFrame.class.getResource("/tango/32x32/status/dialog-warning.png"); if (url != null) { icon = new ImageIcon(url); } } int result = JOptionPane.showOptionDialog(this, "You have changed the look & feel.\n" + "You need to restart for this change to take effect.\n\n" + "Exit now?", "Exit now?", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, icon, options, options[0]); if (result == 0) { exit(); } } public void exit() { if (applicationPreferences.isAskingBeforeQuit()) { // yes, I hate apps that ask this question... String dialogTitle = "Exit now?"; String message = "Are you really 100% sure that you want to quit?\nPlease do yourself a favour and think about it before you answer...\nExit now?"; int result = JOptionPane.showConfirmDialog(this, message, dialogTitle, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); if (JOptionPane.OK_OPTION != result) { return; } } if (logger.isInfoEnabled()) logger.info("Exiting..."); // this probably isn't necessary since jmdns registers a shutdown hook. if (senderService != null) { senderService.stop(); // if(logger.isInfoEnabled()) logger.info("Unregistering services..."); // // this can't be done in the shutdown hook... // jmDns.unregisterAllServices(); } if (applicationPreferences.isCleaningLogsOnExit()) { deleteInactiveLogs(); } applicationPreferences.setPreviousImportPath(importFileChooser.getCurrentDirectory()); applicationPreferences.setPreviousExportPath(exportFileChooser.getCurrentDirectory()); applicationPreferences.setPreviousOpenPath(openFileChooser.getCurrentDirectory()); applicationPreferences.flush(); longTaskManager.shutDown(); System.exit(0); } class ShowViewRunnable implements Runnable { private ViewContainer<?> container; public ShowViewRunnable(ViewContainer<?> container) { this.container = container; } public void run() { boolean isNew = false; if (container.getParent() == null) { isNew = true; if (!applicationPreferences.isUsingInternalFrames()) { showFrame(container); } else { showInternalFrame(container); } } updateWindowMenus(); ViewWindow window = container.resolveViewWindow(); if (!isNew || applicationPreferences.isAutoFocusingWindow()) { // reselected existing views should *always* be focused! window.focusWindow(); } } } private class PreferencesChangeListener implements PropertyChangeListener { @SuppressWarnings({ "unchecked" }) public void propertyChange(PropertyChangeEvent evt) { String propName = evt.getPropertyName(); if (ApplicationPreferences.SOUND_LOCATIONS_PROPERTY.equals(propName)) { if (sounds != null) { sounds.setSoundLocations((Map<String, String>) evt.getNewValue()); } return; } if (ApplicationPreferences.SOURCE_NAMES_PROPERTY.equals(propName) || ApplicationPreferences.SHOWING_IDENTIFIER_PROPERTY.equals(propName)) { updateSourceTitles(); return; } if (ApplicationPreferences.SOURCE_FILTERING_PROPERTY.equals(propName)) { updateStatus(); return; } if (ApplicationPreferences.BLACK_LIST_NAME_PROPERTY.equals(propName)) { updateStatus(); return; } if (ApplicationPreferences.WHITE_LIST_NAME_PROPERTY.equals(propName)) { updateStatus(); return; } if (ApplicationPreferences.MUTE_PROPERTY.equals(propName)) { if (sounds != null) { sounds.setMute((Boolean) evt.getNewValue()); } return; } if (ApplicationPreferences.APPLICATION_PATH_PROPERTY.equals(propName)) { File newPath = (File) evt.getNewValue(); File oldPath = applicationPreferences.getStartupApplicationPath(); if (oldPath != null) { File previousApplicationPathFile = new File(newPath, ApplicationPreferences.PREVIOUS_APPLICATION_PATH_FILENAME); FileWriter writer = null; try { writer = new FileWriter(previousApplicationPathFile); writer.append(oldPath.getAbsolutePath()); } catch (IOException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception while writing previous application path to file '" + previousApplicationPathFile.getAbsolutePath() + "'!", ex); } } finally { IOUtilities.closeQuietly(writer); } } showApplicationPathChangedDialog(); return; } if (ApplicationPreferences.LOOK_AND_FEEL_PROPERTY.equals(propName)) { showLookAndFeelChangedDialog(); return; } if (ApplicationPreferences.CONDITIONS_PROPERTY.equals(propName)) { updateConditions(); return; } if (ApplicationPreferences.PREVIOUS_SEARCH_STRINGS_PROPERTY.equals(propName)) { updatePreviousSearchStrings(); return; } if (ApplicationPreferences.RECENT_FILES_PROPERTY.equals(propName)) { updateRecentFiles(); return; } if (ApplicationPreferences.SHOWING_FULL_RECENT_PATH_PROPERTY.equals(propName)) { updateRecentFiles(); return; } if (ApplicationPreferences.LEVEL_COLORS_PROPERTY.equals(propName)) { levelColors = null; processViewContainers(UPDATE_VIEWS_CONTAINER_PROCESSOR); return; } if (ApplicationPreferences.STATUS_COLORS_PROPERTY.equals(propName)) { statusColors = null; processViewContainers(UPDATE_VIEWS_CONTAINER_PROCESSOR); return; } if (ApplicationPreferences.SHOWING_FULL_CALLSTACK_PROPERTY.equals(propName)) { processViewContainers(UPDATE_VIEWS_CONTAINER_PROCESSOR); return; } if (ApplicationPreferences.USING_WRAPPED_EXCEPTION_STYLE_PROPERTY.equals(propName)) { processViewContainers(UPDATE_VIEWS_CONTAINER_PROCESSOR); return; } if (ApplicationPreferences.SHOWING_STACKTRACE_PROPERTY.equals(propName)) { processViewContainers(UPDATE_VIEWS_CONTAINER_PROCESSOR); return; } if (ApplicationPreferences.SCALE_FACTOR_PROPERTY.equals(propName)) { updateViewScale(applicationPreferences.getScaleFactor()); return; } if (ApplicationPreferences.SHOWING_TOOLBAR_PROPERTY.equals(propName)) { setShowingToolbar(applicationPreferences.isShowingToolbar()); return; } if (ApplicationPreferences.SHOWING_STATUSBAR_PROPERTY.equals(propName)) { setShowingStatusbar(applicationPreferences.isShowingStatusbar()); return; } if (ApplicationPreferences.SHOWING_TIP_OF_THE_DAY_PROPERTY.equals(propName)) { setShowingTipOfTheDay(applicationPreferences.isShowingTipOfTheDay()); return; } if (ApplicationPreferences.CHECKING_FOR_UPDATE_PROPERTY.equals(propName)) { setCheckingForUpdate(applicationPreferences.isCheckingForUpdate()); return; } if (ApplicationPreferences.CHECKING_FOR_SNAPSHOT_PROPERTY.equals(propName)) { setCheckingForSnapshot(applicationPreferences.isCheckingForSnapshot()); return; } if (ApplicationPreferences.GLOBAL_LOGGING_ENABLED_PROPERTY.equals(propName)) { setGlobalLoggingEnabled(applicationPreferences.isGlobalLoggingEnabled()); return; } if (ApplicationPreferences.LOGGING_STATISTIC_ENABLED_PROPERTY.equals(propName)) { setStatisticsEnabled(applicationPreferences.isLoggingStatisticEnabled()); return; } if (ApplicationPreferences.TRAY_ACTIVE_PROPERTY.equals(propName)) { if (traySupport != null) { traySupport.setActive(applicationPreferences.isTrayActive()); } return; } if (ApplicationPreferences.COLORING_WHOLE_ROW_PROPERTY.equals(propName)) { coloringWholeRow = applicationPreferences.isColoringWholeRow(); processViewContainers(UPDATE_VIEWS_CONTAINER_PROCESSOR); //return; } } private void updateSourceTitles() { updateWindowMenus(); processViewContainers(sourceTitleContainerProcessor); } } private void setGlobalLoggingEnabled(boolean globalLoggingEnabled) { loggingFileDump.setEnabled(globalLoggingEnabled); accessFileDump.setEnabled(globalLoggingEnabled); } private void setStatisticsEnabled(boolean statisticsEnabled) { rrdLoggingEventHandler.setEnabled(statisticsEnabled); } private void setCheckingForUpdate(boolean checkingForUpdate) { preferencesDialog.setCheckingForUpdate(checkingForUpdate); checkForUpdateDialog.setCheckingForUpdate(checkingForUpdate); } private void setCheckingForSnapshot(boolean checkingForSnapshot) { preferencesDialog.setCheckingForSnapshot(checkingForSnapshot); // checkForUpdateDialog.setCheckingForSnapshot(checkingForSnapshot); } private void setShowingStatusbar(boolean showingStatusbar) { statusBar.setVisible(showingStatusbar); // change for all other open windows { SortedMap<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> views = getSortedLoggingViews(); for (Map.Entry<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> current : views.entrySet()) { setShowingStatusbar(current.getValue(), showingStatusbar); } } { SortedMap<EventSource<AccessEvent>, ViewContainer<AccessEvent>> views = getSortedAccessViews(); for (Map.Entry<EventSource<AccessEvent>, ViewContainer<AccessEvent>> current : views.entrySet()) { setShowingStatusbar(current.getValue(), showingStatusbar); } } } private void setShowingTipOfTheDay(boolean showingTipOfTheDay) { preferencesDialog.setShowingTipOfTheDay(showingTipOfTheDay); tipOfTheDayDialog.setShowingTipOfTheDay(showingTipOfTheDay); } private void setShowingToolbar(boolean showingToolbar) { toolbar.setVisible(showingToolbar); // change for all other open windows { SortedMap<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> views = getSortedLoggingViews(); for (Map.Entry<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> current : views.entrySet()) { setShowingToolbar(current.getValue(), showingToolbar); } } { SortedMap<EventSource<AccessEvent>, ViewContainer<AccessEvent>> views = getSortedAccessViews(); for (Map.Entry<EventSource<AccessEvent>, ViewContainer<AccessEvent>> current : views.entrySet()) { setShowingToolbar(current.getValue(), showingToolbar); } } } private void setShowingToolbar(ViewContainer container, boolean showingToolbar) { ViewWindow viewWindow = container.resolveViewWindow(); if (viewWindow instanceof ViewContainerFrame) { ViewContainerFrame viewContainerFrame = (ViewContainerFrame) viewWindow; viewContainerFrame.setShowingToolbar(showingToolbar); } } private void setShowingStatusbar(ViewContainer container, boolean showingStatusbar) { ViewWindow viewWindow = container.resolveViewWindow(); if (viewWindow != null) { viewWindow.setShowingStatusbar(showingStatusbar); } } private void updatePreviousSearchStrings() { List<String> previousSearchStrings = applicationPreferences.getPreviousSearchStrings(); processViewContainers(new PreviousSearchStringsContainerProcessor(previousSearchStrings)); } private void updateRecentFiles() { processViewActions(UPDATE_RECENT_FILES_ACTIONS_PROCESSOR); } public Condition getFindActiveCondition() { return findActiveCondition; } private void updateConditions() { List<SavedCondition> conditions = applicationPreferences.getConditions(); List<SavedCondition> active = new ArrayList<SavedCondition>(); if (conditions != null) { for (SavedCondition current : conditions) { if (current.isActive()) { active.add(current); } } } activeConditions = active; int activeCount = active.size(); if (activeCount > 0) { if (activeCount == 1) { findActiveCondition = active.get(0).getCondition(); } else { Or or = new Or(); List<Condition> cond = new ArrayList<Condition>(activeCount); for (SavedCondition current : active) { cond.add(current.getCondition()); } or.setConditions(cond); findActiveCondition = or; } } //flushCachedConditionResults(); processViewContainers(UPDATE_VIEWS_CONTAINER_PROCESSOR); List<String> conditionNames = applicationPreferences.getConditionNames(); processViewContainers(new ConditionNamesContainerProcessor(conditionNames)); processViewActions(new ConditionNamesActionsProcessor(conditionNames)); } private void processViewContainers(ViewContainerProcessor processor) { Map<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> loggingViews = loggingEventViewManager .getViews(); for (Map.Entry<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> current : loggingViews.entrySet()) { processor.process(current.getValue()); } Map<EventSource<AccessEvent>, ViewContainer<AccessEvent>> accessViews = accessEventViewManager.getViews(); for (Map.Entry<EventSource<AccessEvent>, ViewContainer<AccessEvent>> current : accessViews.entrySet()) { processor.process(current.getValue()); } } private void processViewActions(ViewActionsProcessor processor) { processor.process(viewActions); // process other frames Map<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> loggingViews = loggingEventViewManager .getViews(); for (Map.Entry<EventSource<LoggingEvent>, ViewContainer<LoggingEvent>> current : loggingViews.entrySet()) { ViewContainer<LoggingEvent> value = current.getValue(); ViewWindow window = value.resolveViewWindow(); if (window instanceof JFrame) { processor.process(window.getViewActions()); } } Map<EventSource<AccessEvent>, ViewContainer<AccessEvent>> accessViews = accessEventViewManager.getViews(); for (Map.Entry<EventSource<AccessEvent>, ViewContainer<AccessEvent>> current : accessViews.entrySet()) { ViewContainer<AccessEvent> value = current.getValue(); ViewWindow window = value.resolveViewWindow(); if (window instanceof JFrame) { processor.process(window.getViewActions()); } } } private class SourceTitleContainerProcessor implements ViewContainerProcessor { @Override public void process(ViewContainer<?> container) { ViewWindow window = container.resolveViewWindow(); if (window != null) { String title = resolveSourceTitle(container); window.setTitle(title); } } } private void updateViewScale(double scale) { processViewContainers(new UpdateScaleContainerProcessor(scale)); } /* private void flushCachedConditionResults() { colorsCache.clear(); } */ public void cleanObsoleteFiles() { File obsoleteDir = new File(startupApplicationPath, "sources"); if (obsoleteDir.isDirectory()) { longTaskManager.startTask(new CleanObsoleteCallable(obsoleteDir), "Clean obsolete files", "Deletes the directory '" + obsoleteDir.getAbsolutePath() + "' recursively."); } } public void deleteInactiveLogs() { deleteInactiveLogs(loggingFileFactory); deleteInactiveLogs(accessFileFactory); } protected void deleteInactiveLogs(LogFileFactory fileFactory) { List<SourceIdentifier> inactives = collectInactiveLogs(fileFactory); for (SourceIdentifier si : inactives) { File dataFile = fileFactory.getDataFile(si); File indexFile = fileFactory.getIndexFile(si); if (dataFile.delete()) { if (logger.isInfoEnabled()) logger.info("Deleted {}", dataFile); } if (indexFile.delete()) { if (logger.isInfoEnabled()) logger.info("Deleted {}", indexFile); } } } public List<SourceIdentifier> collectInactiveLogs(LogFileFactory fileFactory) { List<SourceIdentifier> result = new ArrayList<SourceIdentifier>(); File logsRoot = fileFactory.getBaseDir(); File[] sources = logsRoot.listFiles(new DirectoryFilter()); if (sources != null) { for (File f : sources) { collectInactiveLogs(fileFactory, f, result); } if (logger.isDebugEnabled()) logger.debug("Inactive logs: {}", result); } return result; } private void collectInactiveLogs(LogFileFactory fileFactory, File sourceDir, List<SourceIdentifier> inactiveLogs) { String primary = sourceDir.getName(); File[] logs = sourceDir.listFiles(new LogFileFilter(fileFactory)); String extension = fileFactory.getDataFileExtension(); for (File f : logs) { String abs = f.getAbsolutePath(); abs = abs.substring(0, abs.length() - extension.length()); File active = new File(abs + FileConstants.ACTIVE_FILE_EXTENSION); if (!active.isFile()) { String secondary = f.getName(); secondary = secondary.substring(0, secondary.length() - extension.length()); inactiveLogs.add(new SourceIdentifier(primary, secondary)); } } } public static void copyText(String text) { Clipboard systemClipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable transferableText = new StringSelection(text); systemClipboard.setContents(transferableText, null); } public class EventSourceComparator<T extends Serializable> implements Comparator<EventSource<T>> { public int compare(EventSource<T> o1, EventSource<T> o2) { if (o1 == o2) { return 0; } if (o1 == null) { return -1; } if (o2 == null) { return 1; } SourceIdentifier si1 = o1.getSourceIdentifier(); SourceIdentifier si2 = o2.getSourceIdentifier(); if (si1 == si2) { return 0; } if (si1 == null) { return -1; } if (si2 == null) { return 1; } String primary1 = getPrimarySourceTitle(si1); String primary2 = getPrimarySourceTitle(si2); if (primary1 != null && primary2 != null) { int compare = primary1.compareTo(primary2); if (compare != 0) { return compare; } } return o1.compareTo(o2); } } private class MainWindowListener extends WindowAdapter { @Override public void windowClosing(WindowEvent e) { if (traySupport != null && traySupport.isActive() && applicationPreferences.isHidingOnClose()) { setFramesVisible(false); } else { exit(); } } } private class ShutdownRunnable implements Runnable { public void run() { if (logger.isInfoEnabled()) logger.info("Executing shutdown hook..."); if (gotoSource != null) { gotoSource.stop(); gotoSource = null; } for (AutostartRunnable current : autostartProcesses) { current.destroyProcess(); } if (logger.isInfoEnabled()) logger.info("Finished executing shutdown hook..."); } } public static class AutostartRunnable implements Runnable { private final Logger logger = LoggerFactory.getLogger(MainFrame.class); private File file; private Process process; public AutostartRunnable(File file) { this.file = file; } public void destroyProcess() { if (process != null) { process.destroy(); } } public void run() { try { if (logger.isInfoEnabled()) logger.info("Starting '{}'.", file.getAbsolutePath()); process = Runtime.getRuntime().exec(file.getAbsolutePath()); Thread errThread = new Thread(new ErrorConsumerRunnable(process.getErrorStream())); errThread.setDaemon(true); errThread.start(); Thread outThread = new Thread(new OutConsumerRunnable(process.getInputStream())); outThread.setDaemon(true); outThread.start(); int exitCode = process.waitFor(); if (logger.isInfoEnabled()) { logger.info("Execution of '{}' finished with exitCode {}.", file.getAbsolutePath(), exitCode); } } catch (IOException e) { if (logger.isWarnEnabled()) { logger.warn("Exception while executing '" + file.getAbsolutePath() + "'!", e); } } catch (InterruptedException e) { if (logger.isDebugEnabled()) { logger.debug("Execution of '" + file.getAbsolutePath() + "' was interrupted.", e); } } } abstract class AbstractOutputConsumerRunnable implements Runnable { private BufferedReader inputReader; public AbstractOutputConsumerRunnable(InputStream input) { inputReader = new BufferedReader(new InputStreamReader(input)); } public void run() { try { for (;;) { String line = inputReader.readLine(); if (line == null) { break; } processLine(line); } } catch (IOException e) { if (logger.isDebugEnabled()) { logger.debug("Exception while reading from process '" + file.getAbsolutePath() + "'.", e); } } } public abstract void processLine(String line); } private class OutConsumerRunnable extends AbstractOutputConsumerRunnable { public OutConsumerRunnable(InputStream input) { super(input); } public void processLine(String line) { if (logger.isInfoEnabled()) logger.info("{}: {}", file.getAbsolutePath(), line); } } private class ErrorConsumerRunnable extends AbstractOutputConsumerRunnable { public ErrorConsumerRunnable(InputStream input) { super(input); } public void processLine(String line) { System.err.println(file.getAbsolutePath() + ": " + line); } } } public static class ProcessConsumerRunnable implements Runnable { private final Logger logger = LoggerFactory.getLogger(MainFrame.class); private Process process; public ProcessConsumerRunnable(Process process) { this.process = process; } public void destroyProcess() { if (process != null) { process.destroy(); } } public void run() { try { Thread errThread = new Thread(new ErrorConsumerRunnable(process.getErrorStream())); errThread.setDaemon(true); errThread.start(); Thread outThread = new Thread(new OutConsumerRunnable(process.getInputStream())); outThread.setDaemon(true); outThread.start(); int exitCode = process.waitFor(); if (logger.isDebugEnabled()) logger.debug("Execution finished with exitCode {}.", exitCode); } catch (InterruptedException e) { if (logger.isDebugEnabled()) logger.debug("Execution of openUrl process was interrupted.", e); } } abstract class AbstractOutputConsumerRunnable implements Runnable { private BufferedReader inputReader; public AbstractOutputConsumerRunnable(InputStream input) { inputReader = new BufferedReader(new InputStreamReader(input)); } public void run() { try { for (;;) { String line = inputReader.readLine(); if (line == null) { break; } processLine(line); } } catch (IOException e) { if (logger.isDebugEnabled()) logger.debug("Exception while reading from openUrl process.", e); } } public abstract void processLine(String line); } private class OutConsumerRunnable extends AbstractOutputConsumerRunnable { public OutConsumerRunnable(InputStream input) { super(input); } public void processLine(String line) { if (logger.isDebugEnabled()) logger.debug("{}", line); } } private class ErrorConsumerRunnable extends AbstractOutputConsumerRunnable { public ErrorConsumerRunnable(InputStream input) { super(input); } public void processLine(String line) { System.err.println("openUrl: " + line); } } } private static String readUrl(String url) { final Logger logger = LoggerFactory.getLogger(MainFrame.class); // Create an instance of HttpClient. CloseableHttpClient client = HttpClientBuilder.create().build(); HttpContext localContext = new BasicHttpContext(); HttpGet httpget = new HttpGet(url); try { HttpResponse response = client.execute(httpget, localContext); StatusLine status = response.getStatusLine(); if (status.getStatusCode() != HttpStatus.OK.getCode()) { if (logger.isWarnEnabled()) logger.warn("Status while retrieving '{}': {}", url, status); return null; } HttpEntity entity = response.getEntity(); String result = EntityUtils.toString(entity); EntityUtils.consume(entity); return result; } catch (IOException e) { if (logger.isWarnEnabled()) logger.warn("Exception while retrieving '{}'!", url, e); return null; } finally { try { client.close(); } catch (IOException e) { if (logger.isWarnEnabled()) logger.warn("Exception while closing down HttpClient!", e); } } } private class CheckForUpdateRunnable implements Runnable { private static final String RELEASE_VERSION_URL = "http://lilith.huxhorn.de/release-version.txt"; private static final String SNAPSHOT_VERSION_URL = "http://lilith.huxhorn.de/snapshot-version.txt"; private boolean showAlways; private boolean checkSnapshot; public CheckForUpdateRunnable(boolean showAlways, boolean checkSnapshot) { this.showAlways = showAlways; this.checkSnapshot = checkSnapshot; } public VersionBundle retrieveVersion(String url) { return VersionBundle.fromString(readUrl(url)); } public String retrieveChanges(String currentVersion) { final String url = "http://lilith.huxhorn.de/releases/" + currentVersion + ".xhtml"; return readUrl(url); } public void run() { VersionBundle releaseVersionBundle = retrieveVersion(RELEASE_VERSION_URL); int compare = Lilith.APP_VERSION_BUNDLE.compareTo(releaseVersionBundle); if (compare < 0) { String version = releaseVersionBundle.getVersion(); String message = "New release: " + version; String changes = retrieveChanges(version); SwingUtilities.invokeLater(new ShowUpdateDialog(message, changes)); return; } if (!Lilith.APP_SNAPSHOT && compare > 0) { String version = releaseVersionBundle.getVersion(); String message = "OH HAI! You can haz newzest release version!!1"; String changes = retrieveChanges(version); SwingUtilities.invokeLater(new ShowUpdateDialog(message, changes)); return; } if (Lilith.APP_SNAPSHOT || checkSnapshot) { // check for snapshot if either checking is enabled or we are already using a snapshot VersionBundle snapshotVersionBundle = retrieveVersion(SNAPSHOT_VERSION_URL); compare = Lilith.APP_VERSION_BUNDLE.compareTo(snapshotVersionBundle); if (compare < 0) { String version = snapshotVersionBundle.getVersion(); Date d = new Date(snapshotVersionBundle.getTimestamp()); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"); String message = "New snapshot: " + version + "-" + format.format(d); String changes = retrieveChanges(version); SwingUtilities.invokeLater(new ShowUpdateDialog(message, changes)); return; } if (compare > 0) { String version = snapshotVersionBundle.getVersion(); String message = "OH HAI! You can haz newzest snapshot version!!1"; String changes = retrieveChanges(version); SwingUtilities.invokeLater(new ShowUpdateDialog(message, changes)); return; } } if (showAlways) { String message = null; // up to date String changes = retrieveChanges(Lilith.APP_VERSION_BUNDLE.getVersion()); SwingUtilities.invokeLater(new ShowUpdateDialog(message, changes)); } } } private class ShowUpdateDialog implements Runnable { private String message; private String changes; public ShowUpdateDialog(String message, String changes) { this.message = message; this.changes = changes; } public void run() { MainFrame.this.showUpdateDialog(message, changes); } } private void showUpdateDialog(String message, String changes) { checkForUpdateDialog.setMessage(message); checkForUpdateDialog.setChanges(changes); if (logger.isDebugEnabled()) logger.debug("Check for update: message='{}', changes='{}'", message, changes); Windows.showWindow(checkForUpdateDialog, this, true); } /* private class ColorsCollectionRunnable implements Runnable { private final Logger logger = LoggerFactory.getLogger(ColorsCollectionRunnable.class); public void run() { for(;;) { try { SoftColorsReference ref= (SoftColorsReference) colorsReferenceQueue.remove(); EventIdentifier id = ref.getId(); colorsCache.remove(id); if(logger.isDebugEnabled()) logger.debug("Removed cached color for {}.", id); } catch (InterruptedException e) { break; } } } } */ private class MainTaskListener implements TaskListener<Long> { private final Logger logger = LoggerFactory.getLogger(MainTaskListener.class); public void taskCreated(Task<Long> longTask) { if (logger.isInfoEnabled()) logger.info("Task {} created.", longTask.getName()); updateTaskStatus(); } public void executionFailed(Task<Long> longTask, ExecutionException exception) { if (logger.isWarnEnabled()) logger.warn("Execution of task {} failed!", longTask.getName(), exception); String message = "Execution of task " + longTask.getName() + " failed!"; Throwable cause = exception.getCause(); if (cause == null) { cause = exception; } String causeMsg = cause.getMessage(); if (causeMsg == null) { causeMsg = cause.toString(); } message = message + "\n" + causeMsg; JOptionPane.showMessageDialog(MainFrame.this, message, "Exception while executing task...", JOptionPane.ERROR_MESSAGE); updateTaskStatus(); } public void executionFinished(Task<Long> longTask, Long result) { if (logger.isInfoEnabled()) logger.info("Execution of task {} finished!", longTask.getName()); updateTaskStatus(); Callable<Long> callable = longTask.getCallable(); if (callable instanceof IndexingCallable) { IndexingCallable iCallable = (IndexingCallable) callable; File dataFile = iCallable.getDataFile(); File indexFile = iCallable.getIndexFile(); createViewFor(dataFile, indexFile, true); return; } if (callable instanceof Log4jImportCallable) { Log4jImportCallable iCallable = (Log4jImportCallable) callable; AppendOperation<EventWrapper<LoggingEvent>> buffer = iCallable.getBuffer(); if (buffer instanceof CodecFileBuffer) { CodecFileBuffer cfb = (CodecFileBuffer) buffer; File dataFile = cfb.getDataFile(); File indexFile = cfb.getIndexFile(); cfb.dispose(); createViewFor(dataFile, indexFile, false); } return; } if (callable instanceof JulImportCallable) { JulImportCallable iCallable = (JulImportCallable) callable; AppendOperation<EventWrapper<LoggingEvent>> buffer = iCallable.getBuffer(); if (buffer instanceof CodecFileBuffer) { CodecFileBuffer cfb = (CodecFileBuffer) buffer; File dataFile = cfb.getDataFile(); File indexFile = cfb.getIndexFile(); cfb.dispose(); createViewFor(dataFile, indexFile, false); } } } public void executionCanceled(Task<Long> longTask) { if (logger.isInfoEnabled()) logger.info("Execution of task {} canceled!", longTask.getName()); Callable<Long> c = longTask.getCallable(); if (c instanceof ExportCallable) { if (logger.isInfoEnabled()) logger.info("Done? {}", longTask.getFuture().isDone()); ExportCallable ec = (ExportCallable) c; FileBuffer output = ec.getOutput(); output.reset(); File dataFile = output.getDataFile(); if (dataFile.isFile()) { if (dataFile.delete()) { if (logger.isInfoEnabled()) logger.info("Deleted {}.", dataFile.getAbsolutePath()); if (dataFile.isFile()) { if (logger.isWarnEnabled()) logger.warn("WTF???? I just deleted {} and now it's still a file?!", dataFile.getAbsolutePath()); } if (dataFile.exists()) { if (logger.isWarnEnabled()) logger.warn("WTF???? I just deleted {} and now it still exists?!", dataFile.getAbsolutePath()); } } else { if (logger.isWarnEnabled()) logger.warn("Couldn't delete {}.", dataFile.getAbsolutePath()); } } else { if (logger.isWarnEnabled()) logger.warn("WTF? {}", dataFile.getAbsolutePath()); } } updateTaskStatus(); } public void progressUpdated(Task<Long> longTask, int progress) { if (logger.isDebugEnabled()) logger.debug("Progress of task {} updated to {}.", longTask.getName(), progress); updateTaskStatus(); } } }