Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src')
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/activator/CoreBundleActivator.java73
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/interfaces/IPreferenceKeys.java43
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/interfaces/ITracing.java21
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/LogManager.java385
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/PreferencesInitializer.java49
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/Startup.java38
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelStateChangeListener.java37
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelTraceListener.java182
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelTraceListenerManager.java137
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/nls/Messages.java36
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/nls/Messages.properties8
11 files changed, 1009 insertions, 0 deletions
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/activator/CoreBundleActivator.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/activator/CoreBundleActivator.java
new file mode 100644
index 000000000..ec97a63bf
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/activator/CoreBundleActivator.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.log.core.activator;
+
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.tcf.te.runtime.tracing.TraceHandler;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class CoreBundleActivator extends Plugin {
+ // The shared instance
+ private static CoreBundleActivator plugin;
+ // The trace handler instance
+ private static TraceHandler traceHandler;
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static CoreBundleActivator getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Convenience method which returns the unique identifier of this plugin.
+ */
+ public static String getUniqueIdentifier() {
+ if (getDefault() != null && getDefault().getBundle() != null) {
+ return getDefault().getBundle().getSymbolicName();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the bundles trace handler.
+ *
+ * @return The bundles trace handler.
+ */
+ public static TraceHandler getTraceHandler() {
+ if (traceHandler == null) {
+ traceHandler = new TraceHandler(getUniqueIdentifier());
+ }
+ return traceHandler;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugin#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/interfaces/IPreferenceKeys.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/interfaces/IPreferenceKeys.java
new file mode 100644
index 000000000..226a31052
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/interfaces/IPreferenceKeys.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.log.core.interfaces;
+
+
+/**
+ * TCF logging bundle preference key identifiers.
+ */
+public interface IPreferenceKeys {
+ /**
+ * Common prefix for all core preference keys
+ */
+ public final String PREFIX = "tcf.log.core."; //$NON-NLS-1$
+
+ /**
+ * If set to <code>true</code>, back-end communication is logged.
+ */
+ public final String PREF_LOGGING_ENABLED = PREFIX + "enabled"; //$NON-NLS-1$
+
+ /**
+ * If set to <code>true</code>, locator heart beat events are logged.
+ */
+ public final String PREF_SHOW_HEARTBEATS = PREFIX + "show.heartbeats"; //$NON-NLS-1$
+
+ /**
+ * The maximum number of bytes the log files are allowed to grow to, in bytes.
+ * Defaults to 5MB.
+ */
+ public final String PREF_MAX_FILE_SIZE = PREFIX + "limits.fileSize"; //$NON-NLS-1$
+
+ /**
+ * The maximum number of files kept in the cycle.
+ * Defaults to 5.
+ */
+ public final String PREF_MAX_FILES_IN_CYCLE = PREFIX + "limits.inCycle"; //$NON-NLS-1$
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/interfaces/ITracing.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/interfaces/ITracing.java
new file mode 100644
index 000000000..afef953b7
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/interfaces/ITracing.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.log.core.interfaces;
+
+/**
+ * TCF logging tracing identifiers.
+ */
+public interface ITracing {
+
+ /**
+ * If enabled, prints information about the logging channel trace listener method invocations.
+ */
+ public static String ID_TRACE_CHANNEL_TRACE_LISTENER = "trace/channelTraceListener"; //$NON-NLS-1$
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/LogManager.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/LogManager.java
new file mode 100644
index 000000000..810da446e
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/LogManager.java
@@ -0,0 +1,385 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.log.core.internal;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tcf.protocol.IChannel;
+import org.eclipse.tcf.protocol.IPeer;
+import org.eclipse.tcf.protocol.Protocol;
+import org.eclipse.tcf.te.tcf.log.core.activator.CoreBundleActivator;
+import org.eclipse.tcf.te.tcf.log.core.interfaces.IPreferenceKeys;
+import org.eclipse.tcf.te.tcf.log.core.internal.listener.ChannelStateChangeListener;
+import org.eclipse.tcf.te.tcf.log.core.internal.listener.ChannelTraceListener;
+import org.eclipse.tcf.te.tcf.log.core.internal.nls.Messages;
+import org.eclipse.tcf.te.tcf.core.Tcf;
+import org.eclipse.tcf.te.tcf.core.interfaces.listeners.IChannelStateChangeListener;
+import org.eclipse.tcf.te.tcf.core.interfaces.listeners.IProtocolStateChangeListener;
+
+
+/**
+ * TCF logging log manager implementation.
+ */
+public final class LogManager implements IProtocolStateChangeListener {
+ // Reference to the channel state change listener
+ private IChannelStateChangeListener channelStateChangeListener;
+
+ // Maps file writer per log file base name
+ private final Map<String, FileWriter> fileWriterMap = new HashMap<String, FileWriter>();
+
+ // Maximum log file size in bytes
+ private long maxFileSize;
+ // Maximum number of files in cycle
+ private int maxInCycle;
+
+ /*
+ * Thread save singleton instance creation.
+ */
+ private static class LazyInstance {
+ public static LogManager instance = new LogManager();
+ }
+
+ /**
+ * Constructor.
+ */
+ /* default */ LogManager() {
+ super();
+
+ // initialize from preferences
+ initializeFromPreferences();
+ }
+
+ /**
+ * Returns the singleton instance.
+ */
+ public static LogManager getInstance() {
+ return LazyInstance.instance;
+ }
+
+ /**
+ * Dispose the log manager instance.
+ */
+ public void dispose() {
+ String message = NLS.bind(Messages.ChannelTraceListener_logManagerDispose_message,
+ ChannelTraceListener.DATE_FORMAT.format(new Date(System.currentTimeMillis())));
+ for (FileWriter writer : fileWriterMap.values()) {
+ try {
+ writer.write(message);
+ writer.write("\n"); //$NON-NLS-1$
+ } catch (IOException e) {
+ /* ignored on purpose */
+ } finally {
+ try {
+ writer.flush();
+ writer.close();
+ } catch (IOException e) {
+ /* ignored on purpose */
+ }
+ }
+ }
+ fileWriterMap.clear();
+ }
+
+ /**
+ * Initialize the log manager based on the current
+ * preference settings
+ */
+ private void initializeFromPreferences() {
+ String fileSize = Platform.getPreferencesService().getString(CoreBundleActivator.getUniqueIdentifier(),
+ IPreferenceKeys.PREF_MAX_FILE_SIZE, "5M", null); //$NON-NLS-1$
+
+ try {
+ // If the last character is either K, M or G -> convert to bytes
+ char lastChar = fileSize.toUpperCase().charAt(fileSize.length() - 1);
+ if ('K' == lastChar || 'M' == lastChar || 'G' == lastChar) {
+ maxFileSize = Long.parseLong(fileSize.substring(0, fileSize.length() - 1));
+ switch (lastChar) {
+ case 'K':
+ maxFileSize = maxFileSize * 1024;
+ break;
+ case 'M':
+ maxFileSize = maxFileSize * 1024 * 1024;
+ break;
+ case 'G':
+ maxFileSize = maxFileSize * 1024 * 1024 * 1024;
+ break;
+ }
+ } else {
+ maxFileSize = Long.parseLong(fileSize);
+ }
+ } catch (NumberFormatException e) {
+ maxFileSize = 5242880L;
+ }
+
+ maxInCycle = Platform.getPreferencesService().getInt(CoreBundleActivator.getUniqueIdentifier(),
+ IPreferenceKeys.PREF_MAX_FILES_IN_CYCLE, 5, null);
+ }
+
+ /**
+ * Create, register and initialize the listeners.
+ * <p>
+ * <b>Note:</b> This method is supposed to be called from {@link Startup} only!
+ */
+ /* default */ final void initListeners() {
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ // If the channel state change listener instance has been created
+ // already, there is nothing left to do here
+ if (channelStateChangeListener != null) return;
+
+ // Register ourself as protocol change listener
+ Tcf.addProtocolStateChangeListener(this);
+
+ // Create and register the channel state change listener
+ channelStateChangeListener = new ChannelStateChangeListener();
+ Tcf.addChannelStateChangeListener(channelStateChangeListener);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.tcf.core.interfaces.listeners.IProtocolStateChangeListener#stateChanged(boolean)
+ */
+ @Override
+ public void stateChanged(boolean state) {
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ // On shutdown, get the listener removed and disposed
+ if (!state) {
+ Tcf.removeChannelStateChangeListener(channelStateChangeListener);
+ channelStateChangeListener = null;
+
+ Tcf.removeProtocolStateChangeListener(this);
+ }
+ }
+
+ /**
+ * Returns the file writer instance to use for the given channel.
+ *
+ * @param channel The channel. Must not be <code>null</code>.
+ * @return The file writer instance or <code>null</code>.
+ */
+ public FileWriter getWriter(IChannel channel) {
+ Assert.isNotNull(channel);
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ // Before looking up the writer, check the file limits
+ checkLimits(channel);
+
+ String logName = getLogName(channel);
+ FileWriter writer = logName != null ? fileWriterMap.get(logName) : null;
+ if (writer == null && logName != null) {
+ // Create the writer
+ IPath path = getLogDir();
+ if (path != null) {
+ path = path.append(logName + ".log"); //$NON-NLS-1$
+ try {
+ writer = new FileWriter(path.toFile(), true);
+ fileWriterMap.put(logName, writer);
+ } catch (IOException e) {
+ /* ignored on purpose */
+ }
+ }
+ }
+
+ return writer;
+ }
+
+ /**
+ * Close the writer instance used for the given channel.
+ *
+ * @param channel The channel. Must not be <code>null</code>.
+ * @param message The last message to write or <code>null</code>.
+ */
+ public void closeWriter(IChannel channel, String message) {
+ Assert.isNotNull(channel);
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ // Remove the writer from the map
+ String logName = getLogName(channel);
+ FileWriter writer = logName != null ? fileWriterMap.remove(logName) : null;
+ if (writer != null) {
+ try {
+ // If specified, write the last message.
+ if (message != null) {
+ writer.write(message);
+ writer.write("\n"); //$NON-NLS-1$
+ }
+ } catch (IOException e) {
+ /* ignored on purpose */
+ } finally {
+ try {
+ writer.flush();
+ writer.close();
+ } catch (IOException e) {
+ /* ignored on purpose */
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the log file base name for the given peer id.
+ *
+ * @param channel The channel. Must not be <code>null</code>.
+ * @return The log file base name.
+ */
+ public String getLogName(IChannel channel) {
+ Assert.isNotNull(channel);
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ String logName = null;
+
+ IPeer peer = channel.getRemotePeer();
+ if (peer != null) {
+ // Get the peer name
+ logName = peer.getName();
+
+ // Get the peer host IP address
+ String ip = peer.getAttributes().get(IPeer.ATTR_IP_HOST);
+ // Fallback: The peer id
+ if (ip == null || "".equals(ip.trim())) { //$NON-NLS-1$
+ ip = peer.getID();
+ }
+
+ // Append the peer host IP address
+ if (ip != null && !"".equals(ip.trim())) { //$NON-NLS-1$
+ logName += " " + ip.trim(); //$NON-NLS-1$
+ }
+
+ // Unify name and replace all undesired characters with '_'
+ logName = makeValid(logName);
+ }
+
+ return logName;
+ }
+
+ /**
+ * Replaces a set of predefined patterns with underscore to
+ * make a valid name.
+ *
+ * @param name The name. Must not be <code>null</code>.
+ * @return The modified name.
+ */
+ private String makeValid(String name) {
+ Assert.isNotNull(name);
+
+ String result = name.replaceAll("\\s", "_"); //$NON-NLS-1$ //$NON-NLS-2$
+ result = result.replaceAll("[:/\\;,]", "_"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ return result;
+ }
+
+ /**
+ * Returns the log directory.
+ *
+ * @return The log directory.
+ */
+ public IPath getLogDir() {
+ IPath logDir = null;
+
+ try {
+ File file = CoreBundleActivator.getDefault().getStateLocation().append(".logs").toFile(); //$NON-NLS-1$
+ if (!file.exists()) file.mkdirs();
+ if (file.canRead() && file.isDirectory()) {
+ logDir = new Path(file.toString());
+ }
+ } catch (IllegalStateException e) {
+ // Ignored: Workspace less environment (-data @none)
+ }
+
+ if (logDir == null) {
+ // First fallback: ${HOME}/.tcf/.logs
+ File file = new Path(System.getProperty("user.home")).append(".tcf/.logs").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ if (!file.exists()) file.mkdirs();
+ if (file.canRead() && file.isDirectory()) {
+ logDir = new Path(file.toString());
+ }
+ }
+
+ if (logDir == null) {
+ // Second fallback: ${TEMP}/.tcf/.logs
+ File file = new Path(System.getProperty("java.io.tmpdir")).append(".tcf/.logs").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ if (!file.exists()) file.mkdirs();
+ if (file.canRead() && file.isDirectory()) {
+ logDir = new Path(file.toString());
+ }
+ }
+
+ return logDir;
+ }
+
+ /**
+ * Checks the limits set by the preferences.
+ *
+ * @param channel The channel. Must not be <code>null</code>.
+ * @return The checked file writer instance.
+ */
+ private void checkLimits(IChannel channel) {
+ Assert.isNotNull(channel);
+
+ String logName = getLogName(channel);
+ if (logName != null && !"".equals(logName.trim())) { //$NON-NLS-1$
+ IPath path = getLogDir();
+ if (path != null) {
+ IPath fullPath = path.append(logName + ".log"); //$NON-NLS-1$
+ File file = fullPath.toFile();
+ if (file.exists()) {
+ long size = file.length();
+ if (size >= maxFileSize) {
+ // Max log file size reached -> cycle files
+
+ // If there is an active writer, flush and close the writer
+ closeWriter(channel, null);
+
+ // Determine if the maximum number of files in the cycle has been reached
+ File maxFileInCycle = path.append(logName + "_" + maxInCycle + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ if (maxFileInCycle.exists()) {
+ // We have to rotate the full cycle, first in cycle to be removed.
+ int no = 1;
+ File fileInCycle = path.append(logName + "_" + no + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ fileInCycle.delete();
+
+ while (no <= maxInCycle) {
+ no++;
+ fileInCycle = path.append(logName + "_" + no + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ File renameTo = path.append(logName + "_" + (no - 1) + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ fileInCycle.renameTo(renameTo);
+ }
+
+ // Rename the log file
+ file.renameTo(maxFileInCycle);
+ } else {
+ // Not at the limit, find the next file name in the cycle
+ int no = 1;
+ File fileInCycle = path.append(logName + "_" + no + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ while (fileInCycle.exists()) {
+ no++;
+ fileInCycle = path.append(logName + "_" + no + ".log").toFile(); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ Assert.isTrue(no <= maxInCycle);
+
+ // Rename the log file
+ file.renameTo(fileInCycle);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/PreferencesInitializer.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/PreferencesInitializer.java
new file mode 100644
index 000000000..5207de915
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/PreferencesInitializer.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.log.core.internal;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.tcf.te.tcf.log.core.activator.CoreBundleActivator;
+import org.eclipse.tcf.te.tcf.log.core.interfaces.IPreferenceKeys;
+
+
+/**
+ * TCF logging bundle preference initializer.
+ */
+public class PreferencesInitializer extends AbstractPreferenceInitializer {
+
+ /**
+ * Constructor.
+ */
+ public PreferencesInitializer() {
+ super();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences()
+ */
+ @Override
+ public void initializeDefaultPreferences() {
+ // Get the bundles preferences manager
+ IEclipsePreferences prefs = DefaultScope.INSTANCE.getNode(CoreBundleActivator.getUniqueIdentifier());
+ if (prefs != null) {
+ // [Hidden] Enable back-end communication logging: default on
+ prefs.putBoolean(IPreferenceKeys.PREF_LOGGING_ENABLED, true);
+ // [Hidden] Heat beat events: default off
+ prefs.putBoolean(IPreferenceKeys.PREF_SHOW_HEARTBEATS, false);
+ // [Hidden] Maximum log file size in bytes: default 5M
+ prefs.put(IPreferenceKeys.PREF_MAX_FILE_SIZE, "5M"); //$NON-NLS-1$
+ // [Hidden] Maximum number of log files in cycle: default 5
+ prefs.putInt(IPreferenceKeys.PREF_MAX_FILES_IN_CYCLE, 5);
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/Startup.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/Startup.java
new file mode 100644
index 000000000..abc0aa209
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/Startup.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.log.core.internal;
+
+import org.eclipse.tcf.protocol.Protocol;
+
+
+/**
+ * Class loaded by the TCF core framework when the framework is fired up. The static
+ * constructor of the class will trigger the registration of the listeners in order
+ * to log the communication from the point the framework started up.
+ * <p>
+ * <b>Note:</b> This will effectively trigger {@link CoreBundleActivator#start(org.osgi.framework.BundleContext)}
+ * to be called.
+ */
+public class Startup {
+
+ static {
+ // We might get here on shutdown as well, and if TCF has not
+ // been loaded, than we will run into an NPE. Lets double check.
+ if (Protocol.getEventQueue() != null) {
+ // Execute the listener registration within the TCF dispatch thread
+ Protocol.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ LogManager.getInstance().initListeners();
+ }
+ });
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelStateChangeListener.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelStateChangeListener.java
new file mode 100644
index 000000000..49056f42e
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelStateChangeListener.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.log.core.internal.listener;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.tcf.protocol.IChannel;
+import org.eclipse.tcf.te.tcf.core.interfaces.listeners.IChannelStateChangeListener;
+
+/**
+ * TCF logging channel state listener implementation.
+ */
+public class ChannelStateChangeListener implements IChannelStateChangeListener {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.te.tcf.core.interfaces.listeners.IChannelStateChangeListener#stateChanged(org.eclipse.tcf.protocol.IChannel, int)
+ */
+ @Override
+ public void stateChanged(IChannel channel, int state) {
+ Assert.isNotNull(channel);
+
+ switch(state) {
+ case IChannel.STATE_OPEN:
+ ChannelTraceListenerManager.getInstance().onChannelOpened(channel);
+ break;
+ case IChannel.STATE_CLOSED:
+ ChannelTraceListenerManager.getInstance().onChannelClosed(channel);
+ break;
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelTraceListener.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelTraceListener.java
new file mode 100644
index 000000000..d4b88e27e
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelTraceListener.java
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.log.core.internal.listener;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tcf.core.AbstractChannel.TraceListener;
+import org.eclipse.tcf.protocol.IChannel;
+import org.eclipse.tcf.te.tcf.log.core.activator.CoreBundleActivator;
+import org.eclipse.tcf.te.tcf.log.core.interfaces.IPreferenceKeys;
+import org.eclipse.tcf.te.tcf.log.core.interfaces.ITracing;
+import org.eclipse.tcf.te.tcf.log.core.internal.LogManager;
+import org.eclipse.tcf.te.tcf.log.core.internal.nls.Messages;
+
+/**
+ * TCF logging channel trace listener implementation.
+ */
+public class ChannelTraceListener implements TraceListener {
+ /**
+ * Time format representing time with milliseconds.
+ */
+ public static final DateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS"); //$NON-NLS-1$
+
+ /**
+ * Time format representing date and time with milliseconds.
+ */
+ public static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); //$NON-NLS-1$
+
+ // Reference to the channel
+ private final IChannel channel;
+
+ /**
+ * Constructor.
+ *
+ * @param channel The channel. Must not be <code>null</code>.
+ */
+ public ChannelTraceListener(IChannel channel) {
+ Assert.isNotNull(channel);
+ this.channel = channel;
+ }
+
+ /**
+ * Return the associated channel.
+ *
+ * @return The channel instance.
+ */
+ protected final IChannel getChannel() {
+ return channel;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.core.AbstractChannel.TraceListener#onChannelClosed(java.lang.Throwable)
+ */
+ @Override
+ public void onChannelClosed(Throwable error) {
+ if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITracing.ID_TRACE_CHANNEL_TRACE_LISTENER)) {
+ CoreBundleActivator.getTraceHandler().trace("TraceListener.onChannelClosed ( " + error + " )", //$NON-NLS-1$ //$NON-NLS-2$
+ ITracing.ID_TRACE_CHANNEL_TRACE_LISTENER, this);
+ }
+
+ // Get the current time stamp
+ String date = DATE_FORMAT.format(new Date(System.currentTimeMillis()));
+
+ String message = NLS.bind(Messages.ChannelTraceListener_channelClosed_message,
+ new Object[] {
+ date,
+ Integer.toHexString(channel.hashCode()),
+ error
+ });
+
+ LogManager.getInstance().closeWriter(channel, message);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.core.AbstractChannel.TraceListener#onMessageReceived(char, java.lang.String, java.lang.String, java.lang.String, byte[])
+ */
+ @Override
+ public void onMessageReceived(char type, String token, String service, String name, byte[] data) {
+ if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITracing.ID_TRACE_CHANNEL_TRACE_LISTENER)) {
+ CoreBundleActivator.getTraceHandler().trace("TraceListener.onMessageReceived ( " + type //$NON-NLS-1$
+ + ", " + token + ", " + service + ", " + name + ", ... )", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ ITracing.ID_TRACE_CHANNEL_TRACE_LISTENER, this);
+ }
+
+ doLogMessage(type, token, service, name, data, true);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tcf.core.AbstractChannel.TraceListener#onMessageSent(char, java.lang.String, java.lang.String, java.lang.String, byte[])
+ */
+ @Override
+ public void onMessageSent(final char type, String token, String service, String name, byte[] data) {
+ if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITracing.ID_TRACE_CHANNEL_TRACE_LISTENER)) {
+ CoreBundleActivator.getTraceHandler().trace("TraceListener.onMessageSent ( " + type //$NON-NLS-1$
+ + ", " + token + ", " + service + ", " + name + ", ... )", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ ITracing.ID_TRACE_CHANNEL_TRACE_LISTENER, this);
+ }
+
+ doLogMessage(type, token, service, name, data, false);
+ }
+
+ /**
+ * Helper method to output the message to the logger.
+ */
+ private void doLogMessage(final char type, String token, String service, String name, byte[] data, boolean received) {
+ // Filter out the heart beat messages if not overwritten by the preferences
+ boolean showHeartbeats = Platform.getPreferencesService().getBoolean(CoreBundleActivator.getUniqueIdentifier(),
+ IPreferenceKeys.PREF_SHOW_HEARTBEATS, false, null);
+ if (!showHeartbeats && name != null && name.toLowerCase().contains("heartbeat")) { //$NON-NLS-1$
+ return;
+ }
+
+ // Format the message
+ final String message = formatMessage(type, token, service, name, data, received);
+ // Get the file writer
+ FileWriter writer = LogManager.getInstance().getWriter(channel);
+ if (writer != null) {
+ try {
+ writer.write(message);
+ writer.write("\n"); //$NON-NLS-1$
+ writer.flush();
+ } catch (IOException e) {
+ /* ignored on purpose */
+ }
+ }
+ }
+
+ /**
+ * Format the trace message.
+ */
+ protected String formatMessage(char type, String token, String service, String name, byte[] data, boolean received) {
+ // Get the current time stamp
+ String time = TIME_FORMAT.format(new Date(System.currentTimeMillis()));
+
+ // Decode the arguments again for tracing purpose
+ String args = null;
+ if (data != null) {
+ StringBuilder builder = new StringBuilder();
+ InputStreamReader reader = new InputStreamReader(new ByteArrayInputStream(data));
+ try {
+ int c = reader.read();
+ while (c != -1) {
+ builder.append(c != 0 ? Character.valueOf((char)c).charValue() : ' ');
+ c = reader.read();
+ }
+ } catch (IOException ex) { /* ignored on purpose */ }
+
+ if (builder.length() > 0) args = builder.toString().trim();
+ }
+
+ // Construct the full message
+ //
+ // The message format is: <time>: [<---|--->] <type> <token> <service>#<name> <args>
+ StringBuilder message = new StringBuilder();
+ message.append(time).append(":"); //$NON-NLS-1$
+ message.append(" ").append(received ? "<---" : "--->"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ message.append(" ").append(Character.valueOf(type)); //$NON-NLS-1$
+ if (token != null) message.append(" ").append(token); //$NON-NLS-1$
+ if (service != null) message.append(" ").append(service); //$NON-NLS-1$
+ if (name != null) message.append(" ").append(name); //$NON-NLS-1$
+ if (args != null && args.trim().length() > 0) message.append(" ").append(args.trim()); //$NON-NLS-1$
+
+ return message.toString();
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelTraceListenerManager.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelTraceListenerManager.java
new file mode 100644
index 000000000..fd87fdf67
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/listener/ChannelTraceListenerManager.java
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.log.core.internal.listener;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tcf.core.AbstractChannel;
+import org.eclipse.tcf.protocol.IChannel;
+import org.eclipse.tcf.protocol.Protocol;
+import org.eclipse.tcf.te.tcf.log.core.activator.CoreBundleActivator;
+import org.eclipse.tcf.te.tcf.log.core.interfaces.IPreferenceKeys;
+import org.eclipse.tcf.te.tcf.log.core.interfaces.ITracing;
+import org.eclipse.tcf.te.tcf.log.core.internal.LogManager;
+import org.eclipse.tcf.te.tcf.log.core.internal.nls.Messages;
+
+/**
+ * TCF logging channel trace listener manager implementation.
+ */
+public class ChannelTraceListenerManager {
+ // The map of trace listeners per channel
+ private final Map<IChannel, AbstractChannel.TraceListener> listeners = new HashMap<IChannel, AbstractChannel.TraceListener>();
+
+ /*
+ * Thread save singleton instance creation.
+ */
+ private static class LazyInstanceHolder {
+ public static ChannelTraceListenerManager instance = new ChannelTraceListenerManager();
+ }
+
+ /**
+ * Returns the singleton instance for the manager.
+ */
+ public static ChannelTraceListenerManager getInstance() {
+ return LazyInstanceHolder.instance;
+ }
+
+ /**
+ * Constructor.
+ */
+ /* default */ ChannelTraceListenerManager() {
+ }
+
+ /**
+ * New channel opened. Attach a channel trace listener.
+ *
+ * @param channel The channel. Must not be <code>null</code>.
+ */
+ public void onChannelOpened(final IChannel channel) {
+ Assert.isNotNull(channel);
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ // The trace listener interface does not have a onChannelOpenend method, but
+ // for consistency, log the channel opening similar to the others.
+ if (CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITracing.ID_TRACE_CHANNEL_TRACE_LISTENER)) {
+ CoreBundleActivator.getTraceHandler().trace("TraceListener.onChannelOpened ( " + channel + " )", //$NON-NLS-1$ //$NON-NLS-2$
+ ITracing.ID_TRACE_CHANNEL_TRACE_LISTENER, this);
+ }
+
+ // The trace listeners can be accessed only via AbstractChannel
+ if (!(channel instanceof AbstractChannel)) return;
+
+ // Get the preference key if or if not logging is enabled
+ boolean loggingEnabled = Platform.getPreferencesService().getBoolean(CoreBundleActivator.getUniqueIdentifier(),
+ IPreferenceKeys.PREF_LOGGING_ENABLED, false, null);
+ // If false, we are done here and wont create any console or trace listener.
+ if (!loggingEnabled) return;
+
+ // As the channel has just opened, there should be no trace listener, but better be safe and check
+ AbstractChannel.TraceListener traceListener = listeners.remove(channel);
+ if (traceListener != null) ((AbstractChannel)channel).removeTraceListener(traceListener);
+ // Create a new trace listener instance
+ traceListener = new ChannelTraceListener(channel);
+ // Attach trace listener to the channel
+ ((AbstractChannel)channel).addTraceListener(traceListener);
+ // Remember the associated trace listener
+ listeners.put(channel, traceListener);
+
+ // Log the channel opening
+ String date = ChannelTraceListener.DATE_FORMAT.format(new Date(System.currentTimeMillis()));
+
+ String message = NLS.bind(Messages.ChannelTraceListener_channelOpened_message,
+ new Object[] {
+ date,
+ Integer.toHexString(channel.hashCode())
+ });
+
+ // Get the file writer
+ FileWriter writer = LogManager.getInstance().getWriter(channel);
+ if (writer != null) {
+ try {
+ writer.write(message);
+ writer.write("\n"); //$NON-NLS-1$
+ writer.flush();
+ } catch (IOException e) {
+ /* ignored on purpose */
+ }
+ }
+ }
+
+ /**
+ * Channel closed. Detach the channel trace listener if any.
+ *
+ * @param channel The channel. Must not be <code>null</code>.
+ */
+ public void onChannelClosed(final IChannel channel) {
+ Assert.isNotNull(channel);
+ Assert.isTrue(Protocol.isDispatchThread());
+
+ // The trace listeners can be accessed only via AbstractChannel
+ if (!(channel instanceof AbstractChannel)) return;
+
+ // Remove the trace listener if any
+ final AbstractChannel.TraceListener traceListener = listeners.remove(channel);
+ if (traceListener != null) {
+ Protocol.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ ((AbstractChannel)channel).removeTraceListener(traceListener);
+ }
+ });
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/nls/Messages.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/nls/Messages.java
new file mode 100644
index 000000000..bf4ce6edf
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/nls/Messages.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Wind River Systems, Inc. and others. All rights reserved.
+ * This program and the accompanying materials are made available under the terms
+ * of the Eclipse Public License v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tcf.te.tcf.log.core.internal.nls;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Plug-in externalized strings management.
+ */
+public class Messages extends NLS {
+
+ // The plug-in resource bundle name
+ private static final String BUNDLE_NAME = "org.eclipse.tcf.te.tcf.log.core.internal.nls.Messages"; //$NON-NLS-1$
+
+ /**
+ * Static constructor.
+ */
+ static {
+ // Load message values from bundle file
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ // **** Declare externalized string id's down here *****
+
+ public static String ChannelTraceListener_channelOpened_message;
+ public static String ChannelTraceListener_channelClosed_message;
+ public static String ChannelTraceListener_logManagerDispose_message;
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/nls/Messages.properties
new file mode 100644
index 000000000..c77b0dbd8
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.log.core/src/org/eclipse/tcf/te/tcf/log/core/internal/nls/Messages.properties
@@ -0,0 +1,8 @@
+#
+# org.eclipse.tcf.te.tcf.log.core
+# Externalized Strings.
+#
+
+ChannelTraceListener_channelOpened_message=# {0}: Opened channel {1}
+ChannelTraceListener_channelClosed_message=# {0}: Closed channel {1} (error={2})
+ChannelTraceListener_logManagerDispose_message=# {0}: Closed session

Back to the top