blob: d20af850b84edf04ca757a8e44f9d1377c5d9a05 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009 Nokia 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:
* Nokia - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.debug.edc.ui.console;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.eclipse.cdt.debug.edc.internal.EDCDebugger;
import org.eclipse.cdt.debug.edc.internal.ui.IconAndMessageAndDetailsDialog;
import org.eclipse.cdt.debug.edc.tcf.extension.services.ILogging;
import org.eclipse.cdt.debug.edc.tcf.extension.services.ILogging.DoneAddListener;
import org.eclipse.cdt.debug.edc.tcf.extension.services.ILogging.DoneRemoveListener;
import org.eclipse.cdt.debug.edc.tcf.extension.services.ILogging.LogListener;
import org.eclipse.cdt.debug.ui.CDebugUIPlugin;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.tm.tcf.core.AbstractChannel;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener;
import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.util.TCFTask;
import org.eclipse.ui.console.ConsolePlugin;
import org.eclipse.ui.console.IConsole;
import org.eclipse.ui.console.IConsoleListener;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;
/**
* A class that manages connecting an ILogging with an IConsole
*/
public class ConsoleLogManager implements LogListener {
/**
* List of created managers
*/
private static List<ConsoleLogManager> managers;
/**
* The IChannel
*/
private IChannel channel;
/**
* The managed consoles
*/
private Map<MessageConsole, MessageConsoleStream> consoleStreamMappings;
/**
* The identifier of the log
*/
private final String logId;
/**
* The type id of the managed consoles
*/
private final String consoleType;
private IChannelListener channelOpenListener;
/**
* Create a new manager to manager a console type with a specific ILogging
* service log id and channel
*
* @param consoleType
* String
* @param logId
* String
* @param channel
* IChannel
*/
public static ConsoleLogManager create(String consoleType, String logId, IChannel channel) {
if (managers == null)
managers = new ArrayList<ConsoleLogManager>();
ConsoleLogManager consoleStreamManager = new ConsoleLogManager(consoleType, logId, channel);
managers.add(consoleStreamManager);
return consoleStreamManager;
}
public static ConsoleLogManager findExisting(String consoleType, String logId, IChannel channel) {
if (managers != null) {
for (ConsoleLogManager consoleLogManager : managers) {
if (consoleLogManager.consoleType.equals(consoleType) && consoleLogManager.logId.equals(logId)
&& consoleLogManager.channel.equals(channel))
return consoleLogManager;
}
}
return null;
}
private ConsoleLogManager(final String consoleType, String logId, IChannel channel) {
this.consoleType = consoleType;
this.logId = logId;
this.channel = channel;
hookChannel(channel);
consoleStreamMappings = new HashMap<MessageConsole, MessageConsoleStream>();
ConsolePlugin.getDefault().getConsoleManager().addConsoleListener(new IConsoleListener() {
public void consolesRemoved(IConsole[] consoles) {
for (IConsole console : consoles) {
if (console instanceof MessageConsole) {
removeConsole((MessageConsole) console);
}
}
}
public void consolesAdded(IConsole[] consoles) {
for (IConsole console : consoles) {
String type = console.getType();
if (type != null && type.equals(consoleType) && console instanceof MessageConsole) {
addConsole((MessageConsole) console);
}
}
}
});
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((consoleType == null) ? 0 : consoleType.hashCode());
result = prime * result + ((logId == null) ? 0 : logId.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ConsoleLogManager other = (ConsoleLogManager) obj;
if (consoleType == null) {
if (other.consoleType != null)
return false;
} else if (!consoleType.equals(other.consoleType))
return false;
if (logId == null) {
if (other.logId != null)
return false;
} else if (!logId.equals(other.logId))
return false;
return true;
}
private void hookChannel(final IChannel channel) {
Protocol.invokeAndWait(new Runnable() {
public void run() {
channel.addChannelListener(new IChannelListener() {
public void onChannelOpened() {
}
public void onChannelClosed(Throwable error) {
managers.remove(ConsoleLogManager.this);
}
public void congestionLevel(int level) {
}
});
}
});
}
public void removeConsole(MessageConsole console) {
if (consoleStreamMappings.remove(console) != null && consoleStreamMappings.isEmpty()) {
if (isChannelOpen()) {
Job job = new Job("Disabling console logging") { //$NON-NLS-1$
@Override
protected IStatus run(IProgressMonitor monitor) {
TCFTask<Object> task = new TCFTask<Object>() {
public void run() {
ILogging logging = ConsoleLogManager.this.channel.getRemoteService(ILogging.class);
assert logging != null;
logging.removeListener(logId, ConsoleLogManager.this, new DoneRemoveListener() {
public void doneRemoveListener(IToken token, Exception error) {
if (error == null)
done(this);
else
error(error);
}
});
}
};
// wait a fixed time since the target may be disconnected
try {
task.get(15, TimeUnit.SECONDS);
} catch (InterruptedException e) {
} catch (Exception e) {
EDCDebugger.getMessageLogger().logError(null, e);
}
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.schedule();
}
}
}
public void addConsole(MessageConsole console) {
if (consoleStreamMappings.isEmpty()) {
if (isChannelOpen()) {
addLoggingListener();
} else {
channelOpenListener = new IChannelListener() {
public void onChannelOpened() {
addLoggingListener();
channel.removeChannelListener(channelOpenListener);
}
public void onChannelClosed(Throwable error) {
}
public void congestionLevel(int level) {
}
};
Protocol.invokeAndWait(new Runnable() {
public void run() {
channel.addChannelListener(channelOpenListener);
}
});
}
}
consoleStreamMappings.put(console, console.newMessageStream());
}
/**
*
*/
private void addLoggingListener() {
Protocol.invokeAndWait(new Runnable() {
public void run() {
ILogging logging = ConsoleLogManager.this.channel.getRemoteService(ILogging.class);
assert logging != null;
if (logging != null)
logging.addListener(logId, ConsoleLogManager.this, new DoneAddListener() {
public void doneAddListener(IToken token, Exception error) {
if (error != null)
EDCDebugger.getMessageLogger().logError("Failed to add logging listener", error);
}
});
}
});
}
private boolean isChannelOpen() {
int state = ((AbstractChannel) channel).getState();
return state == IChannel.STATE_OPEN || state == IChannel.STATE_OPENING;
}
public void appendText(final MessageConsole console, final String text, boolean eol) {
MessageConsoleStream stream = consoleStreamMappings.get(console);
if (stream.isClosed()) {
stream = console.newMessageStream();
consoleStreamMappings.put(console, stream);
}
if (eol)
stream.println(text);
else
stream.print(text);
}
public void write(String msg) {
for (MessageConsole console : consoleStreamMappings.keySet()) {
appendText(console, msg, false);
}
}
public void writeln(String msg) {
for (MessageConsole console : consoleStreamMappings.keySet()) {
appendText(console, msg, true);
}
}
private static String severityString(final int severity) {
String result;
switch (severity) {
case IStatus.INFO: result = "INFO"; break;
case IStatus.WARNING: result = "WARNING"; break;
case IStatus.ERROR:
default: // shouldn't be receiving anything but what's above
result = "ERROR";
}
return result;
}
/** @since 2.0 */
public void dialog(final int severity, final String summary, final String details) {
String edcId = EDCDebugger.getUniqueIdentifier();
EDCDebugger.getMessageLogger().log(new Status(severity, edcId, "EDC debugger: " + summary));
CDebugUIPlugin.getStandardDisplay().asyncExec(new Runnable() {
public void run() {
(new IconAndMessageAndDetailsDialog(severity, summary,
"EDC debugger reports "
+ severityString(severity)
+ ":\n\n" + details))
.open();
}
});
}
static void removeManagersForChannel(IChannel channel) {
if (managers != null) {
for (ConsoleLogManager consoleLogManager : managers.toArray(new ConsoleLogManager[managers.size()])) {
if (consoleLogManager.channel.equals(channel))
managers.remove(consoleLogManager);
}
}
}
}