diff options
author | eutarass | 2008-09-29 18:16:21 +0000 |
---|---|---|
committer | eutarass | 2008-09-29 18:16:21 +0000 |
commit | 4eda31b90ed1a201fd6e670d2a833e02fe44ed18 (patch) | |
tree | d0b7702656d2342cd36a5e32645b8548487297e6 | |
parent | c6d9344ab3988164cf6008d45fc80f83036a5f51 (diff) | |
download | org.eclipse.tcf-4eda31b90ed1a201fd6e670d2a833e02fe44ed18.tar.gz org.eclipse.tcf-4eda31b90ed1a201fd6e670d2a833e02fe44ed18.tar.xz org.eclipse.tcf-4eda31b90ed1a201fd6e670d2a833e02fe44ed18.zip |
1. Extended IErrorReport interface: now error report details are accessible from TCF clients
2. TCF Debugger UI: Got rid of meaningless method TCFNode.invalidateNode()
3. TCF Debugger UI: improved cache performance
15 files changed, 261 insertions, 202 deletions
diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFArgumentsTab.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFArgumentsTab.java index c13c7b310..fcfad26dd 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFArgumentsTab.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFArgumentsTab.java @@ -112,7 +112,6 @@ public class TCFArgumentsTab extends AbstractLaunchConfigurationTab { public void setDefaults(ILaunchConfigurationWorkingCopy config) { config.setAttribute(TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS, (String)null); - config.setAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, (String)null); } public void initializeFrom(ILaunchConfiguration configuration) { diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFMainTab.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFMainTab.java index d9402707d..8642356bb 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFMainTab.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/launch/TCFMainTab.java @@ -56,6 +56,7 @@ public class TCFMainTab extends AbstractLaunchConfigurationTab { private Text working_dir_text; private Button default_dir_button; private Button terminal_button; + private Exception init_error; public void createControl(Composite parent) { Composite comp = new Composite(parent, SWT.NONE); @@ -198,6 +199,17 @@ public class TCFMainTab extends AbstractLaunchConfigurationTab { default_dir_button = new Button(group, SWT.CHECK); default_dir_button.setText("Use default"); default_dir_button.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false)); + default_dir_button.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent evt) { + updateLaunchConfigurationDialog(); + } + }); + } + + protected void updateLaunchConfigurationDialog() { + super.updateLaunchConfigurationDialog(); + working_dir_text.setEnabled(!default_dir_button.getSelection()); } private ITCFLaunchContext getLaunchContext(IProject project) { @@ -257,66 +269,20 @@ public class TCFMainTab extends AbstractLaunchConfigurationTab { } public void initializeFrom(ILaunchConfiguration config) { - updateProjectFromConfig(config); - updateLocalProgramFromConfig(config); - updateRemoteProgramFromConfig(config); - updateTerminalFromConfig(config); - updateWorkingDirFromConfig(config); - } - - private void updateTerminalFromConfig(ILaunchConfiguration config) { - boolean use_terminal = true; try { - use_terminal = config.getAttribute(TCFLaunchDelegate.ATTR_USE_TERMINAL, true); + project_text.setText(config.getAttribute(TCFLaunchDelegate.ATTR_PROJECT_NAME, "")); + local_program_text.setText(config.getAttribute(TCFLaunchDelegate.ATTR_LOCAL_PROGRAM_FILE, "")); + remote_program_text.setText(config.getAttribute(TCFLaunchDelegate.ATTR_REMOTE_PROGRAM_FILE, "")); + working_dir_text.setText(config.getAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, "")); + default_dir_button.setSelection(!config.hasAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY)); + terminal_button.setSelection(config.getAttribute(TCFLaunchDelegate.ATTR_USE_TERMINAL, true)); } - catch (CoreException e) { + catch (Exception e) { + init_error = e; + setErrorMessage("Cannot read launch configuration: " + init_error); Activator.log(e); } - terminal_button.setSelection(use_terminal); - } - - private void updateProjectFromConfig(ILaunchConfiguration config) { - String project_name = ""; - try { - project_name = config.getAttribute(TCFLaunchDelegate.ATTR_PROJECT_NAME, ""); - } - catch (CoreException ce) { - Activator.log(ce); - } - project_text.setText(project_name); - } - - private void updateLocalProgramFromConfig(ILaunchConfiguration config) { - String program_name = ""; - try { - program_name = config.getAttribute(TCFLaunchDelegate.ATTR_LOCAL_PROGRAM_FILE, ""); - } - catch (CoreException ce) { - Activator.log(ce); - } - local_program_text.setText(program_name); - } - - private void updateRemoteProgramFromConfig(ILaunchConfiguration config) { - String program_name = ""; - try { - program_name = config.getAttribute(TCFLaunchDelegate.ATTR_REMOTE_PROGRAM_FILE, ""); - } - catch (CoreException ce) { - Activator.log(ce); - } - remote_program_text.setText(program_name); - } - - private void updateWorkingDirFromConfig(ILaunchConfiguration config) { - String name = ""; - try { - name = config.getAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, ""); //$NON-NLS-1$ - } - catch (CoreException ce) { - Activator.log(ce); - } - working_dir_text.setText(name); + updateLaunchConfigurationDialog(); } private IProject getProject() { @@ -329,7 +295,12 @@ public class TCFMainTab extends AbstractLaunchConfigurationTab { config.setAttribute(TCFLaunchDelegate.ATTR_PROJECT_NAME, project_text.getText()); config.setAttribute(TCFLaunchDelegate.ATTR_LOCAL_PROGRAM_FILE, local_program_text.getText()); config.setAttribute(TCFLaunchDelegate.ATTR_REMOTE_PROGRAM_FILE, remote_program_text.getText()); - config.setAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, working_dir_text.getText()); + if (default_dir_button.getSelection()) { + config.removeAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY); + } + else { + config.setAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, working_dir_text.getText()); + } config.setAttribute(TCFLaunchDelegate.ATTR_USE_TERMINAL, terminal_button.getSelection()); } @@ -341,7 +312,7 @@ public class TCFMainTab extends AbstractLaunchConfigurationTab { if (project == null) { MessageDialog.openInformation(getShell(), "Project required", - "Enter project before searching for program"); + "Enter project before searching for program"); return; } ITCFLaunchContext launch_context = getLaunchContext(project); @@ -412,6 +383,11 @@ public class TCFMainTab extends AbstractLaunchConfigurationTab { setErrorMessage(null); setMessage(null); + if (init_error != null) { + setErrorMessage("Cannot read launch configuration: " + init_error); + return false; + } + String project_name = project_text.getText().trim(); if (project_name.length() != 0) { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(project_name); @@ -476,6 +452,7 @@ public class TCFMainTab extends AbstractLaunchConfigurationTab { public void setDefaults(ILaunchConfigurationWorkingCopy config) { config.setAttribute(TCFLaunchDelegate.ATTR_PROJECT_NAME, ""); config.setAttribute(TCFLaunchDelegate.ATTR_USE_TERMINAL, true); + config.setAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, (String)null); ITCFLaunchContext launch_context = getLaunchContext(null); if (launch_context != null) launch_context.setDefaults(getLaunchConfigurationDialog(), config); } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java index 6cb91e615..e6fb7fbc5 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFChildrenStackTrace.java @@ -13,8 +13,10 @@ package org.eclipse.tm.internal.tcf.debug.ui.model; import java.util.HashMap; import java.util.Map; +import org.eclipse.tm.internal.tcf.debug.model.TCFContextState; import org.eclipse.tm.tcf.protocol.IToken; import org.eclipse.tm.tcf.services.IStackTrace; +import org.eclipse.tm.tcf.util.TCFDataCache; public class TCFChildrenStackTrace extends TCFChildren { @@ -61,8 +63,15 @@ public class TCFChildrenStackTrace extends TCFChildren { @Override protected boolean startDataRetrieval() { final HashMap<String,TCFNode> data = new HashMap<String,TCFNode>(); - if (!node.isSuspended()) { - set(null, null, data); + TCFDataCache<TCFContextState> state = node.getState(); + if (!state.validate()) { + state.wait(this); + return false; + } + Throwable state_error = state.getError(); + TCFContextState state_data = state.getData(); + if (state_error != null || state_data == null || !state_data.is_suspended) { + set(null, state_error, data); return true; } IStackTrace st = node.model.getLaunch().getService(IStackTrace.class); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java index 0a4a42067..55994f550 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNode.java @@ -77,7 +77,6 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo void dispose() { assert !disposed; if (parent != null) parent.dispose(id); - invalidateNode(); if (id != null) { assert model.getNode(id) == this; model.removeNode(id); @@ -319,12 +318,6 @@ public abstract class TCFNode extends PlatformObject implements Comparable<TCFNo /* Node data retrieval state machine */ /** - * Invalidate the node - flush all cached data. - * Subclasses should override this method to flush any additional data. - */ - public abstract void invalidateNode(); - - /** * Validate node - retrieve and put into a cache missing data from remote peer. * The method should initiate retrieval of all data needed by TCFNode.update() methods. * Validation is done asynchronously. If the node is already valid, diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java index b7a39c250..efc8f95be 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExecContext.java @@ -127,6 +127,9 @@ public class TCFNodeExecContext extends TCFNode { @Override void dispose() { + run_context.reset(null); + mem_context.reset(null); + state.reset(null); children_exec.dispose(); children_stack.dispose(); super.dispose(); @@ -448,52 +451,29 @@ public class TCFNodeExecContext extends TCFNode { } @Override - public void invalidateNode() { - run_context.reset(); - mem_context.reset(); - state.reset(); - children_exec.reset(); - children_stack.reset(); - } - - @Override public boolean validateNode(Runnable done) { assert !disposed; - mem_context.validate(); - run_context.validate(); - if (!mem_context.isValid()) { - mem_context.wait(done); - return false; - } - if (!run_context.isValid()) { - run_context.wait(done); - return false; - } - state.validate(); - children_exec.validate(); - if (!state.isValid()) { - state.wait(done); - return false; - } - if (!children_exec.isValid()) { - children_exec.wait(done); + TCFDataCache<?> pending = null; + + if (!mem_context.validate()) pending = mem_context; + if (!run_context.validate()) pending = run_context; + if (pending != null) { + pending.wait(done); return false; } - children_stack.validate(); + if (!state.validate()) pending = state; + if (!children_exec.validate()) pending = children_exec; + if (!children_stack.validate()) pending = children_stack; IRunControl.RunControlContext ctx = run_context.getData(); if (ctx != null && !ctx.hasState()) { // Container need to validate children for // hasSuspendedChildren() method to return valid value. TCFDataCache<?> dt = validateChildrenState(); - if (dt != null) { - dt.wait(done); - return false; - } + if (dt != null) pending = dt; } - - if (!children_stack.isValid()) { - children_stack.wait(done); + if (pending != null) { + pending.wait(done); return false; } diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java index 5d2c0f43a..89308f55f 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeExpression.java @@ -212,6 +212,9 @@ public class TCFNodeExpression extends TCFNode { @Override void dispose() { + value.reset(null); + type.reset(null); + children.reset(null); children.dispose(); super.dispose(); if (!expression.isValid() || expression.getData() == null) return; @@ -446,13 +449,6 @@ public class TCFNodeExpression extends TCFNode { } @Override - public void invalidateNode() { - value.reset(); - type.reset(); - children.reset(); - } - - @Override public boolean validateNode(Runnable done) { TCFDataCache<?> pending = null; if (!field.validate()) pending = field; diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java index 33e733461..8c40f3e41 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeLaunch.java @@ -88,11 +88,6 @@ public class TCFNodeLaunch extends TCFNode { } @Override - public void invalidateNode() { - children.reset(); - } - - @Override public boolean validateNode(Runnable done) { if (!children.validate()) { children.wait(done); diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java index 4ada16a84..371bed81e 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeRegister.java @@ -67,6 +67,13 @@ public class TCFNodeRegister extends TCFNode { } }; } + + @Override + public void dispose() { + context.reset(null); + value.reset(null); + super.dispose(); + } @Override protected void getData(ILabelUpdate result) { @@ -214,12 +221,6 @@ public class TCFNodeRegister extends TCFNode { } @Override - public void invalidateNode() { - context.reset(); - value.reset(); - } - - @Override public boolean validateNode(Runnable done) { TCFDataCache<?> pending = null; if (!context.validate()) pending = context; diff --git a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java index f93d76bef..98baa6423 100644 --- a/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java +++ b/plugins/org.eclipse.tm.tcf.debug.ui/src/org/eclipse/tm/internal/tcf/debug/ui/model/TCFNodeStackFrame.java @@ -132,6 +132,8 @@ public class TCFNodeStackFrame extends TCFNode { @Override void dispose() { + stack_trace_context.reset(null); + line_info.reset(null); children_regs.dispose(); children_vars.dispose(); children_exps.dispose(); @@ -270,23 +272,30 @@ public class TCFNodeStackFrame extends TCFNode { @Override protected void getData(ILabelUpdate result) { result.setImageDescriptor(ImageCache.getImageDescriptor(getImageName()), 0); - Throwable error = stack_trace_context.getError(); - if (error == null) error = line_info.getError(); - if (error != null && ((TCFNodeExecContext)parent).isSuspended()) { - result.setForeground(new RGB(255, 0, 0), 0); - result.setLabel(error.getClass().getName() + ": " + error.getMessage(), 0); + TCFChildrenStackTrace st = ((TCFNodeExecContext)parent).getStackTrace(); + if (st.getData().get(id) == null) { + result.setLabel("", 0); } else { - TCFSourceRef l = line_info.getData(); - if (l == null) { - result.setLabel("...", 0); + Throwable error = stack_trace_context.getError(); + if (error == null) error = line_info.getError(); + if (error != null && ((TCFNodeExecContext)parent).isSuspended()) { + System.out.println(error.toString()); + result.setForeground(new RGB(255, 0, 0), 0); + result.setLabel(error.getClass().getName() + ": " + error.getMessage(), 0); } else { - String label = makeHexAddrString(l.address); - if (l.area != null && l.area.file != null) { - label += ": " + l.area.file + ", line " + l.area.start_line; + TCFSourceRef l = line_info.getData(); + if (l == null) { + result.setLabel("...", 0); + } + else { + String label = makeHexAddrString(l.address); + if (l.area != null && l.area.file != null) { + label += ": " + l.area.file + ", line " + l.area.start_line; + } + result.setLabel(label, 0); } - result.setLabel(label, 0); } } } @@ -324,17 +333,10 @@ public class TCFNodeStackFrame extends TCFNode { } @Override - public void invalidateNode() { - stack_trace_context.reset(); - line_info.reset(); - children_regs.reset(); - children_vars.reset(); - children_exps.reset(); - } - - @Override public boolean validateNode(Runnable done) { TCFDataCache<?> pending = null; + TCFChildrenStackTrace stack_trace = ((TCFNodeExecContext)parent).getStackTrace(); + if (!stack_trace.validate()) pending = stack_trace; if (!stack_trace_context.validate()) pending = stack_trace_context; if (!children_regs.validate()) pending = children_regs; if (!children_vars.validate()) pending = children_vars; diff --git a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java index 76bb99c13..b21625153 100644 --- a/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java +++ b/plugins/org.eclipse.tm.tcf.debug/src/org/eclipse/tm/internal/tcf/debug/model/TCFLaunch.java @@ -214,14 +214,14 @@ public class TCFLaunch extends Launch { } }; if (local_file.length() == 0 || remote_file.length() == 0) r.run(); - else copyToRemoteTarget(getProgramPath(project, local_file), remote_file, r); + else copyFileToRemoteTarget(getProgramPath(project, local_file), remote_file, r); } catch (Exception x) { channel.terminate(x); } } - private void copyToRemoteTarget(String local_file, String remote_file, final Runnable done) { + private void copyFileToRemoteTarget(String local_file, String remote_file, final Runnable done) { if (local_file == null) { channel.terminate(new Exception("Program does not exist")); return; diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/FileSystemProxy.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/FileSystemProxy.java index 5cdec13a4..cd953fa33 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/FileSystemProxy.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/FileSystemProxy.java @@ -40,25 +40,48 @@ public class FileSystemProxy implements IFileSystem { } } - private static final class Status extends FileSystemException { + private static final class Status extends FileSystemException implements IErrorReport { private static final long serialVersionUID = -1636567076145085980L; private final int status; + private final Map<String,Object> attrs; - Status(int status, String message) { + Status(int status, String message, Map<String,Object> attrs) { super(message); - this.status = status; + this.status = status; + this.attrs = attrs; } Status(Exception x) { super(x); - this.status = IErrorReport.TCF_ERROR_OTHER; + this.status = IErrorReport.TCF_ERROR_OTHER; + this.attrs = new HashMap<String,Object>(); } public int getStatus() { return status; } + + public int getErrorCode() { + Number n = (Number)attrs.get(ERROR_CODE); + if (n == null) return 0; + return n.intValue(); + } + + public int getAltCode() { + Number n = (Number)attrs.get(ERROR_ALT_CODE); + if (n == null) return 0; + return n.intValue(); + } + + public String getAltOrg() { + return (String)attrs.get(ERROR_ALT_ORG); + } + + public Map<String, Object> getAttributes() { + return attrs; + } } private abstract class FileSystemCommand extends Command { @@ -71,14 +94,17 @@ public class FileSystemProxy implements IFileSystem { public Status toFSError(Object data) { if (data == null) return null; Map<String,Object> map = (Map<String,Object>)data; - Number error_code = (Number)map.get(ERROR_CODE); + Number error_code = (Number)map.get(IErrorReport.ERROR_CODE); String cmd = getCommandString(); if (cmd.length() > 72) cmd = cmd.substring(0, 72) + "..."; - return new Status(error_code.intValue(), + Status s = new Status(error_code.intValue(), "TCF command exception:" + "\nCommand: " + cmd + "\nException: " + toErrorString(data) + - "\nError code: " + error_code); + "\nError code: " + error_code, map); + Object caused_by = map.get(IErrorReport.ERROR_CAUSE_BY); + if (caused_by != null) s.initCause(toError(caused_by, false)); + return s; } } diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/MemoryProxy.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/MemoryProxy.java index e2e7f13ba..f22f78818 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/MemoryProxy.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/internal/tcf/services/remote/MemoryProxy.java @@ -22,6 +22,7 @@ import org.eclipse.tm.internal.tcf.core.ReadOnlyMap; import org.eclipse.tm.tcf.core.Base64; import org.eclipse.tm.tcf.core.Command; import org.eclipse.tm.tcf.protocol.IChannel; +import org.eclipse.tm.tcf.protocol.IErrorReport; import org.eclipse.tm.tcf.protocol.IToken; import org.eclipse.tm.tcf.protocol.JSON; import org.eclipse.tm.tcf.services.IMemory; @@ -46,14 +47,16 @@ public class MemoryProxy implements IMemory { } } - private class MemoryErrorReport extends MemoryError implements ErrorOffset { + private class MemoryErrorReport extends MemoryError implements ErrorOffset, IErrorReport { private static final long serialVersionUID = 796525409870265390L; + private final Map<String,Object> attrs; private final Range[] ranges; @SuppressWarnings("unchecked") - MemoryErrorReport(String msg, Number addr, Object ranges) { + MemoryErrorReport(String msg, Map<String,Object> attrs, Number addr, Object ranges) { super(msg); + this.attrs = attrs; Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)ranges; this.ranges = c == null ? null : new Range[c.size()]; if (c != null) { @@ -77,6 +80,26 @@ public class MemoryProxy implements IMemory { } } + public int getErrorCode() { + Number n = (Number)attrs.get(ERROR_CODE); + if (n == null) return 0; + return n.intValue(); + } + + public int getAltCode() { + Number n = (Number)attrs.get(ERROR_ALT_CODE); + if (n == null) return 0; + return n.intValue(); + } + + public String getAltOrg() { + return (String)attrs.get(ERROR_ALT_ORG); + } + + public Map<String, Object> getAttributes() { + return attrs; + } + public String getMessage(int offset) { if (ranges == null) return null; int l = 0; @@ -312,14 +335,18 @@ public class MemoryProxy implements IMemory { MemoryError toMemoryError(Number addr, Object data, Object ranges) { if (data == null) return null; Map<String,Object> map = (Map<String,Object>)data; - Integer code = (Integer)map.get(ERROR_CODE); + Integer code = (Integer)map.get(IErrorReport.ERROR_CODE); String cmd = getCommandString(); if (cmd.length() > 72) cmd = cmd.substring(0, 72) + "..."; - return new MemoryErrorReport( + MemoryError e = new MemoryErrorReport( "TCF command exception:" + "\nCommand: " + cmd + "\nException: " + toErrorString(data) + - "\nError code: " + code, addr, ranges); + "\nError code: " + code, + map, addr, ranges); + Object caused_by = map.get(IErrorReport.ERROR_CAUSE_BY); + if (caused_by != null) e.initCause(toError(caused_by, false)); + return e; } } diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/Command.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/Command.java index 14ac70130..bd9d0c420 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/Command.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/core/Command.java @@ -56,7 +56,7 @@ import org.eclipse.tm.tcf.protocol.Protocol; * }.token; * } */ -public abstract class Command implements IErrorReport, IChannel.ICommandListener { +public abstract class Command implements IChannel.ICommandListener { private final IService service; private final String command; @@ -68,6 +68,39 @@ public abstract class Command implements IErrorReport, IChannel.ICommandListener private static final SimpleDateFormat timestamp_format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + private class ErrorReport extends Exception implements IErrorReport { + + private static final long serialVersionUID = 3687543884858739977L; + private final Map<String,Object> attrs; + + ErrorReport(String msg, Map<String,Object> attrs) { + super(msg); + this.attrs = attrs; + Object caused_by = attrs.get(IErrorReport.ERROR_CAUSE_BY); + if (caused_by != null) initCause(toError(caused_by, false)); + } + + public int getErrorCode() { + Number n = (Number)attrs.get(ERROR_CODE); + if (n == null) return 0; + return n.intValue(); + } + + public int getAltCode() { + Number n = (Number)attrs.get(ERROR_ALT_CODE); + if (n == null) return 0; + return n.intValue(); + } + + public String getAltOrg() { + return (String)attrs.get(ERROR_ALT_ORG); + } + + public Map<String, Object> getAttributes() { + return attrs; + } + } + public Command(IChannel channel, IService service, String command, Object[] args) { this.service = service; this.command = command; @@ -143,17 +176,17 @@ public abstract class Command implements IErrorReport, IChannel.ICommandListener public static String toErrorString(Object data) { if (data == null) return null; Map<String,Object> map = (Map<String,Object>)data; - String fmt = (String)map.get(ERROR_FORMAT); + String fmt = (String)map.get(IErrorReport.ERROR_FORMAT); if (fmt != null) { - Collection<Object> c = (Collection<Object>)map.get(ERROR_PARAMS); + Collection<Object> c = (Collection<Object>)map.get(IErrorReport.ERROR_PARAMS); if (c != null) return new MessageFormat(fmt).format(c.toArray()); return fmt; } - Number code = (Number)map.get(ERROR_CODE); + Number code = (Number)map.get(IErrorReport.ERROR_CODE); if (code != null) { - if (code.intValue() == TCF_ERROR_OTHER) { - String alt_org = (String)map.get(ERROR_ALT_ORG); - Number alt_code = (Number)map.get(ERROR_ALT_CODE); + if (code.intValue() == IErrorReport.TCF_ERROR_OTHER) { + String alt_org = (String)map.get(IErrorReport.ERROR_ALT_ORG); + Number alt_code = (Number)map.get(IErrorReport.ERROR_ALT_CODE); if (alt_org != null && alt_code != null) { return alt_org + " Error " + alt_code; } @@ -163,13 +196,13 @@ public abstract class Command implements IErrorReport, IChannel.ICommandListener return "Invalid error report format"; } - private void appendErrorProps(StringBuffer bf, Map<String,Object> map) { - Number time = (Number)map.get(ERROR_TIME); - Number code = (Number)map.get(ERROR_CODE); - String service = (String)map.get(ERROR_SERVICE); - Number severity = (Number)map.get(ERROR_SEVERITY); - Number alt_code = (Number)map.get(ERROR_ALT_CODE); - String alt_org = (String)map.get(ERROR_ALT_ORG); + private static void appendErrorProps(StringBuffer bf, Map<String,Object> map) { + Number time = (Number)map.get(IErrorReport.ERROR_TIME); + Number code = (Number)map.get(IErrorReport.ERROR_CODE); + String service = (String)map.get(IErrorReport.ERROR_SERVICE); + Number severity = (Number)map.get(IErrorReport.ERROR_SEVERITY); + Number alt_code = (Number)map.get(IErrorReport.ERROR_ALT_CODE); + String alt_org = (String)map.get(IErrorReport.ERROR_ALT_ORG); if (time != null) { bf.append('\n'); bf.append("Time: "); @@ -180,9 +213,9 @@ public abstract class Command implements IErrorReport, IChannel.ICommandListener bf.append("Severity: "); bf.append(toErrorString(map)); switch (severity.intValue()) { - case SEVERITY_ERROR: bf.append("Error"); - case SEVERITY_FATAL: bf.append("Fatal"); - case SEVERITY_WARNING: bf.append("Warning"); + case IErrorReport.SEVERITY_ERROR: bf.append("Error"); + case IErrorReport.SEVERITY_FATAL: bf.append("Fatal"); + case IErrorReport.SEVERITY_WARNING: bf.append("Warning"); default: bf.append("Unknown"); } } @@ -209,34 +242,24 @@ public abstract class Command implements IErrorReport, IChannel.ICommandListener } } - @SuppressWarnings("unchecked") public Exception toError(Object data) { - if (data == null) return null; - Map<String,Object> map = (Map<String,Object>)data; - String cmd = getCommandString(); - if (cmd.length() > 72) cmd = cmd.substring(0, 72) + "..."; - StringBuffer bf = new StringBuffer(); - bf.append("TCF command error:"); - bf.append('\n'); - bf.append("Command: "); - bf.append(cmd); - appendErrorProps(bf, map); - Exception x = new Exception(bf.toString()); - Object caused_by = map.get(ERROR_CAUSE_BY); - if (caused_by != null) x.initCause(toNestedError(caused_by)); - return x; + return toError(data, true); } @SuppressWarnings("unchecked") - private Exception toNestedError(Object data) { + public Exception toError(Object data, boolean include_command_text) { if (data == null) return null; Map<String,Object> map = (Map<String,Object>)data; StringBuffer bf = new StringBuffer(); - bf.append("TCF error:"); + bf.append("TCF error report:"); + bf.append('\n'); + if (include_command_text) { + String cmd = getCommandString(); + if (cmd.length() > 72) cmd = cmd.substring(0, 72) + "..."; + bf.append("Command: "); + bf.append(cmd); + } appendErrorProps(bf, map); - Exception x = new Exception(bf.toString()); - Object caused_by = map.get(ERROR_CAUSE_BY); - if (caused_by != null) x.initCause(toNestedError(caused_by)); - return x; + return new ErrorReport(bf.toString(), map); } } diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IErrorReport.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IErrorReport.java index 66349fef6..8e0c6c558 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IErrorReport.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/protocol/IErrorReport.java @@ -10,8 +10,20 @@ *******************************************************************************/ package org.eclipse.tm.tcf.protocol; +import java.util.Map; + /** - * This interface defines TCF standard format of error reports. + * This interface defines TCF standard format of error reports. + * + * Exception objects can implement this interface to make error report details + * available for clients. + * + * Usage example: + * + * Exception x = ... + * if (x instanceof IErrorReport) { + * int error_code = ((IErrorReport)x).getErrorCode(); + * ... * * @noextend This interface is not intended to be extended by clients. */ @@ -75,4 +87,12 @@ public interface IErrorReport { TCF_ERROR_SYM_NOT_FOUND = 22, TCF_ERROR_UNSUPPORTED = 23, TCF_ERROR_INV_DATA_TYPE = 24; + + public int getErrorCode(); + + public int getAltCode(); + + public String getAltOrg(); + + public Map<String,Object> getAttributes(); } diff --git a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/util/TCFDataCache.java b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/util/TCFDataCache.java index e9cb43150..c914a0e9b 100644 --- a/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/util/TCFDataCache.java +++ b/plugins/org.eclipse.tm.tcf/src/org/eclipse/tm/tcf/util/TCFDataCache.java @@ -28,6 +28,7 @@ public abstract class TCFDataCache<V> implements Runnable { private Throwable error; private boolean valid; + private boolean posted; private V data; protected final IChannel channel; @@ -40,6 +41,13 @@ public abstract class TCFDataCache<V> implements Runnable { this.channel = channel; } + private void post() { + if (posted) return; + if (waiting_list.isEmpty()) return; + Protocol.invokeLater(this); + posted = true; + } + /** * @return true if cache contains up-to-date data (or data retrieval error). */ @@ -79,10 +87,13 @@ public abstract class TCFDataCache<V> implements Runnable { */ public void run() { assert Protocol.isDispatchThread(); - if (waiting_list.isEmpty()) return; + posted = false; Runnable[] arr = waiting_list.toArray(new Runnable[waiting_list.size()]); waiting_list.clear(); - for (Runnable r : arr) r.run(); + for (Runnable r : arr) { + if (r instanceof TCFDataCache<?> && ((TCFDataCache<?>)r).posted) continue; + r.run(); + } } /** @@ -113,7 +124,7 @@ public abstract class TCFDataCache<V> implements Runnable { } assert valid; assert command == null; - run(); + post(); return true; } @@ -131,7 +142,7 @@ public abstract class TCFDataCache<V> implements Runnable { this.error = error; this.data = data; valid = true; - Protocol.invokeLater(this); + post(); } /** @@ -147,7 +158,7 @@ public abstract class TCFDataCache<V> implements Runnable { this.data = data; error = null; valid = true; - Protocol.invokeLater(this); + post(); } /** @@ -158,7 +169,7 @@ public abstract class TCFDataCache<V> implements Runnable { error = null; valid = false; data = null; - Protocol.invokeLater(this); + post(); } /** @@ -173,7 +184,7 @@ public abstract class TCFDataCache<V> implements Runnable { error = null; valid = false; data = null; - Protocol.invokeLater(this); + post(); } /** |