Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormoberhuber2008-01-10 19:58:38 +0000
committermoberhuber2008-01-10 19:58:38 +0000
commit6459bb640308817d92790bb1b7b61348c5418ba8 (patch)
tree90d5150437b289ade70b25914ddc9b3b153332f8
parent7a412ee51d3cf40ec6094533fa753b9d01bd0a6a (diff)
downloadorg.eclipse.tcf-6459bb640308817d92790bb1b7b61348c5418ba8.tar.gz
org.eclipse.tcf-6459bb640308817d92790bb1b7b61348c5418ba8.tar.xz
org.eclipse.tcf-6459bb640308817d92790bb1b7b61348c5418ba8.zip
tcf-0.1.0 initial contribution
-rwxr-xr-xdocs/.project11
-rw-r--r--docs/TCF Architecture.pngbin0 -> 6941 bytes
-rw-r--r--docs/TCF Context Identifier Explanation.html257
-rwxr-xr-xdocs/TCF Getting Started.html226
-rw-r--r--docs/TCF Linux Agent Prototype.html199
-rw-r--r--docs/TCF Project.html141
-rw-r--r--docs/TCF Service - Breakpoints.html408
-rw-r--r--docs/TCF Service - File System.html1212
-rw-r--r--docs/TCF Service - Memory.html456
-rw-r--r--docs/TCF Service - Processes.html381
-rw-r--r--docs/TCF Service - Registers.html506
-rw-r--r--docs/TCF Service - Run Control.html618
-rw-r--r--docs/TCF Service - Stack Trace.html278
-rw-r--r--docs/TCF Service - System Monitor.html654
-rw-r--r--docs/TCF Services.html108
-rw-r--r--docs/TCF Specification Image1.pngbin0 -> 4771 bytes
-rw-r--r--docs/TCF Specification.html1407
-rw-r--r--docs/TCF_Launch_Dialog.jpgbin0 -> 62123 bytes
-rw-r--r--docs/TCF_RSE_Files.jpgbin0 -> 131851 bytes
-rw-r--r--docs/TCF_RSE_Processes.jpgbin0 -> 137635 bytes
-rw-r--r--docs/index.html44
-rw-r--r--epl-v10.html328
-rw-r--r--plugins/com.windriver.debug.tcf.core/.classpath7
-rw-r--r--plugins/com.windriver.debug.tcf.core/.cvsignore1
-rw-r--r--plugins/com.windriver.debug.tcf.core/.project28
-rw-r--r--plugins/com.windriver.debug.tcf.core/.settings/org.eclipse.jdt.core.prefs13
-rw-r--r--plugins/com.windriver.debug.tcf.core/.settings/org.eclipse.ltk.core.refactoring.prefs3
-rw-r--r--plugins/com.windriver.debug.tcf.core/META-INF/MANIFEST.MF15
-rwxr-xr-xplugins/com.windriver.debug.tcf.core/about.html28
-rw-r--r--plugins/com.windriver.debug.tcf.core/build.properties5
-rw-r--r--plugins/com.windriver.debug.tcf.core/plugin.properties13
-rw-r--r--plugins/com.windriver.debug.tcf.core/plugin.xml46
-rw-r--r--plugins/com.windriver.debug.tcf.core/schema/startup.exsd73
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/TCFCore.java102
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFLaunchDelegate.java60
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupDirector.java25
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupParticipant.java25
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourcePathComputerDelegate.java49
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFBreakpointListener.java16
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFConstants.java20
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpoint.java108
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsModel.java321
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsStatus.java78
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFError.java70
-rw-r--r--plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFLaunch.java328
-rw-r--r--plugins/com.windriver.debug.tcf.ui/.classpath11
-rw-r--r--plugins/com.windriver.debug.tcf.ui/.cvsignore1
-rw-r--r--plugins/com.windriver.debug.tcf.ui/.project28
-rw-r--r--plugins/com.windriver.debug.tcf.ui/.settings/org.eclipse.jdt.core.prefs13
-rw-r--r--plugins/com.windriver.debug.tcf.ui/META-INF/MANIFEST.MF18
-rwxr-xr-xplugins/com.windriver.debug.tcf.ui/about.html28
-rw-r--r--plugins/com.windriver.debug.tcf.ui/build.properties7
-rw-r--r--plugins/com.windriver.debug.tcf.ui/icons/arguments_tab.gifbin0 -> 95 bytes
-rw-r--r--plugins/com.windriver.debug.tcf.ui/icons/tcf.gifbin0 -> 165 bytes
-rw-r--r--plugins/com.windriver.debug.tcf.ui/plugin.properties13
-rw-r--r--plugins/com.windriver.debug.tcf.ui/plugin.xml86
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/TCFUI.java88
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFBreakpointAdapterFactory.java35
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFLaunchAdapterFactory.java65
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFModelSelectionPolicyFactoryAdapter.java25
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/BreakpointCommand.java102
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/DisconnectCommand.java55
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/ResumeCommand.java110
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepIntoCommand.java106
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepOverCommand.java106
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepReturnCommand.java106
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/SuspendCommand.java110
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/TerminateCommand.java120
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFArgumentsTab.java197
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFMainTab.java718
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFSelfTest.java1207
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFTabGroup.java34
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TestErrorsDialog.java85
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildren.java73
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenExecContext.java99
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenRegisters.java57
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenStackTrace.java70
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFColumnPresentationRegister.java81
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModel.java351
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelManager.java113
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelPresentation.java247
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelProxy.java34
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelSelectionPolicy.java40
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNode.java451
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeExecContext.java487
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeLaunch.java124
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeRegister.java213
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeStackFrame.java258
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFRunnable.java45
-rw-r--r--plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/trace/TraceView.java305
-rw-r--r--plugins/com.windriver.tcf.api/.classpath7
-rw-r--r--plugins/com.windriver.tcf.api/.cvsignore1
-rw-r--r--plugins/com.windriver.tcf.api/.project28
-rw-r--r--plugins/com.windriver.tcf.api/.settings/org.eclipse.jdt.core.prefs13
-rw-r--r--plugins/com.windriver.tcf.api/META-INF/MANIFEST.MF14
-rwxr-xr-xplugins/com.windriver.tcf.api/about.html28
-rw-r--r--plugins/com.windriver.tcf.api/build.properties4
-rw-r--r--plugins/com.windriver.tcf.api/plugin.properties13
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/Activator.java70
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/ErrorCodes.java18
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/EventQueue.java110
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractChannel.java796
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractPeer.java74
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Base64.java146
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/ChannelTCP.java123
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Command.java157
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/StreamChannel.java66
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ChannelLoop.java90
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/LocalPeer.java37
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyCollection.java111
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyMap.java96
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/RemotePeer.java65
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Token.java69
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Transport.java116
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/DiagnosticsService.java103
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/LocatorService.java368
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/BreakpointsProxy.java198
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/DiagnosticsProxy.java158
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/FileSystemProxy.java582
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/GenericProxy.java39
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LineNumbersProxy.java79
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LocatorProxy.java161
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java366
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/ProcessesProxy.java232
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RegistersProxy.java278
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RunControlProxy.java264
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/StackTraceProxy.java123
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/SysMonitorProxy.java204
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IChannel.java261
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IEventQueue.java47
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IPeer.java70
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IService.java25
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IToken.java29
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java516
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/Protocol.java193
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IBreakpoints.java162
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IDiagnostics.java65
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IFileSystem.java696
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILineNumbers.java73
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILocator.java99
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IMemory.java247
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IProcesses.java202
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRegisters.java318
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRunControl.java323
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IStackTrace.java140
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ISysMonitor.java378
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileInputStream.java246
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileOutputStream.java150
-rw-r--r--plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFTask.java117
-rw-r--r--plugins/com.windriver.tcf.dsf.core/.classpath7
-rw-r--r--plugins/com.windriver.tcf.dsf.core/.project28
-rw-r--r--plugins/com.windriver.tcf.dsf.core/META-INF/MANIFEST.MF18
-rwxr-xr-xplugins/com.windriver.tcf.dsf.core/about.html28
-rw-r--r--plugins/com.windriver.tcf.dsf.core/build.properties5
-rw-r--r--plugins/com.windriver.tcf.dsf.core/plugin.properties13
-rw-r--r--plugins/com.windriver.tcf.dsf.core/plugin.xml15
-rw-r--r--plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/Activator.java65
-rw-r--r--plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFExecuter.java201
-rw-r--r--plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFLaunch.java38
-rw-r--r--plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFLaunchDelegate.java24
-rw-r--r--plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFExecutionDMC.java26
-rw-r--r--plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFNativeProcesses.java332
-rw-r--r--plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFProcessDMC.java23
-rw-r--r--plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFRunControl.java829
-rw-r--r--plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFThreadDMC.java23
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/.classpath7
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/.project28
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/META-INF/MANIFEST.MF20
-rwxr-xr-xplugins/com.windriver.tcf.dsf.ui/about.html28
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/build.properties5
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/icons/tcf.gifbin0 -> 165 bytes
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/plugin.properties13
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/plugin.xml35
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/Activator.java60
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/AdapterFactory.java207
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ContainerLayoutNode.java82
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/LaunchDialogTabGroup.java37
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/LaunchVMProvider.java161
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ThreadLayoutNode.java197
-rw-r--r--plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ViewModelAdapter.java126
-rw-r--r--plugins/com.windriver.tcf.rse.ui/.classpath7
-rw-r--r--plugins/com.windriver.tcf.rse.ui/.project28
-rw-r--r--plugins/com.windriver.tcf.rse.ui/META-INF/MANIFEST.MF18
-rwxr-xr-xplugins/com.windriver.tcf.rse.ui/about.html28
-rw-r--r--plugins/com.windriver.tcf.rse.ui/build.properties5
-rw-r--r--plugins/com.windriver.tcf.rse.ui/icons/process-r.gifbin0 -> 582 bytes
-rw-r--r--plugins/com.windriver.tcf.rse.ui/icons/process-s.gifbin0 -> 344 bytes
-rw-r--r--plugins/com.windriver.tcf.rse.ui/icons/system-files-live.gifbin0 -> 224 bytes
-rw-r--r--plugins/com.windriver.tcf.rse.ui/icons/system-files.gifbin0 -> 157 bytes
-rw-r--r--plugins/com.windriver.tcf.rse.ui/icons/system-processes-live.gifbin0 -> 594 bytes
-rw-r--r--plugins/com.windriver.tcf.rse.ui/icons/system-processes.gifbin0 -> 574 bytes
-rw-r--r--plugins/com.windriver.tcf.rse.ui/icons/tcf.gifbin0 -> 165 bytes
-rw-r--r--plugins/com.windriver.tcf.rse.ui/icons/thread-r.gifbin0 -> 925 bytes
-rw-r--r--plugins/com.windriver.tcf.rse.ui/icons/thread-s.gifbin0 -> 942 bytes
-rw-r--r--plugins/com.windriver.tcf.rse.ui/plugin.properties13
-rw-r--r--plugins/com.windriver.tcf.rse.ui/plugin.xml59
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/Activator.java64
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/ITCFFileService.java21
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/ITCFSubSystem.java21
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/Messages.java131
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFConnectorService.java275
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFConnectorServiceManager.java44
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileAdapter.java36
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileResource.java122
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileService.java643
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileSubSystemConfiguration.java116
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessAdapter.java43
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessResource.java313
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessService.java275
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessSubSystemConfiguration.java53
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRSETask.java71
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRemoteFile.java34
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRemoteProcess.java41
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFSystemViewProcessAdapterFactory.java50
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFSystemViewRemoteProcessAdapter.java446
-rw-r--r--plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/messages.properties103
-rw-r--r--readme.txt5
217 files changed, 30700 insertions, 0 deletions
diff --git a/docs/.project b/docs/.project
new file mode 100755
index 000000000..536d25a62
--- /dev/null
+++ b/docs/.project
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>tcf_docs</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ </buildSpec>
+ <natures>
+ </natures>
+</projectDescription>
diff --git a/docs/TCF Architecture.png b/docs/TCF Architecture.png
new file mode 100644
index 000000000..fbf650ca0
--- /dev/null
+++ b/docs/TCF Architecture.png
Binary files differ
diff --git a/docs/TCF Context Identifier Explanation.html b/docs/TCF Context Identifier Explanation.html
new file mode 100644
index 000000000..79e5d09f4
--- /dev/null
+++ b/docs/TCF Context Identifier Explanation.html
@@ -0,0 +1,257 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1251">
+ <TITLE>TCF Context Identifier Explanation</TITLE>
+ <META NAME="GENERATOR" CONTENT="OpenOffice.org 2.2 (Win32)">
+ <META NAME="CREATED" CONTENT="20070830;12134342">
+ <META NAME="CHANGEDBY" CONTENT="Eugene Tarassov">
+ <META NAME="CHANGED" CONTENT="20070830;12351368">
+ <STYLE TYPE="text/css">
+ <!--
+ H1 { color: #000000 }
+ P { color: #000000 }
+ P.western { font-size: 13pt }
+ H2 { color: #000000 }
+ -->
+ </STYLE>
+</HEAD>
+<BODY LANG="en-US" TEXT="#000000" DIR="LTR">
+<P CLASS="western" STYLE="border-top: none; border-bottom: 1.00pt solid #4f81bd; border-left: none; border-right: none; padding-top: 0in; padding-bottom: 0.06in; padding-left: 0in; padding-right: 0in">
+<FONT COLOR="#17365d"><FONT FACE="Cambria"><FONT SIZE=6 STYLE="font-size: 26pt">TCF
+Context Identifier Explanation</FONT></FONT></FONT></P>
+<P CLASS="western"><FONT COLOR="#4f81bd"><FONT FACE="Cambria"><FONT SIZE=3><I>Felix
+Burton, Wind River, Version 2</I></FONT></FONT></FONT></P>
+<H1><FONT COLOR="#365f91"><FONT FACE="Cambria"><FONT SIZE=4><B>Introduction</B></FONT></FONT></FONT></H1>
+<P CLASS="western">Most if not all TCF services functions need some
+way to identify what entity e.g. process, thread, task, semaphore,
+breakpoint, flash device, device on JTAG scan chain, etc they should
+operate on. To do this TCF uses a context identifier (aka ContextId).
+This document is attempting to explain how ContextIds are intended to
+be used. This is document does not define actual services or exact
+context hierarchies, but for the purpose of making things more
+concrete examples may be used.</P>
+<H2 LANG="en-GB" STYLE="margin-top: 0in; margin-bottom: 0.04in"><FONT COLOR="#4f81bd"><FONT FACE="Cambria"><FONT SIZE=3 STYLE="font-size: 13pt"><B>Why
+a single ContextId?</B></FONT></FONT></FONT></H2>
+<P CLASS="western">A prudent question to ask is why use a single
+ContextId instead of having separate IDs for each notion e.g. a
+ProcessId, ThreadId, BreakpointId, JTAGDeviceId, etc. Having separate
+IDs is used in many existing debug APIs and protocols and may seem
+intuitive. However, there are several issues with this approach:</P>
+<P CLASS="western">1. It is inflexible in that it requires each
+function to upfront know how many levels are needed and what type of
+context each level represent.</P>
+<P CLASS="western">2. This in turn makes it difficult to use the same
+API for different environments since they often have different types
+of IDs and has different number of levels. For example Linux have
+processes and threads while OCD have cores.</P>
+<H1 LANG="en-GB"><FONT COLOR="#365f91"><FONT FACE="Cambria"><FONT SIZE=4><B>Context
+identifier</B></FONT></FONT></FONT></H1>
+<P CLASS="western">ContextIds are opaque handles that only have
+meaning to the service that created them or its peer services. They
+are created for clients, by service implementations to identify some
+entity handled by the services. Clients can use contextIds in the
+following ways:</P>
+<P CLASS="western">1. Pass to the originating service or peer
+services</P>
+<P CLASS="western">2. Compare for equality with other contextIds
+retrieved from the originating service or peer services.</P>
+<P CLASS="western">More specifically, clients should not try to
+decode or extract information from the contextId, instead they should
+make requests to the originating service or peer services using the
+contextId for information or action.</P>
+<P CLASS="western">As can be seen from the above, contextIds created
+by one service can be used by its peer services. The service should
+either to do something useful or to give an error indicating that the
+contextId is not relevant to that particular service. To guarantee
+that a contextId created by service A and passed to service B is not
+misinterpreted to be something other that what service A intended,
+there must be a global naming scheme for contextId within a target.</P>
+<P CLASS="western">This allows two or more services to create the
+same contextId when they operate on the same entity. It means that a
+single contextId can have multiple aspects that are handled by
+different services, thereby allowing decoupling of service
+interfaces.</P>
+<H1 LANG="en-GB"><FONT COLOR="#365f91"><FONT FACE="Cambria"><FONT SIZE=4><B>Context
+hierarchies</B></FONT></FONT></FONT></H1>
+<P CLASS="western">Entities represented by contextIds typically
+relate to similar entities in a list or parent/child relationship.
+Examples, 1) Linux processes have children threads, 2) a suspended
+thread has a list of stack frames, and 3) threads have register
+groups which have registers which can have fields. These
+relationships form context hierarchies.</P>
+<P CLASS="western">Depending on the system there may be several
+different context hierarchies. For example contexts available for
+JTAG debugging include:</P>
+<P CLASS="western">1. debugging</P>
+<P CLASS="western">2. memory access</P>
+<P CLASS="western">3. register access</P>
+<P CLASS="western">4. JTAG access</P>
+<P CLASS="western">Interestingly there may also be relations between
+the different hierarchies. For example contexts available for
+debugging may correspond with contexts available for memory access. A
+typical example of this is Linux where a contextId representing a
+process can be used for debugging as well as memory access, open file
+table access, memory map access, etc. In such cases, the same
+contextId should be used in all hierarchies. This allows clients to
+detect when hierarchies come together or split apart so the client
+can represent the relationships properly to the user for example in a
+GUI.</P>
+<H1 LANG="en-GB"><FONT COLOR="#365f91"><FONT FACE="Cambria"><FONT SIZE=4><B>Accessing
+context information</B></FONT></FONT></FONT></H1>
+<P CLASS="western">Information associated with a contextId can be
+sufficiently large to make it impractical to transfer all associated
+information to the client in a single request. To reduce the amount
+of information transferred while still allowing the implementation to
+be relatively simple; the information is categorized as follows:</P>
+<P CLASS="western">1. Child context references per service</P>
+<P CLASS="western">2. Slow changing properties per service, a.k.a.
+properties</P>
+<P CLASS="western">3. Fast changing properties per service, a.k.a.
+state or status
+</P>
+<P CLASS="western">Category 1 provides a simple way to express
+unbounded lists of related contextIds. If such a list becomes too
+large the service can split the list into a list of lists, list of
+lists or lists, etc as needed.</P>
+<P CLASS="western">Category 2 and 3 provides a simple way to express
+arbitrary information about the context in the form of a key/value
+pair. Properties may also contain contextId references for example
+for the parent context.</P>
+<P CLASS="western">The split between category 2 and 3 allows the
+service to handle fast changing information in a more optimal way and
+allows it to handle slow changing information in a more simple way.
+It is up to the service to define what information is slow vs. fast
+changing.</P>
+<H1 LANG="en-GB"><FONT COLOR="#365f91"><FONT FACE="Cambria"><FONT SIZE=4><B>ContextId
+formatting</B></FONT></FONT></FONT></H1>
+<P CLASS="western">The ContextId is represented as string between
+clients and services. The formatting of the string with one exception
+is completely up to the implementation that created the contextId.
+The exception is the ContextId prefix explained below. The remainder
+of the string can be formatted in any way that the service descries.
+Two typical ways comes to mind:</P>
+<P CLASS="western">1. Hierarchical list where each level is spelled
+out. For example on Linux:</P>
+<P CLASS="western" STYLE="margin-left: 0.79in">a. A process could be
+identified by &ldquo;ppid&rdquo; and a thread by &ldquo;ppid,ttid&rdquo;</P>
+<P CLASS="western" STYLE="margin-left: 0.79in">b. A register set by
+&ldquo;ppid,ttid,rset&rdquo;</P>
+<P CLASS="western" STYLE="margin-left: 0.79in">c. A stack frame by
+&ldquo;ppid,ttid,slevel&rdquo;</P>
+<P CLASS="western" STYLE="margin-left: 0.79in">d. A local variable on
+a specific stack level by &ldquo;ppid,ttid,slevel,vname&rdquo;</P>
+<P CLASS="western">2. Flat ID that the generating service used to do
+table lookup for more information. For example</P>
+<P CLASS="western" STYLE="margin-left: 0.79in">a. Index into an array
+&ldquo;tableIndex,generationNumber&rdquo;</P>
+<P CLASS="western" STYLE="margin-left: 0.79in">b. Key used for hash
+lookup &ldquo;sequentialNumber&rdquo;</P>
+<H1 LANG="en-GB"><FONT COLOR="#365f91"><FONT FACE="Cambria"><FONT SIZE=4><B>ContextId
+prefix</B></FONT></FONT></FONT></H1>
+<P CLASS="western">When information from more than one channel is
+joined together to when value-adding services between the two
+endpoints create contextIds it must be possible to for every service
+to determine if a contextId was created by it or a foreign entity. To
+do this, each service manager is assigned a unique contextId prefix
+that all its generated contextIds should be prefixed with followed by
+the colon (:) character. For example imagine that GDB was designed to
+be a value-adding service, contextIds created on this level could be
+prefixed by &ldquo;gdb:&rdquo; to guarantee that the target would be
+able to return error if such contextId was given to it instead of to
+the services in GDB.</P>
+<P CLASS="western">The prefix used by a service manager is
+dynamically assigned by the client initiating the connection. A
+limited TCF endpoint implementation is not required to support
+contextId prefixing. However, in such case it is only be possible to
+have value-adding services if they intercept all services on the
+endpoint.</P>
+<H1 LANG="en-GB"><FONT COLOR="#365f91"><FONT FACE="Cambria"><FONT SIZE=4><B>Context
+information caching</B></FONT></FONT></FONT></H1>
+<P CLASS="western">Clients will most likely need to cache context
+information in order to keep the amount of information transferred to
+a minimum. Such caching should be based on the contextId, service
+name, and type of data i.e. children contextIds, properties or state.</P>
+<P CLASS="western">The suggested implementation is to use a two stage
+cache lookup, where the first stage is using only the contextId and
+the second stage using the service name and the type of data. The
+reason for the two stage approach is to allow easy flushing of the
+cached information when contextIds are removed.</P>
+<P CLASS="western">Services support caching in clients by sending
+events for any changes to the information. The following events are
+expected to be generated by services when needed:</P>
+<P CLASS="western">1. Children added. The event includes the parent
+contextId, service name and list of contextIds and their properties
+to be added to the cache. Clients that have not populated the cache
+for the specified parent contextId should ignore this event.</P>
+<P CLASS="western">2. Children removed. The event includes the parent
+contextId, service name and list of contextIds to be removed from the
+list. When received, clients should update cache by removing all
+listed contextIds for the specified parent contextId and service
+name.</P>
+<P CLASS="western">3. Children changed. The event includes the parent
+contextId and service name. This event does not include the updated
+list of contextIds; instead clients are expected to reread the list
+of children if they need it. When received, clients should invalidate
+the list of children contextIds for the specified parent contextId
+and service name.</P>
+<P CLASS="western">4. Properties changed. This event includes a list
+of contextId, service name and properties. When received, clients
+should update cache with the new properties.</P>
+<P CLASS="western">5. State or status changed. This event includes
+contextId, service name and state or status. When received, clients
+should update cache with the new state or status.</P>
+<P CLASS="western">Invalidating or removing entries from the list of
+children contextIds should also result in recursively invalidating
+all cache entries for the removed contextIds. This is necessary to
+avoid stale cache entries to linger when a removed contextId is
+reused for a new context.</P>
+<H1 LANG="en-GB"><FONT COLOR="#365f91"><FONT FACE="Cambria"><FONT SIZE=4><B>Relationship
+between services</B></FONT></FONT></FONT></H1>
+<P CLASS="western">Even though service interfaces should not have any
+direct dependencies, they can have context hierarchy relationships.</P>
+<P CLASS="western">A good example of such relationship is between the
+&ldquo;run control&rdquo; service and the &ldquo;memory&rdquo;
+service. It seems to make sense to specify that the run control
+hierarchy is &ldquo;rooted&rdquo; in the memory hierarchy since it is
+hard to imagine executing instructions without a memory that stores
+the instructions.</P>
+<P CLASS="western">Another example is for run control, register and
+stack trace services where it seems logical to define registers and
+stack frame hierarchies to be &ldquo;rooted&rdquo; in the run control
+hierarchy.</P>
+<P CLASS="western">By &ldquo;rooted&rdquo; we mean that roots for one
+hierarchy can be found in another hierarchy.</P>
+<P CLASS="western">Usually clients need only one particular hierarchy
+at the time, however some clients, for example in Eclipse the Debug
+View is designed to be provide selection for run control, memory
+view, locals view, registers view, etc in one place, so it needs to
+merge memory, run control and stack trace hierarchies in order to
+provide single tree for selection.</P>
+<P CLASS="western">The services interface specification should define
+the rooting of its context hierarchy, if any. As mentioned in the
+example above, run control service is rooted in the memory hierarchy,
+and register and stack trace services are rooted in the run control
+hierarchy.</P>
+<P CLASS="western">It may be possible to a service context hierarchy
+to be rooted in multiple hierarchies.</P>
+<P CLASS="western">Which context hierarchies are merged is up to the
+implementer of the client.</P>
+<H1 LANG="en-GB"><FONT COLOR="#365f91"><FONT FACE="Cambria"><FONT SIZE=4><B>Context
+hierarchy roots</B></FONT></FONT></FONT></H1>
+<P CLASS="western">For some services it is possible to use &ldquo;null&rdquo;
+as a special parent contextId to the &ldquo;get children&rdquo;
+command to retrieve a list of root contextIds. The service interface
+definition should specify if retrieval of roots is supported by the
+service.</P>
+<P CLASS="western">Example services that would support the &ldquo;null&rdquo;
+parent contextId are JTAG access and kernel awareness services since
+this is global information in the target.</P>
+<P CLASS="western">Example services that would not support the &ldquo;null&rdquo;
+parent contextId are register and stack trace services since parent
+contextId for registers and stack frames is usual obtained through
+run control service.</P>
+<P CLASS="western"><BR><BR>
+</P>
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/docs/TCF Getting Started.html b/docs/TCF Getting Started.html
new file mode 100755
index 000000000..05d2ed32a
--- /dev/null
+++ b/docs/TCF Getting Started.html
@@ -0,0 +1,226 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework: Getting Started</title>
+</head>
+
+<body lang='EN-US'>
+
+<h1>Target Communication Framework: Getting Started</h1>
+
+<p>Copyright (c) 2007 Wind River Systems, Inc. Made available under the EPL v1.0
+<p>Direct comments, questions to the <a href="mailto:dsdp-tm-dev@eclipse.org">dsdp-tm-dev@eclipse.org</a> mailing list
+
+<h2>Table of Contents</h2>
+<ul>
+ <li><a href='#Workspace'>Creating Eclipse Workspace</a>
+ <li><a href='#Plugins'>TCF Plugins</a>
+ <li><a href='#Agent'>Building TCF Agent</a>
+ <li><a href='#Browsing'>Browsing Agent Source Code in CDT</a>
+ <li><a href='#RSE'>Using TCF With Remote System Explorer</a>
+ <li><a href='#Debugger'>Using TCF With Eclipse Debugger</a>
+</ul>
+
+<h2><a name='Workspace'>Creating Eclipse Workspace</a></h2>
+
+<p>Eclipse can be used for developing clients for TCF in Java.
+TCF host side code is organized into several Eclipse plug-in projects,
+below are steps to create and populate Eclipse workspace with TCF projects:</p>
+
+<ul>
+ <li>Install JDK 1.5.0 or later
+ <li>Install <b>Eclipse Classic SDK 3.3</b> or later, last tested with 3.4M3, recommended 3.3.1.1<br>
+ <a href='http://download.eclipse.org/eclipse/downloads/'>http://download.eclipse.org/eclipse/downloads/</a>
+ <li>Install <b>TM RSE SDK 2.0</b> or later, last tested with 3.0M3, recommended 2.0.2<br>
+ <a href='http://download.eclipse.org/dsdp/tm/downloads/'>http://download.eclipse.org/dsdp/tm/downloads/</a>
+ <li><b>Optional</b> dependencies for TCF/DSF/CDT integration: these are not required by
+ TCF itself, and not needed for RSE integration or for TCF based debugger demo,
+ use these for future development:
+ <ul>
+ <li>CDT 4.0 or later, last tested with 5.0M3, recommended 4.0.1<br>
+ <a href='http://download.eclipse.org/tools/cdt/releases/europa/'>http://download.eclipse.org/tools/cdt/releases/europa/</a>
+ <li>DD DSF SDK N20071113-0200 (Must use this version, later versions will NOT work)<br>
+ <a href='http://download.eclipse.org/dsdp/dd/downloads/'>http://download.eclipse.org/dsdp/dd/downloads/</a>
+ </ul></li>
+ <li>Unzip TCF code.
+ <li>Run Eclipse:
+ <pre>eclipse.exe -vm &lt;JDK path&gt;\bin\javaw.exe -data &lt;Workspace path&gt; -vmargs -Xmx200M</pre>
+ <li>Open "Java" perspective.
+ <li>In "Package Explorer" view: do right click and then select "Import...".
+ <li>Select "General/Existing Projects into Workspace" and click "Next".
+ <li>Select root directory: &lt;TCF Root&gt;\plugins, and click "Next".<ul>
+ <li>If DD-DSF and/or CDT are not installed, don't import the following two plugins
+ into your workspace:<ul>
+ <li>com.windriver.tcf.dsf.core
+ <li>com.windriver.tcf.dsf.ui
+ </ul></li>
+ </ul></li>
+ <!--
+ <li><b>Optional</b> for browsing dependencies:<ul>
+ <li>In Package Explorer: do right click and select "Import...".
+ <li>Select "Plug-in Development/Plug-ins and Fragments" and click "Next".
+ <li>Select "Import plug-ins and fragments required by existig workspace plug-ins" and click "Next".
+ <li>Click "Select All", then click "Finish".
+ </ul></li>
+ -->
+</ul>
+
+<!--
+<p>Alternative way to get CDT, DSF and RSE installed:
+<ul>
+ <li>Get Eclipse for C/C++ Package from <a href='http://www.eclipse.org/downloads/'>
+ http://www.eclipse.org/downloads/</a> - it includes CDT.
+ <li>Do "Help > Software Updates > Find and Install > Search for New Features to Install > Next"
+ <li>Select "Europa Discovery Site", press "Finish"
+ <li>Select following:
+ <ul>
+ <li>Remote Access and Device Development
+ <ul>
+ <li>Remote System Explorer End-User Runtime
+ <li>Debugger Services Framework end-user and extender SDK
+ </ul>
+ </ul>
+ <li>Press "Select Required" if in Error
+ <li>Press "Next", "Accept", "Next", "Finish"
+</ul>
+-->
+
+<h2><a name='Plugins'>TCF Plugins</a></h2>
+
+<p>TCF plugins source code is stored in <code>&lt;TCF Root&gt;\plugins</code> directory.
+
+<dl>
+ <dt><b>com.windriver.tcf.api</b>
+ <dd>This is the main TCF plugin. It contains the framework itself and interfaces for standard services.
+ It is the only TCF plugin, which should be required by a TCF client. The rest of TCF plugins are
+ clients developed as a reference implementation or for demonstration purposes.
+ <p>
+ <dt><b>com.windriver.debug.tcf.core,com.windriver.debug.tcf.ui</b>
+ <dd>This is a prototype code that connects Eclipse Debug Framework and Target Communication Framework.
+ It allows to launch Eclipse debug session by connecting to a target running TCF agent,
+ and then perform basic debugging tasks, like resuming, suspending, single-stepping, setting/removing breakpoints, etc.
+ The code can be used as a reference for developing new TCF clients.
+ <p>
+ <dt><b>com.windriver.tcf.dsf.core,com.windriver.tcf.dsf.ui</b>
+ <dd>This code allows Debugger Services Framework (DSF) clients to access targets using TCF as comminucation protocol.
+ It includes implementation of DSF services as TCF clients.
+ <p>
+ <dt><b>com.windriver.tcf.rse.ui</b>
+ <dd>This plugin allows Remote System Explorer (RSE) to connect to remote machines using TCF as communication protocol.
+ It includes implementation of RSE services as TCF clients.
+</dl>
+
+<h2><a name='Agent'>Building TCF Agent</a></h2>
+
+<p><b>Linux</b> is the recommended evaluation platform, since most TCF services
+are implemented. To build the agent:
+<ul>
+ <li>Make sure <code>elfutils-libelf-devel</code> is installed.
+ On Fedora, it can be installed by command:
+ <pre>yum install elfutils-libelf-devel</pre>
+ It also can be built and installed from source code, e.g.
+ <a href="http://www.mr511.de/software/libelf-0.8.9.tar.gz">http://www.mr511.de/software/libelf-0.8.9.tar.gz</a>:
+ <pre>
+ ./configure
+ make
+ make install
+ setenv LD_LIBRARY_PATH /usr/local/lib:$LD_LIBRARY_PATH</pre>
+ <li>Run <code>make</code> command in <code>&lt;TCF Root&gt;/agent</code> directory.
+ <li>Start agent with <code>./agent</code> command.
+</ul>
+
+<p>On <b>Windows</b>, only the TCF file service is currently implemented in the agent,
+so the RSE Processes and Eclipse Debug demos will not work.
+For building the agent, there are two possibilities:<ul>
+<li>Building with gcc (freely available from <a href="http://wascana.sourceforge.net/">Wascana</a>,
+<a href="http://www.cygwin.com">Cygwin</a> or the
+<a href="http://www.mingw.org/">MinGW32 project</a>): run
+<pre>make -fMakefile_cygwin.mak</pre>
+in the agent directory (the Makefile works with mingw, too).</li>
+
+<li>Building with Microsoft Visual C++: Open workspace file <code>&lt;TCF Root&gt;/agent/agent.dsw</code>
+and then build and run the agent using Development Studio commands. If getting an error about
+<tt>IPHlpApi.h</tt> missing, you'll need to install the latest
+<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=0BAF2B35-C656-4969-ACE8-E4C0C0716ADB&displaylang=en">MS Platform SDK</a>.
+For the free <a href="http://www.microsoft.com/express/vc/">Visual C++ Express Edition</a>, the
+following changes in settings may be necessary:<ul>
+ <li>Project &gt; Properties &gt; C/C++ &gt; Preprocessor &gt; Preprocessor Definitions:
+ add <tt>_CRT_SECURE_NO_DEPRECATE</tt></li>
+ <li>Project &gt; Properties &gt; Linker &gt; Input &gt; Additional Dependencies :
+ add <tt>shell32.lib</tt></li>
+</ul></li>
+</ul></p>
+
+<p>On <b>VxWorks</b>, the file service as well as most debug services are currently
+working. Line number mapping and the SysMonitor service (required for RSE Processes
+Demo) are not yet implemented.<br/>
+To build the agent: Use Wind River Workbench to create a Kernel Module project out of source code in
+<code>&lt;TCF Root&gt;/agent</code> directory. Use Workbench commands to build and run the agent.</p>
+
+<h2><a name='Browsing'>Browsing Agent Source Code in CDT</a></h2>
+On Linux, the default configuration from the CDT .project file included in TCF
+should be fine for correctly browsing the agent source code. Linux is recommended
+for working on the agent anyways, because most features are implemented already.
+<p>
+On Windows, open Project Properties of the agent project, and under C/C++ General &gt;
+Indexer switch the configuration to "Win32 - Cygwin" or "Win32 - DevStudio"
+as needed.
+<p>
+For VxWorks, browsing should be configured automatically through the WR Workbench
+Kernel Module Project.
+
+<h2><a name='RSE'>Using TCF With Remote System Explorer</a></h2>
+
+<p>Remote System Explorer is an Eclipse based component that allows users to create connections to remote machines and
+explore their file systems, see list of processes and access some other resources, like remote shells.
+Remote System Explorer has been designed as a flexible, extensible framework to which Eclipse plug-in developers can
+contribute their own system definitions, actions, etc.</p>
+
+<p>Plugin <b>com.windriver.tcf.rse.ui</b> enables use of Processes and Files subsystems of Remote System Explorer over TCF.
+It also extends Processes subsystem to include CPU utilization data and some other process attributes in RSE views.</p>
+
+<p>To connect a remote machine over TCF:</p>
+<ul>
+ <li>Make sure TCF agent is running on remote machine.
+ <li>Run Eclipse with RSE and TCF plugins installed.
+ <li>In Eclipse, do "Window/Open Perspective/Remote System Explorer" command.
+ <li>In "Remote Systems" view: do right click and select "New/Connection..."
+ <li>In "New Connection" dialog box: select TCF and press "Next" button.
+ <li>Enter "Host name" - IP host name ot the target machine, and "Connection name" - arbitrary string to name new connection.
+ Press "Finish" button.
+ <li>New connection should appear in "Remote Systems" view and it is ready to be explored.
+</ul>
+
+<p>RSE features supported by TCF connection:
+<ul>
+ <li>File Subsystem: full support, i.e. browse, upload, download, copy, move, delete
+ <li>Processes: browse, including parent/child relationship
+</ul>
+
+<h2><a name='Debugger'>Using TCF With Eclipse Debugger</a></h2>
+
+<p>Plugins <b>com.windriver.debug.tcf.core</b> and <b>com.windriver.debug.tcf.ui</b> allow to start a debug session
+by connecting to a machine runnning TCF agent. This is not a complete debugger implementation, it is intended for
+demo and reference purposes.
+
+<p>To start a debug session over TCF:</p>
+<ul>
+ <li>Make sure TCF agent is running on remote machine.
+ <li>Run Eclipse with TCF plugins installed.
+ <li>In Eclipse, do "Window/Open Perspective/Debug" command.
+ <li>Do "Run/Open Debug Dialog..." command.
+ <li>In "Debug" dialog box: select "Target Comminucation Framework" configuration type and press "New" button.
+ <li>Enter a name for the configuration.
+ <li>Select a target machine in "Available targtes" list. The list shows targets autodetected on local network.
+ <li>Press "Run Diagnostics" button to test connectivity for selected target.
+ <li>Enter a program name to run in debug session, for example "/bin/ls".
+ <li>Press "Debug" to start the debugger.
+</ul>
+
+<p>In TCF debug session only "Debug", "Breakpoints" and "Registers" views are populated. Source level debugging
+in not supported at this time. Breakpoints can be planted at an absolute addresses only, using menu command "Run/Toggle Breakpoint".
+"Registers" view can be brought in by "Window > Show View > Registers". Registers can be shown only for top stack frame.
+</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/docs/TCF Linux Agent Prototype.html b/docs/TCF Linux Agent Prototype.html
new file mode 100644
index 000000000..50ec8e8fe
--- /dev/null
+++ b/docs/TCF Linux Agent Prototype.html
@@ -0,0 +1,199 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1251">
+ <TITLE>This is a brief description of the TCF Linux user-mode agent prototype implementation</TITLE>
+ <META NAME="GENERATOR" CONTENT="OpenOffice.org 2.2 (Win32)">
+ <META NAME="CREATED" CONTENT="20070830;12381303">
+ <META NAME="CHANGED" CONTENT="16010101;0">
+ <STYLE TYPE="text/css">
+ <!--
+ H1 { color: #000000 }
+ P { color: #000000 }
+ P.western { font-size: 13pt }
+ H2 { color: #000000 }
+ -->
+ </STYLE>
+</HEAD>
+<BODY LANG="en-US" TEXT="#000000" DIR="LTR">
+
+<P>This is a brief description of the TCF Linux
+user-mode agent prototype implementation. The agent is implemented as
+an event driven program. The main event queue is handled by a single
+thread &ndash; the event dispatch thread. Some sub-systems are using
+other threads locally, but will never call other sub-systems using
+these threads. Instead an event will be placed on the main event
+queue to handle the inter sub-system communication.</P>
+
+<H1>Main Program</H1>
+
+<P>Main program parses command line options and initialized sub-systems</P>
+<P>Files:</P>
+<P>main.c</P>
+
+<H1>Target Communication Framework</H1>
+
+<H2>Command and Event Registration and Dispatch</H2>
+
+<P>This module handles registration of command and
+event handlers. It is called when new messages are received and will
+dispatch messages to the appropriate handler. It has no knowledge of
+what transport protocol is used and what services do.</P>
+<P>Files:</P>
+<P>protocol.c</P>
+<P>protocol.h</P>
+
+<H2>Transport Layer</H2>
+
+<P>Implements input and output stream over TCP/IP
+transport and UDP based server side auto discovery.</P>
+<P>Files:</P>
+<P>channel.c</P>
+<P>channel.h</P>
+<P>tcf.h</P>
+
+<H2>Input and Output Stream Interface and Library</H2>
+
+<P>This module defines the input and output stream
+interface and support library functions.</P>
+<P>Files:</P>
+<P>streams.c</P>
+<P>streams.h</P>
+
+<H1>Services</H1>
+
+<H2>Breakpoint</H2>
+
+<P>The breakpoint services implements a global
+breakpoint list.</P>
+<P>Files:</P>
+<P>breakpoints.c</P>
+<P>breakpoints.h</P>
+
+<H2>Run Control</H2>
+
+<P>This module implements the run control service. It
+builds uses the context module to do low level control of contexts.
+It implements a &ldquo;safe queue&rdquo; which contains events that
+that should be processed then their context is suspended. Incoming
+TCF messages are suspended while the safe queue is non-empty and are
+resumed when the last safe queue entry is handled.</P>
+<P>Files:</P>
+<P>runctrl.c</P>
+<P>runctrl.h</P>
+
+<H2>System Monitoring</H2>
+
+<P>This module provides system level monitoring
+information, similar to the UNIX top or Windows task manager.</P>
+<P>Files:</P>
+<P>sysmon.c</P>
+<P>sysmon.h</P>
+
+<H2>Agent Diagnostics</H2>
+
+<P>This service is used to do end-to-end self test
+from the host to the target.</P>
+<P>Files:</P>
+<P>diagnostics.c</P>
+<P>diagnostics.h</P>
+
+<H1>OS Context Handling</H1>
+
+<P>This module handles process/thread OS contexts and
+their state machine. All ptrace() handling is isolated to here.</P>
+<P>Files:</P>
+<P>context.c</P>
+<P>context.h</P>
+
+<H1>Agent Event Queue</H1>
+
+<P>This module implements the main event queue
+dispatch and queuing. All events are processed by a single thread.
+Any thread can queue new events.</P>
+<P>Files:</P>
+<P>events.c</P>
+<P>events.h</P>
+
+<H1>Misc</H1>
+
+<H2>Command line interpreter</H2>
+
+<P>The module allows a user to interact with agent. Current implementation of command line interpreter is incomplete.</P>
+<P>Files:</P>
+<P>cmdline.c</P>
+<P>cmdline.h</P>
+
+<H2>Error message display</H2>
+
+<P>This module defines agent error codes in addition to system codes defined in errno.h</P>
+<P>Files:</P>
+<P>errors.c</P>
+<P>errors.h</P>
+
+<H2>Exception Handling</H2>
+
+<P>Exception handling. Functionality is similar to C++ try/catch.</P>
+<P>Files:</P>
+<P>exceptions.c</P>
+<P>exceptions.h</P>
+
+<H2>JSON Library</H2>
+
+<P>The module contains utility functions for parsing and generating of JSON text.
+TCF standard services use JSON as messages format. See <a href='TCF Specification.html#JSON'>JSON - Preferred Marshaling</a>
+for JSON description.</P>
+<P>Files:</P>
+<P>json.c</P>
+<P>json.h</P>
+
+<H2>Double Linked List</H2>
+
+<P>Utilitity module to support double linked lists.</P>
+<P>Files:</P>
+<P>link.h</P>
+
+<H2>Host OS Abstraction</H2>
+
+<P>Machine and OS dependend definitions.
+This module implements host OS abstraction layer that helps make
+agent code portable between Linux, Windows, VxWorks and potentially other OSes.</P>
+<P>Files:</P>
+<P>mdep.c</P>
+<P>mdep.h</P>
+
+<H2>Malloc Abstraction</H2>
+
+<P>Provides local versions of malloc(), realloc() and free().</P>
+<P>Files:</P>
+<P>myalloc.c</P>
+<P>myalloc.h</P>
+
+<H2>Proxy</H2>
+
+<P>Proxy service should allow tunneling of TCF messages to another target on behalf of a client.
+This service intended to be used when a client has no direct access to a target.</P>
+<P>Files:</P>
+<P>proxy.c</P>
+<P>proxy.h</P>
+
+<H2>Test Application</H2>
+
+<P>Test application is used by Diagnostics service to run various tests.</P>
+<P>Files:</P>
+<P>test.c</P>
+<P>test.h</P>
+
+<H2>Debug Logging</H2>
+
+<P>The module implements logging and tracing that is mostly intended for debugging of the agent.</P>
+<P>Files:</P>
+<P>trace.c</P>
+<P>trace.h</P>
+
+<H1>Architecture</H1>
+
+<P><IMG SRC="TCF%20Architecture.png" NAME="graphics1" ALIGN=BOTTOM WIDTH=647 HEIGHT=359 BORDER=0></P>
+
+</BODY>
+</HTML>
diff --git a/docs/TCF Project.html b/docs/TCF Project.html
new file mode 100644
index 000000000..0071e96fc
--- /dev/null
+++ b/docs/TCF Project.html
@@ -0,0 +1,141 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/TR/1999/REC-html401-19991224/loose.dtd">
+<HTML lang=en-us>
+<HEAD>
+<TITLE>Target Communication Framework</TITLE>
+</HEAD>
+
+<BODY>
+
+<H1>Target Communication Framework project</H1>
+
+<P>
+<H2><A name=Index></A>Index</H2>
+
+<UL>
+ <LI><A href="#Summary">Summary</A>
+ <LI><A href="#Goals">Goals</A>
+ <LI><A href="#Features">Features</A>
+ <LI><A href="#Agent">Reference implementation of a target agent</A>
+ <LI><A href="#Debugger">Prototype of a debugger based on Eclipse Debug Framework and TCF</A>
+ <LI><A href="#RSE">Prototype of a system monitor and remote file access based on Remote System Explorer and TCF</A>
+</UL>
+
+<P>
+<H2><A name=Summary></A>Summary </H2>
+
+<P>Today almost every device software development tool on the market has its own
+method of communication with target system. Communication methods often conflict
+with each other, require individual setup, configuration and maintenance, impose
+all kinds of unnecessary limitations. Target Communication Framework is designed
+to establish common ground in the area of communication protocols between
+development tools and embedded devices.
+
+<P>
+<H2><A name=Goals></A>Goals </H2>
+<P>
+<UL>
+ <LI>Universal, extensible, simple, lightweight, vendor agnostic framework for
+ tools and targets to communicate for purpose of debugging, profiling, code
+ patching and other device software development needs.
+ <LI>Single configuration per target (not per tool per target as today in most
+ cases), or no configuration when possible.
+ <LI>Small overhead and footprint on target side. </LI></UL>
+<P>
+
+<H2><A name=Features></A>Features </H2>
+<P><A href="TCF Specification.html">Target Communication Framework Specification</A> is a document
+describing design goals, requirements and format of TCF communication protocol,
+as well as framework API and software design considerations.
+<P>TCF communication model is based on the idea of services. A service is a group
+of related commands, events and semantics. A service can be discovered,
+added or removed as a group at communication endpoint. Service definitions are
+not part of the framework specification, and new services are expected to be
+defined by developers of tools and target agents. However, standardization of
+common services is needed to achieve certain level of compatibility of
+tools/targets, see <A href="TCF Services.html">TCF Services Specification</A>
+as starting point of this work.
+
+<H2><A name=Agent></A>Reference implementation of a target agent</H2>
+
+<P>Current reference implementation of TCF target agents is fully functional,
+can run on Windows, Linux and VxWorks, and provides the following services:
+<UL>
+ <LI>Run Control - provides threads and processes run control functionality
+ sufficient for debugging of user space programs. On Linux it is implemented
+ using PTRACE, on VxWorks is uses vxdbgLib, on Windows it is not currently supported.
+
+ <LI>Breakpoints - provides basic breakpoints support. On Linux it is
+ implemented using PTRACE, on VxWorks is uses vxdbgLib,
+ on Windows it is not currently supported.
+
+ <LI>Registers - allows inspection and modification of CPU registers.
+ Implemented for Linux and VxWorks, on Windows it is not currently supported.
+
+ <LI>Stack Trace - execution thread stack back-tracing.
+ Implemented for Linux and VxWorks, on Windows it is not currently supported.
+
+ <LI>Memory - program memory access.
+ Implemented for Linux and VxWorks, on Windows it is not currently supported.
+
+ <LI>Processes - provides access to the target OS's process
+ information, allows starting new and terminating existing processes,
+ and allows attaching and detaching processes for debugging.
+ Implemented for Linux and VxWorks, on Windows it is not currently supported.
+
+ <LI>Line Numbers - provides mapping between locations in the source files
+ and corresponding machine instruction addresses in the executable object.
+ Implemented for Linux only.
+
+ <LI>Sys Monitor - provides list of processes, process attributes and
+ CPU/memory utilization data. On Linux it is implemented using /proc file
+ system, on Windows and VxWorks it is not currently supported.
+
+ <LI>File System - provides access to remote file system.
+
+ <LI>Diagnostics - allows testing of communication channel and agent
+ functionality.
+</UL>
+
+<P>The agent code is designed to be easily extensible by adding new command
+handler implementations. The code separates machine dependences, common TCF
+logic and service implementations, which allows easy porting to a new OS or a
+target and reconfiguring of the agent for specific needs. The code is written in
+ANSI C. See <A href="TCF Linux Agent Prototype.html">TCF Linux Agent Prototype</A>
+for more details about the agent code.
+
+<H2><A name=Debugger></A>Prototype of a debugger based on Eclipse Debug Framework and TCF</H2>
+
+<P>The prototype code connects Eclipse Debug Framework and Target Communication
+Framework. It allows to launch Eclipse debug session by connecting to a target
+running TCF agent, and then perform basic debugging tasks, like resuming,
+suspending, single-stepping, setting/removing breakpoints, etc. Since current
+reference implementation of target agent does not support line number
+information access, source level debugging is not supported.
+<P>The prototype launch configuration autodetects TCF targets on a local network
+and allows a user to connect to a target by simply selecting it from a list
+without a need for any further configuration or setup. TCF launch configuration
+dialog also offers controls to run a built-in diagnostics on a selecting target,
+which perform stress testing of communication channel, agent and target itself:
+<P><IMG alt="TCF launch configuration dialog" src="TCF_Launch_Dialog.jpg">
+
+<P>The prototype makes use of flexible debug model element hierarchy support,
+which is available in Eclipse debug framework since Eclipse 3.2. The flexible
+hierarchy allows debugger views to be "data driven" or, in other words, dynamically
+adapt to a given targets capabilities and structure, without a need to modify
+debugger code to support a new target.
+
+<H2><A name=RSE></A>Prototype of a system monitor and remote file access based on Remote System Explorer and TCF</H2>
+
+<P>Remote System Explorer is an Eclipse based component that allows users to
+create connections to remote machines and explore their file systems, see list
+of processes and access some other resources, like remote shells. Remote System
+Explorer has been designed as a flexible, extensible framework to which Eclipse
+plug-in developers can contribute their own system definitions, actions, etc.
+<P>The prototype enables use of Processes and Files subsystems of Remote System
+Explorer over TCF. It also extends Processes subsystem to include CPU
+utilization data and some other process attributes in RSE views:
+<P><IMG alt="Remote System Explorer: Files subsystem over TCF" src="TCF_RSE_Files.jpg">
+<P><IMG alt="Remote System Explorer: Processes subsystem over TCF" src="TCF_RSE_Processes.jpg">
+
+</BODY>
+</HTML> \ No newline at end of file
diff --git a/docs/TCF Service - Breakpoints.html b/docs/TCF Service - Breakpoints.html
new file mode 100644
index 000000000..a49cdf3ab
--- /dev/null
+++ b/docs/TCF Service - Breakpoints.html
@@ -0,0 +1,408 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework Services - Breakpoints</title>
+</head>
+
+<body lang='EN-US'>
+
+<h1>Target Communication Framework Services - Breakpoints</h1>
+
+<ul>
+ <li><a href='#Cmds'>Commands</a>
+ <ul>
+ <li><a href='#CmdSet'>Set</a>
+ <li><a href='#CmdAdd'>Add</a>
+ <li><a href='#CmdChange'>Change</a>
+ <li><a href='#CmdEnable'>Enable</a>
+ <li><a href='#CmdDisable'>Disable</a>
+ <li><a href='#CmdRemove'>Remove</a>
+ <li><a href='#CmdGetIDs'>Get IDs</a>
+ <li><a href='#CmdGetProperties'>Get Properties</a>
+ <li><a href='#CmdGetStatus'>Get Status</a>
+ </ul>
+ <li><a href='#Events'>Events</a>
+ <li><a href='#API'>API</a>
+</ul>
+
+<h1>Breakpoints Service</h1>
+
+<p>Breakpoint is represented by unique identifier and set of properties.
+Breakpoint identifier (String id) needs to be unique across all hosts and targets</p>
+
+<p>Breakpoint properties is extendable collection of named attributes,
+which define breakpoint location and behavior. The service defines some common
+attribute names, host tools and target agents may support additional attributes.</p>
+
+<p>For each breakpoint a target agent maintains another extendable collection of named attributes:
+breakpoint status. While breakpoint properties are persistent and represent user input,
+breakpoint status reflects dynamic target agent reports about breakpoint current state,
+like actual addresses where breakpoint is planted or planting errors.</p>
+
+<p>Breakpoints are associated with communication channel and traget agent must remove them
+when the channel is closed. Target agent should maintain separate breakpoint table
+for each communication channel. It is allowed to set same breakpoint (same ID) through multiple
+channels, target agent should treat it as single breakpoint with maltiple references. Such breakpoint
+is removed when all refering channels are closed.</p>
+
+<p>The service uses standard format for error reports,
+see <a href='TCF Services.html#ErrorFormat'>Error Report Format</a>.</p>
+
+<h2><a name='Cmds'>Commands</a></h2>
+
+<h3><a name='CmdSet'>Set</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Breakpoints • set • <i>&lt;array of breakpoints&gt;</i> •
+
+<i>&lt;array of breakpoints&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;breakpoints list&gt;</i> ]
+
+<i>&lt;breakpoints list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;breakpoint data&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;breakpoint data&gt;</i> , <i>&lt;breakpoint data&gt;</i>
+
+<i>&lt;breakpoint data&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;object&gt;</i>
+</font></b></pre>
+
+<p> The command downloads breakpoints data to a target agent.
+The command is intended to be used only to initialize target breakpoints table
+when communication channel is open. After that, host should
+notify target about (incremental) changes in breakpoint data by sending
+Add, Change and Remove commands.<p>
+
+<p>Breakpoint data consists of a list of breakpoint properties. All properties are optional, except ID.
+Tools and targets can define additional properties. Predefined properties are:</p>
+<ul>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;</i></font></b></code>
+ - breakpoint ID
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Enabled" : <i>&lt;boolean&gt;</i></font></b></code>
+ - if true breakpoint is enabled
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Address" : <i>&lt;string&gt;</i></font></b></code>
+ - if preset, defines address of the breakpoint. Address is an expression that evaluates to breakpoint memory address.
+ Alternatively, breakpoint location can be given as File/Line/Column.
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Condition" : <i>&lt;string&gt;</i></font></b></code>
+ - a conditional expression that is evaluted every time execution hits the breakpoint. If condition is evaluated to false,
+ the breakpoint is skipped and execution is resumed without sending notifications to a host.
+ <li><code><b><font face="Courier New" size=2 color=#333399>"File" : <i>&lt;string&gt;</i></font></b></code>
+ - source code file name of breakpoint location.
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Line" : <i>&lt;int&gt;</i></font></b></code>
+ - source code line number of breakpoint location.
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Column" : <i>&lt;int&gt;</i></font></b></code>
+ - source code column number of breakpoint location.
+</ul>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdAdd'>Add</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Breakpoints • add • <i>&lt;breakpoint data&gt;</i> •
+</font></b></pre>
+
+<p>The command adds breakpoint to target agent breakpoint table. Host should send this command when user creates new breakpoint</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdChange'>Change</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Breakpoints • change • <i>&lt;breakpoint data&gt;</i> •
+</font></b></pre>
+
+<p>The command updates breakpoint data in target agent breakpoint table. Host should send this command when user modifies a breakpoint</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdEnable'>Enable</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Breakpoints • enable • <i>&lt;array of breakpoint IDs&gt;</i> •
+
+<i>&lt;array of breakpoint IDs&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;breakpoint IDs list&gt;</i> ]
+
+<i>&lt;breakpoint IDs list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;breakpoint ID&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;breakpoint ID&gt;</i> , <i>&lt;breakpoint ID&gt;</i>
+
+<i>&lt;breakpoint ID&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string&gt;</i>
+</font></b></pre>
+
+<p>The command enables a list of breakpoints - sets brekpoint property "Enabled" to true.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdDisable'>Disable</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Breakpoints • disable • <i>&lt;array of breakpoint IDs&gt;</i> •
+</font></b></pre>
+
+<p>The command disables a list of breakpoints - sets brekpoint property "Enabled" to false.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdRemove'>Remove</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Breakpoints • remove • <i>&lt;array of breakpoint IDs&gt;</i> •
+</font></b></pre>
+
+<p>The command removes a list of breakpoints. Host should send this command when user deletes breakpoints.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdGetIDs'>Get IDs</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Breakpoints • getIDs •
+</font></b></pre>
+
+<p>The command uploads IDs of breakpoints known to target agent. Only breakpoints what are set through
+this communication channel are reported. Target agent should maintain separate breakpoint table
+for each communication channel.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of breakpoint IDs&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdGetProperties'>Get Properties</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Breakpoints • getProperties • <i>&lt;string: breakpoint ID&gt;</i> •
+</font></b></pre>
+
+<p>The command uploads properties of given breakpoint from target agent breakpoint table.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;;breakpoint data&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdGetStatus'>Get Status</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Breakpoints • getStatus • <i>&lt;string: breakpoint ID&gt;</i> •
+</font></b></pre>
+
+<p>The command uploads status of given breakpoint from target agent.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;;breakpoint status&gt;</i> •
+
+<i>&lt;breakpoint status&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;object&gt;</i>
+</font></b></pre>
+
+<p>Breakpoint stat consists of a list of status properties. All properties are optional.
+Tools and targets can define additional properties. Predefined properties are:</p>
+
+<ul>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Planted" : <i>&lt;array of addresses&gt;</i></font></b></code>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Error" : <i>&lt;string&gt;</i></font></b></code>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"File" : <i>&lt;string&gt;</i></font></b></code>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Line" : <i>&lt;int&gt;</i></font></b></code>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Column" : <i>&lt;int&gt;</i></font></b></code>
+</ul>
+
+<h2><a name='Events'>Events</a></h2>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+E • Breakpoints • status • <i>&lt;string: breakpoint ID&gt;</i> • <i>&lt;breakpoint status&gt;</i> •
+</font></b></pre>
+
+<dl>
+ <dt><b>status</b>
+ <dd>is sent when breakpoint status changes.
+</dl>
+
+<h2><a name='API'>API</a></h2>
+
+<pre>
+<font color=#3F5FBF>/**
+ * Breakpoint is represented by unique identifier and set of properties.
+ * Breakpoint identifier (String id) needs to be unique across all hosts and targets.
+ *
+ * Breakpoint properties (Map<String,Object>) is extendable collection of named attributes,
+ * which define breakpoint location and behavior. This module defines some common
+ * attribute names (see PROP_*), host tools and target agents may support additional attributes.
+ *
+ * For each breakpoint a target agent maintains another extendable collection of named attributes:
+ * breakpoint status (Map<String,Object>, see STATUS_*). While breakpoint properties are
+ * persistent and represent user input, breakpoint status reflects dynamic target agent reports
+ * about breakpoint current state, like actual addresses where breakpoint is planted or planting errors.
+ */</font>
+<font color=#7F0055>public interface</font> IBreakpoints <font color=#7F0055>extends</font> IService {
+
+ <font color=#3F5FBF>/**
+ * Service name.
+ */</font>
+ <font color=#7F0055>static final</font> String NAME = "Breakpoints";
+
+ <font color=#3F5FBF>/**
+ * Breakpoint property names.
+ */</font>
+ <font color=#7F0055>static final</font> String
+ PROP_ID = "ID", // String
+ PROP_ENABLED = "Enabled", // Boolean
+ PROP_ADDRESS = "Address", // String
+ PROP_CONDITION = "Condition", // String
+ PROP_FILE = "File", // String
+ PROP_LINE = "Line", // Number
+ PROP_COLUMN = "Column"; // Number
+
+ <font color=#3F5FBF>/**
+ * Breakpoint status field names.
+ */</font>
+ <font color=#7F0055>static final</font> String
+ STATUS_PLANTED = "Planted", // Array of addresses
+ STATUS_ERROR = "Error", // String
+ STATUS_FILE = "File", // String
+ STATUS_LINE = "Line", // Number
+ STATUS_COLUMN = "Column"; // Number
+
+ <font color=#3F5FBF>/**
+ * Call back interface for breakpoint service commands.
+ */</font>
+ <font color=#7F0055>interface</font> DoneCommand {
+ <font color=#7F0055>void</font> doneCommand(IToken token, Exception error);
+ }
+
+ <font color=#3F5FBF>/**
+ * Download breakpoints data to target agent.
+ * The command is intended to be used only to initialize target breakpoints table
+ * when communication channel is open. After that, host should
+ * notify target about (incremental) changes in breakpoint data by sending
+ * add, change and remove commands.
+ *
+ * @param properties - array of breakpoints.
+ * @param done - command result call back object.
+ */</font>
+ IToken set(Map&lt;String,Object&gt;[] properties, DoneCommand done);
+
+ <font color=#3F5FBF>/**
+ * Called when breakpoint is added into breakpoints table.
+ * @param properties - breakpoint properties.
+ * @param done - command result call back object.
+ */</font>
+ IToken add(Map&lt;String,Object&gt; properties, DoneCommand done);
+
+ <font color=#3F5FBF>/**
+ * Called when breakpoint properties are changed.
+ * @param properties - breakpoint properties.
+ * @param done - command result call back object.
+ */</font>
+ IToken change(Map&lt;String,Object&gt; properties, DoneCommand done);
+
+ <font color=#3F5FBF>/**
+ * Tell target to change (only) PROP_ENABLED breakpoint property 'true'.
+ * @param ids - array of enabled breakpoint identifiers.
+ * @param done - command result call back object.
+ */</font>
+ IToken enable(String[] ids, DoneCommand done);
+
+ <font color=#3F5FBF>/**
+ * Tell target to change (only) PROP_ENABLED breakpoint property to 'false'.
+ * @param ids - array of disabled breakpoint identifiers.
+ * @param done - command result call back object.
+ */</font>
+ IToken disable(String[] ids, DoneCommand done);
+
+ <font color=#3F5FBF>/**
+ * Tell target to remove breakpoint.
+ * @param id - unique breakpoint identifier.
+ * @param done - command result call back object.
+ */</font>
+ IToken remove(String[] ids, DoneCommand done);
+
+ <font color=#3F5FBF>/**
+ * Upload IDs of breakpoints known to target agent.
+ * @param done - command result call back object.
+ */</font>
+ IToken getIDs(DoneGetIDs done);
+
+ <font color=#7F0055>interface</font> DoneGetIDs {
+ <font color=#7F0055>void</font> doneGetIDs(IToken token, Exception error, String[] ids);
+ }
+
+ <font color=#3F5FBF>/**
+ * Upload properties of given breakpoint from target agent breakpoint table.
+ * @param id - unique breakpoint identifier.
+ * @param done - command result call back object.
+ */</font>
+ IToken getProperties(String id, DoneGetProperties done);
+
+ <font color=#7F0055>interface</font> DoneGetProperties {
+ <font color=#7F0055>void</font> doneGetProperties(IToken token, Exception error, Map&lt;String,Object&gt; properties);
+ }
+
+ <font color=#3F5FBF>/**
+ * Upload status of given breakpoint from target agent.
+ * @param id - unique breakpoint identifier.
+ * @param done - command result call back object.
+ */</font>
+ IToken getStatus(String id, DoneGetStatus done);
+
+ <font color=#7F0055>interface</font> DoneGetStatus {
+ <font color=#7F0055>void</font> doneGetStatus(IToken token, Exception error, Map&lt;String,Object&gt; status);
+ }
+
+ <font color=#3F5FBF>/**
+ * Breakpoints service events listener.
+ */</font>
+ <font color=#7F0055>interface</font> BreakpointsListener {
+
+ <font color=#3F5FBF>/**
+ * Called when breakpoint status changes.
+ * @param id - unique breakpoint identifier.
+ * @param status - breakpoint status.
+ */</font>
+ <font color=#7F0055>void</font> breakpointStatusChanged(String id, Map&lt;String,Object&gt; status);
+ }
+
+ <font color=#7F0055>void</font> addListener(BreakpointsListener listener);
+
+ <font color=#7F0055>void</font> removeListener(BreakpointsListener listener);
+}
+</pre>
+
+</body>
+</html>
+
+
diff --git a/docs/TCF Service - File System.html b/docs/TCF Service - File System.html
new file mode 100644
index 000000000..711b31fe4
--- /dev/null
+++ b/docs/TCF Service - File System.html
@@ -0,0 +1,1212 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework Services - File System</title>
+</head>
+
+<body lang='EN-US'>
+
+<h1>Target Communication Framework Services - File System</h1>
+
+<ul>
+ <li><a href='#ReqSync'>Request Synchronization and Reordering</a>
+ <li><a href='#FileNames'>File Names</a>
+ <li><a href='#FileModes'>File Open Modes</a>
+ <li><a href='#FileAttributes'>File Attributes</a>
+ <li><a href='#ErrorCodes'>Error Codes</a>
+ <li><a href='#Cmds'>Commands</a>
+ <ul>
+ <li><a href='#CmdOpen'>open</a>
+ <li><a href='#CmdClose'>close</a>
+ <li><a href='#CmdRead'>read</a>
+ <li><a href='#CmdWrite'>write</a>
+ <li><a href='#CmdStat'>stat</a>
+ <li><a href='#CmdLStat'>lstat</a>
+ <li><a href='#CmdFStat'>fstat</a>
+ <li><a href='#CmdSetStat'>setstat</a>
+ <li><a href='#CmdFSetStat'>fsetstat</a>
+ <li><a href='#CmdOpenDir'>opendir</a>
+ <li><a href='#CmdReadDir'>readdir</a>
+ <li><a href='#CmdMkDir'>mkdir</a>
+ <li><a href='#CmdRmDir'>rmdir</a>
+ <li><a href='#CmdRoots'>roots</a>
+ <li><a href='#CmdRemove'>remove</a>
+ <li><a href='#CmdRealPath'>realpath</a>
+ <li><a href='#CmdRename'>rename</a>
+ <li><a href='#CmdReadLink'>readlink</a>
+ <li><a href='#CmdSymLink'>symlink</a>
+ <li><a href='#CmdSymLink'>copy</a>
+ <li><a href='#CmdSymLink'>user</a>
+ </ul>
+ <li><a href='#API'>API</a>
+</ul>
+
+<h1>File System Service</h1>
+
+<p>File System service provides file transfer (and more generally file
+system access) functionality in TCF. The service design is
+derived from SSH File Transfer Protocol specifications.</p>
+
+<h2><a name='ReqSync'>Request Synchronization and Reordering</a></h2>
+
+<p>The protocol and implementations MUST process requests relating to
+the same file in the order in which they are received. In other
+words, if an application submits multiple requests to the server, the
+results in the responses will be the same as if it had sent the
+requests one at a time and waited for the response in each case. For
+example, the server may process non-overlapping read/write requests
+to the same file in parallel, but overlapping reads and writes cannot
+be reordered or parallelized. However, there are no ordering
+restrictions on the server for processing requests from two different
+file transfer connections. The server may interleave and parallelize
+them at will.</p>
+
+<p>There are no restrictions on the order in which responses to
+outstanding requests are delivered to the client, except that the
+server must ensure fairness in the sense that processing of no
+request will be indefinitely delayed even if the client is sending
+other requests so that there are multiple outstanding requests all
+the time.</p>
+
+<p>There is no limit on the number of outstanding (non-acknowledged)
+requests that the client may send to the server. In practice this is
+limited by the buffering available on the data stream and the queuing
+performed by the server. If the server's queues are full, it should
+not read any more data from the stream, and flow control will prevent
+the client from sending more requests.</p>
+
+<h2><a name='FileNames'>File Names</a></h2>
+
+<p>This protocol represents file names as strings. File names are
+assumed to use the slash ('/') character as a directory separator.</p>
+
+<p>File names starting with a slash are "absolute", and are relative to
+the root of the file system. Names starting with any other character
+are relative to the user's default directory (home directory). Client
+can use 'user()' command to retrieve current user home directory.</p>
+
+<p>Servers SHOULD interpret a path name component ".." as referring to
+the parent directory, and "." as referring to the current directory.
+If the server implementation limits access to certain parts of the
+file system, it must be extra careful in parsing file names when
+enforcing such restrictions. There have been numerous reported
+security bugs where a ".." in a path name has allowed access outside
+the intended area.</p>
+
+<p>An empty path name is valid, and it refers to the user's default
+directory (usually the user's home directory).</p>
+
+<p>Otherwise, no syntax is defined for file names by this specification.
+Clients should not make any other assumptions; however, they can
+splice path name components returned by readdir() together
+using a slash ('/') as the separator, and that will work as expected.</p>
+
+<h2><a name='FileModes'>File Open Modes</a></h2>
+
+<p>File open mode is bitwise OR of mode flags:</p>
+
+<dl>
+ <dt><code>O_READ = 0x00000001</code>
+ <dd>Open the file for reading.
+
+ <dt><code>O_WRITE = 0x00000002</code>
+ <dd>Open the file for writing. If both this and O_READ are
+ specified, the file is opened for both reading and writing.
+
+ <dt><code>O_APPEND = 0x00000004</code>
+ <dd>Force all writes to append data at the end of the file.
+
+ <dt><code>O_CREAT = 0x00000008</code>
+ <dd>If this flag is specified, then a new file will be created if one
+ does not already exist (if O_TRUNC is specified, the new file will
+ be truncated to zero length if it previously exists).
+
+ <dt><code>O_TRUNC = 0x00000010</code>
+ <dd>Forces an existing file with the same name to be truncated to zero
+ length when creating a file by specifying O_CREAT.
+ O_CREAT MUST also be specified if this flag is used.
+
+ <dt><code>O_EXCL = 0x00000020</code>
+ <dd>Causes the request to fail if the named file already exists.
+ O_CREAT MUST also be specified if this flag is used.
+</dl>
+
+<h2><a name='FileAttributes'>File Attributes</a></h2>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;file attributes&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;object&gt;</i>
+</font></b></pre>
+
+<p>All attributes are optional.
+Tools and targets can define additional attributes. Predefined attributes are:</p>
+<ul>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Size" : <i>&lt;int&gt;</i></font></b></code>
+ - file size in bytes
+ <li><code><b><font face="Courier New" size=2 color=#333399>"UID" : <i>&lt;int&gt;</i></font></b></code>
+ - file owner user ID
+ <li><code><b><font face="Courier New" size=2 color=#333399>"GID" : <i>&lt;int&gt;</i></font></b></code>
+ - file owner group ID
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Permissions" : <i>&lt;int&gt;</i></font></b></code>
+ - file access permissions
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ATime" : <i>&lt;int&gt;</i></font></b></code>
+ - file last access time
+ <li><code><b><font face="Courier New" size=2 color=#333399>"MTime" : <i>&lt;int&gt;</i></font></b></code>
+ - file last modification time
+</ul>
+
+<h2><a name='ErrorCodes'>Error codes</a></h2>
+
+<p>The service uses standard format for error reports,
+see <a href='TCF Services.html#ErrorFormat'>Error Report Format</a>.</p>
+
+<p>Currently, the following values are defined for error code (other values may be
+defined by future versions of this protocol):</p>
+
+<dl>
+ <dt><code>STATUS_OK = 0</code>
+ <dd>Indicates successful completion of the operation.
+
+ <dt><code>STATUS_EOF = 1</code>
+ <dd>Indicates end-of-file condition; for 'read' it means that no
+ more data is available in the file, and for 'readdir' it
+ indicates that no more files are contained in the directory.
+
+ <dt><code>STATUS_NO_SUCH_FILE = 2</code>
+ <dd>This code is returned when a reference is made to a file which
+ should exist but doesn't.
+
+ <dt><code>STATUS_PERMISSION_DENIED = 3</code>
+ <dd>is returned when the authenticated user does not have sufficient
+ permissions to perform the operation.
+
+ <dt><code>STATUS_FAILURE = 4</code>
+ <dd>is a generic catch-all error message; it should be returned if an
+ error occurs for which there is no more specific error code.
+
+ <dt><code>STATUS_BAD_MESSAGE = 5</code>
+ <dd>may be returned if a badly formatted packet or protocol
+ incompatibility is detected.
+
+ <dt><code>STATUS_NO_CONNECTION = 6</code>
+ <dd>is a pseudo-error which indicates that the client has no
+ connection to the server (it can only be generated locally by the
+ client, and MUST NOT be returned by servers).
+
+ <dt><code>STATUS_CONNECTION_LOST = 7</code>
+ <dd>is a pseudo-error which indicates that the connection to the
+ server has been lost (it can only be generated locally by the
+ client, and MUST NOT be returned by servers).
+
+ <dt><code>STATUS_OP_UNSUPPORTED = 8</code>
+ <dd>indicates that an attempt was made to perform an operation which
+ is not supported for the server (it may be generated locally by
+ the client if e.g. the version number exchange indicates that a
+ required feature is not supported by the server, or it may be
+ returned by the server if the server does not implement an
+ operation).
+</dl>
+
+<h2><a name='Cmds'>Commands</a></h2>
+
+<h3><a name='CmdOpen'>open</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • open • <i>&lt;string: file name&gt;</i> • <i>&lt;int: mode&gt;</i> • <i>&lt;file attributes&gt;</i> •
+</font></b></pre>
+
+<p>The command opens or creates a file on a remote system. If mode contains O_CREAT then new file is created, otherwise exsting
+file is opened. If the file is created, file attributes is looked up for UID, GID and permissions. If no attribute value is found in
+the command parameters, a default value is used.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;file handle&gt;</i> •
+
+<i>&lt;file handle&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> <i>&lt;string&gt;</i>
+</font></b></pre>
+
+<p>On success, the replay contains open file handle. The handle is encoded as a string of characters. Client should never try
+to decode the string, but should use it as is to issue further file access commands. Client should close the file when it is
+not needed any more. Server should close all files that were left open after client connection was closed ot terminated.</p>
+
+<h3><a name='CmdClose'>close</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • close • <i>&lt;string: file handle&gt;</i> •
+</font></b></pre>
+
+<p>The command closes a handle, which was open by 'open' or 'opendir' commands.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdRead'>read</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • read • <i>&lt;string: file handle&gt;</i> • <i>&lt;int: offset&gt;</i> • <i>&lt;int: size&gt;</i> •
+</font></b></pre>
+
+<p>The command reads bytes from an open file.
+In response to this request, the server will read as many bytes as it
+can from the file (up to `len'), and return them in a byte array.
+If an error occurs or EOF is encountered, the server may return
+fewer bytes then requested. Replay argument 'error report'
+will be not null in case of error, and argument 'eof' will be
+true in case of EOF. For normal disk files, it is guaranteed
+that this will read the specified number of bytes, or up to end of file
+or error. For e.g. device files this may return fewer bytes than requested.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;string: data&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;boolean: eof&gt;</i> •
+</font></b></pre>
+
+<p><i>&lt;string: data&gt;</i> is Base64 encoded byte array of file data. Number of bytes is determined by the string length.
+'eof' is true when 'data' contains all available bytes up to the end of the file.</p>
+
+<h3><a name='CmdWrite'>write</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • write • <i>&lt;string: file handle&gt;</i> • <i>&lt;int: offset&gt;</i> • <i>&lt;string: data&gt;</i> •
+</font></b></pre>
+
+<p>The command writes bytes into an open file.
+The write will extend the file if writing beyond the end of the file.
+It is legal to write way beyond the end of the file; the semantics
+are to write zeroes from the end of the file to the specified offset
+and then the data. <i>&lt;string: data&gt;</i> is Base64 encoded array of data bytes.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdStat'>stat</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • stat • <i>&lt;string: file name&gt;</i> •
+</font></b></pre>
+
+<p>The command retrieves file attributes.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;file attributes&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdLStat'>lstat</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • lstat • <i>&lt;string: file name&gt;</i> •
+</font></b></pre>
+
+<p>The command retrieves file attributes.
+Unlike 'stat', 'lstat' does not follow symbolic links.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;file attributes&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdFStat'>fstat</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • fstat • <i>&lt;string: file handle&gt;</i> •
+</font></b></pre>
+
+<p>The command retrieves file attributes for an open file (identified by the file handle).</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;file attributes&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdSetStat'>setstat</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • setstat • <i>&lt;string: file name&gt;</i> • <i>&lt;file attributes&gt;</i> •
+</font></b></pre>
+
+<p>The command sets file attributes.
+This request is used for operations such as changing the ownership,
+permissions or access times, as well as for truncating a file.
+An error will be returned if the specified file system object does
+not exist or the user does not have sufficient rights to modify the
+specified attributes.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdFSetStat'>fsetstat</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • fsetstat • <i>&lt;string: file handle&gt;</i> • <i>&lt;file attributes&gt;</i> •
+</font></b></pre>
+
+<p>The command sets file attributes for an open file (identified by the file handle).
+This request is used for operations such as changing the ownership,
+permissions or access times, as well as for truncating a file.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdOpenDir'>opendir</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • opendir • <i>&lt;string: path&gt;</i> •
+</font></b></pre>
+
+<p>The command opens a directory for reading.
+Once the directory has been successfully opened, files (and
+directories) contained in it can be listed using 'readdir' requests.
+When the client no longer wishes to read more names from the
+directory, it SHOULD call 'close' for the handle. The handle
+should be closed regardless of whether a read errors have occurred or not.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;file handle&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdReadDir'>readdir</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • readdir • <i>&lt;string: file handle&gt;</i> •
+</font></b></pre>
+
+<p>The command returns one
+or more file names with full file attributes for each file. The
+client should call 'readdir' repeatedly until it has found the
+file it is looking for or until the server responds with a
+message indicating an error or end of file. The client should then
+close the handle using the 'close' request.
+Note: directory entries "." and ".." are NOT included into readdir()
+response.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;array of directory entries&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;boolean: eof&gt;</i> •
+
+<i>&lt;array of directory entries&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;directory entry list&gt;</i> ]
+
+<i>&lt;directory entry list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;directory entry&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&ltdirectory entry list&gt;</i> , <i>&lt;directory entry&gt;</i>
+
+<i>&lt;directory entry&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;object&gt;</i>
+</font></b></pre>
+
+<p>Directory entry attributes are:</p>
+<ul>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"FileName" : <i>&lt;string&gt;</i></font></b></code>
+ - a file name being returned, it will be a relative name within the directory,
+ without any path components.
+ <li><code><b><font face="Courier New" size=2 color=#333399>"LongName" : <i>&lt;string&gt;</i></font></b></code>
+ - a human readable, expanded format for the file name, similar to what
+ is returned by "ls -l" on Unix systems
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Attrs" : <i>&lt;file attributes&gt;</i></font></b></code>
+ - the attributes of the file as described in Section <a href='#FileAttributes'>File Attributes</a>.
+</ul>
+
+<h3><a name='CmdMkDir'>mkdir</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • mkdir • <i>&lt;string: directory path&gt;</i> • <i>&lt;file attributes&gt;</i> •
+</font></b></pre>
+
+<p>The command creates a directory on the server.
+<i>&lt;string: directory path&gt;</i> specifies the directory to be created.
+<i>&lt;file attributes&gt;</i> specifies new directory attributes.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdRmDir'>rmdir</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • rmdir • <i>&lt;string: directory path&gt;</i> •
+</font></b></pre>
+
+<p>The command removes a directory.
+An error will be returned if no directory
+with the specified path exists, or if the specified directory is not
+empty, or if the path specified a file system object other than a
+directory. <i>&lt;string: directory path&gt;</i> - specifies the directory to be removed.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdRoots'>roots</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • roots •
+</font></b></pre>
+
+<p>The command retrieves file system roots - top level file system objects.
+UNIX file system can report just one root with path "/". Other types of systems
+can have more the one root. For example, Windows server can return multiple roots:
+one per disc (e.g. "/C:/", "/D:/", etc.). Note: even Windows implementation of
+the service must use forward slash as directory separator, and must start
+absolute path with "/". Server should implement proper translation of
+protocol file names to OS native names and back.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of directory entries&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdRemove'>remove</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • remove • <i>&lt;string: path&gt;</i> •
+</font></b></pre>
+
+<p>The command removes a file or symbolic link.
+This request cannot be used to remove directories.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdRealPath'>realpath</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • realpath • <i>&lt;string: path&gt;</i> •
+</font></b></pre>
+
+<p>The command canonicalizes any given path name to an absolute path.
+This is useful for converting path names containing ".." components or
+relative pathnames without a leading slash into absolute paths.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;string: path&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdRename'>rename</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • rename • <i>&lt;string: old path&gt;</i> • <i>&lt;string: new path&gt;</i> •
+</font></b></pre>
+
+<p>The command renames a file.
+It is an error if there already exists a file
+with the name specified by <i>&lt;string: new path&gt;</i>. The server may also fail rename
+requests in other situations, for example if <i>&lt;string: old path&gt;</i> and <i>&lt;string: new path&gt;</i>
+point to different file systems on the server.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdReadLink'>readlink</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • readlink • <i>&lt;string: link path&gt;</i> •
+</font></b></pre>
+
+<p>The command reads the target of a symbolic link.
+<i>&lt;string: link path&gt;</i> specifies the path name of the symbolic link to be read.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;string: path&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdSymLink'>symlink</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • symlink • <i>&lt;string: link path&gt;</i> • <i>&lt;string: target path&gt;</i> •
+</font></b></pre>
+
+<p>The command creates a symbolic link on the server.
+<i>&lt;string: link path&gt;</i> specifies the path name of the symbolic link to be created.
+<i>&lt;string: target path&gt;</i> specifies the target of the symbolic link.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdCopy'>copy</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • copy • <i>&lt;string: source path&gt;</i> • <i>&lt;string: destination path&gt;</i> •
+ <i>&lt;boolean: copy permissions&gt;</i> • <i>&lt;boolean: copy ownership&gt;</i> •
+</font></b></pre>
+
+<p>The command copies a file on remote system.
+<i>&lt;string: source path&gt;</i> specifies the path name of the file to be copied.
+<i>&lt;string: destination path&gt;</i> specifies destination file name.
+If <i>&lt;boolean: copy permissions&gt;</i> is true then copy source file permissions.
+If <i>&lt;boolean: copy ownership&gt;</i> is true then copy source file UID and GID.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdUser'>user</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • FileSystem • user •
+</font></b></pre>
+
+<p>The command retrieves information about user account, which is used by server
+to access file system on behalf of the client.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;int: real UID&gt;</i> • <i>&lt;int: effective UID&gt;</i> •
+ <i>&lt;int: real GID&gt;</i> • <i>&lt;int: effective GID&gt;</i> • <i>&lt;string: home directory&gt;</i> •
+</font></b></pre>
+
+<h2><a name='API'>API</a></h2>
+
+<pre>
+<font color=#3F5FBF>/**
+ * File System service provides file transfer (and more generally file
+ * system access) functionality in TCF. The service design is
+ * derived from SSH File Transfer Protocol specifications.
+ */</font>
+<font color=#7F0055>public interface</font> IFileSystem <font color=#7F0055>extends</font> IService {
+
+ <font color=#3F5FBF>/**
+ * Service name.
+ */</font>
+ <font color=#7F0055>static final</font> String NAME = "FileSystem";
+
+ <font color=#3F5FBF>/**
+ * Flags to be used with open() method.
+ */</font>
+ <font color=#7F0055>static final int</font>
+
+ <font color=#3F5FBF>/**
+ * Open the file for reading.
+ */</font>
+ O_READ = 0x00000001,
+
+ <font color=#3F5FBF>/**
+ * Open the file for writing. If both this and O_READ are
+ * specified, the file is opened for both reading and writing.
+ */</font>
+ O_WRITE = 0x00000002,
+
+ <font color=#3F5FBF>/**
+ * Force all writes to append data at the end of the file.
+ */</font>
+ O_APPEND = 0x00000004,
+
+ <font color=#3F5FBF>/**
+ * If this flag is specified, then a new file will be created if one
+ * does not already exist (if O_TRUNC is specified, the new file will
+ * be truncated to zero length if it previously exists).
+ */</font>
+ O_CREAT = 0x00000008,
+
+ <font color=#3F5FBF>/**
+ * Forces an existing file with the same name to be truncated to zero
+ * length when creating a file by specifying O_CREAT.
+ * O_CREAT MUST also be specified if this flag is used.
+ */</font>
+ O_TRUNC = 0x00000010,
+
+ <font color=#3F5FBF>/**
+ * Causes the request to fail if the named file already exists.
+ * O_CREAT MUST also be specified if this flag is used.
+ */</font>
+ O_EXCL = 0x00000020;
+
+ <font color=#3F5FBF>/**
+ * Flags to be used together with FileAttrs.
+ * The flags specify which of the fields are present. Those fields
+ * for which the corresponding flag is not set are not present (not
+ * included in the message).
+ */</font>
+ <font color=#7F0055>static final int</font>
+ ATTR_SIZE = 0x00000001,
+ ATTR_UIDGID = 0x00000002,
+ ATTR_PERMISSIONS = 0x00000004,
+ ATTR_ACMODTIME = 0x00000008;
+
+ <font color=#3F5FBF>/**
+ * FileAttrs is used both when returning file attributes from
+ * the server and when sending file attributes to the server. When
+ * sending it to the server, the flags field specifies which attributes
+ * are included, and the server will use default values for the
+ * remaining attributes (or will not modify the values of remaining
+ * attributes). When receiving attributes from the server, the flags
+ * specify which attributes are included in the returned data. The
+ * server normally returns all attributes it knows about.
+ */</font>
+ <font color=#7F0055>final static class</font> FileAttrs {
+
+ <font color=#3F5FBF>/**
+ * The `flags' specify which of the fields are present.
+ */</font>
+ <font color=#7F0055>public final int</font> flags;
+
+ <font color=#3F5FBF>/**
+ * The `size' field specifies the size of the file in bytes.
+ */</font>
+ <font color=#7F0055>public final long</font> size;
+
+ <font color=#3F5FBF>/**
+ * The `uid' and `gid' fields contain numeric Unix-like user and group
+ * identifiers, respectively.
+ */</font>
+ <font color=#7F0055>public final int</font> uid;
+ <font color=#7F0055>public final int</font> gid;
+
+ <font color=#3F5FBF>/**
+ * The `permissions' field contains a bit mask of file permissions as
+ * defined by posix [1].
+ */</font>
+ <font color=#7F0055>public final int</font> permissions;
+
+ <font color=#3F5FBF>/**
+ * The `atime' and `mtime' contain the access and modification times of
+ * the files, respectively. They are represented as milliseconds from
+ * midnight Jan 1, 1970 in UTC.
+ */</font>
+ <font color=#7F0055>public final long</font> atime;
+ <font color=#7F0055>public final long</font> mtime;
+
+ <font color=#3F5FBF>/**
+ * Additional (non-standard) attributes.
+ */</font>
+ <font color=#7F0055>public final</font> Map&lt;String,Object&gt; attributes;
+
+ <font color=#7F0055>public</font> FileAttrs(<font color=#7F0055>int</font> flags, <font color=#7F0055>long</font> size, <font color=#7F0055>int</font> uid, <font color=#7F0055>int</font> gid,
+ <font color=#7F0055>int</font> permissions, <font color=#7F0055>long</font> atime, <font color=#7F0055>long</font> mtime, Map&lt;String,Object&gt; attributes);
+
+ <font color=#3F5FBF>/**
+ * Determines if the file system object is a file on the remote file system.
+ *
+ * @return true if and only if the object on the remote system can be considered to have "contents" that
+ * have the potential to be read and written as a byte stream.
+ */</font>
+ <font color=#7F0055>public boolean</font> isFile();
+
+ <font color=#3F5FBF>/**
+ * Determines if the file system object is a directory on the remote file system.
+ *
+ * @return true if and only if the object on the remote system is a directory.
+ * That is, it contains entries that can be interpreted as other files.
+ */</font>
+ <font color=#7F0055>public boolean</font> isDirectory();
+ }
+
+ <font color=#3F5FBF>/**
+ * The following flags are defined for the 'permissions' field:
+ */</font>
+ <font color=#7F0055>static final int</font>
+ S_IFMT = 0170000, // bitmask for the file type bitfields
+ S_IFSOCK = 0140000, // socket
+ S_IFLNK = 0120000, // symbolic link
+ S_IFREG = 0100000, // regular file
+ S_IFBLK = 0060000, // block device
+ S_IFDIR = 0040000, // directory
+ S_IFCHR = 0020000, // character device
+ S_IFIFO = 0010000, // fifo
+ S_ISUID = 0004000, // set UID bit
+ S_ISGID = 0002000, // set GID bit (see below)
+ S_ISVTX = 0001000, // sticky bit (see below)
+ S_IRWXU = 00700, // mask for file owner permissions
+ S_IRUSR = 00400, // owner has read permission
+ S_IWUSR = 00200, // owner has write permission
+ S_IXUSR = 00100, // owner has execute permission
+ S_IRWXG = 00070, // mask for group permissions
+ S_IRGRP = 00040, // group has read permission
+ S_IWGRP = 00020, // group has write permission
+ S_IXGRP = 00010, // group has execute permission
+ S_IRWXO = 00007, // mask for permissions for others (not in group)
+ S_IROTH = 00004, // others have read permission
+ S_IWOTH = 00002, // others have write permisson
+ S_IXOTH = 00001; // others have execute permission
+
+ <font color=#7F0055>final static class</font> DirEntry {
+ <font color=#3F5FBF>/**
+ * `filename' is a file name being returned. It is a relative name within
+ * the directory, without any path components;
+ */</font>
+ <font color=#7F0055>public final</font> String filename;
+
+ <font color=#3F5FBF>/**
+ * `longname' is an expanded format for the file name, similar to what
+ * is returned by "ls -l" on Unix systems.
+ * The format of the `longname' field is unspecified by this protocol.
+ * It MUST be suitable for use in the output of a directory listing
+ * command (in fact, the recommended operation for a directory listing
+ * command is to simply display this data). However, clients SHOULD NOT
+ * attempt to parse the longname field for file attributes; they SHOULD
+ * use the attrs field instead.
+ */</font>
+ <font color=#7F0055>public final</font> String longname;
+
+ <font color=#3F5FBF>/**
+ * `attrs' is the attributes of the file.
+ */</font>
+ <font color=#7F0055>public final</font> FileAttrs attrs;
+
+ <font color=#7F0055>public</font> DirEntry(String filename, String longname, FileAttrs attrs);
+ }
+
+ <font color=#3F5FBF>/**
+ * Opaque representation of open file handle.
+ * Note: open file handle can be used only with service instance that
+ * created the handle.
+ */</font>
+ <font color=#7F0055>interface</font> IFileHandle {
+ IFileSystem getService();
+ }
+
+ <font color=#3F5FBF>/**
+ * Status codes.
+ */</font>
+ <font color=#7F0055>static final int</font>
+
+ <font color=#3F5FBF>/**
+ * Indicates successful completion of the operation.
+ */</font>
+ STATUS_OK = 0,
+
+ <font color=#3F5FBF>/**
+ * Indicates end-of-file condition; for read() it means that no
+ * more data is available in the file, and for readdir() it
+ * indicates that no more files are contained in the directory.
+ */</font>
+ STATUS_EOF = 1,
+
+ <font color=#3F5FBF>/**
+ * This code is returned when a reference is made to a file which
+ * should exist but doesn't.
+ */</font>
+ STATUS_NO_SUCH_FILE = 2,
+
+ <font color=#3F5FBF>/**
+ * is returned when the authenticated user does not have sufficient
+ * permissions to perform the operation.
+ */</font>
+ STATUS_PERMISSION_DENIED = 3,
+
+ <font color=#3F5FBF>/**
+ * is a generic catch-all error message; it should be returned if an
+ * error occurs for which there is no more specific error code.
+ *
+ */</font>
+ STATUS_FAILURE = 4,
+
+ <font color=#3F5FBF>/**
+ * may be returned if a badly formatted packet or protocol
+ * incompatibility is detected.
+ */</font>
+ STATUS_BAD_MESSAGE = 5,
+
+ <font color=#3F5FBF>/**
+ * is a pseudo-error which indicates that the client has no
+ * connection to the server (it can only be generated locally by the
+ * client, and MUST NOT be returned by servers).
+ */</font>
+ STATUS_NO_CONNECTION = 6,
+
+ <font color=#3F5FBF>/**
+ * is a pseudo-error which indicates that the connection to the
+ * server has been lost (it can only be generated locally by the
+ * client, and MUST NOT be returned by servers).
+ */</font>
+ STATUS_CONNECTION_LOST = 7,
+
+ <font color=#3F5FBF>/**
+ * indicates that an attempt was made to perform an operation which
+ * is not supported for the server (it may be generated locally by
+ * the client if e.g. the version number exchange indicates that a
+ * required feature is not supported by the server, or it may be
+ * returned by the server if the server does not implement an
+ * operation).
+ */</font>
+ STATUS_OP_UNSUPPORTED = 8;
+
+ <font color=#7F0055>abstract static class</font> FileSystemException extends IOException {
+
+ <font color=#7F0055>protected</font> FileSystemException(String message);
+
+ <font color=#7F0055>protected</font> FileSystemException(Exception x)
+
+ <font color=#7F0055>public abstract int</font> getStatus();
+ }
+
+ <font color=#3F5FBF>/**
+ * Open or create a file on a remote system.
+ *
+ * @param file_name specifies the file name. See 'File Names' for more information.
+ * @param flags is a bit mask of O_* flags.
+ * @param attrs specifies the initial attributes for the file.
+ * Default values will be used for those attributes that are not specified.
+ * @param done is call back object.
+ * @return pending command handle.
+ */</font>
+ IToken open(String file_name, <font color=#7F0055>int</font> flags, FileAttrs attrs, DoneOpen done);
+
+ <font color=#7F0055>interface</font> DoneOpen {
+ <font color=#7F0055>void</font> doneOpen(IToken token, FileSystemException error, IFileHandle handle);
+ }
+
+ <font color=#3F5FBF>/**
+ * Close a file on a remote system.
+ *
+ * @param handle is a handle previously returned in the response to
+ * open() or opendir().
+ * @param done is call back object.
+ * @return pending command handle.
+ */</font>
+ IToken close(IFileHandle handle, DoneClose done);
+
+ <font color=#7F0055>interface</font> DoneClose {
+ <font color=#7F0055>void</font> doneClose(IToken token, FileSystemException error);
+ }
+
+ <font color=#3F5FBF>/**
+ * Read bytes from an open file.
+ * In response to this request, the server will read as many bytes as it
+ * can from the file (up to `len'), and return them in a byte array.
+ * If an error occurs or EOF is encountered, the server may return
+ * fewer bytes then requested. Call back method doneRead() argument 'error'
+ * will be not null in case of error, and argument 'eof' will be
+ * true in case of EOF. For normal disk files, it is guaranteed
+ * that this will read the specified number of bytes, or up to end of file
+ * or error. For e.g. device files this may return fewer bytes than requested.
+ *
+ * @param handle is an open file handle returned by open().
+ * @param offset is the offset (in bytes) relative
+ * to the beginning of the file from where to start reading.
+ * @param len is the maximum number of bytes to read.
+ * @param done is call back object.
+ * @return pending command handle.
+ */</font>
+ IToken read(IFileHandle handle, long offset, <font color=#7F0055>int</font> len, DoneRead done);
+
+ <font color=#7F0055>interface</font> DoneRead {
+ <font color=#7F0055>void</font> doneRead(IToken token, FileSystemException error, byte[] data, boolean eof);
+ }
+
+ <font color=#3F5FBF>/**
+ * Write bytes into an open file.
+ * The write will extend the file if writing beyond the end of the file.
+ * It is legal to write way beyond the end of the file; the semantics
+ * are to write zeroes from the end of the file to the specified offset
+ * and then the data.
+ *
+ * @param handle is an open file handle returned by open().
+ * @param offset is the offset (in bytes) relative
+ * to the beginning of the file from where to start writing.
+ * @param data is byte array that contains data for writing.
+ * @param data_pos if offset in 'data' of first byte to write.
+ * @param data_size is the number of bytes to write.
+ * @param done is call back object.
+ * @return pending command handle.
+ */</font>
+ IToken write(IFileHandle handle, long offset,
+ byte[] data, <font color=#7F0055>int</font> data_pos, <font color=#7F0055>int</font> data_size, DoneWrite done);
+
+ <font color=#7F0055>interface</font> DoneWrite {
+ <font color=#7F0055>void</font> doneWrite(IToken token, FileSystemException error);
+ }
+
+ <font color=#3F5FBF>/**
+ * Retrieve file attributes.
+ *
+ * @param path - specifies the file system object for which
+ * status is to be returned.
+ * @param done is call back object.
+ * @return pending command handle.
+ */</font>
+ IToken stat(String path, DoneStat done);
+
+ <font color=#3F5FBF>/**
+ * Retrieve file attributes.
+ * Unlike 'stat()', 'lstat()' does not follow symbolic links.
+ *
+ * @param path - specifies the file system object for which
+ * status is to be returned.
+ * @param done is call back object.
+ * @return pending command handle.
+ */</font>
+ IToken lstat(String path, DoneStat done);
+
+ <font color=#3F5FBF>/**
+ * Retrieve file attributes for an open file (identified by the file handle).
+ *
+ * @param handle is a file handle returned by 'open()'.
+ * @param done is call back object.
+ * @return pending command handle.
+ */</font>
+ IToken fstat(IFileHandle handle, DoneStat done);
+
+ <font color=#7F0055>interface</font> DoneStat {
+ <font color=#7F0055>void</font> doneStat(IToken token, FileSystemException error, FileAttrs attrs);
+ }
+
+ <font color=#3F5FBF>/**
+ * Set file attributes.
+ * This request is used for operations such as changing the ownership,
+ * permissions or access times, as well as for truncating a file.
+ * An error will be returned if the specified file system object does
+ * not exist or the user does not have sufficient rights to modify the
+ * specified attributes.
+ *
+ * @param path specifies the file system object (e.g. file or directory)
+ * whose attributes are to be modified.
+ * @param attrs specifies the modifications to be made to file attributes.
+ * @param done is call back object.
+ * @return pending command handle.
+ */</font>
+ IToken setstat(String path, FileAttrs attrs, DoneSetStat done);
+
+ <font color=#3F5FBF>/**
+ * Set file attributes for an open file (identified by the file handle).
+ * This request is used for operations such as changing the ownership,
+ * permissions or access times, as well as for truncating a file.
+ *
+ * @param handle is a file handle returned by 'open()'.
+ * @param attrs specifies the modifications to be made to file attributes.
+ * @param done is call back object.
+ * @return pending command handle.
+ */</font>
+ IToken fsetstat(IFileHandle handle, FileAttrs attrs, DoneSetStat done);
+
+ <font color=#7F0055>interface</font> DoneSetStat {
+ <font color=#7F0055>void</font> doneSetStat(IToken token, FileSystemException error);
+ }
+
+ <font color=#3F5FBF>/**
+ * The opendir() command opens a directory for reading.
+ * Once the directory has been successfully opened, files (and
+ * directories) contained in it can be listed using readdir() requests.
+ * When the client no longer wishes to read more names from the
+ * directory, it SHOULD call close() for the handle. The handle
+ * should be closed regardless of whether an error has occurred or not.
+
+ * @param path - name of the directory to be listed (without any trailing slash).
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken opendir(String path, DoneOpen done);
+
+ <font color=#3F5FBF>/**
+ * The files in a directory can be listed using the opendir() and
+ * readdir() requests. Each readdir() request returns one
+ * or more file names with full file attributes for each file. The
+ * client should call readdir() repeatedly until it has found the
+ * file it is looking for or until the server responds with a
+ * message indicating an error or end of file. The client should then
+ * close the handle using the close() request.
+ * Note: directory entries "." and ".." are NOT included into readdir()
+ * response.
+ * @param handle - file handle created by opendir()
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken readdir(IFileHandle handle, DoneReadDir done);
+
+ <font color=#7F0055>interface</font> DoneReadDir {
+ <font color=#7F0055>void</font> doneReadDir(IToken token, FileSystemException error, DirEntry[] entries, boolean eof);
+ }
+
+ <font color=#3F5FBF>/**
+ * Create a directory on the server.
+ *
+ * @param path - specifies the directory to be created.
+ * @param attrs - new directory attributes.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken mkdir(String path, FileAttrs attrs, DoneMkDir done);
+
+ <font color=#7F0055>interface</font> DoneMkDir {
+ <font color=#7F0055>void</font> doneMkDir(IToken token, FileSystemException error);
+ }
+
+ <font color=#3F5FBF>/**
+ * Remove a directory.
+ * An error will be returned if no directory
+ * with the specified path exists, or if the specified directory is not
+ * empty, or if the path specified a file system object other than a
+ * directory.
+ *
+ * @param path - specifies the directory to be removed.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken rmdir(String path, DoneRemove done);
+
+ <font color=#7F0055>interface</font> DoneRemove {
+ <font color=#7F0055>void</font> doneRemove(IToken token, FileSystemException error);
+ }
+
+ <font color=#3F5FBF>/**
+ * Retrieve file system roots - top level file system objects.
+ * UNIX file system can report just one root with path "/". Other types of systems
+ * can have more the one root. For example, Windows server can return multiple roots:
+ * one per disc (e.g. "/C:/", "/D:/", etc.). Note: even Windows implementation of
+ * the service must use forward slash as directory separator, and must start
+ * absolute path with "/". Server should implement proper translation of
+ * protocol file names to OS native names and back.
+ *
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken roots(DoneRoots done);
+
+ <font color=#7F0055>interface</font> DoneRoots {
+ <font color=#7F0055>void</font> doneRoots(IToken token, FileSystemException error, DirEntry[] entries);
+ }
+
+ <font color=#3F5FBF>/**
+ * Remove a file or symbolic link.
+ * This request cannot be used to remove directories.
+ *
+ * @param file_name is the name of the file to be removed.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken remove(String file_name, DoneRemove done);
+
+ <font color=#3F5FBF>/**
+ * Canonicalize any given path name to an absolute path.
+ * This is useful for converting path names containing ".." components or
+ * relative pathnames without a leading slash into absolute paths.
+ *
+ * @param path specifies the path name to be canonicalized.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken realpath(String path, DoneRealPath done);
+
+ <font color=#7F0055>interface</font> DoneRealPath {
+ <font color=#7F0055>void</font> doneRealPath(IToken token, FileSystemException error, String path);
+ }
+
+ <font color=#3F5FBF>/**
+ * Rename a file.
+ * It is an error if there already exists a file
+ * with the name specified by 'new_path'. The server may also fail rename
+ * requests in other situations, for example if `old_path' and `new_path'
+ * point to different file systems on the server.
+ *
+ * @param old_path is the name of an existing file or directory.
+ * @param new_path is the new name for the file or directory.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken rename(String old_path, String new_path, DoneRename done);
+
+ <font color=#7F0055>interface</font> DoneRename {
+ <font color=#7F0055>void</font> doneRename(IToken token, FileSystemException error);
+ }
+
+ <font color=#3F5FBF>/**
+ * Read the target of a symbolic link.
+ *
+ * @param path specifies the path name of the symbolic link to be read.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken readlink(String path, DoneReadLink done);
+
+ <font color=#7F0055>interface</font> DoneReadLink {
+ <font color=#7F0055>void</font> doneReadLink(IToken token, FileSystemException error, String path);
+ }
+
+ <font color=#3F5FBF>/**
+ * Create a symbolic link on the server.
+ *
+ * @param link_path specifies the path name of the symbolic link to be created.
+ * @param target_path specifies the target of the symbolic link.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken symlink(String link_path, String target_path, DoneSymLink done);
+
+ <font color=#7F0055>interface</font> DoneSymLink {
+ <font color=#7F0055>void</font> doneSymLink(IToken token, FileSystemException error);
+ }
+
+ <font color=#3F5FBF>/**
+ * Copy a file on remote system.
+ *
+ * @param src_path specifies the path name of the file to be copied.
+ * @param dst_path specifies destination file name.
+ * @param copy_permissions - if true then copy source file permissions.
+ * @param copy_ownership - if true then copy source file UID and GID.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken copy(String src_path, String dst_path,
+ boolean copy_permissions, boolean copy_ownership, DoneCopy done);
+
+ <font color=#7F0055>interface</font> DoneCopy {
+ <font color=#7F0055>void</font> doneCopy(IToken token, FileSystemException error);
+ }
+
+ <font color=#3F5FBF>/**
+ * Retrieve information about user account, which is used by server
+ * to access file system on behalf of the client.
+ *
+ * @param done - result call back object.
+ * @return pending command handle.
+ */</font>
+ IToken user(DoneUser done);
+
+ <font color=#7F0055>interface</font> DoneUser {
+ <font color=#7F0055>void</font> doneUser(IToken token, FileSystemException error,
+ <font color=#7F0055>int</font> real_uid, <font color=#7F0055>int</font> effective_uid, <font color=#7F0055>int</font> real_gid, <font color=#7F0055>int</font> effective_gid,
+ String home);
+ }
+}
+</pre>
+
+</body>
+</html>
+
+
diff --git a/docs/TCF Service - Memory.html b/docs/TCF Service - Memory.html
new file mode 100644
index 000000000..afca975ea
--- /dev/null
+++ b/docs/TCF Service - Memory.html
@@ -0,0 +1,456 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework Services - Memory</title>
+</head>
+
+<body lang='EN-US'>
+
+<h1>Target Communication Framework Services - Memory</h1>
+
+<ul>
+ <li><a href='#Cmds'>Commands</a>
+ <ul>
+ <li><a href='#CmdGetContext'>Get Context</a>
+ <li><a href='#CmdGetChildren'>Get Children</a>
+ <li><a href='#CmdSetMemory'>Set Memory</a>
+ <li><a href='#CmdGetMemory'>Get Memory</a>
+ <li><a href='#CmdFillMemory'>Fill Memory</a>
+ </ul>
+ <li><a href='#Events'>Events</a>
+ <li><a href='#API'>API</a>
+</ul>
+
+<h1>Memory Service</h1>
+
+<p>The service provides basic operations to read/write memory on a target. Command
+and event parameters are encoded as zero terminated <a href='TCF Specification.html#JSON'>JSON</a> strings.</p>
+
+<p>The service uses standard format for error reports,
+see <a href='TCF Services.html#ErrorFormat'>Error Report Format</a>.</p>
+
+<p>A single memory access can succeed for some addresses and fail for others. In such
+situation result message can contain partially valid data. Array of error addresses,
+in addition to error report, describes data validity on per byte basis:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;array of error addresses&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ <i>&lt;error address list&gt;</i> ]
+
+<i>&lt;error address list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;error address&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;error address list&gt;</i> , <i>&lt;error address&gt;</i>
+
+<i>&lt;error address&gt;</i>
+ <font face=Wingdings>Ø</font> { "addr" : <i>&lt;int: range starting address&gt;</i> , "size" : <i>&lt;int: range length in bytes&gt;</i> , "stat" : <i>&lt;int: status code&gt;</i> , "msg" : <i>&lt;error description&gt;</i> }
+</font></b></pre>
+
+<p>If there is no entry in error addresses array for a data byte, then status of such
+byte is defined by main error report.</p>
+
+<p>Status code is bitwise or of status flags:</p>
+<dl>
+ <dt><code><b>BYTE_VALID        = 0x00</b></code> <dd>no error for this byte
+    <dt><code><b>BYTE_UNKNOWN      = 0x01</b></code> <dd>status is unknown
+ <dt><code><b>BYTE_INVALID      = 0x02</b></code> <dd>byte value in invalid, error message describes the problem
+ <dt><code><b>BYTE_CANNOT_READ  = 0x04</b></code> <dd>cannot read the byte
+ <dt><code><b>BYTE_CANNOT_WRITE = 0x08</b></code> <dd>cannot write the byte
+</dl>
+
+<h2><a name='Cmds'>Commands</a></h2>
+
+<h3><a name='CmdGetContext'>Get Context</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Memory • getContext • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command retrieves context info for given context ID. A context corresponds to an
+execution thread, process, address space, etc. Exact
+meaning of a context depends on the target. Target agent should define contexts hierarchy
+that is:</p>
+
+<ul type='disc'>
+ <li>Sufficient to resolve possible ambiguity of a memory address;
+
+ <li>Adequately reflects target memory management strategy;
+
+ <li>Intuitive to a user.
+</ul>
+
+<p>For traditional OS, like UNIX, memory access context can be one of:</p>
+
+<ul type='disc'>
+ <li>Kernel address space;
+
+ <li>A process.
+</ul>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;context data&gt;</i> •
+
+<i>&lt;context data&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> <i>&lt;object&gt;</i>
+</font></b></pre>
+
+<p>Context data object should, at least, contain member
+<b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;.</i></font></b>
+Context data is expected to be cached by clients.
+Service sends contextChanged event to notify changes in context data.</p>
+
+<p>Predefined memory context properties are:</p>
+<ul>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;</i></font></b></code>
+ - ID of the context, same as getContext command argument.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ParentID" : <i>&lt;string&gt;</i></font></b></code>
+ - ID of a parent context.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"BigEndian" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if memory is big-endian.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"AddressSize" : <i>&lt;int&gt;</i></font></b></code>
+ - size of memory address in bytes.
+</ul>
+
+<h3><a name='CmdGetChildren'>Get Children</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Memory • getChildren • <i>&lt;string: parent context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command requests a list of contexts available for memory access commands.</p>
+
+<p>Parent context ID can be null – to retrieve top level of the hierarchy, can be one
+of context IDs retrieved by previous getChildren commands, or it can be obtained from another service.
+Contexts hierarchy can be simple plain list or it can form a tree. It is up to target agent developers to
+choose layout that is most descriptive for a given target.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of context IDs&gt;</i> •<i></i>
+
+<i>&lt;array of context IDs&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;context ID list&gt;</i> ]
+
+<i>&lt;context ID list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string: context ID&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;context ID list&gt;</i> , <i>&lt;string: context ID&gt;</i>
+
+</font></b></pre>
+
+<h3><a name='CmdSetMemory'>Set Memory</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • &lt;token&gt; • Memory • set •
+ <i>&lt;string: context ID&gt;</i> • <i>&lt;int: address&gt;</i> • <i>&lt;int: word size&gt;</i> •
+ <i>&lt;int: byte count&gt;</i> • <i>&lt;int: mode&gt;</i> • <i>&lt;string: BASE64 encoded byte array&gt;</i> •
+</font></b></pre>
+
+<p>Writes data bytes at given address in memory, "word size" bytes at a time. Address
+should be aligned by "word size". Context ID must be one returned by getContexts.
+Mode is logical OR of any combination of:</p>
+
+<ul type='disc'>
+ <li>0x1 – continue on error (like bus error or page fault)
+
+ <li>0x2 – verify data after writing by reading back and compare
+</ul>
+
+<p>Result message:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of error addresses&gt;</i> •
+</font></b></pre>
+
+<p>Error report provides integer error code and a short, human readable explanation
+of error. Error addresses, when present, let client know which bytes of data failed
+to be written into memory.</p>
+
+<h3><a name='CmdGetMemory'>Get Memory</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • &lt;token&gt; • Memory • get •
+ <i>&lt;string: context ID&gt;</i> • <i>&lt;int: address&gt;</i> • <i>&lt;int: word size&gt;</i> •
+ <i>&lt;int: byte count&gt;</i> • <i>&lt;int: mode&gt;</i> •
+</font></b></pre>
+
+<p>Reads data bytes at given address in memory, "word size" bytes at a time. Address
+should be aligned by "word size". Context ID must be one returned by getContexts.
+Mode is logical OR of any combination of:</p>
+
+<ul type='disc'>
+ <li>0x1 – continue on error (like bus error or page fault)
+
+ <li>0x2 – verify data after reading by re-reading and compare
+</ul>
+
+<p>Result message:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;string: BASE64 encoded byte array&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of error addresses&gt;</i> •
+</font></b></pre>
+
+<p>Error report provides integer error code and a short, human readable explanation
+of error. Error addresses, when present, let client know which bytes of data failed
+to be retrieved from memory.</p>
+
+<h3><a name='CmdFillMemory'>Fill Memory</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • &lt;token&gt; • Memory • fill •
+ <i>&lt;string: context ID&gt;</i> • <i>&lt;int: address&gt;</i> • <i>&lt;int: word size&gt;</i> •
+ &lt;int: byte count&gt; • <i>&lt;int: mode&gt;</i> • <i>&lt;array: array of pattern bytes&gt;</i> •
+</font></b></pre>
+
+<p>Writes pattern bytes at given address in memory, "word size" bytes at a time. Address
+should be aligned by "word size". If "byte count" is bigger then pattern size, then
+pattern is repeated necessary number of times. Context ID must be one returned by
+getContexts. Mode is logical OR of any combination of:</p>
+
+<ul type='disc'>
+ <li>0x1 – continue on error (like bus error or page fault)
+
+ <li>0x2 – verify data after writing by reading back and compare
+</ul>
+
+<p>Result message:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of error addresses&gt;</i> •
+</font></b></pre>
+
+<p>Error report provides integer error code and a short, human readable explanation
+of error. Error addresses, when present, let client know which bytes of data failed
+to be written into memory.</p>
+
+<h2><a name='Events'>Events</a></h2>
+
+<p>Memory service broadcasts notification events when memory contexts are added, removed
+or changed, and when memory content is altered by "set" or "fill" commands.</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+E • Memory • contextAdded • <i>&lt;array of context data&gt;</i> •
+E • Memory • contextChanged • <i>&lt;array of context data&gt;</i> •
+E • Memory • contextRemoved • <i>&lt;array of context IDs&gt;</i> •
+E • Memory • memoryChanged • <i>&lt;string: context ID&gt;</i> • <i>&lt;array of address ranges&gt;</i> •
+
+<i>&lt;array of context data&gt;</i> <font face="Times New Roman" size=3>- see Get Contexts command.</font>
+
+<i>&lt;array of context IDs&gt;</i>
+ <font face=Wingdings>Ø</font> [ <i>&lt;context ID list&gt;</i> ]
+
+<i>&lt;context ID list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string: context ID&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;context ID list&gt;</i> , <i>&lt;string: context ID&gt;</i>
+
+<i>&lt;array of address ranges&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ <i>&lt;address ranges list&gt;</i> ]
+
+<i>&lt;address ranges list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;address range&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;address ranges list&gt;</i> , <i>&lt;address range&gt;</i>
+
+<i>&lt;address range&gt;</i>
+ <font face=Wingdings>Ø</font> { "addr" : <i>&lt;int: range starting address&gt;</i> , "size" : <i>&lt;int: range length in bytes&gt;</i> }
+</font></b></pre>
+
+<h2><a name='API'>API</a></h2>
+
+<pre>
+<font color=#3F5FBF>/**
+ * IMemory service provides basic operations to read/write memory on a target.
+ */</font>
+<font color=#7F0055>public interface</font> Memory <font color=#7F0055>extends</font> Service {
+
+ <font color=#7F0055>static final</font> String NAME = "Memory";
+
+ <font color=#3F5FBF>/**
+ * Retrieve context info for given context ID.
+ *
+ * <font color=#7F9FBF>@param</font> id – context ID.
+ * <font color=#7F9FBF>@param</font> done - callback interface called when operation is completed.
+     */</font>
+ IToken getContext(String id, DoneGetContext done);
+
+ <font color=#3F5FBF>/**
+ * Client callback interface for getContext().
+     */</font>
+ <font color=#7F0055>interface</font> DoneGetContext {
+ <font color=#3F5FBF>/**
+ * Called when contexts data retrieval is done.
+ * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+ * <font color=#7F9FBF>@param</font> context – context data.
+ */</font>
+ <font color=#7F0055>void</font> doneGetContext(IToken token, Exception error, MemoryContext context);
+ }
+
+ <font color=#3F5FBF>/**
+ * Retrieve contexts available for memory commands.
+ * A context corresponds to an execution thread, process, address space, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ *
+ * <font color=#7F9FBF>@param</font> parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getContexts commands.
+ * <font color=#7F9FBF>@param</font> done - callback interface called when operation is completed.
+ */</font>
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ <font color=#3F5FBF>/**
+ * Client callback interface for getChildren().
+ */</font>
+ <font color=#7F0055>interface</font> DoneGetChildren {
+ <font color=#3F5FBF>/**
+ * Called when contexts data retrieval is done.
+         * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+         * <font color=#7F9FBF>@param</font> contexts – array of available context IDs.
+ */</font>
+ <font color=#7F0055>void</font> doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+    <font color=#3F5FBF>/**
+     * Memory access mode:
+     * Carry on when some of the memory cannot be accessed and
+     * return MemoryError at the end if any of the bytes
+     * were not processed correctly.
+     */</font>
+    <font color=#7F0055>final static int</font> MODE_CONTINUEONERROR = 0x1;
+
+    <font color=#3F5FBF>/**
+     * Memory access mode:
+     * Verify result of memory operations (by reading and comparing).
+     */</font>
+    <font color=#7F0055>final static int</font> MODE_VERIFY = 0x2;
+
+    <font color=#7F0055>interface</font> MemoryContext {
+
+        <font color=#3F5FBF>/**
+         * Retrieve context ID.
+         * Same as getProperties().get("id")
+         */</font>
+        String getID();
+
+        <font color=#3F5FBF>/**
+         * Return true if the context has children.
+         * Same as getProperties().get("has_children")
+         * Children can be retrieved by getContexts call.
+         */</font>
+        <font color=#7F0055>boolean</font> hasChildren();
+
+        <font color=#3F5FBF>/**
+         * Retrieve context properties.
+         */</font>
+        Map&lt;String,Object&gt; getProperties();
+
+        <font color=#3F5FBF>/**
+         * Set target memory.
+         * If 'word_size' is 0 it means client does not care about word size.
+         */</font>
+        <font color=#7F0055>void</font> set(long addr, <font color=#7F0055>int</font> word_size, byte[] buf,
+                         <font color=#7F0055>int</font> offs, <font color=#7F0055>int</font> size, <font color=#7F0055>int</font> mode, DoneMemory done);
+
+        <font color=#3F5FBF>/**
+         * Read target memory.
+         */</font>
+        <font color=#7F0055>void</font> get(long addr, <font color=#7F0055>int</font> word_size, byte[] buf,
+                         <font color=#7F0055>int</font> offs, <font color=#7F0055>int</font> size, <font color=#7F0055>int</font> mode, DoneMemory done);
+
+        <font color=#3F5FBF>/**
+         * Fill target memory with given pattern.
+         * 'size' is number of bytes to fill.
+         */</font>
+        <font color=#7F0055>void</font> fill(long addr, <font color=#7F0055>int</font> word_size, byte[] value,
+                          <font color=#7F0055>int</font> size, <font color=#7F0055>int</font> mode, DoneMemory done);
+   
+        <font color=#3F5FBF>/**
+         * Client callback interface for set(), get() and fill().
+         */</font>
+        <font color=#7F0055>interface</font> DoneMemory {
+            <font color=#7F0055>void</font> doneMemory(MemoryError error);
+        }
+    }
+
+    <font color=#7F0055>class</font> MemoryError <font color=#7F0055>extends</font> Exception {
+    }
+
+    <font color=#3F5FBF>/**
+     * ErrorOffset interface can be implemented by MemoryError object,
+     * which is returned by get, set and fill commands.
+     *
+  * get/set/fill () returns this exception when reading failed
+   * for some but not all bytes, and MODE_CONTINUEONERROR
+     * has been set in mode. (For example, when only part of the request
+     * translates to valid memory addresses.)
+     * Exception.getMessage can be used for generalized message of the
+     * possible reasons of partial memory operation.
+     */</font>
+    <font color=#7F0055>interface</font> ErrorOffset {
+       
+        // Error may have per byte information
+        <font color=#7F0055>final static int</font>
+            BYTE_VALID        = 0x00,
+            BYTE_UNKNOWN      = 0x01, // e.g. out of range
+            BYTE_INVALID      = 0x02,
+            BYTE_CANNOT_READ  = 0x04,
+            BYTE_CANNOT_WRITE = 0x08;
+
+        <font color=#7F0055>int</font> getStatus(<font color=#7F0055>int</font> offset);
+
+        <font color=#3F5FBF>/**
+         * Returns the detail message string about the
+         * byte associated with specified location.
+         * <font color=#7F9FBF>@return</font>  the detail error message string.
+         */</font>
+        String getMessage(<font color=#7F0055>int</font> offset);
+       
+    }
+
+    <font color=#7F0055>void</font> addListener(MemoryListener listener);
+
+    <font color=#7F0055>interface</font> MemoryListener {
+
+        <font color=#3F5FBF>/**
+         * Called when a new memory access context(s) is created.
+         */</font>
+        <font color=#7F0055>void</font> contextAdded(Context[] contexts);
+
+        <font color=#3F5FBF>/**
+         * Called when a new memory access context(s) properties changed.
+         */</font>
+        <font color=#7F0055>void</font> contextChanged(Context[] contexts);
+
+        <font color=#3F5FBF>/**
+         * Called when memory access context(s) is removed.
+         */</font>
+        <font color=#7F0055>void</font> contextRemoved(String[] context_ids);
+
+        <font color=#3F5FBF>/**
+         * Called when target memory content was changed and clients
+         * need to update themselves. Clients, at least, should invalidate
+         * corresponding cached memory data.
+         * Not every change is notified - it is not possible,
+         * only those, which are not caused by normal execution of the debuggee.
+         * ‘addr’ and ‘size’ can be null if unknown.
+         */</font>
+        <font color=#7F0055>void</font> memoryChanged(String context_id,
+               long[] addr, long[] size);
+    }
+}
+</pre>
+
+</body>
+</html>
diff --git a/docs/TCF Service - Processes.html b/docs/TCF Service - Processes.html
new file mode 100644
index 000000000..dbb3f0309
--- /dev/null
+++ b/docs/TCF Service - Processes.html
@@ -0,0 +1,381 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework Services - Processes</title>
+</head>
+
+<body lang='EN-US'>
+
+<h1>Target Communication Framework Services - Processes</h1>
+
+<ul>
+ <li><a href='#Cmds'>Commands</a>
+ <ul>
+ <li><a href='#CmdGetContext'>Get Context</a>
+ <li><a href='#CmdGetChildren'>Get Children</a>
+ <li><a href='#CmdAttach'>Attach</a>
+ <li><a href='#CmdDetach'>Detach</a>
+ <li><a href='#CmdTerminate'>Terminate</a>
+ <li><a href='#CmdSignal'>Signal</a>
+ <li><a href='#CmdStart'>Start</a>
+ </ul>
+ <li><a href='#Events'>Events</a>
+ <li><a href='#API'>API</a>
+</ul>
+
+<h1>Processes Service</h1>
+
+<p>Processes service provides access to the target OS's process
+information, allows to start and terminate a process, and allows
+to attach and detach a process for debugging. Debug services,
+like Memory and Run Control, require a process to be attached
+before they can access it.</p>
+
+<p>Command and event parameters are encoded
+as zero terminated <a href='TCF Specification.html#JSON'>JSON</a> strings.</p>
+
+<p>The service uses standard format for error reports,
+see <a href='TCF Services.html#ErrorFormat'>Error Report Format</a>.</p>
+
+<h2><a name='Cmds'>Commands</a></h2>
+
+<h3><a name='CmdGetContext'>Get Context</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Processes • getContext • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command retrieves context info for given context ID.
+A context corresponds to an execution thread, process, address space, etc.
+Context IDs are valid across TCF services, so it is allowed to issue 'Processes.getContext'
+command with a context that was obtained, for example, from Memory service.
+However, 'Processes.getContext' is supposed to return only process specific data.
+If the ID is not a process ID, 'Processes.getContext' may not return any
+useful information.
+</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;context data&gt;</i> •
+
+<i>&lt;context data&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> <i>&lt;object&gt;</i>
+</font></b></pre>
+
+<p>Context data object should, at least, contain member
+<b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;.</i></font></b>
+</p>
+
+<p>Predefined process context properties are:</p>
+<ul>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;</i></font></b></code>
+ - ID of the context, same as getContext command argument.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ParentID" : <i>&lt;string&gt;</i></font></b></code>
+ - parent context ID.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Name" : <i>&lt;string&gt;</i></font></b></code>
+ - process name. Client UI can show this name to a user.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Attached" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if the context is attached to debugger.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CanTerminate" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if the service can terminate the process.
+</ul>
+
+<h3><a name='CmdGetChildren'>Get Children</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Processes • getChildren • <i>&lt;string: parent context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command requests a list of contexts available for process control commands.</p>
+
+<p>Parent context ID can be null – to retrieve top level of the hierarchy, can be one
+of context IDs retrieved by previous getChildren commands, or it can be obtained from another service.
+Contexts hierarchy can be simple plain list or it can form a tree. It is up to target agent developers to
+choose layout that is most descriptive for a given target.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of context IDs&gt;</i> •
+
+<i>&lt;array of context IDs&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;context ID list&gt;</i> ]
+
+<i>&lt;context ID list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string: context ID&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;context ID list&gt;</i> , <i>&lt;string: context ID&gt;</i>
+</font></b></pre>
+
+<h3><a name='CmdAttach'>Attach</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Processes • attach • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command attaches debugger to a process.
+Services like Run Control, Memory, Breakpoints work only with attached processes.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdDetach'>Detach</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Processes • detach • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command detaches debugger from a process.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdTerminate'>Terminate</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Processes • terminate • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command terminates a process.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdSignal'>Signal</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Processes • signal • <i>&lt;string: context ID&gt;</i> • <i>&lt;int: signal&gt;</i> •
+</font></b></pre>
+
+<p>The command sends a signal to a process.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdStart'>Start</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Processes • start • <i>&lt;string: working directory&gt;</i> • <i>&lt;string: program image file&gt;</i> •
+ <i>&lt;string array: command line&gt;</i> • <i>&lt;string array: environment variables&gt;</i> • <i>&lt;boolean: attach&gt;</i> •
+
+<i>&lt;string array&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;string list&gt;</i> ]
+
+<i>&lt;string list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string list&gt;</i> , <i>&lt;string&gt;</i>
+</font></b></pre>
+
+<p>The command starts a new process on remote machine.
+<i>&lt;string: working directory&gt;</i> - initial value of working directory for the process.
+<i>&lt;string: program image file&gt;</i> - image file to start process with.
+<i>&lt;string array: command line&gt;</i> - command line arguments for the process.
+<i>&lt;string array: environment variables&gt;</i> - list of environment variables for the process,
+they will be added to default process environment.
+<i>&lt;boolean: attach&gt;</i> - if true debugger should be attached to the process.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;context data&gt;</i> •
+</font></b></pre>
+
+<p>On success the command returns context data for created process. Context data has same format as Get Context result.</p>
+
+<h2><a name='Events'>Events</a></h2>
+
+<p>No events are currently defined for Processes service.</p>
+
+<h2><a name='API'>API</a></h2>
+
+<pre>
+<font color=#7F0055>public interface</font> IProcesses <font color=#7F0055>extends</font> IService {
+
+ <font color=#7F0055>static final</font> String NAME = "Processes";
+
+ <font color=#3F5FBF>/**
+ * Retrieve context info for given context ID.
+ * A context corresponds to an execution thread, process, address space, etc.
+ * Context IDs are valid across TCF services, so it is allowed to issue
+ * 'IProcesses.getContext' command with a context that was obtained,
+ * for example, from Memory service.
+ * However, 'Processes.getContext' is supposed to return only process specific data,
+ * If the ID is not a process ID, 'IProcesses.getContext' may not return any
+ * useful information
+ *
+ * <font color=#7F9FBF><font color=#7F9FBF>@param</font></font> id – context ID.
+ * <font color=#7F9FBF><font color=#7F9FBF>@param</font></font> done - call back interface called when operation is completed.
+ */</font>
+ IToken getContext(String id, DoneGetContext done);
+
+ <font color=#3F5FBF>/**
+ * Client call back interface for getContext().
+ */</font>
+ <font color=#7F0055>interface</font> DoneGetContext {
+ <font color=#3F5FBF>/**
+ * Called when contexts data retrieval is done.
+ * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+ * <font color=#7F9FBF>@param</font> context – context data.
+ */</font>
+ <font color=#7F0055>void</font> doneGetContext(IToken token, Exception error, ProcessContext context);
+ }
+
+ <font color=#3F5FBF>/**
+ * Retrieve children of given context.
+ *
+ * <font color=#7F9FBF>@param</font> parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getContext or getChildren commands.
+ * <font color=#7F9FBF>@param</font> done - call back interface called when operation is completed.
+ */</font>
+ IToken getChildren(String parent_context_id, <font color=#7F0055>boolean</font> attached_only, DoneGetChildren done);
+
+ <font color=#3F5FBF>/**
+ * Client call back interface for getChildren().
+ */</font>
+ <font color=#7F0055>interface</font> DoneGetChildren {
+ <font color=#3F5FBF>/**
+ * Called when contexts data retrieval is done.
+ * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+ * <font color=#7F9FBF>@param</font> context_ids – array of available context IDs.
+ */</font>
+ <font color=#7F0055>void</font> doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ <font color=#3F5FBF>/**
+ * Context property names.
+ */</font>
+ <font color=#7F0055>static final</font> String
+ <font color=#3F5FBF>/** The TCF context ID */</font>
+ PROP_ID = "ID",
+
+ <font color=#3F5FBF>/** The TCF parent context ID */</font>
+ PROP_PARENTID = "ParentID",
+
+ <font color=#3F5FBF>/** Is the context attached */</font>
+ PROP_ATTACHED = "Attached",
+
+ <font color=#3F5FBF>/** Can terminate the context */</font>
+ PROP_CAN_TERMINATE = "CanTerminate",
+
+ <font color=#3F5FBF>/** Process name. Client UI can show this name to a user */</font>
+ PROP_NAME = "Name";
+
+ <font color=#7F0055>interface</font> ProcessContext {
+
+ <font color=#3F5FBF>/**
+ * Get context ID.
+ * Same as getProperties().get(“ID”)
+ */</font>
+ String getID();
+
+ <font color=#3F5FBF>/**
+ * Get parent context ID.
+ * Same as getProperties().get(“ParentID”)
+ */</font>
+ String getParentID();
+
+ <font color=#3F5FBF>/**
+ * Get process name.
+ * Client UI can show this name to a user.
+ * Same as getProperties().get(“Name”)
+ */</font>
+ String getName();
+
+ <font color=#3F5FBF>/**
+ * Utility method to read context property PROP_ATTACHED.
+ * Services like IRunControl, IMemory, IBreakpoints work only with attached processes.
+ * <font color=#7F9FBF><font color=#7F9FBF>@return</font></font> value of PROP_ATTACHED.
+ */</font>
+ <font color=#7F0055>boolean</font> isAttached();
+
+ <font color=#3F5FBF>/**
+ * Utility method to read context property PROP_CAN_TERMINATE.
+ * <font color=#7F9FBF><font color=#7F9FBF>@return</font></font> value of PROP_CAN_TERMINATE.
+ */</font>
+ <font color=#7F0055>boolean</font> canTerminate();
+
+ <font color=#3F5FBF>/**
+ * Get all available context properties.
+ * <font color=#7F9FBF>@return</font> Map 'property name' -> 'property value'
+ */</font>
+ Map&lt;String, Object&gt; getProperties();
+
+ <font color=#3F5FBF>/**
+ * Attach debugger to a process.
+ * Services like IRunControl, IMemory, IBreakpoints work only with attached processes.
+ * <font color=#7F9FBF>@param</font> done - call back interface called when operation is completed.
+ * <font color=#7F9FBF>@return</font> pending command handle, can be used to cancel the command.
+ */</font>
+ IToken attach(DoneCommand done);
+
+ <font color=#3F5FBF>/**
+ * Detach debugger from a process.
+ * Process execution will continue without debugger supervision.
+ * <font color=#7F9FBF>@param</font> done - call back interface called when operation is completed.
+ * <font color=#7F9FBF>@return</font> pending command handle, can be used to cancel the command.
+ */</font>
+ IToken detach(DoneCommand done);
+
+ <font color=#3F5FBF>/**
+ * Terminate a process.
+ * <font color=#7F9FBF>@param</font> done - call back interface called when operation is completed.
+ * <font color=#7F9FBF>@return</font> pending command handle, can be used to cancel the command.
+ */</font>
+ IToken terminate(DoneCommand done);
+
+ <font color=#3F5FBF>/**
+ * Send a signal to a process.
+ * <font color=#7F9FBF>@param</font> signal - signal ID.
+ * <font color=#7F9FBF>@param</font> done - call back interface called when operation is completed.
+ * <font color=#7F9FBF>@return</font> pending command handle, can be used to cancel the command.
+ */</font>
+ IToken signal(<font color=#7F0055>int</font> signal, DoneCommand done);
+ }
+
+ <font color=#7F0055>interface</font> DoneCommand {
+ <font color=#7F0055>void</font> doneCommand(IToken token, Exception error);
+ }
+
+ <font color=#3F5FBF>/**
+ * Start a new process on remote machine.
+ * <font color=#7F9FBF>@param</font> directory - initial value of working directory for the process.
+ * <font color=#7F9FBF>@param</font> file - process image file.
+ * <font color=#7F9FBF>@param</font> command_line - command line arguments for the process.
+ * <font color=#7F9FBF>@param</font> environment - list of environment variables for the process.
+ * <font color=#7F9FBF>@param</font> attach - if true debugger should be attached to the process.
+ * <font color=#7F9FBF>@param</font> done - call back interface called when operation is completed.
+ * <font color=#7F9FBF>@return</font> pending command handle, can be used to cancel the command.
+ */</font>
+ IToken start(String directory, String file,
+ String[] command_line, String[] environment, <font color=#7F0055>boolean</font> attach, DoneStart done);
+
+ <font color=#7F0055>interface</font> DoneStart {
+ <font color=#7F0055>void</font> doneStart(IToken token, Exception error, ProcessContext process);
+ }
+}
+</pre>
+
+</body>
+</html>
diff --git a/docs/TCF Service - Registers.html b/docs/TCF Service - Registers.html
new file mode 100644
index 000000000..ef346af69
--- /dev/null
+++ b/docs/TCF Service - Registers.html
@@ -0,0 +1,506 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework Services - Registers</title>
+</head>
+
+<body lang='EN-US'>
+
+<h1>Target Communication Framework Services - Registers</h1>
+
+<ul>
+ <li><a href='#Cmds'>Commands</a>
+ <ul>
+ <li><a href='#CmdGetContext'>Get Context</a>
+ <li><a href='#CmdGetChildren'>Get Children</a>
+ <li><a href='#CmdSetRegister'>Set Register</a>
+ <li><a href='#CmdGetRegister'>Get Register</a>
+ </ul>
+ <li><a href='#Events'>Events</a>
+ <li><a href='#API'>API</a>
+</ul>
+
+<h1>Registers Service</h1>
+
+<p>The service provides basic operations to read/write CPU and hardware registers. Command
+and event parameters are encoded as zero terminated <a href='TCF Specification.html#JSON'>JSON</a> strings.</p>
+
+<p>The service uses standard format for error reports,
+see <a href='TCF Services.html#ErrorFormat'>Error Report Format</a>.</p>
+
+<h2><a name='Cmds'>Commands</a></h2>
+
+<h3><a name='CmdGetContext'>Get Context</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Registers • getContext • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command retrieves context info for given context ID. A context corresponds to an
+register, register group, register bit field, etc. Exact meaning of a context depends on the target.
+Target agent should define contexts hierarchy that is:</p>
+
+<ul type='disc'>
+ <li>Adequately reflects target hardware registers layout;
+ <li>Consistent with the lingo/terminology of the processor manuals;
+ <li>Intuitive to a user.
+</ul>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;context data&gt;</i> •
+
+<i>&lt;context data&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> <i>&lt;object&gt;</i>
+</font></b></pre>
+
+<p>Context data object should, at least, contain member
+<b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;.</i></font></b>
+Context data is expected to be cached by clients.
+Service sends contextChanged event to notify changes in context data.</p>
+
+<p>Predefined register context properties are:</p>
+<ul>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;</i></font></b></code>
+ - ID of the context, same as getContext command argument.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ParentID" : <i>&lt;string&gt;</i></font></b></code>
+ - ID of a parent context.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ProcessID" : <i>&lt;string&gt;</i></font></b></code>
+ - process ID.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Name" : <i>&lt;string&gt;</i></font></b></code>
+ - context name.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Description" : <i>&lt;string&gt;</i></font></b></code>
+ - context description.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Formats" : <i>&lt;array of string&gt;</i></font></b></code>
+ - value formats available for register get/set commands.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Readable" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if context value can be read.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ReadOnce" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if reading the context (register) destroys its current value - it can be read only once.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Writeable" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if context value can be written.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"WriteOnce" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if register value can not be overwritten - every write counts.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"SideEffects" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if writing the context can change values of other registers.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Volatile" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if the register value can change even when target is stopped.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Float" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if the register value is a floating-point value.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"BigEndian" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if big endian, which means decreasing numeric significance with increasing bit number.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"LeftToRight" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if the lowest numbered bit (i.e. bit #0 or bit #1, depending on "FirstBit" value) should be shown to user as the left-most bit.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"FirstBit" : <i>&lt;int&gt;</i></font></b></code>
+ - 0 or 1. If the context has bit field children, bit positions of the fields can be zero-based or 1-based.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Bits" : <i>&lt;array of int&gt;</i></font></b></code>
+ - if context is a bit field, contains the field bit numbers in the parent context.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Values" : <i>&lt;array of named values&gt;</i></font></b></code>
+ - predefined names (mnemonics) for some of context values.
+
+</ul>
+
+<h3><a name='CmdGetChildren'>Get Children</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Registers • getChildren • <i>&lt;string: parent context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command requests a list of contexts available for registers access commands.</p>
+
+<p>Parent context ID is usually a thread ID retrieved through Run Control Service or one
+of context IDs retrieved by previous getChildren commands.
+Contexts hierarchy can be simple plain list of registers, or it can form a tree of register groups, registers and bit fields.
+It is up to target agent developers to choose layout that is most descriptive for a given target.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of context IDs&gt;</i> •<i></i>
+
+<i>&lt;array of context IDs&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;context ID list&gt;</i> ]
+
+<i>&lt;context ID list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string: context ID&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;context ID list&gt;</i> , <i>&lt;string: context ID&gt;</i>
+
+</font></b></pre>
+
+<h3><a name='CmdSetRegister'>Set Register</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • &lt;token&gt; • Registers • set • <i>&lt;string: context ID&gt;</i> • <i>&lt;string: value format&gt;</i> • <i>&lt;string: value&gt;</i> •
+</font></b></pre>
+
+<p>Writes value into given register context. Context ID must be one returned by getContexts.
+Value format must be one that is supported by the register context.
+Client can get list of supported formats from context attributes.</p>
+
+<p>Result message:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<p>Error report provides integer error code and a short, human readable explanation
+of error.</p>
+
+<h3><a name='CmdGetRegister'>Get Register</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • &lt;token&gt; • Registers • get • <i>&lt;string: context ID&gt;</i> • <i>&lt;string: value format&gt;</i> •
+</font></b></pre>
+
+<p>Reads register value from given register context. Context ID must be one returned by getContexts.
+Value format must be one that is supported by the register context.
+Client can get list of supported formats from context attributes.</p>
+
+<p>Result message:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;string: value&gt;</i> •
+</font></b></pre>
+
+<p>Error report provides integer error code and a short, human readable explanation
+of error. Value is formatted according to requested format.</p>
+
+<h2><a name='Events'>Events</a></h2>
+
+<p>Registers service broadcasts notification events when registers contexts are changed, and when
+a register content is altered by "set" commands.</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+E • Registers • contextChanged •
+E • Registers • registerChanged • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<h2><a name='API'>API</a></h2>
+
+<pre>
+<font color=#3F5FBF>/**
+ * IRegisters service provides access to target CPU register values and properties.
+ */</font>
+<font color=#7F0055>public interface</font> IRegisters <font color=#7F0055>extends</font> IService {
+
+ <font color=#7F0055>static final</font> String NAME = "Registers";
+
+ <font color=#3F5FBF>/**
+ * Context property names.
+ */</font>
+ <font color=#7F0055>static final</font> String
+ PROP_ID = "ID",
+ PROP_PARENT_ID = "ParentID",
+ PROP_PROCESS_ID = "ProcessID",
+ PROP_NAME = "Name",
+ PROP_DESCRIPTION = "Description",
+ PROP_FORMATS = "Formats",
+ PROP_READBLE = "Readable",
+ PROP_READ_ONCE = "ReadOnce",
+ PROP_WRITEABLE = "Writeable",
+ PROP_WRITE_ONCE = "WriteOnce",
+ PROP_SIDE_EFFECTS = "SideEffects",
+ PROP_VOLATILE = "Volatile",
+ PROP_FLOAT = "Float",
+ PROP_BIG_ENDIAN = "BigEndian",
+ PROP_LEFT_TO_RIGHT = "LeftToRight",
+ PROP_FIST_BIT = "FirstBit",
+ PROP_BITS = "Bits",
+ PROP_VALUES = "Values";
+
+ <font color=#3F5FBF>/**
+ * Standard known formats for register data.
+ */</font>
+ <font color=#7F0055>static final</font> String
+ FORMAT_BINARY = "Binary",
+ FORMAT_OCTAL = "Octal",
+ FORMAT_DECIMAL = "Decimal",
+ FORMAT_HEX = "Hex",
+ FORMAT_NATURAL = "Natural";
+
+ <font color=#3F5FBF>/**
+ * Retrieve context info for given context ID.
+ *
+ * <font color=#7F9FBF>@param</font> id – context ID.
+ * <font color=#7F9FBF>@param</font> done - call back interface called when operation is completed.
+ */</font>
+ IToken getContext(String id, DoneGetContext done);
+
+ <font color=#3F5FBF>/**
+ * Client call back interface for getContext().
+ */</font>
+ <font color=#7F0055>interface</font> DoneGetContext {
+ <font color=#3F5FBF>/**
+ * Called when contexts data retrieval is done.
+ * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+ * <font color=#7F9FBF>@param</font> context – context data.
+ */</font>
+ <font color=#7F0055>void</font> doneGetContext(IToken token, Exception error, RegistersContext context);
+ }
+
+ <font color=#3F5FBF>/**
+ * Retrieve contexts available for registers commands.
+ * A context corresponds to an execution thread, stack frame, registers group, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ *
+ * <font color=#7F9FBF>@param</font> parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getChildren commands.
+ * <font color=#7F9FBF>@param</font> done - call back interface called when operation is completed.
+ */</font>
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ <font color=#3F5FBF>/**
+ * Client call back interface for getChildren().
+ */</font>
+ <font color=#7F0055>interface</font> DoneGetChildren {
+ <font color=#3F5FBF>/**
+ * Called when contexts data retrieval is done.
+ * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+ * <font color=#7F9FBF>@param</font> context_ids – array of available context IDs.
+ */</font>
+ <font color=#7F0055>void</font> doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ <font color=#3F5FBF>/**
+ * RegistersContext objects represent register groups, registers and bit fields.
+ */</font>
+ <font color=#7F0055>interface</font> RegistersContext {
+ <font color=#3F5FBF>/**
+ * Get Context ID.
+ * <font color=#7F9FBF>@return</font> context ID.
+ */</font>
+ String getID();
+
+ <font color=#3F5FBF>/**
+ * Get parent context ID.
+ * <font color=#7F9FBF>@return</font> parent context ID.
+ */</font>
+ String getParentID();
+
+ <font color=#3F5FBF>/**
+ * Get context (register, register group, bit field) name.
+ * <font color=#7F9FBF>@return</font> context name.
+ */</font>
+ String getName();
+
+ <font color=#3F5FBF>/**
+ * Get context description.
+ * <font color=#7F9FBF>@return</font> context description.
+ */</font>
+ String getDescription();
+
+ <font color=#3F5FBF>/**
+ * Get value formats available for register get/set commands.
+ * See FORMAT_* for knows format IDs definition.
+ * <font color=#7F9FBF>@return</font> array of supported format IDs.
+ */</font>
+ String[] getAvailableFormats();
+
+ <font color=#3F5FBF>/**
+ * Check if context value can be read.
+ * <font color=#7F9FBF>@return</font> true if can read value of the context.
+ */</font>
+ <font color=#7F0055>boolean</font> isReadable();
+
+ <font color=#3F5FBF>/**
+ * Check if reading the context (register) destroys its current value -
+ * it can be read only once.
+ * <font color=#7F9FBF>@return</font> true if read-once register.
+ */</font>
+ <font color=#7F0055>boolean</font> isReadOnce();
+
+ <font color=#3F5FBF>/**
+ * Check if context value can be written.
+ * <font color=#7F9FBF>@return</font> true if can write value of the context.
+ */</font>
+ <font color=#7F0055>boolean</font> isWriteable();
+
+ <font color=#3F5FBF>/**
+ * Check if register value can not be overwritten - every write counts.
+ * <font color=#7F9FBF>@return</font> true if write-once register.
+ */</font>
+ <font color=#7F0055>boolean</font> isWriteOnce();
+
+ <font color=#3F5FBF>/**
+ * Check if writing the context can change values of other registers.
+ * <font color=#7F9FBF>@return</font> true if has side effects.
+ */</font>
+ <font color=#7F0055>boolean</font> hasSideEffects();
+
+ <font color=#3F5FBF>/**
+ * Check if the register value can change even when target is stopped.
+ * <font color=#7F9FBF>@return</font> true if the register value can change at any time.
+ */</font>
+ <font color=#7F0055>boolean</font> isVolatile();
+
+ <font color=#3F5FBF>/**
+ * Check if the register value is a floating-point value.
+ * <font color=#7F9FBF>@return</font> true if a floating-point register.
+ */</font>
+ <font color=#7F0055>boolean</font> isFloat();
+
+ <font color=#3F5FBF>/**
+ * Check endianess of the context.
+ * Big endian means decreasing numeric significance with increasing bit number.
+ * <font color=#7F9FBF>@return</font> true if big endian.
+ */</font>
+ <font color=#7F0055>boolean</font> isBigEndian();
+
+ <font color=#3F5FBF>/**
+ * Check if the lowest numbered bit (i.e. bit #0 or bit #1 depending on
+ * getFirstBitNumber() value) should be shown to user as the left-most bit or
+ * the right-most bit.
+ * <font color=#7F9FBF>@return</font> true if the first bit is left-most bit.
+ */</font>
+ <font color=#7F0055>boolean</font> isLeftToRight();
+
+ <font color=#3F5FBF>/**
+ * If the context has bit field children, bit positions of the fields
+ * can be zero-based or 1-based.
+ * <font color=#7F9FBF>@return</font> first bit position - 0 or 1.
+ */</font>
+ <font color=#7F0055>int</font> getFirstBitNumber();
+
+ <font color=#3F5FBF>/**
+ * If context is a bit field, get the field bit numbers in parent context.
+ * <font color=#7F9FBF>@return</font> array of bit numbers.
+ */</font>
+ <font color=#7F0055>int</font>[] getBitNumbers();
+
+ <font color=#3F5FBF>/**
+ * A context can have predefined names (mnemonics) for some its values.
+ * This method returns a list of such named values.
+ * <font color=#7F9FBF>@return</font> array of named values or null.
+ */</font>
+ NamedValue[] getNamedValues();
+
+ <font color=#3F5FBF>/**
+ * Get complete map of context properties.
+ * <font color=#7F9FBF>@return</font> map of context properties.
+ */</font>
+ Map&lt;String,Object&gt; getProperties();
+
+ <font color=#3F5FBF>/**
+ * Read value of the context.
+ * <font color=#7F9FBF>@param</font> format - ID of a format to use for result value.
+ * <font color=#7F9FBF>@param</font> done - call back object.
+ * <font color=#7F9FBF>@return</font> - pending command handle.
+ */</font>
+ IToken get(String format, DoneGet done);
+
+ <font color=#3F5FBF>/**
+ * Set value of the context.
+ * <font color=#7F9FBF>@param</font> format - ID of a format used for value.
+ * <font color=#7F9FBF>@param</font> value - value to write into the context.
+ * <font color=#7F9FBF>@param</font> done - call back object.
+ * <font color=#7F9FBF>@return</font> - pending command handle.
+ */</font>
+ IToken set(String format, String value, DoneSet done);
+ }
+
+ <font color=#3F5FBF>/**
+ * A register context can have predefined names (mnemonics) for some its values.
+ * NamedValue objects represent such values.
+ */</font>
+ <font color=#7F0055>interface</font> NamedValue {
+ <font color=#3F5FBF>/**
+ * Get number associated with this named value.
+ * <font color=#7F9FBF>@return</font> the value as a number.
+ */</font>
+ Number getValue();
+
+ <font color=#3F5FBF>/**
+ * Get name (mnemonic) of the value.
+ * <font color=#7F9FBF>@return</font> value name.
+ */</font>
+ String getName();
+
+ <font color=#3F5FBF>/**
+ * Get human readable description of the value.
+ * <font color=#7F9FBF>@return</font> value description.
+ */</font>
+ String getDescription();
+ }
+
+ <font color=#3F5FBF>/**
+ * 'get' command call back interface.
+ */</font>
+ <font color=#7F0055>interface</font> DoneGet {
+ <font color=#7F0055>void</font> doneGet(IToken token, Exception error, String value);
+ }
+
+ <font color=#3F5FBF>/**
+ * 'set' command call back interface.
+ */</font>
+ <font color=#7F0055>interface</font> DoneSet {
+ <font color=#7F0055>void</font> doneSet(IToken token, Exception error);
+ }
+
+ <font color=#3F5FBF>/**
+ * Add registers service event listener.
+ * <font color=#7F9FBF>@param</font> listener - event listener implementation.
+ */</font>
+ <font color=#7F0055>void</font> addListener(RegistersListener listener);
+
+ <font color=#3F5FBF>/**
+ * Remove registers service event listener.
+ * <font color=#7F9FBF>@param</font> listener - event listener implementation.
+ */</font>
+ <font color=#7F0055>void</font> removeListener(RegistersListener listener);
+
+ <font color=#3F5FBF>/**
+ * Registers event listener is notified when registers context hierarchy
+ * changes, and when a register is modified by the service commands.
+ */</font>
+ <font color=#7F0055>interface</font> RegistersListener {
+
+ <font color=#3F5FBF>/**
+ * Called when register context properties changed.
+ * Most targets have static set of registers and register properties.
+ * Such targets never generate this event. However, some targets,
+ * for example, JTAG probes, allow user to modify register definitions.
+ * Clients should flush all cached register context data.
+ */</font>
+ <font color=#7F0055>void</font> contextChanged();
+
+ <font color=#3F5FBF>/**
+ * Called when register content was changed and clients
+ * need to update themselves. Clients, at least, should invalidate
+ * corresponding cached registers data.
+ * Not every change is notified - it is not possible,
+ * only those, which are not caused by normal execution of the debuggee.
+ */</font>
+ <font color=#7F0055>void</font> registerChanged(String context_id);
+ }
+}
+</pre>
+
+</body>
+</html>
diff --git a/docs/TCF Service - Run Control.html b/docs/TCF Service - Run Control.html
new file mode 100644
index 000000000..dc17b079b
--- /dev/null
+++ b/docs/TCF Service - Run Control.html
@@ -0,0 +1,618 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework Services - Run Control</title>
+</head>
+
+<body lang='EN-US'>
+
+<h1>Target Communication Framework Services - Run Control</h1>
+
+<ul>
+ <li><a href='#Cmds'>Commands</a>
+ <ul>
+ <li><a href='#CmdGetContext'>Get Context</a>
+ <li><a href='#CmdGetChildren'>Get Children</a>
+ <li><a href='#CmdSuspend'>Suspend</a>
+ <li><a href='#CmdResume'>Resume</a>
+ <li><a href='#CmdGetState'>Get State</a>
+ <li><a href='#CmdTerminate'>Terminate</a>
+ </ul>
+ <li><a href='#Events'>Events</a>
+ <li><a href='#API'>API</a>
+</ul>
+
+<h1>Run Control Service</h1>
+
+<p>The service provides basic run control operations for execution contexts on a target.
+Command and event parameters are encoded as zero terminated <a href='TCF Specification.html#JSON'>JSON</a> strings.</p>
+
+<p>The service uses standard format for error reports,
+see <a href='TCF Services.html#ErrorFormat'>Error Report Format</a>.</p>
+
+<h2><a name='Cmds'>Commands</a></h2>
+
+<p>All run control commands are fully asynchronous, which means they never wait until
+context is in a particular state. For example, if single step command arrives when
+context is running, it does not wait until it stops, but returns an error. If a command
+successfully resumed a context, it does not wait until instruction pointer reaches
+desired destination – from client point of view the command execution ends right after
+context was resumed. Various stepping commands can leave a context running in a special
+mode, which is different from normal execution, for example, it can leave temporary
+breakpoints to suspend the context when control reaches a particular place. Such execution
+mode ends when the context is suspended, even if it was suspended for reasons unrelated
+to the command and intended destination was not reached. Client can know when and
+why a context is suspended by listening to events.</p>
+
+<h3><a name='CmdGetContext'>Get Context</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • RunControl • getContext • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command retrieves context properties for given context ID.
+Exact meaning of context depends on the target.
+A context can represent an execution thread, a process, an address space, etc.
+A context can belong to a parent context. Contexts hierarchy can be simple
+plain list or it can form a tree. It is up to target agent developers to choose
+layout that is most descriptive for a given target. Context IDs are valid across
+all services. In other words, all services access same hierarchy of contexts,
+with same IDs, however, each service accesses its own subset of context's
+attributes and functionality, which is relevant to that service.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;context data&gt;</i> •
+
+<i>&lt;context data&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> <i>&lt;object: context properties&gt;</i>
+</font></b></pre>
+
+<p>Context data object is collection of context properties. It should, at least, contain member
+<b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;</i></font></b>.
+It can also contain arbitrary number of components
+describing context properties and capabilities. Context data is supposed to be cached
+by clients and it is not expected to change frequently. It can include, for example,
+context name or ability to perform single step command on the context. But, it should
+not include volatile data like current PC or running/suspended state. Service sends
+contextChanged event to notify changes in context data.</p>
+
+<p>Predefined run control context properties are:</p>
+<ul>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;</i></font></b></code>
+ - ID of the context, same as getContext command argument.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ParentID" : <i>&lt;string&gt;</i></font></b></code>
+ - ID of a parent context.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"IsContainer" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if the context is a container.
+ Executing resume or suspend command on a container causes all its children to resume or suspend.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"HasState" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if the context is an execution context, therefore
+ has an execution state, like state of a program counter (PC).
+ Only context that has a state can be resumed or suspended.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CanSuspend" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if Suspend command is supported for this contex. It does not mean that the command can be executed successfully in
+ the current state of the context. For example, the command still can fail if context is already suspended.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CanResume" : <i>&lt;int: bitset of resume modes&gt;</i></font></b></code>
+ - for each resume mode, corresponding bit is '1' if Resume command mode is supported for this contex, and '0' otherwise.
+ It does not mean that the command can be executed successfully in
+ the current state of the context. For example, the command still can fail if context is already resumed.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CanCount" : <i>&lt;int: bitset of resume modes&gt;</i></font></b></code>
+ - for each resume mode, corresponding bit is '1' if Resume command mode with count other then 1 is supported by the context.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CanTerminate" : <i>&lt;boolean&gt;</i></font></b></code>
+ - true if Terminate command is supported by the context,
+</ul>
+
+<h3><a name='CmdGetChildren'>Get Children</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • RunControl • getChildren • <i>&lt;string: parent context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command requests list of execution contexts available for run control commands.</p>
+
+<p>Parent context ID can be null – to retrieve top level of the hierarchy, can be one
+of context IDs retrieved by previous getChildren commands, or it can be obtained from another service.
+Contexts hierarchy can be simple plain list or it can form a tree. It is up to target agent developers to
+choose layout that is most descriptive for a given target.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of context IDs&gt;</i> •
+
+<i>&lt;array of context IDs&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ <i>&lt;context ID list&gt;</i> ]
+
+<i>&lt;context ID list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string: context ID&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;context ID list&gt;</i> , <i>&lt;string: context ID&gt;</i>
+</font></b></pre>
+
+<h3><a name='CmdSuspend'>Suspend</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • RunControl • suspend • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command suspends execution of given context. The command should fail if CanSuspend property of the context is false.
+If context's IsContainer = true, the command is propagated to context's children. Only contexts with HasState = true
+can be suspended.</p>
+
+<p>Result message:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdResume'>Resume</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • RunControl • resume • <i>&lt;string: context ID&gt;</i> • <i>&lt;int: mode&gt;</i> • <i>&lt;int: count&gt;</i> •
+</font></b></pre>
+
+<p>The command resumes execution of given context. The command should fail if CanResume
+property of the context is '0' for given mode. If context's IsContainer = true, the command is propagated
+to context's children. Only contexts with HasState = true can be resumed.</p>
+
+<p>Resume modes:</p>
+<ul>
+ <li><code>RM_RESUME = 0</code> - rusume normal execution. Execution will
+ continue until suspended by command or breakpoint.
+
+ <li><code>RM_STEP_OVER = 1</code> - step over single instruction. If instruction
+ is function call, execution continues until control returns from the function.
+
+ <li><code>RM_STEP_INTO = 2</code> - single instruction in given context.
+
+ <li><code>RM_STEP_OVER_LINE = 3</code> - resume execution of given context until control reaches instruction
+ that belongs to a different line of source code, but runs any functions called at
+ full speed. Error is returned if line number information not available.
+
+ <li><code>RM_STEP_INTO_LINE = 4</code> - resumes execution of given context until control reaches instruction
+ that belongs to a different line of source code. If a function is called,
+ stop at first line of the function code. Error is returned if line number
+ information not available.
+
+ <li><code>RM_STEP_OUT = 5</code> - resume execution of given context until control returns from current
+ function.
+</ul>
+
+<p>Result message:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='CmdGetState'>Get State</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • RunControl • getState • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command retrieves current state of the context. The command should fail if HasState property of
+the context is false.</p>
+
+<p>Result message:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;boolean: suspended&gt;</i> •
+ <i>&lt;int: PC&gt;</i> • <i>&lt;string: last state change reason&gt;</i> • <i>&lt;state data&gt;</i> •
+
+<i>&lt;state data&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> <i>&lt;object: context state properties&gt;</i>
+</font></b></pre>
+
+<p>State change reason can be any text, but if it is one of predefined strings,
+a generic client might be able to handle it better. Predefined reasons are:</p>
+<ul>
+ <li><code>REASON_USER_REQUEST = "Suspended"</code> - context suspended by command.
+ <li><code>REASON_STEP = "Step"</code> - context resumed or suspended by step command.
+ <li><code>REASON_BREAKPOINT = "Breakpoint"</code> - context suspended by breakpoint.
+ <li><code>REASON_EXCEPTION = "Exception"</code> - context suspended by exception.
+ <li><code>REASON_CONTAINER = "Container"</code> - context suspended or resumed as part of container.
+ <li><code>REASON_WATCHPOINT = "Watchpoint"</code> - context suspended by watchpoint (data breakpoint).
+ <li><code>REASON_SIGNAL = "Signal"</code> - context suspended because it received a signal.
+ <li><code>REASON_SHAREDLIB = "Shared Library"</code> - context suspended because a shared library is loaded or unloaded.
+ <li><code>REASON_ERROR = "Error"</code> - context suspended because of an error in execution environment.
+</ul>
+
+<p>Context state properties can contain any data relevant to context state.
+Defenition of state properties depends on a target.</p>
+
+<h3><a name='CmdTerminate'>Terminate</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • RunControl • terminate • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command terminates execution of given context. The command should fail if CanTerminate
+property of the context is false.</p>
+
+<p>Result message:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h2><a name='Events'>Events</a></h2>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+E • RunControl • contextAdded • <i>&lt;array of context data&gt;</i> •
+
+E • RunControl • contextChanged • <i>&lt;array of context data&gt;</i> •
+
+E • RunControl • contextRemoved • <i>&lt;array of context IDs&gt;</i> •
+
+E • RunControl • contextSuspended • <i>&lt;string: context ID&gt;</i> • <i>&lt;int: PC&gt;</i> •
+ <i>&lt;string: reason&gt;</i> • <i>&lt;state data&gt;</i> •
+
+E • RunControl • contextResumed • <i>&lt;string: context ID&gt;</i> •
+
+E • RunControl • contextException • <i>&lt;string: context ID&gt;</i> • <i>&lt;string: description&gt;</i> •
+
+E • RunControl • containerSuspended • <i>&lt;string: context ID&gt;</i> • <i>&lt;int: PC&gt;</i> •
+ <i>&lt;string: reason&gt;</i> • <i>&lt;state data&gt;</i> • <i>&lt;array of context IDs&gt;</i> •
+
+E • RunControl • containerResumed • <i>&lt;array of context IDs&gt;</i> •
+
+<i>&lt;array of context data&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ <i>&lt;context data list&gt;</i> ]
+
+<i>&lt;context data list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;object: context data&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;context data list&gt;</i> , <i>&lt;object: context data&gt;</i>
+</font></b></pre>
+
+<dl>
+ <dt><b>contextAdded</b>
+ <dd>is sent when new contexts are created or attached for debugging. The message contains
+ array of context data. Context data is same as returned by Get Context command.
+ <dt><b>contextChanged</b>
+ <dd>is sent when context properties change. The message contains
+ array of changed (new) context data. Context data is same as returned by Get Context command.
+ <dt><b>contextRemoved</b>
+ <dd>is sent when context is removed - terminated or dettached. The message contains
+ array of context IDs.
+ <dt><b>contextSuspended</b>
+ <dd>is sent when context is suspended. The message context ID contains context state data,
+ same state data as returned by Get State command.
+ <dt><b>contextResumed</b>
+ <dd>is sent when context is resumed. The message contains resumed context ID.
+ <dt><b>contextException</b>
+ <dd>is sent when execution exception occurs in a context. The message contains context ID and
+ a string that describes nature of the exception.
+ <dt><b>containerSuspended</b>
+ <dd>is sent when target simultaneously suspends multiple threads in a container (process, core, etc.).
+ The message contains context ID and context state data of a context responsible for the event.
+ It can be container ID or any one of container children, for example, it can be thread
+ that hit "suspend all" breakpoint. Message also contains full list of all contexts that were suspended
+ simultaneously. No separate contextSuspened events are sent for contexts in the list. If client needs
+ state data for those contexts, it should use Get State command.
+ <dt><b>containerResumed</b>
+ <dd>is sent when target simultaneously resumes multiple threads in a container (process,
+ core, etc.). Message contains full list of all contexts that were resumed
+ simultaneously. No separate contextResumed events are sent for contexts in the list.
+</dl>
+
+<h2><a name='API'>API</a></h2>
+
+<pre>
+<font color=#7F0055>public interface</font> IRunControl <font color=#7F0055>extends</font> IService {
+
+ <font color=#3F5FBF>/**
+ * Context property names.
+ */</font>
+ <font color=#7F0055>static final</font> String
+ PROP_ID = "ID",
+ PROP_PARENT_ID = "ParentID",
+ PROP_IS_CONTAINER = "IsContainer",
+ PROP_HAS_STATE = "HasState",
+ PROP_CAN_RESUME = "CanResume",
+ PROP_CAN_COUNT = "CanCount",
+ PROP_CAN_SUSPEND = "CanSuspend",
+ PROP_CAN_TERMINATE = "CanTerminate";
+
+ <font color=#3F5FBF>/**
+ * Context resume modes.
+ */</font>
+ <font color=#7F0055>static final int</font>
+ RM_RESUME = 0,
+ RM_STEP_OVER = 1,
+ RM_STEP_INTO = 2,
+ RM_STEP_OVER_LINE = 3,
+ RM_STEP_INTO_LINE = 4,
+ RM_STEP_OUT = 5;
+
+ <font color=#3F5FBF>/**
+ * State change reason of a context.
+ * Reason can be any text, but if it is one of predefined strings,
+ * a generic client might be able to handle it better.
+ */</font>
+ <font color=#7F0055>static final</font> String
+ REASON_USER_REQUEST = "Suspended",
+ REASON_STEP = "Step",
+ REASON_BREAKPOINT = "Breakpoint",
+ REASON_EXCEPTION = "Exception",
+ REASON_CONTAINER = "Container",
+ REASON_WATCHPOINT = "Watchpoint",
+ REASON_SIGNAL = "Signal",
+ REASON_SHAREDLIB = "Shared Library",
+ REASON_ERROR = "Error";
+
+ <font color=#3F5FBF>/**
+ * Retrieve context info for given context ID.
+ *
+ * <font color=#7F9FBF>@param</font> id – context ID.
+ * <font color=#7F9FBF>@param</font> done - callback interface called when operation is completed.
+ */</font>
+ IToken getContext(String id, DoneGetContext done);
+
+ <font color=#3F5FBF>/**
+ * Client callback interface for getContext().
+ */</font>
+ <font color=#7F0055>interface</font> DoneGetContext {
+ <font color=#3F5FBF>/**
+ * Called when contexts data retrieval is done.
+ * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+ * <font color=#7F9FBF>@param</font> context – context data.
+ */</font>
+ <font color=#7F0055>void</font> doneGetContext(IToken token, Exception error, RunControlContext context);
+ }
+
+    <font color=#3F5FBF>/**
+ * Retrieve children of given context.
+ *
+ * <font color=#7F9FBF>@param</font> parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getContext or getChildren commands.
+ * <font color=#7F9FBF>@param</font> done - callback interface called when operation is completed.
+     */</font>
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+    <font color=#3F5FBF>/**
+     * Client callback interface for getContexts().
+     */</font>
+    <font color=#7F0055>interface</font> DoneGetChildren {
+        <font color=#3F5FBF>/**
+         * Called when contexts data retrieval is done.
+         * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+         * <font color=#7F9FBF>@param</font> contexts – array of available context IDs.
+         */</font>
+        <font color=#7F0055>void</font> doneGetChildren(IToken token, RunControlError error, Context[] contexts);
+    }
+
+ <font color=#3F5FBF>/**
+ * A context corresponds to an execution thread, process, address space, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ */</font>
+    <font color=#7F0055>interface</font> RunControlContext {
+
+ <font color=#3F5FBF>/**
+ * Retrieve context ID.
+ * Same as getProperties().get("ID")
+ */</font>
+        String getID();
+
+ <font color=#3F5FBF>/**
+ * Retrieve parent context ID.
+ * Same as getProperties().get("ParentID")
+ */</font>
+ String getParentID();
+
+ <font color=#3F5FBF>/**
+ * Get context properties. See PROP_* definitions for property names.
+ * Context properties are read only, clients should not try to modify them.
+ * <font color=#7F9FBF>@return</font> Map of context properties.
+ */</font>
+        Map&lt;String,Object&gt; getProperties();
+
+ <font color=#3F5FBF>/**
+ * Utility method to read context property PROP_IS_CONTAINER.
+ * Executing resume or suspend command on a container causes all its children to resume or suspend.
+ * <font color=#7F9FBF>@return</font> value of PROP_IS_CONTAINER.
+ */</font>
+ <font color=#7F0055>boolean</font> isContainer();
+
+ <font color=#3F5FBF>/**
+ * Utility method to read context property PROP_HAS_STATE.
+ * Only context that has a state can be resumed or suspended.
+ * <font color=#7F9FBF>@return</font> value of PROP_HAS_STATE.
+ */</font>
+ <font color=#7F0055>boolean</font> hasState();
+
+ <font color=#3F5FBF>/**
+ * Utility method to read context property PROP_CAN_SUSPEND.
+ * Value 'true' means suspend command is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already suspended.
+ * <font color=#7F9FBF>@return</font> value of PROP_CAN_SUSPEND.
+ */</font>
+ <font color=#7F0055>boolean</font> canSuspend();
+
+ <font color=#3F5FBF>/**
+ * Utility method to read a 'mode' bit in context property PROP_CAN_RESUME.
+ * Value 'true' means resume command is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already resumed.
+ * <font color=#7F9FBF>@param</font> mode - resume mode, see RM_*.
+ * <font color=#7F9FBF>@return</font> value of requested bit of PROP_CAN_RESUME.
+ */</font>
+ <font color=#7F0055>boolean</font> canResume(<font color=#7F0055>int</font> mode);
+
+ <font color=#3F5FBF>/**
+ * Utility method to read a 'mode' bit in context property PROP_CAN_COUNT.
+ * Value 'true' means resume command with count other then 1 is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already resumed.
+ * <font color=#7F9FBF>@param</font> mode - resume mode, see RM_*.
+ * <font color=#7F9FBF>@return</font> value of requested bit of PROP_CAN_COUNT.
+ */</font>
+ <font color=#7F0055>boolean</font> canCount(<font color=#7F0055>int</font> mode);
+
+ <font color=#3F5FBF>/**
+ * Utility method to read context property PROP_CAN_TERMINATE.
+ * Value 'true' means terminate command is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already exited.
+ * <font color=#7F9FBF>@return</font> value of PROP_CAN_SUSPEND.
+ */</font>
+ <font color=#7F0055>boolean</font> canTerminate();
+
+ <font color=#3F5FBF>/**
+ * Send a command to retrieve current state of a context.
+ * <font color=#7F9FBF>@param</font> done - command result call back object.
+ * <font color=#7F9FBF>@return</font> pending command handle, can be used to cancel the command.
+ */</font>
+ IToken getState(DoneGetState done);
+
+ <font color=#3F5FBF>/**
+ * Send a command to suspend a context.
+ * Also suspends children if context is a container.
+ * <font color=#7F9FBF>@param</font> done - command result call back object.
+ * <font color=#7F9FBF>@return</font> pending command handle, can be used to cancel the command.
+ */</font>
+ IToken suspend(DoneCommand done);
+
+ <font color=#3F5FBF>/**
+ * Send a command to resume a context.
+ * Also resumes children if context is a container.
+ * <font color=#7F9FBF>@param</font> mode - defines how to resume the context, see RM_*.
+ * <font color=#7F9FBF>@param</font> count - if mode implies stepping, defines how many steps to perform.
+ * <font color=#7F9FBF>@param</font> done - command result call back object.
+ * <font color=#7F9FBF>@return</font> pending command handle, can be used to cancel the command.
+ */</font>
+ IToken resume(<font color=#7F0055>int</font> mode, <font color=#7F0055>int</font> count, DoneCommand done);
+
+ <font color=#3F5FBF>/**
+ * Send a command to terminate a context.
+ * <font color=#7F9FBF>@param</font> done - command result call back object.
+ * <font color=#7F9FBF>@return</font> pending command handle, can be used to cancel the command.
+ */</font>
+ IToken terminate(DoneCommand done);
+    }
+
+    <font color=#7F0055>class</font> RunControlError <font color=#7F0055>extends</font> Exception {
+    }
+
+ <font color=#7F0055>interface</font> DoneGetState {
+ <font color=#7F0055>void</font> doneGetState(IToken token, Exception error, <font color=#7F0055>boolean</font> suspended, String pc,
+ String reason, Map&lt;String,Object&gt; params);
+ }
+
+ <font color=#7F0055>interface</font> DoneCommand {
+ <font color=#3F5FBF>/**
+ * Called when run control command execution is complete.
+ * <font color=#7F9FBF>@param</font> token - pending command handle.
+ * <font color=#7F9FBF>@param</font> error - command execution error or null.
+ */</font>
+ <font color=#7F0055>void</font> doneCommand(IToken token, Exception error);
+ }
+
+ <font color=#3F5FBF>/**
+ * Add run control event listener.
+ * <font color=#7F9FBF>@param</font> listener - run control event listener to add.
+ */</font>
+ <font color=#7F0055>void</font> addListener(RunControlListener listener);
+
+ <font color=#3F5FBF>/**
+ * Remove run control event listener.
+ * <font color=#7F9FBF>@param</font> listener - run control event listener to remove.
+ */</font>
+ <font color=#7F0055>void</font> removeListener(RunControlListener listener);
+
+ <font color=#3F5FBF>/**
+ * Service events listener interface.
+ */</font>
+ <font color=#7F0055>interface</font> RunControlListener {
+
+ <font color=#3F5FBF>/**
+ * Called when a new contexts are created.
+ * <font color=#7F9FBF>@param</font> contexts - array of new context properties.
+ */</font>
+ <font color=#7F0055>void</font> contextAdded(RunControlContext contexts[]);
+
+ <font color=#3F5FBF>/**
+ * Called when a context properties changed.
+ * <font color=#7F9FBF>@param</font> contexts - array of new context properties.
+ */</font>
+ <font color=#7F0055>void</font> contextChanged(RunControlContext contexts[]);
+
+ <font color=#3F5FBF>/**
+ * Called when contexts are removed.
+ * <font color=#7F9FBF>@param</font> context_ids - aray of removed context IDs.
+ */</font>
+ <font color=#7F0055>void</font> contextRemoved(String context_ids[]);
+
+ <font color=#3F5FBF>/**
+ * Called when a thread is suspended.
+ * <font color=#7F9FBF>@param</font> context - ID of a context that was suspended.
+ * <font color=#7F9FBF>@param</font> pc - program counter of the context, can be null.
+ * <font color=#7F9FBF>@param</font> reason - human readable description of suspend reason.
+ * <font color=#7F9FBF>@param</font> params - additional, target specific data about suspended context.
+ */</font>
+ <font color=#7F0055>void</font> contextSuspended(String context, String pc,
+ String reason, Map&lt;String,Object&gt; params);
+
+ <font color=#3F5FBF>/**
+ * Called when a thread is resumed.
+ * <font color=#7F9FBF>@param</font> context - ID of a context that was resumed.
+ */</font>
+ <font color=#7F0055>void</font> contextResumed(String context);
+
+ <font color=#3F5FBF>/**
+ * Called when target simultaneously suspends multiple threads in a container
+ * (process, core, etc.).
+ *
+ * <font color=#7F9FBF>@param</font> context - ID of a context responsible for the event. It can be container ID or
+ * any one of container children, for example, it can be thread that hit "suspend all" breakpoint.
+ * Client expected to move focus (selection) to this context.
+ * <font color=#7F9FBF>@param</font> pc - program counter of the context.
+ * <font color=#7F9FBF>@param</font> reason - human readable description of suspend reason.
+ * <font color=#7F9FBF>@param</font> params - additional target specific data about suspended context.
+ * <font color=#7F9FBF>@param</font> suspended_ids - full list of all contexts that were suspended.
+ */</font>
+ <font color=#7F0055>void</font> containerSuspended(String context, String pc,
+ String reason, Map&lt;String,Object&gt; params, String[] suspended_ids);
+
+ <font color=#3F5FBF>/**
+ * Called when target simultaneously resumes multiple threads in a container (process,
+ * core, etc.).
+ *
+ * <font color=#7F9FBF>@param</font> context_ids - full list of all contexts that were resumed.
+ */</font>
+ <font color=#7F0055>void</font> containerResumed(String[] context_ids);
+
+ <font color=#3F5FBF>/**
+ * Called when an exception is detected in a target thread.
+ * <font color=#7F9FBF>@param</font> context - ID of a context that caused an exception.
+ * <font color=#7F9FBF>@param</font> msg - human readable description of the exception.
+ */</font>
+ <font color=#7F0055>void</font> contextException(String context, String msg);
+ }
+}
+</pre>
+
+</body>
+</html>
diff --git a/docs/TCF Service - Stack Trace.html b/docs/TCF Service - Stack Trace.html
new file mode 100644
index 000000000..c1ce675d5
--- /dev/null
+++ b/docs/TCF Service - Stack Trace.html
@@ -0,0 +1,278 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework Services - Stack Trace</title>
+</head>
+
+<body lang='EN-US'>
+
+<h1>Target Communication Framework Services - Stack Trace</h1>
+
+<ul>
+ <li><a href='#Cmds'>Commands</a>
+ <ul>
+ <li><a href='#CmdGetContext'>Get Context</a>
+ <li><a href='#CmdGetChildren'>Get Children</a>
+ </ul>
+ <li><a href='#Events'>Events</a>
+ <li><a href='#API'>API</a>
+</ul>
+
+<h1>Stack Trace Service</h1>
+
+<p>The service implements thread stack back tracing. Command
+and event parameters are encoded as zero terminated <a href='TCF Specification.html#JSON'>JSON</a> strings.</p>
+
+<p>The service uses standard format for error reports,
+see <a href='TCF Services.html#ErrorFormat'>Error Report Format</a>.</p>
+
+<h2><a name='Cmds'>Commands</a></h2>
+
+<h3><a name='CmdGetContext'>Get Context</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • StackTrace • getContext • <i>&lt;array of context IDs&gt;</i> •
+
+<i>&lt;array of context IDs&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;context ID list&gt;</i> ]
+
+<i>&lt;context ID list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string: context ID&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;context ID list&gt;</i> , <i>&lt;string: context ID&gt;</i>
+</font></b></pre>
+
+<p>The command retrieves context info for given context IDs.
+Command allows to query multiple contexts at once.
+Stack Trace context represents single stack frame.
+If target supports more then one stack per thread,
+each stack is also represented by a separate context.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;array of context data&gt;</i> • <i>&lt;error report&gt;</i> •
+
+<i>&lt;array of context data&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;context data list&gt;</i> ]
+
+<i>&lt;context data list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;context data&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;context data list&gt;</i> , <i>&lt;context data&gt;</i>
+
+<i>&lt;context data&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> <i>&lt;object&gt;</i>
+</font></b></pre>
+
+<p>Context data object should, at least, contain member
+<b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;.</i></font></b>
+Context data is expected to be cached by clients.
+Cached context data should by flushed when parent thread is resumed.</p>
+
+<p>Predefined stack trace context properties are:</p>
+<ul>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;</i></font></b></code>
+ - ID of the context, same as getContext command argument.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ParentID" : <i>&lt;string&gt;</i></font></b></code>
+ - ID of a parent context.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ProcessID" : <i>&lt;string&gt;</i></font></b></code>
+ - process ID.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Name" : <i>&lt;string&gt;</i></font></b></code>
+ - context name if context is a stack
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"FP" : <i>&lt;number&gt;</i></font></b></code>
+ - frame pointer - memory address of stack frame
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"PC" : <i>&lt;number&gt;</i></font></b></code>
+ - program counter - memory address of instruction that will be executed when thread returns from this stack frame.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ArgsCnt" : <i>&lt;number&gt;</i></font></b></code>
+ - function arguments count
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ArgsAddr" : <i>&lt;number&gt;</i></font></b></code>
+ - memory address of function arguments
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Level" : <i>&lt;number&gt;</i></font></b></code>
+ - frame level. Bottom most (oldest) frame is level 0.
+</ul>
+
+<h3><a name='CmdGetChildren'>Get Children</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • StackTrace • getChildren • <i>&lt;string: parent context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command retrieves stack trace context list.
+Parent context usually corresponds to an execution thread.
+Some targets have more then one stack. In such case children of a thread
+are stacks, and stack frames are deeper in the hierarchy - they can be
+retrieved with additional getChildren commands.</p>
+
+<p>The command will fail if parent thread is not suspended.
+Client can use Run Control service to suspend a thread.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of context IDs&gt;</i> •<i></i>
+
+<i>&lt;array of context IDs&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;context ID list&gt;</i> ]
+
+<i>&lt;context ID list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string: context ID&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;context ID list&gt;</i> , <i>&lt;string: context ID&gt;</i>
+
+</font></b></pre>
+
+
+<h2><a name='Events'>Events</a></h2>
+
+<p>No events are currently defined for Stack Trace service.</p>
+
+<h2><a name='API'>API</a></h2>
+
+<pre>
+<font color=#7F0055>public interface</font> IStackTrace <font color=#7F0055>extends</font> IService {
+
+ <font color=#7F0055>static final</font> String NAME = "StackTrace";
+
+ <font color=#3F5FBF>/**
+ * Context property names.
+ */</font>
+ <font color=#7F0055>static final</font> String
+ PROP_ID = "ID",
+ PROP_PARENT_ID = "ParentID",
+ PROP_PROCESS_ID = "ProcessID",
+ PROP_NAME = "Name",
+ PROP_FRAME_ADDRESS = "FP",
+ PROP_PROGRAM_COUNTER = "PC",
+ PROP_ARGUMENTS_COUNT = "ArgsCnt",
+ PROP_ARGUMENTS_ADDRESS = "ArgsAddr",
+ PROP_LEVEL = "Level";
+
+ <font color=#3F5FBF>/**
+ * Retrieve context info for given context IDs.
+ *
+ * The command will fail if parent thread is not suspended.
+ * Client can use Run Control service to suspend a thread.
+ *
+ * <font color=#7F9FBF>@param</font> id – array of context IDs.
+ * <font color=#7F9FBF>@param</font> done - call back interface called when operation is completed.
+ */</font>
+ IToken getContext(String[] id, DoneGetContext done);
+
+ <font color=#3F5FBF>/**
+ * Client call back interface for getContext().
+ */</font>
+ <font color=#7F0055>interface</font> DoneGetContext {
+ <font color=#3F5FBF>/**
+ * Called when context data retrieval is done.
+ * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+ * <font color=#7F9FBF>@param</font> context – array of context data or null if error.
+ */</font>
+ <font color=#7F0055>void</font> doneGetContext(IToken token, Exception error, StackTraceContext[] context);
+ }
+
+ <font color=#3F5FBF>/**
+ * Retrieve stack trace context list.
+ * Parent context usually corresponds to an execution thread.
+ * Some targets have more then one stack. In such case children of a thread
+ * are stacks, and stack frames are deeper in the hierarchy - they can be
+ * retrieved with additional getChildren commands.
+ *
+ * The command will fail if parent thread is not suspended.
+ * Client can use Run Control service to suspend a thread.
+ *
+ * <font color=#7F9FBF>@param</font> parent_context_id – parent context ID.
+ * <font color=#7F9FBF>@param</font> done - call back interface called when operation is completed.
+ */</font>
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ <font color=#3F5FBF>/**
+ * Client call back interface for getChildren().
+ */</font>
+ <font color=#7F0055>interface</font> DoneGetChildren {
+ <font color=#3F5FBF>/**
+ * Called when context list retrieval is done.
+ * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+ * <font color=#7F9FBF>@param</font> context_ids – array of available context IDs.
+ * Stack frames are ordered from stack bottom to top.
+ */</font>
+ <font color=#7F0055>void</font> doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ <font color=#3F5FBF>/**
+ * StackTraceContext represents stack trace objects - stacks and stack frames.
+ */</font>
+ <font color=#7F0055>interface</font> StackTraceContext {
+
+ <font color=#3F5FBF>/**
+ * Get Context ID.
+ * <font color=#7F9FBF>@return</font> context ID.
+ */</font>
+ String getID();
+
+ <font color=#3F5FBF>/**
+ * Get parent context ID.
+ * <font color=#7F9FBF>@return</font> parent context ID.
+ */</font>
+ String getParentID();
+
+ <font color=#3F5FBF>/**
+ * Get context name - if context represents a stack.
+ * <font color=#7F9FBF>@return</font> context name or null.
+ */</font>
+ String getName();
+
+ <font color=#3F5FBF>/**
+ * Get memory address of this frame.
+ * <font color=#7F9FBF>@return</font> address or null if not a stack frame.
+ */</font>
+ Number getFrameAddress();
+
+ <font color=#3F5FBF>/**
+ * Get program counter saved in this stack frame -
+ * it is address of instruction to be executed when the function returns.
+ * <font color=#7F9FBF>@return</font> program counter or null if not a stack frame.
+ */</font>
+ Number getProgramCounter();
+
+ <font color=#3F5FBF>/**
+ * Get number of function arguments for this frame.
+ * <font color=#7F9FBF>@return</font> function arguments count.
+ */</font>
+ <font color=#7F0055>int</font> getArgumentsCount();
+
+ <font color=#3F5FBF>/**
+ * Get address of function arguments area in memory.
+ * <font color=#7F9FBF>@return</font> function arguments address or null if not available.
+ */</font>
+ Number getArgumentsAddress();
+
+ <font color=#3F5FBF>/**
+ * Get stack frame level.
+ * <font color=#7F9FBF>@return</font> frame level or 0 if not a stack frame.
+ */</font>
+ <font color=#7F0055>int</font> getLevel();
+
+ <font color=#3F5FBF>/**
+ * Get complete map of context properties.
+ * <font color=#7F9FBF>@return</font> map of context properties.
+ */</font>
+ Map&lt;String,Object&gt; getProperties();
+ }
+}
+</pre>
+
+</body>
+</html>
diff --git a/docs/TCF Service - System Monitor.html b/docs/TCF Service - System Monitor.html
new file mode 100644
index 000000000..882e91094
--- /dev/null
+++ b/docs/TCF Service - System Monitor.html
@@ -0,0 +1,654 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework Services - System Monitor</title>
+</head>
+
+<body lang='EN-US'>
+
+<h1>Target Communication Framework Services - System Monitor</h1>
+
+<ul>
+ <li><a href='#Cmds'>Commands</a>
+ <ul>
+ <li><a href='#CmdGetContext'>Get Context</a>
+ <li><a href='#CmdGetChildren'>Get Children</a>
+ <li><a href='#CmdGetCommandLine'>Get Command Line</a>
+ <li><a href='#CmdGetEnvironment'>Get Environment</a>
+ </ul>
+ <li><a href='#Events'>Events</a>
+ <li><a href='#API'>API</a>
+</ul>
+
+<h1>System Monitor Service</h1>
+
+<p>The service can be used for monitoring system activity and utilization.
+It provides list of running processes, different process attributes like command line, environment, etc.,
+and some resource utilization data. The service can be used by a client to provide functionality
+similar to Unix 'top' utility or Windows 'Task Manager'.</p>
+
+<p>Command and event parameters are encoded
+as zero terminated <a href='TCF Specification.html#JSON'>JSON</a> strings.</p>
+
+<p>The service uses standard format for error reports,
+see <a href='TCF Services.html#ErrorFormat'>Error Report Format</a>.</p>
+
+<h2><a name='Cmds'>Commands</a></h2>
+
+<h3><a name='CmdGetContext'>Get Context</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • SysMonitor • getContext • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command retrieves context info for given context ID.
+A context corresponds to an execution thread or process.
+Context IDs are valid across TCF services, so it is allowed to issue 'SysMonitor.getContext'
+command with a context that was obtained from another service.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;context data&gt;</i> •
+
+<i>&lt;context data&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> <i>&lt;object&gt;</i>
+</font></b></pre>
+
+<p>Context data object should, at least, contain member
+<b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;.</i></font></b>
+</p>
+
+<p>Predefined context properties are:</p>
+<ul>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;</i></font></b></code>
+ - ID of the context, same as getContext command argument.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ParentID" : <i>&lt;string&gt;</i></font></b></code>
+ - parent context ID.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CWD" : <i>&lt;string&gt;</i></font></b></code>
+ - current working directory of the process.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Root" : <i>&lt;string&gt;</i></font></b></code>
+ - the process's root directory (as set by chroot).
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"UID" : <i>&lt;int&gt;</i></font></b></code>
+ - User ID of the process owner.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"UGID" : <i>&lt;int&gt;</i></font></b></code>
+ - Group ID of the process owner.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"UserName" : <i>&lt;string&gt;</i></font></b></code>
+ - user name of the process owner.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"GroupName" : <i>&lt;string&gt;</i></font></b></code>
+ - group name of the process owner.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"PID" : <i>&lt;int&gt;</i></font></b></code>
+ - system process ID.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"File" : <i>&lt;string&gt;</i></font></b></code>
+ - executable file of the process.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"State" : <i>&lt;string&gt;</i></font></b></code>
+ - one character from the string "RSDZTW" where R is running, S is
+ sleeping in an interruptible wait, D is waiting in uninterruptible
+ disk sleep, Z is zombie, T is traced or stopped (on a signal), and W
+ is paging.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"PPID" : <i>&lt;int&gt;</i></font></b></code>
+ - system ID of the parent process.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"PGRP" : <i>&lt;int&gt;</i></font></b></code>
+ - the process group ID of the process.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Session" : <i>&lt;int&gt;</i></font></b></code>
+ - the session ID of the process.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"TTY" : <i>&lt;int&gt;</i></font></b></code>
+ - the tty the process uses.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"TGID" : <i>&lt;int&gt;</i></font></b></code>
+ - the process group ID of the process which currently owns the tty that
+ the process is connected to.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"TracerPID" : <i>&lt;int&gt;</i></font></b></code>
+ - ID of a process that has attached this process for tracing or debugging.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Flags" : <i>&lt;int&gt;</i></font></b></code>
+ - the kernel flags word of the process. Details depend on the kernel.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"MinFlt" : <i>&lt;int&gt;</i></font></b></code>
+ - the number of minor faults the process has made which have not
+ required loading a memory page from disk.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CMinFlt" : <i>&lt;int&gt;</i></font></b></code>
+ - the number of minor faults that the process's waited-for children have made.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"MajFlt" : <i>&lt;int&gt;</i></font></b></code>
+ - the number of major faults the process has made which have required
+ loading a memory page from disk.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CMajFlt" : <i>&lt;int&gt;</i></font></b></code>
+ - the number of major faults that the process's waited-for children
+ have made.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"UTime" : <i>&lt;int&gt;</i></font></b></code>
+ - the number of milliseconds that this process has been scheduled in user mode.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"STime" : <i>&lt;int&gt;</i></font></b></code>
+ - the number of milliseconds that this process has been scheduled in kernel mode.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CUTime" : <i>&lt;int&gt;</i></font></b></code>
+ - the number of jiffies that this process's waited-for children have
+ been scheduled in user mode.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CSTime" : <i>&lt;int&gt;</i></font></b></code>
+ - the number of jiffies that this process's waited-for children have
+ been scheduled in user mode.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Priority" : <i>&lt;int&gt;</i></font></b></code>
+ - the standard nice value.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Nice" : <i>&lt;int&gt;</i></font></b></code>
+ - the nice value.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ITRealValue" : <i>&lt;int&gt;</i></font></b></code>
+ - the time in milliseconds before the next SIGALRM is sent to the process
+ due to an interval timer.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"StartTime" : <i>&lt;int&gt;</i></font></b></code>
+ - the time in milliseconds the process started after system boot.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"VSize" : <i>&lt;int&gt;</i></font></b></code>
+ - virtual memory size in bytes.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"PSize" : <i>&lt;int&gt;</i></font></b></code>
+ - memory pages size in bytes.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"RSS" : <i>&lt;int&gt;</i></font></b></code>
+ - resident Set Size: number of pages the process has in real memory,
+ minus used for administrative purposes. This is just the pages which
+ count towards text, data, or stack space. This does not include
+ pages which have not been demand-loaded in, or which are swapped out.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"RLimit" : <i>&lt;int&gt;</i></font></b></code>
+ - current limit in bytes on the rss of the process.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CodeStart" : <i>&lt;int&gt;</i></font></b></code>
+ - the address above which program text can run.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CodeEnd" : <i>&lt;int&gt;</i></font></b></code>
+ - the address below which program text can run.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"StackStart" : <i>&lt;int&gt;</i></font></b></code>
+ - the address of the start of the stack.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Signals" : <i>&lt;int&gt;</i></font></b></code>
+ - the bitmap of pending signals.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"SigBlock" : <i>&lt;int&gt;</i></font></b></code>
+ - the bitmap of blocked signals.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"SigIgnore" : <i>&lt;int&gt;</i></font></b></code>
+ - the bitmap of ignored signals.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"SigCatch" : <i>&lt;int&gt;</i></font></b></code>
+ - the bitmap of caught signals.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"WChan" : <i>&lt;int&gt;</i></font></b></code>
+ - this is the "channel" in which the process is waiting. It is the
+ address of a system call, and can be looked up in a namelist if you
+ need a textual name.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"NSwap" : <i>&lt;int&gt;</i></font></b></code>
+ - number of pages swapped.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"CNSwap" : <i>&lt;int&gt;</i></font></b></code>
+ - cumulative NSwap for child processes.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ExitSignal" : <i>&lt;int&gt;</i></font></b></code>
+ - signal to be sent to parent when this process exits.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Processor" : <i>&lt;int&gt;</i></font></b></code>
+ - CPU number last executed on.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"RTPriority" : <i>&lt;int&gt;</i></font></b></code>
+ - real-time scheduling priority.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Policy" : <i>&lt;int&gt;</i></font></b></code>
+ - scheduling policy.
+</ul>
+
+<h3><a name='CmdGetChildren'>Get Children</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • SysMonitor • getChildren • <i>&lt;string: parent context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command requests a list of contexts available for System Monitor commands.</p>
+
+<p>Parent context ID can be null – to retrieve top level of the hierarchy, can be one
+of context IDs retrieved by previous getChildren commands, or it can be obtained from another service.
+Contexts hierarchy can be simple plain list or it can form a tree. It is up to target agent developers to
+choose layout that is most descriptive for a given target.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of context IDs&gt;</i> •
+
+<i>&lt;array of context IDs&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;context ID list&gt;</i> ]
+
+<i>&lt;context ID list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string: context ID&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;context ID list&gt;</i> , <i>&lt;string: context ID&gt;</i>
+</font></b></pre>
+
+<h3><a name='CmdGetCommandLine'>Get Command Line</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • SysMonitor • getCommandLine • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command requests a list of progess command line arguments.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of string&gt;</i> •
+
+<i>&lt;array of string&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> [ ]
+ <font face=Wingdings>Ø</font> [ <i>&lt;string list&gt;</i> ]
+
+<i>&lt;string list&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string list&gt;</i> , <i>&lt;string&gt;</i>
+</font></b></pre>
+
+<h3><a name='CmdGetEnvironment'>Get Environment</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • SysMonitor • getEnvironment • <i>&lt;string: context ID&gt;</i> •
+</font></b></pre>
+
+<p>The command requests a list of progess environment variables.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> • <i>&lt;array of string&gt;</i> •
+</font></b></pre>
+
+<h2><a name='Events'>Events</a></h2>
+
+<p>No events are currently defined for System Monitor service.</p>
+
+<h2><a name='API'>API</a></h2>
+
+<pre>
+<font color=#7F0055>public interface</font> ISysMonitor <font color=#7F0055>extends</font> IService {
+
+ <font color=#7F0055>static final</font> String NAME = "SysMonitor";
+
+ <font color=#3F5FBF>/**
+ * Retrieve context info for given context ID.
+ *
+ * <font color=#7F9FBF>@param</font> id – context ID.
+ * <font color=#7F9FBF>@param</font> done - callback interface called when operation is completed.
+ */</font>
+ IToken getContext(String id, DoneGetContext done);
+
+ <font color=#3F5FBF>/**
+ * Client callback interface for getContext().
+ */</font>
+ <font color=#7F0055>interface</font> DoneGetContext {
+ <font color=#3F5FBF>/**
+ * Called when contexts data retrieval is done.
+ * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+ * <font color=#7F9FBF>@param</font> context – context data.
+ */</font>
+ <font color=#7F0055>void</font> doneGetContext(IToken token, Exception error, SysMonitorContext context);
+ }
+
+ <font color=#3F5FBF>/**
+ * Retrieve children of given context.
+ *
+ * <font color=#7F9FBF>@param</font> parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getContext or getChildren commands.
+ * <font color=#7F9FBF>@param</font> done - callback interface called when operation is completed.
+ */</font>
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ <font color=#3F5FBF>/**
+ * Client callback interface for getChildren().
+ */</font>
+ <font color=#7F0055>interface</font> DoneGetChildren {
+ <font color=#3F5FBF>/**
+ * Called when contexts data retrieval is done.
+ * <font color=#7F9FBF>@param</font> error – error description if operation failed, null if succeeded.
+ * <font color=#7F9FBF>@param</font> context_ids – array of available context IDs.
+ */</font>
+ <font color=#7F0055>void</font> doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ <font color=#3F5FBF>/**
+ * Context property names.
+ */</font>
+ <font color=#7F0055>static final</font> String
+ <font color=#3F5FBF>/** The TCF context ID */</font>
+ PROP_ID = "ID",
+
+ <font color=#3F5FBF>/** The TCF parent context ID */</font>
+ PROP_PARENTID = "ParentID",
+
+ <font color=#3F5FBF>/** Current working directory of the process */</font>
+ PROP_CWD = "CWD",
+
+ <font color=#3F5FBF>/** The process's root directory (as set by chroot) */</font>
+ PROP_ROOT = "Root",
+
+ <font color=#3F5FBF>/** User ID of the process owner */</font>
+ PROP_UID = "UID",
+
+ <font color=#3F5FBF>/** Group ID of the process owner */</font>
+ PROP_UGID = "UGID",
+
+ <font color=#3F5FBF>/** User name of the process owner */</font>
+ PROP_USERNAME = "UserName",
+
+ <font color=#3F5FBF>/** Group name of the process owner */</font>
+ PROP_GROUPNAME = "GroupName",
+
+ <font color=#3F5FBF>/** System process ID */</font>
+ PROP_PID = "PID",
+
+ <font color=#3F5FBF>/** Executable file of the process */</font>
+ PROP_FILE = "File",
+
+ <font color=#3F5FBF>/** One character from the string "RSDZTW" where R is running, S is
+ * sleeping in an interruptible wait, D is waiting in uninterruptible
+ * disk sleep, Z is zombie, T is traced or stopped (on a signal), and W
+ * is paging.*/</font>
+ PROP_STATE = "State",
+
+ <font color=#3F5FBF>/** System ID of the parent process */</font>
+ PROP_PPID = "PPID",
+
+ <font color=#3F5FBF>/** The process group ID of the process */</font>
+ PROP_PGRP = "PGRP",
+
+ <font color=#3F5FBF>/** The session ID of the process */</font>
+ PROP_SESSION = "Session",
+
+ <font color=#3F5FBF>/** The tty the process uses */</font>
+ PROP_TTY = "TTY",
+
+ <font color=#3F5FBF>/** The process group ID of the process which currently owns the tty that
+ * the process is connected to. */</font>
+ PROP_TGID = "TGID",
+
+ <font color=#3F5FBF>/** ID of a process that has attached this process for tracing or debugging */</font>
+ PROP_TRACERPID = "TracerPID",
+
+ <font color=#3F5FBF>/** The kernel flags word of the process. Details depend on the kernel */</font>
+ PROP_FLAGS = "Flags",
+
+ <font color=#3F5FBF>/** The number of minor faults the process has made which have not
+ * required loading a memory page from disk */</font>
+ PROP_MINFLT = "MinFlt",
+
+ <font color=#3F5FBF>/** The number of minor faults that the process's waited-for children have made */</font>
+ PROP_CMINFLT = "CMinFlt",
+
+ <font color=#3F5FBF>/** The number of major faults the process has made which have required
+ * loading a memory page from disk */</font>
+ PROP_MAJFLT = "MajFlt",
+
+ <font color=#3F5FBF>/** The number of major faults that the process's waited-for children
+ * have made */</font>
+ PROP_CMAJFLT = "CMajFlt",
+
+ <font color=#3F5FBF>/** The number of milliseconds that this process has been scheduled in user mode */</font>
+ PROP_UTIME = "UTime",
+
+ <font color=#3F5FBF>/** The number of milliseconds that this process has been scheduled in kernel mode */</font>
+ PROP_STIME = "STime",
+
+ <font color=#3F5FBF>/** The number of jiffies that this process's waited-for children have
+ * been scheduled in user mode */</font>
+ PROP_CUTIME = "CUTime",
+
+ <font color=#3F5FBF>/** The number of jiffies that this process's waited-for children have
+ * been scheduled in user mode */</font>
+ PROP_CSTIME = "CSTime",
+
+ <font color=#3F5FBF>/** The standard nice value */</font>
+ PROP_PRIORITY = "Priority",
+
+ <font color=#3F5FBF>/** The nice value */</font>
+ PROP_NICE = "Nice",
+
+ <font color=#3F5FBF>/** The time in milliseconds before the next SIGALRM is sent to the process
+ * due to an interval timer */</font>
+ PROP_ITREALVALUE = "ITRealValue",
+
+ <font color=#3F5FBF>/** The time in milliseconds the process started after system boot */</font>
+ PROP_STARTTIME = "StartTime",
+
+ <font color=#3F5FBF>/** Virtual memory size in bytes */</font>
+ PROP_VSIZE = "VSize",
+
+ <font color=#3F5FBF>/** Memory pages size in bytes */</font>
+ PROP_PSIZE = "PSize",
+
+ <font color=#3F5FBF>/** Resident Set Size: number of pages the process has in real memory,
+ * minus used for administrative purposes. This is just the pages which
+ * count towards text, data, or stack space. This does not include
+ * pages which have not been demand-loaded in, or which are swapped out */</font>
+ PROP_RSS = "RSS",
+
+ <font color=#3F5FBF>/** Current limit in bytes on the rss of the process */</font>
+ PROP_RLIMIT = "RLimit",
+
+ <font color=#3F5FBF>/** The address above which program text can run */</font>
+ PROP_CODESTART = "CodeStart",
+
+ <font color=#3F5FBF>/** The address below which program text can run */</font>
+ PROP_CODEEND = "CodeEnd",
+
+ <font color=#3F5FBF>/** The address of the start of the stack */</font>
+ PROP_STACKSTART = "StackStart",
+
+ <font color=#3F5FBF>/** The bitmap of pending signals */</font>
+ PROP_SIGNALS = "Signals",
+
+ <font color=#3F5FBF>/** The bitmap of blocked signals */</font>
+ PROP_SIGBLOCK = "SigBlock",
+
+ <font color=#3F5FBF>/** The bitmap of ignored signals */</font>
+ PROP_SIGIGNORE = "SigIgnore",
+
+ <font color=#3F5FBF>/** The bitmap of caught signals */</font>
+ PROP_SIGCATCH = "SigCatch",
+
+ <font color=#3F5FBF>/** This is the "channel" in which the process is waiting. It is the
+ * address of a system call, and can be looked up in a name list if you
+ * need a textual name */</font>
+ PROP_WCHAN = "WChan",
+
+ <font color=#3F5FBF>/** Number of pages swapped */</font>
+ PROP_NSWAP = "NSwap",
+
+ <font color=#3F5FBF>/** Cumulative NSwap for child processes */</font>
+ PROP_CNSWAP = "CNSwap",
+
+ <font color=#3F5FBF>/** Signal to be sent to parent when this process exits */</font>
+ PROP_EXITSIGNAL = "ExitSignal",
+
+ <font color=#3F5FBF>/** CPU number last executed on */</font>
+ PROP_PROCESSOR = "Processor",
+
+ <font color=#3F5FBF>/** Real-time scheduling priority */</font>
+ PROP_RTPRIORITY = "RTPriority",
+
+ <font color=#3F5FBF>/** Scheduling policy */</font>
+ PROP_POLICY = "Policy";
+
+
+ <font color=#3F5FBF>/**
+ * A context corresponds to an execution thread, process, address space, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ */</font>
+ <font color=#7F0055>interface</font> SysMonitorContext {
+
+ <font color=#3F5FBF>/**
+ * Get context ID.
+ * Same as getProperties().get(“ID”)
+ */</font>
+ String getID();
+
+ <font color=#3F5FBF>/**
+ * Get parent context ID.
+ * Same as getProperties().get(“ParentID”)
+ */</font>
+ String getParentID();
+
+ <font color=#3F5FBF>/**
+ * Get process group ID.
+ * Same as getProperties().get(“PGRP”)
+ */</font>
+ <font color=#7F0055>long</font> getPGRP();
+
+ <font color=#3F5FBF>/**
+ * Get process ID.
+ * Same as getProperties().get(“PID”)
+ */</font>
+ <font color=#7F0055>long</font> getPID();
+
+ <font color=#3F5FBF>/**
+ * Get process parent ID.
+ * Same as getProperties().get(“PPID”)
+ */</font>
+ <font color=#7F0055>long</font> getPPID();
+
+ <font color=#3F5FBF>/**
+ * Get process TTY group ID.
+ * Same as getProperties().get(“TGID”)
+ */</font>
+ <font color=#7F0055>long</font> getTGID();
+
+ <font color=#3F5FBF>/**
+ * Get tracer process ID.
+ * Same as getProperties().get(“TracerPID”)
+ */</font>
+ <font color=#7F0055>long</font> getTracerPID();
+
+ <font color=#3F5FBF>/**
+ * Get process owner user ID.
+ * Same as getProperties().get(“UID”)
+ */</font>
+ <font color=#7F0055>long</font> getUID();
+
+ <font color=#3F5FBF>/**
+ * Get process owner user name.
+ * Same as getProperties().get(“UserName”)
+ */</font>
+ String getUserName();
+
+ <font color=#3F5FBF>/**
+ * Get process owner user group ID.
+ * Same as getProperties().get(“UGID”)
+ */</font>
+ <font color=#7F0055>long</font> getUGID();
+
+ <font color=#3F5FBF>/**
+ * Get process owner user group name.
+ * Same as getProperties().get(“GroupName”)
+ */</font>
+ String getGroupName();
+
+ <font color=#3F5FBF>/**
+ * Get process state.
+ * Same as getProperties().get(“State”)
+ */</font>
+ String getState();
+
+ <font color=#3F5FBF>/**
+ * Get process virtual memory size in bytes.
+ * Same as getProperties().get(“VSize”)
+ */</font>
+ <font color=#7F0055>long</font> getVSize();
+
+ <font color=#3F5FBF>/**
+ * Get process virtual memory page size in bytes.
+ * Same as getProperties().get(“PSize”)
+ */</font>
+ <font color=#7F0055>long</font> getPSize();
+
+ <font color=#3F5FBF>/**
+ * Get number of memory pages in process resident set.
+ * Same as getProperties().get(“RSS”)
+ */</font>
+ <font color=#7F0055>long</font> getRSS();
+
+ <font color=#3F5FBF>/**
+ * Get context executable file.
+ * Same as getProperties().get(“File”)
+ */</font>
+ String getFile();
+
+ <font color=#3F5FBF>/**
+ * Get context current file system root.
+ * Same as getProperties().get(“Root”)
+ */</font>
+ String getRoot();
+
+ <font color=#3F5FBF>/**
+ * Get context current working directory.
+ * Same as getProperties().get(“CWD”)
+ */</font>
+ String getCurrentWorkingDirectory();
+
+ <font color=#3F5FBF>/**
+ * Get all available context properties.
+ * @return Map 'property name' -> 'property value'
+ */</font>
+ Map&lt;String,Object&gt; getProperties();
+ }
+
+ <font color=#3F5FBF>/**
+ * Get context command line.
+ */</font>
+ IToken getCommandLine(String id, DoneGetCommandLine done);
+
+ <font color=#7F0055>interface</font> DoneGetCommandLine {
+ <font color=#7F0055>void</font> doneGetCommandLine(IToken token, Exception error, String[] cmd_line);
+ }
+
+ <font color=#3F5FBF>/**
+ * Get context environment variables.
+ */</font>
+ IToken getEnvironment(String id, DoneGetEnvironment done);
+
+ <font color=#7F0055>interface</font> DoneGetEnvironment {
+ <font color=#7F0055>void</font> doneGetEnvironment(IToken token, Exception error, String[] environment);
+ }
+}
+</pre>
+
+</body>
+</html>
diff --git a/docs/TCF Services.html b/docs/TCF Services.html
new file mode 100644
index 000000000..38377555c
--- /dev/null
+++ b/docs/TCF Services.html
@@ -0,0 +1,108 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework Services</title>
+</head>
+
+<body lang='EN-US'>
+
+<h1>Target Communication Framework Services</h1>
+
+<p>Copyright (c) 2007 Wind River Systems, Inc. Made available under the EPL v1.0
+<p>Direct comments, questions to the <a href="mailto:dsdp-tm-dev@eclipse.org">dsdp-tm-dev@eclipse.org</a> mailing list
+
+<h2>Table of Contents</h2>
+<ul>
+ <li><a href='#Overview'>Overview</a>
+ <li><a href='#Syntax'>Syntax Rules Notation</a>
+ <li><a href='#ErrorFormat'>Error Report Format</a>
+ <li><a href='#Services'>Services</a>
+</ul>
+
+<h2><a name='Overview'>Overview</a></h2>
+
+TCF communication model is based on the idea of services. A service is a group of related commands, events and semantics.
+For example, <a href='TCF Service - Memory.html'>Memory Service</a> defines group of command and events for
+reading and writing target memory.
+Service definitions are not part of the <a href='TCF Specification.html'>framework specification</a>, and new services
+are expected to be defined by developers of tools and target agents.
+Defenitions of standard services are provided to achieve certain level of compatibility between tools and targets.
+
+<h2><a name='Syntax'>Syntax Rules Notation</a></h2>
+
+<p>Format of the protocol messages is defined by syntax rules. Syntax is described
+using a simple variant of Backus-Naur Form. In particular:</p>
+
+<ul type='disc'>
+ <li>Italic lower case words in a courier font, enclosed into angular brackets, are
+ used to denote syntactic categories, for example:&nbsp;<b><i><font face="Courier New" size=2 color=#333399>&lt;token&gt;.
+ </font></i></b>Category name can be followed by colon and a text, which explains semantics
+ of the category, for example: <b><i><font face="Courier New" size=2 color=#333399>&lt;int:
+ error code&gt;</font></i></b> has same meaning as <b><i><font face="Courier New" size=2 color=#333399>&lt;int&gt;</font></i></b>,
+ but denotes that the integer number used to indicate an "error code".
+
+ <li>A syntax rule consists of a category designation followed by one or more syntax
+ definitions for the category. The category name and each definition are placed on
+ separate lines, bullets are used to denote definitions, for example:
+</ul>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;chars&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;char&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;chars&gt; &lt;char&gt;</i>
+</font></b></pre>
+
+<ul type='disc'>
+ <li>Spaces are added for readability only and they are not part of the syntax.
+
+ <li>All text in the category definition, other than categories and spaces, is UTF-8
+ based representation of a message bytes.
+
+ <li>The symbol ‘•’ designates a zero byte.
+</ul>
+
+<h2><a name='ErrorFormat'>Error Report Format</a></h2>
+
+<p>Most of TCF standard services use same format for error reporting:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;error report&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;int: error code&gt;</i> • <i>&lt;error description&gt;</i>
+</font></b></pre>
+
+<p>Error code zero means success. Error description provides a short, localizable,
+human readable explanation of error.</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;error description&gt;</i>
+ <font face=Wingdings>Ø</font> null
+ <font face=Wingdings>Ø</font> <i>&lt;string&gt;</i>
+ <font face=Wingdings>Ø</font> { "format" : <i>&lt;string&gt;</i> , "params" : [ <i>&lt;params&gt;</i> ] }
+
+<i>&lt;params&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;value&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;params&gt;</i> , <i>&lt;value&gt;</i>
+</font></b></pre>
+
+<p>For <b><i><font face="Courier New" size=2 color=#333399>&lt;string&gt;</font></i></b>
+and <b><i><font face="Courier New" size=2 color=#333399>&lt;value&gt;</font></i></b> encoding see
+<a href='TCF Specification.html#JSON'>JSON - Preferred Marshaling</a>.
+Error description format supports separation between constant and variable parts
+of the message ("format" and "params"). This is done to support localization. See
+Java class <b><font face="Courier New" size=2>java.text.MessageFormat</font></b> for details.</p>
+
+<h2><a name='Services'>Services</h2>
+<ul>
+ <li><a href='TCF Service - Memory.html'>Memory Service</a>
+ <li><a href='TCF Service - Processes.html'>Processes Service</a>
+ <li><a href='TCF Service - Run Control.html'>Run Control Service</a>
+ <li><a href='TCF Service - Registers.html'>Registers Service</a>
+ <li><a href='TCF Service - Stack Trace.html'>Stack Trace Service</a>
+ <li><a href='TCF Service - Breakpoints.html'>Breakpoints Service</a>
+ <li><a href='TCF Service - File System.html'>File System Service</a>
+ <li><a href='TCF Service - System Monitor.html'>System Monitor Service</a>
+</ul>
+
+</body>
+</html>
+ \ No newline at end of file
diff --git a/docs/TCF Specification Image1.png b/docs/TCF Specification Image1.png
new file mode 100644
index 000000000..85933f613
--- /dev/null
+++ b/docs/TCF Specification Image1.png
Binary files differ
diff --git a/docs/TCF Specification.html b/docs/TCF Specification.html
new file mode 100644
index 000000000..2aec03f3f
--- /dev/null
+++ b/docs/TCF Specification.html
@@ -0,0 +1,1407 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework Specification</title>
+</head>
+<body lang='EN-US'>
+
+<h1>Target Communication Framework Specification</h1>
+
+<p>Copyright (c) 2007 Wind River Systems, Inc. Made available under the EPL v1.0
+<p>Direct comments, questions to the <a href="mailto:dsdp-tm-dev@eclipse.org">dsdp-tm-dev@eclipse.org</a> mailing list
+
+<h1>Table of Contents</h1>
+
+<ul>
+ <li><a href='#Overview'>Overview</a>
+ <ul>
+ <li><a href='#Goals'>Goals</a>
+ <li><a href='#Definitions'>Definitions</a>
+ <li><a href='#Requirements'>Requirements</a>
+ <li><a href='#Syntax'>Syntax Rules Notation</a>
+ </ul>
+ <li><a href='#Design'>Framework Software Design Considerations</a>
+ <ul>
+ <li><a href='#Concurrency'>Concurrency</a>
+ <li><a href='#Reflection'>Reflection</a>
+ <li><a href='#Ordering'>Message ordering</a>
+ </ul>
+ <li><a href='#Transport'>Transport Layer</a>
+ <li><a href='#Protocol'>Communication Protocol</a>
+ <ul>
+ <li><a href='#ProtocolCommands'>Commands</a>
+ <li><a href='#ProtocolResults'>Results</a>
+ <li><a href='#ProtocolEvents'>Events</a>
+ <li><a href='#ProtocolFlowControl'>Flow Control</a>
+ <li><a href='#ProtocolExamples'>Examples</a>
+ </ul>
+ <li><a href='#API'>API</a>
+ <li><a href='#JSON'>JSON - Preferred Marshaling</a>
+ <ul>
+ <li><a href='#JSONExamples'>JSON - Examples</a>
+ </ul>
+ <li><a href='#Locator'>Locator Service</a>
+ <ul>
+ <li><a href='#LocatorPeer'>Peer Attributes</a>
+ <li><a href='#LocatorCommands'>Locator Service Commands</a>
+ <li><a href='#LocatorEvents'>Locator Service Events</a>
+ <li><a href='#LocatorAPI'>Locator Service API</a>
+ </ul>
+</ul>
+
+<h1><a name='Overview'>Overview</a></h1>
+
+<p>Today almost every device software development tool on the market has its own method
+of communication with target system. Communication methods often require individual setup,
+configuration and maintenance, impose unnecessary limitations.
+Target Communication Framework goal is to establish common ground in
+the area of communication protocols between development tools and embedded devices.</p>
+
+<p>The goal is a single protocol used to communicate between all tools and targets:</p>
+<p><img src='TCF Specification Image1.png'></p>
+
+<h2><a name='Goals'>Goals</a></h2>
+
+<ul type='disc'>
+ <li>Universal, simple, lightweight, vendor agnostic framework for tools and targets
+ to communicate for purpose of debugging, profiling, code patching and other device
+ software development needs.
+
+ <li>Single configuration per target (not per tool per target as today in most cases),
+ or no configuration when possible.
+
+ <li>Minimal overhead and footprint on target side.
+</ul>
+
+<h2><a name='Definitions'>Definitions</a></h2>
+
+<dl>
+<dt><b>Peer:</b> <dd>communication endpoint. Both hosts and targets are called peers. A
+peer can act as a client or a server depending on services it implements.
+
+<dt><b>Service:</b> <dd>group of related commands, events and semantic define a service.
+A service can be discovered, added or removed as a group at communication endpoint.
+
+<dt><b>Message:</b> <dd>a packet of data, formatted according to framework specification
+and transmitted over communication channel.
+
+<dt><b>Channel:</b> <dd>communication link connecting two endpoints (peers).  A single
+channel may be used to communicate with multiple services.  Multiple channels may
+be used to connect the same peers, however no command or event ordering is guaranteed
+across channels.
+
+<dt><b>Command:</b> <dd>command is a message sent to remote peer in order to request some
+predefined action there.
+
+<dt><b>Result:</b> <dd>result is a message sent as a response to a command.
+
+<dt><b>Event:</b> <dd>event is a message sent to all interested parties in order to notify
+them about state changes.
+</dl>
+
+<h2><a name='Requirements'>Requirements</a></h2>
+
+<ul type='disc'>
+ <li>Simple and extensible protocol.
+
+ <li>Small footprint on the target.
+
+ <li>Fully asynchronous, message based communication.
+
+ <li>Two ways of message routing:
+
+ <ul>
+ <li>Point to point request/response (command/result) communication.
+
+ <li>Subscription based broadcast of notifications (events).
+ </ul>
+
+ <li>Full duplex, symmetric communication: both host and target should be able to send
+ commands and events at same time, though ability to establish communication channel
+ can be limited to host only.
+
+ <li>For each communication channel between two peers, the framework should preserve
+ order of commands, results and events.
+
+ <li>Support for slow and high latency connections.
+
+ <li>Transport protocol agnostic. The framework should work well, at least, on top
+ of: TCP/IP, UDP, USB, RS232 and JTAG.
+
+ <li>The framework should support multiplexing, that is, single target device shared
+ between multiple tools at same time. To reduce footprint on the target, multiplexing
+ can be implemented on host if needed.
+
+ <li>Dynamic discovery of participating targets and hosts. No configuration when possible.
+
+ <li>Dynamic discovery of available services (high level protocols, command sets).
+ Clients can query for available services.
+
+ <li>Services can be added and removed dynamically.
+
+ <li>Framework should define a set of common high level interfaces (services).  For
+ example: flow control, memory access, registers access, up-load mechanism, kernel
+ awareness, run control, target file system, console, flash programming. Implementation
+ of these interfaces is optional, but if provided it will support much wider compatibility
+ with various tools.
+
+ <li>Framework should be layered in such a way so it is possible to use different transport
+ medias (e.g. TCP/IP, RS232, USB, etc) without any changes to individual services. 
+ In other words, transport implementation should be services agnostic, and services
+ implementation should be transport agnostic.
+
+ <li>Each service defines how marshalling is done for command, result and event arguments.
+ This allows existing target agents to remain unchanged.
+
+ <li>Framework should define a preferred marshalling mechanism that new services can
+ use.
+
+ <li>The definition of services (groups of related commands and events) is separate
+ from the definition of the framework itself.  The framework provides unified communication
+ mechanism, while services use it to communicate with its clients.
+
+ <li>Anybody (including 3rd parties) can add services without having to modify communication
+ protocol or framework software.
+
+ <li>The framework should support tunneling through a proxy. Proxy may be used, for
+ example:
+
+ <ul type='circle'>
+ <li>to bridge different transport protocols, like TCP and RS232;
+
+ <li>to make a RS232 or USB target connection accessible from multiple hosts;
+
+ <li>to access targets behind firewalls or otherwise not directly accessible
+ </ul>
+
+ <li>A proxy should be able to provide services in addition to those implemented by
+ a target. Such distribution of services allows target services to be implemented on
+ a host, thereby reducing the footprint on the target. For example, debug information,
+ stack back trace or OS awareness can be implemented by a proxy on a host. To provide
+ this functionality, proxy services would typically use low-level target services,
+ like memory access.
+
+ <li>Supports of concurrent requests. Maximum number of concurrent requests (window
+ size) can be limited on target side. Simple agents only have to support window size
+ of 1. Framework should maintain a queue of additional requests, so tools don’t need
+ to know the window size. This may only be relevant for certain transport protocols
+ e.g. UDP.
+
+ <li>Events can be broadcasted at any time, i.e. no polling should be required.
+
+ <li>Protocol should support a standard mechanism of sending data larger than MTU.
+</ul>
+
+<h2><a name='Syntax'>Syntax Rules Notation</a></h2>
+
+<p>Format of the protocol messages is defined by syntax rules. Syntax is described
+using a simple variant of Backus-Naur Form. In particular:</p>
+
+<ul type='disc'>
+ <li>Italic lower case words in a courier font, enclosed into angular brackets, are
+ used to denote syntactic categories, for example: <b><i><font face="Courier New" size=2 color=#333399>&lt;token&gt;.
+ </font></i></b>Category name can be followed by colon and a text, which explains semantics
+ of the category, for example: <b><i><font face="Courier New" size=2 color=#333399>&lt;int:
+ error code&gt;</font></i></b> has same meaning as <b><i><font face="Courier New" size=2 color=#333399>&lt;int&gt;</font></i></b>,
+ but denotes that the integer number used to indicate an “error code”.
+
+ <li>A syntax rule consists of a category designation followed by one or more syntax
+ definitions for the category. The category name and each definition are placed on
+ separate lines, bullets are used to denote definitions, for example:
+ <pre><b><font face="Courier New" size=2 color=#333399>
+ <i>&lt;chars&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;char&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;chars&gt; &lt;char&gt;</i>
+ </font></b></pre>
+
+ <li>Spaces are added for readability only and they are not part of the syntax.
+
+ <li>All text in the category definition, other then categories and spaces, is UTF-8
+ based representation of a message bytes.
+
+ <li>The symbol ‘•’ designates a zero byte.
+</ul>
+
+<h1><a name='Design'>Framework Software Design Considerations</a></h1>
+
+<p>The framework will be packaged, distributed and installed on a host as separate
+product. It should be installed as system service and require no configuration for
+most common case – target connected over TCP or UDP on a local network. For more complicated
+setup, framework should have easily accessible and user friendly GUI with all relevant
+configuration options.</p>
+
+<p>Framework should use a dynamic discovery protocol to locate targets and other hosts
+running instances of the framework when possible, and maintain a dynamic list of available
+communication endpoints, as well as lists of services available at each endpoint.
+Host discovery is needed to locate hosts able to proxy communications for targets,
+which are not accessible otherwise - for example, targets connected with RS232 or
+JTAG to a remote host. It should also be possible to add target configuration manually.
+Development tools will access this data through the Locator Service API and use it,
+for example, to present a user a list of available targets that have capabilities
+needed by a particular tool.</p>
+
+<p>Framework should provide software libraries to be used by tools and target agents
+developers. The libraries should be available at least for ANSI C and Java. On host
+side, at least Windows, Solaris and Linux must be supported. Libraries will provide
+APIs for low-level communication protocol, Locator Service, preferred marshaling and
+predefined common services.</p>
+
+<p>The proposed target communication protocol is text-based. It allows extensions,
+which define messages with blocks of binary data, but it is not a recommended data
+formatting, and its usage is supposed to be limited. Text-based protocols have both
+advantages and disadvantages in compare with binary protocols.</p>
+
+<p>Advantages:</p>
+
+<ul type='disc'>
+ <li>The software for text-based protocols is easier to develop and debug since they
+ use a relatively human-friendly communication.
+
+ <li>It is possible to use huge selection of existing tools and library routines to
+ view, edit, validate, and transform text-based data.
+
+ <li>Text based definition is in line with current trend in Internet protocols: most
+ popular protocols such as SMTP and HTTP are text-based.
+</ul>
+
+<p>Disadvantages:</p>
+
+<ul type='disc'>
+ <li>Text-based protocols usually need more bytes to store numerical data than binary
+ protocols do.
+
+ <li>Parsing of text-based data is not efficient compared to parsing of binary data
+ since text-based data is usually not stored in a way similar to how it is stored in
+ computer memory.
+
+ <li>It is seldom possible to read only part of a text-based message since the exact
+ byte offset to a data item is generally not known.
+</ul>
+
+<p>A possible alternative to consider is binary, variable length encoding like BaseStream.</p>
+
+<h2><a name='Concurrency'>Concurrency</a></h2>
+
+<p>Concurrent asynchronous communication is much faster then synchronous, because
+it alleviates communication channel latency and allows better bandwidth utilization.
+But it also requires proper design of framework software. Concurrency, in general,
+implies multithreading. However, systems developed with global multithreading, are
+often unreliable and prone to different kinds of thread synchronization problems,
+which are often very difficult to locate and resolve. We therefore strongly recommend
+that the software is designed to follow the compartment threading model, which simplifies
+thread synchronization and promotes reliable software design. In this model each thread
+execution path is strictly contained in predefined subset of code (compartment), and
+no code, except for reentrant libraries, is executed by multiple threads. Each compartment
+has a message queue and other threads communicate with the compartment thread by posting
+messages to the queue.</p>
+
+<p>Framework APIs are designed to be compatible with the compartment threading model.
+Hence the API functions do not contain any thread synchronization primitives to protect
+against multiple threads using the functions. All framework APIs belong to a single
+compartment and should be used by a single thread. The same thread is used to dispatch
+events and command results. Concurrency is achieved by declaring API functions to
+be asynchronous. Asynchronous functions do not have any return value, and returns
+immediately, most of the time before the intended job is done. They take additional
+arguments to specify a callback function and callback data. In object-oriented languages
+such as Java, this is typically done by a single callback object argument containing
+both the data and the function.  The result listener is called asynchronously when
+the job is done. This approach is commonly known as asynchronous<b>, </b>event-driven<b>
+</b>or<b> </b>callback-based<b> </b>programming<b>.</b></p>
+
+<p>One important characteristic of an asynchronous code is that the methods defined
+by the user will often be called from within the framework itself, rather than from
+the user's application code. The framework often plays the role of the main program
+in coordinating and sequencing application activity. This phenomenon is called Inversion
+of Control (also known as the Hollywood Principle - "Don't call us, we'll call you").</p>
+
+<h2><a name='Reflection'>Reflection</a></h2>
+
+<p>Communication between development tools and embedded devices must allow a host
+to collect target side data and build a reflection of target state. Reflection is
+usually incomplete – a subset of all remote data. Reflection is always delayed – it
+represents a remote peer state in the past. Reflection can be updated by polling for
+data changes or by listening to events (event is communication message that is sent
+asynchronously by a peer to notify others about state change). Reflection is correct
+if it represents a state that actually did happen on remote peer.</p>
+
+<p>Reflection is coherent if it is exactly equal to subset of peer state at a single
+moment of time and that moment of time is not too far in the past. Non-coherent reflection
+can have parts of data representing peer state at different moments of time. Coherent
+reflection is more valuable for a user, because non-coherent reflection can have logically
+conflicting data if that data was collected at different time.</p>
+
+<p>Traditionally, debuggers would ensure coherence of state reflection by collecting
+data only while target is suspended, and flushing all (or most) reflection data (reducing
+observed subset to zero) when target is resumed. This approach does not work well
+for multithreaded, multicore or real time targets. Maintaining correctness and coherence
+of a non-empty reflection while target is running requires additional support from
+target agent, communication software and debugger itself.</p>
+
+<p>Since remote peer state is changing over time, coherent reflection can be built
+only if:</p>
+
+<ul type='disc'>
+ <li>Observed subset of state is properly selected and dynamically re-selected. Observing
+ too much can overflow communication channel. Observing too little has little value
+ for a user.
+
+ <li>Observer is listening to all relevant events.
+
+ <li>Events are coming in exactly same order as corresponding changes happen.
+
+ <li>Events are properly ordered relative to other messages that carry state data.
+
+ <li>All changes in observed subset of peer state are reported by events.
+
+ <li>All event messages must either contain a complete description of a change or they
+ all should not contain any state data at all. If client is getting some data from
+ events and required to retrieve new values of other changed data by using other means
+ (commands), the reflection will not be coherent at least until such retrieval is complete.
+ And if such periods of data retrieval overlap, the reflection will never be coherent.
+ Sending deltas with events is usually more efficient then using data retrieval commands
+ to update reflection.
+</ul>
+
+<h2><a name='Ordering'>Message ordering</a></h2>
+
+<p>The transmission order of commands, results and events is important, it coveys
+valuable information about target state transitions and it should be preserved when
+possible. Consider an example:</p>
+
+<p>Client transmits: </p>
+
+<pre>
+ Command X=2
+</pre>
+
+<p>Then, as result of some activity of another client or the target itself, X is assigned
+value 3.</p>
+
+<p>Target transmits:</p>
+
+<pre>
+ Event X=3
+ Result X=2
+</pre>
+
+<p>Now client has to show value of X to a user. If the order of messages is preserved,
+the client will know that command was executed <i>after</i> X was assigned 3, the
+last message contains last known value of X and 2 is the correct value to show. If
+the target is allowed to transmit events and results in arbitrary order, the client
+will have no clue what to show – 2 or 3. In fact, the client will have to make a tough
+decision about each message it receives: either trust message data as correct last
+known target state, or assume the message came in out-of-order and ignore it, or re-request
+the information from the target.</p>
+
+<p>Note that re-requesting data from the target, in general, does not solve the problem
+of interpretation of messages when order is not preserved. For example, after sending
+a request to read value of X, X could change at about the same time, and client could
+receive:</p>
+
+<pre>
+ Event X=2
+ Result X=3
+ Event X=4
+</pre>
+
+<p>If order is not preserved, it is still impossible to tell which value of X is the
+last one. A client could assume value of X unknown every time it receives a notification
+of X change, and then re-request the data again. But this is expensive and, if events
+coming in frequently, client can end up in infinite loop re-requesting the data again
+and again, and it will never have trustworthy data about current target state.</p>
+
+<p>Developers should be careful when using multithreading or multiple queues in software
+design – it can easily cause message reordering.</p>
+
+<p>The framework itself is required to preserve message order. However, if for whatever
+reason a target agent cannot preserve message order, the result will be that clients
+of the service can receive messages in the wrong order. When this is the case it should
+be well documented, so tools developers are aware and can make the best of the situation.
+In most cases it will not cause any trouble, but there is no perfect way to restore
+actual sequence of events and maintain data coherency after ordering was lost, and
+in some cases it can severely impact tool functionality and user experience.</p>
+
+<h1><a name='Transport'>Transport Layer</a></h1>
+
+
+<p>Tools are required to be transport protocol agnostic, so most of the layer functionality
+is used internally by framework and is not exposed to clients. This layer maintains
+a collection of transport protocol handlers. Each handler is designed to provide:</p>
+
+<ul type='disc'>
+ <li>Enumeration of available peers, including both automatically discovered and manually
+ configured peers. Handler fires notification events when peers are added or removed.
+ Enumeration can be implemented by scanning JTAG chain, by broadcasting special UDP
+ packet and waiting for responses, by communicating with ICE hardware, or by any other
+ suitable means.
+
+ <li>Bidirectional point-to-point communication of data packets. Packets are arrays
+ of bytes of arbitrary size.
+ Transport handler and underlying protocol are responsible for adding all necessary
+ control data, headers, error checking bits, addresses, fragmentation/defragmentation,
+ flow control, transmission retries and whatever necessary to ensure lossless, order-preserving
+ delivery of packets.
+
+ <li>Configuration UI should allow user to inspect and modify properties of both manually
+ configured and automatically discovered peers, setup new peers, view connections status
+ and statistics.
+</ul>
+
+<p>Existing service discovery protocols can be used together with the framework, for
+example:</p>
+
+<ul type='disc'>
+ <li>Zero Configuration Networking (Zeroconf), see <a href='http://www.zeroconf.org/'>http://www.zeroconf.org</a>;
+
+ <li>Service Location Protocol (SLP), developed by the IETF;
+
+ <li>Jini, which is Sun’s Java-base approach to service discovery, see <a href='http://www.sun.com/jini'>http://www.sun.com/jini</a>;
+
+ <li>Salutation, developed by an open industry consortium, called the Salutation Consortium;
+
+ <li>Microsoft’s Universal Plug and Play (UPnP), see <a href='http://www.upnp.org/'>http://www.upnp.org</a>;
+
+ <li>Bluetooth Service Discovery Protocol (SDP).
+</ul>
+
+<p>Service discovery protocols, as well as transport protocols will be supported by
+framework plug-ins, they are not part of framework code itself, and they can be developed
+by 3rd parties. Note that existing discovery protocols define term “service” differently
+- as an independent communication endpoint (usually a TCP/IP port). In this document
+it is called “peer” (host, target, communication endpoint), and a peer can provide
+multiple services over single communication channel.</p>
+
+<p>Using of standard discovery protocols should be optional, because it can potentially
+cause conflict or interference between development tools and application being developed
+over a use of same standard protocol – devices software often includes implementation
+of service discovery protocols as part of application code to support their main functions.
+</p>
+
+<h1><a name='Protocol'>Communication Protocol</a></h1>
+
+<p>The communication protocol defines data packets properties and roles common for
+all services. The communication protocol API provides functions for opening and /closing
+of the communication channel for a particular peer, and for sending and receiving
+data packets. The protocol define contents of a part of a packet, the rest of the
+packet is treated as array of bytes at this level. The communication protocol implementation
+also provides:</p>
+
+<ul type='disc'>
+ <li>Multiplexing – opening multiple channels per peer.
+
+ <li>Proxy – packet forwarding in behalf of other hosts.
+</ul>
+
+<p>Protocol defines three packet types: commands (requests), results (responses),
+and events. Each packet consists of several protocol defined control fields followed
+by byte array of data. Binary representation of control fields is a sequence of zero
+terminated ASCII strings. Format of data array depends on a service. We recommend
+using framework preferred marshaling for data formatting.</p>
+
+<p>Syntax:</p>
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;message&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;command&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;result&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;event&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;flow control message&gt;</i>
+</font></b></pre>
+
+<h2><a name='ProtocolCommands'>Commands</a></h2>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;command&gt;</i>
+ <font face=Wingdings>Ø</font> C • <i>&lt;token&gt; </i>• <i>&lt;service name&gt; </i>• <i>&lt;command name&gt; </i>• <i>&lt;byte array: arguments&gt;</i>
+</font></b></pre>
+
+<p>Command packets start with string “C”.</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;token&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;chars&gt;</i>
+</font></b></pre>
+
+<p>Token is unique string generated by framework for each command. It is used to match
+results to commands.</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;service name&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;chars&gt;</i>
+</font></b></pre>
+
+<p>Service name is used to identify a service that handles the command, it is same
+string as returned by Service.getName().</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;command name&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;chars&gt;</i>
+</font></b></pre>
+
+<p>Command name interpretation depends on a service.</p>
+
+<p>A command should always be answered with result packed. Result does not have to
+be positive – it can include an error code, but there always must be one. Since client
+cannot detect that a response is missing, if for some reasons peer is not able to
+answer a command, it should consider such situation a fatal communication error and
+it must shutdown the communication channel. It is not necessary to wait for result
+before sending next command. In fact, sending multiple commands in a burst can greatly
+improve performance, especially when connection has high latency. At the same time,
+clients should be carefully designed to avoid flooding the communication channel with
+unlimited number of requests, since this will use resources in forms of memory to
+store the requests and time to process them.</p>
+
+<h2><a name='ProtocolResults'>Results</a></h2>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;result&gt;</i>
+ <font face=Wingdings>Ø</font> R • <i>&lt;token&gt;</i> • <i>&lt;byte array: result data&gt;</i>
+ <font face=Wingdings>Ø</font> P • <i>&lt;token&gt;</i> • <i>&lt;byte array: result data&gt;</i>
+</font></b></pre>
+
+<p>Result packets start with string “P” for intermediate result and “R” for final
+result. Receiving of “R” result concludes execution of corresponding command.
+There should be exactly one “R” result for each command. In addition, command execution can produce any number of
+intermediate “P” results. “P” results can be sent before “R”, and it can serve, for
+example, as command execution progress report when execution takes long time.</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;token&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;chars&gt;</i>
+</font></b></pre>
+
+<p>Token should match token field of one of the pending commands that produced the result.</p>
+
+<h2><a name='ProtocolEvents'>Events</a></h2>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;event&gt;</i>
+ <font face=Wingdings>Ø</font> E • <i>&lt;service name&gt;</i> • <i>&lt;event name&gt;</i> • <i>&lt;byte array: event data&gt;</i>
+</font></b></pre>
+
+<p>Event packets start with string “E”.</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;service name&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;chars&gt;</i>
+</font></b></pre>
+
+<p>Service name identifies a service that fired event, same string as returned by
+Service.getName().</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;event name&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;chars&gt;</i>
+</font></b></pre>
+
+<p>Event name meaning depends on a service.</p>
+
+<p>Events are used to notify clients about changes in peer state. Services should
+provide sufficient variety of events for clients to track remote peer state without
+too much of polling. Clients, interested in a particular aspect of the target state,
+should have a “reflection” (or “model”) of that state and update the reflection by
+listening for relevant events. If a service implements a command that changes a particular
+aspect of peers state, then, normally, it should also generate notifications event
+when that same part of the state changes and it should provide a command to retrieve
+current value of the state – to be used by clients to initialize the reflection. Service
+events are defined statically, together with commands. The framework does not do any
+event processing besides delivering them to clients, however a service can define
+additional event related functionality if necessary, for example, commands for event
+filtering, enabling, disabling, registration, etc. Care should be taken when designing
+events for a service - if events are sent too frequently, they will cause flooding
+of the communication channels and degrade performance. However, too few events will
+force clients to poll for changes and can also degrade performance. A balanced approach
+is the best.</p>
+
+<h2><a name='ProtocolFlowControl'>Flow Control</a> </h2>
+
+<p>It often happens that one side of communication channel produces messages faster
+then they can be transmitted over the channel or can be consumed by another side.
+This will cause channel traffic congestion (flooding). Framework will deal with the
+problem and slow down transmitting side by blocking execution inside sendEvent(),
+sendCommand() and sendResult() functions when message buffers are full. However, in
+many cases, it is not the best way to handle congestion. For example, it can make
+a tool UI appear locked for prolonged time or it can break target software if it is
+designed to work in real time. Clients can use flow control events to implement advanced
+techniques to handle traffic congestion, for example, message coalescing, switching
+to less detailed messages, etc.</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;flow control message&gt;</i>
+ <font face=Wingdings>Ø</font> F • <i>&lt;int: traffic congestion level&gt;</i> •
+</font></b></pre>
+
+<p>Traffic congestion level value is in range –100..100, where –100 means no pending
+messages (no traffic), 0 means optimal load, and positive numbers
+indicate level of congestion. When a peer receives flow control message with congestion level > 0
+it should try to reduce its transmition speed.</p>
+
+<h2><a name='ProtocolExamples'>Message Examples</a></h2>
+
+<p>Examples use simplified command arguments and result data. See service description
+for actual data formats.</p>
+
+<p>Executing <b><i>suspend</i></b> command from <b><i>RunControl</i></b> service:</p>
+
+<p>&nbsp;</p>
+
+<pre>
+Send   :      C 1 RunControl suspend “Thread1”
+Receive:      E RunControl suspended “Thread1”
+Receive:      R 1 “Success”
+</pre>
+
+<p>Same command, but target was already suspended:</p>
+
+<pre>
+Receive:      E RunControl suspended “Thread1”
+…
+Send   :      C 2 RunControl suspend “Thread1”
+Receive:      R 2 “Already suspended”
+</pre>
+
+<p>Same command, but target was suspended (by another client) after sending the command,
+but before command was executed: </p>
+
+<pre>
+Receive:      E RunControl running “Thread1”
+…
+Send   :      C 3 RunControl suspend “Thread1”
+Receive:      E RunControl suspended “Thread1”
+Receive:      R 3 “Already suspended”
+</pre>
+
+<h2><a name='API'>Framework API</a></h2>
+
+<pre>
+<font color=#3F5FBF>/**
+ *
+ * Class Protocol provides static methods to access Target Communication Framework root objects:
+ * 1. the framework event queue and dispatch thread;
+ * 2. local instance of Locator service, which maintains a list of available targets;
+ * 3. list of open communication channels.
+ */</font>
+<font color=#7F0055>public class</font> Protocol {
+    
+    <font color=#7F0055>private static</font> IEventQueue <i>event_queue</i>;
+    
+    <font color=#3F5FBF>/**
+ * Before TCF can be used it should be given an object implementing IEventQueue interface.
+ * The implementation maintains a queue of objects implementing Runnable interface and
+ * executes <code>run</code> methods of that objects in a sequence by a single thread.
+ * The thread in referred as TCF event dispatch thread. Objects in the queue are called TCF events.
+ * Executing <code>run</code> method of an event is also called dispatching of event.
+ *
+ * Only few methods in TCF APIs are thread safe - can be invoked from any thread.
+ * If a method description does not say "can be invoked from any thread" explicitly -
+ * the method must be invoked from TCF event dispatch thread. All TCF listeners are
+ * invoked from the dispatch thread.
+ *
+ * <font color=#7F9FBF>@param</font> event_queue - IEventQueue implementation.
+     */</font>
+    <font color=#7F0055>public static void</font> setEventQueue(IEventQueue event_queue);
+   
+    <font color=#3F5FBF>/**
+     * <font color=#7F9FBF>@return</font> instance of IEventQueue that should be used for TCF events.
+     */</font>
+    <font color=#7F0055>public static</font> IEventQueue getEventQueue();
+   
+    <font color=#3F5FBF>/**
+     * Returns true if the calling thread is TCF dispatch thread.
+     * Use this call to ensure that a given task is being executed (or not being)
+     * on dispatch thread.
+     * This method is thread-safe.
+     *
+     * <font color=#7F9FBF>@return</font> true if running on the dispatch thread.
+     */</font>
+    <font color=#7F0055>public static boolean</font> isDispatchThread();
+   
+    <font color=#3F5FBF>/**
+     * Causes runnable to have its run
+     * method called in the dispatch thread of the framework.
+     * Runnables are dispatched in same order as queued.
+ * If invokeLater is called from the dispatching thread
+ * the <i>runnable.run()</i> will still be deferred until
+ * all pending events have been processed.
+ *
+ * This method can be invoked from any thread.
+     *
+     * <font color=#7F9FBF>@param runnable</font> the Runnable whose run
+     * method should be executed asynchronously.</font>
+     */</font>
+    <font color=#7F0055>public static void</font> invokeLater(Runnable runnable);
+   
+    <font color=#3F5FBF>/**
+     * Causes runnable to have its run
+     * method called in the dispatch thread of the framework.
+     * Calling thread is suspended util the method is executed.
+     * This method is thread-safe.
+     *
+     * <font color=#7F9FBF>@param runnable</font> the Runnable whose run
+     * method should be executed on dispatch thread.
+     */</font>
+    <font color=#7F0055>public static void</font> invokeAndWait(Runnable runnable)
+        <font color=#7F0055>throws</font> InterruptedException;
+   
+    <font color=#3F5FBF>/**
+ * Get instance of the framework locator service.
+ * The service can be used to discover available remote peers.
+ *
+ * @return instance of ILocator.
+     */</font>
+ <font color=#7F0055>public static</font> ILocator getLocator();
+
+    <font color=#3F5FBF>/**
+ * Return an array of all open channels.
+ * @return an array of IChannel
+     */</font>
+ <font color=#7F0055>public static</font> IChannel[] getOpenChannels();
+
+    <font color=#3F5FBF>/**
+ * Interface to be implemented by clients willing to be notified when
+ * new TCF communication channel is opened.
+     */</font>
+ <font color=#7F0055>public interface</font> ChannelOpenListener {
+ <font color=#7F0055>public void</font> onChannelOpen(IChannel channel);
+ }
+
+    <font color=#3F5FBF>/**
+ * Add a listener that will be notified when new channel is opened.
+ * @param listener
+     */</font>
+ <font color=#7F0055>public static void</font> addChannelOpenListener(ChannelOpenListener listener);
+
+    <font color=#3F5FBF>/**
+ * Remove channel opening listener.
+ * @param listener
+     */</font>
+ <font color=#7F0055>public static void</font> removeChannelOpenListener(ChannelOpenListener listener);
+
+    <font color=#3F5FBF>/**
+ * Transmit TCF event message.
+ * The message is sent to all open communication channels – broadcasted.
+     */</font>
+ <font color=#7F0055>public static void</font> sendEvent(String service, String name, byte[] data);
+
+    <font color=#3F5FBF>/**
+ * Call back after TCF messages sent by this host up to this moment are delivered
+ * to their intended target. This method is intended for synchronization of messages
+ * across multiple channels.
+ *
+ * Note: Cross channel synchronization can reduce performance and throughput.
+ * Most clients don't need cross channel synchronization and should not call this method.
+ *
+ * @param done will be executed by dispatch thread after communication
+ * messages are delivered to corresponding targets.
+     */</font>
+ <font color=#7F0055>public static void</font> sync(Runnable done);
+}
+
+<font color=#3F5FBF>/**
+ * IChannel represents communication link connecting two endpoints (peers).
+ * The channel asynchroniously transmits messages: commands, results and events.
+ * A single channel may be used to communicate with multiple services.
+ * Multiple channels may be used to connect the same peers, however no command or event
+ * ordering is guaranteed across channels.
+ */</font>
+<font color=#7F0055>public interface</font> IChannel {
+   
+    <font color=#3F5FBF>/**
+     * Channel state IDs
+     */</font>
+    <font color=#7F0055>static final</font> int
+        <i><font color=#0000C0>STATE_OPENNING</font></i> = 0,
+        <i><font color=#0000C0>STATE_OPEN</font></i> = 1,
+        <i><font color=#0000C0>STATE_CLOSED</font></i> = 2;
+   
+    <font color=#3F5FBF>/**
+     * <font color=#7F9FBF>@return</font> channel current state, see STATE_*
+     */</font>
+    int getState();
+
+    <font color=#3F5FBF>/**
+     * Send command message to remote peer for execution. Commands can be queued
+     * locally before transmission. Sending commands too fast can fill up
+     * communication channel buffers. Calling thread will be blocked until
+     * enough buffer space is freed up by transmitting pending messages.
+     */</font>
+    IToken sendCommand(IService service, String name, <font color=#7F0055>byte</font>[] args,
+        ICommandListener done);
+
+    <font color=#3F5FBF>/**
+     * Command listener interface. Clients implement this interface
+     * to receive command results.
+     */</font>
+    <font color=#7F0055>interface</font> ICommandListener {
+       
+        <font color=#3F5FBF>/**
+         * Called when progress message (intermediate result) is received
+         * from remote peer.
+         */</font>
+        <font color=#7F0055>void</font> progress(<font color=#7F0055>byte</font>[] data);
+       
+        <font color=#3F5FBF>/**
+         * Called when command result received from remote peer.
+         */</font>
+        <font color=#7F0055>void</font> result(<font color=#7F0055>byte</font>[] data);
+    }
+
+    <font color=#3F5FBF>/**
+     * Send result message to remote peer. Messages can be queued locally before
+     * transmission. Sending messages too fast can fill up communication channel
+     * buffers. Calling thread will be blocked until enough buffer space is
+     * freed up by transmitting pending messages.
+     */</font>
+    <font color=#7F0055>void</font> sendResult(IToken token, <font color=#7F0055>byte</font>[] results);
+
+    <font color=#3F5FBF>/**
+     * Get current level of outbound traffic congestion.
+     *
+     * <font color=#7F9FBF>@return</font> integer value in range –100..100, where –100 means no pending
+     * messages (no traffic), 0 means optimal load, and positive numbers
+     * indicate level of congestion.
+     *
+     * Note: inbound traffic congestion is detected by framework and reported to
+     * remote peer without client needed to be involved.
+     */</font>
+    int getCongestion();
+
+    <font color=#3F5FBF>/**
+     * Channel listener interface.
+     */</font>
+    <font color=#7F0055>interface</font> IChannelListener {
+
+        <font color=#3F5FBF>/**
+         * Notifies listeners about congestion level changes. When level &gt; 0
+         * client should delay sending more messages.
+         */</font>
+        <font color=#7F0055>void</font> congestionLevel(int level);
+    }
+
+    <font color=#3F5FBF>/**
+     * Subscribe a channel listener. The listener will be notified about changes of
+     * outbound traffic congestion level.
+     */</font>
+    <font color=#7F0055>void</font> addChannelListener(IChannelListener listener);
+
+    <font color=#3F5FBF>/**
+     * Remove a channel listener.
+     */</font>
+    <font color=#7F0055>void</font> removeChannelListener(IChannelListener listener);
+
+    <font color=#3F5FBF>/**
+     * Command server interface.
+     * This interface is to be implemented by service providers.
+     */</font>
+    <font color=#7F0055>interface</font> ICommandServer {
+
+        <font color=#3F5FBF>/**
+         * Called every time a command is received from remote peer.
+         */</font>
+        <font color=#7F0055>void</font> command(IToken token, String name, <font color=#7F0055>byte</font>[] data);
+    }
+   
+    <font color=#3F5FBF>/**
+     * Subscribe a command server. The server will be notified about command
+     * messages received through this channel for given service.
+     */</font>
+    <font color=#7F0055>void</font> addCommandServer(IService service, ICommandServer listener);
+
+    <font color=#3F5FBF>/**
+     * Remove a command server.
+     */</font>
+    <font color=#7F0055>void</font> removeCommandServer(IService service, ICommandServer listener);
+
+ <font color=#3F5FBF>/**
+     * A generic interface for service event listener.
+     * Services usually define a service specific event listener interface,
+     * which is implemented using this generic listener.
+     * Service clients should use service specific listener interface,
+     * unless no such interface is defined.
+     */</font>
+    <font color=#7F0055>interface</font> IEventListener {
+        <font color=#7F0055>void</font> event(String name, <font color=#7F0055>byte</font>[] data);
+    }
+
+    <font color=#3F5FBF>/**
+     * Subscribe an event message listener for given service.
+     */</font>
+    <font color=#7F0055>void</font> addEventListener(IService service, IEventListener listener);
+
+    <font color=#3F5FBF>/**
+     * Unsubscribe an event message listener for given service.
+     */</font>
+    <font color=#7F0055>void</font> removeEventListener(IService service, IEventListener listener);
+
+ <font color=#3F5FBF>/**
+     * <font color=#7F9FBF>@return</font> IPeer object representing local endpoint of communication channel.
+     */</font>
+    IPeer getLocalPeer();
+
+    <font color=#3F5FBF>/**
+     * <font color=#7F9FBF>@return</font> IPeer object representing remote endpoint of communication channel.
+     */</font>
+    IPeer getRemotePeer();
+
+    <font color=#3F5FBF>/**
+     * <font color=#7F9FBF>@return</font> map of services available on local peer. It maps service names to
+     * IService implemetations.
+     */</font>
+    Map&lt;String, IService&gt; getLocalServices();
+
+    <font color=#3F5FBF>/**
+     * <font color=#7F9FBF>@return</font> map of services available on removte peer. It maps service names to
+     * IService implemetations.
+     */</font>
+    Map&lt;String, IService&gt; getRemoteServices();
+
+    <font color=#3F5FBF>/**
+     * Close communication channel.
+     */</font>
+    <font color=#7F0055>void</font> close();
+
+    <font color=#3F5FBF>/**
+     * Close channel in case of communication error.
+     * <font color=#7F9FBF>@param error</font>
+     */</font>
+    <font color=#7F0055>void</font> terminate(Throwable error);
+   
+    <font color=#3F5FBF>/**
+     * Redirect this channel to given peer using this channel remote peer
+     * locator service as a proxy.
+     * <font color=#7F9FBF>@param peer_id</font>
+     */</font>
+    <font color=#7F0055>void</font> redirect(String peer_id);
+}
+
+
+<font color=#3F5FBF>/**
+ * Object implemeting IToken interface is created by framework for every
+ * command sent over communication channel. It is used to match command to its
+ * results, and also can be used to cancel commands.
+ */</font>
+<font color=#7F0055>public</font> interface IToken {
+   
+    <font color=#3F5FBF>/**
+     * Try to cancel a command associated with given token. A command can be
+     * canceled by this method only if it was not transmitted yet to remote peer
+     * for execution. Successfully canceled command does not produce any result
+     * messages.
+     *
+     * <font color=#7F9FBF>@return</font> true if successful.
+     */</font>
+    <font color=#7F0055>boolean</font> cancel();
+}
+
+</pre>
+
+<h1><a name='JSON'>Preferred Marshaling</a></h1>
+
+<p>TCF messages data format is service specific. Since services specifications are
+separate from protocol specification, a service designer can choose any data format that
+suits the service requirements best. However, to promote better compatibility and to
+simplify service design and implementation, we recommend to use <b>JSON</b> for data formatting.</p>
+
+<p><b>JSON</b> (pronounced like the
+English given name <i>Jason</i>), which stands for "<b>J</b>ava<b>S</b>cript <b>O</b>bject
+<b>N</b>otation", is a lightweight, text-based, language-independent computer data
+interchange format. <b>JSON</b> is a subset of the object literal notation of JavaScript
+but its use does not require JavaScript.</p>
+
+<p><b>JSON</b> represents data with the same basic types that programming languages
+use. <b>JSON</b>'s basic types are:</p>
+
+<ul type='disc'>
+ <li>Number (integer, real, or floating-point)
+
+ <li>String (double-quoted with backslash escapement)
+
+ <li>Boolean (<code>true</code> and <code>false</code>)
+
+ <li>Array (an ordered sequence of values)
+
+ <li>Object (collection of key/value pairs)
+
+ <li><code>null</code>
+ </ul>
+
+<p>The structures used in most programming languages easily map directly onto JSON's
+structures, and back again.</p>
+
+<p>JSON maps data onto Unicode string. Then the string is mapped onto array of bytes
+using UTF-8 encoding.</p>
+
+<p>JSON specification:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+<i>&lt;object&gt;</i>
+ <font face=Wingdings>Ø</font> {}
+ <font face=Wingdings>Ø</font> { <i>&lt;members&gt;</i> }
+<i>&lt;members&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string&gt;</i> : <i>&lt;value&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;members&gt;</i> , <i>&lt;string&gt;</i> : <i>&lt;value&gt;</i>
+
+<i>&lt;array&gt;</i>
+ <font face=Wingdings>Ø</font> []
+ <font face=Wingdings>Ø</font> [ <i>&lt;elements&gt;</i> ]
+
+<i>&lt;elements&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;value&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;elements</i>&gt; , <i>&lt;value&gt;</i>
+
+<i>&lt;value&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;string&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;number&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;object&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;array&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;boolean&gt;</i>
+ <font face=Wingdings>Ø</font> null
+
+<i>&lt;boolean&gt;</i>
+ <font face=Wingdings>Ø</font> true
+ <font face=Wingdings>Ø</font> false
+
+<i>&lt;string&gt;</i>
+ <font face=Wingdings>Ø</font> ""
+ <font face=Wingdings>Ø</font> " <i>&lt;chars&gt;</i> "
+
+<i>&lt;chars&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;char&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;chars&gt; &lt;char&gt;</i>
+
+<i>&lt;char</i>&gt;
+ <font face=Wingdings>Ø</font> <i>&lt;any Unicode except " or \ or control&gt;</i>
+ <font face=Wingdings>Ø</font> \"<i></i>
+ <font face=Wingdings>Ø</font> \\<i></i>
+ <font face=Wingdings>Ø</font> \/<i></i>
+ <font face=Wingdings>Ø</font> \b<i></i>
+ <font face=Wingdings>Ø</font> \f<i></i>
+ <font face=Wingdings>Ø</font> \n<i></i>
+ <font face=Wingdings>Ø</font> \r<i></i>
+ <font face=Wingdings>Ø</font> \t<i></i>
+ <font face=Wingdings>Ø</font> \u <i>&lt;four-hex-digits&gt;</i>
+
+<i>&lt;number</i>&gt;
+ <font face=Wingdings>Ø</font> <i>&lt;int&gt;</i>
+ <font face=Wingdings>Ø</font> &lt;<i>int&gt; &lt;fraction&gt;</i>
+ <font face=Wingdings>Ø</font> &lt;<i>int&gt; &lt;exponent&gt;</i>
+ <font face=Wingdings>Ø</font> &lt;<i>int&gt; &lt;fraction&gt; &lt;exponent&gt;</i>
+<i>&lt;int&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;digit&gt;</i>
+ <font face=Wingdings>Ø</font> &lt;<i>digit 1-9&gt; &lt;digits&gt;</i>
+ <font face=Wingdings>Ø</font> - &lt;<i>digit&gt;</i>
+ <font face=Wingdings>Ø</font> - &lt;<i>digit 1-9&gt; &lt;digits</i>&gt;
+
+<i>&lt;fraction&gt;</i>
+ <font face=Wingdings>Ø</font> . <i>&lt;digits&gt;</i>
+
+<i>&lt;exponent&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;e&gt;</i> <i>&lt;digits&gt;</i>
+
+<i>&lt;digits&gt;</i>
+ <font face=Wingdings>Ø</font> <i>&lt;digit&gt;</i>
+ <font face=Wingdings>Ø</font> &lt;<i>digits&gt;</i> &lt;<i>digit&gt;</i>
+
+<i>&lt;e&gt;</i>
+ <font face=Wingdings>Ø</font> e
+ <font face=Wingdings>Ø</font> e+
+ <font face=Wingdings>Ø</font> e-
+ <font face=Wingdings>Ø</font> E
+ <font face=Wingdings>Ø</font> E+
+ <font face=Wingdings>Ø</font> E-
+
+</font></b></pre>
+
+<p>See <a href='http://www.json.org/'>www.json.org</a> for more details.</p>
+
+<h2><a name='JSONExamples'>Examples</a></h2>
+
+<p>This is a JSON array containing two objects:</p>
+
+<pre>
+   [
+       {
+          "Precision": "zip",
+          "Latitude":  37.7668,
+          "Longitude": -122.3959,
+          "City":      "SAN FRANCISCO",
+          "State":     "CA",
+          "Zip":       "94107",
+          "Country":   "US"
+       },
+       {
+          "Precision": "zip",
+          "Latitude":  37.371991,
+          "Longitude": -122.026020,
+          "City":      "SUNNYVALE",
+          "State":     "CA",
+          "Zip":       "94085",
+          "Country":   "US"
+       }
+   ]
+</pre>
+
+<h1><a name='Locator'>Locator Service</a></h1>
+
+<p>Locator Service uses transport layer to search for peers and to collect data about
+peer’s attributes and capabilities (services).  Discovery mechanism depends on transport
+protocol and is part of that protocol handler. Targets, known by other hosts, are
+added to local list of peers. <font color=red>Security? </font>Automatically discovered
+targets require no further configuration. Additional targets can be configured manually.</p>
+
+<p>All TCF peers must implement Locator service. The implementation is part of the framework itself.
+It is the only required service, all other services are optional and, formally, not part of the framework.</p>
+
+<h2><a name='LocatorPeer'>Peer Atributes</a></h2>
+
+<p><i>&lt;object: peer data&gt;</i> is collection of peer attributes. It should, at least, contain member
+<b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;</i></font></b>.
+It can also contain a number of components describing peer properties and capabilities.
+Predefined attributes are:</p>
+
+<ul>
+ <li><code><b><font face="Courier New" size=2 color=#333399>"ID" : <i>&lt;string&gt;</i></font></b></code>
+ - ID of the peer.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Name" : <i>&lt;string&gt;</i></font></b></code>
+ - human readable peer name.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"OSName" : <i>&lt;string&gt;</i></font></b></code>
+ - peer OS name, if applicable.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"TransportName" : <i>&lt;string&gt;</i></font></b></code>
+ - name of a trasport protocol to use to connect to this peer, for example: TCP.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Host" : <i>&lt;string&gt;</i></font></b></code>
+ - peer host name, if transport is TCP or UDP.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Aliases" : <i>&lt;string&gt;</i></font></b></code>
+ - peer host name aliases, if transport is TCP or UDP.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Addresses" : <i>&lt;string&gt;</i></font></b></code>
+ - peer IP addresses, if transport is TCP or UDP.
+
+ <li><code><b><font face="Courier New" size=2 color=#333399>"Port" : <i>&lt;string&gt;</i></font></b></code>
+ - peer port number, if transport is TCP or UDP.
+</ul>
+
+<p>Most clients dont need to know peer attributes other then ID and Name. Clients are expected to call IPeer.openChannel()
+method and let the framework to check peers attributes and create appropriate communication cahnnel that is best suited for
+communication with the peer. After a channel is established, a client can learn peer capabilities by looking
+at services it implements (use IChannel.getRemoteServices() method to get a map of services).</p>
+
+<h2><a name='LocatorCommands'>Locator Service Commands</a></h2>
+
+<h3><a name='LocatorCommandRedirect'>redirect</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Locator • redirect • <i>&lt;string: peer ID&gt;</i> •
+</font></b></pre>
+
+<p>The command redirects the channel to become connected to given peer.
+Locator service starts acting as a proxy.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> • <i>&lt;error report&gt;</i> •
+</font></b></pre>
+
+<h3><a name='LocatorCommandSync'>sync</a></h3>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+C • <i>&lt;token&gt;</i> • Locator • sync •
+</font></b></pre>
+
+<p>Sync command does nothing and simply returns back an empty result. The command is used for
+cross channel synchronization. Since commands are executed in order they were issued, by waiting
+for sync result a client makes sure that all commands, that were issued before sync, are fully processed.</p>
+
+<p>Reply:</p>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+R • <i>&lt;token&gt;</i> •
+</font></b></pre>
+
+<h2><a name='LocatorEvents'>Locator Service Events</a></h2>
+
+<pre><b><font face="Courier New" size=2 color=#333399>
+E • Locator • Hello • <i>&lt;array: service names&gt;</i> •
+E • Locator • peerAdded • <i>&lt;object: peer data&gt;</i> •
+E • Locator • peerChanged • <i>&lt;object: peer data&gt;</i> •
+E • Locator • peerRemoved • <i>&lt;string: peer ID&gt;</i> •
+</font></b></pre>
+
+<dl>
+ <dt><b>Hello</b>
+ <dd>is the first message sent by the framework after establishing a communication channel.
+ The message lets other side of the channel to know capabilities of this peer.
+ Message data consists of an array of service names that are provided by the peer.
+ Service names list is a complete and unambiguous declaration of peer's capabilities.
+ To avoid ambiguity, different services (even slightly different, like versions of same service)
+ must have different names. Framework delays all other communications between peers until exchange
+ of Hello messages is complete.
+ <dt><b>peerAdded</b>
+ <dd>is sent when the service discovers a new peer.
+ <dt><b>peerChanged</b>
+ <dd>is sent when peer attributes change.
+ <dt><b>peerRemoved</b>
+ <dd>is sent when the service deletes information about a peer.
+</dl>
+
+<h2><a name='LocatorAPI'>Locator Service API</a></h2>
+
+<pre>
+<font color=#3F5FBF>/**
+ * Base interface for all service interfaces.
+ * A client can get list of available services by
+ * calling IPeer.getLocalServices or IPeer.getRemoteServives
+ */</font>
+<font color=#7F0055>public</font> interface IService {
+
+    <font color=#3F5FBF>/**
+     * Get unique name of this service.
+     */</font>
+    String getName();
+}
+
+<font color=#3F5FBF>/**
+ * Both hosts and targets are represented by objects
+ * implementing IPeer interface. A peer can act as host or
+ * target depending on services it implements.
+ * List of currently known peers can be retrieved by
+ * calling ILocator.getPeers
+ */</font>
+<font color=#7F0055>public interface</font> IPeer {
+   
+    <font color=#7F0055>static final</font> String
+        <i><font color=#0000C0>ATTR_ID</font></i> = <font color=#2A00FF>"ID"</font>,
+        <i><font color=#0000C0>ATTR_NAME</font></i> = <font color=#2A00FF>"Name"</font>,
+        <i><font color=#0000C0>ATTR_OS_NAME</font></i> = <font color=#2A00FF>"OSName"</font>,
+        <i><font color=#0000C0>ATTR_TRANSPORT_NAME</font></i> = <font color=#2A00FF>"TransportName"</font>,
+        <i><font color=#0000C0>ATTR_IP_HOST</font></i> = <font color=#2A00FF>"Host"</font>,
+        <i><font color=#0000C0>ATTR_IP_ALIASES</font></i> = <font color=#2A00FF>"Aliases"</font>,
+        <i><font color=#0000C0>ATTR_IP_ADDRESSES</font></i> = <font color=#2A00FF>"Addresses"</font>,
+        <i><font color=#0000C0>ATTR_IP_PORT</font></i> = <font color=#2A00FF>"Port"</font>;
+           
+   
+    <font color=#3F5FBF>/**
+     * <font color=#7F9FBF>@return</font> map of peer attributes
+     */</font>
+    Map&lt;String, String&gt; getAttributes();
+
+    <font color=#3F5FBF>/**
+     * <font color=#7F9FBF>@return</font> peer unique ID, same as getAttributes().get(ATTR_ID)
+     */</font>
+    String getID();
+
+    <font color=#3F5FBF>/**
+     * <font color=#7F9FBF>@return</font> peer name, same as getAttributes().get(ATTR_NAME)
+     */</font>
+    String getName();
+
+    <font color=#3F5FBF>/**
+     * Same as getAttributes().get(ATTR_OS_NAME)
+     */</font>
+    String getOSName();
+
+    <font color=#3F5FBF>/**
+     * Same as getAttributes().get(ATTR_TRANSPORT_NAME)
+     */</font>
+    String getTransportName();
+
+    <font color=#3F5FBF>/**
+     * Open channel to communicate with this peer.
+     * Note: the channel is not fully open yet when this method returns.
+     * It’s state is IChannel.STATE_OPENNING.
+     * Protocol.Listener will be called when the channel will be opened or closed.
+     */</font>
+    IChannel openChannel() <font color=#7F0055>throws</font> IOException;
+}
+
+<font color=#3F5FBF>/**
+ * ILocator service uses transport layer to search for peers and to collect data about
+ * peer’s attributes and capabilities (services). Discovery mechanism depends on
+ * transport protocol and is part of that protocol handler. Targets, known by other
+ * hosts, are added to local list of peers.
+ * Automatically discovered targets require no further configuration. Additional targets
+ * can be configured manually.
+ *
+ * Clients should use Protocol.getLocator() to obtain local instance of ILocator,
+ * then ILocator.getPeers() can be used to get of available peers (hosts and targets).
+ */</font>
+<font color=#7F0055>public interface</font> ILocator <font color=#7F0055>extends</font> IService {
+   
+    <font color=#7F0055>static final</font> String <i><font color=#0000C0>NAME</font></i> = <font color=#2A00FF>"Locator"</font>;
+
+ <font color=#3F5FBF>/**
+ * Auto-configuration command and response codes.
+ */</font>
+ <font color=#7F0055>static final int</font>
+ <i><font color=#0000C0>CONF_REQ_INFO</font></i> = 1,
+ <i><font color=#0000C0>CONF_PEER_INFO</font></i> = 2;
+
+    <font color=#3F5FBF>/**
+     * <font color=#7F9FBF>@return</font> Locator service name: "Locator"
+     */</font>
+    String getName();
+
+    <font color=#3F5FBF>/**
+ * Get map (ID -> IPeer) of available peers (hosts and targets).
+ * The method return cached (currently known to the framework) list of peers.
+ * The list is updated according to event received from transport layer
+     */</font>
+    Map&lt;String,IPeer&gt; getPeers();
+
+    <font color=#3F5FBF>/**
+     * Redirect this service channel to given peer using this service as a proxy.
+     */</font>
+    IToken redirect(String peer_id, DoneRedirect done);
+   
+    <font color=#7F0055>interface</font> DoneRedirect {
+        <font color=#7F0055>void</font> doneRedirect(IToken token, Exception error);
+    }
+
+    <font color=#3F5FBF>/**
+ * Call back after TCF messages sent to this target up to this moment are delivered.
+ * This method is intended for synchronization of messages
+ * across multiple channels.
+ *
+ * Note: Cross channel synchronization can reduce performance and throughput.
+ * Most clients don't need channel synchronization and should not call this method.
+ *
+ * @param done will be executed by dispatch thread after communication
+ * messages are delivered to corresponding targets.
+ *
+ * This is internal API, TCF clients should use {@code com.windriver.tcf.api.protocol.Protocol}.
+ */</font>
+ IToken sync(DoneSync done);
+
+ <font color=#7F0055>interface</font> DoneSync {
+ <font color=#7F0055>void</font> doneSync(IToken token);
+ }
+
+    <font color=#3F5FBF>/**
+     * Add a listener for locator service events.
+     */</font>
+    <font color=#7F0055>void</font> addListener(Listener listener);
+
+    <font color=#3F5FBF>/**
+     * Remove a listener for locator service events.
+     */</font>
+    <font color=#7F0055>void</font> removeListener(Listener listener);
+
+    <font color=#7F0055>interface</font> Listener {
+        <font color=#7F0055>void</font> peerAdded(IPeer peer);
+
+        <font color=#7F0055>void</font> peerRemoved(IPeer peer);
+
+        <font color=#7F0055>void</font> peerChanged(IPeer peer);
+    }
+}
+</pre>
+
+</body>
+</html>
+ \ No newline at end of file
diff --git a/docs/TCF_Launch_Dialog.jpg b/docs/TCF_Launch_Dialog.jpg
new file mode 100644
index 000000000..837bd6f53
--- /dev/null
+++ b/docs/TCF_Launch_Dialog.jpg
Binary files differ
diff --git a/docs/TCF_RSE_Files.jpg b/docs/TCF_RSE_Files.jpg
new file mode 100644
index 000000000..c1088b0fc
--- /dev/null
+++ b/docs/TCF_RSE_Files.jpg
Binary files differ
diff --git a/docs/TCF_RSE_Processes.jpg b/docs/TCF_RSE_Processes.jpg
new file mode 100644
index 000000000..e17a15817
--- /dev/null
+++ b/docs/TCF_RSE_Processes.jpg
Binary files differ
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 000000000..ce61a25d6
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+ <title>Target Communication Framework</title>
+</head>
+<body>
+<h1>Target Communication Framework </h1>
+
+<p>Copyright (c) 2007 Wind River Systems, Inc. Made available under the EPL v1.0
+<p>Direct comments, questions to the <a href="mailto:dsdp-tm-dev@eclipse.org">dsdp-tm-dev@eclipse.org</a> mailing list
+
+<h2>Available Documentation</h2>
+
+<table border=1 cellpadding=8>
+ <tr>
+ <td><a href='TCF Project.html'>TCF Project Overview</a>
+ <td width=500>TCF project goals and results
+ <tr>
+ <td><a href='TCF Getting Started.html'>TCF: Getting Started</a>
+ <td width=500>Getting started with TCF - creating Eclipse workspace, building agent, making a first connection
+ <tr>
+ <td><a href='TCF Specification.html'>TCF Specifications</a>
+ <td width=500>Design goals, requirements and format of TCF communication protocol,
+ framework API and software design considerations
+ <tr>
+ <td><a href='TCF Services.html'>TCF Services Definitions</a>
+ <td width=500>TCF communication model is based on the idea of services.
+ A service is a group of related commands, events and semantics.
+ New services are expected to be defined by developers of tools and target agents.
+ To achieve certain level of compatibility of tools/targets TCF inclides definitions
+ of common services
+ <tr>
+ <td><a href='TCF Context Identifier Explanation.html'>TCF Context Identifier Explanation</a>
+ <td width=500>Most if not all TCF services functions need some way to identify what entity e.g. process,
+ thread, task, device on JTAG scan chain, etc they should operate on.
+ To do this TCF uses a context identifier (aka ContextId). This document is attempting to explain how
+ ContextIds are intended to be used
+ <tr>
+ <td><a href='TCF Linux Agent Prototype.html'>TCF Agent Prototype</a>
+ <td width=500>Brief description of the TCF target agent prototype implementation
+</table>
+
+</body>
+</html>
diff --git a/epl-v10.html b/epl-v10.html
new file mode 100644
index 000000000..ed4b19665
--- /dev/null
+++ b/epl-v10.html
@@ -0,0 +1,328 @@
+<html xmlns:o="urn:schemas-microsoft-com:office:office"
+xmlns:w="urn:schemas-microsoft-com:office:word"
+xmlns="http://www.w3.org/TR/REC-html40">
+
+<head>
+<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
+<meta name=ProgId content=Word.Document>
+<meta name=Generator content="Microsoft Word 9">
+<meta name=Originator content="Microsoft Word 9">
+<link rel=File-List
+href="./Eclipse%20EPL%202003_11_10%20Final_files/filelist.xml">
+<title>Eclipse Public License - Version 1.0</title>
+<!--[if gte mso 9]><xml>
+ <o:DocumentProperties>
+ <o:Revision>2</o:Revision>
+ <o:TotalTime>3</o:TotalTime>
+ <o:Created>2004-03-05T23:03:00Z</o:Created>
+ <o:LastSaved>2004-03-05T23:03:00Z</o:LastSaved>
+ <o:Pages>4</o:Pages>
+ <o:Words>1626</o:Words>
+ <o:Characters>9270</o:Characters>
+ <o:Lines>77</o:Lines>
+ <o:Paragraphs>18</o:Paragraphs>
+ <o:CharactersWithSpaces>11384</o:CharactersWithSpaces>
+ <o:Version>9.4402</o:Version>
+ </o:DocumentProperties>
+</xml><![endif]--><!--[if gte mso 9]><xml>
+ <w:WordDocument>
+ <w:TrackRevisions/>
+ </w:WordDocument>
+</xml><![endif]-->
+<style>
+<!--
+ /* Font Definitions */
+@font-face
+ {font-family:Tahoma;
+ panose-1:2 11 6 4 3 5 4 4 2 4;
+ mso-font-charset:0;
+ mso-generic-font-family:swiss;
+ mso-font-pitch:variable;
+ mso-font-signature:553679495 -2147483648 8 0 66047 0;}
+ /* Style Definitions */
+p.MsoNormal, li.MsoNormal, div.MsoNormal
+ {mso-style-parent:"";
+ margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:"Times New Roman";}
+p
+ {margin-right:0in;
+ mso-margin-top-alt:auto;
+ mso-margin-bottom-alt:auto;
+ margin-left:0in;
+ mso-pagination:widow-orphan;
+ font-size:12.0pt;
+ font-family:"Times New Roman";
+ mso-fareast-font-family:"Times New Roman";}
+p.BalloonText, li.BalloonText, div.BalloonText
+ {mso-style-name:"Balloon Text";
+ margin:0in;
+ margin-bottom:.0001pt;
+ mso-pagination:widow-orphan;
+ font-size:8.0pt;
+ font-family:Tahoma;
+ mso-fareast-font-family:"Times New Roman";}
+@page Section1
+ {size:8.5in 11.0in;
+ margin:1.0in 1.25in 1.0in 1.25in;
+ mso-header-margin:.5in;
+ mso-footer-margin:.5in;
+ mso-paper-source:0;}
+div.Section1
+ {page:Section1;}
+-->
+</style>
+</head>
+
+<body lang=EN-US style='tab-interval:.5in'>
+
+<div class=Section1>
+
+<p align=center style='text-align:center'><b>Eclipse Public License - v 1.0</b>
+</p>
+
+<p><span style='font-size:10.0pt'>THE ACCOMPANYING PROGRAM IS PROVIDED UNDER
+THE TERMS OF THIS ECLIPSE PUBLIC LICENSE (&quot;AGREEMENT&quot;). ANY USE,
+REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE
+OF THIS AGREEMENT.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>1. DEFINITIONS</span></b> </p>
+
+<p><span style='font-size:10.0pt'>&quot;Contribution&quot; means:</span> </p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+in the case of the initial Contributor, the initial code and documentation
+distributed under this Agreement, and<br clear=left>
+b) in the case of each subsequent Contributor:</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
+changes to the Program, and</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
+additions to the Program;</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>where
+such changes and/or additions to the Program originate from and are distributed
+by that particular Contributor. A Contribution 'originates' from a Contributor
+if it was added to the Program by such Contributor itself or anyone acting on
+such Contributor's behalf. Contributions do not include additions to the
+Program which: (i) are separate modules of software distributed in conjunction
+with the Program under their own license agreement, and (ii) are not derivative
+works of the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>&quot;Contributor&quot; means any person or
+entity that distributes the Program.</span> </p>
+
+<p><span style='font-size:10.0pt'>&quot;Licensed Patents &quot; mean patent
+claims licensable by a Contributor which are necessarily infringed by the use
+or sale of its Contribution alone or when combined with the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>&quot;Program&quot; means the Contributions
+distributed in accordance with this Agreement.</span> </p>
+
+<p><span style='font-size:10.0pt'>&quot;Recipient&quot; means anyone who
+receives the Program under this Agreement, including all Contributors.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>2. GRANT OF RIGHTS</span></b> </p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+Subject to the terms of this Agreement, each Contributor hereby grants Recipient
+a non-exclusive, worldwide, royalty-free copyright license to<span
+style='color:red'> </span>reproduce, prepare derivative works of, publicly
+display, publicly perform, distribute and sublicense the Contribution of such
+Contributor, if any, and such derivative works, in source code and object code
+form.</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
+Subject to the terms of this Agreement, each Contributor hereby grants
+Recipient a non-exclusive, worldwide,<span style='color:green'> </span>royalty-free
+patent license under Licensed Patents to make, use, sell, offer to sell, import
+and otherwise transfer the Contribution of such Contributor, if any, in source
+code and object code form. This patent license shall apply to the combination
+of the Contribution and the Program if, at the time the Contribution is added
+by the Contributor, such addition of the Contribution causes such combination
+to be covered by the Licensed Patents. The patent license shall not apply to
+any other combinations which include the Contribution. No hardware per se is
+licensed hereunder. </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>c)
+Recipient understands that although each Contributor grants the licenses to its
+Contributions set forth herein, no assurances are provided by any Contributor
+that the Program does not infringe the patent or other intellectual property
+rights of any other entity. Each Contributor disclaims any liability to Recipient
+for claims brought by any other entity based on infringement of intellectual
+property rights or otherwise. As a condition to exercising the rights and
+licenses granted hereunder, each Recipient hereby assumes sole responsibility
+to secure any other intellectual property rights needed, if any. For example,
+if a third party patent license is required to allow Recipient to distribute
+the Program, it is Recipient's responsibility to acquire that license before
+distributing the Program.</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>d)
+Each Contributor represents that to its knowledge it has sufficient copyright
+rights in its Contribution, if any, to grant the copyright license set forth in
+this Agreement. </span></p>
+
+<p><b><span style='font-size:10.0pt'>3. REQUIREMENTS</span></b> </p>
+
+<p><span style='font-size:10.0pt'>A Contributor may choose to distribute the
+Program in object code form under its own license agreement, provided that:</span>
+</p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+it complies with the terms and conditions of this Agreement; and</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b)
+its license agreement:</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>i)
+effectively disclaims on behalf of all Contributors all warranties and
+conditions, express and implied, including warranties or conditions of title
+and non-infringement, and implied warranties or conditions of merchantability
+and fitness for a particular purpose; </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>ii)
+effectively excludes on behalf of all Contributors all liability for damages,
+including direct, indirect, special, incidental and consequential damages, such
+as lost profits; </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iii)
+states that any provisions which differ from this Agreement are offered by that
+Contributor alone and not by any other party; and</span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>iv)
+states that source code for the Program is available from such Contributor, and
+informs licensees how to obtain it in a reasonable manner on or through a
+medium customarily used for software exchange.<span style='color:blue'> </span></span></p>
+
+<p><span style='font-size:10.0pt'>When the Program is made available in source
+code form:</span> </p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>a)
+it must be made available under this Agreement; and </span></p>
+
+<p class=MsoNormal style='margin-left:.5in'><span style='font-size:10.0pt'>b) a
+copy of this Agreement must be included with each copy of the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>Contributors may not remove or alter any
+copyright notices contained within the Program. </span></p>
+
+<p><span style='font-size:10.0pt'>Each Contributor must identify itself as the
+originator of its Contribution, if any, in a manner that reasonably allows
+subsequent Recipients to identify the originator of the Contribution. </span></p>
+
+<p><b><span style='font-size:10.0pt'>4. COMMERCIAL DISTRIBUTION</span></b> </p>
+
+<p><span style='font-size:10.0pt'>Commercial distributors of software may
+accept certain responsibilities with respect to end users, business partners
+and the like. While this license is intended to facilitate the commercial use
+of the Program, the Contributor who includes the Program in a commercial
+product offering should do so in a manner which does not create potential
+liability for other Contributors. Therefore, if a Contributor includes the
+Program in a commercial product offering, such Contributor (&quot;Commercial
+Contributor&quot;) hereby agrees to defend and indemnify every other
+Contributor (&quot;Indemnified Contributor&quot;) against any losses, damages and
+costs (collectively &quot;Losses&quot;) arising from claims, lawsuits and other
+legal actions brought by a third party against the Indemnified Contributor to
+the extent caused by the acts or omissions of such Commercial Contributor in
+connection with its distribution of the Program in a commercial product
+offering. The obligations in this section do not apply to any claims or Losses
+relating to any actual or alleged intellectual property infringement. In order
+to qualify, an Indemnified Contributor must: a) promptly notify the Commercial
+Contributor in writing of such claim, and b) allow the Commercial Contributor
+to control, and cooperate with the Commercial Contributor in, the defense and
+any related settlement negotiations. The Indemnified Contributor may participate
+in any such claim at its own expense.</span> </p>
+
+<p><span style='font-size:10.0pt'>For example, a Contributor might include the
+Program in a commercial product offering, Product X. That Contributor is then a
+Commercial Contributor. If that Commercial Contributor then makes performance
+claims, or offers warranties related to Product X, those performance claims and
+warranties are such Commercial Contributor's responsibility alone. Under this
+section, the Commercial Contributor would have to defend claims against the
+other Contributors related to those performance claims and warranties, and if a
+court requires any other Contributor to pay any damages as a result, the
+Commercial Contributor must pay those damages.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>5. NO WARRANTY</span></b> </p>
+
+<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
+AGREEMENT, THE PROGRAM IS PROVIDED ON AN &quot;AS IS&quot; BASIS, WITHOUT
+WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING,
+WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is solely
+responsible for determining the appropriateness of using and distributing the
+Program and assumes all risks associated with its exercise of rights under this
+Agreement , including but not limited to the risks and costs of program errors,
+compliance with applicable laws, damage to or loss of data, programs or
+equipment, and unavailability or interruption of operations. </span></p>
+
+<p><b><span style='font-size:10.0pt'>6. DISCLAIMER OF LIABILITY</span></b> </p>
+
+<p><span style='font-size:10.0pt'>EXCEPT AS EXPRESSLY SET FORTH IN THIS
+AGREEMENT, NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF
+THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGES.</span> </p>
+
+<p><b><span style='font-size:10.0pt'>7. GENERAL</span></b> </p>
+
+<p><span style='font-size:10.0pt'>If any provision of this Agreement is invalid
+or unenforceable under applicable law, it shall not affect the validity or
+enforceability of the remainder of the terms of this Agreement, and without
+further action by the parties hereto, such provision shall be reformed to the
+minimum extent necessary to make such provision valid and enforceable.</span> </p>
+
+<p><span style='font-size:10.0pt'>If Recipient institutes patent litigation
+against any entity (including a cross-claim or counterclaim in a lawsuit)
+alleging that the Program itself (excluding combinations of the Program with
+other software or hardware) infringes such Recipient's patent(s), then such
+Recipient's rights granted under Section 2(b) shall terminate as of the date
+such litigation is filed. </span></p>
+
+<p><span style='font-size:10.0pt'>All Recipient's rights under this Agreement
+shall terminate if it fails to comply with any of the material terms or
+conditions of this Agreement and does not cure such failure in a reasonable
+period of time after becoming aware of such noncompliance. If all Recipient's
+rights under this Agreement terminate, Recipient agrees to cease use and
+distribution of the Program as soon as reasonably practicable. However,
+Recipient's obligations under this Agreement and any licenses granted by
+Recipient relating to the Program shall continue and survive. </span></p>
+
+<p><span style='font-size:10.0pt'>Everyone is permitted to copy and distribute
+copies of this Agreement, but in order to avoid inconsistency the Agreement is
+copyrighted and may only be modified in the following manner. The Agreement
+Steward reserves the right to publish new versions (including revisions) of
+this Agreement from time to time. No one other than the Agreement Steward has
+the right to modify this Agreement. The Eclipse Foundation is the initial
+Agreement Steward. The Eclipse Foundation may assign the responsibility to
+serve as the Agreement Steward to a suitable separate entity. Each new version
+of the Agreement will be given a distinguishing version number. The Program
+(including Contributions) may always be distributed subject to the version of
+the Agreement under which it was received. In addition, after a new version of
+the Agreement is published, Contributor may elect to distribute the Program
+(including its Contributions) under the new version. Except as expressly stated
+in Sections 2(a) and 2(b) above, Recipient receives no rights or licenses to
+the intellectual property of any Contributor under this Agreement, whether
+expressly, by implication, estoppel or otherwise. All rights in the Program not
+expressly granted under this Agreement are reserved.</span> </p>
+
+<p><span style='font-size:10.0pt'>This Agreement is governed by the laws of the
+State of New York and the intellectual property laws of the United States of
+America. No party to this Agreement will bring a legal action under this
+Agreement more than one year after the cause of action arose. Each party waives
+its rights to a jury trial in any resulting litigation.</span> </p>
+
+<p class=MsoNormal><![if !supportEmptyParas]>&nbsp;<![endif]><o:p></o:p></p>
+
+</div>
+
+</body>
+
+</html> \ No newline at end of file
diff --git a/plugins/com.windriver.debug.tcf.core/.classpath b/plugins/com.windriver.debug.tcf.core/.classpath
new file mode 100644
index 000000000..751c8f2e5
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/com.windriver.debug.tcf.core/.cvsignore b/plugins/com.windriver.debug.tcf.core/.cvsignore
new file mode 100644
index 000000000..c5e82d745
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/.cvsignore
@@ -0,0 +1 @@
+bin \ No newline at end of file
diff --git a/plugins/com.windriver.debug.tcf.core/.project b/plugins/com.windriver.debug.tcf.core/.project
new file mode 100644
index 000000000..8a5b1f874
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>com.windriver.debug.tcf.core</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/com.windriver.debug.tcf.core/.settings/org.eclipse.jdt.core.prefs b/plugins/com.windriver.debug.tcf.core/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..f06d39b5d
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,13 @@
+#Mon Sep 10 12:24:12 PDT 2007
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch,.svn/
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
diff --git a/plugins/com.windriver.debug.tcf.core/.settings/org.eclipse.ltk.core.refactoring.prefs b/plugins/com.windriver.debug.tcf.core/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 000000000..2bfce7b08
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,3 @@
+#Wed Apr 18 17:24:58 PDT 2007
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/plugins/com.windriver.debug.tcf.core/META-INF/MANIFEST.MF b/plugins/com.windriver.debug.tcf.core/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..46a4bff9e
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/META-INF/MANIFEST.MF
@@ -0,0 +1,15 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: com.windriver.debug.tcf.core;singleton:=true
+Bundle-Version: 0.1.0
+Bundle-Activator: com.windriver.debug.tcf.core.TCFCore
+Bundle-Vendor: %providerName
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.debug.core,
+ org.eclipse.core.resources,
+ com.windriver.tcf.api
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Eclipse-LazyStart: true
+Export-Package: com.windriver.debug.tcf.core.model,
+ com.windriver.debug.tcf.core.launch
diff --git a/plugins/com.windriver.debug.tcf.core/about.html b/plugins/com.windriver.debug.tcf.core/about.html
new file mode 100755
index 000000000..6c5b3615b
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>January 10, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugins/com.windriver.debug.tcf.core/build.properties b/plugins/com.windriver.debug.tcf.core/build.properties
new file mode 100644
index 000000000..e9863e281
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml
diff --git a/plugins/com.windriver.debug.tcf.core/plugin.properties b/plugins/com.windriver.debug.tcf.core/plugin.properties
new file mode 100644
index 000000000..d573d34eb
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2007 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 implementation
+###############################################################################
+pluginName = TCF/Eclipse Debugger Integration Core
+providerName = Eclipse.org
+
diff --git a/plugins/com.windriver.debug.tcf.core/plugin.xml b/plugins/com.windriver.debug.tcf.core/plugin.xml
new file mode 100644
index 000000000..1a9590a32
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/plugin.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+ <extension-point id="startup" name="TCF Startup" schema="schema/startup.exsd"/>
+ <extension
+ point="org.eclipse.debug.core.breakpoints">
+ <breakpoint
+ markerType="com.windriver.debug.tcf.breakpoint.marker"
+ class="com.windriver.debug.tcf.core.model.TCFBreakpoint"
+ id="com.windriver.debug.tcf.breakpoint"
+ name="TCF Breakpoint">
+ </breakpoint>
+ </extension>
+ <extension
+ id="com.windriver.debug.tcf.breakpoint.marker"
+ point="org.eclipse.core.resources.markers">
+ <super type="org.eclipse.debug.core.breakpointMarker"/>
+ <persistent value="true"/>
+ </extension>
+ <extension
+ point="org.eclipse.debug.core.launchConfigurationTypes">
+ <launchConfigurationType
+ sourceLocatorId="com.windriver.debug.tcf.SourceLocator"
+ name="Target Communication Framework"
+ sourcePathComputerId="com.windriver.debug.tcf.SourcePathComputer"
+ delegate="com.windriver.debug.tcf.core.launch.TCFLaunchDelegate"
+ modes="run, debug"
+ id="com.windriver.debug.tcf.LaunchConfigurationType">
+ </launchConfigurationType>
+ </extension>
+ <extension
+ point="org.eclipse.debug.core.sourceLocators">
+ <sourceLocator
+ name="TCF Source Lookup Director"
+ class="com.windriver.debug.tcf.core.launch.TCFSourceLookupDirector"
+ id="com.windriver.debug.tcf.SourceLocator">
+ </sourceLocator>
+ </extension>
+ <extension
+ point="org.eclipse.debug.core.sourcePathComputers">
+ <sourcePathComputer
+ class="com.windriver.debug.tcf.core.launch.TCFSourcePathComputerDelegate"
+ id="com.windriver.debug.tcf.SourcePathComputer">
+ </sourcePathComputer>
+ </extension>
+</plugin>
diff --git a/plugins/com.windriver.debug.tcf.core/schema/startup.exsd b/plugins/com.windriver.debug.tcf.core/schema/startup.exsd
new file mode 100644
index 000000000..0d41bb8d9
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/schema/startup.exsd
@@ -0,0 +1,73 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="com.windriver.debug.tcf">
+<annotation>
+ <appInfo>
+ <meta.schema plugin="com.windriver.debug.tcf.core" id="startup" name="TCF Startup"/>
+ </appInfo>
+ <documentation>
+ This extension point is used to register plugins
+ that want to be activated on TCF startup.
+ Once the TCF is started, registered plugins will be activated.
+ </documentation>
+
+</annotation>
+
+ <element name="extension">
+ <complexType>
+ <sequence>
+ <element ref="class" minOccurs="0" maxOccurs="unbounded"/>
+ </sequence>
+ <attribute name="point" type="string" use="required">
+ <annotation>
+ <documentation>
+ a fully qualified identifier of the target extension point
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="id" type="string">
+ <annotation>
+ <documentation>
+ an optional identifier of the extension instance
+ </documentation>
+ </annotation>
+ </attribute>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+ an optional name of the extension instance
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <element name="class">
+ <complexType>
+ <attribute name="name" type="string">
+ <annotation>
+ <documentation>
+ Class will be loaded during statup
+ </documentation>
+ </annotation>
+ </attribute>
+ </complexType>
+ </element>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="apiInfo"/>
+ </appInfo>
+ <documentation>
+ </documentation>
+ </annotation>
+
+ <annotation>
+ <appInfo>
+ <meta.section type="implementation"/>
+ </appInfo>
+ <documentation>
+ </documentation>
+ </annotation>
+
+</schema>
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/TCFCore.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/TCFCore.java
new file mode 100644
index 000000000..e4ffe006d
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/TCFCore.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.BundleContext;
+
+import com.windriver.debug.tcf.core.model.TCFBreakpointsModel;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class TCFCore extends Plugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "com.windriver.debug.tcf.core";
+
+ // The shared instance
+ private static TCFCore plugin;
+ private static TCFBreakpointsModel bp_model;
+
+ public TCFCore() {
+ plugin = this;
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ bp_model = new TCFBreakpointsModel();
+ runTCFStartup();
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ bp_model.dispose();
+ bp_model = null;
+ plugin = null;
+ super.stop(context);
+ }
+
+ private void runTCFStartup() {
+ try {
+ IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(PLUGIN_ID, "startup");
+ IExtension[] extensions = point.getExtensions();
+ for (int i = 0; i < extensions.length; i++) {
+ try {
+ Platform.getBundle(extensions[i].getNamespaceIdentifier()).start();
+ IConfigurationElement[] e = extensions[i].getConfigurationElements();
+ for (int j = 0; j < e.length; j++) {
+ String nm = e[j].getName();
+ if (nm.equals("class")) { //$NON-NLS-1$
+ Class.forName(e[j].getAttribute("name")); //$NON-NLS-1$
+ }
+ }
+ }
+ catch (Throwable x) {
+ log("TCF startup error", x);
+ }
+ }
+ }
+ catch (Exception x) {
+ log("TCF startup error", x);
+ }
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static TCFCore getDefault() {
+ return plugin;
+ }
+
+ public static TCFBreakpointsModel getBreakpointsModel() {
+ return bp_model;
+ }
+
+ /**
+ * Send error message into Eclipse log.
+ * @param msg - error message test
+ * @param err - exception
+ */
+ public static void log(String msg, Throwable err) {
+ getDefault().getLog().log(new Status(IStatus.ERROR,
+ getDefault().getBundle().getSymbolicName(), IStatus.OK, msg, err));
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFLaunchDelegate.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFLaunchDelegate.java
new file mode 100644
index 000000000..8a555cfc3
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFLaunchDelegate.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core.launch;
+
+import java.io.IOException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
+
+import com.windriver.debug.tcf.core.model.ITCFConstants;
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.Protocol;
+
+public class TCFLaunchDelegate extends LaunchConfigurationDelegate {
+
+ public static final String
+ ATTR_PEER_ID = ITCFConstants.ID_TCF_DEBUG_MODEL + ".PeerID",
+ ATTR_PROGRAM_FILE = ITCFConstants.ID_TCF_DEBUG_MODEL + ".ProgramFile",
+ ATTR_PROGRAM_ARGUMENTS = ITCFConstants.ID_TCF_DEBUG_MODEL + ".ProgramArguments",
+ ATTR_WORKING_DIRECTORY = ITCFConstants.ID_TCF_DEBUG_MODEL + ".WorkingDirectory";
+
+ public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException {
+ return new TCFLaunch(configuration, mode);
+ }
+
+ public void launch(final ILaunchConfiguration configuration, final String mode,
+ final ILaunch launch, IProgressMonitor monitor) throws CoreException {
+ if (monitor == null) monitor = new NullProgressMonitor();
+ monitor.beginTask("Launching debugger session", 1); //$NON-NLS-1$
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ try {
+ String id = configuration.getAttribute(TCFLaunchDelegate.ATTR_PEER_ID, "");
+ IPeer peer = Protocol.getLocator().getPeers().get(id);
+ if (peer == null) throw new IOException("Cannot locate peer " + id);
+ TCFLaunch.TerminateListener term = null;
+ if (peer instanceof TCFLaunch.TerminateListener) term = (TCFLaunch.TerminateListener)peer;
+ ((TCFLaunch)launch).launchTCF(mode, peer, term);
+ }
+ catch (Throwable e) {
+ ((TCFLaunch)launch).setError(e);
+ }
+ }
+ });
+ monitor.done();
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupDirector.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupDirector.java
new file mode 100644
index 000000000..57f07834f
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupDirector.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core.launch;
+
+import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
+
+/**
+ * TCF source lookup director. For TCF source lookup there is one source lookup
+ * participant.
+ */
+public class TCFSourceLookupDirector extends AbstractSourceLookupDirector {
+
+ public void initializeParticipants() {
+ addParticipants(new ISourceLookupParticipant[] { new TCFSourceLookupParticipant() });
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupParticipant.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupParticipant.java
new file mode 100644
index 000000000..765476df1
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourceLookupParticipant.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core.launch;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupParticipant;
+
+/**
+ * The TCF source lookup participant knows how to translate a TCF stack frame
+ * into a source file name
+ */
+public class TCFSourceLookupParticipant extends AbstractSourceLookupParticipant {
+
+ public String getSourceName(Object object) throws CoreException {
+ return null;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourcePathComputerDelegate.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourcePathComputerDelegate.java
new file mode 100644
index 000000000..f14abaae0
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/launch/TCFSourcePathComputerDelegate.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core.launch;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.ISourcePathComputerDelegate;
+import org.eclipse.debug.core.sourcelookup.containers.WorkspaceSourceContainer;
+
+/**
+ * Computes the default source lookup path for a TCF launch configuration. The
+ * default source lookup path is the folder or project containing the TCF
+ * program being launched. If the program is not specified, the workspace is
+ * searched by default.
+ */
+public class TCFSourcePathComputerDelegate implements
+ ISourcePathComputerDelegate {
+
+ public ISourceContainer[] computeSourceContainers(
+ ILaunchConfiguration configuration, IProgressMonitor monitor)
+ throws CoreException {
+ ISourceContainer sourceContainer = null;
+ /*
+ * String path =
+ * configuration.getAttribute(IPDAConstants.ATTR_PDA_PROGRAM,
+ * (String)null); if (path != null) { IResource resource =
+ * ResourcesPlugin.getWorkspace().getRoot().findMember(new Path(path));
+ * if (resource != null) { IContainer container = resource.getParent();
+ * if (container.getType() == IResource.PROJECT) { sourceContainer = new
+ * ProjectSourceContainer((IProject)container, false); } else if
+ * (container.getType() == IResource.FOLDER) { sourceContainer = new
+ * FolderSourceContainer(container, false); } } }
+ */
+ if (sourceContainer == null) {
+ sourceContainer = new WorkspaceSourceContainer();
+ }
+ return new ISourceContainer[] { sourceContainer };
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFBreakpointListener.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFBreakpointListener.java
new file mode 100644
index 000000000..a78f8127f
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFBreakpointListener.java
@@ -0,0 +1,16 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core.model;
+
+public interface ITCFBreakpointListener {
+
+ public void breakpointStatusChanged(String id);
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFConstants.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFConstants.java
new file mode 100644
index 000000000..66cba6273
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/ITCFConstants.java
@@ -0,0 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core.model;
+
+public interface ITCFConstants {
+
+ /**
+ * Unique identifier for the TCF debug model
+ */
+ public static final String ID_TCF_DEBUG_MODEL = "com.windriver.debug.tcf";
+
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpoint.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpoint.java
new file mode 100644
index 000000000..3b4e912ab
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpoint.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core.model;
+
+import java.math.BigInteger;
+import java.util.Map;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRunnable;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.ISchedulingRule;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.model.Breakpoint;
+
+import com.windriver.debug.tcf.core.TCFCore;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class TCFBreakpoint extends Breakpoint {
+
+ public static final String MARKER_TYPE = "com.windriver.debug.tcf.breakpoint.marker";
+
+ private static long last_id = 0;
+
+ private static String createNewID() {
+ assert Protocol.isDispatchThread();
+ long id = System.currentTimeMillis();
+ if (id <= last_id) id = last_id + 1;
+ last_id = id;
+ return Long.toHexString(id);
+ }
+
+ private String text;
+
+ public TCFBreakpoint() {
+ }
+
+ public TCFBreakpoint(final IResource resource, Map<String,Object> props) throws DebugException {
+ props.put(IBreakpoints.PROP_ID, createNewID());
+ final Map<String,Object> m = TCFCore.getBreakpointsModel().toMarkerAttributes(props);
+ final IWorkspaceRunnable runnable = new IWorkspaceRunnable() {
+ public void run(IProgressMonitor monitor) throws CoreException {
+ IMarker marker = resource.createMarker(MARKER_TYPE);
+ setMarker(marker);
+ marker.setAttributes(m);
+ DebugPlugin.getDefault().getBreakpointManager().addBreakpoint(TCFBreakpoint.this);
+ }
+ };
+ final ISchedulingRule rule = getMarkerRule(resource);
+ Job job = new Job("Add Breakpoint") { //$NON-NLS-1$
+ protected IStatus run(IProgressMonitor monitor) {
+ try {
+ TCFBreakpoint.this.run(getMarkerRule(resource), runnable);
+ }
+ catch (CoreException e) {
+ return e.getStatus();
+ }
+ return Status.OK_STATUS;
+ }
+ };
+ job.setRule(rule);
+ job.schedule();
+ }
+
+ public String getModelIdentifier() {
+ return ITCFConstants.ID_TCF_DEBUG_MODEL;
+ }
+
+ public String getText() {
+ if (text == null) {
+ IMarker marker = getMarker();
+ if (marker == null) return null;
+ StringBuffer bf = new StringBuffer();
+ String address = marker.getAttribute(
+ ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ADDRESS, null);
+ if (address != null && address.length() > 0) {
+ bf.append("PC = ");
+ BigInteger n = new BigInteger(address, 10);
+ String s = n.toString(16);
+ int l = Math.min(s.length(), 8);
+ bf.append("0x00000000".substring(0, 10 - l));
+ bf.append(s);
+ }
+ else {
+ String id = marker.getAttribute(
+ ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ID, null);
+ bf.append("BP");
+ bf.append(id);
+ }
+ text = bf.toString();
+ }
+ return text;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsModel.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsModel.java
new file mode 100644
index 000000000..a1998a9e2
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsModel.java
@@ -0,0 +1,321 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core.model;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IBreakpointListener;
+import org.eclipse.debug.core.IBreakpointManager;
+import org.eclipse.debug.core.IBreakpointManagerListener;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IBreakpoint;
+
+import com.windriver.debug.tcf.core.TCFCore;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class TCFBreakpointsModel implements IBreakpointListener, IBreakpointManagerListener {
+
+ private static final String PROP_ID = "ID";
+ private final IBreakpointManager bp_manager = DebugPlugin.getDefault().getBreakpointManager();
+
+ private abstract class BreakpointUpdate implements Runnable {
+
+ private final ILaunch[] launches;
+ private final Map<String,Object> marker_attrs;
+ private final String marker_file;
+
+ IBreakpoints service;
+ IBreakpoints.DoneCommand done;
+ Map<String,Object> tcf_attrs;
+
+ @SuppressWarnings("unchecked")
+ BreakpointUpdate(IBreakpoint breakpoint) throws CoreException, IOException {
+ if (breakpoint == null) {
+ marker_attrs = null;
+ marker_file = null;
+ }
+ else {
+ marker_attrs = new HashMap<String,Object>(breakpoint.getMarker().getAttributes());
+ marker_file = getFilePath(breakpoint.getMarker().getResource());
+ }
+ launches = DebugPlugin.getDefault().getLaunchManager().getLaunches();
+ }
+
+ synchronized void exec() throws InterruptedException {
+ assert !Protocol.isDispatchThread();
+ Protocol.invokeLater(this);
+ wait();
+ }
+
+ public void run() {
+ if (marker_attrs != null) {
+ tcf_attrs = toBreakpointAttributes(marker_file, marker_attrs);
+ }
+ for (int i = 0; i < launches.length; i++) {
+ if (launches[i] instanceof TCFLaunch) {
+ TCFLaunch launch = (TCFLaunch)launches[i];
+ final IChannel channel = launch.getChannel();
+ if (channel == null) continue;
+ if (channel.getState() != IChannel.STATE_OPEN) continue;
+ service = channel.getRemoteService(IBreakpoints.class);
+ if (service == null) continue;
+ done = new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) channel.terminate(error);
+ }
+ };
+ update();
+ }
+ }
+ Protocol.sync(new Runnable() {
+ public void run() {
+ synchronized (BreakpointUpdate.this) {
+ BreakpointUpdate.this.notify();
+ }
+ }
+ });
+ };
+
+ abstract void update();
+ }
+
+ public TCFBreakpointsModel() {
+ bp_manager.addBreakpointListener(this);
+ bp_manager.addBreakpointManagerListener(this);
+ }
+
+ public void dispose() {
+ bp_manager.removeBreakpointListener(this);
+ bp_manager.removeBreakpointManagerListener(this);
+ }
+
+ @SuppressWarnings("unchecked")
+ public void downloadBreakpoints(final IChannel channel, final Runnable done)
+ throws IOException, CoreException {
+ assert Protocol.isDispatchThread();
+ IBreakpoints service = channel.getRemoteService(IBreakpoints.class);
+ if (service != null) {
+ IBreakpoint[] arr = bp_manager.getBreakpoints(ITCFConstants.ID_TCF_DEBUG_MODEL);
+ if (arr != null && arr.length > 0) {
+ Map<String,Object>[] bps = new Map[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ IMarker marker = arr[i].getMarker();
+ String file = getFilePath(marker.getResource());
+ bps[i] = toBreakpointAttributes(file, marker.getAttributes());
+ }
+ service.set(bps, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error == null) done.run();
+ else channel.terminate(error);
+ }
+ });
+ return;
+ }
+ }
+ Protocol.invokeLater(done);
+ }
+
+ public void breakpointManagerEnablementChanged(final boolean enabled) {
+ try {
+ IBreakpoint[] arr = bp_manager.getBreakpoints(ITCFConstants.ID_TCF_DEBUG_MODEL);
+ if (arr == null || arr.length == 0) return;
+ final Set<String> ids = new HashSet<String>();
+ for (int i = 0; i < arr.length; i++) {
+ IMarker marker = arr[i].getMarker();
+ Boolean b = marker.getAttribute(IBreakpoint.ENABLED, Boolean.FALSE);
+ if (!b.booleanValue()) continue;
+ ids.add(marker.getAttribute(
+ ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ID, (String)null));
+ }
+ if (ids.isEmpty()) return;
+ new BreakpointUpdate(null) {
+ @Override
+ void update() {
+ if (enabled) {
+ service.enable(ids.toArray(new String[ids.size()]), done);
+ }
+ else {
+ service.disable(ids.toArray(new String[ids.size()]), done);
+ }
+ }
+ }.exec();
+ }
+ catch (Throwable x) {
+ TCFCore.log("Unhandled exception in breakpoint listener", x);
+ }
+ }
+
+ private String getFilePath(IResource resource) throws IOException {
+ if (resource == ResourcesPlugin.getWorkspace().getRoot()) return null;
+ IPath p = resource.getRawLocation();
+ if (p == null) return null;
+ return p.toFile().getCanonicalPath();
+ }
+
+ public void breakpointAdded(IBreakpoint breakpoint) {
+ try {
+ if (!breakpoint.getModelIdentifier().equals(ITCFConstants.ID_TCF_DEBUG_MODEL)) return;
+ new BreakpointUpdate(breakpoint) {
+ @Override
+ void update() {
+ service.add(tcf_attrs, done);
+ }
+ }.exec();
+ }
+ catch (Throwable x) {
+ TCFCore.log("Unhandled exception in breakpoint listener", x);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Set<String> calcMarkerDeltaKeys(IMarker marker, IMarkerDelta delta) throws CoreException {
+ assert delta.getKind() == IResourceDelta.CHANGED;
+ Map<String,Object> m0 = delta.getAttributes();
+ Map<String,Object> m1 = marker.getAttributes();
+ Set<String> keys = new HashSet<String>();
+ if (m0 != null) keys.addAll(m0.keySet());
+ if (m1 != null) keys.addAll(m1.keySet());
+ for (Iterator<String> i = keys.iterator(); i.hasNext();) {
+ String key = i.next();
+ Object v0 = m0 != null ? m0.get(key) : null;
+ Object v1 = m1 != null ? m1.get(key) : null;
+ if (v0 instanceof String && ((String)v0).length() == 0) v0 = null;
+ if (v1 instanceof String && ((String)v1).length() == 0) v1 = null;
+ if (v0 instanceof Boolean && !((Boolean)v0).booleanValue()) v0 = null;
+ if (v1 instanceof Boolean && !((Boolean)v1).booleanValue()) v1 = null;
+ if ((v0 == null) != (v1 == null)) continue;
+ if (v0 != null && !v0.equals(v1)) continue;
+ i.remove();
+ }
+ return keys;
+ }
+
+ public void breakpointChanged(IBreakpoint breakpoint, IMarkerDelta delta) {
+ try {
+ if (!breakpoint.getModelIdentifier().equals(ITCFConstants.ID_TCF_DEBUG_MODEL)) return;
+ final Set<String> s = calcMarkerDeltaKeys(breakpoint.getMarker(), delta);
+ if (s.isEmpty()) return;
+ new BreakpointUpdate(breakpoint) {
+ @Override
+ void update() {
+ if (s.size() == 1 && s.contains(IBreakpoint.ENABLED)) {
+ Boolean enabled = (Boolean)tcf_attrs.get(IBreakpoints.PROP_ENABLED);
+ if (enabled == null || !enabled.booleanValue()) {
+ service.disable(new String[]{ (String)tcf_attrs.get(PROP_ID) }, done);
+ }
+ else {
+ service.enable(new String[]{ (String)tcf_attrs.get(PROP_ID) }, done);
+ }
+ }
+ else {
+ service.change(tcf_attrs, done);
+ }
+ }
+ }.exec();
+ }
+ catch (Throwable x) {
+ TCFCore.log("Unhandled exception in breakpoint listener", x);
+ }
+ }
+
+ public void breakpointRemoved(IBreakpoint breakpoint, IMarkerDelta delta) {
+ try {
+ if (!breakpoint.getModelIdentifier().equals(ITCFConstants.ID_TCF_DEBUG_MODEL)) return;
+ new BreakpointUpdate(breakpoint) {
+ @Override
+ void update() {
+ service.remove(new String[]{ (String)tcf_attrs.get(PROP_ID) }, done);
+ }
+ }.exec();
+ }
+ catch (Throwable x) {
+ TCFCore.log("Unhandled exception in breakpoint listener", x);
+ }
+ }
+
+ public Map<String,Object> toMarkerAttributes(Map<String,Object> p) {
+ assert Protocol.isDispatchThread();
+ Map<String,Object> m = new HashMap<String,Object>();
+ for (Iterator<Map.Entry<String,Object>> i = p.entrySet().iterator(); i.hasNext();) {
+ Map.Entry<String,Object> e = i.next();
+ String key = e.getKey();
+ Object val = e.getValue();
+ if (key.equals(IBreakpoints.PROP_ENABLED)) continue;
+ if (key.equals(IBreakpoints.PROP_FILE)) continue;
+ if (key.equals(IBreakpoints.PROP_LINE)) continue;
+ if (key.equals(IBreakpoints.PROP_COLUMN)) continue;
+ m.put(ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + key, val);
+ }
+ Boolean enabled = (Boolean)p.get(IBreakpoints.PROP_ENABLED);
+ if (enabled == null) m.put(IBreakpoint.ENABLED, Boolean.FALSE);
+ else m.put(IBreakpoint.ENABLED, enabled);
+ m.put(IBreakpoint.REGISTERED, Boolean.TRUE);
+ m.put(IBreakpoint.PERSISTED, Boolean.TRUE);
+ m.put(IBreakpoint.ID, ITCFConstants.ID_TCF_DEBUG_MODEL);
+ String msg = "";
+ if (p.get(IBreakpoints.PROP_ADDRESS) != null) msg += p.get(IBreakpoints.PROP_ADDRESS);
+ m.put(IMarker.MESSAGE, "Breakpoint: " + msg);
+ Number line = (Number)p.get(IBreakpoints.PROP_LINE);
+ if (line != null) {
+ m.put(IMarker.LINE_NUMBER, Integer.toString(line.intValue() + 1));
+ Number column = (Number)p.get(IBreakpoints.PROP_COLUMN);
+ if (column != null) {
+ m.put(IMarker.CHAR_START, column.toString());
+ m.put(IMarker.CHAR_END, Integer.toString(column.intValue() + 1));
+ }
+ }
+ return m;
+ }
+
+ public Map<String,Object> toBreakpointAttributes(String file, Map<String,Object> p) {
+ assert Protocol.isDispatchThread();
+ Map<String,Object> m = new HashMap<String,Object>();
+ for (Iterator<Map.Entry<String,Object>> i = p.entrySet().iterator(); i.hasNext();) {
+ Map.Entry<String,Object> e = i.next();
+ String key = e.getKey();
+ Object val = e.getValue();
+ if (!key.startsWith(ITCFConstants.ID_TCF_DEBUG_MODEL)) continue;
+ m.put(key.substring(ITCFConstants.ID_TCF_DEBUG_MODEL.length() + 1), val);
+ }
+ Boolean enabled = (Boolean)p.get(IBreakpoint.ENABLED);
+ if (enabled != null && enabled.booleanValue() && bp_manager.isEnabled()) {
+ m.put(IBreakpoints.PROP_ENABLED, enabled);
+ }
+ if (file != null) {
+ m.put(IBreakpoints.PROP_FILE, file);
+ String line = (String)p.get(IMarker.LINE_NUMBER);
+ if (line != null) {
+ m.put(IBreakpoints.PROP_LINE, new Integer(Integer.parseInt(line) - 1));
+ String column = (String)p.get(IMarker.CHAR_START);
+ if (column != null) {
+ m.put(IBreakpoints.PROP_COLUMN, new Integer(column));
+ }
+ }
+ }
+ return m;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsStatus.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsStatus.java
new file mode 100644
index 000000000..a9a6cb735
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFBreakpointsStatus.java
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core.model;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.debug.core.model.IBreakpoint;
+
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class TCFBreakpointsStatus {
+
+ private final IBreakpoints service;
+ private final Map<String,Map<String,Object>> status = new HashMap<String,Map<String,Object>>();
+ private final Set<ITCFBreakpointListener> listeners = new HashSet<ITCFBreakpointListener>();
+
+ private static final Map<String,Object> status_not_supported = new HashMap<String,Object>();
+
+ static {
+ status_not_supported.put(IBreakpoints.STATUS_ERROR, "Not supported");
+ }
+
+ TCFBreakpointsStatus(TCFLaunch launch) {
+ assert Protocol.isDispatchThread();
+ service = launch.getChannel().getRemoteService(IBreakpoints.class);
+ if (service != null) {
+ service.addListener(new IBreakpoints.BreakpointsListener() {
+
+ public void breakpointStatusChanged(String id, Map<String, Object> status) {
+ assert Protocol.isDispatchThread();
+ TCFBreakpointsStatus.this.status.put(id, status);
+ for (Iterator<ITCFBreakpointListener> i = listeners.iterator(); i.hasNext();) {
+ i.next().breakpointStatusChanged(id);
+ }
+ }
+ });
+ }
+ }
+
+ public Map<String, Object> getStatus(String id) {
+ assert id != null;
+ assert Protocol.isDispatchThread();
+ if (service == null) return status_not_supported;
+ return status.get(id);
+ }
+
+ public Map<String, Object> getStatus(IBreakpoint bp) {
+ if (!bp.getModelIdentifier().equals(ITCFConstants.ID_TCF_DEBUG_MODEL)) return status_not_supported;
+ IMarker marker = bp.getMarker();
+ if (marker == null) return null;
+ return getStatus(marker.getAttribute(
+ ITCFConstants.ID_TCF_DEBUG_MODEL + '.' + IBreakpoints.PROP_ID, null));
+ }
+
+ public void addListener(ITCFBreakpointListener listener) {
+ assert Protocol.isDispatchThread();
+ listeners.add(listener);
+ }
+
+ public void removeListener(ITCFBreakpointListener listener) {
+ assert Protocol.isDispatchThread();
+ listeners.remove(listener);
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFError.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFError.java
new file mode 100644
index 000000000..f754eb7c2
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFError.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core.model;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.debug.core.DebugException;
+
+import com.windriver.debug.tcf.core.TCFCore;
+
+public class TCFError extends DebugException {
+
+ private static final long serialVersionUID = -4261097789666829020L;
+
+ public TCFError(Throwable exception) {
+ super(new Status(exception));
+ }
+
+ private static class Status implements IStatus {
+
+ private final Throwable exception;
+
+ private Status(Throwable exception) {
+ this.exception = exception;
+ }
+
+ public IStatus[] getChildren() {
+ return null;
+ }
+
+ public int getCode() {
+ return 1;
+ }
+
+ public Throwable getException() {
+ return exception;
+ }
+
+ public String getMessage() {
+ return exception.getMessage();
+ }
+
+ public String getPlugin() {
+ return TCFCore.PLUGIN_ID;
+ }
+
+ public int getSeverity() {
+ return ERROR;
+ }
+
+ public boolean isMultiStatus() {
+ return false;
+ }
+
+ public boolean isOK() {
+ return false;
+ }
+
+ public boolean matches(int severityMask) {
+ return false;
+ }
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFLaunch.java b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFLaunch.java
new file mode 100644
index 000000000..a7a07eda7
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.core/src/com/windriver/debug/tcf/core/model/TCFLaunch.java
@@ -0,0 +1,328 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.core.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.Launch;
+
+import com.windriver.debug.tcf.core.TCFCore;
+import com.windriver.debug.tcf.core.launch.TCFLaunchDelegate;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IProcesses;
+import com.windriver.tcf.api.services.IProcesses.ProcessContext;
+
+public class TCFLaunch extends Launch {
+
+ public interface Listener {
+
+ public void onConnected(TCFLaunch launch);
+
+ public void onDisconnected(TCFLaunch launch);
+
+ }
+
+ public interface TerminateListener {
+
+ public boolean canTerminate();
+
+ public boolean isTerminated();
+
+ public void terminate(Runnable done);
+ }
+
+ private static final Collection<Listener> listeners = new ArrayList<Listener>();
+
+ private IChannel channel;
+ private Throwable error;
+ private TerminateListener terminate_listener;
+ private TCFBreakpointsStatus breakpoints_status;
+ private String mode;
+ private boolean connecting;
+ private ProcessContext process;
+
+ public TCFLaunch(ILaunchConfiguration launchConfiguration, String mode) {
+ super(launchConfiguration, mode, null);
+ }
+
+ private void onConnected() {
+ try {
+ final Runnable done = new Runnable() {
+ public void run() {
+ connecting = false;
+ for (Listener l : listeners) l.onConnected(TCFLaunch.this);
+ fireChanged();
+ }
+ };
+ if (mode.equals(ILaunchManager.DEBUG_MODE)) {
+ TCFCore.getBreakpointsModel().downloadBreakpoints(channel, new Runnable() {
+ public void run() {
+ if (channel.getState() != IChannel.STATE_OPEN) return;
+ breakpoints_status = new TCFBreakpointsStatus(TCFLaunch.this);
+ downloadApplication(done);
+ }
+ });
+ }
+ else {
+ downloadApplication(done);
+ }
+ }
+ catch (Exception x) {
+ channel.terminate(x);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void downloadApplication(final Runnable done) {
+ try {
+ ILaunchConfiguration cfg = getLaunchConfiguration();
+ final String file = cfg.getAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, "");
+ if (file.length() == 0) {
+ Protocol.invokeLater(done);
+ return;
+ }
+ final String dir = cfg.getAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, "");
+ final String args = cfg.getAttribute(TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS, "");
+ final Map<String,String> env = cfg.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, (Map)null);
+ final boolean append = cfg.getAttribute(ILaunchManager.ATTR_APPEND_ENVIRONMENT_VARIABLES, true);
+ final boolean attach = mode.equals(ILaunchManager.DEBUG_MODE);
+ final IProcesses ps = channel.getRemoteService(IProcesses.class);
+ if (ps == null) throw new Exception("Target does not provide Processes service");
+ IProcesses.DoneGetEnvironment done_env = new IProcesses.DoneGetEnvironment() {
+ public void doneGetEnvironment(IToken token, Exception error, Map<String,String> def) {
+ if (error != null) {
+ channel.terminate(error);
+ return;
+ }
+ Map<String,String> vars = new HashMap<String,String>();
+ if (append) vars.putAll(def);
+ if (env != null) vars.putAll(env);
+ ps.start(dir, file, toArgsArray(args), vars, attach, new IProcesses.DoneStart() {
+ public void doneStart(IToken token, Exception error, ProcessContext process) {
+ if (error != null) {
+ channel.terminate(error);
+ return;
+ }
+ TCFLaunch.this.process = process;
+ Protocol.invokeLater(done);
+ }
+ });
+ }
+ };
+ if (append) ps.getEnvironment(done_env);
+ else done_env.doneGetEnvironment(null, null, null);
+ }
+ catch (Exception x) {
+ channel.terminate(x);
+ }
+ }
+
+ private String[] toArgsArray(String cmd) {
+ int i = 0;
+ int l = cmd.length();
+ List<String> arr = new ArrayList<String>();
+ for (;;) {
+ while (i < l && cmd.charAt(i) == ' ') i++;
+ if (i >= l) break;
+ String s = null;
+ if (cmd.charAt(i) == '"') {
+ i++;
+ StringBuffer bf = new StringBuffer();
+ while (i < l) {
+ char ch = cmd.charAt(i++);
+ if (ch == '"') break;
+ if (ch == '\\' && i < l) ch = cmd.charAt(i++);
+ bf.append(ch);
+ }
+ s = bf.toString();
+ }
+ else {
+ int i0 = i;
+ while (i < l && cmd.charAt(i) != ' ') i++;
+ s = cmd.substring(i0, i);
+ }
+ arr.add(s);
+ }
+ return arr.toArray(new String[arr.size()]);
+ }
+
+ private void onDisconnected(Throwable error) {
+ this.error = error;
+ breakpoints_status = null;
+ connecting = false;
+ for (Iterator<Listener> i = listeners.iterator(); i.hasNext();) {
+ i.next().onDisconnected(this);
+ }
+ if (DebugPlugin.getDefault() != null) fireTerminate();
+ }
+
+ /*--------------------------------------------------------------------------------------------*/
+
+ public Throwable getError() {
+ return error;
+ }
+
+ public void setError(Throwable x) {
+ if (error != null) return;
+ error = x;
+ if (channel != null && channel.getState() == IChannel.STATE_OPEN) {
+ channel.terminate(x);
+ }
+ fireChanged();
+ }
+
+ public TCFBreakpointsStatus getBreakpointsStatus() {
+ return breakpoints_status;
+ }
+
+ public static void addListener(Listener listener) {
+ assert Protocol.isDispatchThread();
+ listeners.add(listener);
+ }
+
+ public static void removeListener(Listener listener) {
+ assert Protocol.isDispatchThread();
+ listeners.remove(listener);
+ }
+
+ public IChannel getChannel() {
+ assert Protocol.isDispatchThread();
+ if (channel == null || channel.getState() != IChannel.STATE_OPEN) return null;
+ return channel;
+ }
+
+ public IProcesses.ProcessContext getProcessContext() {
+ return process;
+ }
+
+ public boolean isConnecting() {
+ return connecting;
+ }
+
+ public IPeer getPeer() {
+ assert Protocol.isDispatchThread();
+ return channel.getRemotePeer();
+ }
+
+ public <V extends IService> V getService(Class<V> cls) {
+ assert Protocol.isDispatchThread();
+ return channel.getRemoteService(cls);
+ }
+
+ public boolean canTerminate() {
+ final boolean res[] = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (terminate_listener == null) res[0] = false;
+ else res[0] = terminate_listener.canTerminate();
+ }
+ });
+ return res[0];
+ }
+
+ public boolean isTerminated() {
+ final boolean res[] = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (channel == null || channel.getState() == IChannel.STATE_CLOSED) res[0] = true;
+ else if (terminate_listener == null) res[0] = false;
+ else res[0] = terminate_listener.isTerminated();
+ }
+ });
+ return res[0];
+ }
+
+ public void terminate() {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (terminate_listener == null) return;
+ terminate_listener.terminate(new Runnable() {
+ public void run() {
+ fireTerminate();
+ }
+ });
+ }
+ });
+ }
+
+ public void terminate(Runnable done) {
+ if (terminate_listener == null) done.run();
+ else terminate_listener.terminate(done);
+ }
+
+ public boolean canDisconnect() {
+ final boolean res[] = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ res[0] = channel != null && channel.getState() != IChannel.STATE_CLOSED;
+ }
+ });
+ return res[0];
+ }
+
+ public boolean isDisconnected() {
+ final boolean res[] = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ res[0] = channel == null || channel.getState() == IChannel.STATE_CLOSED;
+ }
+ });
+ return res[0];
+ }
+
+ public void disconnect() throws DebugException {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (channel != null && channel.getState() != IChannel.STATE_CLOSED) {
+ channel.close();
+ }
+ fireTerminate();
+ }
+ });
+ }
+
+ public void launchTCF(String mode, IPeer peer, TerminateListener terminate_listener) throws DebugException {
+ assert Protocol.isDispatchThread();
+ this.mode = mode;
+ this.terminate_listener = terminate_listener;
+ connecting = true;
+ channel = peer.openChannel();
+ channel.addChannelListener(new IChannel.IChannelListener() {
+
+ public void onChannelOpened() {
+ onConnected();
+ }
+
+ public void congestionLevel(int level) {
+ }
+
+ public void onChannelClosed(Throwable error) {
+ channel.removeChannelListener(this);
+ onDisconnected(error);
+ }
+
+ });
+ assert channel.getState() == IChannel.STATE_OPENNING;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/.classpath b/plugins/com.windriver.debug.tcf.ui/.classpath
new file mode 100644
index 000000000..03ba07a5f
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins">
+ <accessrules>
+ <accessrule kind="accessible" pattern="org/eclipse/debug/**/provisional/**"/>
+ </accessrules>
+ </classpathentry>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/com.windriver.debug.tcf.ui/.cvsignore b/plugins/com.windriver.debug.tcf.ui/.cvsignore
new file mode 100644
index 000000000..ba077a403
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/.cvsignore
@@ -0,0 +1 @@
+bin
diff --git a/plugins/com.windriver.debug.tcf.ui/.project b/plugins/com.windriver.debug.tcf.ui/.project
new file mode 100644
index 000000000..fb751e4e7
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>com.windriver.debug.tcf.ui</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/com.windriver.debug.tcf.ui/.settings/org.eclipse.jdt.core.prefs b/plugins/com.windriver.debug.tcf.ui/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..78e20524b
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,13 @@
+#Mon Sep 10 12:26:30 PDT 2007
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch,.svn/
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
diff --git a/plugins/com.windriver.debug.tcf.ui/META-INF/MANIFEST.MF b/plugins/com.windriver.debug.tcf.ui/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..4743cd6da
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: com.windriver.debug.tcf.ui;singleton:=true
+Bundle-Version: 0.1.0
+Bundle-Activator: com.windriver.debug.tcf.ui.TCFUI
+Bundle-Vendor: %providerName
+Bundle-Localization: plugin
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.debug.core,
+ org.eclipse.debug.ui,
+ com.windriver.debug.tcf.core,
+ com.windriver.tcf.api
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Eclipse-LazyStart: true
+Export-Package: com.windriver.debug.tcf.ui.adapters,
+ com.windriver.debug.tcf.ui.launch
diff --git a/plugins/com.windriver.debug.tcf.ui/about.html b/plugins/com.windriver.debug.tcf.ui/about.html
new file mode 100755
index 000000000..6c5b3615b
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>January 10, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugins/com.windriver.debug.tcf.ui/build.properties b/plugins/com.windriver.debug.tcf.ui/build.properties
new file mode 100644
index 000000000..bbc49de86
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/build.properties
@@ -0,0 +1,7 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml,\
+ bin/
+
diff --git a/plugins/com.windriver.debug.tcf.ui/icons/arguments_tab.gif b/plugins/com.windriver.debug.tcf.ui/icons/arguments_tab.gif
new file mode 100644
index 000000000..44660b5f0
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/icons/arguments_tab.gif
Binary files differ
diff --git a/plugins/com.windriver.debug.tcf.ui/icons/tcf.gif b/plugins/com.windriver.debug.tcf.ui/icons/tcf.gif
new file mode 100644
index 000000000..3198679ae
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/icons/tcf.gif
Binary files differ
diff --git a/plugins/com.windriver.debug.tcf.ui/plugin.properties b/plugins/com.windriver.debug.tcf.ui/plugin.properties
new file mode 100644
index 000000000..c791ca4f7
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2007 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 implementation
+###############################################################################
+pluginName = TCF/Eclipse Debugger Integration UI
+providerName = Eclipse.org
+
diff --git a/plugins/com.windriver.debug.tcf.ui/plugin.xml b/plugins/com.windriver.debug.tcf.ui/plugin.xml
new file mode 100644
index 000000000..cc3b88d16
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/plugin.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+
+ <extension point="com.windriver.debug.tcf.core.startup"/>
+
+ <extension
+ id="com.windriver.debug.tcf.ui.adapters"
+ point="org.eclipse.core.runtime.adapters">
+ <factory
+ class="com.windriver.debug.tcf.ui.adapters.TCFLaunchAdapterFactory"
+ adaptableType="com.windriver.debug.tcf.core.model.TCFLaunch">
+ <adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider"/>
+ <adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider"/>
+ <adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory"/>
+ <adapter type="org.eclipse.debug.core.commands.ITerminateHandler"/>
+ </factory>
+ <factory
+ class="com.windriver.debug.tcf.ui.adapters.TCFBreakpointAdapterFactory"
+ adaptableType="com.windriver.debug.tcf.ui.model.TCFNode">
+ <adapter type="org.eclipse.debug.ui.actions.IToggleBreakpointsTarget"/>
+ <adapter type="org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension"/>
+ </factory>
+ </extension>
+
+ <extension
+ point="org.eclipse.debug.ui.debugModelPresentations">
+ <debugModelPresentation
+ class = "com.windriver.debug.tcf.ui.model.TCFModelPresentation"
+ id = "com.windriver.debug.tcf">
+ </debugModelPresentation>
+ </extension>
+
+ <extension
+ point="org.eclipse.debug.ui.launchConfigurationTypeImages">
+ <launchConfigurationTypeImage
+ icon="icons/tcf.gif"
+ configTypeID="com.windriver.debug.tcf.LaunchConfigurationType"
+ id="com.windriver.debug.tcf.LaunchConfigurationTypeImage">
+ </launchConfigurationTypeImage>
+ </extension>
+
+ <extension
+ point="org.eclipse.debug.ui.launchConfigurationTabGroups">
+ <launchConfigurationTabGroup
+ type="com.windriver.debug.tcf.LaunchConfigurationType"
+ description="Run or debug a program using Target Communication Framework"
+ class="com.windriver.debug.tcf.ui.launch.TCFTabGroup"
+ id="com.windriver.debug.tcf.LaunchConfigurationTabGroup">
+ </launchConfigurationTabGroup>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.contexts">
+ <context
+ name="Debugging using Target Communication Framework"
+ description="Debugging using Target Communication Framework"
+ id="com.windriver.debug.tcf.ui.debugging"
+ parentId="org.eclipse.debug.ui.debugging">
+ </context>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.views">
+ <view
+ name="TCF Trace"
+ icon="icons/tcf.gif"
+ category="org.eclipse.debug.ui"
+ class="com.windriver.debug.tcf.ui.trace.TraceView"
+ id="com.windriver.tcf.TraceView">
+ </view>
+ </extension>
+
+ <extension
+ point="org.eclipse.ui.perspectiveExtensions">
+ <perspectiveExtension
+ targetID="org.eclipse.debug.ui.DebugPerspective">
+ <view
+ relative="org.eclipse.ui.console.ConsoleView"
+ relationship="stack"
+ id="com.windriver.tcf.TraceView">
+ </view>
+ </perspectiveExtension>
+ </extension>
+
+</plugin>
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/TCFUI.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/TCFUI.java
new file mode 100644
index 000000000..5ce3dbb2b
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/TCFUI.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+
+import com.windriver.debug.tcf.ui.model.TCFModelManager;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class TCFUI extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "com.windriver.debug.tcf.ui";
+
+ // The shared instance
+ private static TCFUI plugin;
+ private static TCFModelManager model_manager;
+
+ private static final BundleListener bundle_listener = new BundleListener() {
+ public void bundleChanged(BundleEvent event) {
+ if (plugin != null && event.getBundle() == plugin.getBundle() &&
+ plugin.getBundle().getState() != Bundle.ACTIVE && model_manager != null) {
+ model_manager.dispose();
+ model_manager = null;
+ }
+ }
+ };
+
+ /**
+ * The constructor
+ */
+ public TCFUI() {
+ plugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ context.addBundleListener(bundle_listener);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static TCFUI getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Returns the shared TCFModel instance
+ *
+ * @return the shared TCFModel instance
+ */
+ public static TCFModelManager getModelManager() {
+ if (plugin != null && model_manager == null && plugin.getBundle().getState() == Bundle.ACTIVE) {
+ model_manager = new TCFModelManager();
+ }
+ return model_manager;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFBreakpointAdapterFactory.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFBreakpointAdapterFactory.java
new file mode 100644
index 000000000..c5f428dac
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFBreakpointAdapterFactory.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.adapters;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget;
+import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension;
+
+import com.windriver.debug.tcf.ui.commands.BreakpointCommand;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+
+public class TCFBreakpointAdapterFactory implements IAdapterFactory {
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Object obj, Class adapterType) {
+ if (obj instanceof TCFNode) {
+ return new BreakpointCommand();
+ }
+ System.out.println(obj.getClass().getName() + " -> " + adapterType);
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Class[] getAdapterList() {
+ return new Class[]{ IToggleBreakpointsTarget.class, IToggleBreakpointsTargetExtension.class };
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFLaunchAdapterFactory.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFLaunchAdapterFactory.java
new file mode 100644
index 000000000..4159fcea4
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFLaunchAdapterFactory.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.adapters;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.debug.core.commands.ITerminateHandler;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.tcf.api.protocol.Protocol;
+
+public class TCFLaunchAdapterFactory implements IAdapterFactory {
+
+ @SuppressWarnings("unchecked")
+ private final Class[] adapter_list = {
+ IElementContentProvider.class,
+ IElementLabelProvider.class,
+ IModelProxyFactory.class,
+ ITerminateHandler.class
+ };
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(final Object from, final Class to) {
+ if (from instanceof TCFLaunch) {
+ final Object[] res = new Object[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFLaunch launch = (TCFLaunch)from;
+ TCFModel model = TCFUI.getModelManager().getModel(launch);
+ if (model != null) {
+ if (to.isInstance(model)) {
+ res[0] = model;
+ return;
+ }
+ Object cmd = model.getCommand(to);
+ if (cmd != null) {
+ res[0] = cmd;
+ return;
+ }
+ }
+ }
+ });
+ if (res[0] != null) return res[0];
+ }
+ System.err.println(from.getClass().getName() + " -> " + to);
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Class[] getAdapterList() {
+ return adapter_list;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFModelSelectionPolicyFactoryAdapter.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFModelSelectionPolicyFactoryAdapter.java
new file mode 100644
index 000000000..d8ad27b10
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/adapters/TCFModelSelectionPolicyFactoryAdapter.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.adapters;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+public class TCFModelSelectionPolicyFactoryAdapter implements IModelSelectionPolicyFactory {
+
+ public IModelSelectionPolicy createModelSelectionPolicyAdapter(
+ Object element, IPresentationContext context) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/BreakpointCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/BreakpointCommand.java
new file mode 100644
index 000000000..12ec02760
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/BreakpointCommand.java
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.ui.actions.IToggleBreakpointsTargetExtension;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbenchPart;
+
+import com.windriver.debug.tcf.core.model.TCFBreakpoint;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class BreakpointCommand implements IToggleBreakpointsTargetExtension {
+
+ public boolean canToggleBreakpoints(IWorkbenchPart part, ISelection selection) {
+ Object obj = ((IStructuredSelection)selection).getFirstElement();
+ if (obj instanceof TCFNode) {
+ final TCFNode node = (TCFNode)obj;
+ if (node == null) return false;
+ final boolean[] res = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ res[0] = node.getAddress() != null;
+ }
+ });
+ return res[0];
+ }
+ else {
+ return false;
+ }
+ }
+
+ public void toggleBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ Object obj = ((IStructuredSelection)selection).getFirstElement();
+ if (obj instanceof TCFNode) {
+ final TCFNode node = (TCFNode)obj;
+ if (node == null) return;
+ final CoreException[] res = new CoreException[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ try {
+ String addr = node.getAddress();
+ if (addr == null) return;
+ Map<String,Object> m = new HashMap<String,Object>();
+ m.put(IBreakpoints.PROP_ENABLED, Boolean.TRUE);
+ m.put(IBreakpoints.PROP_ADDRESS, addr);
+ new TCFBreakpoint(ResourcesPlugin.getWorkspace().getRoot(), m);
+ }
+ catch (CoreException x) {
+ res[0] = x;
+ }
+ }
+ });
+ if (res[0] != null) throw res[0];
+ }
+ }
+
+ public boolean canToggleLineBreakpoints(IWorkbenchPart part, ISelection selection) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void toggleLineBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void toggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void toggleWatchpoints(IWorkbenchPart part, ISelection selection) throws CoreException {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/DisconnectCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/DisconnectCommand.java
new file mode 100644
index 000000000..3ef011689
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/DisconnectCommand.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.commands;
+
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IDisconnectHandler;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+
+public class DisconnectCommand implements IDisconnectHandler {
+
+ private final TCFModel model;
+
+ public DisconnectCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ monitor.setEnabled(model.getLaunch().canDisconnect());
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ try {
+ model.getLaunch().disconnect();
+ monitor.setStatus(Status.OK_STATUS);
+ }
+ catch (DebugException x) {
+ monitor.setStatus(x.getStatus());
+ }
+ done();
+ }
+ };
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/ResumeCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/ResumeCommand.java
new file mode 100644
index 000000000..f4ecd5049
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/ResumeCommand.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IResumeHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class ResumeCommand implements IResumeHandler {
+
+ private final TCFModel model;
+
+ public ResumeCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null) {
+ node = node.getParent();
+ }
+ else if (ctx.isContainer()) {
+ if (ctx.canResume(IRunControl.RM_RESUME)) res = true;
+ node = null;
+ }
+ else {
+ if (node.isSuspended() && ctx.canResume(IRunControl.RM_RESUME)) res = true;
+ node = null;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null) {
+ node = node.getParent();
+ }
+ else {
+ set.add(ctx);
+ node = null;
+ }
+ }
+ }
+ final Set<IToken> cmds = new HashSet<IToken>();
+ for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ cmds.add(ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot resume", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ };
+ return true;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepIntoCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepIntoCommand.java
new file mode 100644
index 000000000..76e09d274
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepIntoCommand.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IStepIntoHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class StepIntoCommand implements IStepIntoHandler {
+
+ private final TCFModel model;
+
+ public StepIntoCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_INTO)) {
+ node = node.getParent();
+ }
+ else {
+ if (node.isSuspended()) res = true;
+ node = null;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_INTO)) {
+ node = node.getParent();
+ }
+ else {
+ set.add(ctx);
+ node = null;
+ }
+ }
+ }
+ final Set<IToken> cmds = new HashSet<IToken>();
+ for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ cmds.add(ctx.resume(IRunControl.RM_STEP_INTO, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot step into", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ };
+ return true;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepOverCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepOverCommand.java
new file mode 100644
index 000000000..3a8170fbb
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepOverCommand.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IStepOverHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class StepOverCommand implements IStepOverHandler {
+
+ private final TCFModel model;
+
+ public StepOverCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OVER)) {
+ node = node.getParent();
+ }
+ else {
+ if (node.isSuspended()) res = true;
+ node = null;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OVER)) {
+ node = node.getParent();
+ }
+ else {
+ set.add(ctx);
+ node = null;
+ }
+ }
+ }
+ final Set<IToken> cmds = new HashSet<IToken>();
+ for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ cmds.add(ctx.resume(IRunControl.RM_STEP_OVER, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot step into", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ };
+ return true;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepReturnCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepReturnCommand.java
new file mode 100644
index 000000000..8975a8155
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/StepReturnCommand.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.IStepReturnHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class StepReturnCommand implements IStepReturnHandler {
+
+ private final TCFModel model;
+
+ public StepReturnCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OUT)) {
+ node = node.getParent();
+ }
+ else {
+ if (node.isSuspended()) res = true;
+ node = null;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null || !ctx.canResume(IRunControl.RM_STEP_OUT)) {
+ node = node.getParent();
+ }
+ else {
+ set.add(ctx);
+ node = null;
+ }
+ }
+ }
+ final Set<IToken> cmds = new HashSet<IToken>();
+ for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ cmds.add(ctx.resume(IRunControl.RM_STEP_OUT, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot step into", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ };
+ return true;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/SuspendCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/SuspendCommand.java
new file mode 100644
index 000000000..45419650e
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/SuspendCommand.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.ISuspendHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class SuspendCommand implements ISuspendHandler {
+
+ private final TCFModel model;
+
+ public SuspendCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null) {
+ node = node.getParent();
+ }
+ else if (ctx.isContainer()) {
+ if (ctx.canSuspend()) res = true;
+ node = null;
+ }
+ else {
+ if (node.isRunning() && ctx.canSuspend()) res = true;
+ node = null;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx == null) {
+ node = node.getParent();
+ }
+ else {
+ set.add(ctx);
+ node = null;
+ }
+ }
+ }
+ final Set<IToken> cmds = new HashSet<IToken>();
+ for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ cmds.add(ctx.suspend(new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot suspend", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ };
+ return true;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/TerminateCommand.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/TerminateCommand.java
new file mode 100644
index 000000000..81f16e12a
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/commands/TerminateCommand.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.commands;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.commands.IDebugCommandRequest;
+import org.eclipse.debug.core.commands.IEnabledStateRequest;
+import org.eclipse.debug.core.commands.ITerminateHandler;
+
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.debug.tcf.ui.model.TCFModel;
+import com.windriver.debug.tcf.ui.model.TCFNode;
+import com.windriver.debug.tcf.ui.model.TCFRunnable;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class TerminateCommand implements ITerminateHandler {
+
+ private final TCFModel model;
+
+ public TerminateCommand(TCFModel model) {
+ this.model = model;
+ }
+
+ public void canExecute(final IEnabledStateRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ boolean res = false;
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx != null && ctx.canTerminate()) {
+ res = true;
+ node = null;
+ }
+ else {
+ node = node.getParent();
+ if (node == null && model.getLaunch().canTerminate()) res = true;
+ }
+ }
+ }
+ monitor.setEnabled(res);
+ monitor.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ public boolean execute(final IDebugCommandRequest monitor) {
+ new TCFRunnable(model.getDisplay(), monitor) {
+ public void run() {
+ Object[] elements = monitor.getElements();
+ Set<IRunControl.RunControlContext> set = new HashSet<IRunControl.RunControlContext>();
+ for (int i = 0; i < elements.length; i++) {
+ TCFNode node = null;
+ if (elements[i] instanceof TCFNode) node = (TCFNode)elements[i];
+ else node = model.getRootNode();
+ while (node != null && !node.isDisposed()) {
+ if (!node.validateNode(this)) return;
+ IRunControl.RunControlContext ctx = node.getRunContext();
+ if (ctx != null && ctx.canTerminate()) {
+ set.add(ctx);
+ node = null;
+ }
+ else {
+ node = node.getParent();
+ if (node == null) set.add(null);
+ }
+ }
+ }
+ final Set<IToken> cmds = new HashSet<IToken>();
+ for (Iterator<IRunControl.RunControlContext> i = set.iterator(); i.hasNext();) {
+ IRunControl.RunControlContext ctx = i.next();
+ if (ctx == null) {
+ cmds.add(null);
+ model.getLaunch().terminate(new Runnable() {
+ public void run() {
+ assert cmds.contains(null);
+ cmds.remove(null);
+ if (cmds.isEmpty()) done();
+ }
+ });
+ }
+ else {
+ cmds.add(ctx.terminate(new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ monitor.setStatus(new Status(IStatus.ERROR,
+ TCFUI.PLUGIN_ID, IStatus.OK, "Cannot resume", error));
+ }
+ if (cmds.isEmpty()) done();
+ }
+ }));
+ }
+ }
+ }
+ };
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFArgumentsTab.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFArgumentsTab.java
new file mode 100644
index 000000000..082d741bc
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFArgumentsTab.java
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.launch;
+
+import java.net.URL;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
+import org.eclipse.debug.ui.StringVariableSelectionDialog;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Text;
+
+import com.windriver.debug.tcf.core.launch.TCFLaunchDelegate;
+import com.windriver.debug.tcf.ui.TCFUI;
+
+public class TCFArgumentsTab extends AbstractLaunchConfigurationTab {
+
+ private Text text_arguments;
+ private Button button_variables;
+ private Text text_working_dir;
+ private Button button_default_dir;
+ private Image image;
+
+ public void createControl(Composite parent) {
+ Font font = parent.getFont();
+ Composite comp = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout(1, true);
+ comp.setLayout(layout);
+ comp.setFont(font);
+
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ comp.setLayoutData(gd);
+ setControl(comp);
+
+ createArgumentsGroup(comp);
+ createWorkingDirGroup(comp);
+
+ URL url = FileLocator.find(TCFUI.getDefault().getBundle(),
+ new Path("icons/arguments_tab.gif"), null);
+ ImageDescriptor descriptor = null;
+ if (url == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ }
+ else {
+ descriptor = ImageDescriptor.createFromURL(url);
+ }
+ image = descriptor.createImage(parent.getDisplay());
+ }
+
+ private void createArgumentsGroup(Composite comp) {
+ Font font = comp.getFont();
+
+ Group group = new Group(comp, SWT.NONE);
+ group.setFont(font);
+ group.setLayout(new GridLayout());
+ group.setLayoutData(new GridData(GridData.FILL_BOTH));
+ group.setText("Program Arguments");
+
+ text_arguments = new Text(group, SWT.MULTI | SWT.WRAP | SWT.BORDER | SWT.V_SCROLL);
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ gd.heightHint = 40;
+ gd.widthHint = 100;
+ text_arguments.setLayoutData(gd);
+ text_arguments.setFont(font);
+ text_arguments.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent evt) {
+ updateLaunchConfigurationDialog();
+ }
+ });
+ button_variables= createPushButton(group, "Variables", null);
+ gd = new GridData(GridData.HORIZONTAL_ALIGN_END);
+ button_variables.setLayoutData(gd);
+ button_variables.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent arg0) {
+ handleVariablesButtonSelected(text_arguments);
+ }
+ });
+ }
+
+ private void createWorkingDirGroup(Composite comp) {
+ Font font = comp.getFont();
+
+ Group group = new Group(comp, SWT.NONE);
+ GridLayout workingDirLayout = new GridLayout();
+ workingDirLayout.makeColumnsEqualWidth = false;
+ group.setLayout(workingDirLayout);
+ group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ group.setFont(font);
+ group.setText("Working directory");
+
+ text_working_dir = new Text(group, SWT.SINGLE | SWT.BORDER);
+ text_working_dir.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ text_working_dir.setFont(font);
+
+ button_default_dir = new Button(group, SWT.CHECK);
+ button_default_dir.setText("Use default");
+ button_default_dir.setLayoutData(new GridData(GridData.FILL, GridData.BEGINNING, true, false));
+ button_default_dir.setFont(font);
+ }
+
+ @Override
+ public void dispose() {
+ if (image != null) {
+ image.dispose();
+ image = null;
+ }
+ super.dispose();
+ }
+
+ /**
+ * A variable entry button has been pressed for the given text
+ * field. Prompt the user for a variable and enter the result
+ * in the given field.
+ */
+ private void handleVariablesButtonSelected(Text textField) {
+ String variable = getVariable();
+ if (variable != null) textField.append(variable);
+ }
+
+ /**
+ * Prompts the user to choose and configure a variable and returns
+ * the resulting string, suitable to be used as an attribute.
+ */
+ private String getVariable() {
+ StringVariableSelectionDialog dialog = new StringVariableSelectionDialog(getShell());
+ dialog.open();
+ return dialog.getVariableExpression();
+ }
+
+ public boolean isValid(ILaunchConfiguration config) {
+ return true;
+ }
+
+ 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) {
+ try {
+ text_arguments.setText(configuration.getAttribute(TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS, "")); //$NON-NLS-1$
+ text_working_dir.setText(configuration.getAttribute(TCFLaunchDelegate.ATTR_WORKING_DIRECTORY, "")); //$NON-NLS-1$
+ }
+ catch (CoreException e) {
+ setErrorMessage("Cannot read launch configuration: " + e);
+ }
+ }
+
+ public void performApply(ILaunchConfigurationWorkingCopy configuration) {
+ configuration.setAttribute(
+ TCFLaunchDelegate.ATTR_PROGRAM_ARGUMENTS,
+ getAttributeValueFrom(text_arguments));
+ configuration.setAttribute(
+ TCFLaunchDelegate.ATTR_WORKING_DIRECTORY,
+ getAttributeValueFrom(text_working_dir));
+ }
+
+ protected String getAttributeValueFrom(Text text) {
+ String content = text.getText().trim();
+ content = content.replaceAll("\r\n", "\n"); // eliminate Windows \r line delimiter
+ if (content.length() > 0) return content;
+ return null;
+ }
+
+ public String getName() {
+ return "Arguments";
+ }
+
+ @Override
+ public Image getImage() {
+ return image;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFMainTab.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFMainTab.java
new file mode 100644
index 000000000..3e9168d3c
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFMainTab.java
@@ -0,0 +1,718 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.launch;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CLabel;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.ProgressBar;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeColumn;
+import org.eclipse.swt.widgets.TreeItem;
+
+import com.windriver.debug.tcf.core.launch.TCFLaunchDelegate;
+import com.windriver.debug.tcf.ui.TCFUI;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.ILocator;
+
+/**
+ * Launch configuration dialog tab to specify the Target Communication Framework
+ * configuration.
+ */
+public class TCFMainTab extends AbstractLaunchConfigurationTab {
+
+ private Text peer_id_text;
+ private Text program_text;
+ private Tree peer_tree;
+ private PeerInfo[] peer_info;
+ private Display display;
+
+ private final Map<LocatorListener,ILocator> listeners = new HashMap<LocatorListener,ILocator>();
+ private final Map<String,Image> image_cache = new HashMap<String,Image>();
+
+ private static class PeerInfo {
+ PeerInfo parent;
+ int index;
+ PeerInfo[] children;
+ Map<String,String> attrs;
+ }
+
+ private class LocatorListener implements ILocator.LocatorListener {
+
+ private final PeerInfo parent;
+
+ LocatorListener(PeerInfo parent) {
+ this.parent = parent;
+ }
+
+ public void peerAdded(IPeer peer) {
+ if (display == null) return;
+ final Map<String,String> attrs = new HashMap<String,String>(peer.getAttributes());
+ display.asyncExec(new Runnable() {
+ public void run() {
+ PeerInfo[] arr = parent == null ? peer_info : parent.children;
+ PeerInfo[] buf = new PeerInfo[arr.length + 1];
+ System.arraycopy(arr, 0, buf, 0, arr.length);
+ PeerInfo info = new PeerInfo();
+ info.parent = parent;
+ info.index = arr.length;
+ info.attrs = attrs;
+ buf[arr.length] = info;
+ if (parent == null) {
+ peer_info = buf;
+ }
+ else {
+ parent.children = buf;
+ }
+ updateItems();
+ }
+ });
+ }
+
+ public void peerChanged(IPeer peer) {
+ if (display == null) return;
+ final Map<String,String> attrs = new HashMap<String,String>(peer.getAttributes());
+ display.asyncExec(new Runnable() {
+ public void run() {
+ String id = attrs.get(IPeer.ATTR_ID);
+ PeerInfo[] arr = parent == null ? peer_info : parent.children;
+ for (int i = 0; i < arr.length; i++) {
+ if (arr[i].attrs.get(IPeer.ATTR_ID).equals(id)) {
+ arr[i].attrs = attrs;
+ updateItems();
+ }
+ }
+ assert false;
+ }
+ });
+ }
+
+ public void peerRemoved(final String id) {
+ if (display == null) return;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ PeerInfo[] arr = parent == null ? peer_info : parent.children;
+ PeerInfo[] buf = new PeerInfo[arr.length - 1];
+ int j = 0;
+ for (int i = 0; i < arr.length; i++) {
+ if (!arr[i].attrs.get(IPeer.ATTR_ID).equals(id)) {
+ buf[j++] = arr[i];
+ }
+ }
+ if (parent == null) {
+ peer_info = buf;
+ }
+ else {
+ parent.children = buf;
+ }
+ updateItems();
+ }
+ });
+ }
+
+ private void updateItems() {
+ PeerInfo[] arr = null;
+ TreeItem[] items = null;
+ if (parent == null) {
+ arr = peer_info;
+ peer_tree.setItemCount(arr.length);
+ items = peer_tree.getItems();
+ }
+ else {
+ TreeItem item = findItem(parent);
+ if (item == null) return;
+ arr = parent.children;
+ item.setItemCount(arr.length);
+ items = item.getItems();
+ }
+ assert items.length == arr.length;
+ for (int i = 0; i < items.length; i++) {
+ fillItem(items[i], arr[i]);
+ }
+ String id = peer_id_text.getText();
+ TreeItem item = findItem(findPeerInfo(id));
+ if (item != null) peer_tree.setSelection(item);
+ }
+ }
+
+ public void createControl(Composite parent) {
+ display = parent.getDisplay();
+
+ Font font = parent.getFont();
+ Composite comp = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout(1, true);
+ comp.setLayout(layout);
+ comp.setFont(font);
+
+ GridData gd = new GridData(GridData.FILL_BOTH);
+ comp.setLayoutData(gd);
+ setControl(comp);
+
+ createTargetGroup(comp);
+ createProgramGroup(comp);
+ }
+
+ private void createTargetGroup(Composite parent) {
+ Font font = parent.getFont();
+
+ Group group = new Group(parent, SWT.NONE);
+ GridLayout top_layout = new GridLayout();
+ top_layout.verticalSpacing = 0;
+ top_layout.numColumns = 2;
+ group.setLayout(top_layout);
+ group.setLayoutData(new GridData(GridData.FILL_BOTH));
+ group.setFont(font);
+ group.setText("Target");
+
+ createVerticalSpacer(group, top_layout.numColumns);
+
+ Label host_label = new Label(group, SWT.NONE);
+ host_label.setText("Target ID:");
+ host_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+ host_label.setFont(font);
+
+ peer_id_text = new Text(group, SWT.SINGLE | SWT.BORDER);
+ peer_id_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ peer_id_text.setFont(font);
+ peer_id_text.setEditable(false);
+ peer_id_text.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ updateLaunchConfigurationDialog();
+ }
+ });
+
+ createVerticalSpacer(group, top_layout.numColumns);
+
+ Label peer_label = new Label(group, SWT.NONE);
+ peer_label.setText("Available targets:");
+ peer_label.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+ peer_label.setFont(font);
+
+ if (peer_info == null) loadPeerInfo(null);
+
+ peer_tree = new Tree(group, SWT.VIRTUAL | SWT.BORDER | SWT.SINGLE);
+ GridData gd = new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1);
+ gd.minimumHeight = 150;
+ peer_tree.setLayoutData(gd);
+
+ for (int i = 0; i < 5; i++) {
+ TreeColumn column = new TreeColumn(peer_tree, SWT.LEAD, i);
+ column.setMoveable(true);
+ switch (i) {
+ case 0:
+ column.setText("Name");
+ column.setWidth(120);
+ break;
+ case 1:
+ column.setText("OS");
+ column.setWidth(100);
+ break;
+ case 2:
+ column.setText("Transport");
+ column.setWidth(60);
+ break;
+ case 3:
+ column.setText("Host");
+ column.setWidth(100);
+ break;
+ case 4:
+ column.setText("Port");
+ column.setWidth(40);
+ break;
+ }
+ }
+
+ peer_tree.setHeaderVisible(true);
+ peer_tree.setFont(font);
+ peer_tree.setItemCount(peer_info.length);
+ peer_tree.addListener(SWT.SetData, new Listener() {
+ public void handleEvent(Event event) {
+ TreeItem item = (TreeItem)event.item;
+ PeerInfo info = findPeerInfo(item);
+ fillItem(item, info);
+ }
+ });
+ peer_tree.addSelectionListener(new SelectionListener() {
+ public void widgetDefaultSelected(SelectionEvent e) {
+ }
+ public void widgetSelected(SelectionEvent e) {
+ TreeItem[] selections = peer_tree.getSelection();
+ if (selections.length > 0) {
+ assert selections.length == 1;
+ PeerInfo info = findPeerInfo(selections[0]);
+ peer_id_text.setText(getPath(info));
+ }
+ }
+ });
+
+ createVerticalSpacer(group, top_layout.numColumns);
+
+ Button button_test = new Button(group, SWT.PUSH);
+ button_test.setText("Run &Diagnostics");
+ button_test.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+ button_test.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ TreeItem[] selection = peer_tree.getSelection();
+ if (selection.length > 0) {
+ assert selection.length == 1;
+ runDiagnostics(selection[0], false);
+ }
+ }
+ });
+
+ Button button_loop = new Button(group, SWT.PUSH);
+ button_loop.setText("Diagnostics &Loop");
+ button_loop.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
+ button_loop.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ TreeItem[] selection = peer_tree.getSelection();
+ if (selection.length > 0) {
+ assert selection.length == 1;
+ runDiagnostics(selection[0], true);
+ }
+ }
+ });
+ }
+
+ private void createProgramGroup(Composite parent) {
+ display = parent.getDisplay();
+
+ Font font = parent.getFont();
+
+ Group group = new Group(parent, SWT.NONE);
+ GridLayout top_layout = new GridLayout();
+ group.setLayout(top_layout);
+ group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ group.setFont(font);
+ group.setText("Program");
+
+ program_text = new Text(group, SWT.SINGLE | SWT.BORDER);
+ program_text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ program_text.setFont(font);
+ }
+
+ @Override
+ public void dispose() {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ for (Iterator<LocatorListener> i = listeners.keySet().iterator(); i.hasNext();) {
+ LocatorListener listener = i.next();
+ listeners.get(listener).removeListener(listener);
+ }
+ listeners.clear();
+ peer_info = null;
+ display = null;
+ }
+ });
+ for (Image i : image_cache.values()) i.dispose();
+ image_cache.clear();
+ super.dispose();
+ }
+
+ public String getName() {
+ return "Main";
+ }
+
+ @Override
+ public Image getImage() {
+ return getImage("icons/tcf.gif");
+ }
+
+ public void initializeFrom(ILaunchConfiguration configuration) {
+ try {
+ String id = configuration.getAttribute(
+ TCFLaunchDelegate.ATTR_PEER_ID, (String)null);
+ if (id != null) {
+ peer_id_text.setText(id);
+ TreeItem item = findItem(findPeerInfo(id));
+ if (item != null) peer_tree.setSelection(item);
+ }
+ program_text.setText(configuration.getAttribute(
+ TCFLaunchDelegate.ATTR_PROGRAM_FILE, "")); //$NON-NLS-1$
+ }
+ catch (CoreException e) {
+ setErrorMessage(e.getMessage());
+ }
+ }
+
+ public boolean isValid(ILaunchConfiguration launchConfig) {
+ String id = peer_id_text.getText().trim();
+ if (id.length() == 0) {
+ setErrorMessage("Specify a target ID");
+ return false;
+ }
+ setErrorMessage(null);
+ return super.isValid(launchConfig);
+ }
+
+ public void performApply(ILaunchConfigurationWorkingCopy configuration) {
+ String id = peer_id_text.getText().trim();
+ if (id.length() == 0) id = null;
+ configuration.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, id);
+ String nm = program_text.getText().trim();
+ if (nm.length() == 0) nm = null;
+ configuration.setAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, nm);
+ }
+
+ public void setDefaults(ILaunchConfigurationWorkingCopy configuration) {
+ configuration.setAttribute(TCFLaunchDelegate.ATTR_PEER_ID, "TCFLocal");
+ configuration.setAttribute(TCFLaunchDelegate.ATTR_PROGRAM_FILE, (String)null);
+ }
+
+ private void loadPeerInfo(final PeerInfo parent) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (parent == null) {
+ ILocator locator = Protocol.getLocator();
+ Map<String,IPeer> map = locator.getPeers();
+ PeerInfo[] buf = new PeerInfo[map.size()];
+ int n = 0;
+ for (Iterator<IPeer> i = map.values().iterator(); i.hasNext();) {
+ IPeer p = i.next();
+ PeerInfo info = new PeerInfo();
+ info.parent = parent;
+ info.index = n;
+ info.attrs = new HashMap<String,String>(p.getAttributes());
+ buf[n++] = info;
+ }
+ LocatorListener listener = new LocatorListener(parent);
+ listeners.put(listener, locator);
+ locator.addListener(listener);
+ assert peer_info == null;
+ peer_info = buf;
+ }
+ else {
+ PeerInfo[] buf = new PeerInfo[0];
+ assert parent.children == null;
+ parent.children = buf;
+ }
+ }
+ });
+ }
+
+ private PeerInfo findPeerInfo(TreeItem item) {
+ TreeItem parent = item.getParentItem();
+ if (parent == null) return peer_info[peer_tree.indexOf(item)];
+ PeerInfo info = findPeerInfo(parent);
+ if (info.children == null) loadPeerInfo(info);
+ return info.children[parent.indexOf(item)];
+ }
+
+ private PeerInfo findPeerInfo(String path) {
+ int i = path.lastIndexOf('/');
+ String id = null;
+ PeerInfo[] arr = null;
+ if (i < 0) {
+ if (peer_info == null) loadPeerInfo(null);
+ arr = peer_info;
+ id = path;
+ }
+ else {
+ PeerInfo p = findPeerInfo(path.substring(0, i));
+ if (p == null) return null;
+ if (p.children == null) loadPeerInfo(p);
+ arr = p.children;
+ id = path.substring(i + 1);
+ }
+ for (int n = 0; n < arr.length; n++) {
+ if (arr[n].attrs.get(IPeer.ATTR_ID).equals(id)) return arr[n];
+ }
+ return null;
+ }
+
+ private TreeItem findItem(PeerInfo info) {
+ if (info == null) return null;
+ if (info.parent == null) {
+ return peer_tree.getItem(info.index);
+ }
+ TreeItem i = findItem(info.parent);
+ if (i == null) return null;
+ peer_tree.showItem(i);
+ return i.getItem(info.index);
+ }
+
+ private interface DoneFindPeer {
+ void doneFindPeer(Collection<Throwable> errors, IPeer peer);
+ }
+
+ private void findPeer(TreeItem item, final DoneFindPeer done) {
+ assert display != null;
+ assert Thread.currentThread() == display.getThread();
+ final String path = getPath(findPeerInfo(item));
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ final Collection<Throwable> errors = new ArrayList<Throwable>();
+ try {
+ final int i = path.lastIndexOf('/');
+ if (i < 0) {
+ done.doneFindPeer(errors, Protocol.getLocator().getPeers().get(path));
+ }
+ else {
+ openChannel(path.substring(0, i), errors, new DoneOpenChannel() {
+ public void doneOpenChannel(IChannel channel) {
+ IPeer peer = null;
+ if (channel != null) {
+ ILocator locator = channel.getRemoteService(ILocator.class);
+ peer = locator.getPeers().get(path.substring(i + 1));
+ channel.close();
+ }
+ done.doneFindPeer(errors, peer);
+ }
+ });
+ }
+ }
+ catch (Throwable x) {
+ errors.add(x);
+ done.doneFindPeer(errors, null);
+ }
+ }
+ });
+ }
+
+ private interface DoneOpenChannel {
+ void doneOpenChannel(IChannel channel);
+ }
+
+ private static class OpenChannelListener implements IChannel.IChannelListener {
+
+ private final Collection<Throwable> errors;
+ private final IChannel channel;
+ private final DoneOpenChannel done;
+
+ OpenChannelListener(Collection<Throwable> errors, IChannel channel, DoneOpenChannel done) {
+ this.errors = errors;
+ this.channel = channel;
+ this.done = done;
+ channel.addChannelListener(this);
+ }
+
+ public void onChannelOpened() {
+ channel.removeChannelListener(this);
+ done.doneOpenChannel(channel);
+ }
+
+ public void congestionLevel(int level) {
+ }
+
+ public void onChannelClosed(Throwable e) {
+ errors.add(e);
+ channel.removeChannelListener(this);
+ done.doneOpenChannel(null);
+ }
+ }
+
+ private void openChannel(String path, final Collection<Throwable> errors, final DoneOpenChannel done) {
+ assert Protocol.isDispatchThread();
+ try {
+ int i = path.lastIndexOf('/');
+ if (i < 0) {
+ IPeer peer = Protocol.getLocator().getPeers().get(path);
+ if (peer == null) {
+ errors.add(new Exception("Peer not found: " + path));
+ done.doneOpenChannel(null);
+ return;
+ }
+ new OpenChannelListener(errors, peer.openChannel(), done);
+ }
+ else {
+ final String id = path.substring(i + 1);
+ openChannel(path.substring(0, i), errors, new DoneOpenChannel() {
+ public void doneOpenChannel(IChannel channel) {
+ if (errors.size() > 0) {
+ if (channel != null) channel.close();
+ done.doneOpenChannel(null);
+ }
+ else {
+ channel.redirect(id);
+ new OpenChannelListener(errors, channel, done);
+ }
+ }
+ });
+ }
+ }
+ catch (Throwable x) {
+ errors.add(x);
+ done.doneOpenChannel(null);
+ }
+ }
+
+ private void runDiagnostics(TreeItem item, boolean loop) {
+ final Shell shell = new Shell(getShell(), SWT.TITLE | SWT.PRIMARY_MODAL);
+ GridLayout layout = new GridLayout();
+ layout.verticalSpacing = 0;
+ layout.numColumns = 2;
+ shell.setLayout(layout);
+ shell.setText("Running Diagnostics...");
+ CLabel label = new CLabel(shell, SWT.NONE);
+ label.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false));
+ label.setText("Running Diagnostics...");
+ final TCFSelfTest[] test = new TCFSelfTest[1];
+ Button button_cancel = new Button(shell, SWT.PUSH);
+ button_cancel.setText("&Cancel");
+ button_cancel.setLayoutData(new GridData(GridData.END, GridData.CENTER, false, false));
+ button_cancel.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ if (test[0] != null) test[0].cancel();
+ }
+ });
+ }
+ });
+ createVerticalSpacer(shell, 0);
+ ProgressBar bar = new ProgressBar(shell, SWT.HORIZONTAL);
+ bar.setLayoutData(new GridData(GridData.FILL, GridData.CENTER, true, false, 2, 1));
+ shell.setDefaultButton(button_cancel);
+ shell.pack();
+ shell.setSize(483, shell.getSize().y);
+ Rectangle rc0 = getShell().getBounds();
+ Rectangle rc1 = shell.getBounds();
+ shell.setLocation(rc0.x + (rc0.width - rc1.width) / 2, rc0.y + (rc0.height - rc1.height) / 2);
+ shell.setVisible(true);
+ runDiagnostics(item, loop, test, shell, label, bar);
+ }
+
+ private void runDiagnostics(final TreeItem item, final boolean loop, final TCFSelfTest[] test,
+ final Shell shell, final CLabel label, final ProgressBar bar) {
+ final TCFSelfTest.TestListener done = new TCFSelfTest.TestListener() {
+ private String last_text = "";
+ private int last_count = 0;
+ private int last_total = 0;
+ public void progress(final String label_text, final int count_done, final int count_total) {
+ if ((label_text == null || last_text.equals(label_text)) &&
+ last_total == count_total &&
+ (count_done - last_count) / (float)count_total < 0.02f) return;
+ if (label_text != null) last_text = label_text;
+ last_total = count_total;
+ last_count = count_done;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ label.setText(last_text);
+ bar.setMinimum(0);
+ bar.setMaximum(last_total);
+ bar.setSelection(last_count);
+ }
+ });
+ }
+ public void done(final Collection<Throwable> errors) {
+ final boolean b = test[0] == null ? false : test[0].isCanceled();
+ test[0] = null;
+ display.asyncExec(new Runnable() {
+ public void run() {
+ if (errors.size() > 0) {
+ shell.dispose();
+ new TestErrorsDialog(getControl().getShell(),
+ getImage("icons/tcf.gif"), errors).open();
+ }
+ else if (loop && !b) {
+ runDiagnostics(item, true, test, shell, label, bar);
+ }
+ else {
+ shell.dispose();
+ }
+ }
+ });
+ }
+ };
+ findPeer(item, new DoneFindPeer() {
+ public void doneFindPeer(Collection<Throwable> errors, IPeer peer) {
+ if (errors.size() > 0) {
+ done.done(errors);
+ }
+ else {
+ try {
+ test[0] = new TCFSelfTest(peer, done);
+ }
+ catch (Throwable x) {
+ errors.add(x);
+ done.done(errors);
+ }
+ }
+ }
+ });
+ }
+
+ private void fillItem(TreeItem item, PeerInfo info) {
+ String text[] = new String[5];
+ text[0] = info.attrs.get(IPeer.ATTR_NAME);
+ text[1] = info.attrs.get(IPeer.ATTR_OS_NAME);
+ text[2] = info.attrs.get(IPeer.ATTR_TRANSPORT_NAME);
+ text[3] = info.attrs.get(IPeer.ATTR_IP_HOST);
+ text[4] = info.attrs.get(IPeer.ATTR_IP_PORT);
+ item.setText(text);
+ item.setImage(getImage(getImageName(info)));
+ if (info.children == null) loadPeerInfo(info);
+ item.setItemCount(info.children.length);
+ }
+
+ private String getPath(PeerInfo info) {
+ String id = info.attrs.get(IPeer.ATTR_ID);
+ if (info.parent == null) return id;
+ return getPath(info.parent) + "/" + id;
+ }
+
+ private Image getImage(String name) {
+ if (name == null) return null;
+ if (display == null) return null;
+ Image image = image_cache.get(name);
+ if (image == null) {
+ URL url = FileLocator.find(TCFUI.getDefault().getBundle(), new Path(name), null);
+ ImageDescriptor descriptor = null;
+ if (url == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ }
+ else {
+ descriptor = ImageDescriptor.createFromURL(url);
+ }
+ image = descriptor.createImage(display);
+ image_cache.put(name, image);
+ }
+ return image;
+ }
+
+ private String getImageName(PeerInfo info) {
+ return "icons/tcf.gif";
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFSelfTest.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFSelfTest.java
new file mode 100644
index 000000000..84208836d
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFSelfTest.java
@@ -0,0 +1,1207 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.launch;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+import com.windriver.tcf.api.services.IDiagnostics;
+import com.windriver.tcf.api.services.IFileSystem;
+import com.windriver.tcf.api.services.ILineNumbers;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRegisters;
+import com.windriver.tcf.api.services.IRunControl;
+import com.windriver.tcf.api.services.IDiagnostics.ISymbol;
+import com.windriver.tcf.api.services.IFileSystem.DirEntry;
+import com.windriver.tcf.api.services.IFileSystem.FileAttrs;
+import com.windriver.tcf.api.services.IFileSystem.FileSystemException;
+import com.windriver.tcf.api.services.IFileSystem.IFileHandle;
+import com.windriver.tcf.api.services.ILineNumbers.CodeArea;
+import com.windriver.tcf.api.services.IMemory.MemoryContext;
+import com.windriver.tcf.api.services.IMemory.MemoryError;
+import com.windriver.tcf.api.services.IRegisters.RegistersContext;
+import com.windriver.tcf.api.services.IRunControl.RunControlContext;
+import com.windriver.tcf.api.util.TCFFileInputStream;
+import com.windriver.tcf.api.util.TCFFileOutputStream;
+
+class TCFSelfTest {
+
+ private final static int NUM_CHANNELS = 4;
+
+ private final TestListener listener;
+ private final IChannel[] channels;
+ private final LinkedList<Runnable> pending_tests = new LinkedList<Runnable>();
+ private final Map<Test,IChannel> active_tests = new HashMap<Test,IChannel>();
+ private final Collection<Throwable> errors = new ArrayList<Throwable>();
+
+ private int count_total;
+ private int count_done;
+ private boolean canceled;
+ private boolean memory_lock;
+
+ public interface TestListener {
+ public void progress(String label, int done, int total);
+ public void done(Collection<Throwable> errors);
+ }
+
+ @SuppressWarnings("serial")
+ private static class CancelException extends Exception {
+ CancelException() {
+ super("Canceled");
+ }
+ }
+
+ private interface Test {
+ }
+
+ TCFSelfTest(IPeer peer, TestListener listener) throws IOException {
+ this.listener = listener;
+ pending_tests.add(new Runnable() {
+ public void run() {
+ for (IChannel channel : channels) new TestEcho(channel);
+ }
+ });
+ pending_tests.add(new Runnable() {
+ public void run() {
+ int i = 0;
+ for (IChannel channel : channels) new TestRCBP1(channel, i++);
+ }
+ });
+ pending_tests.add(new Runnable() {
+ public void run() {
+ for (IChannel channel : channels) new TestFileSystem(channel);
+ }
+ });
+ pending_tests.add(new Runnable() {
+ public void run() {
+ for (int i = 0; i < channels.length; i++) {
+ switch (i % 3) {
+ case 0: new TestEcho(channels[i]); break;
+ case 1: new TestRCBP1(channels[i], i); break;
+ case 2: new TestFileSystem(channels[i]); break;
+ }
+ }
+ }
+ });
+ count_total = NUM_CHANNELS * pending_tests.size() * 2;
+ channels = new IChannel[NUM_CHANNELS];
+ listener.progress("Openning communication channels...", count_done, count_total);
+ for (int i = 0; i < channels.length; i++) {
+ final IChannel channel = channels[i] = peer.openChannel();
+ channel.addChannelListener(new IChannel.IChannelListener() {
+
+ public void onChannelOpened() {
+ for (int i = 0; i < channels.length; i++) {
+ if (channels[i] == null) return;
+ if (channels[i].getState() != IChannel.STATE_OPEN) return;
+ }
+ runNextTest();
+ }
+
+ public void congestionLevel(int level) {
+ }
+
+ public void onChannelClosed(Throwable error) {
+ channel.removeChannelListener(this);
+ if (error == null && (!active_tests.isEmpty() || !pending_tests.isEmpty())) {
+ error = new IOException("Remote peer closed connection before all tests finished");
+ }
+ int cnt = 0;
+ for (int i = 0; i < channels.length; i++) {
+ if (channels[i] == channel) {
+ channels[i] = null;
+ if (error != null && !(error instanceof CancelException)) errors.add(error);
+ for (Iterator<Test> n = active_tests.keySet().iterator(); n.hasNext();) {
+ if (active_tests.get(n.next()) == channel) n.remove();
+ }
+ }
+ else if (channels[i] != null) {
+ cnt++;
+ }
+ }
+ if (cnt == 0) {
+ TCFSelfTest.this.listener.done(errors);
+ }
+ else if (active_tests.isEmpty()) {
+ for (int i = 0; i < channels.length; i++) {
+ if (channels[i] != null && channels[i].getState() != IChannel.STATE_CLOSED) {
+ if (errors.isEmpty()) channels[i].close();
+ else channels[i].terminate(new CancelException());
+ }
+ }
+ }
+ }
+ });
+ }
+ }
+
+ void cancel() {
+ if (canceled) return;
+ for (final Test t : active_tests.keySet()) {
+ if (t instanceof TestRCBP1) {
+ ((TestRCBP1)t).cancel(new Runnable() {
+ public void run() {
+ assert active_tests.get(t) == null;
+ cancel();
+ }
+ });
+ return;
+ }
+ }
+ canceled = true;
+ for (IChannel c : channels) {
+ if (c != null && c.getState() != IChannel.STATE_CLOSED) {
+ c.terminate(new CancelException());
+ }
+ }
+ }
+
+ boolean isCanceled() {
+ return canceled;
+ }
+
+ private class TestEcho implements Test, IDiagnostics.DoneEcho {
+
+ private final IDiagnostics diag;
+ private final LinkedList<String> msgs = new LinkedList<String>();
+ private int count = 0;
+
+ TestEcho(IChannel channel) {
+ diag = channel.getRemoteService(IDiagnostics.class);
+ listener.progress("Running Echo Test...", ++count_done, count_total);
+ active_tests.put(this, channel);
+ if (diag == null) {
+ done(this);
+ }
+ else {
+ for (int i = 0; i < 32; i++) sendMessage();
+ }
+ }
+
+ private void sendMessage() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(Integer.toHexString(count));
+ for (int i = 0; i < 64; i++) {
+ buf.append('-');
+ buf.append((char)(0x400 * i + count));
+ }
+ String s = buf.toString();
+ msgs.add(s);
+ diag.echo(s, this);
+ count++;
+ }
+
+ public void doneEcho(IToken token, Throwable error, String b) {
+ String s = msgs.removeFirst();
+ if (active_tests.get(this) == null) return;
+ if (error != null) {
+ errors.add(error);
+ done(this);
+ }
+ else if (!s.equals(b)) {
+ errors.add(new Exception("Echo test failed: " + s + " != " + b));
+ done(this);
+ }
+ else if (count < 0x400) {
+ sendMessage();
+ }
+ else if (msgs.isEmpty()){
+ done(this);
+ }
+ }
+ }
+
+ private class TestRCBP1 implements Test,
+ IDiagnostics.DoneGetTestList, IDiagnostics.DoneRunTest,
+ IRunControl.DoneGetContext, IRunControl.DoneGetChildren,
+ IRunControl.DoneGetState, IRunControl.RunControlListener,
+ IDiagnostics.DoneGetSymbol {
+
+ private final int channel_id;
+ private final IDiagnostics diag;
+ private final IMemory mm;
+ private final IRunControl rc;
+ private final IRegisters rg;
+ private final IBreakpoints bp;
+ private final ILineNumbers ln;
+ private final Map<String,IRunControl.RunControlContext> threads = new HashMap<String,IRunControl.RunControlContext>();
+ private final Map<String,SuspendedContext> suspended = new HashMap<String,SuspendedContext>();
+ private final Map<String,SuspendedContext> suspended_prev = new HashMap<String,SuspendedContext>();
+ private final Set<String> running = new HashSet<String>();
+ private final Map<IToken,String> get_state_cmds = new HashMap<IToken,String>();
+ private final Map<String,Map<String,IRegisters.RegistersContext>> regs =
+ new HashMap<String,Map<String,IRegisters.RegistersContext>>();
+
+ private String context_id; // Test process context ID
+ private IRunControl.RunControlContext context;
+ private String main_thread_id;
+ private Runnable pending_cancel;
+ private ISymbol func0;
+ private ISymbol func1;
+ private ISymbol func2;
+ private ISymbol array;
+ private int bp_cnt = 0;
+
+ private class SuspendedContext {
+ final String id;
+ final String pc;
+ final String reason;
+ final Map<String,Object> params;
+ boolean resumed;
+
+ SuspendedContext(String id, String pc, String reason, Map<String,Object> params) {
+ this.id = id;
+ this.pc = pc;
+ this.reason = reason;
+ this.params = params;
+ }
+ }
+
+ TestRCBP1(IChannel channel, int channel_id) {
+ this.channel_id = channel_id;
+ diag = channel.getRemoteService(IDiagnostics.class);
+ mm = channel.getRemoteService(IMemory.class);
+ rc = channel.getRemoteService(IRunControl.class);
+ rg = channel.getRemoteService(IRegisters.class);
+ bp = channel.getRemoteService(IBreakpoints.class);
+ ln = channel.getRemoteService(ILineNumbers.class);
+ active_tests.put(this, channel);
+ listener.progress("Running Run Control Test...", ++count_done, count_total);
+ if (diag == null || rc == null) {
+ done(this);
+ }
+ else if (bp == null) {
+ exit(new Exception("Remote Breakpoints service not found"));
+ }
+ else {
+ diag.getTestList(this);
+ }
+ }
+
+ public void doneGetTestList(IToken token, Throwable error, String[] list) {
+ assert active_tests.get(this) != null;
+ if (error != null) {
+ exit(error);
+ }
+ else {
+ for (int i = 0; i < list.length; i++) {
+ if (list[i].equals("RCBP1")) {
+ diag.runTest("RCBP1", this);
+ return;
+ }
+ }
+ }
+ exit(null);
+ }
+
+ public void doneRunTest(IToken token, Throwable error, String context_id) {
+ assert active_tests.get(this) != null;
+ assert this.context_id == null;
+ if (error != null) {
+ exit(error);
+ }
+ else {
+ this.context_id = context_id;
+ if (pending_cancel != null) {
+ Protocol.invokeLater(pending_cancel);
+ pending_cancel = null;
+ }
+ else {
+ diag.getSymbol(context_id, "tcf_test_func0", this);
+ diag.getSymbol(context_id, "tcf_test_func1", this);
+ diag.getSymbol(context_id, "tcf_test_func2", this);
+ diag.getSymbol(context_id, "tcf_test_array", this);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void doneGetSymbol(IToken token, Throwable error, ISymbol symbol) {
+ assert active_tests.get(this) != null;
+ assert this.context_id != null;
+ if (error != null) {
+ exit(error);
+ }
+ else if (!symbol.isGlobal()) {
+ exit(new Exception("Symbols 'tcf_test_*' must be global"));
+ }
+ else if (!symbol.isAbs()) {
+ exit(new Exception("Symbols 'tcf_test_*' must be absolute"));
+ }
+ else if (func0 == null) {
+ func0 = symbol;
+ }
+ else if (func1 == null) {
+ func1 = symbol;
+ }
+ else if (func2 == null) {
+ func2 = symbol;
+ }
+ else {
+ array = symbol;
+ Map<String,Object> m[] = new Map[4];
+ for (int i = 0; i < m.length; i++) {
+ m[i] = new HashMap();
+ m[i].put(IBreakpoints.PROP_ID, "TcfTestBP" + i);
+ m[i].put(IBreakpoints.PROP_ENABLED, Boolean.TRUE);
+ switch (i) {
+ case 0:
+ m[i].put(IBreakpoints.PROP_ADDRESS, func0.getValue().toString());
+ m[i].put(IBreakpoints.PROP_CONDITION, "$thread!=\"\"");
+ break;
+ case 1:
+ m[i].put(IBreakpoints.PROP_ADDRESS, "(31+1)/16+tcf_test_func1-2");
+ m[i].put(IBreakpoints.PROP_CONDITION, "tcf_test_func0!=tcf_test_func1");
+ break;
+ case 2:
+ m[i].put(IBreakpoints.PROP_ADDRESS, "tcf_test_func2");
+ m[i].put(IBreakpoints.PROP_ENABLED, Boolean.FALSE);
+ break;
+ case 3:
+ m[i].put(IBreakpoints.PROP_ID, "TcfTestBP3" + channel_id);
+ m[i].put(IBreakpoints.PROP_ENABLED, Boolean.FALSE);
+ m[i].put(IBreakpoints.PROP_ADDRESS, "tcf_test_func2");
+ break;
+ }
+ }
+ bp.set(m, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) {
+ exit(error);
+ }
+ else {
+ rc.getContext(context_id, TestRCBP1.this);
+ }
+ }
+ });
+ }
+ }
+
+ public void doneGetContext(IToken token, Exception error, RunControlContext context) {
+ if (canceled) return;
+ if (error != null) {
+ exit(error);
+ }
+ else {
+ if (this.context == null) {
+ this.context = context;
+ assert context_id.equals(context.getID());
+ assert threads.isEmpty();
+ assert running.isEmpty();
+ assert suspended.isEmpty();
+ rc.addListener(this);
+ }
+ rc.getChildren(context.getID(), this);
+ if (context.hasState()) {
+ threads.put(context.getID(), context);
+ get_state_cmds.put(context.getState(this), context.getID());
+ }
+ }
+ }
+
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ if (canceled) return;
+ if (error != null) {
+ exit(error);
+ }
+ else {
+ for (String id : contexts) rc.getContext(id, this);
+ }
+ }
+
+ public void doneGetState(IToken token, Exception error,
+ boolean suspended, String pc, String reason,
+ Map<String, Object> params) {
+ final String id = get_state_cmds.remove(token);
+ if (canceled) return;
+ if (id == null) {
+ exit(new Exception("Invalid getState responce"));
+ }
+ else if (!suspended) {
+ if (this.suspended.get(id) != null) {
+ exit(new Exception("Invalid result of getState command"));
+ }
+ else {
+ running.add(id);
+ }
+ }
+ else {
+ assert threads.get(id) != null;
+ if (running.contains(id)) {
+ exit(new Exception("Invalid result of getState command"));
+ }
+ else {
+ SuspendedContext sc = this.suspended.get(id);
+ if (sc != null) {
+ if (!sc.pc.equals(pc) || !sc.reason.equals(reason)) {
+ exit(new Exception("Invalid result of getState command"));
+ }
+ else {
+ resume(sc);
+ }
+ }
+ else {
+ if (main_thread_id != null) {
+ exit(new Exception("Missing contextSuspended event for " + id));
+ }
+ else if ("Breakpoint".equals(reason)) {
+ exit(new Exception("Invalid suspend reason of main thread after test start: " + reason + " " + pc));
+ }
+ else {
+ main_thread_id = id;
+ final SuspendedContext sx = new SuspendedContext(id, pc, reason, params);
+ this.suspended.put(id, sx);
+ final String bp_id = "TcfTestBP3" + channel_id;
+ Map<String,Object> m = new HashMap<String,Object>();
+ m.put(IBreakpoints.PROP_ID, bp_id);
+ m.put(IBreakpoints.PROP_ENABLED, Boolean.FALSE);
+ m.put(IBreakpoints.PROP_ADDRESS, "tcf_test_func2");
+ m.put(IBreakpoints.PROP_CONDITION, "$thread==\"" + id + "\"");
+ bp.change(m, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ Protocol.sync(new Runnable() {
+ public void run() {
+ bp.enable(new String[]{ bp_id }, new IBreakpoints.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) exit(error);
+ }
+ });
+ resume(sx);
+ }
+ });
+ }
+ }
+ }
+ }
+ }
+
+ public void containerResumed(String[] context_ids) {
+ for (String id : context_ids) contextResumed(id);
+ }
+
+ public void containerSuspended(String context, String pc,
+ String reason, Map<String, Object> params,
+ String[] suspended_ids) {
+ for (String id : suspended_ids) {
+ if (id.equals(context)) continue;
+ contextSuspended(id, null, null, null);
+ }
+ contextSuspended(context, pc, reason, params);
+ }
+
+ public void contextAdded(RunControlContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ if (threads.get(contexts[i].getID()) != null) {
+ exit(new Exception("Invalid contextAdded event"));
+ return;
+ }
+ if (context.getID().equals(contexts[i].getProperties().get("ParentID"))) {
+ threads.put(contexts[i].getID(), contexts[i]);
+ running.add(contexts[i].getID());
+ }
+ }
+ }
+
+ public void contextChanged(RunControlContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ if (contexts[i].getID().equals(context.getID())) {
+ context = contexts[i];
+ }
+ if (context.getID().equals(contexts[i].getProperties().get("ProcessID"))) {
+ threads.put(contexts[i].getID(), contexts[i]);
+ }
+ }
+ }
+
+ public void contextException(String context, String msg) {
+ if (context.equals(this.context.getID()) || threads.get(context) != null) {
+ exit(new Exception(msg));
+ }
+ }
+
+ public void contextRemoved(String[] contexts) {
+ for (String id : contexts) {
+ if (suspended.get(id) != null) {
+ exit(new Exception("Invalid contextRemoved event"));
+ return;
+ }
+ threads.remove(id);
+ running.remove(id);
+ if (threads.isEmpty()) {
+ if (bp_cnt != 30) {
+ exit(new Exception("Test main thread breakpoint count = " + bp_cnt + ", expected 30"));
+ }
+ rc.removeListener(this);
+ // Flush communication channel of pending commands
+ Protocol.sync(new Runnable() {
+ public void run() {
+ exit(null);
+ }
+ });
+ }
+ }
+ }
+
+ public void contextResumed(String id) {
+ if (threads.get(id) == null) return;
+ SuspendedContext sc = suspended.remove(id);
+ if (!isAlienBreakpoint(sc)) suspended_prev.put(id, sc);
+ running.add(id);
+ }
+
+ private String toSymName(long addr) {
+ if (func0.getValue().longValue() == addr) return "tcf_test_func0";
+ if (func1.getValue().longValue() == addr) return "tcf_test_func1";
+ if (func2.getValue().longValue() == addr) return "tcf_test_func2";
+ return "*no name*";
+ }
+
+ private void checkSuspendedContext(SuspendedContext sp, ISymbol sym) {
+ long pc = Long.parseLong(sp.pc);
+ if (pc != sym.getValue().longValue() || !"Breakpoint".equals(sp.reason)) {
+ exit(new Exception("Invalid contextSuspended event: " + sp.id + " '" + toSymName(pc) + "' " + sp.pc + " " + sp.reason +
+ ", expected breakpoint at '" + toSymName(sym.getValue().longValue()) + "' " + sym.getValue()));
+ }
+ }
+
+ private boolean isAlienBreakpoint(SuspendedContext sc) {
+ // Check if context suspended by a breakpoint from another debug session
+ // Test should ignore such breakpoints.
+ if (!"Breakpoint".equals(sc.reason)) return false;
+ long pc = Long.parseLong(sc.pc);
+ if (pc == func0.getValue().longValue()) return false;
+ if (pc == func1.getValue().longValue()) return false;
+ if (pc == func2.getValue().longValue()) return false;
+ return true;
+ }
+
+ public void contextSuspended(String id, String pc, String reason, Map<String, Object> params) {
+ if (threads.get(id) == null) return;
+ assert main_thread_id != null;
+ running.remove(id);
+ SuspendedContext sc = suspended.get(id);
+ if (sc != null) {
+ if (!sc.pc.equals(pc) || !sc.reason.equals(reason)) {
+ exit(new Exception("Invalid contextSuspended event"));
+ }
+ }
+ else {
+ sc = new SuspendedContext(id, pc, reason, params);
+ suspended.put(id, sc);
+ if (!isAlienBreakpoint(sc)) {
+ if ("Breakpoint".equals(reason) && id.equals(main_thread_id)) bp_cnt++;
+ SuspendedContext sp = suspended_prev.get(id);
+ if (sp != null) {
+ if (Long.parseLong(sc.pc) == func2.getValue().longValue()) {
+ checkSuspendedContext(sp, func1);
+ }
+ else if (Long.parseLong(sc.pc) == func1.getValue().longValue()) {
+ checkSuspendedContext(sp, func0);
+ }
+ else if (Long.parseLong(sc.pc) == func0.getValue().longValue()) {
+ if (id.equals(main_thread_id)) {
+ if ("Breakpoint".equals(sp.reason)) {
+ checkSuspendedContext(sp, func2);
+ }
+ }
+ else {
+ checkSuspendedContext(sp, func1);
+ }
+ }
+ }
+ }
+ }
+ final SuspendedContext sc0 = sc;
+ ILineNumbers.DoneMapToSource ln_done = new ILineNumbers.DoneMapToSource() {
+ public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) {
+ if (error != null) exit(error);
+ if (mm != null) runMemoryTest(sc0);
+ else if (rg != null) runRegistersTest(sc0);
+ else resume(sc0);
+ }
+ };
+ if (ln != null) {
+ BigInteger x = new BigInteger(pc);
+ BigInteger y = x.add(BigInteger.valueOf(1));
+ ln.mapToSource(id, x, y, ln_done);
+ }
+ else {
+ ln_done.doneMapToSource(null, null, null);
+ }
+ }
+
+ private void resume(final SuspendedContext sc) {
+ IRunControl.RunControlContext ctx = threads.get(sc.id);
+ if (ctx != null && !sc.resumed) {
+ sc.resumed = true;
+ ctx.resume(IRunControl.RM_RESUME, 1, new IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (canceled) return;
+ if (active_tests.get(this) == null) return;
+ if (threads.get(sc.id) == null) return;
+ if (error != null) exit(error);
+ }
+ });
+ }
+ }
+
+ private void runMemoryTest(final SuspendedContext sc) {
+ if (memory_lock) {
+ resume(sc);
+ return;
+ }
+ memory_lock = true;
+ mm.getContext(context_id, new IMemory.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, final MemoryContext mem_ctx) {
+ if (error != null) {
+ exit(error);
+ return;
+ }
+ if (!context_id.equals(mem_ctx.getID())) {
+ exit(new Exception("Bad memory context data: invalid ID"));
+ }
+ Object pid = context.getProperties().get("ProcessID");
+ if (pid != null && !pid.equals(mem_ctx.getProperties().get("ProcessID"))) {
+ exit(new Exception("Bad memory context data: invalid ProcessID"));
+ }
+ final boolean big_endian = mem_ctx.isBigEndian();
+ final int addr_size = mem_ctx.getAddressSize();
+ final byte[] buf = new byte[0x1000];
+ mem_ctx.get(array.getValue(), 1, buf, 0, addr_size, 0, new IMemory.DoneMemory() {
+ public void doneMemory(IToken token, MemoryError error) {
+ byte[] tmp = new byte[addr_size + 1];
+ tmp[0] = 0; // Extra byte to avoid sign extension by BigInteger
+ if (big_endian) {
+ System.arraycopy(buf, 0, tmp, 1, addr_size);
+ }
+ else {
+ for (int i = 0; i < addr_size; i++) {
+ tmp[i + 1] = buf[addr_size - i - 1];
+ }
+ }
+ Number mem_address = new BigInteger(tmp);
+ testSetMemoryCommand(sc, mem_ctx, mem_address, buf);
+ }
+ });
+ }
+ });
+ }
+
+ private void testSetMemoryCommand(final SuspendedContext sc,
+ final IMemory.MemoryContext mem_ctx,
+ final Number addr, final byte[] buf) {
+ final byte[] data = new byte[buf.length];
+ new Random().nextBytes(data);
+ mem_ctx.set(addr, 1, data, 0, data.length, 0, new IMemory.DoneMemory() {
+ public void doneMemory(IToken token, MemoryError error) {
+ if (error != null) {
+ exit(error);
+ return;
+ }
+ mem_ctx.get(addr, 1, buf, 0, buf.length, 0, new IMemory.DoneMemory() {
+ public void doneMemory(IToken token, MemoryError error) {
+ if (error != null) {
+ exit(error);
+ return;
+ }
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] != buf[i]) {
+ exit(new Exception(
+ "Invalid Memory.get responce: wrong data at offset " + i +
+ ", expected " + data[i] + ", actual " + buf[i]));
+ return;
+ }
+ }
+ testFillMemoryCommand(sc, mem_ctx, addr, buf);
+ }
+ });
+ }
+ });
+ }
+
+ private void testFillMemoryCommand(final SuspendedContext sc,
+ final IMemory.MemoryContext mem_ctx,
+ final Number addr, final byte[] buf) {
+ final byte[] data = new byte[buf.length / 7];
+ new Random().nextBytes(data);
+ mem_ctx.fill(addr, 1, data, buf.length, 0, new IMemory.DoneMemory() {
+ public void doneMemory(IToken token, MemoryError error) {
+ if (error != null) {
+ exit(error);
+ return;
+ }
+ mem_ctx.get(addr, 1, buf, 0, buf.length, 0, new IMemory.DoneMemory() {
+ public void doneMemory(IToken token, MemoryError error) {
+ if (error != null) {
+ exit(error);
+ return;
+ }
+ for (int i = 0; i < data.length; i++) {
+ if (data[i % data.length] != buf[i]) {
+ exit(new Exception(
+ "Invalid Memory.get responce: wrong data at offset " + i +
+ ", expected " + data[i % data.length] + ", actual " + buf[i]));
+ return;
+ }
+ }
+ memory_lock = false;
+ if (rg != null) runRegistersTest(sc);
+ else resume(sc);
+ }
+ });
+ }
+ });
+ }
+
+ private void runRegistersTest(final SuspendedContext sc) {
+ if (regs.get(sc.id) == null) {
+ final Map<String,IRegisters.RegistersContext> reg_map =
+ new HashMap<String,IRegisters.RegistersContext>();
+ final Set<IToken> cmds = new HashSet<IToken>();
+ regs.put(sc.id, reg_map);
+ cmds.add(rg.getChildren(sc.id, new IRegisters.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] context_ids) {
+ cmds.remove(token);
+ if (error != null) {
+ for (IToken t : cmds) t.cancel();
+ exit(error);
+ return;
+ }
+ for (final String id : context_ids) {
+ cmds.add(rg.getChildren(id, this));
+ cmds.add(rg.getContext(id, new IRegisters.DoneGetContext() {
+ public void doneGetContext(IToken token,
+ Exception error,
+ RegistersContext context) {
+ cmds.remove(token);
+ if (error != null) {
+ for (IToken t : cmds) t.cancel();
+ exit(error);
+ return;
+ }
+ reg_map.put(id, context);
+ if (cmds.isEmpty()) {
+ testGetSetRegisterCommands(sc);
+ }
+ }
+ }));
+ }
+ }
+ }));
+ }
+ else {
+ testGetSetRegisterCommands(sc);
+ }
+ }
+
+ private void testGetSetRegisterCommands(final SuspendedContext sc) {
+ final Set<IToken> cmds = new HashSet<IToken>();
+ Map<String,IRegisters.RegistersContext> reg_map = regs.get(sc.id);
+ for (final IRegisters.RegistersContext ctx : reg_map.values()) {
+ if (!ctx.isReadable()) continue;
+ if (ctx.isReadOnce()) continue;
+ String[] fmts = ctx.getAvailableFormats();
+ for (final String fmt : fmts) {
+ cmds.add(ctx.get(fmt, new IRegisters.DoneGet() {
+ public void doneGet(IToken token, Exception error, String value) {
+ cmds.remove(token);
+ if (error != null) {
+ for (IToken t : cmds) t.cancel();
+ exit(error);
+ return;
+ }
+ cmds.add(ctx.set(fmt, value, new IRegisters.DoneSet() {
+ public void doneSet(IToken token, Exception error) {
+ cmds.remove(token);
+ if (error != null) {
+ for (IToken t : cmds) t.cancel();
+ exit(error);
+ return;
+ }
+ if (cmds.isEmpty()) {
+ resume(sc);
+ }
+ }
+ }));
+ }
+ }));
+ }
+ }
+ if (cmds.isEmpty()) {
+ resume(sc);
+ }
+ }
+
+ void cancel(final Runnable done) {
+ if (rc != null) rc.removeListener(this);
+ if (context_id == null) {
+ if (pending_cancel != null) {
+ exit(null);
+ }
+ else {
+ pending_cancel = done;
+ }
+ }
+ else {
+ diag.cancelTest(context_id, new IDiagnostics.DoneCancelTest() {
+ public void doneCancelTest(IToken token, Throwable error) {
+ exit(error);
+ done.run();
+ }
+ });
+ }
+ }
+
+ private void exit(Throwable x) {
+ if (active_tests.get(this) == null) return;
+ if (pending_cancel != null) {
+ pending_cancel.run();
+ pending_cancel = null;
+ }
+ else {
+ if (x != null) errors.add(x);
+ if (rc != null) rc.removeListener(this);
+ }
+ done(this);
+ }
+ }
+
+ private int file_count = 0;
+
+ private class TestFileSystem implements Test, IFileSystem.DoneStat,
+ IFileSystem.DoneOpen, IFileSystem.DoneClose,
+ IFileSystem.DoneWrite, IFileSystem.DoneRead,
+ IFileSystem.DoneRename, IFileSystem.DoneRealPath,
+ IFileSystem.DoneRemove, IFileSystem.DoneRoots,
+ IFileSystem.DoneReadDir {
+
+ private static final int
+ STATE_PRE = 0,
+ STATE_WRITE = 1,
+ STATE_READ = 2,
+ STATE_OUT = 3,
+ STATE_INP = 4,
+ STATE_EXIT = 5;
+
+ private final IFileSystem files;
+ private final byte[] data = new byte[0x1000];
+ private String root;
+ private String tmp_path;
+ private String file_name;
+ private IFileHandle handle;
+ private int state = STATE_PRE;
+
+ TestFileSystem(IChannel channel) {
+ files = channel.getRemoteService(IFileSystem.class);
+ active_tests.put(this, channel);
+ listener.progress("Running File System Test...", ++count_done, count_total);
+ if (files == null) {
+ done(this);
+ }
+ else {
+ files.roots(this);
+ }
+ }
+
+ public void doneRoots(IToken token, FileSystemException error, DirEntry[] entries) {
+ assert state == STATE_PRE;
+ if (error != null) {
+ error(error);
+ }
+ else if (entries == null || entries.length == 0) {
+ error(new Exception("Invalid FileSysrem.roots responce: empty roots array"));
+ }
+ else {
+ root = entries[0].filename;
+ files.opendir(root, this);
+ }
+ }
+
+ public void doneReadDir(IToken token, FileSystemException error,
+ DirEntry[] entries, boolean eof) {
+ assert state == STATE_PRE;
+ if (error != null) {
+ error(error);
+ }
+ else {
+ if (entries != null && tmp_path == null) {
+ for (DirEntry e : entries) {
+ if (e.filename.equals("tmp") || e.filename.equalsIgnoreCase("temp")) {
+ tmp_path = root + "/" + e.filename;
+ break;
+ }
+ }
+ }
+ if (eof) {
+ if (tmp_path == null) {
+ error(new Exception("File system test filed: cannot find temporary directory"));
+ return;
+ }
+ files.close(handle, this);
+ }
+ else {
+ files.readdir(handle, this);
+ }
+ }
+ }
+
+ public void doneStat(IToken token, FileSystemException error, FileAttrs attrs) {
+ if (error != null) {
+ error(error);
+ }
+ else if (state == STATE_READ) {
+ if (attrs.size != data.length) {
+ error(new Exception("Invalid FileSysrem.fstat responce: wrong file size"));
+ }
+ else {
+ files.close(handle, this);
+ }
+ }
+ else {
+ file_name = tmp_path + "/tcf-test-" + (file_count++) + ".tmp";
+ files.open(file_name, IFileSystem.O_CREAT | IFileSystem.O_TRUNC | IFileSystem.O_WRITE, null, this);
+ }
+ }
+
+ public void doneOpen(IToken token, FileSystemException error, final IFileHandle handle) {
+ if (error != null) {
+ error(error);
+ }
+ else {
+ this.handle = handle;
+ if (state == STATE_READ) {
+ files.read(handle, 0, data.length + 1, this);
+ }
+ else if (state == STATE_WRITE) {
+ new Random().nextBytes(data);
+ files.write(handle, 0, data, 0, data.length, this);
+ }
+ else if (state == STATE_INP) {
+ Thread thread = new Thread() {
+ public void run() {
+ try {
+ InputStream inp = new TCFFileInputStream(handle);
+ int i = 0;
+ for (;;) {
+ int ch = inp.read();
+ if (ch < 0) break;
+ int dt = data[i % data.length] & 0xff;
+ if (ch != dt) {
+ error(new Exception("Invalid TCFFileInputStream.read responce: wrong data at offset " + i +
+ ", expected " + dt + ", actual " + ch));
+ }
+ i++;
+ }
+ if (i != data.length * 16) {
+ error(new Exception("Invalid TCFFileInputStream.read responce: wrong file length: " +
+ "expected " + data.length + ", actual " + i));
+ }
+ inp.close();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ state = STATE_EXIT;
+ files.rename(file_name, file_name + ".rnm", TestFileSystem.this);
+ }
+ });
+ }
+ catch (Throwable x) {
+ error(x);
+ }
+ }
+ private void error(final Throwable x) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ TestFileSystem.this.error(x);
+ }
+ });
+ }
+ };
+ thread.setName("TCF FileSystem Test");
+ thread.start();
+ }
+ else if (state == STATE_OUT) {
+ new Random().nextBytes(data);
+ Thread thread = new Thread() {
+ public void run() {
+ try {
+ OutputStream out = new TCFFileOutputStream(handle);
+ for (int i = 0; i < data.length * 16; i++) {
+ out.write(data[i % data.length] & 0xff);
+ }
+ out.close();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ state = STATE_INP;
+ files.open(file_name, IFileSystem.O_READ, null, TestFileSystem.this);
+ }
+ });
+ }
+ catch (Throwable x) {
+ error(x);
+ }
+ }
+ private void error(final Throwable x) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ TestFileSystem.this.error(x);
+ }
+ });
+ }
+ };
+ thread.setName("TCF FileSystem Test");
+ thread.start();
+ }
+ else {
+ assert state == STATE_PRE;
+ files.readdir(handle, this);
+ }
+ }
+ }
+
+ public void doneWrite(IToken token, FileSystemException error) {
+ if (error != null) {
+ error(error);
+ }
+ else {
+ files.close(handle, this);
+ }
+ }
+
+ public void doneRead(IToken token, FileSystemException error, byte[] data, boolean eof) {
+ if (error != null) {
+ error(error);
+ }
+ else if (!eof) {
+ error(new Exception("Invalid FileSysrem.read responce: EOF expected"));
+ }
+ else if (data.length != this.data.length) {
+ error(new Exception("Invalid FileSysrem.read responce: wrong data array size"));
+ }
+ else {
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] != this.data[i]) {
+ error(new Exception("Invalid FileSysrem.read responce: wrong data at offset " + i +
+ ", expected " + this.data[i] + ", actual " + data[i]));
+ return;
+ }
+ }
+ files.fstat(handle, this);
+ }
+ }
+
+ public void doneClose(IToken token, FileSystemException error) {
+ if (error != null) {
+ error(error);
+ }
+ else {
+ handle = null;
+ if (state == STATE_PRE) {
+ files.realpath(tmp_path, this);
+ }
+ else if (state == STATE_WRITE) {
+ state = STATE_READ;
+ files.open(file_name, IFileSystem.O_READ, null, this);
+ }
+ else if (state == STATE_READ) {
+ state = STATE_OUT;
+ files.open(file_name, IFileSystem.O_WRITE, null, this);
+ }
+ else {
+ assert false;
+ }
+ }
+ }
+
+ public void doneRename(IToken token, FileSystemException error) {
+ assert state == STATE_EXIT;
+ if (error != null) {
+ error(error);
+ }
+ else {
+ files.realpath(file_name + ".rnm", this);
+ }
+ }
+
+ public void doneRealPath(IToken token, FileSystemException error, String path) {
+ if (error != null) {
+ error(error);
+ }
+ else if (state == STATE_PRE) {
+ state = STATE_WRITE;
+ tmp_path = path;
+ files.stat(tmp_path, this);
+ }
+ else if (!path.equals(file_name + ".rnm")) {
+ error(new Exception("Invalid FileSysrem.realpath responce: " + path));
+ }
+ else {
+ files.remove(file_name + ".rnm", this);
+ }
+ }
+
+ public void doneRemove(IToken token, FileSystemException error) {
+ assert state == STATE_EXIT;
+ if (error != null) {
+ error(error);
+ }
+ else {
+ done(this);
+ }
+ }
+
+ private void error(Throwable x) {
+ if (active_tests.get(this) == null) return;
+ errors.add(x);
+ done(this);
+ }
+ }
+
+ private void done(Test test) {
+ assert active_tests.get(test) != null;
+ active_tests.remove(test);
+ listener.progress(null, ++count_done, count_total);
+ if (active_tests.isEmpty()) runNextTest();
+ }
+
+ private void runNextTest() {
+ while (active_tests.isEmpty()) {
+ if (canceled || errors.size() > 0 || pending_tests.size() == 0) {
+ for (IChannel channel : channels) {
+ if (channel != null && channel.getState() != IChannel.STATE_CLOSED) {
+ if (errors.isEmpty()) channel.close();
+ else channel.terminate(new CancelException());
+ }
+ }
+ return;
+ }
+ pending_tests.removeFirst().run();
+ }
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFTabGroup.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFTabGroup.java
new file mode 100644
index 000000000..8d06cafd5
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TCFTabGroup.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.launch;
+
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
+import org.eclipse.debug.ui.CommonTab;
+import org.eclipse.debug.ui.EnvironmentTab;
+import org.eclipse.debug.ui.ILaunchConfigurationDialog;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+import org.eclipse.debug.ui.sourcelookup.SourceLookupTab;
+
+/**
+ * Launch configuration dialog tab group for Target Communication Framework
+ */
+public class TCFTabGroup extends AbstractLaunchConfigurationTabGroup {
+
+ public void createTabs(ILaunchConfigurationDialog dialog, String mode) {
+ setTabs(new ILaunchConfigurationTab[] {
+ new TCFMainTab(),
+ new TCFArgumentsTab(),
+ new EnvironmentTab(),
+ new SourceLookupTab(),
+ new CommonTab()
+ });
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TestErrorsDialog.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TestErrorsDialog.java
new file mode 100644
index 000000000..312e85c9a
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/launch/TestErrorsDialog.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.launch;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+class TestErrorsDialog extends Dialog {
+
+ private final int SIZING_TEXT_WIDTH = 600;
+ private final int SIZING_TEXT_HEIGHT = 400;
+
+ private Collection<Throwable> errors;
+ private Image image;
+ private Text text;
+
+ TestErrorsDialog(Shell parent, Image image, Collection<Throwable> errors) {
+ super(parent);
+ this.image = image;
+ this.errors = errors;
+ }
+
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ shell.setText("Connection Diagnostic errors");
+ shell.setImage(image);
+ }
+
+ protected void createButtonsForButtonBar(Composite parent) {
+ createButton(parent, IDialogConstants.OK_ID, "&OK", true);
+ }
+
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = (Composite)super.createDialogArea(parent);
+ composite.setSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
+
+ Label label = new Label(composite, SWT.WRAP);
+ label.setFont(JFaceResources.getFontRegistry().get(JFaceResources.BANNER_FONT));
+ label.setText("Connection diagnostics ended with errors:");
+
+ text = new Text(composite, SWT.MULTI | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
+ text.setFont(JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT));
+ text.setEditable(false);
+ text.setText(createText());
+ GridData data = new GridData(GridData.FILL_BOTH);
+ data.widthHint = SIZING_TEXT_WIDTH;
+ data.heightHint = SIZING_TEXT_HEIGHT;
+ text.setLayoutData(data);
+
+ return composite;
+ }
+
+ private String createText() {
+ StringWriter buf = new StringWriter();
+ PrintWriter pwr = new PrintWriter(buf);
+ for (Iterator<Throwable> i = errors.iterator(); i.hasNext();) {
+ i.next().printStackTrace(pwr);
+ pwr.println();
+ }
+ pwr.flush();
+ return buf.toString();
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildren.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildren.java
new file mode 100644
index 000000000..fafd5e541
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildren.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TCFChildren {
+
+ final TCFNode node;
+ final Map<String,TCFNode> children = new HashMap<String,TCFNode>();
+ final Map<String,TCFNode> children_next = new HashMap<String,TCFNode>();
+
+ protected boolean valid;
+
+ TCFChildren(TCFNode node) {
+ this.node = node;
+ }
+
+ void dispose() {
+ TCFNode arr[] = children.values().toArray(new TCFNode[children.size()]);
+ for (int i = 0; i < arr.length; i++) arr[i].dispose();
+ assert children.isEmpty();
+ }
+
+ void dispose(String id) {
+ children.remove(id);
+ }
+
+ void doneValidate() {
+ valid = true;
+ TCFNode[] a = children.values().toArray(new TCFNode[children.size()]);
+ for (TCFNode n : a) {
+ if (children_next.get(n.id) != n) n.dispose();
+ }
+ for (TCFNode n : children_next.values()) {
+ if (children.get(n.id) == null) {
+ children.put(n.id, n);
+ n.model.addNode(n.id, n);
+ }
+ assert children.get(n.id) == n;
+ }
+ assert children.size() == children_next.size();
+ }
+
+ boolean validate(TCFRunnable done) {
+ doneValidate();
+ return true;
+ }
+
+ void invalidate() {
+ children_next.clear();
+ TCFNode[] a = children.values().toArray(new TCFNode[children.size()]);
+ for (int i = 0; i < a.length; i++) a[i].invalidateNode(TCFNode.CF_ALL);
+ valid = false;
+ }
+
+ int size() {
+ return children.size();
+ }
+
+ TCFNode[] toArray() {
+ return children.values().toArray(new TCFNode[children.size()]);
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenExecContext.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenExecContext.java
new file mode 100644
index 000000000..95229f778
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenExecContext.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class TCFChildrenExecContext extends TCFChildren {
+
+ private boolean mem_valid;
+ private boolean run_valid;
+
+ TCFChildrenExecContext(TCFNode node) {
+ super(node);
+ }
+
+ @Override
+ boolean validate(TCFRunnable done) {
+ if (!mem_valid && !validateMemoryChildren(done)) return false;
+ if (!run_valid && !validateRunControlChildren(done)) return false;
+ doneValidate();
+ return true;
+ }
+
+ @Override
+ void invalidate() {
+ mem_valid = false;
+ run_valid = false;
+ super.invalidate();
+ }
+
+ private boolean validateMemoryChildren(TCFRunnable done) {
+ assert node.data_command == null;
+ IMemory mem = node.model.getLaunch().getService(IMemory.class);
+ if (mem == null) {
+ mem_valid = true;
+ return true;
+ }
+ if (done != null) node.wait_list.add(done);
+ node.data_command = mem.getChildren(node.id, new IMemory.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ if (node.data_command != token) return;
+ node.data_command = null;
+ if (error != null) {
+ node.node_error = error;
+ }
+ else {
+ for (int i = 0; i < contexts.length; i++) {
+ String id = contexts[i];
+ TCFNode n = node.model.getNode(id);
+ if (n == null) n = new TCFNodeExecContext(node, id);
+ children_next.put(id, n);
+ }
+ }
+ mem_valid = true;
+ node.validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRunControlChildren(TCFRunnable done) {
+ assert node.data_command == null;
+ IRunControl run = node.model.getLaunch().getService(IRunControl.class);
+ if (run == null) {
+ run_valid = true;
+ return true;
+ }
+ if (done != null) node.wait_list.add(done);
+ node.data_command = run.getChildren(node.id, new IRunControl.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ if (node.data_command != token) return;
+ node.data_command = null;
+ if (error != null) {
+ node.node_error = error;
+ }
+ else {
+ for (String id : contexts) {
+ TCFNode n = node.model.getNode(id);
+ if (n == null) n = new TCFNodeExecContext(node, id);
+ children_next.put(id, n);
+ }
+ }
+ run_valid = true;
+ node.validateNode(null);
+ }
+ });
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenRegisters.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenRegisters.java
new file mode 100644
index 000000000..ec76afab7
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenRegisters.java
@@ -0,0 +1,57 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRegisters;
+
+public class TCFChildrenRegisters extends TCFChildren {
+
+ TCFChildrenRegisters(TCFNode node) {
+ super(node);
+ }
+
+ @Override
+ boolean validate(TCFRunnable done) {
+ children_next.clear();
+ String addr = node.getAddress();
+ if (addr == null) {
+ doneValidate();
+ return true;
+ }
+ IRegisters regs = node.model.getLaunch().getService(IRegisters.class);
+ if (regs == null) {
+ doneValidate();
+ return true;
+ }
+ assert node.data_command == null;
+ if (done != null) node.wait_list.add(done);
+ node.data_command = regs.getChildren(node.id, new IRegisters.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ if (node.data_command != token) return;
+ node.data_command = null;
+ if (error != null) {
+ node.node_error = error;
+ }
+ else {
+ for (String id : contexts) {
+ TCFNode n = node.model.getNode(id);
+ if (n == null) n = new TCFNodeRegister(node, id);
+ children_next.put(id, n);
+ }
+ }
+ doneValidate();
+ node.validateNode(null);
+ }
+ });
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenStackTrace.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenStackTrace.java
new file mode 100644
index 000000000..8bcf2e757
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFChildrenStackTrace.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IStackTrace;
+
+public class TCFChildrenStackTrace extends TCFChildren {
+
+ private final TCFChildren children_regs;
+
+ TCFChildrenStackTrace(TCFNode node, TCFChildren children_regs) {
+ super(node);
+ this.children_regs = children_regs;
+ }
+
+ @Override
+ boolean validate(TCFRunnable done) {
+ children_next.clear();
+ String addr = node.getAddress();
+ if (addr == null) {
+ doneValidate();
+ return true;
+ }
+ String nm = node.id + "-TF";
+ TCFNode n = children.get(nm);
+ if (n == null) n = new TCFNodeStackFrame(node, nm, children_regs);
+ children_next.put(n.id, n);
+ IStackTrace st = node.model.getLaunch().getService(IStackTrace.class);
+ if (st == null) {
+ doneValidate();
+ return true;
+ }
+ assert node.data_command == null;
+ if (done != null) node.wait_list.add(done);
+ node.data_command = st.getChildren(node.id, new IStackTrace.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ if (node.data_command != token) return;
+ node.data_command = null;
+ if (error != null) {
+ node.node_error = error;
+ }
+ else {
+ int cnt = contexts.length;
+ for (String id : contexts) {
+ TCFNode n = node.model.getNode(id);
+ if (n == null || ((TCFNodeStackFrame)n).getFrameNo() != cnt) {
+ n = new TCFNodeStackFrame(node, id, cnt);
+ }
+ assert ((TCFNodeStackFrame)n).getFrameNo() == cnt;
+ assert n.id.equals(id);
+ children_next.put(id, n);
+ cnt--;
+ }
+ }
+ doneValidate();
+ node.validateNode(null);
+ }
+ });
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFColumnPresentationRegister.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFColumnPresentationRegister.java
new file mode 100644
index 000000000..8881fcb20
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFColumnPresentationRegister.java
@@ -0,0 +1,81 @@
+package com.windriver.debug.tcf.ui.model;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.resource.ImageDescriptor;
+
+public class TCFColumnPresentationRegister implements IColumnPresentation {
+
+ public static final String PRESENTATION_ID = "Registers";
+
+ private static String[] cols_all = {
+ TCFNodeRegister.COL_NAME,
+ TCFNodeRegister.COL_HEX_VALUE,
+ TCFNodeRegister.COL_DEC_VALUE,
+ TCFNodeRegister.COL_DESCRIPTION,
+ TCFNodeRegister.COL_READBLE,
+ TCFNodeRegister.COL_READ_ONCE,
+ TCFNodeRegister.COL_WRITEABLE,
+ TCFNodeRegister.COL_WRITE_ONCE,
+ TCFNodeRegister.COL_SIDE_EFFECTS,
+ TCFNodeRegister.COL_VOLATILE,
+ TCFNodeRegister.COL_FLOAT,
+ TCFNodeRegister.COL_MNEMONIC
+ };
+
+ private static String[] headers = {
+ "Name",
+ "Hex",
+ "Decimal",
+ "Description",
+ "Readable",
+ "Read Once",
+ "Writable",
+ "Write Once",
+ "Side Effects",
+ "Volatile",
+ "Float",
+ "Mnemonic"
+ };
+
+ private static String[] cols_ini = {
+ TCFNodeRegister.COL_NAME,
+ TCFNodeRegister.COL_HEX_VALUE,
+ TCFNodeRegister.COL_DEC_VALUE,
+ TCFNodeRegister.COL_DESCRIPTION,
+ TCFNodeRegister.COL_MNEMONIC
+ };
+
+ public void dispose() {
+ }
+
+ public String[] getAvailableColumns() {
+ return cols_all;
+ }
+
+ public String getHeader(String id) {
+ for (int i = 0; i < cols_all.length; i++) {
+ if (id.equals(cols_all[i])) return headers[i];
+ }
+ return null;
+ }
+
+ public String getId() {
+ return PRESENTATION_ID;
+ }
+
+ public ImageDescriptor getImageDescriptor(String id) {
+ return null;
+ }
+
+ public String[] getInitialColumns() {
+ return cols_ini;
+ }
+
+ public void init(IPresentationContext context) {
+ }
+
+ public boolean isOptional() {
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModel.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModel.java
new file mode 100644
index 000000000..f4826d2c3
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModel.java
@@ -0,0 +1,351 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.debug.core.commands.IDisconnectHandler;
+import org.eclipse.debug.core.commands.IResumeHandler;
+import org.eclipse.debug.core.commands.IStepIntoHandler;
+import org.eclipse.debug.core.commands.IStepOverHandler;
+import org.eclipse.debug.core.commands.IStepReturnHandler;
+import org.eclipse.debug.core.commands.ISuspendHandler;
+import org.eclipse.debug.core.commands.ITerminateHandler;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentation;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.swt.widgets.Display;
+
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+import com.windriver.debug.tcf.ui.commands.DisconnectCommand;
+import com.windriver.debug.tcf.ui.commands.ResumeCommand;
+import com.windriver.debug.tcf.ui.commands.StepIntoCommand;
+import com.windriver.debug.tcf.ui.commands.StepOverCommand;
+import com.windriver.debug.tcf.ui.commands.StepReturnCommand;
+import com.windriver.debug.tcf.ui.commands.SuspendCommand;
+import com.windriver.debug.tcf.ui.commands.TerminateCommand;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class TCFModel implements IElementContentProvider, IElementLabelProvider,
+ IModelProxyFactory, IColumnPresentationFactory {
+
+ private final Display display;
+ private final TCFLaunch launch;
+ private final TCFNode launch_node;
+ private final Map<IPresentationContext,TCFModelProxy> model_proxies =
+ new HashMap<IPresentationContext,TCFModelProxy>();
+ private final Map<String,TCFNode> id2node = new HashMap<String,TCFNode>();
+ private final Map<TCFNode,ModelDelta> deltas = new HashMap<TCFNode,ModelDelta>();
+ @SuppressWarnings("unchecked")
+ private final Map<Class,Object> commands = new HashMap<Class,Object>();
+
+ private final IMemory.MemoryListener mem_listener = new IMemory.MemoryListener() {
+
+ public void contextAdded(IMemory.MemoryContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ TCFNode node = getNode(contexts[i].getParentID());
+ if (node != null) node.onContextAdded(contexts[i]);
+ }
+ fireModelChanged();
+ }
+
+ public void contextChanged(IMemory.MemoryContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ TCFNode node = getNode(contexts[i].getID());
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextChanged(contexts[i]);
+ }
+ }
+ fireModelChanged();
+ }
+
+ public void contextRemoved(String[] context_ids) {
+ for (int i = 0; i < context_ids.length; i++) {
+ TCFNode node = getNode(context_ids[i]);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextRemoved();
+ }
+ }
+ fireModelChanged();
+ }
+
+ public void memoryChanged(String context_id, Number[] addr, long[] size) {
+ TCFNode node = getNode(context_id);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onMemoryChanged(addr, size);
+ }
+ fireModelChanged();
+ }
+ };
+
+ private final IRunControl.RunControlListener run_listener = new IRunControl.RunControlListener() {
+
+ public void containerResumed(String[] context_ids) {
+ for (int i = 0; i < context_ids.length; i++) {
+ TCFNode node = getNode(context_ids[i]);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContainerResumed();
+ }
+ }
+ fireModelChanged();
+ }
+
+ public void containerSuspended(String context, String pc, String reason,
+ Map<String,Object> params, String[] suspended_ids) {
+ for (int i = 0; i < suspended_ids.length; i++) {
+ TCFNode node = getNode(suspended_ids[i]);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContainerSuspended();
+ }
+ }
+ TCFNode node = getNode(context);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextSuspended(pc, reason, params);
+ }
+ fireModelChanged();
+ }
+
+ public void contextAdded(IRunControl.RunControlContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ TCFNode node = getNode(contexts[i].getParentID());
+ if (node != null) node.onContextAdded(contexts[i]);
+ }
+ fireModelChanged();
+ }
+
+ public void contextChanged(IRunControl.RunControlContext[] contexts) {
+ for (int i = 0; i < contexts.length; i++) {
+ TCFNode node = getNode(contexts[i].getID());
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextChanged(contexts[i]);
+ }
+ }
+ fireModelChanged();
+ }
+
+ public void contextException(String context, String msg) {
+ TCFNode node = getNode(context);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextException(msg);
+ }
+ fireModelChanged();
+ }
+
+ public void contextRemoved(String[] context_ids) {
+ for (int i = 0; i < context_ids.length; i++) {
+ TCFNode node = getNode(context_ids[i]);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextRemoved();
+ }
+ }
+ fireModelChanged();
+ }
+
+ public void contextResumed(String context) {
+ TCFNode node = getNode(context);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextResumed();
+ }
+ fireModelChanged();
+ }
+
+ public void contextSuspended(String context, String pc, String reason, Map<String,Object> params) {
+ TCFNode node = getNode(context);
+ if (node instanceof TCFNodeExecContext) {
+ ((TCFNodeExecContext)node).onContextSuspended(pc, reason, params);
+ }
+ fireModelChanged();
+ }
+ };
+
+ TCFModel(Display display, TCFLaunch launch) {
+ this.display = display;
+ this.launch = launch;
+ launch_node = new TCFNodeLaunch(TCFModel.this);
+ commands.put(ISuspendHandler.class, new SuspendCommand(this));
+ commands.put(IResumeHandler.class, new ResumeCommand(this));
+ commands.put(ITerminateHandler.class, new TerminateCommand(this));
+ commands.put(IDisconnectHandler.class, new DisconnectCommand(this));
+ commands.put(IStepIntoHandler.class, new StepIntoCommand(this));
+ commands.put(IStepOverHandler.class, new StepOverCommand(this));
+ commands.put(IStepReturnHandler.class, new StepReturnCommand(this));
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object getCommand(Class c) {
+ Object o = commands.get(c);
+ assert o == null || c.isInstance(o);
+ return o;
+ }
+
+ void onConnected() {
+ assert Protocol.isDispatchThread();
+ IMemory mem = launch.getService(IMemory.class);
+ if (mem != null) mem.addListener(mem_listener);
+ IRunControl run = launch.getService(IRunControl.class);
+ if (run != null) run.addListener(run_listener);
+ launch_node.invalidateNode();
+ launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ fireModelChanged();
+ }
+
+ void onDisconnected() {
+ assert Protocol.isDispatchThread();
+ TCFNode[] a = id2node.values().toArray(new TCFNode[id2node.size()]);
+ for (int i = 0; i < a.length; i++) {
+ if (!a[i].isDisposed()) a[i].dispose();
+ }
+ launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ fireModelChanged();
+ }
+
+ void onProxyInstalled(final TCFModelProxy p) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ model_proxies.put(p.getPresentationContext(), p);
+ }
+ });
+ }
+
+ void onProxyDisposed(final TCFModelProxy p) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ model_proxies.remove(p.getPresentationContext());
+ }
+ });
+ }
+
+ void launchChanged() {
+ launch_node.makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ fireModelChanged();
+ }
+
+ void dispose() {
+ }
+
+ void addNode(String id, TCFNode node) {
+ assert id != null;
+ assert Protocol.isDispatchThread();
+ assert id2node.get(id) == null;
+ assert !node.isDisposed();
+ id2node.put(id, node);
+ }
+
+ void removeNode(String id) {
+ assert id != null;
+ assert Protocol.isDispatchThread();
+ id2node.remove(id);
+ }
+
+ ModelDelta getDelta(TCFNode node) {
+ return deltas.get(node);
+ }
+
+ void addDelta(TCFNode node, ModelDelta delta) {
+ assert deltas.get(node) == null;
+ deltas.put(node, delta);
+ }
+
+ void fireModelChanged() {
+ assert Protocol.isDispatchThread();
+ ModelDelta delta = deltas.get(launch_node);
+ assert (delta == null) == deltas.isEmpty();
+ if (delta != null) {
+ deltas.clear();
+ IModelDelta top = delta.getParentDelta();
+ for (TCFModelProxy p : model_proxies.values()) p.fireModelChanged(top);
+ }
+ }
+
+ public Display getDisplay() {
+ return display;
+ }
+
+ public TCFLaunch getLaunch() {
+ return launch;
+ }
+
+ public TCFNode getRootNode() {
+ return launch_node;
+ }
+
+ public TCFNode getNode(String id) {
+ if (id == null) return null;
+ if (id.equals("")) return launch_node;
+ assert Protocol.isDispatchThread();
+ return id2node.get(id);
+ }
+
+ public void update(IChildrenCountUpdate[] updates) {
+ for (int i = 0; i < updates.length; i++) {
+ Object o = updates[i].getElement();
+ if (o instanceof TCFLaunch) launch_node.update(updates[i]);
+ else ((TCFNode)o).update(updates[i]);
+ }
+ }
+
+ public void update(IChildrenUpdate[] updates) {
+ for (int i = 0; i < updates.length; i++) {
+ Object o = updates[i].getElement();
+ if (o instanceof TCFLaunch) launch_node.update(updates[i]);
+ else ((TCFNode)o).update(updates[i]);
+ }
+ }
+
+ public void update(IHasChildrenUpdate[] updates) {
+ for (int i = 0; i < updates.length; i++) {
+ Object o = updates[i].getElement();
+ if (o instanceof TCFLaunch) launch_node.update(updates[i]);
+ else ((TCFNode)o).update(updates[i]);
+ }
+ }
+
+ public void update(ILabelUpdate[] updates) {
+ for (int i = 0; i < updates.length; i++) {
+ Object o = updates[i].getElement();
+ assert o != launch_node;
+ if (o instanceof TCFLaunch) launch_node.update(updates[i]);
+ else ((TCFNode)o).update(updates[i]);
+ }
+ }
+
+ public IModelProxy createModelProxy(Object element, IPresentationContext context) {
+ return new TCFModelProxy(this);
+ }
+
+ public IColumnPresentation createColumnPresentation(IPresentationContext context, Object element) {
+ String id = getColumnPresentationId(context, element);
+ if (id == null) return null;
+ if (id.equals(TCFColumnPresentationRegister.PRESENTATION_ID)) return new TCFColumnPresentationRegister();
+ return null;
+ }
+
+ public String getColumnPresentationId(IPresentationContext context, Object element) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(context.getId())) {
+ return TCFColumnPresentationRegister.PRESENTATION_ID;
+ }
+ return null;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelManager.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelManager.java
new file mode 100644
index 000000000..cfb9c9688
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelManager.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchesListener;
+import org.eclipse.swt.widgets.Display;
+
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+import com.windriver.tcf.api.protocol.Protocol;
+
+public class TCFModelManager {
+
+ private final Display display;
+ private final Map<TCFLaunch,TCFModel> models = new HashMap<TCFLaunch,TCFModel>();
+
+ private final TCFLaunch.Listener tcf_launch_listener = new TCFLaunch.Listener() {
+
+ public void onConnected(TCFLaunch launch) {
+ TCFModel model = models.get(launch);
+ if (model != null) model.onConnected();
+ }
+
+ public void onDisconnected(TCFLaunch launch) {
+ TCFModel model = models.get(launch);
+ if (model != null) model.onDisconnected();
+ }
+ };
+
+ private final ILaunchesListener debug_launch_listener = new ILaunchesListener() {
+
+ public void launchesAdded(final ILaunch[] launches) {
+ }
+
+ public void launchesChanged(final ILaunch[] launches) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ for (int i = 0; i < launches.length; i++) {
+ if (launches[i] instanceof TCFLaunch) {
+ TCFModel model = models.get(launches[i]);
+ if (model != null) model.launchChanged();
+ }
+ }
+ }
+ });
+ }
+
+ public void launchesRemoved(final ILaunch[] launches) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ for (int i = 0; i < launches.length; i++) {
+ if (launches[i] instanceof TCFLaunch) {
+ TCFModel model = models.remove(launches[i]);
+ if (model != null) model.dispose();
+ }
+ }
+ }
+ });
+ }
+ };
+
+ public TCFModelManager() {
+ display = Display.getDefault();
+ DebugPlugin.getDefault().getLaunchManager().addLaunchListener(debug_launch_listener);
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFLaunch.addListener(tcf_launch_listener);
+ }
+ });
+ }
+
+ public void dispose() {
+ DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(debug_launch_listener);
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFLaunch.removeListener(tcf_launch_listener);
+ for (Iterator<TCFModel> i = models.values().iterator(); i.hasNext();) {
+ TCFModel model = i.next();
+ model.dispose();
+ i.remove();
+ }
+ assert models.isEmpty();
+ }
+ });
+ }
+
+ public TCFModel getModel(TCFLaunch launch) {
+ TCFModel model = models.get(launch);
+ if (model == null) {
+ model = new TCFModel(display, launch);
+ models.put(launch, model);
+ if (launch.getChannel() != null) tcf_launch_listener.onConnected(launch);
+ }
+ return model;
+ }
+
+ public TCFNode getRootNode(TCFLaunch launch) {
+ return getModel(launch).getRootNode();
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelPresentation.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelPresentation.java
new file mode 100644
index 000000000..07e358631
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelPresentation.java
@@ -0,0 +1,247 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IValue;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugModelPresentation;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.debug.ui.IDebugView;
+import org.eclipse.debug.ui.IValueDetailListener;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.IWindowListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+
+import com.windriver.debug.tcf.core.model.ITCFBreakpointListener;
+import com.windriver.debug.tcf.core.model.TCFBreakpoint;
+import com.windriver.debug.tcf.core.model.TCFBreakpointsStatus;
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class TCFModelPresentation implements IDebugModelPresentation {
+
+ private final Collection<ILabelProviderListener> listeners = new HashSet<ILabelProviderListener>();
+
+ private IWorkbenchWindow active_window;
+ private TCFLaunch launch_selection;
+
+ private final TCFLaunch.Listener launch_listener = new TCFLaunch.Listener() {
+
+ public void onConnected(TCFLaunch launch) {
+ updateLaunchSelection();
+ }
+
+ public void onDisconnected(TCFLaunch launch) {
+ updateLaunchSelection();
+ }
+ };
+
+ private final ISelectionListener selection_listener = new ISelectionListener() {
+
+ public void selectionChanged(IWorkbenchPart part, ISelection selection) {
+ updateLaunchSelection();
+ }
+ };
+
+ private final IWindowListener window_listener = new IWindowListener() {
+
+ public void windowActivated(IWorkbenchWindow window) {
+ if (active_window != null) {
+ active_window.getSelectionService().removeSelectionListener(
+ IDebugUIConstants.ID_DEBUG_VIEW, selection_listener);
+ active_window = null;
+ }
+ window.getSelectionService().addSelectionListener(
+ IDebugUIConstants.ID_DEBUG_VIEW, selection_listener);
+ active_window = window;
+ updateLaunchSelection();
+ }
+
+ public void windowClosed(IWorkbenchWindow window) {
+ if (window == active_window) {
+ active_window.getSelectionService().removeSelectionListener(
+ IDebugUIConstants.ID_DEBUG_VIEW, selection_listener);
+ active_window = null;
+ }
+ }
+
+ public void windowDeactivated(IWorkbenchWindow window) {
+ }
+
+ public void windowOpened(IWorkbenchWindow window) {
+ }
+ };
+
+ private final ITCFBreakpointListener breakpoint_status_listener = new ITCFBreakpointListener() {
+
+ public void breakpointStatusChanged(String id) {
+ refreshBreakpointView();
+ }
+ };
+
+ public TCFModelPresentation() {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFLaunch.addListener(launch_listener);
+ }
+ });
+ PlatformUI.getWorkbench().addWindowListener(window_listener);
+ IWorkbenchWindow w = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ if (w != null) window_listener.windowActivated(w);
+ }
+
+ private void updateLaunchSelection() {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ TCFLaunch launch = null;
+ IAdaptable adaptable = DebugUITools.getDebugContext();
+ if (adaptable != null) {
+ ILaunch x = (ILaunch)adaptable.getAdapter(ILaunch.class);
+ if (x instanceof TCFLaunch) {
+ final TCFLaunch l = (TCFLaunch)x;
+ final boolean[] b = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ IChannel channel = l.getChannel();
+ b[0] = channel != null && channel.getState() == IChannel.STATE_OPEN;
+ }
+ });
+ if (b[0]) launch = l;
+ }
+ }
+ if (launch_selection != launch) {
+ setBreakpointStatusListener(launch_selection, launch);
+ launch_selection = launch;
+ refreshBreakpointView();
+ }
+ }
+ });
+ }
+
+ private void refreshBreakpointView() {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ if (active_window != null) {
+ final IDebugView view = (IDebugView)active_window.getActivePage().findView(
+ IDebugUIConstants.ID_BREAKPOINT_VIEW);
+ if (view != null) {
+ view.getViewer().refresh();
+ }
+ }
+ }
+ });
+ }
+
+ private void setBreakpointStatusListener(final TCFLaunch prev, final TCFLaunch next) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ if (prev != null && prev.getBreakpointsStatus() != null) {
+ prev.getBreakpointsStatus().removeListener(breakpoint_status_listener);
+ }
+ if (next != null && next.getBreakpointsStatus() != null) {
+ next.getBreakpointsStatus().addListener(breakpoint_status_listener);
+ }
+ }
+ });
+ }
+
+ public void addListener(ILabelProviderListener listener) {
+ listeners.add(listener);
+ }
+
+ public void removeListener(ILabelProviderListener listener) {
+ listeners.remove(listener);
+ }
+
+ public void dispose() {
+ if (launch_selection != null) {
+ setBreakpointStatusListener(launch_selection, null);
+ launch_selection = null;
+ }
+ if (active_window != null) {
+ active_window.getSelectionService().removeSelectionListener(
+ IDebugUIConstants.ID_DEBUG_VIEW, selection_listener);
+ active_window = null;
+ }
+ PlatformUI.getWorkbench().removeWindowListener(window_listener);
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFLaunch.removeListener(launch_listener);
+ }
+ });
+ }
+
+ public void computeDetail(IValue value, IValueDetailListener listener) {
+ }
+
+ public Image getImage(Object element) {
+ return null;
+ }
+
+ public String getText(Object element) {
+ if (element instanceof TCFBreakpoint) {
+ final TCFBreakpoint breakpoint = (TCFBreakpoint)element;
+ final TCFLaunch launch = launch_selection;
+ final String[] text = new String[1];
+ text[0] = breakpoint.getText();
+ if (launch != null) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ TCFBreakpointsStatus bs = launch.getBreakpointsStatus();
+ if (bs != null) {
+ Map<String,Object> map = bs.getStatus(breakpoint);
+ if (map != null) {
+ String status = null;
+ String error = (String)map.get(IBreakpoints.STATUS_ERROR);
+ Object planted = map.get(IBreakpoints.STATUS_PLANTED);
+ if (error != null) status = error;
+ else if (planted != null) status = "Planted";
+ if (status != null) text[0] += " (" + status + ")";
+ }
+ }
+ }
+ });
+ }
+ return text[0];
+ }
+ return null;
+ }
+
+ public void setAttribute(String attribute, Object value) {
+ }
+
+ public boolean isLabelProperty(Object element, String property) {
+ return true;
+ }
+
+ public String getEditorId(IEditorInput input, Object element) {
+ return null;
+ }
+
+ public IEditorInput getEditorInput(Object element) {
+ return null;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelProxy.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelProxy.java
new file mode 100644
index 000000000..dbdae8822
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelProxy.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import org.eclipse.debug.internal.ui.viewers.provisional.AbstractModelProxy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxy;
+import org.eclipse.jface.viewers.Viewer;
+
+public class TCFModelProxy extends AbstractModelProxy implements IModelProxy {
+
+ private final TCFModel model;
+
+ TCFModelProxy(TCFModel model) {
+ this.model = model;
+ }
+
+ public void installed(Viewer viewer) {
+ super.installed(viewer);
+ model.onProxyInstalled(this);
+ }
+
+ public void dispose() {
+ model.onProxyDisposed(this);
+ super.dispose();
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelSelectionPolicy.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelSelectionPolicy.java
new file mode 100644
index 000000000..6c07354ea
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFModelSelectionPolicy.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelSelectionPolicy;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.jface.viewers.ISelection;
+
+public class TCFModelSelectionPolicy implements IModelSelectionPolicy {
+
+ public boolean contains(ISelection selection, IPresentationContext context) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean isSticky(ISelection selection, IPresentationContext context) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public boolean overrides(ISelection existing, ISelection candidate,
+ IPresentationContext context) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public ISelection replaceInvalidSelection(ISelection invalidSelection,
+ ISelection newSelection) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNode.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNode.java
new file mode 100644
index 000000000..c213e0c2d
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNode.java
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.model.IMemoryBlock;
+import org.eclipse.debug.core.model.IMemoryBlockExtension;
+import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.RGB;
+import org.osgi.framework.Bundle;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRunControl;
+
+/**
+ * TCFNode is base class for all TCF debug model elements.
+ */
+public class TCFNode extends PlatformObject
+implements IMemoryBlockRetrievalExtension, Comparable<TCFNode> {
+
+ protected final String id;
+ protected final TCFNode parent;
+ protected final TCFModel model;
+
+ protected boolean disposed;
+
+ protected TCFNode(TCFNode parent, String id) {
+ assert Protocol.isDispatchThread();
+ this.parent = parent;
+ this.id = id;
+ model = parent.model;
+ }
+
+ protected TCFNode(TCFModel model) {
+ id = null;
+ parent = null;
+ this.model = model;
+ }
+
+ /**
+ * Dispose this node. The node is removed from the model.
+ */
+ void dispose() {
+ assert !disposed;
+ if (parent != null) parent.dispose(id);
+ model.removeNode(id);
+ disposed = true;
+ }
+
+ /**
+ * A child node is being disposed.
+ * The child should be removed from this node children lists.
+ */
+ void dispose(String id) {
+ }
+
+ /**
+ * Check if node is disposed.
+ * @return true if disposed.
+ */
+ public final boolean isDisposed() {
+ return disposed;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapter) {
+ if (adapter == ILaunch.class) return model.getLaunch();
+ if (adapter == IModelProxyFactory.class) return model;
+ if (adapter == IElementLabelProvider.class) return model;
+ if (adapter == IElementContentProvider.class) return model;
+ if (adapter == IColumnPresentationFactory.class) return model;
+ Object o = model.getCommand(adapter);
+ if (o != null) return o;
+ //System.err.println(adapter.getName());
+ return super.getAdapter(adapter);
+ }
+
+ public final TCFNode getParent() {
+ assert Protocol.isDispatchThread();
+ return parent;
+ }
+
+ public IRunControl.RunControlContext getRunContext() {
+ return null;
+ }
+
+ public IMemory.MemoryContext getMemoryContext() {
+ return null;
+ }
+
+ public boolean isRunning() {
+ return false;
+ }
+
+ public boolean isSuspended() {
+ return false;
+ }
+
+ /**
+ * Return address of this node.
+ * For executable contexts and stack frames address is current PC.
+ * @return
+ */
+ public String getAddress() {
+ return null;
+ }
+
+ /**
+ * Retrieve children count for a presentation context.
+ * @param result - children count update request.
+ */
+ final void update(final IChildrenCountUpdate result) {
+ new TCFRunnable(model.getDisplay(), result) {
+ public void run() {
+ if (!disposed && model.getLaunch().getChannel() != null) {
+ if (!validateNode(this)) return;
+ getData(result);
+ }
+ else {
+ result.setChildCount(0);
+ }
+ result.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ /**
+ * Retrieve children for a presentation context.
+ * @param result - children update request.
+ */
+ final void update(final IChildrenUpdate result) {
+ new TCFRunnable(model.getDisplay(), result) {
+ public void run() {
+ if (!disposed && model.getLaunch().getChannel() != null) {
+ if (!validateNode(this)) return;
+ getData(result);
+ }
+ result.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ /**
+ * Check if node has children in a presentation context.
+ * @param result - "has children" update request.
+ */
+ final void update(final IHasChildrenUpdate result) {
+ new TCFRunnable(model.getDisplay(), result) {
+ public void run() {
+ if (!disposed && model.getLaunch().getChannel() != null) {
+ if (!validateNode(this)) return;
+ getData(result);
+ }
+ else {
+ result.setHasChilren(false);
+ }
+ result.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ /**
+ * Retrieve node label for a presentation context.
+ * @param result - label update request.
+ */
+ final void update(final ILabelUpdate result) {
+ new TCFRunnable(model.getDisplay(), result) {
+ public void run() {
+ if (!disposed) {
+ if (!validateNode(this)) return;
+ if (node_error != null) {
+ result.setBackground(new RGB(255, 0, 0), 0);
+ result.setLabel(node_error.getClass().getName() +
+ ": " + node_error.getMessage(), 0);
+ }
+ else {
+ getData(result);
+ }
+ }
+ else {
+ result.setLabel("[Disposed]", 0);
+ }
+ result.setStatus(Status.OK_STATUS);
+ done();
+ }
+ };
+ }
+
+ /**
+ * Retrieve children count for a presentation context.
+ * The node is validated before calling this method,
+ * so the method should return cached data.
+ * The method is always called on TCF dispatch thread.
+ * @param result - children count update request.
+ */
+ protected void getData(IChildrenCountUpdate result) {
+ result.setChildCount(0);
+ }
+
+ /**
+ * Retrieve children for a presentation context.
+ * The node is validated before calling this method,
+ * so the method should return cached data.
+ * The method is always called on TCF dispatch thread.
+ * @param result - children update request.
+ */
+ protected void getData(IChildrenUpdate result) {
+ }
+
+ /**
+ * Check if the node has children in a presentation context.
+ * The node is validated before calling this method,
+ * so the method should return cached data.
+ * The method is always called on TCF dispatch thread.
+ * @param result - "has children" update request.
+ */
+ protected void getData(IHasChildrenUpdate result) {
+ result.setHasChilren(false);
+ }
+
+ /**
+ * Retrieve node label for a presentation context.
+ * The node is validated before calling this method,
+ * so the method should return cached data.
+ * The method is always called on TCF dispatch thread.
+ * @param result - label update request.
+ */
+ protected void getData(ILabelUpdate result) {
+ result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ result.setLabel(id, 0);
+ }
+
+ /**
+ * Create ModelDelta for changes in this node.
+ * @param flags - description of what has changed: CF_CONTEXT, CF_CHILDREN or CF_ALL.
+ * @return - ModelDelta that describes node changes.
+ */
+ ModelDelta makeModelDelta(int flags) {
+ int count = -1;
+ //if (node_valid == CF_ALL) count = children.size();
+ ModelDelta delta = model.getDelta(this);
+ int index = -1;
+ /*
+ if (parent.node_valid == CF_ALL) {
+ index = 0;
+ for (Iterator<TCFNode> i = parent.children.values().iterator(); i.hasNext();) {
+ if (i.next() == this) break;
+ index++;
+ }
+ }
+ */
+ if (delta == null || delta.getChildCount() != count || delta.getIndex() != index) {
+ ModelDelta parent_delta = parent.makeModelDelta(IModelDelta.NO_CHANGE);
+ delta = parent_delta.addNode(this, index, flags, count);
+ model.addDelta(this, delta);
+ }
+ else {
+ delta.setFlags(delta.getFlags() | flags);
+ }
+ return delta;
+ }
+
+ void onContextAdded(IRunControl.RunControlContext context) {
+ assert !disposed;
+ // TODO: Bug in Eclipse: IModelDelta.INSERTED fails if this is root node
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.CONTENT);
+ }
+
+ void onContextAdded(IMemory.MemoryContext context) {
+ assert !disposed;
+ // TODO: Bug in Eclipse: IModelDelta.INSERTED fails if this is root node
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.CONTENT);
+ }
+
+ /*--------------------------------------------------------------------------------------*/
+ /* Node data retrieval state machine */
+
+ protected static final int
+ CF_CHILDREN = 0x0001,
+ CF_CONTEXT = 0x0002,
+ CF_ALL = CF_CHILDREN | CF_CONTEXT;
+
+ protected int node_valid;
+ protected Throwable node_error;
+ protected IToken data_command;
+ protected final Collection<TCFRunnable> wait_list = new ArrayList<TCFRunnable>();
+
+ /**
+ * Invalidate the node - flush all cached data.
+ */
+ public void invalidateNode() {
+ invalidateNode(CF_ALL);
+ }
+
+ protected void invalidateNode(int flags) {
+ // flags - set of CF_*
+
+ // cancel current data retrieval command
+ if (data_command != null) {
+ data_command.cancel();
+ data_command = null;
+ }
+
+ // cancel waiting monitors
+ if (!wait_list.isEmpty()) {
+ TCFRunnable[] arr = wait_list.toArray(new TCFRunnable[wait_list.size()]);
+ for (TCFRunnable r : arr) r.cancel();
+ wait_list.clear();
+ }
+
+ if (flags == CF_ALL) {
+ node_error = null;
+ }
+
+ node_valid &= ~flags;
+ }
+
+ /**
+ * Validate node - retrieve and put into a cache missing data from remote peer.
+ * Validation is done asynchronously.
+ * @param done - call back, it is called when validation is done.
+ * @return true if the node is valid, false if validation is started.
+ */
+ public boolean validateNode(TCFRunnable done) {
+ assert Protocol.isDispatchThread();
+ assert (node_valid & ~CF_ALL) == 0;
+ if (data_command != null) {
+ if (done != null) wait_list.add(done);
+ return false;
+ }
+ else if (model.getLaunch().getChannel() == null) {
+ node_error = null;
+ node_valid = CF_ALL;
+ }
+ else {
+ if ((node_valid & CF_CONTEXT) == 0 && !validateContext(done)) return false;
+ if ((node_valid & CF_CHILDREN) == 0 && !validateChildren(done)) return false;
+ }
+ assert node_valid == CF_ALL;
+ if (!wait_list.isEmpty()) {
+ Runnable[] arr = wait_list.toArray(new Runnable[wait_list.size()]);
+ wait_list.clear();
+ for (int i = 0; i < arr.length; i++) arr[i].run();
+ }
+ return true;
+ }
+
+ protected boolean validateContext(TCFRunnable done) {
+ node_valid |= CF_CONTEXT;
+ return true;
+ }
+
+ protected boolean validateChildren(TCFRunnable done) {
+ node_valid |= CF_CHILDREN;
+ return true;
+ }
+
+ /*--------------------------------------------------------------------------------------*/
+ /* Memory Block Retrieval */
+
+ public IMemoryBlockExtension getExtendedMemoryBlock(String addr, Object ctx) throws DebugException {
+ assert ctx == this;
+ return getMemoryBlock(addr, 0);
+ }
+
+ public IMemoryBlock getMemoryBlock(long addr, long length) throws DebugException {
+ return getMemoryBlock(Long.toString(addr), length);
+ }
+
+ public boolean supportsStorageRetrieval() {
+ return getMemoryContext() != null;
+ }
+
+ private IMemoryBlockExtension getMemoryBlock(String addr, long length) throws DebugException {
+ assert !Protocol.isDispatchThread();
+ // TODO: MemoryBlock
+ return null;
+ }
+
+ /*--------------------------------------------------------------------------------------*/
+ /* Misc */
+
+ private static final Map<String,ImageDescriptor> image_cache = new HashMap<String,ImageDescriptor>();
+
+ static ImageDescriptor getImageDescriptor(String name) {
+ if (name == null) return null;
+ ImageDescriptor descriptor = image_cache.get(name);
+ if (descriptor == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ Bundle bundle = Platform.getBundle("org.eclipse.debug.ui");
+ if (bundle != null){
+ URL url = FileLocator.find(bundle, new Path(name), null);
+ descriptor = ImageDescriptor.createFromURL(url);
+ }
+ image_cache.put(name, descriptor);
+ }
+ return descriptor;
+ }
+
+ protected String getImageName() {
+ return null;
+ }
+
+ public int compareTo(TCFNode n) {
+ return id.compareTo(n.id);
+ }
+
+ public String toString() {
+ String s = "[" + Integer.toHexString(hashCode()) + "] " + id;
+ if (disposed) s += ", disposed";
+ return s;
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeExecContext.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeExecContext.java
new file mode 100644
index 000000000..996391ce0
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeExecContext.java
@@ -0,0 +1,487 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class TCFNodeExecContext extends TCFNode {
+
+ private final TCFChildren children_exec;
+ private final TCFChildren children_stack;
+ private final TCFChildren children_regs;
+
+ private IMemory.MemoryContext mem_context;
+ private IRunControl.RunControlContext run_context;
+
+ private boolean suspended;
+ private String suspended_pc;
+ private String suspended_reason;
+ @SuppressWarnings("unused")
+ private Map<String,Object> suspended_params;
+ private boolean running;
+ private boolean terminated;
+ @SuppressWarnings("unused")
+ private String exception_msg;
+
+ private boolean valid_mem_ctx;
+ private boolean valid_run_ctx;
+ private boolean valid_state;
+
+ TCFNodeExecContext(TCFNode parent, String id) {
+ super(parent, id);
+ children_exec = new TCFChildrenExecContext(this);
+ children_regs = new TCFChildrenRegisters(this);
+ children_stack = new TCFChildrenStackTrace(this, children_regs);
+ }
+
+ @Override
+ void dispose() {
+ children_exec.dispose();
+ children_stack.dispose();
+ children_regs.dispose();
+ super.dispose();
+ }
+
+ @Override
+ void dispose(String id) {
+ children_exec.dispose(id);
+ children_stack.dispose(id);
+ children_regs.dispose(id);
+ }
+
+ @Override
+ public IRunControl.RunControlContext getRunContext() {
+ assert Protocol.isDispatchThread();
+ return run_context;
+ }
+
+ @Override
+ public IMemory.MemoryContext getMemoryContext() {
+ assert Protocol.isDispatchThread();
+ return mem_context;
+ }
+
+ @Override
+ public boolean isRunning() {
+ assert Protocol.isDispatchThread();
+ return running;
+ }
+
+ @Override
+ public boolean isSuspended() {
+ assert Protocol.isDispatchThread();
+ return suspended;
+ }
+
+ @Override
+ public String getAddress() {
+ assert Protocol.isDispatchThread();
+ return suspended_pc;
+ }
+
+ @Override
+ protected void getData(IChildrenCountUpdate result) {
+ if (run_context != null && run_context.hasState()) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ result.setChildCount(children_regs.size());
+ }
+ else {
+ result.setChildCount(children_stack.size());
+ }
+ }
+ else {
+ result.setChildCount(children_exec.size());
+ }
+ }
+
+ @Override
+ protected void getData(IChildrenUpdate result) {
+ int offset = 0;
+ TCFNode[] arr = null;
+ if (run_context != null && run_context.hasState()) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ arr = children_regs.toArray();
+ }
+ else {
+ arr = children_stack.toArray();
+ }
+ }
+ else {
+ arr = children_exec.toArray();
+ }
+ Arrays.sort(arr);
+ for (TCFNode n : arr) {
+ if (offset >= result.getOffset() && offset < result.getOffset() + result.getLength()) {
+ result.setChild(n, offset);
+ }
+ offset++;
+ }
+ }
+
+ @Override
+ protected void getData(IHasChildrenUpdate result) {
+ if (run_context != null && run_context.hasState()) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ result.setHasChilren(children_regs.size() > 0);
+ }
+ else {
+ result.setHasChilren(children_stack.size() > 0);
+ }
+ }
+ else {
+ result.setHasChilren(children_exec.size() > 0);
+ }
+ }
+
+ @Override
+ protected void getData(ILabelUpdate result) {
+ result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ String label = id;
+ if (run_context != null) {
+ if (run_context.hasState()) {
+ if (running) {
+ label += " (Running)";
+ }
+ else if (suspended) {
+ if (suspended_reason != null) {
+ label += " (" + suspended_reason + ")";
+ }
+ else {
+ label += " (Suspended)";
+ }
+ }
+ }
+ String file = (String)run_context.getProperties().get("File");
+ if (file != null) label += " " + file;
+ }
+ result.setLabel(label, 0);
+ }
+
+ @Override
+ ModelDelta makeModelDelta(int flags) {
+ if (run_context != null && run_context.isContainer()) flags |= IModelDelta.STATE;
+ return super.makeModelDelta(flags);
+ }
+
+ @Override
+ void onContextAdded(IRunControl.RunControlContext context) {
+ assert !disposed;
+ if (node_valid == CF_ALL) {
+ String id = context.getID();
+ TCFNodeExecContext n = (TCFNodeExecContext)children_exec.children.get(id);
+ if (n == null) {
+ n = new TCFNodeExecContext(this, id);
+ n.run_context = context;
+ n.valid_run_ctx = true;
+ children_exec.children.put(id, n);
+ model.addNode(id, n);
+ n.makeModelDelta(IModelDelta.INSERTED);
+ }
+ else {
+ n.run_context = context;
+ n.makeModelDelta(IModelDelta.STATE);
+ }
+ }
+ else {
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.CONTENT);
+ }
+ }
+
+ void onContextChanged(IRunControl.RunControlContext context) {
+ assert !disposed;
+ run_context = context;
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ @Override
+ void onContextAdded(IMemory.MemoryContext context) {
+ assert !disposed;
+ if (node_valid == CF_ALL) {
+ String id = context.getID();
+ TCFNodeExecContext n = (TCFNodeExecContext)children_exec.children.get(id);
+ if (n == null) {
+ n = new TCFNodeExecContext(this, id);
+ n.mem_context = context;
+ n.valid_mem_ctx = true;
+ children_exec.children.put(id, n);
+ model.addNode(id, n);
+ n.makeModelDelta(IModelDelta.INSERTED);
+ }
+ else {
+ n.mem_context = context;
+ n.makeModelDelta(IModelDelta.STATE);
+ }
+ }
+ else {
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.CONTENT);
+ }
+ }
+
+ void onContextChanged(IMemory.MemoryContext context) {
+ assert !disposed;
+ mem_context = context;
+ invalidateNode(CF_CHILDREN);
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ void onContextRemoved() {
+ assert !disposed;
+ dispose();
+ if (parent.node_valid == CF_ALL) {
+ makeModelDelta(IModelDelta.REMOVED);
+ }
+ else {
+ parent.invalidateNode(CF_CHILDREN);
+ parent.makeModelDelta(IModelDelta.CONTENT);
+ }
+ }
+
+ void onContainerSuspended() {
+ assert !disposed;
+ if (run_context == null) return;
+ if (!run_context.hasState()) return;
+ suspended = false;
+ running = false;
+ valid_state = false;
+ invalidateNode(CF_CHILDREN);
+ suspended = true;
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ void onContainerResumed() {
+ assert !disposed;
+ if (run_context == null) return;
+ if (!run_context.hasState()) return;
+ suspended = false;
+ running = false;
+ valid_state = false;
+ invalidateNode(CF_CHILDREN);
+ suspended = false;
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ void onContextSuspended(String pc, String reason, Map<String,Object> params) {
+ assert !disposed;
+ if (run_context == null) return;
+ if (!run_context.hasState()) return;
+ invalidateNode(CF_CHILDREN);
+ suspended = true;
+ suspended_pc = pc;
+ suspended_reason = reason;
+ suspended_params = params;
+ running = false;
+ valid_state = true;
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ void onContextResumed() {
+ assert !disposed;
+ if (run_context == null) return;
+ if (!run_context.hasState()) return;
+ invalidateNode(CF_CHILDREN);
+ exception_msg = null;
+ terminated = false;
+ suspended = false;
+ suspended_pc = null;
+ suspended_reason = null;
+ suspended_params = null;
+ running = true;
+ valid_state = true;
+ makeModelDelta(IModelDelta.STATE | IModelDelta.CONTENT);
+ }
+
+ void onContextException(String msg) {
+ assert !disposed;
+ exception_msg = msg;
+ makeModelDelta(IModelDelta.STATE);
+ }
+
+ void onMemoryChanged(Number[] addr, long[] size) {
+ assert !disposed;
+ }
+
+ @Override
+ protected void invalidateNode(int flags) {
+ super.invalidateNode(flags);
+ if ((flags & CF_CONTEXT) != 0) {
+ valid_mem_ctx = false;
+ valid_run_ctx = false;
+ valid_state = false;
+ running = false;
+ suspended = false;
+ }
+ if ((flags & CF_CHILDREN) != 0) {
+ children_exec.invalidate();
+ children_stack.invalidate();
+ children_regs.invalidate();
+ }
+ }
+
+ @Override
+ protected boolean validateContext(TCFRunnable done) {
+ if (!valid_mem_ctx && !validateMemoryContext(done)) return false;
+ if (!valid_run_ctx && !validateRunControlContext(done)) return false;
+ if (!valid_state && !validateRunControlState(done)) return false;
+ node_valid |= CF_CONTEXT;
+ return true;
+ }
+
+ @Override
+ protected boolean validateChildren(TCFRunnable done) {
+ if (!children_stack.valid && !children_stack.validate(done)) return false;
+ if (!children_regs.valid && !children_regs.validate(done)) return false;
+ if (!children_exec.valid && !children_exec.validate(done)) return false;
+ node_valid |= CF_CHILDREN;
+ return true;
+ }
+
+ private boolean validateMemoryContext(TCFRunnable done) {
+ assert data_command == null;
+ IMemory mem = model.getLaunch().getService(IMemory.class);
+ if (mem == null) {
+ valid_mem_ctx = true;
+ return true;
+ }
+ if (done != null) wait_list.add(done);
+ data_command = mem.getContext(id, new IMemory.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IMemory.MemoryContext context) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ mem_context = context;
+ }
+ valid_mem_ctx = true;
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRunControlContext(TCFRunnable done) {
+ assert data_command == null;
+ IRunControl run = model.getLaunch().getService(IRunControl.class);
+ if (run == null) {
+ valid_run_ctx = true;
+ return true;
+ }
+ if (done != null) wait_list.add(done);
+ data_command = run.getContext(id, new IRunControl.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IRunControl.RunControlContext context) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ run_context = context;
+ }
+ valid_run_ctx = true;
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRunControlState(TCFRunnable done) {
+ assert data_command == null;
+ if (node_error != null || run_context == null || !run_context.hasState()) {
+ suspended = false;
+ suspended_pc = null;
+ suspended_reason = null;
+ suspended_params = null;
+ running = false;
+ valid_state = true;
+ return true;
+ }
+ if (done != null) wait_list.add(done);
+ data_command = run_context.getState(new IRunControl.DoneGetState() {
+ public void doneGetState(IToken token, Exception error, boolean suspend, String pc, String reason, Map<String,Object> params) {
+ if (token != data_command) return;
+ data_command = null;
+ if (error != null) {
+ suspended = false;
+ suspended_pc = null;
+ suspended_reason = null;
+ suspended_params = null;
+ node_error = error;
+ running = false;
+ }
+ else {
+ suspended = suspend;
+ if (suspend) {
+ suspended_pc = pc;
+ suspended_reason = reason;
+ suspended_params = params;
+ }
+ else {
+ suspended_pc = null;
+ suspended_reason = null;
+ suspended_params = null;
+ }
+ running = !suspend;
+ }
+ valid_state = true;
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean hasSuspendedChildren() {
+ for (TCFNode n : children_exec.children.values()) {
+ if (n instanceof TCFNodeExecContext) {
+ TCFNodeExecContext e = (TCFNodeExecContext)n;
+ if (e.run_context != null) {
+ if (e.run_context.hasState() && e.suspended) return true;
+ if (e.run_context.isContainer() && e.hasSuspendedChildren()) return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected String getImageName() {
+ if (run_context != null && run_context.hasState()) {
+ // Thread
+ if (terminated) return "icons/full/obj16/threadt_obj.gif";
+ if (suspended) return "icons/full/obj16/threads_obj.gif";
+ return "icons/full/obj16/thread_obj.gif";
+ }
+ else if (run_context != null) {
+ // Thread container (process)
+ if (terminated) return "icons/full/obj16/debugtt_obj.gif";
+ if (hasSuspendedChildren()) return "icons/full/obj16/debugts_obj.gif";
+ return "icons/full/obj16/debugt_obj.gif";
+ }
+ return super.getImageName();
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeLaunch.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeLaunch.java
new file mode 100644
index 000000000..b800e2cbe
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeLaunch.java
@@ -0,0 +1,124 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import java.util.Arrays;
+
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
+import org.eclipse.swt.graphics.RGB;
+
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+
+public class TCFNodeLaunch extends TCFNode {
+
+ private final TCFChildren children;
+
+ TCFNodeLaunch(TCFModel model) {
+ super(model);
+ children = new TCFChildrenExecContext(this);
+ }
+
+ @Override
+ void dispose() {
+ children.dispose();
+ super.dispose();
+ }
+
+ @Override
+ void dispose(String id) {
+ children.dispose(id);
+ }
+
+ @Override
+ protected void getData(IChildrenCountUpdate result) {
+ result.setChildCount(children.size());
+ }
+
+ @Override
+ protected void getData(IChildrenUpdate result) {
+ int offset = 0;
+ TCFNode[] arr = children.toArray();
+ Arrays.sort(arr);
+ for (TCFNode n : arr) {
+ if (offset >= result.getOffset() && offset < result.getOffset() + result.getLength()) {
+ result.setChild(n, offset);
+ }
+ offset++;
+ }
+ }
+
+ @Override
+ protected void getData(IHasChildrenUpdate result) {
+ result.setHasChilren(children.size() > 0);
+ }
+
+ @Override
+ protected void getData(ILabelUpdate result) {
+ result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ String label = id;
+ TCFLaunch launch = model.getLaunch();
+ String status = "";
+ if (launch.isConnecting()) status = "Connecting";
+ else if (launch.isDisconnected()) status = "Disconnected";
+ else if (launch.isTerminated()) status = "Terminated";
+ Throwable error = launch.getError();
+ if (error != null) {
+ status += " - " + error;
+ result.setForeground(new RGB(255, 0, 0), 0);
+ }
+ if (status.length() > 0) status = " (" + status + ")";
+ label = launch.getLaunchConfiguration().getName() + status;
+ result.setLabel(label, 0);
+ }
+
+ @Override
+ ModelDelta makeModelDelta(int flags) {
+ int count = -1;
+ //if (node_valid == CF_ALL) count = children.size();
+ ModelDelta delta = model.getDelta(this);
+ if (delta == null) {
+ delta = new ModelDelta(DebugPlugin.getDefault().getLaunchManager(), IModelDelta.NO_CHANGE);
+ delta = delta.addNode(model.getLaunch(), -1, flags, count);
+ model.addDelta(this, delta);
+ }
+ else {
+ assert delta.getChildCount() == count;
+ delta.setFlags(delta.getFlags() | flags);
+ }
+ return delta;
+ }
+
+ @Override
+ protected void invalidateNode(int flags) {
+ super.invalidateNode(flags);
+ if ((flags & CF_CHILDREN) != 0) {
+ children.invalidate();
+ }
+ }
+
+ @Override
+ protected boolean validateChildren(TCFRunnable done) {
+ if (!children.valid && !children.validate(done)) return false;
+ node_valid |= CF_CHILDREN;
+ return true;
+ }
+
+ @Override
+ protected String getImageName() {
+ return "icons/full/obj16/ldebug_obj.gif";
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeRegister.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeRegister.java
new file mode 100644
index 000000000..9309c1bd9
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeRegister.java
@@ -0,0 +1,213 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IRegisters;
+
+// TODO: hierarchical registers
+public class TCFNodeRegister extends TCFNode {
+
+ /**
+ * Presentation column IDs.
+ */
+ public static final String
+ COL_NAME = "Name",
+ COL_HEX_VALUE = "HexValue",
+ COL_DEC_VALUE = "DecValue",
+ COL_DESCRIPTION = "Description",
+ COL_READBLE = "Readable",
+ COL_READ_ONCE = "ReadOnce",
+ COL_WRITEABLE = "Writeable",
+ COL_WRITE_ONCE = "WriteOnce",
+ COL_SIDE_EFFECTS = "SideEffects",
+ COL_VOLATILE = "Volatile",
+ COL_FLOAT = "Float",
+ COL_MNEMONIC = "Menimonic";
+
+
+ private IRegisters.RegistersContext context;
+ private String hex_value;
+ private String dec_value;
+ private Number num_value;
+ private boolean valid_context;
+ private boolean valid_hex_value;
+ private boolean valid_dec_value;
+
+ TCFNodeRegister(TCFNode parent, String id) {
+ super(parent, id);
+ }
+
+ @Override
+ protected void getData(ILabelUpdate result) {
+ result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ if (context != null) {
+ String[] cols = result.getColumnIds();
+ if (cols == null) {
+ result.setLabel(context.getName() + " = " + hex_value, 0);
+ }
+ else {
+ for (int i = 0; i < cols.length; i++) {
+ String c = cols[i];
+ if (c.equals(COL_NAME)) result.setLabel(context.getName(), i);
+ else if (c.equals(COL_HEX_VALUE)) result.setLabel(hex_value, i);
+ else if (c.equals(COL_DEC_VALUE)) result.setLabel(dec_value, i);
+ else if (c.equals(COL_DESCRIPTION)) result.setLabel(context.getDescription(), i);
+ else if (c.equals(COL_READBLE)) result.setLabel(bool(context.isReadable()), i);
+ else if (c.equals(COL_READ_ONCE)) result.setLabel(bool(context.isReadOnce()), i);
+ else if (c.equals(COL_WRITEABLE)) result.setLabel(bool(context.isWriteable()), i);
+ else if (c.equals(COL_WRITE_ONCE)) result.setLabel(bool(context.isWriteOnce()), i);
+ else if (c.equals(COL_SIDE_EFFECTS)) result.setLabel(bool(context.hasSideEffects()), i);
+ else if (c.equals(COL_VOLATILE)) result.setLabel(bool(context.isVolatile()), i);
+ else if (c.equals(COL_FLOAT)) result.setLabel(bool(context.isFloat()), i);
+ else if (c.equals(COL_MNEMONIC)) result.setLabel(getMnemonic(), i);
+ }
+ }
+ }
+ else {
+ result.setLabel(id, 0);
+ }
+ }
+
+ private String bool(boolean b) {
+ return b ? "yes" : "no";
+ }
+
+ private String getMnemonic() {
+ if (num_value != null) {
+ IRegisters.NamedValue[] arr = context.getNamedValues();
+ if (arr != null) {
+ if (context.isFloat()) {
+ for (IRegisters.NamedValue n : arr) {
+ if (n.getValue().doubleValue() == num_value.doubleValue()) return n.getName();
+ }
+ }
+ else {
+ for (IRegisters.NamedValue n : arr) {
+ if (n.getValue().longValue() == num_value.longValue()) return n.getName();
+ }
+ }
+ }
+ }
+ return "";
+ }
+
+ @Override
+ protected void invalidateNode(int flags) {
+ super.invalidateNode(flags);
+ if ((flags & CF_CONTEXT) != 0) {
+ valid_context = false;
+ valid_hex_value = false;
+ valid_dec_value = false;
+ hex_value = null;
+ dec_value = null;
+ num_value = null;
+ }
+ }
+
+ @Override
+ protected boolean validateContext(TCFRunnable done) {
+ if (!valid_context && !validateRegisterContext(done)) return false;
+ if (!valid_hex_value && !validateRegisterHexValue(done)) return false;
+ if (!valid_dec_value && !validateRegisterDecValue(done)) return false;
+ node_valid |= CF_CONTEXT;
+ return true;
+ }
+
+ private boolean validateRegisterContext(TCFRunnable done) {
+ assert data_command == null;
+ IRegisters regs = model.getLaunch().getService(IRegisters.class);
+ if (done != null) wait_list.add(done);
+ data_command = regs.getContext(id, new IRegisters.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IRegisters.RegistersContext context) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ TCFNodeRegister.this.context = context;
+ }
+ valid_context = true;
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRegisterHexValue(TCFRunnable done) {
+ assert data_command == null;
+ if (done != null) wait_list.add(done);
+ String[] fmts = context.getAvailableFormats();
+ String fmt = null;
+ for (String s : fmts) {
+ if (s.equals(IRegisters.FORMAT_HEX)) fmt = s;
+ }
+ if (fmt == null) {
+ valid_hex_value = true;
+ return true;
+ }
+ data_command = context.get(fmt, new IRegisters.DoneGet() {
+ public void doneGet(IToken token, Exception error, String value) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ hex_value = value;
+ }
+ valid_hex_value = true;
+ if (!context.isFloat()) num_value = Long.valueOf(value, 16);
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRegisterDecValue(TCFRunnable done) {
+ assert data_command == null;
+ if (done != null) wait_list.add(done);
+ String[] fmts = context.getAvailableFormats();
+ String fmt = null;
+ for (String s : fmts) {
+ if (s.equals(IRegisters.FORMAT_DECIMAL)) fmt = s;
+ }
+ if (fmt == null) {
+ valid_dec_value = true;
+ return true;
+ }
+ data_command = context.get(fmt, new IRegisters.DoneGet() {
+ public void doneGet(IToken token, Exception error, String value) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ dec_value = value;
+ }
+ valid_dec_value = true;
+ if (!context.isFloat()) num_value = Long.valueOf(value, 10);
+ else num_value = Double.valueOf(value);
+ validateNode(null);
+ }
+ });
+ return false;
+ }
+
+ @Override
+ protected String getImageName() {
+ return "icons/full/obj16/genericregister_obj.gif";
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeStackFrame.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeStackFrame.java
new file mode 100644
index 000000000..91683da5e
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFNodeStackFrame.java
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.ILineNumbers;
+import com.windriver.tcf.api.services.IMemory;
+import com.windriver.tcf.api.services.IRunControl;
+import com.windriver.tcf.api.services.IStackTrace;
+import com.windriver.tcf.api.services.ILineNumbers.CodeArea;
+
+public class TCFNodeStackFrame extends TCFNode {
+
+ private IStackTrace.StackTraceContext stack_trace_context;
+ private ILineNumbers.CodeArea code_area;
+
+ private final int frame_no;
+ private final TCFChildren children_regs;
+
+ TCFNodeStackFrame(TCFNode parent, String id, TCFChildren children_regs) {
+ super(parent, id);
+ this.frame_no = 0;
+ this.children_regs = children_regs;
+ }
+
+ TCFNodeStackFrame(TCFNode parent, String id, int frame_no) {
+ super(parent, id);
+ this.frame_no = frame_no;
+ children_regs = new TCFChildrenRegisters(this);
+ }
+
+ int getFrameNo() {
+ return frame_no;
+ }
+
+ @Override
+ void dispose() {
+ children_regs.dispose();
+ super.dispose();
+ }
+
+ @Override
+ void dispose(String id) {
+ children_regs.dispose(id);
+ }
+
+ @Override
+ public IRunControl.RunControlContext getRunContext() {
+ return parent.getRunContext();
+ }
+
+ @Override
+ public IMemory.MemoryContext getMemoryContext() {
+ return parent.getMemoryContext();
+ }
+
+ @Override
+ public boolean isRunning() {
+ return parent.isRunning();
+ }
+
+ @Override
+ public boolean isSuspended() {
+ return parent.isSuspended();
+ }
+
+ @Override
+ public String getAddress() {
+ assert Protocol.isDispatchThread();
+ if (frame_no == 0) return parent.getAddress();
+ if (stack_trace_context != null) {
+ return stack_trace_context.getReturnAddress().toString();
+ }
+ return null;
+ }
+
+ @Override
+ protected void getData(IChildrenCountUpdate result) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ result.setChildCount(children_regs.size());
+ }
+ else {
+ result.setChildCount(0);
+ }
+ }
+
+ @Override
+ protected void getData(IChildrenUpdate result) {
+ int offset = 0;
+ TCFNode[] arr = null;
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ arr = children_regs.toArray();
+ }
+ else {
+ arr = null;
+ }
+ if (arr != null) {
+ Arrays.sort(arr);
+ for (TCFNode n : arr) {
+ if (offset >= result.getOffset() && offset < result.getOffset() + result.getLength()) {
+ result.setChild(n, offset);
+ }
+ offset++;
+ }
+ }
+ }
+
+ @Override
+ protected void getData(IHasChildrenUpdate result) {
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(result.getPresentationContext().getId())) {
+ result.setHasChilren(children_regs.size() > 0);
+ }
+ else {
+ result.setHasChilren(false);
+ }
+ }
+
+ @Override
+ protected void getData(ILabelUpdate result) {
+ result.setImageDescriptor(getImageDescriptor(getImageName()), 0);
+ String label = id;
+ Number n = null;
+ if (frame_no == 0 && parent.getAddress() != null) {
+ n = new BigInteger(parent.getAddress());
+ }
+ else if (stack_trace_context != null) {
+ n = stack_trace_context.getReturnAddress();
+ }
+ if (n == null) {
+ label = "...";
+ }
+ else {
+ label = makeHexAddrString(n);
+ if (code_area != null && code_area.file != null) {
+ label += ": " + code_area.file + ", line " + (code_area.start_line + 1);
+ }
+ }
+ result.setLabel(label, 0);
+ }
+
+ private String makeHexAddrString(Number n) {
+ BigInteger i = null;
+ if (n instanceof BigInteger) i = (BigInteger)n;
+ else i = new BigInteger(n.toString());
+ String s = i.toString(16);
+ IMemory.MemoryContext m = getMemoryContext();
+ int sz = (m != null ? m.getAddressSize() : 4) * 2;
+ int l = sz - s.length();
+ if (l < 0) l = 0;
+ if (l > 16) l = 16;
+ return "0x0000000000000000".substring(0, 2 + l) + s;
+ }
+
+ @Override
+ protected void invalidateNode(int flags) {
+ super.invalidateNode(flags);
+ if ((flags & CF_CHILDREN) != 0) {
+ children_regs.invalidate();
+ }
+ }
+
+ @Override
+ protected boolean validateContext(TCFRunnable done) {
+ assert data_command == null;
+ if (frame_no == 0) {
+ node_valid |= CF_CONTEXT;
+ return true;
+ }
+ IStackTrace st = model.getLaunch().getService(IStackTrace.class);
+ if (done != null) wait_list.add(done);
+ data_command = st.getContext(new String[]{ id }, new IStackTrace.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IStackTrace.StackTraceContext[] context) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else {
+ stack_trace_context = context[0];
+ }
+ BigInteger n = null;
+ ILineNumbers ln = model.getLaunch().getService(ILineNumbers.class);
+ if (node_error == null && ln != null) {
+ String s = getAddress();
+ if (s != null) n = new BigInteger(s);
+ }
+ code_area = null;
+ if (n == null) {
+ node_valid |= CF_CONTEXT;
+ validateNode(null);
+ }
+ else {
+ BigInteger m = n.add(BigInteger.valueOf(1));
+ data_command = ln.mapToSource(parent.id, n, m, new ILineNumbers.DoneMapToSource() {
+ public void doneMapToSource(IToken token, Exception error, CodeArea[] areas) {
+ if (data_command != token) return;
+ data_command = null;
+ if (error != null) {
+ node_error = error;
+ }
+ else if (areas != null && areas.length > 0) {
+ for (ILineNumbers.CodeArea area : areas) {
+ if (code_area == null || area.start_line < code_area.start_line) {
+ code_area = area;
+ }
+ }
+ }
+ node_valid |= CF_CONTEXT;
+ validateNode(null);
+ }
+ });
+ }
+ }
+ });
+ return false;
+ }
+
+ @Override
+ protected boolean validateChildren(TCFRunnable done) {
+ if (!children_regs.valid && !children_regs.validate(done)) return false;
+ node_valid |= CF_CHILDREN;
+ return true;
+ }
+
+ @Override
+ protected String getImageName() {
+ if (isRunning()) return "icons/full/obj16/stckframe_running_obj.gif";
+ return "icons/full/obj16/stckframe_obj.gif";
+ }
+
+ @Override
+ public int compareTo(TCFNode n) {
+ if (n instanceof TCFNodeStackFrame) {
+ TCFNodeStackFrame f = (TCFNodeStackFrame)n;
+ if (frame_no < f.frame_no) return -1;
+ if (frame_no > f.frame_no) return +1;
+ }
+ return id.compareTo(n.id);
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFRunnable.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFRunnable.java
new file mode 100644
index 000000000..f55cb8afb
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/model/TCFRunnable.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.model;
+
+import org.eclipse.debug.core.IRequest;
+import org.eclipse.swt.widgets.Display;
+
+import com.windriver.tcf.api.protocol.Protocol;
+
+public abstract class TCFRunnable implements Runnable {
+
+ private final IRequest monitor;
+ private final Display display;
+
+ public TCFRunnable(Display display, IRequest monitor) {
+ this.monitor = monitor;
+ this.display = display;
+ Protocol.invokeLater(this);
+ }
+
+ public void cancel() {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ monitor.cancel();
+ monitor.done();
+ }
+ });
+ }
+
+ public void done() {
+ display.asyncExec(new Runnable() {
+ public void run() {
+ monitor.done();
+ }
+ });
+ }
+}
diff --git a/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/trace/TraceView.java b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/trace/TraceView.java
new file mode 100644
index 000000000..824346801
--- /dev/null
+++ b/plugins/com.windriver.debug.tcf.ui/src/com/windriver/debug/tcf/ui/trace/TraceView.java
@@ -0,0 +1,305 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.debug.tcf.ui.trace;
+
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.TabFolder;
+import org.eclipse.swt.widgets.TabItem;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.part.ViewPart;
+
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.core.AbstractChannel;
+
+public class TraceView extends ViewPart implements Protocol.ChannelOpenListener {
+
+ private Composite parent;
+ private TabFolder tabs;
+ private Label no_data;
+ private final Map<TabItem,Page> tab2page = new HashMap<TabItem,Page>();
+
+ private class Page implements AbstractChannel.TraceListener {
+
+ final AbstractChannel channel;
+
+ private TabItem tab;
+ private Text text;
+
+ private final StringBuffer bf = new StringBuffer();
+ private int bf_line_cnt = 0;
+ private boolean closed;
+
+ private final Thread update_thread = new Thread() {
+ public void run() {
+ synchronized (Page.this) {
+ while (!closed) {
+ if (bf_line_cnt > 0) {
+ Runnable r = new Runnable() {
+ public void run() {
+ String str = null;
+ int cnt = 0;
+ synchronized (Page.this) {
+ str = bf.toString();
+ cnt = bf_line_cnt;
+ bf.setLength(0);
+ bf_line_cnt = 0;
+ }
+ if (text == null) return;
+ if (text.getLineCount() > 1000 - cnt) {
+ String s = text.getText();
+ int n = 0;
+ int i = -1;
+ while (n < cnt) {
+ int j = s.indexOf('\n', i + 1);
+ if (j < 0) break;
+ i = j;
+ n++;
+ }
+ if (i >= 0) {
+ text.setText(s.substring(i + 1));
+ }
+ }
+ text.append(str);
+ }
+ };
+ getSite().getShell().getDisplay().asyncExec(r);
+ }
+ try {
+ Page.this.wait(1000);
+ }
+ catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ }
+ };
+
+ Page(AbstractChannel channel) {
+ this.channel = channel;
+ update_thread.start();
+ }
+
+ public void dispose() {
+ synchronized (this) {
+ closed = true;
+ update_thread.interrupt();
+ }
+ try {
+ update_thread.join();
+ }
+ catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ tab2page.remove(tab);
+ tab.dispose();
+ tab = null;
+ text = null;
+ if (tab2page.isEmpty()) hideTabs();
+ }
+
+ public synchronized void onChannelClosed(Throwable error) {
+ if (error == null) {
+ channel.removeTraceListener(this);
+ getSite().getShell().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ dispose();
+ }
+ });
+ }
+ else {
+ bf.append("Channel terminated: " + error);
+ bf_line_cnt++;
+ }
+ }
+
+ public synchronized void onMessageReceived(char type, String token,
+ String service, String name, byte[] data) {
+ try {
+ bf.append("Inp: ");
+ bf.append(type);
+ if (token != null) {
+ bf.append(' ');
+ bf.append(token);
+ }
+ if (service != null) {
+ bf.append(' ');
+ bf.append(service);
+ }
+ if (name != null) {
+ bf.append(' ');
+ bf.append(name);
+ }
+ if (data != null) {
+ int i = 0;
+ while (i < data.length) {
+ int j = i;
+ while (j < data.length && data[j] != 0) j++;
+ bf.append(' ');
+ bf.append(new String(data, i, j - i, "UTF8"));
+ if (j < data.length && data[j] == 0) j++;
+ i = j;
+ }
+ }
+ bf.append('\n');
+ bf_line_cnt++;
+ }
+ catch (UnsupportedEncodingException x) {
+ x.printStackTrace();
+ }
+ }
+
+ public synchronized void onMessageSent(char type, String token,
+ String service, String name, byte[] data) {
+ try {
+ bf.append("Out: ");
+ bf.append(type);
+ if (token != null) {
+ bf.append(' ');
+ bf.append(token);
+ }
+ if (service != null) {
+ bf.append(' ');
+ bf.append(service);
+ }
+ if (name != null) {
+ bf.append(' ');
+ bf.append(name);
+ }
+ if (data != null) {
+ int i = 0;
+ while (i < data.length) {
+ int j = i;
+ while (j < data.length && data[j] != 0) j++;
+ bf.append(' ');
+ bf.append(new String(data, i, j - i, "UTF8"));
+ if (j < data.length && data[j] == 0) j++;
+ i = j;
+ }
+ }
+ bf.append('\n');
+ bf_line_cnt++;
+ }
+ catch (UnsupportedEncodingException x) {
+ x.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void createPartControl(Composite parent) {
+ this.parent = parent;
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ IChannel[] arr = Protocol.getOpenChannels();
+ for (IChannel c : arr) onChannelOpen(c);
+ Protocol.addChannelOpenListener(TraceView.this);
+ }
+ });
+ if (tab2page.size() == 0) hideTabs();
+ }
+
+ @Override
+ public void setFocus() {
+ if (tabs != null) tabs.setFocus();
+ }
+
+ @Override
+ public void dispose() {
+ final Page[] pages = tab2page.values().toArray(new Page[tab2page.size()]);
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ Protocol.removeChannelOpenListener(TraceView.this);
+ for (Page p : pages) p.channel.removeTraceListener(p);
+ }
+ });
+ for (Page p : pages) p.dispose();
+ assert tab2page.isEmpty();
+ if (tabs != null) {
+ tabs.dispose();
+ tabs = null;
+ }
+ if (no_data != null) {
+ no_data.dispose();
+ no_data = null;
+ }
+ super.dispose();
+ }
+
+ public void onChannelOpen(final IChannel channel) {
+ if (!(channel instanceof AbstractChannel)) return;
+ AbstractChannel c = (AbstractChannel)channel;
+ IPeer rp = c.getRemotePeer();
+ final String name = rp.getName();
+ final String host = rp.getAttributes().get(IPeer.ATTR_IP_HOST);
+ final String port = rp.getAttributes().get(IPeer.ATTR_IP_PORT);
+ final Page p = new Page(c);
+ c.addTraceListener(p);
+ getSite().getShell().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ showTabs();
+ p.tab = new TabItem(tabs, SWT.NONE);
+ tab2page.put(p.tab, p);
+ String title = name;
+ if (host != null) {
+ title += ", " + host;
+ if (port != null) {
+ title += ":" + port;
+ }
+ }
+ p.tab.setText(title);
+ p.text = new Text(tabs, SWT.H_SCROLL | SWT.V_SCROLL |
+ SWT.BORDER | SWT.READ_ONLY | SWT.MULTI);
+ p.tab.setControl(p.text);
+ p.text.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ }
+ });
+ }
+
+ private void showTabs() {
+ boolean b = false;
+ if (no_data != null) {
+ no_data.dispose();
+ no_data = null;
+ b = true;
+ }
+ if (tabs == null) {
+ tabs = new TabFolder(parent, SWT.NONE);
+ b = true;
+ }
+ if (b) parent.layout();
+ }
+
+ private void hideTabs() {
+ boolean b = false;
+ if (tabs != null) {
+ tabs.dispose();
+ tabs = null;
+ b = true;
+ }
+ if (!parent.isDisposed()) {
+ if (no_data == null) {
+ no_data = new Label(parent, SWT.NONE);
+ no_data.setText("No open communication channels at this time.");
+ b = true;
+ }
+ if (b) parent.layout();
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/.classpath b/plugins/com.windriver.tcf.api/.classpath
new file mode 100644
index 000000000..751c8f2e5
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/com.windriver.tcf.api/.cvsignore b/plugins/com.windriver.tcf.api/.cvsignore
new file mode 100644
index 000000000..c5e82d745
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/.cvsignore
@@ -0,0 +1 @@
+bin \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/.project b/plugins/com.windriver.tcf.api/.project
new file mode 100644
index 000000000..48171f9bd
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>com.windriver.tcf.api</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/com.windriver.tcf.api/.settings/org.eclipse.jdt.core.prefs b/plugins/com.windriver.tcf.api/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..d598b3c83
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,13 @@
+#Mon Sep 10 12:26:22 PDT 2007
+eclipse.preferences.version=1
+org.eclipse.jdt.core.builder.cleanOutputFolder=clean
+org.eclipse.jdt.core.builder.duplicateResourceTask=warning
+org.eclipse.jdt.core.builder.invalidClasspath=abort
+org.eclipse.jdt.core.builder.recreateModifiedClassFileInOutputFolder=ignore
+org.eclipse.jdt.core.builder.resourceCopyExclusionFilter=*.launch,.svn/
+org.eclipse.jdt.core.circularClasspath=error
+org.eclipse.jdt.core.classpath.exclusionPatterns=enabled
+org.eclipse.jdt.core.classpath.multipleOutputLocations=enabled
+org.eclipse.jdt.core.compiler.maxProblemPerUnit=100
+org.eclipse.jdt.core.incompatibleJDKLevel=ignore
+org.eclipse.jdt.core.incompleteClasspath=error
diff --git a/plugins/com.windriver.tcf.api/META-INF/MANIFEST.MF b/plugins/com.windriver.tcf.api/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..87bb955c3
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/META-INF/MANIFEST.MF
@@ -0,0 +1,14 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: com.windriver.tcf.api
+Bundle-Version: 0.1.0
+Bundle-Activator: com.windriver.tcf.api.Activator
+Bundle-Vendor: %providerName
+Require-Bundle: org.eclipse.core.runtime
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Eclipse-LazyStart: true
+Export-Package: com.windriver.tcf.api.core,
+ com.windriver.tcf.api.protocol,
+ com.windriver.tcf.api.services,
+ com.windriver.tcf.api.util
diff --git a/plugins/com.windriver.tcf.api/about.html b/plugins/com.windriver.tcf.api/about.html
new file mode 100755
index 000000000..6c5b3615b
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>January 10, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/build.properties b/plugins/com.windriver.tcf.api/build.properties
new file mode 100644
index 000000000..34d2e4d2d
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/build.properties
@@ -0,0 +1,4 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
diff --git a/plugins/com.windriver.tcf.api/plugin.properties b/plugins/com.windriver.tcf.api/plugin.properties
new file mode 100644
index 000000000..8c23febbe
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2007 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 implementation
+###############################################################################
+pluginName = Target Communication Framework (TCF)
+providerName = Eclipse.org
+
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/Activator.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/Activator.java
new file mode 100644
index 000000000..97ead437f
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/Activator.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Plugin;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.BundleContext;
+
+import com.windriver.tcf.api.protocol.Protocol;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends Plugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "com.windriver.tcf.api";
+
+ // The shared instance
+ private static Activator plugin;
+
+ public Activator() {
+ plugin = this;
+ }
+
+ @Override
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ Protocol.setEventQueue(new EventQueue());
+ }
+
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ /**
+ * Send error message into Eclipse log.
+ * @param msg - error message test
+ * @param err - exception
+ */
+ public static void log(String msg, Throwable err) {
+ if (plugin == null || plugin.getLog() == null) {
+ err.printStackTrace();
+ }
+ else {
+ plugin.getLog().log(new Status(IStatus.ERROR,
+ getDefault().getBundle().getSymbolicName(), IStatus.OK, msg, err));
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/ErrorCodes.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/ErrorCodes.java
new file mode 100644
index 000000000..e26cfa100
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/ErrorCodes.java
@@ -0,0 +1,18 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api;
+
+public class ErrorCodes {
+
+ public static final int
+ ERR_TERMINATE = 1;
+
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/EventQueue.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/EventQueue.java
new file mode 100644
index 000000000..fec45e8dd
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/EventQueue.java
@@ -0,0 +1,110 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api;
+
+import java.util.LinkedList;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.jobs.IJobChangeEvent;
+import org.eclipse.core.runtime.jobs.IJobChangeListener;
+import org.eclipse.core.runtime.jobs.Job;
+
+import com.windriver.tcf.api.protocol.IEventQueue;
+
+/**
+ * Implementation of Target Communication Framework event queue.
+ * This implementation is intended for Eclipse environment.
+ */
+class EventQueue implements IEventQueue, Runnable {
+
+ private final boolean debug = Platform.inDebugMode();
+ private final LinkedList<Runnable> queue = new LinkedList<Runnable>();
+ private final Thread thread;
+ private boolean waiting;
+ private int job_cnt;
+
+ EventQueue() {
+ thread = new Thread(this);
+ thread.setDaemon(true);
+ thread.setName("TCF Event Dispatch");
+ thread.start();
+ // Need to monitor jobs to detect congestion
+ Job.getJobManager().addJobChangeListener(new IJobChangeListener() {
+
+ public void aboutToRun(IJobChangeEvent event) {
+ job_cnt++;
+ }
+
+ public void awake(IJobChangeEvent event) {
+ //job_cnt++;
+ }
+
+ public void done(IJobChangeEvent event) {
+ job_cnt--;
+ if (Job.getJobManager().isIdle()) job_cnt = 0;
+ }
+
+ public void running(IJobChangeEvent event) {
+ }
+
+ public void scheduled(IJobChangeEvent event) {
+ }
+
+ public void sleeping(IJobChangeEvent event) {
+ //job_cnt--;
+ }
+ });
+ }
+
+ private void error(Throwable x) {
+ if (debug) x.printStackTrace();
+ Activator.log("Unhandled excetion in TCF event dispatch", x);
+ }
+
+ public void run() {
+ for (;;) {
+ try {
+ Runnable r = null;
+ synchronized (this) {
+ while (queue.isEmpty()) {
+ waiting = true;
+ wait();
+ }
+ r = queue.removeFirst();
+ }
+ r.run();
+ }
+ catch (Throwable x) {
+ error(x);
+ }
+ }
+ }
+
+ public synchronized void invokeLater(final Runnable r) {
+ queue.add(r);
+ if (waiting) {
+ waiting = false;
+ notifyAll();
+ }
+ }
+
+ public boolean isDispatchThread() {
+ return Thread.currentThread() == thread;
+ }
+
+ public synchronized int getCongestion() {
+ int l0 = job_cnt / 100 - 100;
+ int l1 = queue.size() / 100 - 100;
+ if (l1 > l0) l0 = l1;
+ if (l0 > 100) l0 = 100;
+ return l0;
+ }
+} \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractChannel.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractChannel.java
new file mode 100644
index 000000000..767f8b153
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractChannel.java
@@ -0,0 +1,796 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.core;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+
+import com.windriver.tcf.api.Activator;
+import com.windriver.tcf.api.internal.core.Token;
+import com.windriver.tcf.api.internal.core.Transport;
+import com.windriver.tcf.api.internal.services.local.DiagnosticsService;
+import com.windriver.tcf.api.internal.services.local.LocatorService;
+import com.windriver.tcf.api.internal.services.remote.GenericProxy;
+import com.windriver.tcf.api.internal.services.remote.LocatorProxy;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.ILocator;
+
+public abstract class AbstractChannel implements IChannel {
+
+ public interface TraceListener {
+
+ public void onMessageReceived(char type, String token,
+ String service, String name, byte[] data);
+
+ public void onMessageSent(char type, String token,
+ String service, String name, byte[] data);
+
+ public void onChannelClosed(Throwable error);
+ }
+
+ private static class Message {
+ final char type;
+ Token token;
+ String service;
+ String name;
+ byte[] data;
+
+ boolean is_sent;
+ boolean is_canceled;
+
+ Collection<TraceListener> trace;
+
+ Message(char type) {
+ this.type = type;
+ }
+
+ public String toString() {
+ try {
+ StringBuffer bf = new StringBuffer();
+ bf.append('[');;
+ bf.append(type);
+ if (token != null) {
+ bf.append(' ');
+ bf.append(token.getID());
+ }
+ if (service != null) {
+ bf.append(' ');
+ bf.append(service);
+ }
+ if (name != null) {
+ bf.append(' ');
+ bf.append(name);
+ }
+ if (data != null) {
+ int i = 0;
+ while (i < data.length) {
+ int j = i;
+ while (j < data.length && data[j] != 0) j++;
+ bf.append(' ');
+ bf.append(new String(data, i, j - i, "UTF8"));
+ if (j < data.length && data[j] == 0) j++;
+ i = j;
+ }
+ }
+ bf.append(']');
+ return bf.toString();
+ }
+ catch (Exception x) {
+ return x.toString();
+ }
+ }
+ }
+
+ private static IChannelListener[] listeners_array = new IChannelListener[64];
+
+ private final LinkedList<String> redirect_queue = new LinkedList<String>();
+ private final Map<Class<?>,IService> local_service_by_class = new HashMap<Class<?>,IService>();
+ private final Map<Class<?>,IService> remote_service_by_class = new HashMap<Class<?>,IService>();
+ private final Map<String,IService> local_service_by_name = new HashMap<String,IService>();
+ private final Map<String,IService> remote_service_by_name = new HashMap<String,IService>();
+ private final LinkedList<Message> out_queue = new LinkedList<Message>();
+ private final Collection<IChannelListener> channel_listeners = new ArrayList<IChannelListener>();
+ private final Map<String,IChannel.IEventListener[]> event_listeners = new HashMap<String,IChannel.IEventListener[]>();
+ private final Map<String,IChannel.ICommandServer> command_servers = new HashMap<String,IChannel.ICommandServer>();
+ private final Map<String,Message> inp_tokens = new HashMap<String,Message>();
+ private final Map<String,Message> out_tokens = new HashMap<String,Message>();
+ private final Thread inp_thread;
+ private final Thread out_thread;
+ private boolean shutdown;
+ private int state = STATE_OPENNING;
+ private IToken redirect_command;
+ private IPeer peer;
+
+ private static final int pending_command_limit = 10;
+ private int local_congestion_level = -100;
+ private int remote_congestion_level = -100;
+ private long local_congestion_time;
+ private int inp_queue_size = 0;
+ private Collection<TraceListener> trace_listeners;
+
+ public static final int
+ EOS = -1,
+ EOM = -2;
+
+ protected AbstractChannel(IPeer peer) {
+ assert Protocol.isDispatchThread();
+ assert Protocol.getLocator().getPeers().get(peer.getID()) == peer;
+ this.peer = peer;
+
+ addLocalService(Protocol.getLocator());
+ addLocalService(new DiagnosticsService(this));
+
+ inp_thread = new Thread() {
+
+ byte[] buf = new byte[1024];
+ byte[] eos;
+
+ private void error() throws IOException {
+ throw new IOException("Protocol syntax error");
+ }
+
+ private byte[] readBytes(int end) throws IOException {
+ int len = 0;
+ for (;;) {
+ int n = read();
+ if (n == end) break;
+ if (n < 0) error();
+ if (len >= buf.length) {
+ byte[] tmp = new byte[buf.length * 2];
+ System.arraycopy(buf, 0, tmp, 0, len);
+ buf = tmp;
+ }
+ buf[len++] = (byte)n;
+ }
+ byte[] res = new byte[len];
+ System.arraycopy(buf, 0, res, 0, len);
+ return res;
+ }
+
+ private String readString() throws IOException {
+ return new String(readBytes(0), "UTF8");
+ }
+
+ public void run() {
+ try {
+ while (true) {
+ int n = read();
+ if (n == EOM) continue;
+ if (n == EOS) {
+ eos = readBytes(EOM);
+ break;
+ }
+ final Message msg = new Message((char)n);
+ if (read() != 0) error();
+ switch (msg.type) {
+ case 'C':
+ msg.token = new Token(readBytes(0));
+ msg.service = readString();
+ msg.name = readString();
+ msg.data = readBytes(EOM);
+ break;
+ case 'R':
+ msg.token = new Token(readBytes(0));
+ msg.data = readBytes(EOM);
+ break;
+ case 'E':
+ msg.service = readString();
+ msg.name = readString();
+ msg.data = readBytes(EOM);
+ break;
+ case 'F':
+ msg.data = readBytes(EOM);
+ break;
+ default:
+ error();
+ }
+ long delay = 0;
+ synchronized (out_queue) {
+ inp_queue_size++;
+ if (inp_queue_size > 32) delay = inp_queue_size;
+ }
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ handleInput(msg);
+ }
+ });
+ if (delay > 0) sleep(delay);
+ }
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ if (out_tokens.isEmpty()) {
+ close();
+ }
+ else {
+ IOException x = new IOException("Connection reset by peer");
+ try {
+ Object[] args = JSON.parseSequence(eos);
+ int error_code = ((Number)args[0]).intValue();
+ if (error_code != 0) {
+ x = new IOException(Command.toErrorString(args[1]));
+ }
+ }
+ catch (IOException e) {
+ x = e;
+ }
+ terminate(x);
+ }
+ }
+ });
+ }
+ catch (final Throwable x) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ terminate(x);
+ }
+ });
+ }
+ }
+ };
+
+ out_thread = new Thread() {
+
+ public void run() {
+ try {
+ while (true) {
+ Message msg = null;
+ boolean last = false;
+ synchronized (out_queue) {
+ while (out_queue.isEmpty()) out_queue.wait();
+ msg = out_queue.removeFirst();
+ if (msg == null) break;
+ last = out_queue.isEmpty();
+ if (msg.is_canceled) {
+ if (last) flush();
+ continue;
+ }
+ msg.is_sent = true;
+ }
+ if (msg.trace != null) {
+ final Message m = msg;
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ for (TraceListener l : m.trace) {
+ try {
+ l.onMessageSent(m.type, m.token == null ? null : m.token.getID(),
+ m.service, m.name, m.data);
+ }
+ catch (Throwable x) {
+ Activator.log("Exception in channel listener", x);
+ }
+ }
+ }
+ });
+ }
+ write(msg.type);
+ write(0);
+ if (msg.token != null) {
+ write(msg.token.getBytes());
+ write(0);
+ }
+ if (msg.service != null) {
+ write(msg.service.getBytes("UTF8"));
+ write(0);
+ }
+ if (msg.name != null) {
+ write(msg.name.getBytes("UTF8"));
+ write(0);
+ }
+ if (msg.data != null) {
+ write(msg.data);
+ }
+ write(EOM);
+ int delay = 0;
+ int level = remote_congestion_level;
+ if (level > 0) delay = level * 10;
+ if (last || delay > 0) flush();
+ if (delay > 0) sleep(delay);
+ else yield();
+ }
+ write(EOS);
+ flush();
+ }
+ catch (final Throwable x) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ terminate(x);
+ }
+ });
+ }
+ }
+ };
+ inp_thread.setName("TCF Channel Receiver");
+ out_thread.setName("TCF Channel Transmitter");
+
+ try {
+ Object[] args = new Object[]{ local_service_by_name.keySet() };
+ sendEvent(Protocol.getLocator(), "Hello", JSON.toJSONSequence(args));
+ }
+ catch (IOException x) {
+ throw new Error(x);
+ }
+ }
+
+ protected void start() {
+ assert Protocol.isDispatchThread();
+ inp_thread.start();
+ out_thread.start();
+ LocatorService.channelStarted(this);
+ }
+
+ public void redirect(String peer_id) {
+ assert Protocol.isDispatchThread();
+ if (state == STATE_OPENNING) {
+ assert redirect_command == null;
+ redirect_queue.add(peer_id);
+ }
+ else {
+ assert state == STATE_OPEN;
+ state = STATE_OPENNING;
+ try {
+ onLocatorHello(new ArrayList<String>());
+ }
+ catch (Throwable x) {
+ terminate(x);
+ }
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void onLocatorHello(Collection<String> c) throws IOException {
+ if (state != STATE_OPENNING) throw new IOException("Invalid event: Locator.Hello");
+ remote_service_by_class.clear();
+ String pkg_name = LocatorProxy.class.getPackage().getName();
+ for (Iterator<String> i = c.iterator(); i.hasNext();) {
+ String service_name = i.next();
+ try {
+ Class<?> cls = Class.forName(pkg_name + "." + service_name + "Proxy");
+ IService service = (IService)cls.getConstructor(IChannel.class).newInstance(this);
+ for (Class<?> fs : cls.getInterfaces()) {
+ if (fs.equals(IService.class)) continue;
+ if (!IService.class.isAssignableFrom(fs)) continue;
+ remote_service_by_class.put(fs, service);
+ }
+ assert service_name.equals(service.getName());
+ remote_service_by_name.put(service_name, service);
+ }
+ catch (Exception x) {
+ IService service = new GenericProxy(this, service_name);
+ remote_service_by_name.put(service_name, service);
+ }
+ }
+ assert redirect_command == null;
+ if (redirect_queue.size() > 0) {
+ String id = redirect_queue.removeFirst();
+ ILocator l = (ILocator)remote_service_by_class.get(ILocator.NAME);
+ if (l == null) throw new IOException("Peer " + peer.getID() + " has no locator service");
+ peer = l.getPeers().get(id);
+ if (peer == null) throw new IOException("Unknown peer ID: " + id);
+ redirect_command = l.redirect(id, new ILocator.DoneRedirect() {
+ public void doneRedirect(IToken token, Exception x) {
+ assert redirect_command == token;
+ assert state == STATE_OPENNING;
+ redirect_command = null;
+ remote_congestion_level = 0;
+ if (x != null) terminate(x);
+ // Wait for next "Hello"
+ }
+ });
+ }
+ else {
+ state = STATE_OPEN;
+ Transport.channelOpened(this);
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ listeners_array = channel_listeners.toArray(listeners_array);
+ for (int i = 0; i < listeners_array.length && listeners_array[i] != null; i++) {
+ listeners_array[i].onChannelOpened();
+ }
+ }
+ });
+ }
+ }
+
+ public final int getState() {
+ return state;
+ }
+
+ public void addChannelListener(IChannelListener listener) {
+ assert Protocol.isDispatchThread();
+ channel_listeners.add(listener);
+ }
+
+ public void removeChannelListener(IChannelListener listener) {
+ assert Protocol.isDispatchThread();
+ channel_listeners.remove(listener);
+ }
+
+ public void addTraceListener(TraceListener listener) {
+ if (trace_listeners == null) {
+ trace_listeners = new ArrayList<TraceListener>();
+ }
+ else {
+ trace_listeners = new ArrayList<TraceListener>(trace_listeners);
+ }
+ trace_listeners.add(listener);
+ }
+
+ public void removeTraceListener(TraceListener listener) {
+ trace_listeners = new ArrayList<TraceListener>(trace_listeners);
+ trace_listeners.remove(listener);
+ if (trace_listeners.isEmpty()) trace_listeners = null;
+ }
+
+ public void addEventListener(IService service, IChannel.IEventListener listener) {
+ assert Protocol.isDispatchThread();
+ IChannel.IEventListener[] list = event_listeners.get(service.getName());
+ IChannel.IEventListener[] next = new IChannel.IEventListener[list == null ? 1 : list.length + 1];
+ if (list != null) System.arraycopy(list, 0, next, 0, list.length);
+ next[next.length - 1] = listener;
+ event_listeners.put(service.getName(), next);
+ }
+
+ public void removeEventListener(IService service, IChannel.IEventListener listener) {
+ assert Protocol.isDispatchThread();
+ IChannel.IEventListener[] list = event_listeners.get(service.getName());
+ for (int i = 0; i < list.length; i++) {
+ if (list[i] == listener) {
+ if (list.length == 1) {
+ event_listeners.remove(service.getName());
+ }
+ else {
+ IChannel.IEventListener[] next = new IChannel.IEventListener[list.length - 1];
+ System.arraycopy(list, 0, next, 0, i - 1);
+ System.arraycopy(list, i + 1, next, i, next.length - i);
+ event_listeners.put(service.getName(), next);
+ }
+ return;
+ }
+ }
+ }
+
+ public void addCommandServer(IService service, IChannel.ICommandServer listener) {
+ assert Protocol.isDispatchThread();
+ if (command_servers.put(service.getName(), listener) != null) {
+ throw new Error("Only one command server per service is allowed");
+ }
+ }
+
+ public void removeCommandServer(IService service, IChannel.ICommandServer listener) {
+ assert Protocol.isDispatchThread();
+ if (command_servers.remove(service.getName()) != listener) {
+ throw new Error("Invalid command server");
+ }
+ }
+
+ private void sendEndOfStream() {
+ if (shutdown) return;
+ shutdown = true;
+ synchronized (out_queue) {
+ out_queue.clear();
+ out_queue.add(0, null);
+ out_queue.notify();
+ }
+ }
+
+ public void close() {
+ assert Protocol.isDispatchThread();
+ try {
+ sendEndOfStream();
+ out_thread.join(10000);
+ stop();
+ inp_thread.join(10000);
+ terminate(null);
+ }
+ catch (Exception x) {
+ terminate(x);
+ }
+ }
+
+ public void terminate(final Throwable error) {
+ assert Protocol.isDispatchThread();
+ sendEndOfStream();
+ if (state == STATE_CLOSED) return;
+ if (error != null) Activator.log("TCF channel terminated", error);
+ state = STATE_CLOSED;
+ Transport.channelClosed(this, error);
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ if (!out_tokens.isEmpty()) {
+ Exception x = null;
+ if (error instanceof Exception) x = (Exception)error;
+ else if (error != null) x = new Exception(error);
+ else x = new IOException("Channel is closed");
+ for (Message msg : out_tokens.values()) {
+ String s = msg.toString();
+ if (s.length() > 72) s = s.substring(0, 72) + "...]";
+ IOException y = new IOException("Command " + s + " aborted");
+ y.initCause(x);
+ msg.token.getListener().terminated(msg.token, y);
+ }
+ out_tokens.clear();
+ }
+ listeners_array = channel_listeners.toArray(listeners_array);
+ for (int i = 0; i < listeners_array.length && listeners_array[i] != null; i++) {
+ listeners_array[i].onChannelClosed(error);
+ }
+ if (trace_listeners != null) {
+ for (TraceListener l : trace_listeners) {
+ try {
+ l.onChannelClosed(error);
+ }
+ catch (Throwable x) {
+ Activator.log("Exception in channel listener", x);
+ }
+ }
+ }
+ }
+ });
+ }
+
+ public int getCongestion() {
+ assert Protocol.isDispatchThread();
+ int level = out_tokens.size() * 100 / pending_command_limit - 100;
+ if (remote_congestion_level > level) level = remote_congestion_level;
+ if (level > 100) level = 100;
+ return level;
+ }
+
+ public IPeer getLocalPeer() {
+ assert Protocol.isDispatchThread();
+ return LocatorService.getLocalPeer();
+ }
+
+ public IPeer getRemotePeer() {
+ assert Protocol.isDispatchThread();
+ return peer;
+ }
+
+ private void addLocalService(IService service) {
+ for (Class<?> fs : service.getClass().getInterfaces()) {
+ if (fs.equals(IService.class)) continue;
+ if (!IService.class.isAssignableFrom(fs)) continue;
+ local_service_by_class.put(fs, service);
+ }
+ local_service_by_name.put(service.getName(), service);
+ }
+
+ public Collection<String> getLocalServices() {
+ assert Protocol.isDispatchThread();
+ return local_service_by_name.keySet();
+ }
+
+ public Collection<String> getRemoteServices() {
+ return remote_service_by_name.keySet();
+ }
+
+ @SuppressWarnings("unchecked")
+ public <V extends IService> V getLocalService(Class<V> cls) {
+ return (V)local_service_by_class.get(cls);
+ }
+
+ @SuppressWarnings("unchecked")
+ public <V extends IService> V getRemoteService(Class<V> cls) {
+ return (V)remote_service_by_class.get(cls);
+ }
+
+ public IService getLocalService(String service_name) {
+ return local_service_by_name.get(service_name);
+ }
+
+ public IService getRemoteService(String service_name) {
+ return remote_service_by_name.get(service_name);
+ }
+
+ private void addToOutQueue(Message msg) {
+ msg.trace = trace_listeners;
+ synchronized (out_queue) {
+ out_queue.add(msg);
+ out_queue.notify();
+ }
+ }
+
+ public IToken sendCommand(IService service, String name, byte[] args, ICommandListener listener) {
+ assert Protocol.isDispatchThread();
+ if (state != STATE_OPEN) throw new Error("Channel is closed");
+ final Message msg = new Message('C');
+ msg.service = service.getName();
+ msg.name = name;
+ msg.data = args;
+ Token token = new Token(listener) {
+ public boolean cancel() {
+ assert Protocol.isDispatchThread();
+ if (state != STATE_OPEN) return false;
+ synchronized (out_queue) {
+ if (msg.is_sent) return false;
+ msg.is_canceled = true;
+ }
+ out_tokens.remove(msg.token.getID());
+ return true;
+ }
+ };
+ msg.token = token;
+ out_tokens.put(token.getID(), msg);
+ addToOutQueue(msg);
+ return token;
+ }
+
+ public void sendResult(IToken token, byte[] results) {
+ assert Protocol.isDispatchThread();
+ if (state != STATE_OPEN) {
+ throw new Error("Channel is closed");
+ }
+ Message msg = new Message('R');
+ msg.data = results;
+ msg.token = (Token)token;
+ inp_tokens.remove(((Token)token).getID());
+ addToOutQueue(msg);
+ }
+
+ public void sendEvent(IService service, String name, byte[] args) {
+ assert Protocol.isDispatchThread();
+ if (!(state == STATE_OPEN || state == STATE_OPENNING && service instanceof ILocator)) {
+ throw new Error("Channel is closed");
+ }
+ Message msg = new Message('E');
+ msg.service = service.getName();
+ msg.name = name;
+ msg.data = args;
+ addToOutQueue(msg);
+ }
+
+ private void handleInput(Message msg) {
+ assert Protocol.isDispatchThread();
+ synchronized (out_queue) {
+ inp_queue_size--;
+ }
+ if (state == STATE_CLOSED) return;
+ if (trace_listeners != null) {
+ for (TraceListener l : trace_listeners) {
+ try {
+ l.onMessageReceived(msg.type,
+ msg.token != null ? msg.token.getID() : null,
+ msg.service, msg.name, msg.data);
+ }
+ catch (Throwable x) {
+ x.printStackTrace();
+ }
+ }
+ }
+ try {
+ Token token = null;
+ IChannel.IEventListener[] list = null;
+ IChannel.ICommandServer cmds = null;
+ switch (msg.type) {
+ case 'C':
+ token = msg.token;
+ inp_tokens.put(token.getID(), msg);
+ cmds = command_servers.get(msg.service);
+ if (cmds != null) {
+ cmds.command(token, msg.name, msg.data);
+ }
+ else {
+ throw new IOException("Unknown command " + msg.service + "." + msg.name);
+ }
+ sendCongestionLevel();
+ break;
+ case 'P':
+ token = out_tokens.get(msg.token.getID()).token;
+ token.getListener().progress(token, msg.data);
+ break;
+ case 'R':
+ token = out_tokens.remove(msg.token.getID()).token;
+ token.getListener().result(token, msg.data);
+ break;
+ case 'E':
+ list = event_listeners.get(msg.service);
+ if (list != null) {
+ for (int i = 0; i < list.length; i++) {
+ list[i].event(msg.name, msg.data);
+ }
+ }
+ sendCongestionLevel();
+ break;
+ case 'F':
+ remote_congestion_level = Integer.parseInt(new String(msg.data, "UTF8"));
+ break;
+ default:
+ assert false;
+ break;
+ }
+ }
+ catch (Throwable x) {
+ terminate(x);
+ }
+ }
+
+ private void sendCongestionLevel() throws IOException {
+ assert Protocol.isDispatchThread();
+ if (state != STATE_OPEN) return;
+ int level = Protocol.getEventQueue().getCongestion();
+ int n = inp_tokens.size() * 100 / pending_command_limit - 100;
+ if (n > level) level = n;
+ if (level > 100) level = 100;
+ if (level == local_congestion_level) return;
+ long time = System.currentTimeMillis();
+ if (level < local_congestion_level) {
+ if (time - local_congestion_time < 500) return;
+ int i = (local_congestion_level - level) / 4;
+ if (i <= 0) i = 1;
+ local_congestion_level -= i;
+ }
+ else {
+ local_congestion_level = level;
+ }
+ local_congestion_time = time;
+ synchronized (out_queue) {
+ Message msg = out_queue.isEmpty() ? null : out_queue.get(0);
+ if (msg == null || msg.type != 'F') {
+ msg = new Message('F');
+ out_queue.add(0, msg);
+ out_queue.notify();
+ }
+ msg.data = Integer.toString(local_congestion_level).getBytes("UTF8");
+ msg.trace = trace_listeners;
+ }
+ }
+
+ /**
+ * Read one byte from the channel input stream.
+ * @return next data byte or -1 if end of stream is reached.
+ * @throws IOException
+ */
+ protected abstract int read() throws IOException;
+
+ /**
+ * Write one byte into the channel output stream.
+ * The stream can put the byte into a buffer instead of transmitting it right away.
+ * @param n - the data byte.
+ * @throws IOException
+ */
+ protected abstract void write(int n) throws IOException;
+
+ /**
+ * Flush the channel output stream.
+ * All buffered data should be transmitted immediately.
+ * @throws IOException
+ */
+ protected abstract void flush() throws IOException;
+
+ /**
+ * Stop (close) channel underlying streams.
+ * If a thread is blocked by read() or write(), it should be
+ * resumed (or interrupted).
+ * @throws IOException
+ */
+ protected abstract void stop() throws IOException;
+
+ /**
+ * Write array of bytes into the channel output stream.
+ * The stream can put bytes into a buffer instead of transmitting it right away.
+ * @param buf
+ * @throws IOException
+ */
+ protected void write(byte[] buf) throws IOException {
+ assert Thread.currentThread() == out_thread;
+ for (int i = 0; i < buf.length; i++) write(buf[i]);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractPeer.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractPeer.java
new file mode 100644
index 000000000..314d9b03a
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/AbstractPeer.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.core;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.internal.core.ReadOnlyMap;
+import com.windriver.tcf.api.internal.core.Transport;
+import com.windriver.tcf.api.internal.services.local.LocatorService;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.Protocol;
+
+public abstract class AbstractPeer implements IPeer {
+
+ private final Map<String, String> ro_attrs;
+ private final Map<String, String> rw_attrs;
+
+ public AbstractPeer(Map<String, String> attrs) {
+ if (attrs != null) {
+ rw_attrs = new HashMap<String, String>(attrs);
+ }
+ else {
+ rw_attrs = new HashMap<String, String>();
+ }
+ ro_attrs = new ReadOnlyMap<String, String>(rw_attrs);
+ assert getID() != null;
+ LocatorService.addPeer(this);
+ }
+
+ protected Map<String, String> getAttributesStorage() {
+ assert Protocol.isDispatchThread();
+ return rw_attrs;
+ }
+
+ public void dispose() {
+ assert Protocol.isDispatchThread();
+ Transport.peerDisposed(this);
+ LocatorService.removePeer(this);
+ }
+
+ public Map<String, String> getAttributes() {
+ assert Protocol.isDispatchThread();
+ return ro_attrs;
+ }
+
+ public String getID() {
+ assert Protocol.isDispatchThread();
+ return ro_attrs.get(ATTR_ID);
+ }
+
+ public String getName() {
+ assert Protocol.isDispatchThread();
+ return ro_attrs.get(ATTR_NAME);
+ }
+
+ public String getOSName() {
+ assert Protocol.isDispatchThread();
+ return ro_attrs.get(ATTR_OS_NAME);
+ }
+
+ public String getTransportName() {
+ assert Protocol.isDispatchThread();
+ return ro_attrs.get(ATTR_TRANSPORT_NAME);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Base64.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Base64.java
new file mode 100644
index 000000000..498104fac
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Base64.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.core;
+
+/**
+ * Methods for translating Base64 encoded strings to byte arrays and back.
+ */
+public class Base64 {
+
+ public static char[] toBase64(byte[] buf, int pos, int len) {
+ char[] out_buf = new char[4 * ((len + 2) / 3)];
+ int end = pos + len;
+ int out_pos = 0;
+ while (pos < end) {
+ int byte0 = buf[pos++] & 0xff;
+ out_buf[out_pos++] = int2char[byte0 >> 2];
+ if (pos == end) {
+ out_buf[out_pos++] = int2char[(byte0 << 4) & 0x3f];
+ out_buf[out_pos++] = '=';
+ out_buf[out_pos++] = '=';
+ }
+ else {
+ int byte1 = buf[pos++] & 0xff;
+ out_buf[out_pos++] = int2char[(byte0 << 4) & 0x3f | (byte1 >> 4)];
+ if (pos == end) {
+ out_buf[out_pos++] = int2char[(byte1 << 2) & 0x3f];
+ out_buf[out_pos++] = '=';
+ }
+ else {
+ int byte2 = buf[pos++] & 0xff;
+ out_buf[out_pos++] = int2char[(byte1 << 2) & 0x3f | (byte2 >> 6)];
+ out_buf[out_pos++] = int2char[byte2 & 0x3f];
+ }
+ }
+ }
+ assert out_pos == out_buf.length;
+ return out_buf;
+ }
+
+ public static void toByteArray(byte[] buf, int offs, int size, char[] inp) {
+ int out_pos = offs;
+ if (inp != null) {
+ int inp_len = inp.length;
+ if (inp_len % 4 != 0) {
+ throw new IllegalArgumentException(
+ "BASE64 string length must be a multiple of four.");
+ }
+ int out_len = inp_len / 4 * 3;
+ if (inp_len > 0 && inp[inp_len - 1] == '=') {
+ out_len--;
+ if (inp[inp_len - 2] == '=') {
+ out_len--;
+ }
+ }
+ if (out_len > size) {
+ throw new IllegalArgumentException(
+ "BASE64 data array is longer then destination buffer.");
+ }
+ int inp_pos = 0;
+ while (inp_pos < inp_len) {
+ int n0, n1, n2, n3;
+ char ch0 = inp[inp_pos++];
+ char ch1 = inp[inp_pos++];
+ char ch2 = inp[inp_pos++];
+ char ch3 = inp[inp_pos++];
+ if (ch0 >= char2int.length || (n0 = char2int[ch0]) < 0) {
+ throw new IllegalArgumentException("Illegal character " + ch0);
+ }
+ if (ch1 >= char2int.length || (n1 = char2int[ch1]) < 0) {
+ throw new IllegalArgumentException("Illegal character " + ch1);
+ }
+ buf[out_pos++] = (byte)((n0 << 2) | (n1 >> 4));
+ if (ch2 == '=') break;
+ if (ch2 >= char2int.length || (n2 = char2int[ch2]) < 0) {
+ throw new IllegalArgumentException("Illegal character " + ch2);
+ }
+ buf[out_pos++] = (byte)((n1 << 4) | (n2 >> 2));
+ if (ch3 == '=') break;
+ if (ch3 >= char2int.length || (n3 = char2int[ch3]) < 0) {
+ throw new IllegalArgumentException("Illegal character " + ch3);
+ }
+ buf[out_pos++] = (byte)((n2 << 6) | n3);
+ }
+ assert out_pos == offs + out_len;
+ }
+ while (out_pos < offs + size) buf[out_pos++] = 0;
+ }
+
+ public static byte[] toByteArray(char[] inp) {
+ int inp_len = inp.length;
+ int out_len = inp_len / 4 * 3;
+ if (inp_len > 0 && inp[inp_len - 1] == '=') {
+ out_len--;
+ if (inp[inp_len - 2] == '=') {
+ out_len--;
+ }
+ }
+ byte[] buf = new byte[out_len];
+ toByteArray(buf, 0, buf.length, inp);
+ return buf;
+ }
+
+ /*
+ * See RFC 2045.
+ */
+ private static final char int2char[] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '+', '/'
+ };
+
+ /*
+ * See RFC 2045
+ */
+ private static final byte char2int[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51
+ };
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/ChannelTCP.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/ChannelTCP.java
new file mode 100644
index 000000000..c50a5ad03
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/ChannelTCP.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.core;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.SocketException;
+
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.Protocol;
+
+public class ChannelTCP extends StreamChannel {
+
+ private Socket socket;
+ private InputStream inp;
+ private OutputStream out;
+ private boolean closed;
+
+ public ChannelTCP(IPeer peer, final String host, final int port) {
+ super(peer);
+ Thread thread = new Thread() {
+ public void run() {
+ try {
+ socket = new Socket(host, port);
+ socket.setTcpNoDelay(true);
+ inp = new BufferedInputStream(socket.getInputStream());
+ out = new BufferedOutputStream(socket.getOutputStream());
+ /* Uncomment for testing of buffers.
+ inp = new BufferedInputStream(new FilterInputStream(socket.getInputStream()) {
+ public int read() throws IOException {
+ System.out.println("Inp 1");
+ return in.read();
+ }
+ public int read(byte b[]) throws IOException {
+ int n = in.read(b);
+ System.out.println("Inp " + n);
+ return n;
+ }
+ public int read(byte b[], int off, int len) throws IOException {
+ int n = in.read(b, off, len);
+ System.out.println("Inp " + n);
+ return n;
+ }
+ });
+ out = new BufferedOutputStream(new FilterOutputStream(socket.getOutputStream()){
+ public void write(int b) throws IOException {
+ System.out.println("Out 1");
+ out.write(b);
+ }
+ public void write(byte b[]) throws IOException {
+ System.out.println("Out " + b.length);
+ out.write(b);
+ }
+ public void write(byte b[], int off, int len) throws IOException {
+ System.out.println("Out " + len);
+ out.write(b, off, len);
+ }
+ });
+ */
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ ChannelTCP.this.start();
+ }
+ });
+ }
+ catch (final IOException x) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ ChannelTCP.this.terminate(x);
+ }
+ });
+ }
+ }
+ };
+ thread.setName("TCF Socket Connect");
+ thread.start();
+ }
+
+ @Override
+ protected final int get() throws IOException {
+ try {
+ if (closed) return -1;
+ return inp.read();
+ }
+ catch (SocketException x) {
+ if (closed) return -1;
+ throw x;
+ }
+ }
+
+ @Override
+ protected final void put(int b) throws IOException {
+ assert b >= 0 && b <= 0xff;
+ if (closed) return;
+ out.write(b);
+ }
+
+ @Override
+ protected final void flush() throws IOException {
+ if (closed) return;
+ out.flush();
+ }
+
+ @Override
+ protected void stop() throws IOException {
+ closed = true;
+ socket.close();
+ out.close();
+ inp.close();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Command.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Command.java
new file mode 100644
index 000000000..d704ba96b
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/Command.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.core;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.Map;
+
+import com.windriver.tcf.api.internal.core.Token;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.protocol.Protocol;
+
+/**
+ * This is utility class that helps to implement sending a command and receiving
+ * command result over TCF communication channel. The class uses JSON to encode
+ * command arguments and to decode result data. Clients are expected to subclass
+ * <code>Command</code> and override <code>done</code> method.
+ *
+ * Note: most clients don't need to handle protocol commands directly and
+ * can use service APIs instead. Service API does all command encoding/decoding
+ * for a client.
+ *
+ * Typical usage example:
+ *
+ * public IToken getContext(String id, final DoneGetContext done) {
+ * return new Command(channel, IService.this, "getContext", new Object[]{ id }) {
+ * @Override
+ * public void done(Exception error, Object[] args) {
+ * Context ctx = null;
+ * if (error == null) {
+ * assert args.length == 3;
+ * error = JSON.toError(args[0], args[1]);
+ * if (args[2] != null) ctx = new Context(args[2]);
+ * }
+ * done.doneGetContext(token, error, ctx);
+ * }
+ * }.token;
+ * }
+ */
+public abstract class Command implements IChannel.ICommandListener {
+
+ private final IService service;
+ private final String command;
+ private final Object[] args;
+
+ public final IToken token;
+
+ private boolean done;
+
+ public Command(IChannel channel, IService service, String command, Object[] args) {
+ this.service = service;
+ this.command = command;
+ this.args = args;
+ IToken t = null;
+ try {
+ t = channel.sendCommand(service, command, JSON.toJSONSequence(args), this);
+ }
+ catch (Throwable y) {
+ t = new Token();
+ final Exception x = y instanceof Exception ? (Exception)y : new Exception(y);
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ assert !done;
+ done = true;
+ done(x, null);
+ }
+ });
+ }
+ token = t;
+ }
+
+ public void progress(IToken token, byte[] data) {
+ assert this.token == token;
+ }
+
+ public void result(IToken token, byte[] data) {
+ assert this.token == token;
+ Exception error = null;
+ Object[] args = null;
+ try {
+ args = JSON.parseSequence(data);
+ }
+ catch (Exception e) {
+ error = e;
+ }
+ assert !done;
+ done = true;
+ done(error, args);
+ }
+
+ public void terminated(IToken token, Exception error) {
+ assert this.token == token;
+ assert !done;
+ done = true;
+ done(error, null);
+ }
+
+ public abstract void done(Exception error, Object[] args);
+
+ public String getCommandString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(service.getName());
+ buf.append(' ');
+ buf.append(command);
+ if (args != null) {
+ for (int i = 0; i < args.length; i++) {
+ buf.append(i == 0 ? " " : ", ");
+ try {
+ buf.append(JSON.toJSON(args[i]));
+ }
+ catch (IOException x) {
+ buf.append("***");
+ buf.append(x.getMessage());
+ buf.append("***");
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ @SuppressWarnings("unchecked")
+ public static String toErrorString(Object data) {
+ if (data instanceof String) {
+ return (String)data;
+ }
+ else if (data != null) {
+ Map<String,Object> map = (Map<String,Object>)data;
+ Collection<Object> c = (Collection<Object>)map.get("params");
+ return new MessageFormat((String)map.get("format")).format(c.toArray());
+ }
+ return null;
+ }
+
+ public Exception toError(Object code, Object data) {
+ int error_code = ((Number)code).intValue();
+ if (error_code == 0) return null;
+ String cmd = getCommandString();
+ if (cmd.length() > 72) cmd = cmd.substring(0, 72) + "...";
+ return new Exception(
+ "TCF command exception:" +
+ "\nCommand: " + cmd +
+ "\nException: " + toErrorString(data) +
+ "\nError code: " + code);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/StreamChannel.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/StreamChannel.java
new file mode 100644
index 000000000..a6b871740
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/core/StreamChannel.java
@@ -0,0 +1,66 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.core;
+
+import java.io.IOException;
+
+import com.windriver.tcf.api.protocol.IPeer;
+
+public abstract class StreamChannel extends AbstractChannel {
+
+ public static final int ESC = 3;
+
+ public StreamChannel(IPeer peer) {
+ super(peer);
+ }
+
+ protected abstract int get() throws IOException;
+ protected abstract void put(int n) throws IOException;
+
+ @Override
+ protected final int read() throws IOException {
+ int res = get();
+ if (res < 0) return EOS;
+ assert res >= 0 && res <= 0xff;
+ if (res != ESC) return res;
+ int n = get();
+ switch (n) {
+ case 0: return ESC;
+ case 1: return EOM;
+ case 2: return EOS;
+ default:
+ if (n < 0) return EOS;
+ assert false;
+ return 0;
+ }
+ }
+
+ @Override
+ protected final void write(int n) throws IOException {
+ switch (n) {
+ case ESC: put(ESC); put(0); break;
+ case EOM: put(ESC); put(1); break;
+ case EOS: put(ESC); put(2); break;
+ default:
+ assert n >= 0 && n <= 0xff;
+ put(n);
+ }
+ }
+
+ @Override
+ protected void write(byte[] buf) throws IOException {
+ for (int i = 0; i < buf.length; i++) {
+ int n = buf[i] & 0xff;
+ put(n);
+ if (n == ESC) put(0);
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ChannelLoop.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ChannelLoop.java
new file mode 100644
index 000000000..1bb1cd141
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ChannelLoop.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.core;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+import com.windriver.tcf.api.core.StreamChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+
+public class ChannelLoop extends StreamChannel {
+
+ private final byte[] buf = new byte[0x1000];
+ private int buf_inp;
+ private int buf_out;
+ private boolean waiting;
+ private boolean closed;
+
+ ChannelLoop(IPeer peer) {
+ super(peer);
+ start();
+ }
+
+ @Override
+ protected synchronized int get() throws IOException {
+ try {
+ while (buf_inp == buf_out) {
+ if (closed) return -1;
+ waiting = true;
+ wait();
+ }
+ int b = buf[buf_out] & 0xff;
+ buf_out = (buf_out + 1) % buf.length;
+ if (waiting) {
+ waiting = false;
+ notifyAll();
+ }
+ return b;
+ }
+ catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ }
+
+ @Override
+ protected synchronized void put(int b) throws IOException {
+ assert b >=0 && b <= 0xff;
+ try {
+ for (;;) {
+ int nxt_inp = (buf_inp + 1) % buf.length;
+ if (nxt_inp != buf_out) {
+ buf[buf_inp] = (byte)b;
+ buf_inp = nxt_inp;
+ break;
+ }
+ if (closed) return;
+ waiting = true;
+ wait();
+ }
+ if (waiting) {
+ waiting = false;
+ notifyAll();
+ }
+ }
+ catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ }
+
+ @Override
+ protected void flush() throws IOException {
+ }
+
+ @Override
+ protected synchronized void stop() throws IOException {
+ closed = true;
+ if (waiting) {
+ waiting = false;
+ notifyAll();
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/LocalPeer.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/LocalPeer.java
new file mode 100644
index 000000000..9300e3ad4
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/LocalPeer.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.core;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.AbstractPeer;
+import com.windriver.tcf.api.protocol.IChannel;
+
+public class LocalPeer extends AbstractPeer {
+
+ private static Map<String, String> createAttributes() {
+ Map<String, String> attrs = new HashMap<String, String>();
+ attrs.put(ATTR_ID, "TCFLocal");
+ attrs.put(ATTR_NAME, "Local Peer");
+ attrs.put(ATTR_OS_NAME, System.getProperty("os.name"));
+ attrs.put(ATTR_TRANSPORT_NAME, "Loop");
+ return attrs;
+ }
+
+ public LocalPeer() {
+ super(createAttributes());
+ }
+
+ public IChannel openChannel() {
+ return new ChannelLoop(this);
+ }
+} \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyCollection.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyCollection.java
new file mode 100644
index 000000000..cc8aeb422
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyCollection.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.core;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+public class ReadOnlyCollection<E> implements Set<E> {
+
+ private final Collection<E> base;
+
+ public ReadOnlyCollection(Collection<E> base) {
+ this.base = base;
+ }
+
+ private void error() {
+ throw new Error("Read only Collection");
+ }
+
+ public boolean add(E e) {
+ error();
+ return false;
+ }
+
+ public boolean addAll(Collection<? extends E> c) {
+ error();
+ return false;
+ }
+
+ public void clear() {
+ error();
+ }
+
+ public boolean contains(Object o) {
+ return base.contains(o);
+ }
+
+ public boolean containsAll(Collection<?> c) {
+ return base.containsAll(c);
+ }
+
+ public boolean isEmpty() {
+ return base.isEmpty();
+ }
+
+ public Iterator<E> iterator() {
+ final Iterator<E> iterator = base.iterator();
+ return new Iterator<E>() {
+
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ public E next() {
+ return iterator.next();
+ }
+
+ public void remove() {
+ error();
+ }
+ };
+ }
+
+ public boolean remove(Object o) {
+ error();
+ return false;
+ }
+
+ public boolean removeAll(Collection<?> c) {
+ error();
+ return false;
+ }
+
+ public boolean retainAll(Collection<?> c) {
+ error();
+ return false;
+ }
+
+ public int size() {
+ return base.size();
+ }
+
+ public Object[] toArray() {
+ return base.toArray();
+ }
+
+ public <T> T[] toArray(T[] a) {
+ return base.toArray(a);
+ }
+
+ public boolean equals(Object o) {
+ return base.equals(o);
+ }
+
+ public int hashCode() {
+ return base.hashCode();
+ }
+
+ public String toString() {
+ return base.toString();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyMap.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyMap.java
new file mode 100644
index 000000000..458d27f72
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/ReadOnlyMap.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.core;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+public class ReadOnlyMap<K,V> implements Map<K,V> {
+
+ private final Map<K,V> base;
+ private Set<K> key_set;
+ private Set<Map.Entry<K, V>> entry_set;
+ private Collection<V> values;
+
+ public ReadOnlyMap(Map<K,V> base) {
+ this.base = base;
+ }
+
+ private void error() {
+ throw new Error("Read only Map");
+ }
+
+ public void clear() {
+ error();
+ }
+
+ public boolean containsKey(Object key) {
+ return base.containsKey(key);
+ }
+
+ public boolean containsValue(Object value) {
+ return base.containsValue(value);
+ }
+
+ public Set<Map.Entry<K, V>> entrySet() {
+ if (entry_set == null) entry_set = new ReadOnlyCollection<Map.Entry<K, V>>(base.entrySet());
+ return entry_set;
+ }
+
+ public V get(Object key) {
+ return base.get(key);
+ }
+
+ public boolean isEmpty() {
+ return base.isEmpty();
+ }
+
+ public Set<K> keySet() {
+ if (key_set == null) key_set = new ReadOnlyCollection<K>(base.keySet());
+ return key_set;
+ }
+
+ public V put(K key, V value) {
+ error();
+ return null;
+ }
+
+ public void putAll(Map<? extends K, ? extends V> m) {
+ error();
+ }
+
+ public V remove(Object key) {
+ error();
+ return null;
+ }
+
+ public int size() {
+ return base.size();
+ }
+
+ public Collection<V> values() {
+ if (values == null) values = new ReadOnlyCollection<V>(base.values());
+ return values;
+ }
+
+ public boolean equals(Object o) {
+ return base.equals(o);
+ }
+
+ public int hashCode() {
+ return base.hashCode();
+ }
+
+ public String toString() {
+ return base.toString();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/RemotePeer.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/RemotePeer.java
new file mode 100644
index 000000000..fa4c93eef
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/RemotePeer.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.core;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.AbstractPeer;
+import com.windriver.tcf.api.core.ChannelTCP;
+import com.windriver.tcf.api.protocol.IChannel;
+
+public class RemotePeer extends AbstractPeer {
+
+ public RemotePeer(Map<String,String> attrs) {
+ super(attrs);
+ }
+
+ public boolean updateAttributes(Map<String,String> attrs1) {
+ boolean equ = true;
+ Map<String,String> attrs0 = getAttributesStorage();
+ assert attrs1.get(ATTR_ID).equals(attrs0.get(ATTR_ID));
+ for (Iterator<String> i = attrs0.keySet().iterator(); i.hasNext();) {
+ String key = i.next();
+ if (!attrs0.get(key).equals(attrs1.get(key))) {
+ equ = false;
+ break;
+ }
+ }
+ for (Iterator<String> i = attrs1.keySet().iterator(); i.hasNext();) {
+ String key = i.next();
+ if (!attrs1.get(key).equals(attrs0.get(key))) {
+ equ = false;
+ break;
+ }
+ }
+ if (!equ) {
+ attrs0.clear();
+ attrs0.putAll(attrs1);
+ }
+ return !equ;
+ }
+
+ public IChannel openChannel() {
+ String transport = getTransportName();
+ if (transport.equals("TCP")) {
+ Map<String,String> attrs = getAttributes();
+ String host = attrs.get(ATTR_IP_HOST);
+ String port = attrs.get(ATTR_IP_PORT);
+ if (host == null) throw new Error("No host name");
+ if (port == null) throw new Error("No port number");
+ return new ChannelTCP(this, host, Integer.parseInt(port));
+ }
+ else {
+ throw new Error("Unknow transport name: " + transport);
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Token.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Token.java
new file mode 100644
index 000000000..9892b9cbd
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Token.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.core;
+
+import java.io.UnsupportedEncodingException;
+
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+
+public class Token implements IToken {
+
+ private static int cnt = 0;
+
+ private final String id;
+ private final byte[] bytes;
+ private final IChannel.ICommandListener listener;
+
+ public Token() {
+ id = null;
+ bytes = null;
+ listener = null;
+ }
+
+ public Token(IChannel.ICommandListener listener) {
+ this.listener = listener;
+ id = Integer.toString(cnt++);
+ try {
+ bytes = id.getBytes("ASCII");
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new Error(e);
+ }
+ }
+
+ public Token(byte[] bytes) {
+ this.bytes = bytes;
+ listener = null;
+ try {
+ id = new String(bytes, "ASCII");
+ }
+ catch (UnsupportedEncodingException e) {
+ throw new Error(e);
+ }
+ }
+
+ public boolean cancel() {
+ return false;
+ }
+
+ public String getID() {
+ return id;
+ }
+
+ public byte[] getBytes() {
+ return bytes;
+ }
+
+ public IChannel.ICommandListener getListener() {
+ return listener;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Transport.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Transport.java
new file mode 100644
index 000000000..3e2d1840e
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/core/Transport.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.core;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Set;
+
+import com.windriver.tcf.api.Activator;
+import com.windriver.tcf.api.core.AbstractChannel;
+import com.windriver.tcf.api.core.AbstractPeer;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.ILocator;
+
+public class Transport {
+
+ private static final Collection<AbstractChannel> channels =
+ new LinkedList<AbstractChannel>();
+ private static final Collection<Protocol.ChannelOpenListener> listeners =
+ new LinkedList<Protocol.ChannelOpenListener>();
+
+ public static void channelOpened(final AbstractChannel channel) {
+ channels.add(channel);
+ for (Protocol.ChannelOpenListener l : listeners) {
+ try {
+ l.onChannelOpen(channel);
+ }
+ catch (Throwable x) {
+ Activator.log("Exception in channel listener", x);
+ }
+ }
+ }
+
+ public static void channelClosed(final AbstractChannel channel, final Throwable x) {
+ channels.remove(channel);
+ }
+
+ public static IChannel[] getOpenChannels() {
+ return channels.toArray(new IChannel[channels.size()]);
+ }
+
+ public static void addChanalOpenListener(Protocol.ChannelOpenListener listener) {
+ listeners.add(listener);
+ }
+
+ public static void removeChanalOpenListener(Protocol.ChannelOpenListener listener) {
+ listeners.remove(listener);
+ }
+
+ public static void peerDisposed(AbstractPeer peer) {
+ Collection<AbstractChannel> bf = new ArrayList<AbstractChannel>(channels);
+ for (Iterator<AbstractChannel> i = bf.iterator(); i.hasNext();) {
+ AbstractChannel c = i.next();
+ if (c.getRemotePeer() != peer) continue;
+ c.close();
+ }
+ }
+
+ /**
+ * Transmit TCF event message.
+ * The message is sent to all open communication channels – broadcasted.
+ *
+ * This is internal API, TCF clients should use {@code com.windriver.tcf.api.protocol.Protocol}.
+ */
+ public static void sendEvent(String service_name, String event_name, byte[] data) {
+ for (Iterator<AbstractChannel> i = channels.iterator(); i.hasNext();) {
+ AbstractChannel channel = i.next();
+ IService s = channel.getRemoteService(service_name);
+ if (s != null) channel.sendEvent(s, event_name, data);
+ }
+ }
+
+ /**
+ * Call back after TCF messages sent by this host up to this moment are delivered
+ * to their intended targets. This method is intended for synchronization of messages
+ * across multiple channels.
+ *
+ * Note: Cross channel synchronization can reduce performance and throughput.
+ * Most clients don't need cross channel synchronization and should not call this method.
+ *
+ * @param done will be executed by dispatch thread after communication
+ * messages are delivered to corresponding targets.
+ *
+ * This is internal API, TCF clients should use {@code com.windriver.tcf.api.protocol.Protocol}.
+ */
+ public static void sync(final Runnable done) {
+ final Set<IToken> set = new HashSet<IToken>();
+ ILocator.DoneSync done_sync = new ILocator.DoneSync() {
+ public void doneSync(IToken token) {
+ assert set.contains(token);
+ set.remove(token);
+ if (set.isEmpty()) done.run();
+ }
+ };
+ for (Iterator<AbstractChannel> i = channels.iterator(); i.hasNext();) {
+ AbstractChannel channel = i.next();
+ ILocator s = channel.getRemoteService(ILocator.class);
+ if (s != null) set.add(s.sync(done_sync));
+ }
+ if (set.isEmpty()) Protocol.invokeLater(done);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/DiagnosticsService.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/DiagnosticsService.java
new file mode 100644
index 000000000..88ad937bb
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/DiagnosticsService.java
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.local;
+
+import com.windriver.tcf.api.internal.core.Token;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IDiagnostics;
+
+public class DiagnosticsService implements IDiagnostics {
+
+ private final IChannel channel;
+
+ private class CommandServer implements IChannel.ICommandServer {
+
+ public void command(IToken token, String name, byte[] data) {
+ try {
+ if (name.equals("echo")) {
+ channel.sendResult(token, data);
+ }
+ else if (name.equals("getTestList")) {
+ channel.sendResult(token, JSON.toJSONSequence(new Object[]{
+ new Integer(0), null, new String[0]}));
+ }
+ else {
+ channel.terminate(new Exception("Illegal command: " + name));
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ }
+
+ public DiagnosticsService(IChannel channel) {
+ this.channel = channel;
+ channel.addCommandServer(this, new CommandServer());
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken echo(final String s, final DoneEcho done) {
+ final IToken token = new Token();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ done.doneEcho(token, null, s);
+ }
+ });
+ return token;
+ }
+
+ public IToken getTestList(final DoneGetTestList done) {
+ final IToken token = new Token();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ done.doneGetTestList(token, null, new String[0]);
+ }
+ });
+ return token;
+ }
+
+ public IToken runTest(final String s, final DoneRunTest done) {
+ final IToken token = new Token();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ done.doneRunTest(token, new Exception("Test suite not found: " + s), null);
+ }
+ });
+ return token;
+ }
+
+ public IToken cancelTest(String context_id, final DoneCancelTest done) {
+ final IToken token = new Token();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ done.doneCancelTest(token, null);
+ }
+ });
+ return token;
+ }
+
+ public IToken getSymbol(String context_id, String symbol_name, final DoneGetSymbol done) {
+ final IToken token = new Token();
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ done.doneGetSymbol(token, new Exception("Invalid context"), null);
+ }
+ });
+ return token;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/LocatorService.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/LocatorService.java
new file mode 100644
index 000000000..9672433ea
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/local/LocatorService.java
@@ -0,0 +1,368 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.local;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.windriver.tcf.api.Activator;
+import com.windriver.tcf.api.core.AbstractChannel;
+import com.windriver.tcf.api.internal.core.LocalPeer;
+import com.windriver.tcf.api.internal.core.RemotePeer;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.ILocator;
+
+/**
+ * Locator service uses transport layer to search
+ * for peers and to collect and maintain up-to-date
+ * data about peer’s attributes and capabilities (services).
+ */
+public class LocatorService implements ILocator {
+
+ private static LocatorService locator;
+ private static final Map<String,IPeer> peers = new HashMap<String,IPeer>();
+ private static final Collection<LocatorListener> listeners = new ArrayList<LocatorListener>();
+
+ private static LocalPeer local_peer;
+
+ private DatagramSocket socket;
+
+ private Thread output_thread = new Thread() {
+ public void run() {
+ for (;;) {
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ sendPeerInfoRequest();
+ }
+ });
+ try {
+ sleep(5 * 1000);
+ }
+ catch (InterruptedException x) {
+ break;
+ }
+ }
+ }
+ };
+
+ private Thread input_thread = new Thread() {
+ public void run() {
+ for (;;) {
+ try {
+ byte[] buf = new byte[0x1000];
+ final DatagramPacket p = new DatagramPacket(buf, buf.length);
+ socket.receive(p);
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ handleDatagramPacket(p);
+ }
+ });
+ }
+ catch (Exception x) {
+ Activator.log("Cannot read from datagram socket", x);
+ break;
+ }
+ }
+ }
+ };
+
+ public LocatorService() {
+ locator = this;
+ try {
+ socket = new DatagramSocket();
+ socket.setBroadcast(true);
+ input_thread.setName("TCF Locator Receiver");
+ output_thread.setName("TCF Locator Transmitter");
+ input_thread.start();
+ output_thread.start();
+ }
+ catch (Exception x) {
+ Activator.log("Cannot create datagram socket", x);
+ }
+ }
+
+ public static LocalPeer getLocalPeer() {
+ return local_peer;
+ }
+
+ public static void addPeer(IPeer peer) {
+ assert peers.get(peer.getID()) == null;
+ if (peer instanceof LocalPeer) local_peer = (LocalPeer)peer;
+ peers.put(peer.getID(), peer);
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext(); ) {
+ i.next().peerAdded(peer);
+ }
+ }
+
+ public static void removePeer(IPeer peer) {
+ assert peers.get(peer.getID()) == peer;
+ peers.remove(peer);
+ String id = peer.getID();
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext(); ) {
+ i.next().peerRemoved(id);
+ }
+ }
+
+ private void notifyPeer(IPeer peer) {
+ assert peers.get(peer.getID()) == peer;
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext(); ) {
+ i.next().peerChanged(peer);
+ }
+ }
+
+ public static void channelStarted(final AbstractChannel channel) {
+ channel.addEventListener(locator, new IChannel.IEventListener() {
+ public void event(String name, byte[] data) {
+ locator.event(channel, name, data);
+ }
+ });
+ channel.addCommandServer(locator, new IChannel.ICommandServer() {
+ public void command(IToken token, String name, byte[] data) {
+ locator.command(channel, token, name, data);
+ }
+ });
+ }
+
+ @SuppressWarnings("unchecked")
+ private void event(AbstractChannel channel, String name, byte[] data) {
+ try {
+ if (name.equals("Hello")) {
+ Collection<String> c = (Collection<String>)JSON.parseSequence(data)[0];
+ channel.onLocatorHello(c);
+ }
+ else {
+ throw new IOException("Unknown event: Locator." + name);
+ }
+ }
+ catch (IOException e) {
+ channel.terminate(e);
+ }
+ }
+
+ private void command(AbstractChannel channel, IToken token, String name, byte[] data) {
+ try {
+ if (name.equals("redirect")) {
+ // String peer_id = (String)JSON.parseSequence(data)[0];
+ // TODO: perform local ILocator.redirect
+ channel.sendResult(token, JSON.toJSONSequence(new Object[]{
+ new Integer(0), null }));
+ }
+ else if (name.equals("sync")) {
+ channel.sendResult(token, null);
+ }
+ else {
+ channel.terminate(new Exception("Illegal command: " + name));
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+
+ private void sendPeerInfoRequest() {
+ try {
+ byte[] buf = new byte[8];
+ int i = 0;
+ buf[i++] = 'T';
+ buf[i++] = 'C';
+ buf[i++] = 'F';
+ buf[i++] = '1';
+ buf[i++] = CONF_REQ_INFO;
+ buf[i++] = 0;
+ buf[i++] = 0;
+ buf[i++] = 0;
+ for (Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces(); e.hasMoreElements();) {
+ NetworkInterface f = e.nextElement();
+ /* TODO: Class InterfaceAddress does not exists in Java versions before 1.6.
+ * When support for old Java versions is not needed any more,
+ * the code below should be replaced with:
+ * for (InterfaceAddress ia : f.getInterfaceAddresses()) {
+ * socket.send(new DatagramPacket(buf, buf.length, ia.getBroadcast(), 1534));
+ * }
+ */
+ Enumeration<InetAddress> n = f.getInetAddresses();
+ while (n.hasMoreElements()) {
+ InetAddress ina = n.nextElement();
+ byte[] adr = ina.getAddress();
+ if (adr.length != 4) {
+ // TODO: Support IPv6
+ // System.out.println("Dont support IPv6: " + ina);
+ continue;
+ }
+ /* Since we don't know actual broadcast address,
+ * lets try different combinations.
+ * Hopefully one of them will work.
+ */
+ int h = adr[0] & 0xff;
+ if (h >= 1 && h <= 127 && h != 38) {
+ adr[3] = (byte)255;
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[2] = (byte)255;
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[1] = (byte)255;
+ }
+ else if (h >= 128 && h <= 191) {
+ adr[3] = (byte)255;
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[2] = (byte)255;
+ }
+ else {
+ adr[3] = (byte)(adr[3] | 0x0f);
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[3] = (byte)(adr[3] | 0x01f);
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[3] = (byte)(adr[3] | 0x03f);
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[3] = (byte)(adr[3] | 0x07f);
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ adr[3] = (byte)255;
+ }
+ socket.send(new DatagramPacket(buf, buf.length,
+ InetAddress.getByAddress(null, adr), 1534));
+ }
+ }
+ }
+ catch (Exception x) {
+ Activator.log("Cannot send datagram packet", x);
+ }
+ }
+
+ private void handleDatagramPacket(DatagramPacket p) {
+ try {
+ byte[] buf = p.getData();
+ int len = p.getLength();
+ if (len < 8) return;
+ if (buf[0] != 'T') return;
+ if (buf[1] != 'C') return;
+ if (buf[2] != 'F') return;
+ if (buf[3] != '1') return;
+ switch (buf[4]) {
+ case CONF_PEER_INFO:
+ handlePeerInfoPacket(p);
+ break;
+ case CONF_REQ_INFO:
+ handleReqInfoPacket(p);
+ break;
+ }
+ }
+ catch (Throwable x) {
+ Activator.log("Invalid datagram packet received", x);
+ }
+ }
+
+ private void handlePeerInfoPacket(DatagramPacket p) throws Exception {
+ Map<String,String> map = new HashMap<String,String>();
+ String s = new String(p.getData(), 8, p.getLength() - 8, "UTF8");
+ int len = s.length();
+ int i = 0;
+ while (i < len) {
+ int i0 = i;
+ while (i < len && s.charAt(i) != '=' && s.charAt(i) != 0) i++;
+ int i1 = i;
+ if (i < len && s.charAt(i) == '=') i++;
+ int i2 = i;
+ while (i < len && s.charAt(i) != 0) i++;
+ int i3 = i;
+ if (i < len && s.charAt(i) == 0) i++;
+ String key = s.substring(i0, i1);
+ String val = s.substring(i2, i3);
+ map.put(key, val);
+ }
+ String id = map.get(IPeer.ATTR_ID);
+ if (id == null) throw new Exception("Invalid peer info: no ID");
+ IPeer peer = peers.get(id);
+ if (peer instanceof RemotePeer) {
+ if (((RemotePeer)peer).updateAttributes(map)) {
+ notifyPeer(peer);
+ }
+ }
+ else {
+ new RemotePeer(map);
+ }
+ }
+
+ private void handleReqInfoPacket(DatagramPacket p) {
+ byte[] buf = p.getData();
+ int len = p.getLength();
+ // TODO: handleReqInfoPacket()
+ }
+
+ /*----------------------------------------------------------------------------------*/
+
+ /*
+ * Return local instance of Locator service
+ */
+ public static LocatorService getLocator() {
+ return locator;
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#getName()
+ */
+ public String getName() {
+ return NAME;
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#getPeers()
+ */
+ public Map<String,IPeer> getPeers() {
+ return peers;
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#redirect()
+ */
+ public IToken redirect(String peer_id, DoneRedirect done) {
+ throw new Error("Channel redirect cannot be done on local peer");
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#sync()
+ */
+ public IToken sync(DoneSync done) {
+ throw new Error("Channel sync cannot be done on local peer");
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#addListener(com.windriver.tcf.api.protocol.ILocator.Listener)
+ */
+ public void addListener(LocatorListener listener) {
+ listeners.add(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see com.windriver.tcf.api.protocol.ILocator#removeListener(com.windriver.tcf.api.protocol.ILocator.Listener)
+ */
+ public void removeListener(LocatorListener listener) {
+ listeners.remove(listener);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/BreakpointsProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/BreakpointsProxy.java
new file mode 100644
index 000000000..475ff79fe
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/BreakpointsProxy.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.services.IBreakpoints;
+
+public class BreakpointsProxy implements IBreakpoints {
+
+ private final IChannel channel;
+ private final Map<BreakpointsListener,IChannel.IEventListener> listeners =
+ new HashMap<BreakpointsListener,IChannel.IEventListener>();
+
+ public BreakpointsProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public IToken set(Map<String, Object>[] properties, final DoneCommand done) {
+ return new Command(channel, this, "set", new Object[]{ properties }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken add(Map<String, Object> properties, final DoneCommand done) {
+ return new Command(channel, this, "add", new Object[]{ properties }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken change(Map<String, Object> properties, final DoneCommand done) {
+ return new Command(channel, this, "change", new Object[]{ properties }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken disable(String[] ids, final DoneCommand done) {
+ return new Command(channel, this, "disable", new Object[]{ ids }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken enable(String[] ids, final DoneCommand done) {
+ return new Command(channel, this, "enable", new Object[]{ ids }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken remove(String[] ids, final DoneCommand done) {
+ return new Command(channel, this, "remove", new Object[]{ ids }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken getIDs(final DoneGetIDs done) {
+ return new Command(channel, this, "getIDs", null) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray(args[2]);
+ }
+ done.doneGetIDs(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken getProperties(String id, final DoneGetProperties done) {
+ return new Command(channel, this, "getProperties", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ Map<String,Object> map = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ map = (Map<String,Object>)args[2];
+ }
+ done.doneGetProperties(token, error, map);
+ }
+ }.token;
+ }
+
+ public IToken getStatus(String id, final DoneGetStatus done) {
+ return new Command(channel, this, "getStatus", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ Map<String,Object> map = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ map = (Map<String,Object>)args[2];
+ }
+ done.doneGetStatus(token, error, map);
+ }
+ }.token;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ @SuppressWarnings("unchecked")
+ private String[] toStringArray(Object o) {
+ Collection<String> c = (Collection<String>)o;
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+
+ public void addListener(final BreakpointsListener listener) {
+ IChannel.IEventListener l = new IChannel.IEventListener() {
+
+ @SuppressWarnings("unchecked")
+ public void event(String name, byte[] data) {
+ try {
+ Object[] args = JSON.parseSequence(data);
+ if (name.equals("status")) {
+ assert args.length == 2;
+ listener.breakpointStatusChanged((String)args[0], (Map<String,Object>)args[1]);
+ }
+ else {
+ throw new IOException("Breakpoints service: unknown event: " + name);
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ };
+ channel.addEventListener(this, l);
+ listeners.put(listener, l);
+ }
+
+ public void removeListener(BreakpointsListener listener) {
+ IChannel.IEventListener l = listeners.get(listener);
+ if (l != null) channel.removeEventListener(this, l);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/DiagnosticsProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/DiagnosticsProxy.java
new file mode 100644
index 000000000..cafcb845e
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/DiagnosticsProxy.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote;
+
+import java.util.Collection;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IDiagnostics;
+
+public class DiagnosticsProxy implements IDiagnostics {
+
+ private final IChannel channel;
+
+ private static class Symbol implements ISymbol {
+
+ private final Map<String,Object> props;
+
+ Symbol(Map<String,Object> props) {
+ this.props = props;
+ }
+
+ public String getSectionName() {
+ return (String)props.get("Section");
+ }
+
+ public Number getValue() {
+ return (Number)props.get("Value");
+ }
+
+ public boolean isAbs() {
+ Boolean b = (Boolean)props.get("Abs");
+ return b != null && b.booleanValue();
+ }
+
+ public boolean isCommon() {
+ String s = (String)props.get("Storage");
+ return s != null && s.equals("COMMON");
+ }
+
+ public boolean isGlobal() {
+ String s = (String)props.get("Storage");
+ return s != null && s.equals("GLOBAL");
+ }
+
+ public boolean isLocal() {
+ String s = (String)props.get("Storage");
+ return s != null && s.equals("LOCAL");
+ }
+
+ public boolean isUndef() {
+ String s = (String)props.get("Storage");
+ return s != null && s.equals("UNDEF");
+ }
+ }
+
+ public DiagnosticsProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken echo(String s, final DoneEcho done) {
+ return new Command(channel, this, "echo", new Object[]{ s }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String str = null;
+ if (error == null) {
+ assert args.length == 1;
+ str = (String)args[0];
+ }
+ done.doneEcho(token, error, str);
+ }
+ }.token;
+ }
+
+ public IToken getTestList(final DoneGetTestList done) {
+ return new Command(channel, this, "getTestList", null) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray((Collection<String>)args[2]);
+ }
+ done.doneGetTestList(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken runTest(String s, final DoneRunTest done) {
+ return new Command(channel, this, "runTest", new Object[]{ s }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String str = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ str = (String)args[2];
+ }
+ done.doneRunTest(token, error, str);
+ }
+ }.token;
+ }
+
+ public IToken cancelTest(String s, final DoneCancelTest done) {
+ return new Command(channel, this, "cancelTest", new Object[]{ s }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCancelTest(token, error);
+ }
+ }.token;
+ }
+
+ public IToken getSymbol(String context_id, String symbol_name, final DoneGetSymbol done) {
+ return new Command(channel, this, "getSymbol", new Object[]{ context_id, symbol_name }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ ISymbol sym = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ sym = toSymbol(args[2]);
+ }
+ done.doneGetSymbol(token, error, sym);
+ }
+ }.token;
+ }
+
+ private String[] toStringArray(Collection<String> c) {
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+
+ @SuppressWarnings("unchecked")
+ private ISymbol toSymbol(Object o) {
+ if (o == null) return null;
+ return new Symbol((Map<String,Object>)o);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/FileSystemProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/FileSystemProxy.java
new file mode 100644
index 000000000..38d8678ef
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/FileSystemProxy.java
@@ -0,0 +1,582 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Base64;
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IFileSystem;
+
+public class FileSystemProxy implements IFileSystem {
+
+ private final class FileHandle implements IFileHandle {
+ final String id;
+
+ FileHandle(String id) {
+ this.id = id;
+ }
+
+ public IFileSystem getService() {
+ return FileSystemProxy.this;
+ }
+
+ public String toString() {
+ return "[File Handle '" + id + "']";
+ }
+ }
+
+ private static final class Status extends FileSystemException {
+
+ private static final long serialVersionUID = -1636567076145085980L;
+
+ private final int status;
+
+ Status(int status, String message) {
+ super(message);
+ this.status = status;
+ }
+
+ Status(Exception x) {
+ super(x);
+ this.status = STATUS_FAILURE;
+ }
+
+ public int getStatus() {
+ return status;
+ }
+ }
+
+ private abstract class FileSystemCommand extends Command {
+
+ FileSystemCommand(String command, Object[] args) {
+ super(channel, FileSystemProxy.this, command, args);
+ }
+
+ public Status toFSError(Object code, Object data) {
+ int error_code = ((Number)code).intValue();
+ if (error_code == 0) return null;
+ String cmd = getCommandString();
+ if (cmd.length() > 32) cmd = cmd.substring(0, 32) + "...";
+ return new Status(error_code,
+ "TCF command exception:" +
+ "\nCommand: " + cmd +
+ "\nException: " + toErrorString(data) +
+ "\nError code: " + code);
+ }
+ }
+
+ private final IChannel channel;
+
+ public FileSystemProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public IToken close(IFileHandle handle, final DoneClose done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ return new FileSystemCommand("close", new Object[]{ id }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneClose(token, s);
+ }
+ }.token;
+ }
+
+ public IToken setstat(String path, FileAttrs attrs, final DoneSetStat done) {
+ Object dt = toObject(attrs);
+ return new FileSystemCommand("setstat", new Object[]{ path, dt }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneSetStat(token, s);
+ }
+ }.token;
+ }
+
+ public IToken fsetstat(IFileHandle handle, FileAttrs attrs, final DoneSetStat done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ Object dt = toObject(attrs);
+ return new FileSystemCommand("fsetstat", new Object[]{ id, dt }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneSetStat(token, s);
+ }
+ }.token;
+ }
+
+ public IToken stat(String path, final DoneStat done) {
+ return new FileSystemCommand("stat", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ FileAttrs a = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ a = toFileAttrs(args[2]);
+ }
+ }
+ done.doneStat(token, s, a);
+ }
+ }.token;
+ }
+
+ public IToken fstat(IFileHandle handle, final DoneStat done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ return new FileSystemCommand("fstat", new Object[]{ id }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ FileAttrs a = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ a = toFileAttrs(args[2]);
+ }
+ }
+ done.doneStat(token, s, a);
+ }
+ }.token;
+ }
+
+ public IToken lstat(String path, final DoneStat done) {
+ return new FileSystemCommand("lstat", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ FileAttrs a = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ a = toFileAttrs(args[2]);
+ }
+ }
+ done.doneStat(token, s, a);
+ }
+ }.token;
+ }
+
+ public IToken mkdir(String path, FileAttrs attrs, final DoneMkDir done) {
+ Object dt = toObject(attrs);
+ return new FileSystemCommand("mkdir", new Object[]{ path, dt }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneMkDir(token, s);
+ }
+ }.token;
+ }
+
+ public IToken open(String file_name, int flags, FileAttrs attrs, final DoneOpen done) {
+ Object dt = toObject(attrs);
+ return new FileSystemCommand("open", new Object[]{ file_name, new Integer(flags), dt }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ FileHandle h = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ h = toFileHandle(args[2]);
+ }
+ }
+ done.doneOpen(token, s, h);
+ }
+ }.token;
+ }
+
+ public IToken opendir(String path, final DoneOpen done) {
+ return new FileSystemCommand("opendir", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ FileHandle h = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ h = toFileHandle(args[2]);
+ }
+ }
+ done.doneOpen(token, s, h);
+ }
+ }.token;
+ }
+
+ public IToken read(IFileHandle handle, long offset, int len, final DoneRead done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ return new FileSystemCommand("read", new Object[]{
+ id, Long.valueOf(offset), Integer.valueOf(len) }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ byte[] b = null;
+ boolean eof = false;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 4;
+ s = toFSError(args[1], args[2]);
+ if (s == null) {
+ String str = (String)args[0];
+ if (str != null) b = Base64.toByteArray(str.toCharArray());
+ eof = ((Boolean)args[3]).booleanValue();
+ }
+ }
+ done.doneRead(token, s, b, eof);
+ }
+ }.token;
+ }
+
+ public IToken readdir(IFileHandle handle, final DoneReadDir done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ return new FileSystemCommand("readdir", new Object[]{ id }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ DirEntry[] b = null;
+ boolean eof = false;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 4;
+ s = toFSError(args[1], args[2]);
+ if (s == null) {
+ b = toDirEntryArray(args[0]);
+ eof = ((Boolean)args[3]).booleanValue();
+ }
+ }
+ done.doneReadDir(token, s, b, eof);
+ }
+ }.token;
+ }
+
+ public IToken roots(final DoneRoots done) {
+ return new FileSystemCommand("roots", null) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ DirEntry[] b = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[1], args[2]);
+ if (s == null) {
+ b = toDirEntryArray(args[0]);
+ }
+ }
+ done.doneRoots(token, s, b);
+ }
+ }.token;
+ }
+
+ public IToken readlink(String path, final DoneReadLink done) {
+ return new FileSystemCommand("readlink", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ String p = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ p = (String)args[2];
+ }
+ }
+ done.doneReadLink(token, s, p);
+ }
+ }.token;
+ }
+
+ public IToken realpath(String path, final DoneRealPath done) {
+ return new FileSystemCommand("realpath", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ String p = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 3;
+ s = toFSError(args[0], args[1]);
+ if (s == null) {
+ p = (String)args[2];
+ }
+ }
+ done.doneRealPath(token, s, p);
+ }
+ }.token;
+ }
+
+ public IToken remove(String file_name, final DoneRemove done) {
+ return new FileSystemCommand("remove", new Object[]{ file_name }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneRemove(token, s);
+ }
+ }.token;
+ }
+
+ public IToken rename(String old_path, String new_path, final DoneRename done) {
+ return new FileSystemCommand("rename", new Object[]{ old_path, new_path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneRename(token, s);
+ }
+ }.token;
+ }
+
+ public IToken rmdir(String path, final DoneRemove done) {
+ return new FileSystemCommand("rmdir", new Object[]{ path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneRemove(token, s);
+ }
+ }.token;
+ }
+
+ public IToken symlink(String link_path, String target_path, final DoneSymLink done) {
+ return new FileSystemCommand("symlink", new Object[]{ link_path, target_path }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneSymLink(token, s);
+ }
+ }.token;
+ }
+
+ public IToken write(IFileHandle handle, long offset, byte[] data,
+ int data_pos, int data_size, final DoneWrite done) {
+ assert handle.getService() == this;
+ String id = ((FileHandle)handle).id;
+ return new FileSystemCommand("write", new Object[]{
+ id, Long.valueOf(offset), Base64.toBase64(data, data_pos, data_size) }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneWrite(token, s);
+ }
+ }.token;
+ }
+
+ public IToken copy(String src_path, String dst_path,
+ boolean copy_permissions, boolean copy_uidgid, final DoneCopy done) {
+ return new FileSystemCommand("copy", new Object[]{
+ src_path, dst_path, Boolean.valueOf(copy_permissions),
+ Boolean.valueOf(copy_uidgid) }) {
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 2;
+ s = toFSError(args[0], args[1]);
+ }
+ done.doneCopy(token, s);
+ }
+ }.token;
+ }
+
+ public IToken user(final DoneUser done) {
+ return new FileSystemCommand("user", null) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ Status s = null;
+ int r_uid = 0;
+ int e_uid = 0;
+ int r_gid = 0;
+ int e_gid = 0;
+ String home = null;
+ if (error != null) {
+ s = new Status(error);
+ }
+ else {
+ assert args.length == 5;
+ r_uid = ((Number)args[0]).intValue();
+ e_uid = ((Number)args[1]).intValue();
+ r_gid = ((Number)args[2]).intValue();
+ e_gid = ((Number)args[3]).intValue();
+ home = (String)args[4];
+ }
+ done.doneUser(token, s, r_uid, e_uid, r_gid, e_gid, home);
+ }
+ }.token;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ private Object toObject(FileAttrs attrs) {
+ if (attrs == null) return null;
+ Map<String,Object> m = new HashMap<String,Object>();
+ if (attrs.attributes != null) m.putAll(attrs.attributes);
+ if ((attrs.flags & ATTR_SIZE) != 0) {
+ m.put("Size", Long.valueOf(attrs.size));
+ }
+ if ((attrs.flags & ATTR_UIDGID) != 0) {
+ m.put("UID", Integer.valueOf(attrs.uid));
+ m.put("GID", Integer.valueOf(attrs.gid));
+ }
+ if ((attrs.flags & ATTR_PERMISSIONS) != 0) {
+ m.put("Permissions", Integer.valueOf(attrs.permissions));
+ }
+ if ((attrs.flags & ATTR_ACMODTIME) != 0) {
+ m.put("ATime", Long.valueOf(attrs.atime));
+ m.put("MTime", Long.valueOf(attrs.mtime));
+ }
+ return m;
+ }
+
+ @SuppressWarnings("unchecked")
+ private FileAttrs toFileAttrs(Object o) {
+ if (o == null) return null;
+ Map<String,Object> m = new HashMap<String,Object>((Map<String,Object>)o);
+ int flags = 0;
+ long size = 0;
+ int uid = 0;
+ int gid = 0;
+ int permissions = 0;
+ long atime = 0;
+ long mtime = 0;
+ Number n = (Number)m.remove("Size");
+ if (n != null) {
+ size = n.longValue();
+ flags |= ATTR_SIZE;
+ }
+ Number n1 = (Number)m.remove("UID");
+ Number n2 = (Number)m.remove("GID");
+ if (n1 != null && n2 != null) {
+ uid = n1.intValue();
+ gid = n2.intValue();
+ flags |= ATTR_UIDGID;
+ }
+ n = (Number)m.remove("Permissions");
+ if (n != null) {
+ permissions = n.intValue();
+ flags |= ATTR_PERMISSIONS;
+ }
+ n1 = (Number)m.remove("ATime");
+ n2 = (Number)m.remove("MTime");
+ if (n1 != null && n2 != null) {
+ atime = n1.longValue();
+ mtime = n2.longValue();
+ flags |= ATTR_ACMODTIME;
+ }
+ return new FileAttrs(flags, size, uid, gid, permissions, atime, mtime, m);
+ }
+
+ private FileHandle toFileHandle(Object o) {
+ if (o == null) return null;
+ return new FileHandle(o.toString());
+ }
+
+ @SuppressWarnings("unchecked")
+ private DirEntry[] toDirEntryArray(Object o) {
+ if (o == null) return null;
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ DirEntry[] res = new DirEntry[c.size()];
+ int i = 0;
+ for (Map<String,Object> m : c) {
+ res[i++] = new DirEntry(
+ (String)m.get("FileName"),
+ (String)m.get("LongName"),
+ toFileAttrs(m.get("Attrs")));
+ }
+ return res;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/GenericProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/GenericProxy.java
new file mode 100644
index 000000000..36293b5c2
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/GenericProxy.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote;
+
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IService;
+
+/**
+ * Objects of GenericProxy class represent remote services, which don't
+ * have a proxy class defined for them.
+ * Clients still can use such services, but framework will not provide
+ * service specific utility methods for message formatting and parsing.
+ */
+public class GenericProxy implements IService {
+
+ private final IChannel channel;
+ private final String name;
+
+ public GenericProxy(IChannel channel, String name) {
+ this.channel = channel;
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public IChannel getChannel() {
+ return channel;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LineNumbersProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LineNumbersProxy.java
new file mode 100644
index 000000000..51e32cd7f
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LineNumbersProxy.java
@@ -0,0 +1,79 @@
+package com.windriver.tcf.api.internal.services.remote;
+
+import java.util.Collection;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.ILineNumbers;
+
+public class LineNumbersProxy implements ILineNumbers {
+
+ private final IChannel channel;
+
+ public LineNumbersProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken mapToSource(String context_id, Number start_address,
+ Number end_address, final DoneMapToSource done) {
+ return new Command(channel, this, "mapToSource", new Object[]{ context_id,
+ start_address, end_address }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ CodeArea[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toTextAreaArray(args[2]);
+ }
+ done.doneMapToSource(token, error, arr);
+ }
+ }.token;
+ }
+
+ private static int getInteger(Map<String,Object> map, String name, int def) {
+ Number n = (Number)map.get(name);
+ if (n == null) return def;
+ return n.intValue();
+ }
+
+ private static String getString(Map<String,Object> map, String name, String def) {
+ String s = (String)map.get(name);
+ if (s == null) return def;
+ return s;
+ }
+
+ private static boolean getBoolean(Map<String,Object> map, String name) {
+ Boolean b = (Boolean)map.get(name);
+ if (b == null) return false;
+ return b.booleanValue();
+ }
+
+ @SuppressWarnings("unchecked")
+ private CodeArea[] toTextAreaArray(Object o) {
+ if (o == null) return null;
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ int n = 0;
+ CodeArea[] arr = new CodeArea[c.size()];
+ String directory = null;
+ String file = null;
+ for (Map<String,Object> area : c) {
+ directory = getString(area, "Dir", directory);
+ file = getString(area, "File", file);
+ arr[n++] = new CodeArea(directory, file,
+ getInteger(area, "SLine", 0), getInteger(area, "SCol", 0),
+ getInteger(area, "ELine", 0), getInteger(area, "ECol", 0),
+ (Number)area.get("SAddr"), (Number)area.get("EAddr"),
+ getInteger(area, "ISA", 0),
+ getBoolean(area, "IsStmt"), getBoolean(area, "BasicBlock"),
+ getBoolean(area, "PrologueEnd"), getBoolean(area, "EpilogueBegin"));
+ }
+ return arr;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LocatorProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LocatorProxy.java
new file mode 100644
index 000000000..91dccfb38
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/LocatorProxy.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.ILocator;
+
+public class LocatorProxy implements ILocator {
+
+ private final IChannel channel;
+ private final Map<String,IPeer> peers = new HashMap<String,IPeer>();
+ private final Collection<LocatorListener> listeners = new ArrayList<LocatorListener>();
+
+ private class Peer implements IPeer {
+
+ private final Map<String, String> attrs;
+
+ Peer(Map<String,String> attrs) {
+ this.attrs = attrs;
+ }
+
+ public Map<String, String> getAttributes() {
+ assert Protocol.isDispatchThread();
+ return attrs;
+ }
+
+ public String getID() {
+ assert Protocol.isDispatchThread();
+ return attrs.get(ATTR_ID);
+ }
+
+ public String getName() {
+ assert Protocol.isDispatchThread();
+ return attrs.get(ATTR_NAME);
+ }
+
+ public String getOSName() {
+ assert Protocol.isDispatchThread();
+ return attrs.get(ATTR_OS_NAME);
+ }
+
+ public String getTransportName() {
+ assert Protocol.isDispatchThread();
+ return attrs.get(ATTR_TRANSPORT_NAME);
+ }
+
+ public IChannel openChannel() {
+ assert Protocol.isDispatchThread();
+ IChannel c = channel.getRemotePeer().openChannel();
+ c.redirect(getID());
+ return c;
+ }
+ };
+
+ private final IChannel.IEventListener event_listener = new IChannel.IEventListener() {
+
+ @SuppressWarnings("unchecked")
+ public void event(String name, byte[] data) {
+ try {
+ Object[] args = JSON.parseSequence(data);
+ if (name.equals("peerAdded")) {
+ assert args.length == 1;
+ IPeer peer = new Peer((Map<String,String>)args[0]);
+ peers.put(peer.getID(), peer);
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext();) {
+ i.next().peerAdded(peer);
+ }
+ }
+ else if (name.equals("peerChanged")) {
+ assert args.length == 1;
+ Map<String,String> m = (Map<String,String>)args[0];
+ if (m == null) throw new Error("Locator service: invalid peerChanged event - no peer ID");
+ IPeer peer = peers.get(m.get(IPeer.ATTR_ID));
+ if (peer == null) throw new Error("Invalid peerChanged event: unknown peer ID");
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext();) {
+ i.next().peerChanged(peer);
+ }
+ }
+ else if (name.equals("peerRemoved")) {
+ assert args.length == 1;
+ String id = (String)args[0];
+ IPeer peer = peers.get(id);
+ if (peer == null) throw new Error("Locator service: invalid peerRemoved event - unknown peer ID");
+ for (Iterator<LocatorListener> i = listeners.iterator(); i.hasNext();) {
+ i.next().peerRemoved(id);
+ }
+ }
+ else {
+ throw new IOException("Locator service: unknown event: " + name);
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ };
+
+ public LocatorProxy(IChannel channel) {
+ this.channel = channel;
+ channel.addEventListener(this, event_listener);
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public Map<String,IPeer> getPeers() {
+ return peers;
+ }
+
+ public IToken redirect(String peer_id, final DoneRedirect done) {
+ return new Command(channel, this, "redirect", new Object[]{ peer_id }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneRedirect(token, error);
+ }
+ }.token;
+ }
+
+ public IToken sync(final DoneSync done) {
+ return new Command(channel, this, "sync", null) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error != null) channel.terminate(error);
+ done.doneSync(token);
+ }
+ }.token;
+ }
+
+ public void addListener(LocatorListener listener) {
+ listeners.add(listener);
+ }
+
+ public void removeListener(LocatorListener listener) {
+ listeners.remove(listener);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java
new file mode 100644
index 000000000..19b3e1aa4
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/MemoryProxy.java
@@ -0,0 +1,366 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Base64;
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.internal.core.ReadOnlyMap;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.services.IMemory;
+
+public class MemoryProxy implements IMemory {
+
+ private final IChannel channel;
+ private final Map<MemoryListener,IChannel.IEventListener> listeners =
+ new HashMap<MemoryListener,IChannel.IEventListener>();
+
+ private static class Range implements Comparable<Range> {
+ int offs;
+ int size;
+ int stat;
+ String msg;
+
+ public int compareTo(Range o) {
+ if (offs < o.offs) return -1;
+ if (offs > o.offs) return +1;
+ return 0;
+ }
+ }
+
+ private class MemoryErrorReport extends MemoryError implements ErrorOffset {
+
+ private static final long serialVersionUID = 796525409870265390L;
+ private final Range[] ranges;
+
+ @SuppressWarnings("unchecked")
+ MemoryErrorReport(String msg, Number addr, Object ranges) {
+ super(msg);
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)ranges;
+ this.ranges = new Range[c.size()];
+ int n = 0;
+ BigInteger addr_bi = addr instanceof BigInteger ?
+ (BigInteger)addr : new BigInteger(addr.toString());
+ for (Map<String,Object> m : c) {
+ Range r = new Range();
+ Number x = (Number)m.get("addr");
+ BigInteger y = x instanceof BigInteger ?
+ (BigInteger)x : new BigInteger(x.toString());
+ r.offs = addr_bi.subtract(y).intValue();
+ r.size = ((Number)m.get("size")).intValue();
+ r.stat = ((Number)m.get("stat")).intValue();
+ r.msg = Command.toErrorString(m.get("msg"));
+ assert r.offs >= 0;
+ assert r.size >= 0;
+ this.ranges[n++] = r;
+ }
+ Arrays.sort(this.ranges);
+ }
+
+ public String getMessage(int offset) {
+ int l = 0;
+ int h = ranges.length - 1;
+ while (l <= h) {
+ int n = (l + h) / 2;
+ Range r = ranges[n];
+ if (r.offs > offset) {
+ h = n - 1;
+ }
+ else if (offset >= r.offs + r.size) {
+ l = n + 1;
+ }
+ else {
+ return r.msg;
+ }
+ }
+ return null;
+ }
+
+ public int getStatus(int offset) {
+ int l = 0;
+ int h = ranges.length - 1;
+ while (l <= h) {
+ int n = (l + h) / 2;
+ Range r = ranges[n];
+ if (r.offs > offset) {
+ h = n - 1;
+ }
+ else if (offset >= r.offs + r.size) {
+ l = n + 1;
+ }
+ else {
+ return r.stat;
+ }
+ }
+ return BYTE_UNKNOWN;
+ }
+ }
+
+ private class MemContext implements MemoryContext {
+
+ private final Map<String,Object> props;
+
+ MemContext(Map<String,Object> props) {
+ assert props instanceof ReadOnlyMap;
+ this.props = props;
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getParentID() {
+ String s = (String)props.get(PROP_PARENT_ID);
+ if (s == null) return "";
+ return s;
+ }
+
+ public int getAddressSize() {
+ Number n = (Number)props.get(PROP_ADDRESS_SIZE);
+ if (n == null) return 0;
+ return n.intValue();
+ }
+
+ public int getProcessID() {
+ Number n = (Number)props.get(PROP_PROCESS_ID);
+ if (n == null) return 0;
+ return n.intValue();
+ }
+
+ public boolean isBigEndian() {
+ Boolean n = (Boolean)props.get(PROP_BIG_ENDIAN);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+
+ public IToken fill(final Number addr, int word_size,
+ byte[] value, int size, int mode, final DoneMemory done) {
+ return new MemoryCommand("fill", new Object[] {
+ getID(), addr, word_size, size, mode, value
+ } ) {
+ public void done(Exception error, Object[] args) {
+ MemoryError e = null;
+ if (error != null) {
+ e = new MemoryError(error.getMessage());
+ }
+ else {
+ assert args.length == 3;
+ e = toMemoryError(addr, args[0], args[1], args[2]);
+ }
+ done.doneMemory(token, e);
+ }
+ }.token;
+ }
+
+ public IToken get(final Number addr, int word_size,
+ final byte[] buf, final int offs, final int size,
+ int mode, final DoneMemory done) {
+ return new MemoryCommand("get", new Object[] {
+ getID(), addr, word_size, size, mode
+ } ) {
+ public void done(Exception error, Object[] args) {
+ MemoryError e = null;
+ if (error != null) {
+ e = new MemoryError(error.getMessage());
+ }
+ else {
+ assert args.length == 4;
+ String str = (String)args[0];
+ if (str != null) Base64.toByteArray(buf, offs, size, str.toCharArray());
+ e = toMemoryError(addr, args[1], args[2], args[3]);
+ }
+ done.doneMemory(token, e);
+ }
+ }.token;
+ }
+
+ public IToken set(final Number addr, int word_size,
+ byte[] buf, int offs, int size, int mode, final DoneMemory done) {
+ return new MemoryCommand("set", new Object[] {
+ getID(), addr, word_size, size, mode, Base64.toBase64(buf, offs, size)
+ } ) {
+ public void done(Exception error, Object[] args) {
+ MemoryError e = null;
+ if (error != null) {
+ e = new MemoryError(error.getMessage());
+ }
+ else {
+ assert args.length == 3;
+ e = toMemoryError(addr, args[0], args[1], args[2]);
+ }
+ done.doneMemory(token, e);
+ }
+ }.token;
+ }
+
+ public String toString() {
+ return "[Memory Context " + props.toString() + "]";
+ }
+ }
+
+ public MemoryProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public void addListener(final MemoryListener listener) {
+ IChannel.IEventListener l = new IChannel.IEventListener() {
+
+ public void event(String name, byte[] data) {
+ try {
+ Object[] args = JSON.parseSequence(data);
+ if (name.equals("contextAdded")) {
+ assert args.length == 1;
+ listener.contextAdded(toContextArray(args[0]));
+ }
+ else if (name.equals("contextChanged")) {
+ assert args.length == 1;
+ listener.contextChanged(toContextArray(args[0]));
+ }
+ else if (name.equals("contextRemoved")) {
+ assert args.length == 1;
+ listener.contextRemoved(toStringArray(args[0]));
+ }
+ else if (name.equals("memoryChanged")) {
+ assert args.length == 2;
+ listener.memoryChanged((String)args[0],
+ toAddrArray(args[1]), toSizeArray(args[1]));
+ }
+ else {
+ throw new IOException("Memory service: unknown event: " + name);
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ };
+ channel.addEventListener(this, l);
+ listeners.put(listener, l);
+ }
+
+ public void removeListener(MemoryListener listener) {
+ IChannel.IEventListener l = listeners.remove(listener);
+ if (l != null) channel.removeEventListener(this, l);
+ }
+
+ public IToken getContext(String context_id, final DoneGetContext done) {
+ return new Command(channel, this, "getContext", new Object[]{ context_id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ MemContext ctx = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new MemContext((Map<String,Object>)args[2]);
+ }
+ }
+ done.doneGetContext(token, error, ctx);
+ }
+ }.token;
+ }
+
+ public IToken getChildren(String parent_context_id, final DoneGetChildren done) {
+ return new Command(channel, this, "getChildren", new Object[]{ parent_context_id }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray(args[2]);
+ }
+ done.doneGetChildren(token, error, arr);
+ }
+ }.token;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ private abstract class MemoryCommand extends Command {
+
+ MemoryCommand(String cmd, Object[] args) {
+ super(channel, MemoryProxy.this, cmd, args);
+ }
+
+ MemoryError toMemoryError(Number addr, Object code, Object data, Object ranges) {
+ int error_code = ((Number)code).intValue();
+ if (error_code == 0) return null;
+ String cmd = getCommandString();
+ if (cmd.length() > 72) cmd = cmd.substring(0, 72) + "...";
+ return new MemoryErrorReport(
+ "TCF command exception:" +
+ "\nCommand: " + cmd +
+ "\nException: " + toErrorString(data) +
+ "\nError code: " + code, addr, ranges);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private MemoryContext[] toContextArray(Object o) {
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ if (c == null) return new MemoryContext[0];
+ int n = 0;
+ MemoryContext[] ctx = new MemoryContext[c.size()];
+ for (Iterator<Map<String,Object>> i = c.iterator(); i.hasNext();) {
+ ctx[n++] = new MemContext(i.next());
+ }
+ return ctx;
+ }
+
+ @SuppressWarnings("unchecked")
+ private long[] toSizeArray(Object o) {
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ if (c == null) return null;
+ long[] a = new long[c.size()];
+ int n = 0;
+ for (Map<String,Object> m : c) {
+ Number sz = (Number)m.get("size");
+ a[n++] = sz == null ? 0 : sz.longValue();
+ }
+ return a;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Number[] toAddrArray(Object o) {
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ if (c == null) return null;
+ Number[] a = new Number[c.size()];
+ int n = 0;
+ for (Map<String,Object> m : c) {
+ a[n++] = (Number)m.get("addr");
+ }
+ return a;
+ }
+
+ @SuppressWarnings("unchecked")
+ private String[] toStringArray(Object o) {
+ Collection<String> c = (Collection<String>)o;
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/ProcessesProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/ProcessesProxy.java
new file mode 100644
index 000000000..4db81a295
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/ProcessesProxy.java
@@ -0,0 +1,232 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IProcesses;
+
+public class ProcessesProxy implements IProcesses {
+
+ private final IChannel channel;
+
+ private class ProcessContext implements IProcesses.ProcessContext {
+
+ private final Map<String,Object> props;
+
+ ProcessContext(Map<String,Object> props) {
+ this.props = props;
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getParentID() {
+ return (String)props.get(PROP_PARENTID);
+ }
+
+ public boolean canTerminate() {
+ Boolean b = (Boolean)props.get(PROP_CAN_TERMINATE);
+ return b != null && b.booleanValue();
+ }
+
+ public String getName() {
+ return (String)props.get(PROP_NAME);
+ }
+
+ public boolean isAttached() {
+ Boolean b = (Boolean)props.get(PROP_ATTACHED);
+ return b != null && b.booleanValue();
+ }
+
+ public IToken attach(final DoneCommand done) {
+ return new Command(channel, ProcessesProxy.this,
+ "attach", new Object[]{ getID() }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken detach(final DoneCommand done) {
+ return new Command(channel, ProcessesProxy.this,
+ "detach", new Object[]{ getID() }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken signal(int signal, final DoneCommand done) {
+ return new Command(channel, ProcessesProxy.this,
+ "signal", new Object[]{ getID(), signal }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public IToken terminate(final DoneCommand done) {
+ return new Command(channel, ProcessesProxy.this,
+ "terminate", new Object[]{ getID() }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+
+ public String toString() {
+ return "[Processes Context " + props.toString() + "]";
+ }
+ }
+
+ public ProcessesProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken getChildren(String parent_context_id, boolean attached_only, final DoneGetChildren done) {
+ return new Command(channel, this,
+ "getChildren", new Object[]{ parent_context_id, attached_only }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] ids = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ ids = toStringArray(args[2]);
+ }
+ done.doneGetChildren(token, error, ids);
+ }
+ }.token;
+ }
+
+ public IToken getContext(String id, final DoneGetContext done) {
+ return new Command(channel, this,
+ "getContext", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ ProcessContext ctx = null;
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new ProcessContext((Map<String, Object>)args[2]);
+ }
+ }
+ done.doneGetContext(token, error, ctx);
+ }
+ }.token;
+ }
+
+ public IToken getEnvironment(final DoneGetEnvironment done) {
+ return new Command(channel, this, "getEnvironment", null) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ Map<String,String> env = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ env = toEnvMap(args[2]);
+ }
+ done.doneGetEnvironment(token, error, env);
+ }
+ }.token;
+ }
+
+ public IToken start(String directory, String file,
+ String[] command_line, Map<String,String> environment,
+ boolean attach, final DoneStart done) {
+ return new Command(channel, this,
+ "start", new Object[]{ directory, file, command_line,
+ toEnvStringArray(environment), attach }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ ProcessContext ctx = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new ProcessContext((Map<String, Object>)args[2]);
+ }
+ }
+ done.doneStart(token, error, ctx);
+ }
+ }.token;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static String[] toStringArray(Object o) {
+ if (o == null) return new String[0];
+ Collection<String> c = (Collection<String>)o;
+ return (String[])c.toArray(new String[c.size()]);
+ }
+
+ private static String[] toEnvStringArray(Map<String,String> m) {
+ if (m == null) return new String[0];
+ int n = 0;
+ String[] arr = new String[m.size()];
+ for (String s : m.keySet()) {
+ arr[n++] = s + "=" + m.get(s);
+ }
+ return arr;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static Map<String,String> toEnvMap(Object o) {
+ Map<String,String> m = new HashMap<String,String>();
+ if (o == null) return m;
+ Collection<String> c = (Collection<String>)o;
+ for (String s : c) {
+ int i = s.indexOf('=');
+ if (i >= 0) m.put(s.substring(0, i), s.substring(i + 1));
+ else m.put(s, "");
+ }
+ return m;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RegistersProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RegistersProxy.java
new file mode 100644
index 000000000..e313078ec
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RegistersProxy.java
@@ -0,0 +1,278 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.services.IRegisters;
+
+public class RegistersProxy implements IRegisters {
+
+ private final IChannel channel;
+ private final Map<RegistersListener,IChannel.IEventListener> listeners =
+ new HashMap<RegistersListener,IChannel.IEventListener>();
+
+ private class Context implements RegistersContext {
+
+ private final Map<String,Object> props;
+
+ Context(Map<String,Object> props) {
+ this.props = props;
+ }
+
+ public String[] getAvailableFormats() {
+ return toStringArray(props.get(PROP_FORMATS));
+ }
+
+ public int[] getBitNumbers() {
+ return toIntArray(props.get(PROP_BITS));
+ }
+
+ public String getDescription() {
+ return (String)props.get(PROP_DESCRIPTION);
+ }
+
+ public int getFirstBitNumber() {
+ Number n = (Number)props.get(PROP_FIST_BIT);
+ if (n == null) return 0;
+ return n.intValue();
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getName() {
+ return (String)props.get(PROP_NAME);
+ }
+
+ public NamedValue[] getNamedValues() {
+ return toValuesArray(props.get(PROP_VALUES));
+ }
+
+ public String getParentID() {
+ return (String)props.get(PROP_PARENT_ID);
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+
+ public boolean hasSideEffects() {
+ Boolean n = (Boolean)props.get(PROP_SIDE_EFFECTS);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isBigEndian() {
+ Boolean n = (Boolean)props.get(PROP_BIG_ENDIAN);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isFloat() {
+ Boolean n = (Boolean)props.get(PROP_FLOAT);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isLeftToRight() {
+ Boolean n = (Boolean)props.get(PROP_LEFT_TO_RIGHT);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isReadOnce() {
+ Boolean n = (Boolean)props.get(PROP_READ_ONCE);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isReadable() {
+ Boolean n = (Boolean)props.get(PROP_READBLE);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isVolatile() {
+ Boolean n = (Boolean)props.get(PROP_VOLATILE);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isWriteOnce() {
+ Boolean n = (Boolean)props.get(PROP_WRITE_ONCE);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public boolean isWriteable() {
+ Boolean n = (Boolean)props.get(PROP_WRITEABLE);
+ if (n == null) return false;
+ return n.booleanValue();
+ }
+
+ public IToken get(String format, final DoneGet done) {
+ return new Command(channel, RegistersProxy.this, "get",
+ new Object[]{ getID(), format }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String val = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ val = (String)args[2];
+ }
+ done.doneGet(token, error, val);
+ }
+ }.token;
+ }
+
+ public IToken set(String format, String value, final DoneSet done) {
+ return new Command(channel, RegistersProxy.this, "set",
+ new Object[]{ getID(), format, value }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneSet(token, error);
+ }
+ }.token;
+ }
+
+ public String toString() {
+ return "[Registers Context " + props.toString() + "]";
+ }
+ }
+
+ public RegistersProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken getChildren(String parent_context_id, final DoneGetChildren done) {
+ return new Command(channel, this, "getChildren", new Object[]{ parent_context_id }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray(args[2]);
+ }
+ done.doneGetChildren(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken getContext(String id, final DoneGetContext done) {
+ return new Command(channel, this, "getContext", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ Context ctx = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new Context((Map<String,Object>)args[2]);
+ }
+ }
+ done.doneGetContext(token, error, ctx);
+ }
+ }.token;
+ }
+
+ public void addListener(final RegistersListener listener) {
+ IChannel.IEventListener l = new IChannel.IEventListener() {
+
+ public void event(String name, byte[] data) {
+ try {
+ Object[] args = JSON.parseSequence(data);
+ if (name.equals("contextChanged")) {
+ listener.contextChanged();
+ }
+ else if (name.equals("registerChanged")) {
+ assert args.length == 1;
+ listener.registerChanged((String)args[0]);
+ }
+ else {
+ throw new IOException("Registers service: unknown event: " + name);
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ };
+ channel.addEventListener(this, l);
+ listeners.put(listener, l);
+ }
+
+ public void removeListener(RegistersListener listener) {
+ IChannel.IEventListener l = listeners.remove(listener);
+ if (l != null) channel.removeEventListener(this, l);
+ }
+
+ @SuppressWarnings("unchecked")
+ private String[] toStringArray(Object o) {
+ Collection<String> c = (Collection<String>)o;
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+
+ @SuppressWarnings("unchecked")
+ private int[] toIntArray(Object o) {
+ Collection<Number> c = (Collection<Number>)o;
+ if (c == null) return null;
+ int i = 0;
+ int[] arr = new int[c.size()];
+ for (Number n : c) arr[i++] = n.intValue();
+ return arr;
+ }
+
+ @SuppressWarnings("unchecked")
+ private NamedValue[] toValuesArray(Object o) {
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ if (c == null) return null;
+ int i = 0;
+ NamedValue[] arr = new NamedValue[c.size()];
+ for (final Map<String,Object> m : c) {
+ arr[i++] = new NamedValue() {
+
+ public String getDescription() {
+ return (String)m.get("Description");
+ }
+
+ public String getName() {
+ return (String)m.get("Name");
+ }
+
+ public Number getValue() {
+ return (Number)m.get("Value");
+ }
+ };
+ }
+ return arr;
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RunControlProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RunControlProxy.java
new file mode 100644
index 000000000..774a5e6ec
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/RunControlProxy.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.internal.core.ReadOnlyMap;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.JSON;
+import com.windriver.tcf.api.services.IRunControl;
+
+public class RunControlProxy implements IRunControl {
+
+ private final IChannel channel;
+ private final Map<RunControlListener,IChannel.IEventListener> listeners =
+ new HashMap<RunControlListener,IChannel.IEventListener>();
+
+ private class RunContext implements IRunControl.RunControlContext {
+
+ private final Map<String, Object> props;
+
+ RunContext(Map<String, Object> props) {
+ assert props instanceof ReadOnlyMap;
+ this.props = props;
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getParentID() {
+ String s = (String)props.get(PROP_PARENT_ID);
+ if (s == null) return "";
+ return s;
+ }
+
+ public boolean isContainer() {
+ Boolean b = (Boolean)props.get(PROP_IS_CONTAINER);
+ return b != null && b.booleanValue();
+ }
+
+ public boolean hasState() {
+ Boolean b = (Boolean)props.get(PROP_HAS_STATE);
+ return b != null && b.booleanValue();
+ }
+
+ public boolean canResume(int mode) {
+ if (props.containsKey(PROP_CAN_RESUME)) {
+ int b = ((Number)props.get(PROP_CAN_RESUME)).intValue();
+ return (b & (1 << mode)) != 0;
+ }
+ return false;
+ }
+
+ public boolean canCount(int mode) {
+ if (props.containsKey(PROP_CAN_COUNT)) {
+ int b = ((Number)props.get(PROP_CAN_COUNT)).intValue();
+ return (b & (1 << mode)) != 0;
+ }
+ return false;
+ }
+
+ public boolean canSuspend() {
+ Boolean b = (Boolean)props.get(PROP_CAN_SUSPEND);
+ return b != null && b.booleanValue();
+ }
+
+ public boolean canTerminate() {
+ Boolean b = (Boolean)props.get(PROP_CAN_TERMINATE);
+ return b != null && b.booleanValue();
+ }
+
+ public IToken getState(final DoneGetState done) {
+ return new Command(channel, RunControlProxy.this, "getState", new Object[]{ getID() }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ boolean susp = false;
+ String pc = null;
+ String reason = null;
+ Map<String,Object> map = null;
+ if (error == null) {
+ assert args.length == 6;
+ error = toError(args[0], args[1]);
+ susp = ((Boolean)args[2]).booleanValue();
+ if (args[3] != null) pc = ((Number)args[3]).toString();
+ reason = (String)args[4];
+ map = (Map<String,Object>)args[5];
+ }
+ done.doneGetState(token, error, susp, pc, reason, map);
+ }
+ }.token;
+ }
+
+ public IToken resume(int mode, int count, DoneCommand done) {
+ return command("resume", new Object[]{ getID(), mode, count }, done);
+ }
+
+ public IToken suspend(DoneCommand done) {
+ return command("suspend", new Object[]{ getID() }, done);
+ }
+
+ public IToken terminate(DoneCommand done) {
+ return command("terminate", new Object[]{ getID() }, done);
+ }
+
+ private IToken command(String cmd, Object[] args, final DoneCommand done) {
+ return new Command(channel, RunControlProxy.this, cmd, args) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ if (error == null) {
+ assert args.length == 2;
+ error = toError(args[0], args[1]);
+ }
+ done.doneCommand(token, error);
+ }
+ }.token;
+ }
+
+ public String toString() {
+ return "[Run Control Context " + props.toString() + "]";
+ }
+ }
+
+ public RunControlProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public void addListener(final RunControlListener listener) {
+ IChannel.IEventListener l = new IChannel.IEventListener() {
+
+ @SuppressWarnings("unchecked")
+ public void event(String name, byte[] data) {
+ try {
+ Object[] args = JSON.parseSequence(data);
+ if (name.equals("contextSuspended")) {
+ assert args.length == 4;
+ listener.contextSuspended(
+ (String)args[0],
+ args[1] == null ? null : ((Number)args[1]).toString(),
+ (String)args[2], (Map<String,Object>)args[3]);
+ }
+ else if (name.equals("contextResumed")) {
+ assert args.length == 1;
+ listener.contextResumed((String)args[0]);
+ }
+ else if (name.equals("contextAdded")) {
+ assert args.length == 1;
+ listener.contextAdded(toContextArray(args[0]));
+ }
+ else if (name.equals("contextChanged")) {
+ assert args.length == 1;
+ listener.contextChanged(toContextArray(args[0]));
+ }
+ else if (name.equals("contextRemoved")) {
+ assert args.length == 1;
+ listener.contextRemoved(toStringArray(args[0]));
+ }
+ else if (name.equals("contextException")) {
+ assert args.length == 2;
+ listener.contextException((String)args[0], (String)args[1]);
+ }
+ else if (name.equals("containerSuspended")) {
+ assert args.length == 5;
+ listener.containerSuspended(
+ (String)args[0],
+ args[1] == null ? null : ((Number)args[1]).toString(),
+ (String)args[2], (Map)args[3],
+ toStringArray(args[4]));
+ }
+ else if (name.equals("containerResumed")) {
+ assert args.length == 1;
+ listener.containerResumed(toStringArray(args[0]));
+ }
+ else {
+ throw new IOException("RunControl service: unknown event: " + name);
+ }
+ }
+ catch (Throwable x) {
+ channel.terminate(x);
+ }
+ }
+ };
+ channel.addEventListener(this, l);
+ listeners.put(listener, l);
+ }
+
+ public void removeListener(RunControlListener listener) {
+ IChannel.IEventListener l = listeners.remove(listener);
+ if (l != null) channel.removeEventListener(this, l);
+ }
+
+ public IToken getContext(String context_id, final DoneGetContext done) {
+ return new Command(channel, this, "getContext", new Object[]{ context_id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ RunControlContext ctx = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new RunContext((Map<String, Object>)args[2]);
+ }
+ }
+ done.doneGetContext(token, error, ctx);
+ }
+ }.token;
+ }
+
+ public IToken getChildren(String parent_context_id, final DoneGetChildren done) {
+ return new Command(channel, this, "getChildren", new Object[]{ parent_context_id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray(args[2]);
+ }
+ done.doneGetChildren(token, error, arr);
+ }
+ }.token;
+ }
+
+ @SuppressWarnings("unchecked")
+ private RunControlContext[] toContextArray(Object o) {
+ if (o == null) return null;
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ int n = 0;
+ RunControlContext[] ctx = new RunControlContext[c.size()];
+ for (Map<String, Object> m : c) ctx[n++] = new RunContext(m);
+ return ctx;
+ }
+
+ @SuppressWarnings("unchecked")
+ private String[] toStringArray(Object o) {
+ Collection<String> c = (Collection<String>)o;
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/StackTraceProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/StackTraceProxy.java
new file mode 100644
index 000000000..5385c5d1f
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/StackTraceProxy.java
@@ -0,0 +1,123 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote;
+
+import java.util.Collection;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IStackTrace;
+
+public class StackTraceProxy implements IStackTrace {
+
+ private final IChannel channel;
+
+ private class Context implements StackTraceContext {
+
+ private final Map<String,Object> props;
+
+ Context(Map<String,Object> props) {
+ this.props = props;
+ }
+
+ public Number getArgumentsAddress() {
+ return (Number)props.get(PROP_ARGUMENTS_ADDRESS);
+ }
+
+ public int getArgumentsCount() {
+ Number n = (Number)props.get(PROP_ARGUMENTS_COUNT);
+ if (n == null) return 0;
+ return n.intValue();
+ }
+
+ public Number getFrameAddress() {
+ return (Number)props.get(PROP_FRAME_ADDRESS);
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getName() {
+ return (String)props.get(PROP_NAME);
+ }
+
+ public String getParentID() {
+ return (String)props.get(PROP_PARENT_ID);
+ }
+
+ public Number getReturnAddress() {
+ return (Number)props.get(PROP_RETURN_ADDRESS);
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+ }
+
+ public StackTraceProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public IToken getChildren(String parent_context_id, final DoneGetChildren done) {
+ return new Command(channel, this, "getChildren", new Object[]{ parent_context_id }) {
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray(args[2]);
+ }
+ done.doneGetChildren(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken getContext(String[] id, final DoneGetContext done) {
+ return new Command(channel, this, "getContext", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ StackTraceContext[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[1], args[2]);
+ arr = toContextArray(args[0]);
+ }
+ done.doneGetContext(token, error, arr);
+ }
+ }.token;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ @SuppressWarnings("unchecked")
+ private StackTraceContext[] toContextArray(Object o) {
+ if (o == null) return null;
+ Collection<Map<String,Object>> c = (Collection<Map<String,Object>>)o;
+ int n = 0;
+ StackTraceContext[] ctx = new StackTraceContext[c.size()];
+ for (Map<String,Object> m : c) ctx[n++] = new Context(m);
+ return ctx;
+ }
+
+ @SuppressWarnings("unchecked")
+ private String[] toStringArray(Object o) {
+ Collection<String> c = (Collection<String>)o;
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/SysMonitorProxy.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/SysMonitorProxy.java
new file mode 100644
index 000000000..6e4648bc8
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/internal/services/remote/SysMonitorProxy.java
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.internal.services.remote;
+
+import java.util.Collection;
+import java.util.Map;
+
+import com.windriver.tcf.api.core.Command;
+import com.windriver.tcf.api.internal.core.ReadOnlyMap;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.ISysMonitor;
+
+public class SysMonitorProxy implements ISysMonitor {
+
+ private final IChannel channel;
+
+ private class SysMonitorContext implements ISysMonitor.SysMonitorContext {
+
+ private final Map<String, Object> props;
+
+ SysMonitorContext(Map<String, Object> props) {
+ assert props instanceof ReadOnlyMap;
+ this.props = props;
+ }
+
+ public String getID() {
+ return (String)props.get(PROP_ID);
+ }
+
+ public String getCurrentWorkingDirectory() {
+ return (String)props.get(PROP_CWD);
+ }
+
+ public String getFile() {
+ return (String)props.get(PROP_FILE);
+ }
+
+ public String getParentID() {
+ return (String)props.get(PROP_PARENTID);
+ }
+
+ public String getRoot() {
+ return (String)props.get(PROP_ROOT);
+ }
+
+ public String getGroupName() {
+ return (String)props.get(PROP_GROUPNAME);
+ }
+
+ public long getPGRP() {
+ if (!props.containsKey(PROP_PGRP)) return -1;
+ return ((Number)props.get(PROP_PGRP)).longValue();
+ }
+
+ public long getPID() {
+ if (!props.containsKey(PROP_PID)) return -1;
+ return ((Number)props.get(PROP_PID)).longValue();
+ }
+
+ public long getPPID() {
+ if (!props.containsKey(PROP_PPID)) return -1;
+ return ((Number)props.get(PROP_PPID)).longValue();
+ }
+
+ public long getRSS() {
+ if (!props.containsKey(PROP_RSS)) return -1;
+ return ((Number)props.get(PROP_RSS)).longValue();
+ }
+
+ public String getState() {
+ return (String)props.get(PROP_STATE);
+ }
+
+ public long getTGID() {
+ if (!props.containsKey(PROP_TGID)) return -1;
+ return ((Number)props.get(PROP_TGID)).longValue();
+ }
+
+ public long getTracerPID() {
+ if (!props.containsKey(PROP_TRACERPID)) return -1;
+ return ((Number)props.get(PROP_TRACERPID)).longValue();
+ }
+
+ public long getUGID() {
+ if (!props.containsKey(PROP_UGID)) return -1;
+ return ((Number)props.get(PROP_UGID)).longValue();
+ }
+
+ public long getUID() {
+ if (!props.containsKey(PROP_UID)) return -1;
+ return ((Number)props.get(PROP_UID)).longValue();
+ }
+
+ public String getUserName() {
+ return (String)props.get(PROP_USERNAME);
+ }
+
+ public long getVSize() {
+ if (!props.containsKey(PROP_VSIZE)) return -1;
+ return ((Number)props.get(PROP_VSIZE)).longValue();
+ }
+
+ public long getPSize() {
+ if (!props.containsKey(PROP_PSIZE)) return -1;
+ return ((Number)props.get(PROP_PSIZE)).longValue();
+ }
+
+ public Map<String, Object> getProperties() {
+ return props;
+ }
+
+ public String toString() {
+ return "[Sys Monitor Context " + props.toString() + "]";
+ }
+ }
+
+ public SysMonitorProxy(IChannel channel) {
+ this.channel = channel;
+ }
+
+ public String getName() {
+ return NAME;
+ }
+
+ public IToken getChildren(String parent_context_id, final DoneGetChildren done) {
+ return new Command(channel, this, "getChildren", new Object[]{ parent_context_id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray((Collection<String>)args[2]);
+ }
+ done.doneGetChildren(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken getContext(String id, final DoneGetContext done) {
+ return new Command(channel, this, "getContext", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ SysMonitorContext ctx = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ if (args[2] != null) {
+ ctx = new SysMonitorContext((Map<String, Object>)args[2]);
+ }
+ }
+ done.doneGetContext(token, error, ctx);
+ }
+ }.token;
+ }
+
+ public IToken getCommandLine(String id, final DoneGetCommandLine done) {
+ return new Command(channel, this, "getCommandLine", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray((Collection<String>)args[2]);
+ }
+ done.doneGetCommandLine(token, error, arr);
+ }
+ }.token;
+ }
+
+ public IToken getEnvironment(String id, final DoneGetEnvironment done) {
+ return new Command(channel, this, "getEnvironment", new Object[]{ id }) {
+ @SuppressWarnings("unchecked")
+ @Override
+ public void done(Exception error, Object[] args) {
+ String[] arr = null;
+ if (error == null) {
+ assert args.length == 3;
+ error = toError(args[0], args[1]);
+ arr = toStringArray((Collection<String>)args[2]);
+ }
+ done.doneGetEnvironment(token, error, arr);
+ }
+ }.token;
+ }
+
+ private static String[] toStringArray(Collection<String> c) {
+ if (c == null) return new String[0];
+ return (String[])c.toArray(new String[c.size()]);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IChannel.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IChannel.java
new file mode 100644
index 000000000..4b15660b8
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IChannel.java
@@ -0,0 +1,261 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.protocol;
+
+import java.util.Collection;
+
+/**
+ * IChannel represents communication link connecting two end points (peers).
+ * The channel asynchronously transmits messages: commands, results and events.
+ * A single channel may be used to communicate with multiple services.
+ * Multiple channels may be used to connect the same peers, however no command or event
+ * ordering is guaranteed across channels.
+ */
+
+public interface IChannel {
+
+ /**
+ * Channel state IDs
+ */
+ static final int
+ STATE_OPENNING = 0,
+ STATE_OPEN = 1,
+ STATE_CLOSED = 2;
+
+ /**
+ * @return channel state, see STATE_*
+ */
+ int getState();
+
+ /**
+ * Send command message to remote peer for execution. Commands can be queued
+ * locally before transmission. Sending commands too fast can fill up
+ * communication channel buffers. Calling thread will be blocked until
+ * enough buffer space is freed up by transmitting pending messages.
+ * @param service - a remote service that will be sent the command
+ * @param name - command name
+ * @param args - command arguments encoded into array of bytes
+ * @param done - call back object
+ * @return pending command handle
+ */
+ IToken sendCommand(IService service, String name, byte[] args, ICommandListener done);
+
+ /**
+ * Command listener interface. Clients implement this interface to
+ * receive command results.
+ */
+ interface ICommandListener {
+
+ /**
+ * Called when progress message (intermediate result) is received
+ * from remote peer.
+ * @param token - command handle
+ * @param data - progress message arguments encoded into array of bytes
+ */
+ void progress(IToken token, byte[] data);
+
+ /**
+ * Called when command result received from remote peer.
+ * @param token - command handle
+ * @param data - command result message arguments encoded into array of bytes
+ */
+ void result(IToken token, byte[] data);
+
+ /**
+ * Called when communication channel was closed while command was waiting for result.
+ * @param token - command handle
+ * @param error - exception that forced the channel to close
+ */
+ void terminated(IToken token, Exception error);
+ }
+
+ /**
+ * Send result message to remote peer. Messages can be queued locally before
+ * transmission. Sending messages too fast can fill up communication channel
+ * buffers. Calling thread will be blocked until enough buffer space is
+ * freed up by transmitting pending messages.
+ * @param token - command handle
+ * @param results - result message arguments encoded into array of bytes
+ */
+ void sendResult(IToken token, byte[] results);
+
+ /**
+ * Get current level of outbound traffic congestion.
+ *
+ * @return integer value in range –100..100, where –100 means no pending
+ * messages (no traffic), 0 means optimal load, and positive numbers
+ * indicate level of congestion.
+ *
+ * Note: inbound traffic congestion is detected by framework and reported to
+ * remote peer without client needed to be involved.
+ */
+ int getCongestion();
+
+ /**
+ * Channel listener interface.
+ */
+ interface IChannelListener {
+
+ /**
+ * Called when a channel is opened.
+ */
+ void onChannelOpened();
+
+ /**
+ * Called when channel closed. If it is closed because of an error,
+ * ‘error’ parameter will describe the error. ‘error’ is null if channel
+ * is closed normally by calling Channel.close().
+ * @param error - channel exception or null
+ */
+ void onChannelClosed(Throwable error);
+
+ /**
+ * Notifies listeners about channel congestion level changes.
+ * When level > 0 client should delay sending more messages.
+ * @param level - current congestion level
+ */
+ void congestionLevel(int level);
+ }
+
+ /**
+ * Subscribe a channel listener. The listener will be notified about changes of
+ * channel state and changes of outbound traffic congestion level.
+ * @param listener - channel listener implementation
+ */
+ void addChannelListener(IChannelListener listener);
+
+ /**
+ * Remove a channel listener.
+ * @param listener - channel listener implementation
+ */
+ void removeChannelListener(IChannelListener listener);
+
+ /**
+ * Command server interface.
+ * This interface is to be implemented by service providers.
+ */
+ interface ICommandServer {
+
+ /**
+ * Called every time a command is received from remote peer.
+ * @param token - command handle
+ * @param name - command name
+ * @param data - command arguments encoded into array of bytes
+ */
+ void command(IToken token, String name, byte[] data);
+ }
+
+ /**
+ * Subscribe a command server. The server will be notified about command
+ * messages received through this channel for given service.
+ * @param service - local service implementation
+ * @param server - implementation of service commands listener
+ */
+ void addCommandServer(IService service, ICommandServer server);
+
+ /**
+ * Remove a command server.
+ * @param service - local service implementation
+ * @param server - implementation of service commands listener
+ */
+ void removeCommandServer(IService service, ICommandServer server);
+
+ /**
+ * A generic interface for service event listener.
+ * Services usually define a service specific event listener interface.
+ * Clients should user service specific listener interface, unless no such interface is defined.
+ */
+ interface IEventListener {
+ /**
+ * Called when service event message is received
+ * @param name - event name
+ * @param data - event arguments encode as array of bytes
+ */
+ void event(String name, byte[] data);
+ }
+
+ /**
+ * Subscribe an event listener for given service.
+ * @param service - remote service proxy
+ * @param server - implementation of service event listener
+ */
+ void addEventListener(IService service, IEventListener listener);
+
+ /**
+ * Unsubscribe an event listener for given service.
+ * @param service - remote service proxy
+ * @param server - implementation of service event listener
+ */
+ void removeEventListener(IService service, IEventListener listener);
+
+ /**
+ * @return IPeer object representing local endpoint of communication channel.
+ */
+ IPeer getLocalPeer();
+
+ /**
+ * @return IPeer object representing remote endpoint of communication channel.
+ */
+ IPeer getRemotePeer();
+
+ /**
+ * @return collection of services available on local peer.
+ */
+ Collection<String> getLocalServices();
+
+ /**
+ * @return an object representing a service from local peer.
+ * Return null if the service is not available.
+ */
+ IService getLocalService(String service_name);
+
+ /**
+ * @return an object representing a service from local peer.
+ * Service object should implement given interface.
+ * Return null if implementation of the interface is not available.
+ */
+ <V extends IService> V getLocalService(Class<V> service_interface);
+
+ /**
+ * @return collection of services available on remote peer.
+ */
+ Collection<String> getRemoteServices();
+
+ /**
+ * @return an object representing a service from remote peer.
+ * Return null if the service is not available.
+ */
+ IService getRemoteService(String service_name);
+
+ /**
+ * @return an object representing a service from remote peer.
+ * Service object should implement given interface.
+ * Return null if implementation of the interface is not available.
+ */
+ <V extends IService> V getRemoteService(Class<V> service_interface);
+
+ /**
+ * Close communication channel.
+ */
+ void close();
+
+ /**
+ * Close channel in case of communication error.
+ * @param error - cause of channel termination
+ */
+ void terminate(Throwable error);
+
+ /**
+ * Redirect this channel to given peer using this channel remote peer locator service as a proxy.
+ * @param peer_id - peer that will become new remote communication endpoint of this channel
+ */
+ void redirect(String peer_id);
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IEventQueue.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IEventQueue.java
new file mode 100644
index 000000000..0ace6e635
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IEventQueue.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.protocol;
+
+/**
+ * Clients of the framework should implement this interface and call Protocol.setEventQueue.
+ * Implementation should encapsulate a queue and asynchronous event dispatch machinery, which
+ * extracts events from the queue and dispatches them by calling event's run() method.
+ * The implementation is used by framework to queue and dispatch all events.
+ */
+public interface IEventQueue {
+
+ /**
+ * Causes <code>runnable</code> to have its <code>run</code>
+ * method called in the dispatch thread of this event queue.
+ * Events are dispatched in same order as queued.
+ *
+ * @param runnable the <code>Runnable</code> whose <code>run</code>
+ * method should be executed asynchronously.
+ */
+ void invokeLater(Runnable runnable);
+
+ /**
+ * Returns true if the calling thread is this event queue's dispatch thread.
+ * Use this call the ensure that a given task is being executed (or not being) on dispatch thread.
+ *
+ * @return true if running on the dispatch thread.
+ */
+ boolean isDispatchThread();
+
+ /**
+ * Get current level of queue congestion.
+ *
+ * @return integer value in range –100..100, where –100 means no pending
+ * messages (no traffic), 0 means optimal load, and positive numbers
+ * indicate level of congestion.
+ */
+ public int getCongestion();
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IPeer.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IPeer.java
new file mode 100644
index 000000000..7abc75e2c
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IPeer.java
@@ -0,0 +1,70 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.protocol;
+
+import java.util.Map;
+
+/**
+ * Both hosts and targets are represented by objects
+ * implementing IPeer interface. A peer can act as host or
+ * target depending on services it implements.
+ * List of currently known peers can be retrieved by
+ * calling ILocator.getPeers()
+ */
+public interface IPeer {
+
+ /**
+ * Peer property names. Implementation can define additional properties.
+ */
+ static final String
+ ATTR_ID = "ID",
+ ATTR_NAME = "Name",
+ ATTR_OS_NAME = "OSName",
+ ATTR_TRANSPORT_NAME = "TransportName",
+ ATTR_IP_HOST = "Host",
+ ATTR_IP_ALIASES = "Aliases",
+ ATTR_IP_ADDRESSES = "Addresses",
+ ATTR_IP_PORT = "Port";
+
+
+ /**
+ * @return map of peer attributes
+ */
+ Map<String, String> getAttributes();
+
+ /**
+ * @return peer unique ID, same as getAttributes().get(ATTR_ID)
+ */
+ String getID();
+
+ /**
+ * @return peer name, same as getAttributes().get(ATTR_NAME)
+ */
+ String getName();
+
+ /**
+ * Same as getAttributes().get(ATTR_OS_NAME)
+ */
+ String getOSName();
+
+ /**
+ * Same as getAttributes().get(ATTR_TRANSPORT_NAME)
+ */
+ String getTransportName();
+
+ /**
+ * Open channel to communicate with this peer.
+ * Note: the channel is not fully open yet when this method returns.
+ * It’s state is IChannel.STATE_OPENNING.
+ * Protocol.Listener will be called when the channel will be opened or closed.
+ */
+ IChannel openChannel();
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IService.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IService.java
new file mode 100644
index 000000000..d6eb3d4f1
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IService.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.protocol;
+
+/**
+ * Base interface for all service interfaces. A client can get list of available services
+ * by calling Peer.getServices()
+ */
+
+public interface IService {
+
+ /**
+ * Get unique name of this service.
+ * @return service name.
+ */
+ String getName();
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IToken.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IToken.java
new file mode 100644
index 000000000..b42645107
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/IToken.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.protocol;
+
+/**
+ * IToken is created by the framework for each command sent to a remote peer.
+ * It is used to match results to commands and to cancel pending commands.
+ */
+public interface IToken {
+
+ /**
+ * Try to cancel a command associated with given token. A command can be
+ * canceled by this method only if it was not transmitted yet to remote peer
+ * for execution. Successfully canceled command does not produce any result
+ * messages.
+ *
+ * @return true if successful.
+ */
+ boolean cancel();
+
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java
new file mode 100644
index 000000000..16fdcb5e8
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/JSON.java
@@ -0,0 +1,516 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.protocol;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import com.windriver.tcf.api.internal.core.ReadOnlyCollection;
+import com.windriver.tcf.api.internal.core.ReadOnlyMap;
+
+/**
+ * JSON is TCF preferred marshaling. This class implements generation and parsing of JSON strings.
+ * The code is optimized for speed since it is a time-critical part of the framework.
+ */
+public class JSON {
+
+ private static char[] tmp_buf = new char[0x1000];
+ private static byte[] tmp_bbf = new byte[0x1000];
+ private static int tmp_buf_pos;
+
+ private static Reader reader;
+ private static final char[] cur_buf = new char[0x1000];
+ private static int cur_buf_pos;
+ private static int cur_buf_len;
+ private static int cur_ch;
+
+ // This buffer is used to create nice error reports
+ private static final char[] err_buf = new char[100];
+ private static int err_buf_pos;
+ private static int err_buf_cnt;
+
+ private static void write(char ch) {
+ if (tmp_buf_pos >= tmp_buf.length) {
+ char[] tmp = new char[tmp_buf.length * 2];
+ System.arraycopy(tmp_buf, 0, tmp, 0, tmp_buf_pos);
+ tmp_buf = tmp;
+ }
+ tmp_buf[tmp_buf_pos++] = ch;
+ }
+
+ private static void write(String s) {
+ int l = s.length();
+ for (int i = 0; i < l; i++) {
+ char ch = s.charAt(i);
+ if (tmp_buf_pos >= tmp_buf.length) write(ch);
+ else tmp_buf[tmp_buf_pos++] = ch;
+ }
+ }
+
+ private static void writeUInt(int n) {
+ assert n >= 0;
+ if (n >= 10) writeUInt(n / 10);
+ write((char)('0' + n % 10));
+ }
+
+ private static void read() throws IOException {
+ if (cur_buf_pos >= cur_buf_len) {
+ cur_buf_len = reader.read(cur_buf);
+ cur_buf_pos = 0;
+ if (cur_buf_len < 0) {
+ cur_buf_len = 0;
+ cur_ch = -1;
+ return;
+ }
+ }
+ cur_ch = cur_buf[cur_buf_pos++];
+ err_buf[err_buf_pos++] = (char)cur_ch;
+ if (err_buf_pos >= err_buf.length) {
+ err_buf_pos = 0;
+ err_buf_cnt++;
+ }
+ }
+
+ private static void error() throws IOException {
+ error("syntax error");
+ }
+
+ private static void error(String msg) throws IOException {
+ StringBuffer bf = new StringBuffer();
+ bf.append("JSON " + msg + ":");
+ int cnt = 0;
+ boolean nl = true;
+ for (int i = 0;; i++) {
+ char ch = 0;
+ if (err_buf_cnt == 0 && i < err_buf_pos) {
+ ch = err_buf[i];
+ }
+ else if (err_buf_cnt > 0 && i < err_buf.length) {
+ ch = err_buf[(err_buf_pos + i) % err_buf.length];
+ }
+ else {
+ int n = reader.read();
+ if (n < 0) break;
+ ch = (char)n;
+ }
+ if (nl) {
+ bf.append("\n ");
+ if (err_buf_cnt == 0) bf.append(cnt);
+ else bf.append('*');
+ bf.append(": ");
+ if (cnt == 0 && err_buf_cnt > 0) bf.append("...");
+ nl = false;
+ }
+ if (ch == 0) {
+ cnt++;
+ nl = true;
+ continue;
+ }
+ bf.append(ch);
+ }
+ throw new IOException(bf.toString());
+ }
+
+ private static int readHexDigit() throws IOException {
+ int n = 0;
+ if (cur_ch >= '0' && cur_ch <= '9') n = cur_ch - '0';
+ else if (cur_ch >= 'A' && cur_ch <= 'F') n = cur_ch - 'A' + 10;
+ else if (cur_ch >= 'a' && cur_ch <= 'f') n = cur_ch - 'a' + 10;
+ else error();
+ read();
+ return n;
+ }
+
+ private static Object readNestedObject() throws IOException {
+ switch (cur_ch) {
+ case '"':
+ read();
+ tmp_buf_pos = 0;
+ for (;;) {
+ if (cur_ch <= 0) error();
+ if (cur_ch == '"') break;
+ if (cur_ch == '\\') {
+ read();
+ if (cur_ch <= 0) error();
+ switch (cur_ch) {
+ case '"':
+ case '\\':
+ case '/':
+ break;
+ case 'b':
+ cur_ch = '\b';
+ break;
+ case 'f':
+ cur_ch = '\f';
+ break;
+ case 'n':
+ cur_ch = '\n';
+ break;
+ case 'r':
+ cur_ch = '\r';
+ break;
+ case 't':
+ cur_ch = '\t';
+ break;
+ case 'u':
+ read();
+ int n = 0;
+ n |= readHexDigit() << 12;
+ n |= readHexDigit() << 8;
+ n |= readHexDigit() << 4;
+ n |= readHexDigit();
+ write((char)n);
+ continue;
+ default:
+ error();
+ break;
+ }
+ }
+ if (tmp_buf_pos >= tmp_buf.length) {
+ write((char)cur_ch);
+ }
+ else {
+ tmp_buf[tmp_buf_pos++] = (char)cur_ch;
+ }
+ if (cur_buf_pos >= cur_buf_len) {
+ read();
+ }
+ else {
+ cur_ch = cur_buf[cur_buf_pos++];
+ err_buf[err_buf_pos++] = (char)cur_ch;
+ if (err_buf_pos >= err_buf.length) {
+ err_buf_pos = 0;
+ err_buf_cnt++;
+ }
+ }
+ }
+ read();
+ return new String(tmp_buf, 0, tmp_buf_pos);
+ case '[':
+ Collection<Object> l = new ArrayList<Object>();
+ read();
+ if (cur_ch <= 0) error();
+ if (cur_ch != ']') {
+ for (;;) {
+ l.add(readNestedObject());
+ if (cur_ch == ']') break;
+ if (cur_ch != ',') error();
+ read();
+ }
+ }
+ read();
+ return new ReadOnlyCollection<Object>(l);
+ case '{':
+ Map<String,Object> m = new HashMap<String,Object>();
+ read();
+ if (cur_ch <= 0) error();
+ if (cur_ch != '}') {
+ for (;;) {
+ String key = (String)readNestedObject();
+ if (cur_ch != ':') error();
+ read();
+ Object val = readNestedObject();
+ m.put(key, val);
+ if (cur_ch == '}') break;
+ if (cur_ch != ',') error();
+ read();
+ }
+ }
+ read();
+ return new ReadOnlyMap<String,Object>(m);
+ case 'n':
+ read();
+ if (cur_ch != 'u') error();
+ read();
+ if (cur_ch != 'l') error();
+ read();
+ if (cur_ch != 'l') error();
+ read();
+ return null;
+ case 'f':
+ read();
+ if (cur_ch != 'a') error();
+ read();
+ if (cur_ch != 'l') error();
+ read();
+ if (cur_ch != 's') error();
+ read();
+ if (cur_ch != 'e') error();
+ read();
+ return Boolean.FALSE;
+ case 't':
+ read();
+ if (cur_ch != 'r') error();
+ read();
+ if (cur_ch != 'u') error();
+ read();
+ if (cur_ch != 'e') error();
+ read();
+ return Boolean.TRUE;
+ default:
+ boolean neg = cur_ch == '-';
+ if (neg) read();
+ if (cur_ch >= '0' && cur_ch <= '9') {
+ // TODO: float number
+ int v = 0;
+ while (v <= 0x7fffffff / 10 - 1) {
+ v = v * 10 + (cur_ch - '0');
+ read();
+ if (cur_ch < '0' || cur_ch > '9') {
+ return new Integer(neg ? -v : v);
+ }
+ }
+ long vl = v;
+ while (vl < 0x7fffffffffffffffl / 10 - 1) {
+ vl = vl * 10 + (cur_ch - '0');
+ read();
+ if (cur_ch < '0' || cur_ch > '9') {
+ return new Long(neg ? -vl : vl);
+ }
+ }
+ StringBuffer sb = new StringBuffer();
+ if (neg) sb.append('-');
+ sb.append(vl);
+ while (true) {
+ sb.append(cur_ch);
+ read();
+ if (cur_ch < '0' || cur_ch > '9') {
+ return new BigInteger(sb.toString());
+ }
+ }
+ }
+ error();
+ return null;
+ }
+ }
+
+ private static Object readObject() throws IOException {
+ Object o = readNestedObject();
+ if (cur_ch >= 0) error();
+ return o;
+ }
+
+ private static Object[] readSequence() throws IOException {
+ List<Object> l = new ArrayList<Object>();
+ while (cur_ch >= 0) {
+ l.add(readNestedObject());
+ if (cur_ch != 0) error("missing \\0 terminator");
+ read();
+ }
+ return l.toArray();
+ }
+
+ @SuppressWarnings("unchecked")
+ private static void writeObject(Object o) throws IOException {
+ if (o == null) {
+ write("null");
+ }
+ else if (o instanceof Boolean) {
+ write(o.toString());
+ }
+ else if (o instanceof Number) {
+ write(o.toString());
+ }
+ else if (o instanceof String) {
+ String s = (String)o;
+ char[] arr = new char[s.length()];
+ s.getChars(0, arr.length, arr, 0);
+ writeObject(arr);
+ }
+ else if (o instanceof char[]) {
+ char[] s = (char[])o;
+ write('"');
+ int l = s.length;
+ for (int i = 0; i < l; i++) {
+ char ch = s[i];
+ switch (ch) {
+ case 0:
+ write("\\u0000");
+ break;
+ case '\r':
+ write("\\r");
+ break;
+ case '\n':
+ write("\\n");
+ break;
+ case '\t':
+ write("\\t");
+ break;
+ case '\b':
+ write("\\b");
+ break;
+ case '\f':
+ write("\\f");
+ break;
+ case '"':
+ case '\\':
+ write('\\');
+ default:
+ if (tmp_buf_pos >= tmp_buf.length) write(ch);
+ else tmp_buf[tmp_buf_pos++] = ch;
+ }
+ }
+ write('"');
+ }
+ else if (o instanceof byte[]) {
+ write('[');
+ byte[] arr = (byte[])o;
+ boolean comma = false;
+ for (int i = 0; i < arr.length; i++) {
+ if (comma) write(',');
+ writeUInt(arr[i] & 0xff);
+ comma = true;
+ }
+ write(']');
+ }
+ else if (o instanceof Object[]) {
+ write('[');
+ Object[] arr = (Object[])o;
+ boolean comma = false;
+ for (int i = 0; i < arr.length; i++) {
+ if (comma) write(',');
+ writeObject(arr[i]);
+ comma = true;
+ }
+ write(']');
+ }
+ else if (o instanceof Collection) {
+ write('[');
+ boolean comma = false;
+ for (Iterator<Object> i = ((Collection<Object>)o).iterator(); i.hasNext();) {
+ if (comma) write(',');
+ writeObject(i.next());
+ comma = true;
+ }
+ write(']');
+ }
+ else if (o instanceof Map) {
+ Map<String,Object> map = (Map<String,Object>)o;
+ write('{');
+ boolean comma = false;
+ for (Iterator<Map.Entry<String,Object>> i = map.entrySet().iterator(); i.hasNext();) {
+ if (comma) write(',');
+ Map.Entry<String,Object> e = i.next();
+ writeObject(e.getKey());
+ write(':');
+ writeObject(e.getValue());
+ comma = true;
+ }
+ write('}');
+ }
+ else {
+ throw new IOException("JSON: unsupported object type");
+ }
+ }
+
+ private static byte[] toBytes() throws UnsupportedEncodingException {
+ int inp_pos = 0;
+ int out_pos = 0;
+ while (inp_pos < tmp_buf_pos) {
+ if (out_pos >= tmp_bbf.length - 4) {
+ byte[] tmp = new byte[tmp_bbf.length * 2];
+ System.arraycopy(tmp_bbf, 0, tmp, 0, out_pos);
+ tmp_bbf = tmp;
+ }
+ int ch = tmp_buf[inp_pos++];
+ if (ch < 0x80) {
+ tmp_bbf[out_pos++] = (byte)ch;
+ }
+ else if (ch < 0x800) {
+ tmp_bbf[out_pos++] = (byte)((ch >> 6) | 0xc0);
+ tmp_bbf[out_pos++] = (byte)(ch & 0x3f | 0x80);
+ }
+ else if (ch < 0x10000) {
+ tmp_bbf[out_pos++] = (byte)((ch >> 12) | 0xe0);
+ tmp_bbf[out_pos++] = (byte)((ch >> 6) & 0x3f | 0x80);
+ tmp_bbf[out_pos++] = (byte)(ch & 0x3f | 0x80);
+ }
+ else {
+ tmp_bbf[out_pos++] = (byte)((ch >> 18) | 0xf0);
+ tmp_bbf[out_pos++] = (byte)((ch >> 12) & 0x3f | 0x80);
+ tmp_bbf[out_pos++] = (byte)((ch >> 6) & 0x3f | 0x80);
+ tmp_bbf[out_pos++] = (byte)(ch & 0x3f | 0x80);
+ }
+ }
+ byte[] res = new byte[out_pos];
+ System.arraycopy(tmp_bbf, 0, res, 0, out_pos);
+ return res;
+ }
+
+ public static String toJSON(Object o) throws IOException {
+ assert Protocol.isDispatchThread();
+ tmp_buf_pos = 0;
+ writeObject(o);
+ return new String(tmp_buf, 0, tmp_buf_pos);
+ }
+
+ public static byte[] toJASONBytes(Object o) throws IOException {
+ assert Protocol.isDispatchThread();
+ tmp_buf_pos = 0;
+ writeObject(o);
+ return toBytes();
+ }
+
+ public static byte[] toJSONSequence(Object[] o) throws IOException {
+ assert Protocol.isDispatchThread();
+ if (o == null || o.length == 0) return null;
+ tmp_buf_pos = 0;
+ for (int i = 0; i < o.length; i++) {
+ writeObject(o[i]);
+ write((char)0);
+ }
+ return toBytes();
+ }
+
+ public static Object parseOne(String s) throws IOException {
+ assert Protocol.isDispatchThread();
+ reader = new StringReader(s);
+ err_buf_pos = 0;
+ err_buf_cnt = 0;
+ cur_buf_pos = 0;
+ cur_buf_len = 0;
+ read();
+ return readObject();
+ }
+
+ public static Object parseOne(byte[] b) throws IOException {
+ assert Protocol.isDispatchThread();
+ reader = new InputStreamReader(new ByteArrayInputStream(b), "UTF8");
+ err_buf_pos = 0;
+ err_buf_cnt = 0;
+ cur_buf_pos = 0;
+ cur_buf_len = 0;
+ read();
+ return readObject();
+ }
+
+ public static Object[] parseSequence(byte[] b) throws IOException {
+ assert Protocol.isDispatchThread();
+ reader = new InputStreamReader(new ByteArrayInputStream(b), "UTF8");
+ err_buf_pos = 0;
+ err_buf_cnt = 0;
+ cur_buf_pos = 0;
+ cur_buf_len = 0;
+ read();
+ return readSequence();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/Protocol.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/Protocol.java
new file mode 100644
index 000000000..7e577ccf5
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/protocol/Protocol.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.protocol;
+
+import com.windriver.tcf.api.internal.core.LocalPeer;
+import com.windriver.tcf.api.internal.core.Transport;
+import com.windriver.tcf.api.internal.services.local.LocatorService;
+import com.windriver.tcf.api.services.ILocator;
+
+/**
+ *
+ * Class Protocol provides static methods to access Target Communication Framework root objects:
+ * 1. the framework event queue and dispatch thread;
+ * 2. local instance of Locator service, which maintains a list of available targets;
+ * 3. list of open communication channels.
+ */
+public class Protocol {
+
+ private static IEventQueue event_queue;
+
+ /**
+ * Before TCF can be used it should be given an object implementing IEventQueue interface.
+ * The implementation maintains a queue of objects implementing Runnable interface and
+ * executes <code>run</code> methods of that objects in a sequence by a single thread.
+ * The thread in referred as TCF event dispatch thread. Objects in the queue are called TCF events.
+ * Executing <code>run</code> method of an event is also called dispatching of event.
+ *
+ * Only few methods in TCF APIs are thread safe - can be invoked from any thread.
+ * If a method description does not say "can be invoked from any thread" explicitly -
+ * the method must be invoked from TCF event dispatch thread. All TCF listeners are
+ * invoked from the dispatch thread.
+ *
+ * @param event_queue - IEventQueue implementation.
+ */
+ public static void setEventQueue(IEventQueue event_queue) {
+ assert Protocol.event_queue == null;
+ Protocol.event_queue = event_queue;
+ event_queue.invokeLater(new Runnable() {
+
+ public void run() {
+ new LocatorService();
+ new LocalPeer();
+ }
+ });
+ }
+
+ /**
+ * @return instance of IEventQueue that is used for TCF events.
+ */
+ public static IEventQueue getEventQueue() {
+ return event_queue;
+ }
+
+ /**
+ * Returns true if the calling thread is TCF event dispatch thread.
+ * Use this call the ensure that a given task is being executed (or not being)
+ * on dispatch thread.
+ *
+ * @return true if running on the dispatch thread.
+ */
+ public static boolean isDispatchThread() {
+ return event_queue != null && event_queue.isDispatchThread();
+ }
+
+ /**
+ * Causes <code>runnable</code> to have its <code>run</code>
+ * method called in the dispatch thread of the framework.
+ * Events are dispatched in same order as queued.
+ * If invokeLater is called from the dispatching thread
+ * the <i>runnable.run()</i> will still be deferred until
+ * all pending events have been processed.
+ *
+ * This method can be invoked from any thread.
+ *
+ * @param runnable the <code>Runnable</code> whose <code>run</code>
+ * method should be executed asynchronously.
+ */
+ public static void invokeLater(Runnable runnable) {
+ event_queue.invokeLater(runnable);
+ }
+
+ /**
+ * Causes <code>runnable</code> to have its <code>run</code>
+ * method called in the dispatch thread of the framework.
+ * Calling thread is suspended until the method is executed.
+ *
+ * This method can be invoked from any thread.
+ *
+ * @param runnable the <code>Runnable</code> whose <code>run</code>
+ * method should be executed on dispatch thread.
+ */
+ public static void invokeAndWait(final Runnable runnable) {
+ if (event_queue.isDispatchThread()) {
+ runnable.run();
+ }
+ else {
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ runnable.run();
+ }
+ finally {
+ synchronized (this) {
+ notify();
+ }
+ }
+ }
+ };
+ synchronized (r) {
+ event_queue.invokeLater(r);
+ try {
+ r.wait();
+ }
+ catch (InterruptedException x) {
+ throw new Error(x);
+ }
+ }
+ }
+ }
+
+ /**
+ * Get instance of the framework locator service.
+ * The service can be used to discover available remote peers.
+ *
+ * @return instance of ILocator.
+ */
+ public static ILocator getLocator() {
+ return LocatorService.getLocator();
+ }
+
+ /**
+ * Return an array of all open channels.
+ * @return an array of IChannel
+ */
+ public static IChannel[] getOpenChannels() {
+ return Transport.getOpenChannels();
+ }
+
+ /**
+ * Interface to be implemented by clients willing to be notified when
+ * new TCF communication channel is opened.
+ */
+ public interface ChannelOpenListener {
+ public void onChannelOpen(IChannel channel);
+ }
+
+ /**
+ * Add a listener that will be notified when new channel is opened.
+ * @param listener
+ */
+ public static void addChannelOpenListener(ChannelOpenListener listener) {
+ Transport.addChanalOpenListener(listener);
+ }
+
+ /**
+ * Remove channel opening listener.
+ * @param listener
+ */
+ public static void removeChannelOpenListener(ChannelOpenListener listener) {
+ Transport.removeChanalOpenListener(listener);
+ }
+
+ /**
+ * Transmit TCF event message.
+ * The message is sent to all open communication channels – broadcasted.
+ */
+ public static void sendEvent(String service_name, String event_name, byte[] data) {
+ Transport.sendEvent(service_name, event_name, data);
+ }
+
+ /**
+ * Call back after TCF messages sent by this host up to this moment are delivered
+ * to their intended target. This method is intended for synchronization of messages
+ * across multiple channels.
+ *
+ * Note: Cross channel synchronization can reduce performance and throughput.
+ * Most clients don't need cross channel synchronization and should not call this method.
+ *
+ * @param done will be executed by dispatch thread after communication
+ * messages are delivered to corresponding targets.
+ */
+ public static void sync(Runnable done) {
+ Transport.sync(done);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IBreakpoints.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IBreakpoints.java
new file mode 100644
index 000000000..fbcb5e0b5
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IBreakpoints.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * Breakpoint is represented by unique identifier and set of properties.
+ * Breakpoint identifier (String id) needs to be unique across all hosts and targets.
+ *
+ * Breakpoint properties (Map<String,Object>) is extendable collection of named attributes,
+ * which define breakpoint location and behavior. This module defines some common
+ * attribute names (see PROP_*), host tools and target agents may support additional attributes.
+ *
+ * For each breakpoint a target agent maintains another extendable collection of named attributes:
+ * breakpoint status (Map<String,Object>, see STATUS_*). While breakpoint properties are
+ * persistent and represent user input, breakpoint status reflects dynamic target agent reports
+ * about breakpoint current state, like actual addresses where breakpoint is planted or planting errors.
+ */
+public interface IBreakpoints extends IService {
+
+ /**
+ * Service name.
+ */
+ static final String NAME = "Breakpoints";
+
+ /**
+ * Breakpoint property names.
+ */
+ static final String
+ PROP_ID = "ID", // String
+ PROP_ENABLED = "Enabled", // Boolean
+ PROP_ADDRESS = "Address", // String
+ PROP_CONDITION = "Condition", // String
+ PROP_FILE = "File", // String
+ PROP_LINE = "Line", // Number
+ PROP_COLUMN = "Column"; // Number
+
+ /**
+ * Breakpoint status field names.
+ */
+ static final String
+ STATUS_PLANTED = "Planted", // Array of addresses
+ STATUS_ERROR = "Error", // String
+ STATUS_FILE = "File", // String
+ STATUS_LINE = "Line", // Number
+ STATUS_COLUMN = "Column"; // Number
+
+ /**
+ * Call back interface for breakpoint service commands.
+ */
+ interface DoneCommand {
+ void doneCommand(IToken token, Exception error);
+ }
+
+ /**
+ * Download breakpoints data to target agent.
+ * The command is intended to be used only to initialize target breakpoints table
+ * when communication channel is open. After that, host should
+ * notify target about (incremental) changes in breakpoint data by sending
+ * add, change and remove commands.
+ *
+ * @param properties - array of breakpoints.
+ * @param done - command result call back object.
+ */
+ IToken set(Map<String,Object>[] properties, DoneCommand done);
+
+ /**
+ * Called when breakpoint is added into breakpoints table.
+ * @param properties - breakpoint properties.
+ * @param done - command result call back object.
+ */
+ IToken add(Map<String,Object> properties, DoneCommand done);
+
+ /**
+ * Called when breakpoint properties are changed.
+ * @param properties - breakpoint properties.
+ * @param done - command result call back object.
+ */
+ IToken change(Map<String,Object> properties, DoneCommand done);
+
+ /**
+ * Tell target to change (only) PROP_ENABLED breakpoint property 'true'.
+ * @param ids - array of enabled breakpoint identifiers.
+ * @param done - command result call back object.
+ */
+ IToken enable(String[] ids, DoneCommand done);
+
+ /**
+ * Tell target to change (only) PROP_ENABLED breakpoint property to 'false'.
+ * @param ids - array of disabled breakpoint identifiers.
+ * @param done - command result call back object.
+ */
+ IToken disable(String[] ids, DoneCommand done);
+
+ /**
+ * Tell target to remove breakpoint.
+ * @param id - unique breakpoint identifier.
+ * @param done - command result call back object.
+ */
+ IToken remove(String[] ids, DoneCommand done);
+
+ /**
+ * Upload IDs of breakpoints known to target agent.
+ * @param done - command result call back object.
+ */
+ IToken getIDs(DoneGetIDs done);
+
+ interface DoneGetIDs {
+ void doneGetIDs(IToken token, Exception error, String[] ids);
+ }
+
+ /**
+ * Upload properties of given breakpoint from target agent breakpoint table.
+ * @param id - unique breakpoint identifier.
+ * @param done - command result call back object.
+ */
+ IToken getProperties(String id, DoneGetProperties done);
+
+ interface DoneGetProperties {
+ void doneGetProperties(IToken token, Exception error, Map<String,Object> properties);
+ }
+
+ /**
+ * Upload status of given breakpoint from target agent.
+ * @param id - unique breakpoint identifier.
+ * @param done - command result call back object.
+ */
+ IToken getStatus(String id, DoneGetStatus done);
+
+ interface DoneGetStatus {
+ void doneGetStatus(IToken token, Exception error, Map<String,Object> status);
+ }
+
+ /**
+ * Breakpoints service events listener.
+ */
+ interface BreakpointsListener {
+
+ /**
+ * Called when breakpoint status changes.
+ * @param id - unique breakpoint identifier.
+ * @param status - breakpoint status.
+ */
+ void breakpointStatusChanged(String id, Map<String,Object> status);
+ }
+
+ void addListener(BreakpointsListener listener);
+
+ void removeListener(BreakpointsListener listener);
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IDiagnostics.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IDiagnostics.java
new file mode 100644
index 000000000..9552c4a6d
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IDiagnostics.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.services;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * This is optional service that can be implemented by a peer.
+ * If implemented, the service can be used for testing of the peer and
+ * communication channel functionality and reliability.
+ */
+
+public interface IDiagnostics extends IService {
+
+ public static final String NAME = "Diagnostics";
+
+ public IToken echo(String s, DoneEcho done);
+
+ public interface DoneEcho {
+ public void doneEcho(IToken token, Throwable error, String s);
+ }
+
+ public IToken getTestList(DoneGetTestList done);
+
+ public interface DoneGetTestList {
+ public void doneGetTestList(IToken token, Throwable error, String[] list);
+ }
+
+ public IToken runTest(String s, DoneRunTest done);
+
+ public interface DoneRunTest {
+ public void doneRunTest(IToken token, Throwable error, String context_id);
+ }
+
+ public IToken cancelTest(String context_id, DoneCancelTest done);
+
+ public interface DoneCancelTest {
+ public void doneCancelTest(IToken token, Throwable error);
+ }
+
+ public IToken getSymbol(String context_id, String symbol_name, DoneGetSymbol done);
+
+ public interface DoneGetSymbol {
+ public void doneGetSymbol(IToken token, Throwable error, ISymbol symbol);
+ }
+
+ public interface ISymbol {
+ public String getSectionName();
+ public Number getValue();
+ public boolean isUndef();
+ public boolean isCommon();
+ public boolean isGlobal();
+ public boolean isLocal();
+ public boolean isAbs();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IFileSystem.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IFileSystem.java
new file mode 100644
index 000000000..70213469b
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IFileSystem.java
@@ -0,0 +1,696 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.services;
+
+import java.io.IOException;
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * File System service provides file transfer (and more generally file
+ * system access) functionality in TCF. The service design is
+ * derived from SSH File Transfer Protocol specifications.
+ *
+ * Request Synchronization and Reordering
+ *
+ * The protocol and implementations MUST process requests relating to
+ * the same file in the order in which they are received. In other
+ * words, if an application submits multiple requests to the server, the
+ * results in the responses will be the same as if it had sent the
+ * requests one at a time and waited for the response in each case. For
+ * example, the server may process non-overlapping read/write requests
+ * to the same file in parallel, but overlapping reads and writes cannot
+ * be reordered or parallelized. However, there are no ordering
+ * restrictions on the server for processing requests from two different
+ * file transfer connections. The server may interleave and parallelize
+ * them at will.
+ *
+ * There are no restrictions on the order in which responses to
+ * outstanding requests are delivered to the client, except that the
+ * server must ensure fairness in the sense that processing of no
+ * request will be indefinitely delayed even if the client is sending
+ * other requests so that there are multiple outstanding requests all
+ * the time.
+ *
+ * There is no limit on the number of outstanding (non-acknowledged)
+ * requests that the client may send to the server. In practice this is
+ * limited by the buffering available on the data stream and the queuing
+ * performed by the server. If the server's queues are full, it should
+ * not read any more data from the stream, and flow control will prevent
+ * the client from sending more requests.
+ *
+ * File Names
+ *
+ * This protocol represents file names as strings. File names are
+ * assumed to use the slash ('/') character as a directory separator.
+ *
+ * File names starting with a slash are "absolute", and are relative to
+ * the root of the file system. Names starting with any other character
+ * are relative to the user's default directory (home directory). Client
+ * can use 'user()' command to retrieve current user home directory.
+ *
+ * Servers SHOULD interpret a path name component ".." as referring to
+ * the parent directory, and "." as referring to the current directory.
+ * If the server implementation limits access to certain parts of the
+ * file system, it must be extra careful in parsing file names when
+ * enforcing such restrictions. There have been numerous reported
+ * security bugs where a ".." in a path name has allowed access outside
+ * the intended area.
+ *
+ * An empty path name is valid, and it refers to the user's default
+ * directory (usually the user's home directory).
+ *
+ * Otherwise, no syntax is defined for file names by this specification.
+ * Clients should not make any other assumptions; however, they can
+ * splice path name components returned by readdir() together
+ * using a slash ('/') as the separator, and that will work as expected.
+ */
+public interface IFileSystem extends IService {
+
+ /**
+ * Service name.
+ */
+ static final String NAME = "FileSystem";
+
+ /**
+ * Flags to be used with open() method.
+ */
+ static final int
+
+ /**
+ * Open the file for reading.
+ */
+ O_READ = 0x00000001,
+
+ /**
+ * Open the file for writing. If both this and O_READ are
+ * specified, the file is opened for both reading and writing.
+ */
+ O_WRITE = 0x00000002,
+
+ /**
+ * Force all writes to append data at the end of the file.
+ */
+ O_APPEND = 0x00000004,
+
+ /**
+ * If this flag is specified, then a new file will be created if one
+ * does not already exist (if O_TRUNC is specified, the new file will
+ * be truncated to zero length if it previously exists).
+ */
+ O_CREAT = 0x00000008,
+
+ /**
+ * Forces an existing file with the same name to be truncated to zero
+ * length when creating a file by specifying O_CREAT.
+ * O_CREAT MUST also be specified if this flag is used.
+ */
+ O_TRUNC = 0x00000010,
+
+ /**
+ * Causes the request to fail if the named file already exists.
+ * O_CREAT MUST also be specified if this flag is used.
+ */
+ O_EXCL = 0x00000020;
+
+ /**
+ * Flags to be used together with FileAttrs.
+ * The flags specify which of the fields are present. Those fields
+ * for which the corresponding flag is not set are not present (not
+ * included in the message).
+ */
+ static final int
+ ATTR_SIZE = 0x00000001,
+ ATTR_UIDGID = 0x00000002,
+ ATTR_PERMISSIONS = 0x00000004,
+ ATTR_ACMODTIME = 0x00000008;
+
+ /**
+ * FileAttrs is used both when returning file attributes from
+ * the server and when sending file attributes to the server. When
+ * sending it to the server, the flags field specifies which attributes
+ * are included, and the server will use default values for the
+ * remaining attributes (or will not modify the values of remaining
+ * attributes). When receiving attributes from the server, the flags
+ * specify which attributes are included in the returned data. The
+ * server normally returns all attributes it knows about.
+ */
+ final static class FileAttrs {
+
+ /**
+ * The `flags' specify which of the fields are present.
+ */
+ public final int flags;
+
+ /**
+ * The `size' field specifies the size of the file in bytes.
+ */
+ public final long size;
+
+ /**
+ * The `uid' and `gid' fields contain numeric Unix-like user and group
+ * identifiers, respectively.
+ */
+ public final int uid;
+ public final int gid;
+
+ /**
+ * The `permissions' field contains a bit mask of file permissions as
+ * defined by posix [1].
+ */
+ public final int permissions;
+
+ /**
+ * The `atime' and `mtime' contain the access and modification times of
+ * the files, respectively. They are represented as milliseconds from
+ * midnight Jan 1, 1970 in UTC.
+ */
+ public final long atime;
+ public final long mtime;
+
+ /**
+ * Additional (non-standard) attributes.
+ */
+ public final Map<String,Object> attributes;
+
+ public FileAttrs(int flags, long size, int uid, int gid,
+ int permissions, long atime, long mtime, Map<String,Object> attributes) {
+ this.flags = flags;
+ this.size = size;
+ this.uid = uid;
+ this.gid = gid;
+ this.permissions = permissions;
+ this.atime = atime;
+ this.mtime = mtime;
+ this.attributes = attributes;
+ }
+
+ /**
+ * Determines if the file system object is a file on the remote file system.
+ *
+ * @return true if and only if the object on the remote system can be considered to have "contents" that
+ * have the potential to be read and written as a byte stream.
+ */
+ public boolean isFile() {
+ if ((flags & ATTR_PERMISSIONS) == 0) return false;
+ return (permissions & S_IFMT) == S_IFREG;
+ }
+
+ /**
+ * Determines if the file system object is a directory on the remote file system.
+ *
+ * @return true if and only if the object on the remote system is a directory.
+ * That is, it contains entries that can be interpreted as other files.
+ */
+ public boolean isDirectory() {
+ if ((flags & ATTR_PERMISSIONS) == 0) return false;
+ return (permissions & S_IFMT) == S_IFDIR;
+ }
+ }
+
+ /**
+ * The following flags are defined for the 'permissions' field:
+ */
+ static final int
+ S_IFMT = 0170000, // bitmask for the file type bitfields
+ S_IFSOCK = 0140000, // socket
+ S_IFLNK = 0120000, // symbolic link
+ S_IFREG = 0100000, // regular file
+ S_IFBLK = 0060000, // block device
+ S_IFDIR = 0040000, // directory
+ S_IFCHR = 0020000, // character device
+ S_IFIFO = 0010000, // fifo
+ S_ISUID = 0004000, // set UID bit
+ S_ISGID = 0002000, // set GID bit (see below)
+ S_ISVTX = 0001000, // sticky bit (see below)
+ S_IRWXU = 00700, // mask for file owner permissions
+ S_IRUSR = 00400, // owner has read permission
+ S_IWUSR = 00200, // owner has write permission
+ S_IXUSR = 00100, // owner has execute permission
+ S_IRWXG = 00070, // mask for group permissions
+ S_IRGRP = 00040, // group has read permission
+ S_IWGRP = 00020, // group has write permission
+ S_IXGRP = 00010, // group has execute permission
+ S_IRWXO = 00007, // mask for permissions for others (not in group)
+ S_IROTH = 00004, // others have read permission
+ S_IWOTH = 00002, // others have write permisson
+ S_IXOTH = 00001; // others have execute permission
+
+ final static class DirEntry {
+ /**
+ * `filename' is a file name being returned. It is a relative name within
+ * the directory, without any path components;
+ */
+ public final String filename;
+
+ /**
+ * `longname' is an expanded format for the file name, similar to what
+ * is returned by "ls -l" on Unix systems.
+ * The format of the `longname' field is unspecified by this protocol.
+ * It MUST be suitable for use in the output of a directory listing
+ * command (in fact, the recommended operation for a directory listing
+ * command is to simply display this data). However, clients SHOULD NOT
+ * attempt to parse the longname field for file attributes; they SHOULD
+ * use the attrs field instead.
+ */
+ public final String longname;
+
+ /**
+ * `attrs' is the attributes of the file.
+ */
+ public final FileAttrs attrs;
+
+ public DirEntry(String filename, String longname, FileAttrs attrs) {
+ this.filename = filename;
+ this.longname = longname;
+ this.attrs = attrs;
+ }
+ }
+
+ /**
+ * Opaque representation of open file handle.
+ * Note: open file handle can be used only with service instance that
+ * created the handle.
+ */
+ interface IFileHandle {
+ IFileSystem getService();
+ }
+
+ /**
+ * Status codes.
+ */
+ static final int
+
+ /**
+ * Indicates successful completion of the operation.
+ */
+ STATUS_OK = 0,
+
+ /**
+ * Indicates end-of-file condition; for read() it means that no
+ * more data is available in the file, and for readdir() it
+ * indicates that no more files are contained in the directory.
+ */
+ STATUS_EOF = 1,
+
+ /**
+ * This code is returned when a reference is made to a file which
+ * should exist but doesn't.
+ */
+ STATUS_NO_SUCH_FILE = 2,
+
+ /**
+ * is returned when the authenticated user does not have sufficient
+ * permissions to perform the operation.
+ */
+ STATUS_PERMISSION_DENIED = 3,
+
+ /**
+ * is a generic catch-all error message; it should be returned if an
+ * error occurs for which there is no more specific error code.
+ *
+ */
+ STATUS_FAILURE = 4,
+
+ /**
+ * may be returned if a badly formatted packet or protocol
+ * incompatibility is detected.
+ */
+ STATUS_BAD_MESSAGE = 5,
+
+ /**
+ * is a pseudo-error which indicates that the client has no
+ * connection to the server (it can only be generated locally by the
+ * client, and MUST NOT be returned by servers).
+ */
+ STATUS_NO_CONNECTION = 6,
+
+ /**
+ * is a pseudo-error which indicates that the connection to the
+ * server has been lost (it can only be generated locally by the
+ * client, and MUST NOT be returned by servers).
+ */
+ STATUS_CONNECTION_LOST = 7,
+
+ /**
+ * indicates that an attempt was made to perform an operation which
+ * is not supported for the server (it may be generated locally by
+ * the client if e.g. the version number exchange indicates that a
+ * required feature is not supported by the server, or it may be
+ * returned by the server if the server does not implement an
+ * operation).
+ */
+ STATUS_OP_UNSUPPORTED = 8;
+
+ abstract static class FileSystemException extends IOException {
+
+ protected FileSystemException(String message) {
+ super(message);
+ }
+
+ protected FileSystemException(Exception x) {
+ super(x.getMessage());
+ initCause(x);
+ }
+
+ public abstract int getStatus();
+ }
+
+ /**
+ * Open or create a file on a remote system.
+ *
+ * @param file_name specifies the file name. See 'File Names' for more information.
+ * @param flags is a bit mask of O_* flags.
+ * @param attrs specifies the initial attributes for the file.
+ * Default values will be used for those attributes that are not specified.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken open(String file_name, int flags, FileAttrs attrs, DoneOpen done);
+
+ interface DoneOpen {
+ void doneOpen(IToken token, FileSystemException error, IFileHandle handle);
+ }
+
+ /**
+ * Close a file on a remote system.
+ *
+ * @param handle is a handle previously returned in the response to
+ * open() or opendir().
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken close(IFileHandle handle, DoneClose done);
+
+ interface DoneClose {
+ void doneClose(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Read bytes from an open file.
+ * In response to this request, the server will read as many bytes as it
+ * can from the file (up to `len'), and return them in a byte array.
+ * If an error occurs or EOF is encountered, the server may return
+ * fewer bytes then requested. Call back method doneRead() argument 'error'
+ * will be not null in case of error, and argument 'eof' will be
+ * true in case of EOF. For normal disk files, it is guaranteed
+ * that this will read the specified number of bytes, or up to end of file
+ * or error. For e.g. device files this may return fewer bytes than requested.
+ *
+ * @param handle is an open file handle returned by open().
+ * @param offset is the offset (in bytes) relative
+ * to the beginning of the file from where to start reading.
+ * @param len is the maximum number of bytes to read.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken read(IFileHandle handle, long offset, int len, DoneRead done);
+
+ interface DoneRead {
+ void doneRead(IToken token, FileSystemException error, byte[] data, boolean eof);
+ }
+
+ /**
+ * Write bytes into an open file.
+ * The write will extend the file if writing beyond the end of the file.
+ * It is legal to write way beyond the end of the file; the semantics
+ * are to write zeroes from the end of the file to the specified offset
+ * and then the data.
+ *
+ * @param handle is an open file handle returned by open().
+ * @param offset is the offset (in bytes) relative
+ * to the beginning of the file from where to start writing.
+ * @param data is byte array that contains data for writing.
+ * @param data_pos if offset in 'data' of first byte to write.
+ * @param data_size is the number of bytes to write.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken write(IFileHandle handle, long offset,
+ byte[] data, int data_pos, int data_size, DoneWrite done);
+
+ interface DoneWrite {
+ void doneWrite(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Retrieve file attributes.
+ *
+ * @param path - specifies the file system object for which
+ * status is to be returned.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken stat(String path, DoneStat done);
+
+ /**
+ * Retrieve file attributes.
+ * Unlike 'stat()', 'lstat()' does not follow symbolic links.
+ *
+ * @param path - specifies the file system object for which
+ * status is to be returned.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken lstat(String path, DoneStat done);
+
+ /**
+ * Retrieve file attributes for an open file (identified by the file handle).
+ *
+ * @param handle is a file handle returned by 'open()'.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken fstat(IFileHandle handle, DoneStat done);
+
+ interface DoneStat {
+ void doneStat(IToken token, FileSystemException error, FileAttrs attrs);
+ }
+
+ /**
+ * Set file attributes.
+ * This request is used for operations such as changing the ownership,
+ * permissions or access times, as well as for truncating a file.
+ * An error will be returned if the specified file system object does
+ * not exist or the user does not have sufficient rights to modify the
+ * specified attributes.
+ *
+ * @param path specifies the file system object (e.g. file or directory)
+ * whose attributes are to be modified.
+ * @param attrs specifies the modifications to be made to file attributes.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken setstat(String path, FileAttrs attrs, DoneSetStat done);
+
+ /**
+ * Set file attributes for an open file (identified by the file handle).
+ * This request is used for operations such as changing the ownership,
+ * permissions or access times, as well as for truncating a file.
+ *
+ * @param handle is a file handle returned by 'open()'.
+ * @param attrs specifies the modifications to be made to file attributes.
+ * @param done is call back object.
+ * @return pending command handle.
+ */
+ IToken fsetstat(IFileHandle handle, FileAttrs attrs, DoneSetStat done);
+
+ interface DoneSetStat {
+ void doneSetStat(IToken token, FileSystemException error);
+ }
+
+ /**
+ * The opendir() command opens a directory for reading.
+ * Once the directory has been successfully opened, files (and
+ * directories) contained in it can be listed using readdir() requests.
+ * When the client no longer wishes to read more names from the
+ * directory, it SHOULD call close() for the handle. The handle
+ * should be closed regardless of whether an error has occurred or not.
+
+ * @param path - name of the directory to be listed (without any trailing slash).
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken opendir(String path, DoneOpen done);
+
+ /**
+ * The files in a directory can be listed using the opendir() and
+ * readdir() requests. Each readdir() request returns one
+ * or more file names with full file attributes for each file. The
+ * client should call readdir() repeatedly until it has found the
+ * file it is looking for or until the server responds with a
+ * message indicating an error or end of file. The client should then
+ * close the handle using the close() request.
+ * Note: directory entries "." and ".." are NOT included into readdir()
+ * response.
+ * @param handle - file handle created by opendir()
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken readdir(IFileHandle handle, DoneReadDir done);
+
+ interface DoneReadDir {
+ void doneReadDir(IToken token, FileSystemException error, DirEntry[] entries, boolean eof);
+ }
+
+ /**
+ * Create a directory on the server.
+ *
+ * @param path - specifies the directory to be created.
+ * @param attrs - new directory attributes.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken mkdir(String path, FileAttrs attrs, DoneMkDir done);
+
+ interface DoneMkDir {
+ void doneMkDir(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Remove a directory.
+ * An error will be returned if no directory
+ * with the specified path exists, or if the specified directory is not
+ * empty, or if the path specified a file system object other than a
+ * directory.
+ *
+ * @param path - specifies the directory to be removed.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken rmdir(String path, DoneRemove done);
+
+ interface DoneRemove {
+ void doneRemove(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Retrieve file system roots - top level file system objects.
+ * UNIX file system can report just one root with path "/". Other types of systems
+ * can have more the one root. For example, Windows server can return multiple roots:
+ * one per disc (e.g. "/C:/", "/D:/", etc.). Note: even Windows implementation of
+ * the service must use forward slash as directory separator, and must start
+ * absolute path with "/". Server should implement proper translation of
+ * protocol file names to OS native names and back.
+ *
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken roots(DoneRoots done);
+
+ interface DoneRoots {
+ void doneRoots(IToken token, FileSystemException error, DirEntry[] entries);
+ }
+
+ /**
+ * Remove a file or symbolic link.
+ * This request cannot be used to remove directories.
+ *
+ * @param file_name is the name of the file to be removed.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken remove(String file_name, DoneRemove done);
+
+ /**
+ * Canonicalize any given path name to an absolute path.
+ * This is useful for converting path names containing ".." components or
+ * relative pathnames without a leading slash into absolute paths.
+ *
+ * @param path specifies the path name to be canonicalized.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken realpath(String path, DoneRealPath done);
+
+ interface DoneRealPath {
+ void doneRealPath(IToken token, FileSystemException error, String path);
+ }
+
+ /**
+ * Rename a file.
+ * It is an error if there already exists a file
+ * with the name specified by 'new_path'. The server may also fail rename
+ * requests in other situations, for example if `old_path' and `new_path'
+ * point to different file systems on the server.
+ *
+ * @param old_path is the name of an existing file or directory.
+ * @param new_path is the new name for the file or directory.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken rename(String old_path, String new_path, DoneRename done);
+
+ interface DoneRename {
+ void doneRename(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Read the target of a symbolic link.
+ *
+ * @param path specifies the path name of the symbolic link to be read.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken readlink(String path, DoneReadLink done);
+
+ interface DoneReadLink {
+ void doneReadLink(IToken token, FileSystemException error, String path);
+ }
+
+ /**
+ * Create a symbolic link on the server.
+ *
+ * @param link_path specifies the path name of the symbolic link to be created.
+ * @param target_path specifies the target of the symbolic link.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken symlink(String link_path, String target_path, DoneSymLink done);
+
+ interface DoneSymLink {
+ void doneSymLink(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Copy a file on remote system.
+ *
+ * @param src_path specifies the path name of the file to be copied.
+ * @param dst_path specifies destination file name.
+ * @param copy_permissions - if true then copy source file permissions.
+ * @param copy_ownership - if true then copy source file UID and GID.
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken copy(String src_path, String dst_path,
+ boolean copy_permissions, boolean copy_ownership, DoneCopy done);
+
+ interface DoneCopy {
+ void doneCopy(IToken token, FileSystemException error);
+ }
+
+ /**
+ * Retrieve information about user account, which is used by server
+ * to access file system on behalf of the client.
+ *
+ * @param done - result call back object.
+ * @return pending command handle.
+ */
+ IToken user(DoneUser done);
+
+ interface DoneUser {
+ void doneUser(IToken token, FileSystemException error,
+ int real_uid, int effective_uid, int real_gid, int effective_gid,
+ String home);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILineNumbers.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILineNumbers.java
new file mode 100644
index 000000000..2547e6f1e
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILineNumbers.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.services;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * Line numbers service associates locations in the source files with the corresponding
+ * machine instruction addresses in the executable object.
+ */
+public interface ILineNumbers extends IService {
+
+ static final String NAME = "LineNumbers";
+
+ /**
+ * TextArea represent a continues area in source text mapped to
+ * continues range of code addresses.
+ * Line and columns are counted starting from 0.
+ * File name can be relative path, in such case client should
+ * use TextArea directory name as origin for the path.
+ * File and directory names are valid on a host where code was compiled.
+ * It is client responsibility to map names to this host file system.
+ */
+ final class CodeArea {
+ public final String directory;
+ public final String file;
+ public final int start_line;
+ public final int start_column;
+ public final int end_line;
+ public final int end_column;
+ public final Number start_address;
+ public final Number end_address;
+ public final int isa;
+ public final boolean is_statement;
+ public final boolean basic_block;
+ public final boolean prologue_end;
+ public final boolean epilogue_begin;
+
+ public CodeArea(String directory, String file, int start_line, int start_column,
+ int end_line, int end_column, Number start_address, Number end_address, int isa,
+ boolean is_statement, boolean basic_block,
+ boolean prologue_end, boolean epilogue_begin) {
+ this.directory = directory;
+ this.file = file;
+ this.start_line = start_line;
+ this.start_column = start_column;
+ this.end_line = end_line;
+ this.end_column = end_column;
+ this.start_address = start_address;
+ this.end_address = end_address;
+ this.isa = isa;
+ this.is_statement = is_statement;
+ this.basic_block = basic_block;
+ this.prologue_end = prologue_end;
+ this.epilogue_begin = epilogue_begin;
+ }
+ }
+
+ IToken mapToSource(String context_id, Number start_address, Number end_address, DoneMapToSource done);
+
+ interface DoneMapToSource {
+ void doneMapToSource(IToken token, Exception error, CodeArea[] areas);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILocator.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILocator.java
new file mode 100644
index 000000000..9116d9d7f
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ILocator.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * ILocator service uses transport layer to search for peers and to collect data about
+ * peer’s attributes and capabilities (services). Discovery mechanism depends on transport protocol
+ * and is part of that protocol handler. Targets, known to other hosts, can be found through
+ * remote instances of ILocator service. Automatically discovered targets require no further
+ * configuration. Additional targets can be configured manually.
+ *
+ * Clients should use Protocol.getLocator() to obtain local instance of ILocator,
+ * then ILocator.getPeers() can be used to get list of available peers (hosts and targets).
+ */
+
+public interface ILocator extends IService {
+
+ static final String NAME = "Locator";
+
+ /**
+ * Auto-configuration command and response codes.
+ */
+ static final int
+ CONF_REQ_INFO = 1,
+ CONF_PEER_INFO = 2;
+
+ /**
+ * @return Locator service name: "Locator"
+ */
+ String getName();
+
+ /**
+ * Get map (ID -> IPeer) of available peers (hosts and targets).
+ * The method return cached (currently known to the framework) list of peers.
+ * The list is updated according to event received from transport layer
+ */
+ Map<String,IPeer> getPeers();
+
+ /**
+ * Redirect this service channel to given peer using this service as a proxy.
+ * @param peer_id - Peer ID.
+ */
+ IToken redirect(String peer_id, DoneRedirect done);
+
+ interface DoneRedirect {
+ void doneRedirect(IToken token, Exception error);
+ }
+
+ /**
+ * Call back after TCF messages sent to this target up to this moment are delivered.
+ * This method is intended for synchronization of messages
+ * across multiple channels.
+ *
+ * Note: Cross channel synchronization can reduce performance and throughput.
+ * Most clients don't need channel synchronization and should not call this method.
+ *
+ * @param done will be executed by dispatch thread after communication
+ * messages are delivered to corresponding targets.
+ *
+ * This is internal API, TCF clients should use {@code com.windriver.tcf.api.protocol.Protocol}.
+ */
+ IToken sync(DoneSync done);
+
+ interface DoneSync {
+ void doneSync(IToken token);
+ }
+
+ /**
+ * Add a listener for ILocator service events.
+ */
+ void addListener(LocatorListener listener);
+
+ /**
+ * Remove a listener for ILocator service events.
+ */
+ void removeListener(LocatorListener listener);
+
+ interface LocatorListener {
+ void peerAdded(IPeer peer);
+
+ void peerChanged(IPeer peer);
+
+ void peerRemoved(String id);
+ }
+} \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IMemory.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IMemory.java
new file mode 100644
index 000000000..0f01c4a95
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IMemory.java
@@ -0,0 +1,247 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * IMemory service provides basic operations to read/write memory on a target.
+ */
+public interface IMemory extends IService {
+
+ static final String NAME = "Memory";
+
+ /**
+ * Context property names.
+ */
+ static final String
+ PROP_ID = "ID",
+ PROP_PARENT_ID = "ParentID",
+ PROP_PROCESS_ID = "ProcessID",
+ PROP_BIG_ENDIAN = "BigEndian",
+ PROP_ADDRESS_SIZE = "AddressSize";
+
+ /**
+ * Retrieve context info for given context ID.
+ *
+ * @param id – context ID.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getContext(String id, DoneGetContext done);
+
+ /**
+ * Client call back interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – context data.
+ */
+ void doneGetContext(IToken token, Exception error, MemoryContext context);
+ }
+
+ /**
+ * Retrieve contexts available for memory commands.
+ * A context corresponds to an execution thread, process, address space, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ *
+ * @param parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getChildren commands.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ /**
+ * Client call back interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * Memory access mode:
+ * Carry on when some of the memory cannot be accessed and
+ * return MemoryError at the end if any of the bytes
+ * were not processed correctly.
+ */
+ final static int MODE_CONTINUEONERROR = 0x1;
+
+ /**
+ * Memory access mode:
+ * Verify result of memory operations (by reading and comparing).
+ */
+ final static int MODE_VERIFY = 0x2;
+
+ interface MemoryContext {
+
+ /**
+ * Retrieve context ID.
+ * Same as (String)getProperties().get(“ID”)
+ */
+ String getID();
+
+ /**
+ * Retrieve parent context ID.
+ * Same as (String)getProperties().get(“ParentID”)
+ */
+ String getParentID();
+
+ /**
+ * Retrieves process ID, if applicable.
+ * @return process system ID.
+ */
+ int getProcessID();
+
+ /**
+ * Retrieve memory endianess.
+ * @return true if memory id big-endian.
+ */
+ boolean isBigEndian();
+
+ /**
+ * Retrieve memory address size.
+ * @return number of bytes used to store memory address value.
+ */
+ int getAddressSize();
+
+ /**
+ * Retrieve context properties.
+ */
+ Map<String,Object> getProperties();
+
+ /**
+ * Set target memory.
+ * If 'word_size' is 0 it means client does not care about word size.
+ */
+ IToken set(Number addr, int word_size, byte[] buf,
+ int offs, int size, int mode, DoneMemory done);
+
+ /**
+ * Read target memory.
+ */
+ IToken get(Number addr, int word_size, byte[] buf,
+ int offs, int size, int mode, DoneMemory done);
+
+ /**
+ * Fill target memory with given pattern.
+ * 'size' is number of bytes to fill.
+ */
+ IToken fill(Number addr, int word_size, byte[] value,
+ int size, int mode, DoneMemory done);
+ }
+
+ /**
+ * Client call back interface for set(), get() and fill() commands.
+ */
+ interface DoneMemory {
+ public void doneMemory(IToken token, MemoryError error);
+ }
+
+ class MemoryError extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public MemoryError(String msg) {
+ super(msg);
+ }
+ }
+
+ /**
+ * ErrorOffset interface can be implemented by MemoryError object,
+ * which is returned by get, set and fill commands.
+ *
+ * get/set/fill () returns this exception when reading failed
+ * for some but not all bytes, and MODE_CONTINUEONERROR
+ * has been set in mode. (For example, when only part of the request
+ * translates to valid memory addresses.)
+ * Exception.getMessage can be used for generalized message of the
+ * possible reasons of partial memory operation.
+ */
+ interface ErrorOffset {
+
+ // Error may have per byte information
+ final static int
+ BYTE_VALID = 0x00,
+ BYTE_UNKNOWN = 0x01, // e.g. out of range
+ BYTE_INVALID = 0x02,
+ BYTE_CANNOT_READ = 0x04,
+ BYTE_CANNOT_WRITE = 0x08;
+
+ int getStatus(int offset);
+
+ /**
+ * Returns the detail message string about the
+ * byte associated with specified location.
+ * @return the detail error message string.
+ */
+ String getMessage(int offset);
+
+ }
+
+ /**
+ * Add memory service event listener.
+ * @param listener - event listener implementation.
+ */
+ void addListener(MemoryListener listener);
+
+ /**
+ * Remove memory service event listener.
+ * @param listener - event listener implementation.
+ */
+ void removeListener(MemoryListener listener);
+
+ /**
+ * Memory event listener is notified when memory context hierarchy
+ * changes, and when memory is modified by memory service commands.
+ */
+ interface MemoryListener {
+
+ /**
+ * Called when a new memory access context(s) is created.
+ */
+ void contextAdded(MemoryContext[] contexts);
+
+ /**
+ * Called when a memory access context(s) properties changed.
+ */
+ void contextChanged(MemoryContext[] contexts);
+
+ /**
+ * Called when memory access context(s) is removed.
+ */
+ void contextRemoved(String[] context_ids);
+
+ /**
+ * Called when target memory content was changed and clients
+ * need to update themselves. Clients, at least, should invalidate
+ * corresponding cached memory data.
+ * Not every change is notified - it is not possible,
+ * only those, which are not caused by normal execution of the debuggee.
+ * ‘addr’ and ‘size’ can be null if unknown.
+ */
+ void memoryChanged(String context_id, Number[] addr, long[] size);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IProcesses.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IProcesses.java
new file mode 100644
index 000000000..531e8e57a
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IProcesses.java
@@ -0,0 +1,202 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * IProcesses service provides access to the target OS's process
+ * information, allows to start and terminate a process, and allows
+ * to attach and detach a process for debugging. Debug services,
+ * like IMemory and IRunControl, require a process to be attached
+ * before they can access it.
+ */
+public interface IProcesses extends IService {
+
+ static final String NAME = "Processes";
+
+ /**
+ * Retrieve context info for given context ID.
+ * A context corresponds to an execution thread, process, address space, etc.
+ * Context IDs are valid across TCF services, so it is allowed to issue
+ * 'IProcesses.getContext' command with a context that was obtained,
+ * for example, from Memory service.
+ * However, 'Processes.getContext' is supposed to return only process specific data,
+ * If the ID is not a process ID, 'IProcesses.getContext' may not return any
+ * useful information
+ *
+ * @param id – context ID.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getContext(String id, DoneGetContext done);
+
+ /**
+ * Client call back interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – context data.
+ */
+ void doneGetContext(IToken token, Exception error, ProcessContext context);
+ }
+
+ /**
+ * Retrieve children of given context.
+ *
+ * @param parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getContext or getChildren commands.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, boolean attached_only, DoneGetChildren done);
+
+ /**
+ * Client call back interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * Context property names.
+ */
+ static final String
+ /** The TCF context ID */
+ PROP_ID = "ID",
+
+ /** The TCF parent context ID */
+ PROP_PARENTID = "ParentID",
+
+ /** Is the context attached */
+ PROP_ATTACHED = "Attached",
+
+ /** Can terminate the context */
+ PROP_CAN_TERMINATE = "CanTerminate",
+
+ /** Process name. Client UI can show this name to a user */
+ PROP_NAME = "Name";
+
+ interface ProcessContext {
+
+ /**
+ * Get context ID.
+ * Same as getProperties().get(“ID”)
+ */
+ String getID();
+
+ /**
+ * Get parent context ID.
+ * Same as getProperties().get(“ParentID”)
+ */
+ String getParentID();
+
+ /**
+ * Get process name.
+ * Client UI can show this name to a user.
+ * Same as getProperties().get(“Name”)
+ */
+ String getName();
+
+ /**
+ * Utility method to read context property PROP_ATTACHED.
+ * Services like IRunControl, IMemory, IBreakpoints work only with attached processes.
+ * @return value of PROP_ATTACHED.
+ */
+ boolean isAttached();
+
+ /**
+ * Utility method to read context property PROP_CAN_TERMINATE.
+ * @return value of PROP_CAN_TERMINATE.
+ */
+ boolean canTerminate();
+
+ /**
+ * Get all available context properties.
+ * @return Map 'property name' -> 'property value'
+ */
+ Map<String, Object> getProperties();
+
+ /**
+ * Attach debugger to a process.
+ * Services like IRunControl, IMemory, IBreakpoints work only with attached processes.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken attach(DoneCommand done);
+
+ /**
+ * Detach debugger from a process.
+ * Process execution will continue without debugger supervision.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken detach(DoneCommand done);
+
+ /**
+ * Terminate a process.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken terminate(DoneCommand done);
+
+ /**
+ * Send a signal to a process.
+ * @param signal - signal ID.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken signal(int signal, DoneCommand done);
+ }
+
+ interface DoneCommand {
+ void doneCommand(IToken token, Exception error);
+ }
+
+ /**
+ * Get default set of environment variables used to start a new process.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken getEnvironment(DoneGetEnvironment done);
+
+ interface DoneGetEnvironment {
+ void doneGetEnvironment(IToken token, Exception error, Map<String,String> environment);
+ }
+
+ /**
+ * Start a new process on remote machine.
+ * @param directory - initial value of working directory for the process.
+ * @param file - process image file.
+ * @param command_line - command line arguments for the process.
+ * @param environment - map of environment variables for the process,
+ * if null then default set of environment variables will be used.
+ * @param attach - if true debugger should be attached to the process.
+ * @param done - call back interface called when operation is completed.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken start(String directory, String file,
+ String[] command_line, Map<String,String> environment,
+ boolean attach, DoneStart done);
+
+ interface DoneStart {
+ void doneStart(IToken token, Exception error, ProcessContext process);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRegisters.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRegisters.java
new file mode 100644
index 000000000..2cf4de1f4
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRegisters.java
@@ -0,0 +1,318 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * IRegisters service provides access to target CPU register values and properties.
+ */
+public interface IRegisters extends IService {
+
+ static final String NAME = "Registers";
+
+ /**
+ * Context property names.
+ */
+ static final String
+ PROP_ID = "ID",
+ PROP_PARENT_ID = "ParentID",
+ PROP_PROCESS_ID = "ProcessID",
+ PROP_NAME = "Name",
+ PROP_DESCRIPTION = "Description",
+ PROP_FORMATS = "Formats",
+ PROP_READBLE = "Readable",
+ PROP_READ_ONCE = "ReadOnce",
+ PROP_WRITEABLE = "Writeable",
+ PROP_WRITE_ONCE = "WriteOnce",
+ PROP_SIDE_EFFECTS = "SideEffects",
+ PROP_VOLATILE = "Volatile",
+ PROP_FLOAT = "Float",
+ PROP_BIG_ENDIAN = "BigEndian",
+ PROP_LEFT_TO_RIGHT = "LeftToRight",
+ PROP_FIST_BIT = "FirstBit",
+ PROP_BITS = "Bits",
+ PROP_VALUES = "Values";
+
+ /**
+ * Standard known formats for register data.
+ */
+ static final String
+ FORMAT_BINARY = "Binary",
+ FORMAT_OCTAL = "Octal",
+ FORMAT_DECIMAL = "Decimal",
+ FORMAT_HEX = "Hex",
+ FORMAT_NATURAL = "Natural";
+
+ /**
+ * Retrieve context info for given context ID.
+ *
+ * @param id – context ID.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getContext(String id, DoneGetContext done);
+
+ /**
+ * Client call back interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – context data.
+ */
+ void doneGetContext(IToken token, Exception error, RegistersContext context);
+ }
+
+ /**
+ * Retrieve contexts available for registers commands.
+ * A context corresponds to an execution thread, stack frame, registers group, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ *
+ * @param parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getChildren commands.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ /**
+ * Client call back interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * RegistersContext objects represent register groups, registers and bit fields.
+ */
+ interface RegistersContext {
+ /**
+ * Get Context ID.
+ * @return context ID.
+ */
+ String getID();
+
+ /**
+ * Get parent context ID.
+ * @return parent context ID.
+ */
+ String getParentID();
+
+ /**
+ * Get context (register, register group, bit field) name.
+ * @return context name.
+ */
+ String getName();
+
+ /**
+ * Get context description.
+ * @return context description.
+ */
+ String getDescription();
+
+ /**
+ * Get value formats available for register get/set commands.
+ * See FORMAT_* for knows format IDs definition.
+ * @return array of supported format IDs.
+ */
+ String[] getAvailableFormats();
+
+ /**
+ * Check if context value can be read.
+ * @return true if can read value of the context.
+ */
+ boolean isReadable();
+
+ /**
+ * Check if reading the context (register) destroys its current value -
+ * it can be read only once.
+ * @return true if read-once register.
+ */
+ boolean isReadOnce();
+
+ /**
+ * Check if context value can be written.
+ * @return true if can write value of the context.
+ */
+ boolean isWriteable();
+
+ /**
+ * Check if register value can not be overwritten - every write counts.
+ * @return true if write-once register.
+ */
+ boolean isWriteOnce();
+
+ /**
+ * Check if writing the context can change values of other registers.
+ * @return true if has side effects.
+ */
+ boolean hasSideEffects();
+
+ /**
+ * Check if the register value can change even when target is stopped.
+ * @return true if the register value can change at any time.
+ */
+ boolean isVolatile();
+
+ /**
+ * Check if the register value is a floating-point value.
+ * @return true if a floating-point register.
+ */
+ boolean isFloat();
+
+ /**
+ * Check endianess of the context.
+ * Big endian means decreasing numeric significance with increasing bit number.
+ * @return true if big endian.
+ */
+ boolean isBigEndian();
+
+ /**
+ * Check if the lowest numbered bit (i.e. bit #0 or bit #1 depending on
+ * getFirstBitNumber() value) should be shown to user as the left-most bit or
+ * the right-most bit.
+ * @return true if the first bit is left-most bit.
+ */
+ boolean isLeftToRight();
+
+ /**
+ * If the context has bit field children, bit positions of the fields
+ * can be zero-based or 1-based.
+ * @return first bit position - 0 or 1.
+ */
+ int getFirstBitNumber();
+
+ /**
+ * If context is a bit field, get the field bit numbers in parent context.
+ * @return array of bit numbers.
+ */
+ int[] getBitNumbers();
+
+ /**
+ * A context can have predefined names (mnemonics) for some its values.
+ * This method returns a list of such named values.
+ * @return array of named values or null.
+ */
+ NamedValue[] getNamedValues();
+
+ /**
+ * Get complete map of context properties.
+ * @return map of context properties.
+ */
+ Map<String,Object> getProperties();
+
+ /**
+ * Read value of the context.
+ * @param format - ID of a format to use for result value.
+ * @param done - call back object.
+ * @return - pending command handle.
+ */
+ IToken get(String format, DoneGet done);
+
+ /**
+ * Set value of the context.
+ * @param format - ID of a format used for value.
+ * @param value - value to write into the context.
+ * @param done - call back object.
+ * @return - pending command handle.
+ */
+ IToken set(String format, String value, DoneSet done);
+ }
+
+ /**
+ * A register context can have predefined names (mnemonics) for some its values.
+ * NamedValue objects represent such values.
+ */
+ interface NamedValue {
+ /**
+ * Get number associated with this named value.
+ * @return the value as a number.
+ */
+ Number getValue();
+
+ /**
+ * Get name (mnemonic) of the value.
+ * @return value name.
+ */
+ String getName();
+
+ /**
+ * Get human readable description of the value.
+ * @return value description.
+ */
+ String getDescription();
+ }
+
+ /**
+ * 'get' command call back interface.
+ */
+ interface DoneGet {
+ void doneGet(IToken token, Exception error, String value);
+ }
+
+ /**
+ * 'set' command call back interface.
+ */
+ interface DoneSet {
+ void doneSet(IToken token, Exception error);
+ }
+
+ /**
+ * Add registers service event listener.
+ * @param listener - event listener implementation.
+ */
+ void addListener(RegistersListener listener);
+
+ /**
+ * Remove registers service event listener.
+ * @param listener - event listener implementation.
+ */
+ void removeListener(RegistersListener listener);
+
+ /**
+ * Registers event listener is notified when registers context hierarchy
+ * changes, and when a register is modified by the service commands.
+ */
+ interface RegistersListener {
+
+ /**
+ * Called when register context properties changed.
+ * Most targets have static set of registers and register properties.
+ * Such targets never generate this event. However, some targets,
+ * for example, JTAG probes, allow user to modify register definitions.
+ * Clients should flush all cached register context data.
+ */
+ void contextChanged();
+
+ /**
+ * Called when register content was changed and clients
+ * need to update themselves. Clients, at least, should invalidate
+ * corresponding cached registers data.
+ * Not every change is notified - it is not possible,
+ * only those, which are not caused by normal execution of the debuggee.
+ */
+ void registerChanged(String context_id);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRunControl.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRunControl.java
new file mode 100644
index 000000000..fc8befbcc
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IRunControl.java
@@ -0,0 +1,323 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+public interface IRunControl extends IService {
+
+ static final String NAME = "RunControl";
+
+ /**
+ * Context property names.
+ */
+ static final String
+ PROP_ID = "ID",
+ PROP_PARENT_ID = "ParentID",
+ PROP_IS_CONTAINER = "IsContainer",
+ PROP_HAS_STATE = "HasState",
+ PROP_CAN_RESUME = "CanResume",
+ PROP_CAN_COUNT = "CanCount",
+ PROP_CAN_SUSPEND = "CanSuspend",
+ PROP_CAN_TERMINATE = "CanTerminate";
+
+ /**
+ * Context resume modes.
+ */
+ static final int
+ RM_RESUME = 0,
+ RM_STEP_OVER = 1,
+ RM_STEP_INTO = 2,
+ RM_STEP_OVER_LINE = 3,
+ RM_STEP_INTO_LINE = 4,
+ RM_STEP_OUT = 5;
+
+ /**
+ * State change reason of a context.
+ * Reason can be any text, but if it is one of predefined strings,
+ * a generic client might be able to handle it better.
+ */
+ static final String
+ REASON_USER_REQUEST = "Suspended",
+ REASON_STEP = "Step",
+ REASON_BREAKPOINT = "Breakpoint",
+ REASON_EXCEPTION = "Exception",
+ REASON_CONTAINER = "Container",
+ REASON_WATCHPOINT = "Watchpoint",
+ REASON_SIGNAL = "Signal",
+ REASON_SHAREDLIB = "Shared Library",
+ REASON_ERROR = "Error";
+
+ /**
+ * Retrieve context properties for given context ID.
+ *
+ * @param id – context ID.
+ * @param done - callback interface called when operation is completed.
+ */
+ IToken getContext(String id, DoneGetContext done);
+
+ /**
+ * Client callback interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – context data.
+ */
+ void doneGetContext(IToken token, Exception error, RunControlContext context);
+ }
+
+ /**
+ * Retrieve children of given context.
+ *
+ * @param parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getContext or getChildren commands.
+ * @param done - callback interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ /**
+ * Client callback interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * A context corresponds to an execution thread, process, address space, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ */
+ interface RunControlContext {
+
+ /**
+ * Retrieve context ID.
+ * Same as getProperties().get(“ID”)
+ */
+ String getID();
+
+ /**
+ * Retrieve parent context ID.
+ * Same as getProperties().get(“ParentID”)
+ */
+ String getParentID();
+
+ /**
+ * Get context properties. See PROP_* definitions for property names.
+ * Context properties are read only, clients should not try to modify them.
+ * @return Map of context properties.
+ */
+ Map<String,Object> getProperties();
+
+ /**
+ * Utility method to read context property PROP_IS_CONTAINER.
+ * Executing resume or suspend command on a container causes all its children to resume or suspend.
+ * @return value of PROP_IS_CONTAINER.
+ */
+ boolean isContainer();
+
+ /**
+ * Utility method to read context property PROP_HAS_STATE.
+ * Only context that has a state can be resumed or suspended.
+ * @return value of PROP_HAS_STATE.
+ */
+ boolean hasState();
+
+ /**
+ * Utility method to read context property PROP_CAN_SUSPEND.
+ * Value 'true' means suspend command is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already suspended.
+ * @return value of PROP_CAN_SUSPEND.
+ */
+ boolean canSuspend();
+
+ /**
+ * Utility method to read a 'mode' bit in context property PROP_CAN_RESUME.
+ * Value 'true' means resume command is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already resumed.
+ * @param mode - resume mode, see RM_*.
+ * @return value of requested bit of PROP_CAN_RESUME.
+ */
+ boolean canResume(int mode);
+
+ /**
+ * Utility method to read a 'mode' bit in context property PROP_CAN_COUNT.
+ * Value 'true' means resume command with count other then 1 is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already resumed.
+ * @param mode - resume mode, see RM_*.
+ * @return value of requested bit of PROP_CAN_COUNT.
+ */
+ boolean canCount(int mode);
+
+ /**
+ * Utility method to read context property PROP_CAN_TERMINATE.
+ * Value 'true' means terminate command is supported by the context,
+ * however the method does not check that the command can be executed successfully in
+ * the current state of the context. For example, the command still can fail if context is
+ * already exited.
+ * @return value of PROP_CAN_SUSPEND.
+ */
+ boolean canTerminate();
+
+ /**
+ * Send a command to retrieve current state of a context.
+ * @param done - command result call back object.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken getState(DoneGetState done);
+
+ /**
+ * Send a command to suspend a context.
+ * Also suspends children if context is a container.
+ * @param done - command result call back object.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken suspend(DoneCommand done);
+
+ /**
+ * Send a command to resume a context.
+ * Also resumes children if context is a container.
+ * @param mode - defines how to resume the context, see RM_*.
+ * @param count - if mode implies stepping, defines how many steps to perform.
+ * @param done - command result call back object.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken resume(int mode, int count, DoneCommand done);
+
+ /**
+ * Send a command to terminate a context.
+ * @param done - command result call back object.
+ * @return pending command handle, can be used to cancel the command.
+ */
+ IToken terminate(DoneCommand done);
+ }
+
+ class RunControlError extends Exception {
+
+ private static final long serialVersionUID = 1L;
+ }
+
+ interface DoneGetState {
+ void doneGetState(IToken token, Exception error, boolean suspended, String pc,
+ String reason, Map<String,Object> params);
+ }
+
+ interface DoneCommand {
+ /**
+ * Called when run control command execution is complete.
+ * @param token - pending command handle.
+ * @param error - command execution error or null.
+ */
+ void doneCommand(IToken token, Exception error);
+ }
+
+ /**
+ * Add run control event listener.
+ * @param listener - run control event listener to add.
+ */
+ void addListener(RunControlListener listener);
+
+ /**
+ * Remove run control event listener.
+ * @param listener - run control event listener to remove.
+ */
+ void removeListener(RunControlListener listener);
+
+ /**
+ * Service events listener interface.
+ */
+ interface RunControlListener {
+
+ /**
+ * Called when new contexts are created.
+ * @param contexts - array of new context properties.
+ */
+ void contextAdded(RunControlContext contexts[]);
+
+ /**
+ * Called when a context properties changed.
+ * @param contexts - array of new context properties.
+ */
+ void contextChanged(RunControlContext contexts[]);
+
+ /**
+ * Called when contexts are removed.
+ * @param context_ids - aray of removed context IDs.
+ */
+ void contextRemoved(String context_ids[]);
+
+ /**
+ * Called when a thread is suspended.
+ * @param context - ID of a context that was suspended.
+ * @param pc - program counter of the context, can be null.
+ * @param reason - human readable description of suspend reason.
+ * @param params - additional, target specific data about suspended context.
+ */
+ void contextSuspended(String context, String pc,
+ String reason, Map<String,Object> params);
+
+ /**
+ * Called when a thread is resumed.
+ * @param context - ID of a context that was resumed.
+ */
+ void contextResumed(String context);
+
+ /**
+ * Called when target simultaneously suspends multiple threads in a container
+ * (process, core, etc.).
+ *
+ * @param context - ID of a context responsible for the event. It can be container ID or
+ * any one of container children, for example, it can be thread that hit "suspend all" breakpoint.
+ * Client expected to move focus (selection) to this context.
+ * @param pc - program counter of the context.
+ * @param reason - human readable description of suspend reason.
+ * @param params - additional target specific data about suspended context.
+ * @param suspended_ids - full list of all contexts that were suspended.
+ */
+ void containerSuspended(String context, String pc,
+ String reason, Map<String,Object> params, String[] suspended_ids);
+
+ /**
+ * Called when target simultaneously resumes multiple threads in a container (process,
+ * core, etc.).
+ *
+ * @param context_ids - full list of all contexts that were resumed.
+ */
+ void containerResumed(String[] context_ids);
+
+ /**
+ * Called when an exception is detected in a target thread.
+ * @param context - ID of a context that caused an exception.
+ * @param msg - human readable description of the exception.
+ */
+ void contextException(String context, String msg);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IStackTrace.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IStackTrace.java
new file mode 100644
index 000000000..a3657bcab
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/IStackTrace.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+public interface IStackTrace extends IService {
+
+ static final String NAME = "StackTrace";
+
+ /**
+ * Context property names.
+ */
+ static final String
+ PROP_ID = "ID",
+ PROP_PARENT_ID = "ParentID",
+ PROP_PROCESS_ID = "ProcessID",
+ PROP_NAME = "Name",
+ PROP_FRAME_ADDRESS = "FP",
+ PROP_RETURN_ADDRESS = "RP",
+ PROP_ARGUMENTS_COUNT = "ArgsCnt",
+ PROP_ARGUMENTS_ADDRESS = "ArgsAddr";
+
+ /**
+ * Retrieve context info for given context IDs.
+ *
+ * The command will fail if parent thread is not suspended.
+ * Client can use Run Control service to suspend a thread.
+ *
+ * @param id – array of context IDs.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getContext(String[] id, DoneGetContext done);
+
+ /**
+ * Client call back interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – array of context data or null if error.
+ */
+ void doneGetContext(IToken token, Exception error, StackTraceContext[] context);
+ }
+
+ /**
+ * Retrieve stack trace context list.
+ * Parent context usually corresponds to an execution thread.
+ * Some targets have more then one stack. In such case children of a thread
+ * are stacks, and stack frames are deeper in the hierarchy - they can be
+ * retrieved with additional getChildren commands.
+ *
+ * The command will fail if parent thread is not suspended.
+ * Client can use Run Control service to suspend a thread.
+ *
+ * @param parent_context_id – parent context ID.
+ * @param done - call back interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ /**
+ * Client call back interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ * Stack frames are ordered from stack bottom to top.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * StackTraceContext represents stack trace objects - stacks and stack frames.
+ */
+ interface StackTraceContext {
+
+ /**
+ * Get Context ID.
+ * @return context ID.
+ */
+ String getID();
+
+ /**
+ * Get parent context ID.
+ * @return parent context ID.
+ */
+ String getParentID();
+
+ /**
+ * Get context name - if context represents a stack.
+ * @return context name or null.
+ */
+ String getName();
+
+ /**
+ * Get memory address of this frame.
+ * @return address or null if not a stack frame.
+ */
+ Number getFrameAddress();
+
+ /**
+ * Get program counter saved in this stack frame -
+ * it is address of instruction to be executed when the function returns.
+ * @return return address or null if not a stack frame.
+ */
+ Number getReturnAddress();
+
+ /**
+ * Get number of function arguments for this frame.
+ * @return function arguments count.
+ */
+ int getArgumentsCount();
+
+ /**
+ * Get address of function arguments area in memory.
+ * @return function arguments address or null if not available.
+ */
+ Number getArgumentsAddress();
+
+ /**
+ * Get complete map of context properties.
+ * @return map of context properties.
+ */
+ Map<String,Object> getProperties();
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ISysMonitor.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ISysMonitor.java
new file mode 100644
index 000000000..f154c9c0e
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/services/ISysMonitor.java
@@ -0,0 +1,378 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.services;
+
+import java.util.Map;
+
+import com.windriver.tcf.api.protocol.IService;
+import com.windriver.tcf.api.protocol.IToken;
+
+/**
+ * This is optional service that can be implemented by a peer.
+ * If implemented, the service can be used for monitoring system activity and utilization.
+ * It provides list of running processes, different process attributes like command line, environment, etc.,
+ * and some resource utilization data. The service can be used by a client to provide functionality
+ * similar to Unix 'top' utility or Windows 'Task Manager'.
+ */
+public interface ISysMonitor extends IService {
+
+ static final String NAME = "SysMonitor";
+
+ /**
+ * Retrieve context info for given context ID.
+ *
+ * @param id – context ID.
+ * @param done - callback interface called when operation is completed.
+ */
+ IToken getContext(String id, DoneGetContext done);
+
+ /**
+ * Client callback interface for getContext().
+ */
+ interface DoneGetContext {
+ /**
+ * Called when context data retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context – context data.
+ */
+ void doneGetContext(IToken token, Exception error, SysMonitorContext context);
+ }
+
+ /**
+ * Retrieve children of given context.
+ *
+ * @param parent_context_id – parent context ID. Can be null –
+ * to retrieve top level of the hierarchy, or one of context IDs retrieved
+ * by previous getContext or getChildren commands.
+ * @param done - callback interface called when operation is completed.
+ */
+ IToken getChildren(String parent_context_id, DoneGetChildren done);
+
+ /**
+ * Client callback interface for getChildren().
+ */
+ interface DoneGetChildren {
+ /**
+ * Called when context list retrieval is done.
+ * @param error – error description if operation failed, null if succeeded.
+ * @param context_ids – array of available context IDs.
+ */
+ void doneGetChildren(IToken token, Exception error, String[] context_ids);
+ }
+
+ /**
+ * Context property names.
+ */
+ static final String
+ /** The TCF context ID */
+ PROP_ID = "ID",
+
+ /** The TCF parent context ID */
+ PROP_PARENTID = "ParentID",
+
+ /** Current working directory of the process */
+ PROP_CWD = "CWD",
+
+ /** The process's root directory (as set by chroot) */
+ PROP_ROOT = "Root",
+
+ /** User ID of the process owner */
+ PROP_UID = "UID",
+
+ /** Group ID of the process owner */
+ PROP_UGID = "UGID",
+
+ /** User name of the process owner */
+ PROP_USERNAME = "UserName",
+
+ /** Group name of the process owner */
+ PROP_GROUPNAME = "GroupName",
+
+ /** System process ID */
+ PROP_PID = "PID",
+
+ /** Executable file of the process */
+ PROP_FILE = "File",
+
+ /** One character from the string "RSDZTW" where R is running, S is
+ * sleeping in an interruptible wait, D is waiting in uninterruptible
+ * disk sleep, Z is zombie, T is traced or stopped (on a signal), and W
+ * is paging.*/
+ PROP_STATE = "State",
+
+ /** System ID of the parent process */
+ PROP_PPID = "PPID",
+
+ /** The process group ID of the process */
+ PROP_PGRP = "PGRP",
+
+ /** The session ID of the process */
+ PROP_SESSION = "Session",
+
+ /** The tty the process uses */
+ PROP_TTY = "TTY",
+
+ /** The process group ID of the process which currently owns the tty that
+ * the process is connected to. */
+ PROP_TGID = "TGID",
+
+ /** ID of a process that has attached this process for tracing or debugging */
+ PROP_TRACERPID = "TracerPID",
+
+ /** The kernel flags word of the process. Details depend on the kernel */
+ PROP_FLAGS = "Flags",
+
+ /** The number of minor faults the process has made which have not
+ * required loading a memory page from disk */
+ PROP_MINFLT = "MinFlt",
+
+ /** The number of minor faults that the process's waited-for children have made */
+ PROP_CMINFLT = "CMinFlt",
+
+ /** The number of major faults the process has made which have required
+ * loading a memory page from disk */
+ PROP_MAJFLT = "MajFlt",
+
+ /** The number of major faults that the process's waited-for children
+ * have made */
+ PROP_CMAJFLT = "CMajFlt",
+
+ /** The number of milliseconds that this process has been scheduled in user mode */
+ PROP_UTIME = "UTime",
+
+ /** The number of milliseconds that this process has been scheduled in kernel mode */
+ PROP_STIME = "STime",
+
+ /** The number of jiffies that this process's waited-for children have
+ * been scheduled in user mode */
+ PROP_CUTIME = "CUTime",
+
+ /** The number of jiffies that this process's waited-for children have
+ * been scheduled in user mode */
+ PROP_CSTIME = "CSTime",
+
+ /** The standard nice value */
+ PROP_PRIORITY = "Priority",
+
+ /** The nice value */
+ PROP_NICE = "Nice",
+
+ /** The time in milliseconds before the next SIGALRM is sent to the process
+ * due to an interval timer */
+ PROP_ITREALVALUE = "ITRealValue",
+
+ /** The time in milliseconds the process started after system boot */
+ PROP_STARTTIME = "StartTime",
+
+ /** Virtual memory size in bytes */
+ PROP_VSIZE = "VSize",
+
+ /** Memory pages size in bytes */
+ PROP_PSIZE = "PSize",
+
+ /** Resident Set Size: number of pages the process has in real memory,
+ * minus used for administrative purposes. This is just the pages which
+ * count towards text, data, or stack space. This does not include
+ * pages which have not been demand-loaded in, or which are swapped out */
+ PROP_RSS = "RSS",
+
+ /** Current limit in bytes on the rss of the process */
+ PROP_RLIMIT = "RLimit",
+
+ /** The address above which program text can run */
+ PROP_CODESTART = "CodeStart",
+
+ /** The address below which program text can run */
+ PROP_CODEEND = "CodeEnd",
+
+ /** The address of the start of the stack */
+ PROP_STACKSTART = "StackStart",
+
+ /** The bitmap of pending signals */
+ PROP_SIGNALS = "Signals",
+
+ /** The bitmap of blocked signals */
+ PROP_SIGBLOCK = "SigBlock",
+
+ /** The bitmap of ignored signals */
+ PROP_SIGIGNORE = "SigIgnore",
+
+ /** The bitmap of caught signals */
+ PROP_SIGCATCH = "SigCatch",
+
+ /** This is the "channel" in which the process is waiting. It is the
+ * address of a system call, and can be looked up in a name list if you
+ * need a textual name */
+ PROP_WCHAN = "WChan",
+
+ /** Number of pages swapped */
+ PROP_NSWAP = "NSwap",
+
+ /** Cumulative NSwap for child processes */
+ PROP_CNSWAP = "CNSwap",
+
+ /** Signal to be sent to parent when this process exits */
+ PROP_EXITSIGNAL = "ExitSignal",
+
+ /** CPU number last executed on */
+ PROP_PROCESSOR = "Processor",
+
+ /** Real-time scheduling priority */
+ PROP_RTPRIORITY = "RTPriority",
+
+ /** Scheduling policy */
+ PROP_POLICY = "Policy";
+
+
+ /**
+ * A context corresponds to an execution thread, process, address space, etc.
+ * A context can belong to a parent context. Contexts hierarchy can be simple
+ * plain list or it can form a tree. It is up to target agent developers to choose
+ * layout that is most descriptive for a given target. Context IDs are valid across
+ * all services. In other words, all services access same hierarchy of contexts,
+ * with same IDs, however, each service accesses its own subset of context's
+ * attributes and functionality, which is relevant to that service.
+ */
+ interface SysMonitorContext {
+
+ /**
+ * Get context ID.
+ * Same as getProperties().get(“ID”)
+ */
+ String getID();
+
+ /**
+ * Get parent context ID.
+ * Same as getProperties().get(“ParentID”)
+ */
+ String getParentID();
+
+ /**
+ * Get process group ID.
+ * Same as getProperties().get(“PGRP”)
+ */
+ long getPGRP();
+
+ /**
+ * Get process ID.
+ * Same as getProperties().get(“PID”)
+ */
+ long getPID();
+
+ /**
+ * Get process parent ID.
+ * Same as getProperties().get(“PPID”)
+ */
+ long getPPID();
+
+ /**
+ * Get process TTY group ID.
+ * Same as getProperties().get(“TGID”)
+ */
+ long getTGID();
+
+ /**
+ * Get tracer process ID.
+ * Same as getProperties().get(“TracerPID”)
+ */
+ long getTracerPID();
+
+ /**
+ * Get process owner user ID.
+ * Same as getProperties().get(“UID”)
+ */
+ long getUID();
+
+ /**
+ * Get process owner user name.
+ * Same as getProperties().get(“UserName”)
+ */
+ String getUserName();
+
+ /**
+ * Get process owner user group ID.
+ * Same as getProperties().get(“UGID”)
+ */
+ long getUGID();
+
+ /**
+ * Get process owner user group name.
+ * Same as getProperties().get(“GroupName”)
+ */
+ String getGroupName();
+
+ /**
+ * Get process state.
+ * Same as getProperties().get(“State”)
+ */
+ String getState();
+
+ /**
+ * Get process virtual memory size in bytes.
+ * Same as getProperties().get(“VSize”)
+ */
+ long getVSize();
+
+ /**
+ * Get process virtual memory page size in bytes.
+ * Same as getProperties().get(“PSize”)
+ */
+ long getPSize();
+
+ /**
+ * Get number of memory pages in process resident set.
+ * Same as getProperties().get(“RSS”)
+ */
+ long getRSS();
+
+ /**
+ * Get context executable file.
+ * Same as getProperties().get(“File”)
+ */
+ String getFile();
+
+ /**
+ * Get context current file system root.
+ * Same as getProperties().get(“Root”)
+ */
+ String getRoot();
+
+ /**
+ * Get context current working directory.
+ * Same as getProperties().get(“CWD”)
+ */
+ String getCurrentWorkingDirectory();
+
+ /**
+ * Get all available context properties.
+ * @return Map 'property name' -> 'property value'
+ */
+ Map<String,Object> getProperties();
+ }
+
+ /**
+ * Get context command line.
+ */
+ IToken getCommandLine(String id, DoneGetCommandLine done);
+
+ interface DoneGetCommandLine {
+ void doneGetCommandLine(IToken token, Exception error, String[] cmd_line);
+ }
+
+ /**
+ * Get context environment variables.
+ */
+ IToken getEnvironment(String id, DoneGetEnvironment done);
+
+ interface DoneGetEnvironment {
+ void doneGetEnvironment(IToken token, Exception error, String[] environment);
+ }
+}
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileInputStream.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileInputStream.java
new file mode 100644
index 000000000..da81ce5e0
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileInputStream.java
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IFileSystem;
+import com.windriver.tcf.api.services.IFileSystem.FileSystemException;
+import com.windriver.tcf.api.services.IFileSystem.IFileHandle;
+
+/**
+ * TCFFileInputStream is high performance InputStream implementation over TCF FileSystem service.
+ * The class uses read-ahead buffers to achieve maximum throughput.
+ */
+public final class TCFFileInputStream extends InputStream {
+
+ private static final int BUF_SIZE = 0x1000;
+ private static final int MAX_READ_AHEAD = 8;
+
+ private static class Buffer {
+
+ final long seq;
+
+ IToken token;
+ byte[] buf;
+ boolean eof;
+
+ Buffer(long seq) {
+ this.seq = seq;
+ }
+ }
+
+ private final IFileHandle handle;
+ private long mark = 0;
+ private Buffer buf;
+ private int buf_pos = 0;
+ private long buf_seq = 0;
+ private boolean closed = false;
+
+ private boolean suspend_read_ahead;
+ private Runnable waiting_client;
+ private final LinkedList<Buffer> read_ahead_buffers = new LinkedList<Buffer>();
+
+ public TCFFileInputStream(IFileHandle handle) {
+ this.handle = handle;
+ }
+
+ private void startReadAhead(Buffer prv) {
+ if (prv.eof) return;
+ if (suspend_read_ahead) return;
+ if (read_ahead_buffers.size() > 0) {
+ prv = read_ahead_buffers.getLast();
+ if (prv.eof) return;
+ }
+ long seq = prv.seq + 1;
+ while (read_ahead_buffers.size() < MAX_READ_AHEAD) {
+ final Buffer buf = new Buffer(seq);
+ IFileSystem fs = handle.getService();
+ buf.token = fs.read(handle, buf.seq * BUF_SIZE, BUF_SIZE, new IFileSystem.DoneRead() {
+ public void doneRead(IToken token, FileSystemException error,
+ byte[] data, boolean eof) {
+ assert buf.token == token;
+ assert read_ahead_buffers.contains(buf);
+ buf.token = null;
+ if (error == null) {
+ assert data != null && data.length <= BUF_SIZE;
+ assert eof || data.length == BUF_SIZE;
+ buf.buf = data;
+ buf.eof = eof;
+ startReadAhead(buf);
+ }
+ else {
+ suspend_read_ahead = true;
+ read_ahead_buffers.remove(buf);
+ }
+ if (waiting_client != null) {
+ Protocol.invokeLater(waiting_client);
+ waiting_client = null;
+ }
+ }
+ });
+ read_ahead_buffers.add(buf);
+ seq++;
+ }
+ }
+
+ private boolean stopReadAhead(Runnable done) {
+ suspend_read_ahead = true;
+ for (Iterator<Buffer> i = read_ahead_buffers.iterator(); i.hasNext();) {
+ Buffer buf = i.next();
+ if (buf.token == null || buf.token.cancel()) i.remove();
+ }
+ if (read_ahead_buffers.size() > 0) {
+ assert waiting_client == null;
+ waiting_client = done;
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public synchronized int read() throws IOException {
+ if (closed) throw new IOException("Stream is closed");
+ while (buf == null || buf_pos >= buf.buf.length) {
+ if (buf != null && buf.eof) return -1;
+ long offset = buf_seq * BUF_SIZE + buf_pos;
+ buf_seq = offset / BUF_SIZE;
+ buf_pos = (int)(offset % BUF_SIZE);
+ buf = new TCFTask<Buffer>() {
+ public void run() {
+ assert waiting_client == null;
+ while (read_ahead_buffers.size() > 0) {
+ Buffer buf = read_ahead_buffers.getFirst();
+ if (buf.seq == buf_seq) {
+ if (buf.token != null) {
+ waiting_client = this;
+ }
+ else {
+ read_ahead_buffers.remove(buf);
+ startReadAhead(buf);
+ done(buf);
+ }
+ return;
+ }
+ suspend_read_ahead = true;
+ if (buf.token != null && buf.token.cancel()) buf.token = null;
+ if (buf.token != null) {
+ waiting_client = this;
+ return;
+ }
+ read_ahead_buffers.remove(buf);
+ }
+ IFileSystem fs = handle.getService();
+ fs.read(handle, buf_seq * BUF_SIZE, BUF_SIZE, new IFileSystem.DoneRead() {
+ public void doneRead(IToken token, FileSystemException error,
+ byte[] data, boolean eof) {
+ if (error != null) {
+ error(error);
+ return;
+ }
+ assert data != null && data.length <= BUF_SIZE;
+ assert eof || data.length == BUF_SIZE;
+ Buffer buf = new Buffer(buf_seq);
+ buf.buf = data;
+ buf.eof = eof;
+ if (!eof) {
+ suspend_read_ahead = false;
+ startReadAhead(buf);
+ }
+ done(buf);
+ }
+ });
+ }
+ }.getIO();
+ assert buf.token == null;
+ assert buf.eof || buf.buf.length == BUF_SIZE;
+ }
+ assert buf.seq == buf_seq;
+ return buf.buf[buf_pos++] & 0xff;
+ }
+
+ @Override
+ public synchronized int read(final byte arr[], final int off, final int len) throws IOException {
+ if (closed) throw new IOException("Stream is closed");
+ if (arr == null) throw new NullPointerException();
+ if (off < 0 || len < 0 || len > arr.length - off) throw new IndexOutOfBoundsException();
+ int pos = 0;
+ while (pos < len) {
+ if (buf != null && buf_pos < buf.buf.length) {
+ int buf_len = buf.buf.length;
+ int n = len - pos < buf_len - buf_pos ? len - pos : buf_len - buf_pos;
+ System.arraycopy(buf.buf, buf_pos, arr, off + pos, n);
+ pos += n;
+ buf_pos += n;
+ }
+ else {
+ int c = read();
+ if (c == -1) {
+ if (pos == 0) return -1;
+ break;
+ }
+ arr[off + pos++] = (byte)c;
+ }
+ }
+ return pos;
+ }
+
+ @Override
+ public boolean markSupported() {
+ return true;
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ if (closed) throw new IOException("Stream is closed");
+ new TCFTask<Object>() {
+ public void run() {
+ if (!stopReadAhead(this)) return;
+ done(this);
+ }
+ }.getIO();
+ buf_seq = mark / BUF_SIZE;
+ buf_pos = (int)(mark % BUF_SIZE);
+ if (buf != null && buf.seq != buf_seq) buf = null;
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ mark = buf_seq * BUF_SIZE + buf_pos;
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ if (closed) return;
+ new TCFTask<Object>() {
+ public void run() {
+ if (!stopReadAhead(this)) return;
+ assert read_ahead_buffers.isEmpty();
+ IFileSystem fs = handle.getService();
+ fs.close(handle, new IFileSystem.DoneClose() {
+ public void doneClose(IToken token, FileSystemException error) {
+ if (error != null) error(error);
+ else done(this);
+ }
+ });
+ }
+ }.getIO();
+ closed = true;
+ buf_seq = 0;
+ buf_pos = 0;
+ buf = null;
+ }
+} \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileOutputStream.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileOutputStream.java
new file mode 100644
index 000000000..486e119e6
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFFileOutputStream.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.util;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IFileSystem;
+import com.windriver.tcf.api.services.IFileSystem.FileSystemException;
+import com.windriver.tcf.api.services.IFileSystem.IFileHandle;
+
+/**
+ * TCFFileOutputStream is high performance OutputStream implementation over TCF FileSystem service.
+ * The class uses write-back buffers to achieve maximum throughput.
+ */
+public final class TCFFileOutputStream extends OutputStream {
+
+ private static final int BUF_SIZE = 0x1000;
+ private static final int MAX_WRITE_BACK = 8;
+
+ private final IFileHandle handle;
+ private final Set<IToken> write_commands = new HashSet<IToken>();
+ private final int[] dirty = new int[1];
+ private final byte[] buf = new byte[BUF_SIZE];
+ private int buf_pos = 0;
+ private long offset = 0;
+ private IOException flush_error;
+ private boolean closed;
+
+ public TCFFileOutputStream(IFileHandle handle) {
+ this.handle = handle;
+ }
+
+ @Override
+ public synchronized void write(int b) throws IOException {
+ if (closed) throw new IOException("Stream is closed");
+ if (buf_pos == BUF_SIZE) flush();
+ buf[buf_pos++] = (byte)b;
+ }
+
+ @Override
+ public void write(byte b[], int off, int len) throws IOException {
+ if (len == 0) return;
+ if (b == null) throw new NullPointerException();
+ if (off < 0 || off > b.length || len < 0 ||
+ off + len > b.length || off + len < 0)
+ throw new IndexOutOfBoundsException();
+ while (len > 0) {
+ if (buf_pos == BUF_SIZE) flush();
+ if (buf_pos == 0 && len > BUF_SIZE) {
+ flush(b, off, len);
+ return;
+ }
+ int n = BUF_SIZE - buf_pos;
+ if (len < n) n = len;
+ System.arraycopy(b, off, buf, buf_pos, n);
+ off += n;
+ len -= n;
+ buf_pos += n;
+ }
+ }
+
+ @Override
+ public synchronized void flush() throws IOException {
+ if (buf_pos == 0) return;
+ flush(buf, 0, buf_pos);
+ buf_pos = 0;
+ }
+
+ private void flush(final byte[] buf, final int off, final int len) throws IOException {
+ synchronized (dirty) {
+ if (flush_error != null) throw flush_error;
+ while (dirty[0] >= MAX_WRITE_BACK) {
+ try {
+ dirty.wait();
+ }
+ catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ }
+ }
+ new TCFTask<Object>() {
+ public void run() {
+ IFileSystem fs = handle.getService();
+ write_commands.add(fs.write(handle, offset, buf, off, len, new IFileSystem.DoneWrite() {
+ public void doneWrite(IToken token, FileSystemException error) {
+ assert write_commands.contains(token);
+ write_commands.remove(token);
+ if (error != null) {
+ for (Iterator<IToken> i = write_commands.iterator(); i.hasNext();) {
+ if (i.next().cancel()) i.remove();
+ }
+ }
+ synchronized (dirty) {
+ if (error != null && flush_error == null) flush_error = error;
+ dirty[0] = write_commands.size();
+ dirty.notifyAll();
+ }
+ }
+ }));
+ synchronized (dirty) {
+ dirty[0] = write_commands.size();
+ }
+ done(this);
+ }
+ }.getIO();
+ offset += len;
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ if (closed) return;
+ flush();
+ synchronized (dirty) {
+ while (dirty[0] > 0) {
+ try {
+ dirty.wait();
+ }
+ catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ }
+ }
+ new TCFTask<Object>() {
+ public void run() {
+ IFileSystem fs = handle.getService();
+ fs.close(handle, new IFileSystem.DoneClose() {
+ public void doneClose(IToken token, FileSystemException error) {
+ if (error != null) error(error);
+ else done(this);
+ }
+ });
+ }
+ }.getIO();
+ closed = true;
+ }
+} \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFTask.java b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFTask.java
new file mode 100644
index 000000000..abda52d02
--- /dev/null
+++ b/plugins/com.windriver.tcf.api/src/com/windriver/tcf/api/util/TCFTask.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.api.util;
+
+import java.io.IOException;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import com.windriver.tcf.api.protocol.Protocol;
+
+public abstract class TCFTask<V> implements Runnable, Future<V> {
+
+ private V result;
+ private Throwable error;
+ private boolean canceled;
+
+ public TCFTask() {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ TCFTask.this.run();
+ }
+ catch (Throwable x) {
+ if (result == null && error == null) error(x);
+ }
+ }
+ });
+ }
+
+ public synchronized void done(V result) {
+ if (canceled) return;
+ assert Protocol.isDispatchThread();
+ assert this.error == null;
+ assert this.result == null;
+ this.result = result;
+ notifyAll();
+ }
+
+ public synchronized void error(Throwable error) {
+ assert Protocol.isDispatchThread();
+ if (canceled) return;
+ assert this.error == null;
+ assert this.result == null;
+ this.error = error;
+ //System.err.print("TCFTask exception: ");
+ //error.printStackTrace();
+ notifyAll();
+ }
+
+ public synchronized boolean cancel(boolean mayInterruptIfRunning) {
+ if (isDone()) return false;
+ canceled = true;
+ error = new CancellationException();
+ notifyAll();
+ return true;
+ }
+
+ public V get() throws InterruptedException, ExecutionException {
+ assert !Protocol.isDispatchThread();
+ synchronized (this) {
+ if (!isDone()) wait();
+ if (error instanceof ExecutionException) throw (ExecutionException)error;
+ if (error instanceof InterruptedException) throw (InterruptedException)error;
+ if (error != null) throw new ExecutionException(error);
+ return result;
+ }
+ }
+
+ public V getE() {
+ try {
+ return get();
+ }
+ catch (Throwable e) {
+ if (e instanceof Error) throw (Error)e;
+ throw new Error(e);
+ }
+ }
+
+ public V getIO() throws IOException {
+ try {
+ return get();
+ }
+ catch (Throwable e) {
+ if (e instanceof IOException) throw (IOException)e;
+ IOException y = new IOException();
+ y.initCause(e);
+ throw y;
+ }
+ }
+
+ public synchronized V get(long timeout, TimeUnit unit)
+ throws InterruptedException, ExecutionException, TimeoutException {
+ unit.toNanos(timeout);
+ // TODO Auto-generated method stub
+ assert false;
+ return null;
+ }
+
+ public synchronized boolean isCancelled() {
+ return canceled;
+ }
+
+ public synchronized boolean isDone() {
+ return canceled || error != null || result != null;
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.core/.classpath b/plugins/com.windriver.tcf.dsf.core/.classpath
new file mode 100644
index 000000000..751c8f2e5
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/com.windriver.tcf.dsf.core/.project b/plugins/com.windriver.tcf.dsf.core/.project
new file mode 100644
index 000000000..afac03b39
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>com.windriver.tcf.dsf.core</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/com.windriver.tcf.dsf.core/META-INF/MANIFEST.MF b/plugins/com.windriver.tcf.dsf.core/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..31b80627c
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: com.windriver.tcf.dsf.core;singleton:=true
+Bundle-Version: 0.1.0
+Bundle-Activator: com.windriver.tcf.dsf.core.Activator
+Bundle-Vendor: %providerName
+Require-Bundle: org.eclipse.core.runtime,
+ org.eclipse.debug.core,
+ org.eclipse.core.resources,
+ org.eclipse.dd.dsf,
+ org.eclipse.dd.dsf.debug,
+ com.windriver.tcf.api,
+ com.windriver.debug.tcf.core
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Eclipse-LazyStart: true
+Export-Package: com.windriver.tcf.dsf.core.launch,
+ com.windriver.tcf.dsf.core.services
diff --git a/plugins/com.windriver.tcf.dsf.core/about.html b/plugins/com.windriver.tcf.dsf.core/about.html
new file mode 100755
index 000000000..6c5b3615b
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>January 10, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.dsf.core/build.properties b/plugins/com.windriver.tcf.dsf.core/build.properties
new file mode 100644
index 000000000..e9863e281
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml
diff --git a/plugins/com.windriver.tcf.dsf.core/plugin.properties b/plugins/com.windriver.tcf.dsf.core/plugin.properties
new file mode 100644
index 000000000..250c86adf
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2007 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 implementation
+###############################################################################
+pluginName = TCF/DSF Integration Core
+providerName = Eclipse.org
+
diff --git a/plugins/com.windriver.tcf.dsf.core/plugin.xml b/plugins/com.windriver.tcf.dsf.core/plugin.xml
new file mode 100644
index 000000000..272eed3aa
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/plugin.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+ <extension
+ point="org.eclipse.debug.core.launchConfigurationTypes">
+ <launchConfigurationType
+ sourceLocatorId="com.windriver.debug.tcf.SourceLocator"
+ name="DSF over TCF"
+ sourcePathComputerId="com.windriver.debug.tcf.SourcePathComputer"
+ delegate="com.windriver.tcf.dsf.core.launch.TCFDSFLaunchDelegate"
+ modes="debug"
+ id="com.windriver.tcf.dsf.LaunchConfigurationType">
+ </launchConfigurationType>
+ </extension>
+</plugin>
diff --git a/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/Activator.java b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/Activator.java
new file mode 100644
index 000000000..e8153f7ef
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/Activator.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.core;
+
+import org.eclipse.core.runtime.Plugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends Plugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "com.windriver.tcf.dsf.core";
+
+ // The shared instance
+ private static Activator plugin;
+ private static BundleContext bundle_context;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ bundle_context = context;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ public static BundleContext getBundleContext() {
+ return bundle_context;
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFExecuter.java b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFExecuter.java
new file mode 100644
index 000000000..94b3cc18e
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFExecuter.java
@@ -0,0 +1,201 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.core.launch;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.TreeSet;
+import java.util.concurrent.AbstractExecutorService;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Delayed;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.dd.dsf.concurrent.DsfExecutor;
+
+import com.windriver.tcf.api.protocol.Protocol;
+
+public class TCFDSFExecuter extends AbstractExecutorService implements DsfExecutor {
+
+ private class ScheduledFutureTask<V> extends FutureTask<V> implements ScheduledFuture<V> {
+
+ private long time; // Milliseconds
+ private final int id;
+ private final long period; // Milliseconds
+
+ public ScheduledFutureTask(long delay, long period, Runnable runnable, V result) {
+ super(runnable, result);
+ time = System.currentTimeMillis() + delay;
+ id = sf_count++;
+ this.period = period;
+ }
+
+ public ScheduledFutureTask(long delay, Callable<V> callable) {
+ super(callable);
+ time = System.currentTimeMillis() + delay;
+ id = sf_count++;
+ period = 0;
+ }
+
+ public long getDelay(TimeUnit unit) {
+ return unit.convert(time - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
+ }
+
+ public int compareTo(Delayed o) {
+ if (o == this) return 0;
+ ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)o;
+ if (time < x.time) return -1;
+ if (time > x.time) return +1;
+ if (id < x.id) return -1;
+ if (id > x.id) return +1;
+ assert false;
+ return 0;
+ }
+
+ public void run() {
+ if (period == 0) {
+ super.run();
+ }
+ else {
+ boolean ok = super.runAndReset();
+ synchronized (TCFDSFExecuter.this) {
+ // Reschedule if not canceled and not shutdown
+ if (ok && !is_shutdown) {
+ time = period > 0 ? time + period : System.currentTimeMillis() - period;
+ queue.add(this);
+ notify();
+ }
+ }
+ }
+ }
+ }
+
+ private static int sf_count = 0;
+ private final TreeSet<ScheduledFutureTask<?>> queue = new TreeSet<ScheduledFutureTask<?>>();
+ private final Thread thread;
+ private boolean is_shutdown;
+ private boolean is_terminated;
+
+ public TCFDSFExecuter() {
+ thread = new Thread(new Runnable() {
+ public void run() {
+ synchronized (TCFDSFExecuter.this) {
+ try {
+ while (true) {
+ if (queue.isEmpty()) {
+ if (is_shutdown) break;
+ TCFDSFExecuter.this.wait();
+ }
+ else {
+ long time = System.currentTimeMillis();
+ ScheduledFutureTask<?> s = queue.first();
+ if (s.time <= time) {
+ queue.remove(s);
+ Protocol.invokeLater(s);
+ }
+ else {
+ TCFDSFExecuter.this.wait(s.time - time);
+ }
+ }
+ }
+ }
+ catch (Throwable x) {
+ x.printStackTrace();
+ }
+ is_terminated = true;
+ }
+ }
+ });
+ thread.setName("TCF Future Task Scheduler");
+ thread.start();
+ }
+
+ public boolean isInExecutorThread() {
+ return Protocol.isDispatchThread();
+ }
+
+ public synchronized ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+ if (command == null || unit == null) throw new NullPointerException();
+ if (is_shutdown) throw new RejectedExecutionException();
+ delay = unit.toMillis(delay);
+ ScheduledFutureTask<Boolean> s = new ScheduledFutureTask<Boolean>(delay, 0, command, Boolean.TRUE);
+ queue.add(s);
+ notify();
+ return s;
+ }
+
+ public synchronized <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+ if (callable == null || unit == null) throw new NullPointerException();
+ if (is_shutdown) throw new RejectedExecutionException();
+ delay = unit.toMillis(delay);
+ ScheduledFutureTask<V> s = new ScheduledFutureTask<V>(delay, callable);
+ queue.add(s);
+ notify();
+ return s;
+ }
+
+ public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
+ long initialDelay, long period, TimeUnit unit) {
+ if (command == null || unit == null) throw new NullPointerException();
+ if (is_shutdown) throw new RejectedExecutionException();
+ if (period <= 0) throw new RejectedExecutionException();
+ ScheduledFutureTask<Boolean> s = new ScheduledFutureTask<Boolean>(
+ unit.toMillis(initialDelay), unit.toMillis(period), command, Boolean.TRUE);
+ queue.add(s);
+ notify();
+ return s;
+ }
+
+ public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
+ long initialDelay, long delay, TimeUnit unit) {
+ if (command == null || unit == null) throw new NullPointerException();
+ if (is_shutdown) throw new RejectedExecutionException();
+ if (delay <= 0) throw new RejectedExecutionException();
+ ScheduledFutureTask<Boolean> s = new ScheduledFutureTask<Boolean>(
+ unit.toMillis(initialDelay), -unit.toMillis(delay), command, Boolean.TRUE);
+ queue.add(s);
+ notify();
+ return s;
+ }
+
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ thread.join(unit.toMillis(timeout));
+ return is_terminated;
+ }
+
+ public synchronized boolean isShutdown() {
+ return is_shutdown;
+ }
+
+ public synchronized boolean isTerminated() {
+ return is_terminated;
+ }
+
+ public synchronized void shutdown() {
+ is_shutdown = true;
+ notify();
+ }
+
+ public synchronized List<Runnable> shutdownNow() {
+ List<Runnable> res = new ArrayList<Runnable>(queue);
+ queue.clear();
+ is_shutdown = true;
+ notify();
+ return res;
+ }
+
+ public synchronized void execute(Runnable command) {
+ if (is_shutdown) throw new RejectedExecutionException();
+ Protocol.invokeLater(command);
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFLaunch.java b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFLaunch.java
new file mode 100644
index 000000000..f9535ce5e
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFLaunch.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.core.launch;
+
+import org.eclipse.dd.dsf.concurrent.DsfExecutor;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.debug.core.ILaunchConfiguration;
+
+import com.windriver.debug.tcf.core.model.ITCFConstants;
+import com.windriver.debug.tcf.core.model.TCFLaunch;
+
+public class TCFDSFLaunch extends TCFLaunch {
+
+ private final TCFDSFExecuter executor;
+ private final DsfSession session;
+
+ public TCFDSFLaunch(ILaunchConfiguration launchConfiguration, String mode) {
+ super(launchConfiguration, mode);
+ executor = new TCFDSFExecuter();
+ session = DsfSession.startSession(executor, ITCFConstants.ID_TCF_DEBUG_MODEL);
+ }
+
+ public DsfExecutor getDsfExecutor() {
+ return executor;
+ }
+
+ public DsfSession getSession() {
+ return session;
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFLaunchDelegate.java b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFLaunchDelegate.java
new file mode 100644
index 000000000..a672e46e4
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/launch/TCFDSFLaunchDelegate.java
@@ -0,0 +1,24 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.core.launch;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+
+import com.windriver.debug.tcf.core.launch.TCFLaunchDelegate;
+
+public class TCFDSFLaunchDelegate extends TCFLaunchDelegate {
+
+ public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) throws CoreException {
+ return new TCFDSFLaunch(configuration, mode);
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFExecutionDMC.java b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFExecutionDMC.java
new file mode 100644
index 000000000..b648df9dc
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFExecutionDMC.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.core.services;
+
+import org.eclipse.dd.dsf.datamodel.AbstractDMContext;
+import org.eclipse.dd.dsf.datamodel.IDMContext;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.dd.dsf.service.IDsfService;
+
+public abstract class TCFDSFExecutionDMC extends AbstractDMContext implements IExecutionDMContext, IContainerDMContext {
+
+ TCFDSFExecutionDMC(IDsfService service, IDMContext[] parents) {
+ super(service, parents);
+ }
+
+ public abstract String getTcfContextId();
+}
diff --git a/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFNativeProcesses.java b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFNativeProcesses.java
new file mode 100644
index 000000000..5c1235ae6
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFNativeProcesses.java
@@ -0,0 +1,332 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.core.services;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.dd.dsf.concurrent.RequestMonitor;
+import org.eclipse.dd.dsf.datamodel.IDMContext;
+import org.eclipse.dd.dsf.datamodel.ServiceDMContext;
+import org.eclipse.dd.dsf.debug.service.INativeProcesses;
+import org.eclipse.dd.dsf.service.AbstractDsfService;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.osgi.framework.BundleContext;
+
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.IProcesses;
+import com.windriver.tcf.api.services.IProcesses.ProcessContext;
+import com.windriver.tcf.dsf.core.Activator;
+
+public class TCFDSFNativeProcesses extends AbstractDsfService implements INativeProcesses {
+
+ private class ProcessDMC extends TCFDSFProcessDMC {
+
+ final String id;
+
+ ProcessDMC(String id) {
+ super(TCFDSFNativeProcesses.this, new IDMContext[0]);
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".context[" + id + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return super.baseEquals(obj) && ((ProcessDMC)obj).id.equals(id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+ }
+
+ private class ThreadDMC extends TCFDSFThreadDMC {
+
+ final String id;
+
+ ThreadDMC(String id) {
+ super(TCFDSFNativeProcesses.this, new IDMContext[0]);
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".context[" + id + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return super.baseEquals(obj) && ((ThreadDMC)obj).id.equals(id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+ }
+
+ private static class ProcessData implements IProcessDMData {
+
+ private final IProcesses.ProcessContext ctx;
+
+ ProcessData(IProcesses.ProcessContext ctx) {
+ this.ctx = ctx;
+ }
+
+ public IDMContext getDebugContext() {
+ // TODO Auto-generated method stub
+ assert false;
+ return null;
+ }
+
+ public String getId() {
+ return ctx.getID();
+ }
+
+ public String getName() {
+ return ctx.getName();
+ }
+
+ public boolean isDebuggerAttached() {
+ return ctx.isAttached();
+ }
+
+ public boolean isValid() {
+ return true;
+ }
+ }
+
+ private static class ThreadData implements IThreadDMData {
+
+ private final IProcesses.ProcessContext ctx;
+
+ ThreadData(IProcesses.ProcessContext ctx) {
+ this.ctx = ctx;
+ }
+
+ public IDMContext getDebugContext() {
+ // TODO Auto-generated method stub
+ assert false;
+ return null;
+ }
+
+ public String getId() {
+ return ctx.getID();
+ }
+
+ public String getName() {
+ return ctx.getName();
+ }
+
+ public boolean isDebuggerAttached() {
+ return ctx.isAttached();
+ }
+
+ public boolean isValid() {
+ return true;
+ }
+
+ }
+
+ final IProcesses service;
+ private IDMContext service_dmc;
+
+ TCFDSFNativeProcesses(DsfSession session, IChannel channel) {
+ super(session);
+ service = channel.getRemoteService(IProcesses.class);
+ service_dmc = new ServiceDMContext(this, "#native_process");
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return Activator.getBundleContext();
+ }
+
+ public IDMContext getServiceContext() {
+ return service_dmc;
+ }
+
+ public boolean isValid() {
+ return true;
+ }
+
+ public void attachDebuggerToProcess(IProcessDMContext ctx, RequestMonitor rm) {
+ // TODO Auto-generated method stub
+ assert false;
+ }
+
+ public void canTerminate(IDMContext ctx, DataRequestMonitor<Boolean> rm) {
+ // TODO Auto-generated method stub
+ assert false;
+ }
+
+ public void terminate(IDMContext ctx, RequestMonitor requestMonitor) {
+ // TODO Auto-generated method stub
+ assert false;
+ }
+
+ public void debugNewProcess(String file, DataRequestMonitor<IProcessDMContext> rm) {
+ // TODO Auto-generated method stub
+ assert false;
+ }
+
+ public void runNewProcess(String file, DataRequestMonitor<IProcessDMContext> rm) {
+ // TODO Auto-generated method stub
+ assert false;
+ }
+
+ public IProcessDMContext getProcessForDebugContext(IDMContext ctx) {
+ if (ctx instanceof IProcessDMContext) {
+ return (IProcessDMContext)ctx;
+ }
+ if (ctx instanceof TCFDSFExecutionDMC) {
+ String id = ((TCFDSFExecutionDMC)ctx).getTcfContextId();
+ return new ProcessDMC(id);
+ }
+ return null;
+ }
+
+ public IThreadDMContext getThreadForDebugContext(IDMContext ctx) {
+ if (ctx instanceof IThreadDMContext) {
+ return (IThreadDMContext)ctx;
+ }
+ if (ctx instanceof TCFDSFExecutionDMC) {
+ String id = ((TCFDSFExecutionDMC)ctx).getTcfContextId();
+ return new ThreadDMC(id);
+ }
+ return null;
+ }
+
+ public void getProcessesBeingDebugged(final DataRequestMonitor<IProcessDMContext[]> rm) {
+ final Collection<String> list = new ArrayList<String>();
+ final Set<IToken> cmds = new HashSet<IToken>();
+ final IProcesses.DoneGetChildren done = new IProcesses.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] context_ids) {
+ if (cmds.isEmpty()) return;
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ for (IToken t : cmds) t.cancel();
+ cmds.clear();
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$
+ rm.done();
+ }
+ else {
+ for (String id : context_ids) {
+ list.add(id);
+ cmds.add(service.getChildren(id, true, this));
+ }
+ if (cmds.isEmpty()) createDMContexts(list, rm);
+ }
+ }
+ };
+ cmds.add(service.getChildren(null, true, done));
+ }
+
+ public void getRunningProcesses(final DataRequestMonitor<IProcessDMContext[]> rm) {
+ final Collection<String> list = new ArrayList<String>();
+ final Set<IToken> cmds = new HashSet<IToken>();
+ final IProcesses.DoneGetChildren done = new IProcesses.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] context_ids) {
+ if (cmds.isEmpty()) return;
+ assert cmds.contains(token);
+ cmds.remove(token);
+ if (error != null) {
+ for (IToken t : cmds) t.cancel();
+ cmds.clear();
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$
+ rm.done();
+ }
+ else {
+ for (String id : context_ids) {
+ list.add(id);
+ cmds.add(service.getChildren(id, false, this));
+ }
+ if (cmds.isEmpty()) createDMContexts(list, rm);
+ }
+ }
+ };
+ cmds.add(service.getChildren(null, false, done));
+ }
+
+ @SuppressWarnings("unchecked")
+ public void getModelData(IDMContext dmc, final DataRequestMonitor<?> rm) {
+ if (dmc instanceof ProcessDMC) {
+ service.getContext(((ProcessDMC)dmc).id, new IProcesses.DoneGetContext() {
+
+ @SuppressWarnings("unchecked")
+ public void doneGetContext(IToken token, Exception error, ProcessContext context) {
+ if (error != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Data error", error)); //$NON-NLS-1$
+ }
+ else {
+ ((DataRequestMonitor<IProcessDMData>)rm).setData(new ProcessData(context));
+ }
+ rm.done();
+ }
+ });
+ }
+ else if (dmc instanceof ThreadDMC) {
+ service.getContext(((ProcessDMC)dmc).id, new IProcesses.DoneGetContext() {
+
+ @SuppressWarnings("unchecked")
+ public void doneGetContext(IToken token, Exception error, ProcessContext context) {
+ if (error != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Data error", error)); //$NON-NLS-1$
+ }
+ else {
+ ((DataRequestMonitor<IThreadDMData>)rm).setData(new ThreadData(context));
+ }
+ rm.done();
+ }
+ });
+ }
+ else if (dmc == service_dmc) {
+ ((DataRequestMonitor<TCFDSFNativeProcesses>)rm).setData(this);
+ rm.done();
+ }
+ else {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ private void createDMContexts(Collection<String> ids, DataRequestMonitor<IProcessDMContext[]> rm) {
+ assert false;
+ }
+
+ public void getProcessData(IProcessDMContext dmc,
+ DataRequestMonitor<IProcessDMData> rm) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void getThreadData(IThreadDMContext dmc, DataRequestMonitor<IThreadDMData> rm) {
+ // TODO Auto-generated method stub
+ assert false;
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFProcessDMC.java b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFProcessDMC.java
new file mode 100644
index 000000000..427fb92bf
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFProcessDMC.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.core.services;
+
+import org.eclipse.dd.dsf.datamodel.AbstractDMContext;
+import org.eclipse.dd.dsf.datamodel.IDMContext;
+import org.eclipse.dd.dsf.debug.service.INativeProcesses.IProcessDMContext;
+import org.eclipse.dd.dsf.service.IDsfService;
+
+public abstract class TCFDSFProcessDMC extends AbstractDMContext implements IProcessDMContext {
+
+ TCFDSFProcessDMC(IDsfService service, IDMContext[] parents) {
+ super(service, parents);
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFRunControl.java b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFRunControl.java
new file mode 100644
index 000000000..3564e25cf
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFRunControl.java
@@ -0,0 +1,829 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.core.services;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.dd.dsf.concurrent.RequestMonitor;
+import org.eclipse.dd.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.dd.dsf.datamodel.IDMContext;
+import org.eclipse.dd.dsf.datamodel.ServiceDMContext;
+import org.eclipse.dd.dsf.service.AbstractDsfService;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.osgi.framework.BundleContext;
+
+import com.windriver.tcf.dsf.core.Activator;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IRunControl;
+import com.windriver.tcf.api.services.IRunControl.RunControlContext;
+
+public class TCFDSFRunControl extends AbstractDsfService implements org.eclipse.dd.dsf.debug.service.IRunControl {
+
+ public static class SuspendedEvent extends AbstractDMEvent<IExecutionDMContext> implements ISuspendedDMEvent {
+
+ private final StateChangeReason reason;
+
+ public SuspendedEvent(IExecutionDMContext dmc, String reason) {
+ super(dmc);
+ this.reason = toStateChangeReason(reason);
+ }
+
+ public StateChangeReason getReason() {
+ return reason;
+ }
+ }
+
+ public static class ResumedEvent extends AbstractDMEvent<IExecutionDMContext> implements IResumedDMEvent {
+
+ public ResumedEvent(IExecutionDMContext dmc) {
+ super(dmc);
+ }
+
+ public StateChangeReason getReason() {
+ return StateChangeReason.USER_REQUEST;
+ }
+ }
+
+ public class ContainerSuspendedEvent extends AbstractDMEvent<IExecutionDMContext> implements IContainerSuspendedDMEvent {
+
+ private final String trigger_id;
+ private final StateChangeReason reason;
+
+ public ContainerSuspendedEvent(IExecutionDMContext dmc, String trigger_id, String reason) {
+ super(dmc);
+ this.trigger_id = trigger_id;
+ this.reason = toStateChangeReason(reason);
+ }
+
+ public IExecutionDMContext getTriggeringContext() {
+ return model.get(trigger_id);
+ }
+
+ public StateChangeReason getReason() {
+ return reason;
+ }
+ }
+
+ public static class ContainerResumedEvent extends AbstractDMEvent<IExecutionDMContext> implements IContainerResumedDMEvent {
+
+ public ContainerResumedEvent(IExecutionDMContext dmc) {
+ super(dmc);
+ }
+
+ public StateChangeReason getReason() {
+ return StateChangeReason.USER_REQUEST;
+ }
+ }
+
+ public static class StartedEvent extends AbstractDMEvent<IContainerDMContext> implements IStartedDMEvent {
+
+ private final IExecutionDMContext exe;
+
+ public StartedEvent(IContainerDMContext dmc, IExecutionDMContext exe) {
+ super(dmc);
+ this.exe = exe;
+ }
+
+ public IExecutionDMContext getExecutionContext() {
+ return exe;
+ }
+ }
+
+ public static class ChangedEvent extends AbstractDMEvent<IExecutionDMContext> {
+
+ public ChangedEvent(IExecutionDMContext dmc) {
+ super(dmc);
+ }
+ }
+
+ public static class ExitedEvent extends AbstractDMEvent<IContainerDMContext> implements IExitedDMEvent {
+
+ private final IExecutionDMContext exe;
+
+ public ExitedEvent(IContainerDMContext dmc, IExecutionDMContext exe) {
+ super(dmc);
+ this.exe = exe;
+ }
+
+ public IExecutionDMContext getExecutionContext() {
+ return exe;
+ }
+ }
+
+ private final com.windriver.tcf.api.services.IRunControl.RunControlListener run_listener =
+ new com.windriver.tcf.api.services.IRunControl.RunControlListener() {
+
+ public void containerResumed(String[] context_ids) {
+ for (String id : context_ids) {
+ ExecutionDMC n = model.get(id);
+ if (n != null) n.onContextResumed();
+ }
+ for (String id : context_ids) {
+ ExecutionDMC n = model.get(id);
+ if (n != null && n.ctx.isContainer()) {
+ getSession().dispatchEvent(new ContainerResumedEvent(n), getProperties());
+ }
+ }
+ }
+
+ public void containerSuspended(String trigger_id, String pc,
+ String reason, Map<String, Object> params,
+ String[] suspended_ids) {
+ if (trigger_id != null) {
+ ExecutionDMC n = model.get(trigger_id);
+ if (n != null) n.onContextSuspended(pc, reason, params);
+ }
+ for (String id : suspended_ids) {
+ if (id.equals(trigger_id)) continue;
+ ExecutionDMC n = model.get(id);
+ if (n != null) n.onContainerSuspended(reason);
+ }
+ for (String id : suspended_ids) {
+ ExecutionDMC n = model.get(id);
+ if (n != null && n.ctx.isContainer()) {
+ getSession().dispatchEvent(new ContainerSuspendedEvent(n, trigger_id, reason), getProperties());
+ }
+ }
+ }
+
+ public void contextAdded(RunControlContext[] contexts) {
+ for (RunControlContext ctx : contexts) {
+ ExecutionDMC n = model.get(ctx.getParentID());
+ if (n != null) n.onContextAdded(ctx);
+ }
+ }
+
+ public void contextChanged(RunControlContext[] contexts) {
+ for (RunControlContext ctx : contexts) {
+ ExecutionDMC n = model.get(ctx.getID());
+ if (n != null) n.onContextChanged(ctx);
+ }
+ }
+
+ public void contextException(String id, String msg) {
+ ExecutionDMC n = model.get(id);
+ if (n != null) n.onContextException(msg);
+ }
+
+ public void contextRemoved(String[] context_ids) {
+ for (String id : context_ids) {
+ ExecutionDMC n = model.get(id);
+ if (n != null) n.onContextRemoved();
+ }
+ }
+
+ public void contextResumed(String id) {
+ ExecutionDMC n = model.get(id);
+ if (n != null) n.onContextResumed();
+ }
+
+ public void contextSuspended(String id, String pc, String reason, Map<String, Object> params) {
+ ExecutionDMC n = model.get(id);
+ if (n != null) n.onContextSuspended(pc, reason, params);
+ }
+ };
+
+ private interface IDataRequest {
+ void cancel();
+ void done();
+ }
+
+ private static final int
+ VALID_CHILDREN = 4,
+ VALID_CONTEXT = 8,
+ VALID_STATE = 16,
+ VALID_ALL = VALID_CHILDREN | VALID_CONTEXT | VALID_STATE;
+
+ private class ExecutionDMC extends TCFDSFExecutionDMC {
+
+ final String id;
+ final ExecutionDMC parent;
+
+ final SortedMap<String,ExecutionDMC> children = new TreeMap<String,ExecutionDMC>();
+ final Map<String,ExecutionDMC> children_next = new HashMap<String,ExecutionDMC>();
+ final Collection<IDataRequest> node_wait_list = new ArrayList<IDataRequest>();
+
+ int valid;
+ Throwable error;
+ boolean disposed;
+ IToken command;
+
+ RunControlContext ctx;
+ int is_stepping;
+ int is_resuming;
+ boolean is_suspended;
+ boolean is_running;
+ String suspend_pc;
+ String suspend_reason;
+ String exception_msg;
+ Map<String,Object> suspend_params;
+
+ public ExecutionDMC(ExecutionDMC parent, String id) {
+ super(TCFDSFRunControl.this, parent == null ? null : new IDMContext[] { parent });
+ this.parent = parent;
+ this.id = id;
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".context[" + id + "]"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return super.baseEquals(obj) && ((ExecutionDMC)obj).id.equals(id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ @Override
+ public String getTcfContextId() {
+ return id;
+ }
+
+ void dispose() {
+ assert !disposed;
+ ExecutionDMC arr[] = children.values().toArray(new ExecutionDMC[children.size()]);
+ for (int i = 0; i < arr.length; i++) arr[i].dispose();
+ assert children.isEmpty();
+ if (parent != null) {
+ parent.children.remove(id);
+ parent.children_next.remove(id);
+ }
+ model.remove(id);
+ disposed = true;
+ }
+
+ void invalidateDMC(int flags) {
+ // cancel current data retrieval command
+ if (command != null) {
+ command.cancel();
+ command = null;
+ }
+
+ // cancel waiting requests
+ if (!node_wait_list.isEmpty()) {
+ IDataRequest[] arr = node_wait_list.toArray(new IDataRequest[node_wait_list.size()]);
+ node_wait_list.clear();
+ for (IDataRequest r : arr) r.cancel();
+ }
+
+ if ((flags & VALID_STATE) != 0) {
+ is_suspended = false;
+ is_running = false;
+ }
+
+ if ((flags & VALID_CHILDREN) != 0) {
+ children_next.clear();
+ for (ExecutionDMC n : children.values()) n.invalidateDMC(VALID_ALL);
+ }
+
+ if (flags == VALID_ALL) {
+ error = null;
+ }
+
+ valid &= ~flags;
+ }
+
+ boolean validateDMC(IDataRequest done) {
+ assert Protocol.isDispatchThread();
+ assert (valid & ~VALID_ALL) == 0;
+ assert parent == null || parent.children.get(id) == model.get(id);
+ if (channel.getState() != IChannel.STATE_OPEN) {
+ children_next.clear();
+ error = null;
+ command = null;
+ valid = VALID_ALL;
+ }
+ if (command != null) {
+ if (done != null) node_wait_list.add(done);
+ return false;
+ }
+ if (parent != null && parent.error != null) {
+ valid = VALID_ALL;
+ }
+ if ((valid & VALID_CONTEXT) == 0 && !validateRunControlContext(done)) return false;
+ if ((valid & VALID_STATE) == 0 && !validateRunControlState(done)) return false;
+ if ((valid & VALID_CHILDREN) == 0 && !validateRunControlChildren(done)) return false;
+ assert valid == VALID_ALL;
+ assert command == null;
+ ExecutionDMC[] a = children.values().toArray(new ExecutionDMC[children.size()]);
+ for (ExecutionDMC n : a) {
+ if (children_next.get(n.id) == null) n.dispose();
+ }
+ for (ExecutionDMC n : children_next.values()) {
+ if (children.get(n.id) == null) {
+ children.put(n.id, n);
+ model.put(n.id, n);
+ }
+ }
+ if (!node_wait_list.isEmpty()) {
+ IDataRequest[] arr = node_wait_list.toArray(new IDataRequest[node_wait_list.size()]);
+ node_wait_list.clear();
+ for (IDataRequest r : arr) r.done();
+ }
+ assert valid == VALID_ALL;
+ return true;
+ }
+
+ private boolean validateRunControlChildren(IDataRequest done) {
+ assert command == null;
+ if (tcf_run_service == null) {
+ valid |= VALID_CHILDREN;
+ return true;
+ }
+ if (done != null) node_wait_list.add(done);
+ command = tcf_run_service.getChildren(id, new IRunControl.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] contexts) {
+ if (command != token) return;
+ command = null;
+ if (error != null) {
+ ExecutionDMC.this.error = error;
+ }
+ else {
+ for (int i = 0; i < contexts.length; i++) {
+ String id = contexts[i];
+ ExecutionDMC node = model.get(id);
+ if (node == null) node = new ExecutionDMC(ExecutionDMC.this, id);
+ children_next.put(id, node);
+ }
+ }
+ valid |= VALID_CHILDREN;
+ validateDMC(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRunControlContext(IDataRequest done) {
+ assert command == null;
+ if (tcf_run_service == null) {
+ valid |= VALID_CONTEXT;
+ return true;
+ }
+ if (done != null) node_wait_list.add(done);
+ command = tcf_run_service.getContext(id, new IRunControl.DoneGetContext() {
+ public void doneGetContext(IToken token, Exception error, IRunControl.RunControlContext ctx) {
+ if (command != token) return;
+ command = null;
+ if (error != null) {
+ ExecutionDMC.this.error = error;
+ }
+ else {
+ ExecutionDMC.this.ctx = ctx;
+ }
+ valid |= VALID_CONTEXT;
+ validateDMC(null);
+ }
+ });
+ return false;
+ }
+
+ private boolean validateRunControlState(IDataRequest done) {
+ assert command == null;
+ if (ctx == null) {
+ valid |= VALID_STATE;
+ return true;
+ }
+ if (error != null || !ctx.hasState()) {
+ is_running = false;
+ is_suspended = false;
+ suspend_pc = null;
+ suspend_reason = null;
+ suspend_params = null;
+ valid |= VALID_STATE;
+ return true;
+ }
+ if (done != null) node_wait_list.add(done);
+ command = ctx.getState(new IRunControl.DoneGetState() {
+ public void doneGetState(IToken token, Exception error, boolean suspend, String pc, String reason, Map<String,Object> params) {
+ if (token != command) return;
+ command = null;
+ if (error != null) {
+ is_running = false;
+ is_suspended = false;
+ suspend_pc = null;
+ suspend_reason = null;
+ suspend_params = null;
+ ExecutionDMC.this.error = error;
+ }
+ else {
+ is_running = !suspend;
+ is_suspended = suspend;
+ if (suspend) {
+ suspend_pc = pc;
+ suspend_reason = reason;
+ suspend_params = params;
+ }
+ else {
+ suspend_pc = null;
+ suspend_reason = null;
+ suspend_params = null;
+ }
+ }
+ valid |= VALID_STATE;
+ validateDMC(null);
+ }
+ });
+ return false;
+ }
+
+ /*--------------------------------------------------------------------------------------*/
+ /* Events */
+
+ void onContextAdded(IRunControl.RunControlContext context) {
+ String id = context.getID();
+ assert !disposed;
+ assert children.get(id) == null;
+ ExecutionDMC n = new ExecutionDMC(this, id);
+ n.ctx = context;
+ n.valid |= VALID_CONTEXT;
+ children.put(id, n);
+ model.put(id, n);
+ getSession().dispatchEvent(new StartedEvent(this, n), getProperties());
+ }
+
+ void onContextChanged(IRunControl.RunControlContext context) {
+ assert !disposed;
+ ctx = context;
+ invalidateDMC(VALID_CHILDREN);
+ getSession().dispatchEvent(new ChangedEvent(this), getProperties());
+ }
+
+ void onContextRemoved() {
+ assert !disposed;
+ dispose();
+ getSession().dispatchEvent(new ExitedEvent(parent, this), getProperties());
+ }
+
+ void onContainerSuspended(String reason) {
+ assert !disposed;
+ if (ctx == null) return;
+ if (!ctx.hasState()) return;
+ invalidateDMC(VALID_STATE);
+ getSession().dispatchEvent(new SuspendedEvent(this, reason), getProperties());
+ }
+
+ void onContextSuspended(String pc, String reason, Map<String,Object> params) {
+ assert !disposed;
+ if (ctx == null) return;
+ assert ctx.hasState();
+ is_suspended = true;
+ suspend_pc = pc;
+ suspend_reason = reason;
+ suspend_params = params;
+ is_running = false;
+ valid |= VALID_STATE;
+ getSession().dispatchEvent(new SuspendedEvent(this, reason), getProperties());
+ }
+
+ void onContextResumed() {
+ assert !disposed;
+ if (ctx == null) return;
+ assert ctx.hasState();
+ exception_msg = null;
+ is_suspended = false;
+ suspend_pc = null;
+ suspend_reason = null;
+ suspend_params = null;
+ is_running = true;
+ valid |= VALID_STATE;
+ getSession().dispatchEvent(new ResumedEvent(this), getProperties());
+ }
+
+ void onContextException(String msg) {
+ assert !disposed;
+ exception_msg = msg;
+ }
+ }
+
+ private static class ExecutionData implements IExecutionDMData {
+
+ private final StateChangeReason reason;
+
+ ExecutionData(StateChangeReason reason) {
+ this.reason = reason;
+ }
+
+ public boolean isValid() {
+ return true;
+ }
+
+ public StateChangeReason getStateChangeReason() {
+ return reason;
+ }
+ }
+
+ private static StateChangeReason toStateChangeReason(String s) {
+ if (s == null) return StateChangeReason.UNKNOWN;
+ if (s.equals(com.windriver.tcf.api.services.IRunControl.REASON_USER_REQUEST)) return StateChangeReason.USER_REQUEST;
+ if (s.equals(com.windriver.tcf.api.services.IRunControl.REASON_STEP)) return StateChangeReason.STEP;
+ if (s.equals(com.windriver.tcf.api.services.IRunControl.REASON_BREAKPOINT)) return StateChangeReason.BREAKPOINT;
+ if (s.equals(com.windriver.tcf.api.services.IRunControl.REASON_EXCEPTION)) return StateChangeReason.EXCEPTION;
+ if (s.equals(com.windriver.tcf.api.services.IRunControl.REASON_CONTAINER)) return StateChangeReason.CONTAINER;
+ if (s.equals(com.windriver.tcf.api.services.IRunControl.REASON_WATCHPOINT)) return StateChangeReason.WATCHPOINT;
+ if (s.equals(com.windriver.tcf.api.services.IRunControl.REASON_SIGNAL)) return StateChangeReason.SIGNAL;
+ if (s.equals(com.windriver.tcf.api.services.IRunControl.REASON_SHAREDLIB)) return StateChangeReason.SHAREDLIB;
+ if (s.equals(com.windriver.tcf.api.services.IRunControl.REASON_ERROR)) return StateChangeReason.ERROR;
+ return StateChangeReason.UNKNOWN;
+ }
+
+ private final IChannel channel;
+ private final com.windriver.tcf.api.services.IRunControl tcf_run_service;
+ private final Map<String,ExecutionDMC> model = new HashMap<String,ExecutionDMC>();
+ private IDMContext service_dmc;
+
+ public TCFDSFRunControl(DsfSession session, IChannel channel) {
+ super(session);
+ this.channel = channel;
+ tcf_run_service = channel.getRemoteService(com.windriver.tcf.api.services.IRunControl.class);
+ if (tcf_run_service != null) tcf_run_service.addListener(run_listener);
+ service_dmc = new ServiceDMContext(this, "#run_control");
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return Activator.getBundleContext();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void getModelData(IDMContext dmc, final DataRequestMonitor<?> rm) {
+ if (dmc instanceof ExecutionDMC) {
+ final ExecutionDMC ctx = (ExecutionDMC)dmc;
+ IDataRequest done = new IDataRequest() {
+
+ public void cancel() {
+ rm.setCanceled(true);
+ rm.done();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void done() {
+ if (ctx.error != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Data error", ctx.error)); //$NON-NLS-1$
+ }
+ else {
+ ExecutionData dt = new ExecutionData(toStateChangeReason(ctx.suspend_reason));
+ ((DataRequestMonitor<IExecutionDMData>)rm).setData(dt);
+ }
+ rm.done();
+ }
+ };
+ if (ctx.validateDMC(done)) done.done();
+ }
+ else if (dmc == service_dmc) {
+ ((DataRequestMonitor<TCFDSFRunControl>)rm).setData(this);
+ rm.done();
+ }
+ else {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ public IDMContext getServiceContext() {
+ return service_dmc;
+ }
+
+ public boolean isValid() {
+ return true;
+ }
+
+ public IContainerDMContext getContainerDMC() {
+ // TODO: getContainerDMC()
+ assert false;
+ return null;
+ }
+
+ public boolean canInstructionStep(IDMContext context) {
+ if (context instanceof ExecutionDMC) {
+ ExecutionDMC x = (ExecutionDMC)context;
+ return x.ctx.canResume(com.windriver.tcf.api.services.IRunControl.RM_STEP_INTO);
+ }
+ return false;
+ }
+
+ public boolean canResume(IDMContext context) {
+ if (context instanceof ExecutionDMC) {
+ ExecutionDMC x = (ExecutionDMC)context;
+ return x.ctx.canResume(com.windriver.tcf.api.services.IRunControl.RM_RESUME);
+ }
+ return false;
+ }
+
+ public boolean canStep(IDMContext context) {
+ if (context instanceof ExecutionDMC) {
+ ExecutionDMC x = (ExecutionDMC)context;
+ return x.ctx.canResume(com.windriver.tcf.api.services.IRunControl.RM_STEP_OVER);
+ }
+ return false;
+ }
+
+ public boolean canSuspend(IDMContext context) {
+ if (context instanceof ExecutionDMC) {
+ ExecutionDMC x = (ExecutionDMC)context;
+ return x.ctx.canSuspend();
+ }
+ return false;
+ }
+
+ public void getExecutionContexts(IContainerDMContext context, final DataRequestMonitor<IExecutionDMContext[]> rm) {
+ if (context instanceof ExecutionDMC) {
+ final ExecutionDMC ctx = (ExecutionDMC)context;
+ IDataRequest done = new IDataRequest() {
+
+ public void cancel() {
+ rm.setCanceled(true);
+ rm.done();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void done() {
+ if (ctx.error != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Data error", ctx.error)); //$NON-NLS-1$
+ }
+ else {
+ rm.setData(ctx.children.values().toArray(new ExecutionDMC[ctx.children.size()]));
+ }
+ rm.done();
+ }
+ };
+ if (ctx.validateDMC(done)) done.done();
+ }
+ else {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ public void step(IDMContext context, StepType stepType, final RequestMonitor rm) {
+ if (context instanceof ExecutionDMC) {
+ final ExecutionDMC x = (ExecutionDMC)context;
+ int md = -1;
+ switch (stepType) {
+ case STEP_OVER:
+ md = com.windriver.tcf.api.services.IRunControl.RM_STEP_OVER_LINE;
+ break;
+ case STEP_INTO:
+ md = com.windriver.tcf.api.services.IRunControl.RM_STEP_INTO_LINE;
+ break;
+ case STEP_RETURN:
+ md = com.windriver.tcf.api.services.IRunControl.RM_STEP_OUT;
+ break;
+ }
+ if (md < 0) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ NOT_SUPPORTED, "Invalid step type", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ else {
+ x.ctx.resume(md, 1, new com.windriver.tcf.api.services.IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$
+ }
+ x.is_stepping--;
+ rm.done();
+ }
+ });
+ x.is_stepping++;
+ }
+ }
+ else {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ public void instructionStep(IDMContext context, StepType stepType, final RequestMonitor rm) {
+ if (context instanceof ExecutionDMC) {
+ final ExecutionDMC x = (ExecutionDMC)context;
+ int md = -1;
+ switch (stepType) {
+ case STEP_OVER:
+ md = com.windriver.tcf.api.services.IRunControl.RM_STEP_OVER;
+ break;
+ case STEP_INTO:
+ md = com.windriver.tcf.api.services.IRunControl.RM_STEP_INTO;
+ break;
+ case STEP_RETURN:
+ md = com.windriver.tcf.api.services.IRunControl.RM_STEP_OUT;
+ break;
+ }
+ if (md < 0) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ NOT_SUPPORTED, "Invalid step type", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ else {
+ x.ctx.resume(md, 1, new com.windriver.tcf.api.services.IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$
+ }
+ x.is_stepping--;
+ rm.done();
+ }
+ });
+ x.is_stepping++;
+ }
+ }
+ else {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ public boolean isStepping(IDMContext context) {
+ if (context instanceof ExecutionDMC) {
+ ExecutionDMC x = (ExecutionDMC)context;
+ return x.is_stepping > 0;
+ }
+ return false;
+ }
+
+ public void resume(IDMContext context, final RequestMonitor rm) {
+ if (context instanceof ExecutionDMC) {
+ final ExecutionDMC x = (ExecutionDMC)context;
+ x.ctx.resume(com.windriver.tcf.api.services.IRunControl.RM_RESUME, 1,
+ new com.windriver.tcf.api.services.IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$
+ }
+ x.is_resuming--;
+ rm.done();
+ }
+ });
+ x.is_resuming++;
+ }
+ else {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ public void suspend(IDMContext context, final RequestMonitor rm) {
+ if (context instanceof ExecutionDMC) {
+ final ExecutionDMC x = (ExecutionDMC)context;
+ x.ctx.suspend(new com.windriver.tcf.api.services.IRunControl.DoneCommand() {
+ public void doneCommand(IToken token, Exception error) {
+ if (error != null) {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ REQUEST_FAILED, "Command error", error)); //$NON-NLS-1$
+ }
+ rm.done();
+ }
+ });
+ }
+ else {
+ rm.setStatus(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
+ INVALID_HANDLE, "Unknown DMC type", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ public boolean isSuspended(IDMContext context) {
+ if (context instanceof ExecutionDMC) {
+ ExecutionDMC x = (ExecutionDMC)context;
+ return x.is_suspended && x.is_resuming == 0 && x.is_stepping == 0;
+ }
+ return false;
+ }
+
+ public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor<IExecutionDMData> rm) {
+ // TODO Auto-generated method stub
+ assert false;
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFThreadDMC.java b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFThreadDMC.java
new file mode 100644
index 000000000..ec91b6911
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.core/src/com/windriver/tcf/dsf/core/services/TCFDSFThreadDMC.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.core.services;
+
+import org.eclipse.dd.dsf.datamodel.AbstractDMContext;
+import org.eclipse.dd.dsf.datamodel.IDMContext;
+import org.eclipse.dd.dsf.debug.service.INativeProcesses.IThreadDMContext;
+import org.eclipse.dd.dsf.service.IDsfService;
+
+public abstract class TCFDSFThreadDMC extends AbstractDMContext implements IThreadDMContext {
+
+ public TCFDSFThreadDMC(IDsfService service, IDMContext[] parents) {
+ super(service, parents);
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.ui/.classpath b/plugins/com.windriver.tcf.dsf.ui/.classpath
new file mode 100644
index 000000000..751c8f2e5
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/com.windriver.tcf.dsf.ui/.project b/plugins/com.windriver.tcf.dsf.ui/.project
new file mode 100644
index 000000000..77c9739b6
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>com.windriver.tcf.dsf.ui</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/com.windriver.tcf.dsf.ui/META-INF/MANIFEST.MF b/plugins/com.windriver.tcf.dsf.ui/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..a4b898b02
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,20 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: com.windriver.tcf.dsf.ui;singleton:=true
+Bundle-Version: 0.1.0
+Bundle-Activator: com.windriver.tcf.dsf.ui.Activator
+Bundle-Vendor: %providerName
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.dd.dsf.debug,
+ org.eclipse.dd.dsf.debug.ui,
+ org.eclipse.dd.dsf,
+ org.eclipse.dd.dsf.ui,
+ org.eclipse.debug.ui,
+ com.windriver.tcf.api,
+ com.windriver.debug.tcf.core,
+ com.windriver.debug.tcf.ui,
+ com.windriver.tcf.dsf.core
+Eclipse-LazyStart: true
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/plugins/com.windriver.tcf.dsf.ui/about.html b/plugins/com.windriver.tcf.dsf.ui/about.html
new file mode 100755
index 000000000..6c5b3615b
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>January 10, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.dsf.ui/build.properties b/plugins/com.windriver.tcf.dsf.ui/build.properties
new file mode 100644
index 000000000..e9863e281
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml
diff --git a/plugins/com.windriver.tcf.dsf.ui/icons/tcf.gif b/plugins/com.windriver.tcf.dsf.ui/icons/tcf.gif
new file mode 100644
index 000000000..3198679ae
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/icons/tcf.gif
Binary files differ
diff --git a/plugins/com.windriver.tcf.dsf.ui/plugin.properties b/plugins/com.windriver.tcf.dsf.ui/plugin.properties
new file mode 100644
index 000000000..85a170935
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2007 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 implementation
+###############################################################################
+pluginName = TCF/DSF Integration UI
+providerName = Eclipse.org
+
diff --git a/plugins/com.windriver.tcf.dsf.ui/plugin.xml b/plugins/com.windriver.tcf.dsf.ui/plugin.xml
new file mode 100644
index 000000000..4da1ce1d0
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/plugin.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+
+ <extension point="com.windriver.debug.tcf.core.startup"/>
+
+ <extension point="org.eclipse.debug.ui.launchConfigurationTabGroups">
+ <launchConfigurationTabGroup
+ type="com.windriver.tcf.dsf.LaunchConfigurationType"
+ class="com.windriver.tcf.dsf.ui.LaunchDialogTabGroup"
+ id="org.eclipse.dd.dsf.mi.launch.localRunLaunchTabGroup">
+ </launchConfigurationTabGroup>
+ </extension>
+
+ <extension point="org.eclipse.debug.ui.launchConfigurationTypeImages">
+ <launchConfigurationTypeImage
+ icon="icons/tcf.gif"
+ configTypeID="com.windriver.tcf.dsf.LaunchConfigurationType"
+ id="com.windriver.tcf.dsf.LaunchImage">
+ </launchConfigurationTypeImage>
+ </extension>
+
+ <extension point="org.eclipse.core.runtime.adapters">
+ <factory
+ class="com.windriver.tcf.dsf.ui.AdapterFactory"
+ adaptableType="com.windriver.tcf.dsf.core.launch.TCFDSFLaunch">
+ <adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider"/>
+ <adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider"/>
+ <adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory"/>
+ <adapter type="org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory"/>
+ <adapter type="org.eclipse.debug.core.commands.ITerminateHandler"/>
+ </factory>
+ </extension>
+
+</plugin>
diff --git a/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/Activator.java b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/Activator.java
new file mode 100644
index 000000000..f37328701
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/Activator.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.ui;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "com.windriver.tcf.dsf.ui";
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/AdapterFactory.java b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/AdapterFactory.java
new file mode 100644
index 000000000..f8d0604f8
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/AdapterFactory.java
@@ -0,0 +1,207 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.ui;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.dd.dsf.concurrent.Immutable;
+import org.eclipse.dd.dsf.debug.ui.actions.DsfResumeCommand;
+import org.eclipse.dd.dsf.debug.ui.actions.DsfStepIntoCommand;
+import org.eclipse.dd.dsf.debug.ui.actions.DsfStepOverCommand;
+import org.eclipse.dd.dsf.debug.ui.actions.DsfStepReturnCommand;
+import org.eclipse.dd.dsf.debug.ui.actions.DsfSuspendCommand;
+import org.eclipse.dd.dsf.debug.ui.actions.DsfTerminateCommand;
+import org.eclipse.dd.dsf.debug.ui.sourcelookup.MISourceDisplayAdapter;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchesListener2;
+import org.eclipse.debug.core.commands.IResumeHandler;
+import org.eclipse.debug.core.commands.IStepIntoHandler;
+import org.eclipse.debug.core.commands.IStepOverHandler;
+import org.eclipse.debug.core.commands.IStepReturnHandler;
+import org.eclipse.debug.core.commands.ISuspendHandler;
+import org.eclipse.debug.core.commands.ITerminateHandler;
+import org.eclipse.debug.core.model.IDebugModelProvider;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementContentProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelProxyFactory;
+import org.eclipse.debug.ui.sourcelookup.ISourceDisplay;
+
+import com.windriver.debug.tcf.core.model.ITCFConstants;
+import com.windriver.tcf.dsf.core.launch.TCFDSFLaunch;
+
+@SuppressWarnings("restriction")
+public class AdapterFactory implements IAdapterFactory, DsfSession.SessionEndedListener, ILaunchesListener2 {
+
+ @Immutable
+ private final class SessionAdapterSet {
+
+ private final DsfSession fSession;
+ final ViewModelAdapter fViewModelAdapter;
+ final MISourceDisplayAdapter fSourceDisplayAdapter;
+ final DsfStepIntoCommand fStepIntoCommand;
+ final DsfStepOverCommand fStepOverCommand;
+ final DsfStepReturnCommand fStepReturnCommand;
+ final DsfSuspendCommand fSuspendCommand;
+ final DsfResumeCommand fResumeCommand;
+ final DsfTerminateCommand fTerminateCommand;
+ final IDebugModelProvider fDebugModelProvider;
+ final TCFDSFLaunch fLaunch;
+
+ SessionAdapterSet(DsfSession session, TCFDSFLaunch launch) {
+ fSession = session;
+
+ fViewModelAdapter = new ViewModelAdapter(session, launch);
+
+ if (launch.getSourceLocator() instanceof ISourceLookupDirector) {
+ fSourceDisplayAdapter = new MISourceDisplayAdapter(session, (ISourceLookupDirector)launch.getSourceLocator());
+ } else {
+ fSourceDisplayAdapter = null;
+ }
+ session.registerModelAdapter(ISourceDisplay.class, fSourceDisplayAdapter);
+
+ fStepIntoCommand = new DsfStepIntoCommand(session);
+ fStepOverCommand = new DsfStepOverCommand(session);
+ fStepReturnCommand = new DsfStepReturnCommand(session);
+ fSuspendCommand = new DsfSuspendCommand(session);
+ fResumeCommand = new DsfResumeCommand(session);
+ fTerminateCommand = new DsfTerminateCommand(session);
+ session.registerModelAdapter(IStepIntoHandler.class, fStepIntoCommand);
+ session.registerModelAdapter(IStepOverHandler.class, fStepOverCommand);
+ session.registerModelAdapter(IStepReturnHandler.class, fStepReturnCommand);
+ session.registerModelAdapter(ISuspendHandler.class, fSuspendCommand);
+ session.registerModelAdapter(IResumeHandler.class, fResumeCommand);
+ session.registerModelAdapter(ITerminateHandler.class, fTerminateCommand);
+
+ fDebugModelProvider = new IDebugModelProvider() {
+ // @see org.eclipse.debug.core.model.IDebugModelProvider#getModelIdentifiers()
+ public String[] getModelIdentifiers() {
+ return new String[] { ITCFConstants.ID_TCF_DEBUG_MODEL };
+ }
+ };
+ session.registerModelAdapter(IDebugModelProvider.class, fDebugModelProvider);
+
+ fLaunch = launch;
+
+ /*
+ * Registering the launch as an adapter, ensures that this launch,
+ * and debug model ID will be associated with all DMContexts from this
+ * session.
+ */
+ session.registerModelAdapter(ILaunch.class, fLaunch);
+ }
+
+ void dispose() {
+ fViewModelAdapter.dispose();
+
+ fSession.unregisterModelAdapter(ISourceDisplay.class);
+ if (fSourceDisplayAdapter != null) fSourceDisplayAdapter.dispose();
+
+ fSession.unregisterModelAdapter(IStepIntoHandler.class);
+ fSession.unregisterModelAdapter(IStepOverHandler.class);
+ fSession.unregisterModelAdapter(IStepReturnHandler.class);
+ fSession.unregisterModelAdapter(ISuspendHandler.class);
+ fSession.unregisterModelAdapter(IResumeHandler.class);
+ fSession.unregisterModelAdapter(ITerminateHandler.class);
+ fStepIntoCommand.dispose();
+ fStepOverCommand.dispose();
+ fStepReturnCommand.dispose();
+ fSuspendCommand.dispose();
+ fResumeCommand.dispose();
+ fTerminateCommand.dispose();
+ }
+ }
+
+ @SuppressWarnings({ "unchecked", "restriction" })
+ private final Class[] adapter_list = {
+ IElementLabelProvider.class,
+ IElementContentProvider.class,
+ IColumnPresentationFactory.class,
+ IModelProxyFactory.class,
+ ITerminateHandler.class
+ };
+
+ private Map<String,SessionAdapterSet> fSessionAdapterSetMap =
+ Collections.synchronizedMap(new HashMap<String,SessionAdapterSet>());
+
+ public AdapterFactory() {
+ DsfSession.addSessionEndedListener(this);
+ DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
+ }
+
+ @SuppressWarnings({ "restriction", "unchecked" })
+ public Object getAdapter(Object adaptableObject, Class adapterType) {
+ if (!(adaptableObject instanceof TCFDSFLaunch)) return null;
+
+ TCFDSFLaunch launch = (TCFDSFLaunch)adaptableObject;
+
+ // Find the correct set of adapters based on the launch session-ID. If not found
+ // it means that we have a new launch and new session, and we have to create a
+ // new set of adapters.
+ DsfSession session = launch.getSession();
+ if (session == null) return null;
+
+ SessionAdapterSet adapter_set;
+ synchronized(fSessionAdapterSetMap) {
+ adapter_set = fSessionAdapterSetMap.get(session.getId());
+ if (adapter_set == null) {
+ adapter_set = new SessionAdapterSet(session, launch);
+ fSessionAdapterSetMap.put(session.getId(), adapter_set);
+ }
+ }
+
+ // Returns the adapter type for the launch object.
+ if (adapterType.equals(IElementLabelProvider.class)) return adapter_set.fViewModelAdapter;
+ if (adapterType.equals(IElementContentProvider.class)) return adapter_set.fViewModelAdapter;
+ if (adapterType.equals(IModelProxyFactory.class)) return adapter_set.fViewModelAdapter;
+ if (adapterType.equals(IColumnPresentationFactory.class)) return adapter_set.fViewModelAdapter;
+ if (adapterType.equals(ITerminateHandler.class)) return adapter_set.fTerminateCommand;
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Class[] getAdapterList() {
+ return adapter_list;
+ }
+
+ public void sessionEnded(DsfSession session) {
+ }
+
+ public void launchesTerminated(ILaunch[] launches) {
+ }
+
+ public void launchesAdded(ILaunch[] launches) {
+ }
+
+ public void launchesChanged(ILaunch[] launches) {
+ }
+
+ public void launchesRemoved(ILaunch[] launches) {
+ // Dispose the set of adapters for a launch only after the launch is removed.
+ for (ILaunch launch : launches) {
+ if (launch instanceof TCFDSFLaunch) {
+ DsfSession session = ((TCFDSFLaunch)launch).getSession();
+ synchronized (fSessionAdapterSetMap) {
+ if (fSessionAdapterSetMap.containsKey(session.getId())) {
+ fSessionAdapterSetMap.get(session.getId()).dispose();
+ fSessionAdapterSetMap.remove(session);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ContainerLayoutNode.java b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ContainerLayoutNode.java
new file mode 100644
index 000000000..31d80eba3
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ContainerLayoutNode.java
@@ -0,0 +1,82 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Ericsson 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:
+ * Ericsson - Initial API and implementation
+ * Wind River Systems - reused for TCF connection type
+ *******************************************************************************/
+
+package com.windriver.tcf.dsf.ui;
+
+import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.dd.dsf.debug.service.INativeProcesses;
+import org.eclipse.dd.dsf.debug.service.IRunControl;
+import org.eclipse.dd.dsf.debug.service.INativeProcesses.IProcessDMData;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+import com.windriver.tcf.dsf.core.services.TCFDSFRunControl;
+
+@SuppressWarnings("restriction")
+public class ContainerLayoutNode extends AbstractDMVMLayoutNode{
+
+ public ContainerLayoutNode(AbstractVMProvider provider, DsfSession session) {
+ super(provider, session, IRunControl.IExecutionDMContext.class);
+ }
+
+ @Override
+ protected void updateElementsInSessionThread(IChildrenUpdate update) {
+ if (!checkService(IRunControl.class, null, update)) return;
+
+ IContainerDMContext containerCtx = getServicesTracker().getService(TCFDSFRunControl.class).getContainerDMC();
+ update.setChild(new DMVMContext(containerCtx), 0);
+ update.done();
+ }
+
+ @Override
+ // Labels are only updated for elements that are visible.
+ protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
+ for (final ILabelUpdate update : updates) {
+ if (!checkService(IRunControl.class, null, update)) continue;
+ if (!checkService(INativeProcesses.class, null, update)) continue;
+
+ final IContainerDMContext dmc = findDmcInPath(update.getElementPath(), IContainerDMContext.class);
+
+ INativeProcesses processes = getServicesTracker().getService(INativeProcesses.class);
+
+ String imageKey = null;
+
+ if (getServicesTracker().getService(IRunControl.class).isSuspended(dmc)) {
+ imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;
+ } else {
+ imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING;
+ }
+ update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
+
+ processes.getProcessData(
+ processes.getProcessForDebugContext(dmc),
+ new DataRequestMonitor<IProcessDMData>(getSession().getExecutor(), null) {
+ @SuppressWarnings("restriction")
+ @Override
+ public void handleCompleted() {
+ if (!getStatus().isOK()) {
+ update.done();
+ return;
+ }
+ update.setLabel(getData().getName(), 0);
+ update.done();
+ }
+ });
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/LaunchDialogTabGroup.java b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/LaunchDialogTabGroup.java
new file mode 100644
index 000000000..9a7d62dcc
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/LaunchDialogTabGroup.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.ui;
+
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
+import org.eclipse.debug.ui.CommonTab;
+import org.eclipse.debug.ui.EnvironmentTab;
+import org.eclipse.debug.ui.ILaunchConfigurationDialog;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+import org.eclipse.debug.ui.sourcelookup.SourceLookupTab;
+
+import com.windriver.debug.tcf.ui.launch.TCFArgumentsTab;
+import com.windriver.debug.tcf.ui.launch.TCFMainTab;
+
+/**
+ * Launch configuration dialog tab group for TCF over DSF
+ */
+public class LaunchDialogTabGroup extends AbstractLaunchConfigurationTabGroup {
+
+ public void createTabs(ILaunchConfigurationDialog dialog, String mode) {
+ setTabs(new ILaunchConfigurationTab[] {
+ new TCFMainTab(),
+ new TCFArgumentsTab(),
+ new EnvironmentTab(),
+ new SourceLookupTab(),
+ new CommonTab()
+ });
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/LaunchVMProvider.java b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/LaunchVMProvider.java
new file mode 100644
index 000000000..caf259806
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/LaunchVMProvider.java
@@ -0,0 +1,161 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.ui;
+
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.dd.dsf.concurrent.ThreadSafe;
+import org.eclipse.dd.dsf.debug.ui.viewmodel.launch.StackFramesLayoutNode;
+import org.eclipse.dd.dsf.debug.ui.viewmodel.launch.StandardLaunchRootLayoutNode;
+import org.eclipse.dd.dsf.debug.ui.viewmodel.launch.StandardProcessLayoutNode;
+import org.eclipse.dd.dsf.debug.ui.viewmodel.launch.StandardLaunchRootLayoutNode.LaunchesEvent;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
+import org.eclipse.dd.dsf.ui.viewmodel.IVMRootLayoutNode;
+import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IDebugEventSetListener;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchesListener2;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+
+@SuppressWarnings("restriction")
+public class LaunchVMProvider extends AbstractDMVMProvider
+ implements IDebugEventSetListener, ILaunchesListener2 {
+
+ @ThreadSafe
+ public LaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext,
+ DsfSession session, ILaunch launch)
+ {
+ super(adapter, presentationContext, session);
+
+ IVMRootLayoutNode launchNode = new StandardLaunchRootLayoutNode(this, launch);
+ // Container node to contain all processes and threads
+ IVMLayoutNode containerNode = new ContainerLayoutNode(this, getSession());
+ IVMLayoutNode processesNode = new StandardProcessLayoutNode(this);
+ launchNode.setChildNodes(new IVMLayoutNode[] { containerNode, processesNode});
+
+ IVMLayoutNode threadsNode = new ThreadLayoutNode(this, getSession());
+ containerNode.setChildNodes(new IVMLayoutNode[] { threadsNode });
+
+ IVMLayoutNode stackFramesNode = new StackFramesLayoutNode(this, getSession());
+ threadsNode.setChildNodes(new IVMLayoutNode[] { stackFramesNode });
+
+ setRootLayoutNode(launchNode);
+
+ DebugPlugin.getDefault().addDebugEventListener(this);
+ DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
+ }
+
+
+ public void handleDebugEvents(final DebugEvent[] events) {
+ if (isDisposed()) return;
+
+ // We're in session's executor thread. Re-dispach to VM Adapter
+ // executor thread and then call root layout node.
+ try {
+ getExecutor().execute(new Runnable() {
+ public void run() {
+ if (isDisposed()) return;
+
+ for (final DebugEvent event : events) {
+ IVMRootLayoutNode rootLayoutNode = getRootLayoutNode();
+ if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) {
+ rootLayoutNode.createDelta(
+ event,
+ new DataRequestMonitor<IModelDelta>(getExecutor(), null) {
+ @Override
+ public void handleCompleted() {
+ if (getStatus().isOK()) {
+ getModelProxy().fireModelChangedNonDispatch(getData());
+ }
+ }
+ @Override
+ public String toString() {
+ return "Result of a delta for debug event: '" + event.toString() +
+ "' in VMP: '" + LaunchVMProvider.this + "'" +
+ "\n" + getData();
+ }
+ });
+ }
+ }
+ }});
+ }
+ catch (RejectedExecutionException e) {
+ // Ignore. This exception could be thrown if the provider is being
+ // shut down.
+ }
+ }
+
+ @Override
+ public void dispose() {
+ DebugPlugin.getDefault().removeDebugEventListener(this);
+ DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this);
+ super.dispose();
+ }
+
+ public void launchesAdded(ILaunch[] launches) {
+ handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.ADDED));
+ }
+
+ public void launchesRemoved(ILaunch[] launches) {
+ handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.REMOVED));
+ }
+
+ public void launchesChanged(ILaunch[] launches) {
+ handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.CHANGED));
+ }
+
+ public void launchesTerminated(ILaunch[] launches) {
+ handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.TERMINATED));
+ }
+
+ private void handleLaunchesEvent(final LaunchesEvent event) {
+ if (isDisposed()) return;
+
+ // We're in session's executor thread. Re-dispach to VM Adapter
+ // executor thread and then call root layout node.
+ try {
+ getExecutor().execute(new Runnable() {
+ public void run() {
+ if (isDisposed()) return;
+
+ IVMRootLayoutNode rootLayoutNode = getRootLayoutNode();
+ if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) {
+ rootLayoutNode.createDelta(
+ event,
+ new DataRequestMonitor<IModelDelta>(getExecutor(), null) {
+ @Override
+ public void handleCompleted() {
+ if (getStatus().isOK()) {
+ getModelProxy().fireModelChangedNonDispatch(getData());
+ }
+ }
+ @Override public String toString() {
+ return "Result of a delta for launch event: '" + event.toString() +
+ "' in VMP: '" + LaunchVMProvider.this + "'" +
+ "\n" + getData();
+ }
+ });
+ }
+ }});
+ }
+ catch (RejectedExecutionException e) {
+ // Ignore. This exception could be thrown if the provider is being
+ // shut down.
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ThreadLayoutNode.java b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ThreadLayoutNode.java
new file mode 100644
index 000000000..54ef832fc
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ThreadLayoutNode.java
@@ -0,0 +1,197 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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
+ * Ericsson - Modified for multi threaded functionality
+ *******************************************************************************/
+package com.windriver.tcf.dsf.ui;
+
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.dd.dsf.concurrent.RequestMonitor;
+import org.eclipse.dd.dsf.datamodel.IDMEvent;
+import org.eclipse.dd.dsf.debug.service.INativeProcesses;
+import org.eclipse.dd.dsf.debug.service.IRunControl;
+import org.eclipse.dd.dsf.debug.service.INativeProcesses.IThreadDMData;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMData;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IExitedDMEvent;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IStartedDMEvent;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMProvider;
+import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
+import org.eclipse.dd.dsf.ui.viewmodel.IVMLayoutNode;
+import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMLayoutNode;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+
+import com.windriver.tcf.dsf.core.services.TCFDSFExecutionDMC;
+
+@SuppressWarnings("restriction")
+public class ThreadLayoutNode extends AbstractDMVMLayoutNode {
+
+ public ThreadLayoutNode(AbstractVMProvider provider, DsfSession session) {
+ super(provider, session, IRunControl.IExecutionDMContext.class);
+ }
+
+ @Override
+ protected void updateElementsInSessionThread(final IChildrenUpdate update) {
+ if (!checkService(IRunControl.class, null, update)) return;
+ final IContainerDMContext contDmc = findDmcInPath(update.getElementPath(), IContainerDMContext.class);
+
+ if (contDmc == null) {
+ handleFailedUpdate(update);
+ return;
+ }
+
+ getServicesTracker().getService(IRunControl.class).getExecutionContexts(contDmc,
+ new DataRequestMonitor<IExecutionDMContext[]>(getSession().getExecutor(), null){
+ @Override
+ public void handleCompleted() {
+ if (!getStatus().isOK()) {
+ handleFailedUpdate(update);
+ return;
+ }
+ fillUpdateWithVMCs(update, getData());
+ update.done();
+ }
+ });
+ }
+
+ @Override
+ protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
+ for (final ILabelUpdate update : updates) {
+ if (!checkService(IRunControl.class, null, update)) continue;
+ if (!checkService(INativeProcesses.class, null, update)) continue;
+
+ final IExecutionDMContext dmc = findDmcInPath(update.getElementPath(), IExecutionDMContext.class);
+
+ INativeProcesses processes = getServicesTracker().getService(INativeProcesses.class);
+
+ String imageKey = null;
+ if (getServicesTracker().getService(IRunControl.class).isSuspended(dmc)) {
+ imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;
+ }
+ else {
+ imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING;
+ }
+ update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
+
+ // Find the Reason for the State
+ final StringBuilder reason = new StringBuilder();
+ getServicesTracker().getService(IRunControl.class).getExecutionData(dmc,
+ new DataRequestMonitor<IExecutionDMData>(getSession().getExecutor(), null) {
+ @Override
+ public void handleCompleted(){
+ if (!getStatus().isOK()) {
+ update.done();
+ return;
+ }
+ if(getData().getStateChangeReason() != null){
+ reason.append(": " + getData().getStateChangeReason() ); //$NON-NLS-1$
+ }
+ }
+ });
+
+ getServicesTracker().getService(INativeProcesses.class).getThreadData(
+ processes.getThreadForDebugContext(dmc),
+ new DataRequestMonitor<IThreadDMData>(getSession().getExecutor(), null) {
+ @Override
+ public void handleCompleted() {
+ if (!getStatus().isOK()) {
+ update.done();
+ return;
+ }
+ final StringBuilder builder = new StringBuilder("Thread["); //$NON-NLS-1$
+ builder.append(((TCFDSFExecutionDMC)dmc).getTcfContextId());
+ builder.append("] "); //$NON-NLS-1$
+ builder.append(getData().getId());
+ builder.append(getData().getName());
+ if(getServicesTracker().getService(IRunControl.class).isSuspended(dmc))
+ builder.append(" (Suspended"); //$NON-NLS-1$
+ else
+ builder.append(" (Running"); //$NON-NLS-1$
+ // Reason will be null before ContainerSuspendEvent is fired
+ if(reason.length() > 0 )
+ builder.append(reason);
+ builder.append(")"); //$NON-NLS-1$
+ update.setLabel(builder.toString(), 0);
+ update.done();
+ }
+ });
+ }
+ }
+
+ @Override
+ protected int getNodeDeltaFlagsForDMEvent(IDMEvent<?> e) {
+ if(e instanceof IRunControl.IContainerResumedDMEvent || e instanceof IRunControl.IContainerSuspendedDMEvent || e instanceof IStartedDMEvent || e instanceof IExitedDMEvent) {
+ return IModelDelta.CONTENT;
+ }
+ if(e instanceof IRunControl.IResumedDMEvent || e instanceof IRunControl.ISuspendedDMEvent) {
+ return IModelDelta.STATE;
+ }
+ return IModelDelta.NO_CHANGE;
+ }
+
+ @Override
+ protected void buildDeltaForDMEvent(final IDMEvent<?> e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
+ if(e instanceof IRunControl.IContainerResumedDMEvent || e instanceof IRunControl.IContainerSuspendedDMEvent) {
+ // Since IContainerDMContext sub-classes IExecutionDMContext, container
+ // events require special processing:
+ // Retrieve all the thread elements and mark their state as changed.
+ // Then pass these elements to the child layout nodes for processing
+ final Map<IVMLayoutNode,Integer> childNodeDeltas = getChildNodesWithDeltaFlags(e);
+ if (childNodeDeltas.size() == 0) {
+ // There are no child nodes with deltas, just return to parent.
+ requestMonitor.done();
+ return;
+ }
+
+ // Calculate the index of this node by retrieving all the
+ // elements and then finding the DMC that the event is for.
+ updateElements(new ElementsUpdate(
+ new DataRequestMonitor<List<Object>>(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (isDisposed()) return;
+
+ // Check for an empty list of elements. If it's empty then we
+ // don't have to call the children nodes, so return here.
+ // No need to propagate error, there's no means or need to display it.
+ if (!getStatus().isOK() || getData().isEmpty()) {
+ requestMonitor.done();
+ return;
+ }
+
+ for (int i = 0; i < getData().size(); i++) {
+ IVMContext vmc = (IVMContext)getData().get(i);
+ VMDelta delta = parentDelta.addNode(vmc, nodeOffset + i, IModelDelta.STATE);
+ callChildNodesToBuildDelta(childNodeDeltas, delta, e, requestMonitor);
+ if (vmc.equals(getData().get(i))) break;
+ }
+ }
+ },
+ parentDelta));
+ return;
+ }
+ else if (e instanceof IRunControl.IResumedDMEvent || e instanceof IRunControl.ISuspendedDMEvent) {
+ parentDelta.addNode(new DMVMContext(e.getDMContext()), IModelDelta.STATE);
+ super.buildDeltaForDMEvent(e, parentDelta, nodeOffset, requestMonitor);
+ }
+ else {
+ super.buildDeltaForDMEvent(e, parentDelta, nodeOffset, requestMonitor);
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ViewModelAdapter.java b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ViewModelAdapter.java
new file mode 100644
index 000000000..e70d2704c
--- /dev/null
+++ b/plugins/com.windriver.tcf.dsf.ui/src/com/windriver/tcf/dsf/ui/ViewModelAdapter.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.dsf.ui;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.dd.dsf.concurrent.ThreadSafe;
+import org.eclipse.dd.dsf.debug.ui.viewmodel.expression.ExpressionVMProvider;
+import org.eclipse.dd.dsf.debug.ui.viewmodel.register.RegisterVMProvider;
+import org.eclipse.dd.dsf.debug.ui.viewmodel.variable.VariableVMProvider;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMAdapter;
+import org.eclipse.dd.dsf.ui.viewmodel.dm.AbstractDMVMProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IColumnPresentationFactory;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.widgets.Display;
+import org.osgi.framework.Bundle;
+
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.dsf.core.launch.TCFDSFLaunch;
+
+@ThreadSafe
+@SuppressWarnings("restriction")
+public class ViewModelAdapter extends AbstractDMVMAdapter implements IElementLabelProvider {
+
+ private final TCFDSFLaunch launch;
+
+ public ViewModelAdapter(DsfSession session, TCFDSFLaunch launch) {
+ super(session);
+ this.launch = launch;
+ getSession().registerModelAdapter(IColumnPresentationFactory.class, this);
+ }
+
+ @Override
+ public void dispose() {
+ getSession().unregisterModelAdapter(IColumnPresentationFactory.class);
+ super.dispose();
+ }
+
+ @Override
+ protected AbstractDMVMProvider createViewModelProvider(IPresentationContext context) {
+ if (IDebugUIConstants.ID_DEBUG_VIEW.equals(context.getId()) ) {
+ return new LaunchVMProvider(this, context, getSession(), launch);
+ }
+ if (IDebugUIConstants.ID_VARIABLE_VIEW.equals(context.getId()) ) {
+ return new VariableVMProvider(this, context, getSession());
+ }
+ if (IDebugUIConstants.ID_REGISTER_VIEW.equals(context.getId()) ) {
+ return new RegisterVMProvider(this, context, getSession());
+ }
+ if (IDebugUIConstants.ID_EXPRESSION_VIEW.equals(context.getId()) ) {
+ return new ExpressionVMProvider(this, context, getSession());
+ }
+ return null;
+ }
+
+ private static final Map<String,ImageDescriptor> image_cache =
+ new HashMap<String,ImageDescriptor>();
+
+ private static ImageDescriptor getImageDescriptor(String name) {
+ if (name == null) return null;
+ ImageDescriptor descriptor = image_cache.get(name);
+ if (descriptor == null) {
+ descriptor = ImageDescriptor.getMissingImageDescriptor();
+ Bundle bundle = Platform.getBundle("org.eclipse.debug.ui");
+ if (bundle != null){
+ URL url = FileLocator.find(bundle, new Path(name), null);
+ descriptor = ImageDescriptor.createFromURL(url);
+ }
+ image_cache.put(name, descriptor);
+ }
+ return descriptor;
+ }
+
+ public void update(final ILabelUpdate[] updates) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ for (ILabelUpdate u : updates) {
+ Object o = u.getElement();
+ if (o instanceof TCFDSFLaunch) {
+ u.setImageDescriptor(getImageDescriptor("icons/full/obj16/ldebug_obj.gif"), 0);
+ TCFDSFLaunch launch = (TCFDSFLaunch)o;
+ String status = "";
+ if (launch.isConnecting()) status = "Connecting";
+ else if (launch.isDisconnected()) status = "Disconnected";
+ else if (launch.isTerminated()) status = "Terminated";
+ Throwable error = launch.getError();
+ if (error != null) {
+ status += " - " + error;
+ u.setForeground(new RGB(255, 0, 0), 0);
+ }
+ if (status.length() > 0) status = " (" + status + ")";
+ u.setLabel(launch.getLaunchConfiguration().getName() + status, 0);
+ }
+ else {
+ u.setForeground(new RGB(255, 0, 0), 0);
+ u.setLabel("Invalid object: " + o.getClass(), 0);
+ }
+ }
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ for (ILabelUpdate u : updates) u.done();
+ }
+ });
+ }
+ });
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/.classpath b/plugins/com.windriver.tcf.rse.ui/.classpath
new file mode 100644
index 000000000..751c8f2e5
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/plugins/com.windriver.tcf.rse.ui/.project b/plugins/com.windriver.tcf.rse.ui/.project
new file mode 100644
index 000000000..bcca78522
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>com.windriver.tcf.rse.ui</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/plugins/com.windriver.tcf.rse.ui/META-INF/MANIFEST.MF b/plugins/com.windriver.tcf.rse.ui/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..b45ab5134
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/META-INF/MANIFEST.MF
@@ -0,0 +1,18 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: com.windriver.tcf.rse.ui;singleton:=true
+Bundle-Version: 0.1.0
+Bundle-Activator: com.windriver.tcf.rse.ui.Activator
+Bundle-Vendor: %providerName
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.eclipse.rse.core,
+ org.eclipse.rse.ui,
+ org.eclipse.rse.services,
+ com.windriver.tcf.api,
+ org.eclipse.ui.views,
+ org.eclipse.rse.subsystems.files.core,
+ org.eclipse.rse.subsystems.processes.core
+Eclipse-LazyStart: true
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
diff --git a/plugins/com.windriver.tcf.rse.ui/about.html b/plugins/com.windriver.tcf.rse.ui/about.html
new file mode 100755
index 000000000..6c5b3615b
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/about.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
+<title>About</title>
+</head>
+<body lang="EN-US">
+<h2>About This Content</h2>
+
+<p>January 10, 2008</p>
+<h3>License</h3>
+
+<p>The Eclipse Foundation makes available all content in this plug-in (&quot;Content&quot;). Unless otherwise
+indicated below, the Content is provided to you under the terms and conditions of the
+Eclipse Public License Version 1.0 (&quot;EPL&quot;). A copy of the EPL is available
+at <a href="http://www.eclipse.org/legal/epl-v10.html">http://www.eclipse.org/legal/epl-v10.html</a>.
+For purposes of the EPL, &quot;Program&quot; will mean the Content.</p>
+
+<p>If you did not receive this Content directly from the Eclipse Foundation, the Content is
+being redistributed by another party (&quot;Redistributor&quot;) and different terms and conditions may
+apply to your use of any object code in the Content. Check the Redistributor's license that was
+provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise
+indicated below, the terms and conditions of the EPL still apply to any source code in the Content
+and such source code may be obtained at <a href="http://www.eclipse.org/">http://www.eclipse.org</a>.</p>
+
+</body>
+</html> \ No newline at end of file
diff --git a/plugins/com.windriver.tcf.rse.ui/build.properties b/plugins/com.windriver.tcf.rse.ui/build.properties
new file mode 100644
index 000000000..e9863e281
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/build.properties
@@ -0,0 +1,5 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.xml
diff --git a/plugins/com.windriver.tcf.rse.ui/icons/process-r.gif b/plugins/com.windriver.tcf.rse.ui/icons/process-r.gif
new file mode 100644
index 000000000..87aa144a8
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/icons/process-r.gif
Binary files differ
diff --git a/plugins/com.windriver.tcf.rse.ui/icons/process-s.gif b/plugins/com.windriver.tcf.rse.ui/icons/process-s.gif
new file mode 100644
index 000000000..c1644b2ec
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/icons/process-s.gif
Binary files differ
diff --git a/plugins/com.windriver.tcf.rse.ui/icons/system-files-live.gif b/plugins/com.windriver.tcf.rse.ui/icons/system-files-live.gif
new file mode 100644
index 000000000..885b8a69e
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/icons/system-files-live.gif
Binary files differ
diff --git a/plugins/com.windriver.tcf.rse.ui/icons/system-files.gif b/plugins/com.windriver.tcf.rse.ui/icons/system-files.gif
new file mode 100644
index 000000000..874c99262
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/icons/system-files.gif
Binary files differ
diff --git a/plugins/com.windriver.tcf.rse.ui/icons/system-processes-live.gif b/plugins/com.windriver.tcf.rse.ui/icons/system-processes-live.gif
new file mode 100644
index 000000000..96a447a71
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/icons/system-processes-live.gif
Binary files differ
diff --git a/plugins/com.windriver.tcf.rse.ui/icons/system-processes.gif b/plugins/com.windriver.tcf.rse.ui/icons/system-processes.gif
new file mode 100644
index 000000000..e07b81aa6
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/icons/system-processes.gif
Binary files differ
diff --git a/plugins/com.windriver.tcf.rse.ui/icons/tcf.gif b/plugins/com.windriver.tcf.rse.ui/icons/tcf.gif
new file mode 100644
index 000000000..3198679ae
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/icons/tcf.gif
Binary files differ
diff --git a/plugins/com.windriver.tcf.rse.ui/icons/thread-r.gif b/plugins/com.windriver.tcf.rse.ui/icons/thread-r.gif
new file mode 100644
index 000000000..17d7d69df
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/icons/thread-r.gif
Binary files differ
diff --git a/plugins/com.windriver.tcf.rse.ui/icons/thread-s.gif b/plugins/com.windriver.tcf.rse.ui/icons/thread-s.gif
new file mode 100644
index 000000000..3fa5fe586
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/icons/thread-s.gif
Binary files differ
diff --git a/plugins/com.windriver.tcf.rse.ui/plugin.properties b/plugins/com.windriver.tcf.rse.ui/plugin.properties
new file mode 100644
index 000000000..f736bbb13
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/plugin.properties
@@ -0,0 +1,13 @@
+###############################################################################
+# Copyright (c) 2007 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 implementation
+###############################################################################
+pluginName = TCF/RSE Integration UI
+providerName = Eclipse.org
+
diff --git a/plugins/com.windriver.tcf.rse.ui/plugin.xml b/plugins/com.windriver.tcf.rse.ui/plugin.xml
new file mode 100644
index 000000000..def23b5df
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/plugin.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+ <extension
+ point="org.eclipse.rse.core.systemTypes">
+ <systemType
+ description="Connects using Target Commenucation Framework"
+ icon="icons/tcf.gif"
+ iconLive="icons/tcf.gif"
+ id="com.windriver.tcf.rse.ui.systemType"
+ label="TCF"
+ name="TCF">
+ </systemType>
+ </extension>
+ <extension
+ point="org.eclipse.rse.core.subsystemConfigurations">
+ <configuration
+ category="processes"
+ class="com.windriver.tcf.rse.ui.TCFProcessSubSystemConfiguration"
+ description="Processes"
+ icon="icons/system-processes.gif"
+ iconlive="icons/system-processes-live.gif"
+ id="com.windriver.tcf.rse.ui.Processes"
+ name="Processes"
+ priority="200"
+ systemTypeIds="com.windriver.tcf.rse.ui.systemType"
+ vendor="Wind River">
+ </configuration>
+ </extension>
+ <extension
+ point="org.eclipse.rse.core.subsystemConfigurations">
+ <configuration
+ category="files"
+ class="com.windriver.tcf.rse.ui.TCFFileSubSystemConfiguration"
+ description="Files"
+ icon="icons/system-files.gif"
+ iconlive="icons/system-files-live.gif"
+ id="com.windriver.tcf.rse.ui.Files"
+ name="Files"
+ priority="200"
+ systemTypeIds="com.windriver.tcf.rse.ui.systemType"
+ vendor="Wind River">
+ </configuration>
+ </extension>
+ <extension point="org.eclipse.core.runtime.adapters">
+ <factory
+ class="com.windriver.tcf.rse.ui.TCFSystemViewProcessAdapterFactory"
+ adaptableType="com.windriver.tcf.rse.ui.TCFRemoteProcess">
+ <adapter type="org.eclipse.rse.ui.view.ISystemViewElementAdapter"/>
+ <adapter type="org.eclipse.rse.ui.view.ISystemDragDropAdapter"/>
+ <adapter type="org.eclipse.rse.ui.view.ISystemRemoteElementAdapter"/>
+ <adapter type="org.eclipse.ui.views.properties.IPropertySource"/>
+ <adapter type="org.eclipse.ui.model.IWorkbenchAdapter"/>
+ <adapter type="org.eclipse.ui.IActionFilter"/>
+ <adapter type="org.eclipse.ui.progress.IDeferredWorkbenchAdapter"/>
+ <adapter type="org.eclipse.rse.core.subsystems.IRemoteObjectIdentifier"/>
+ </factory>
+ </extension>
+</plugin>
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/Activator.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/Activator.java
new file mode 100644
index 000000000..682b8d4c2
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/Activator.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "com.windriver.tcf.rse.ui";
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+ public ImageDescriptor getImageDescriptorFromPath(String path) {
+ return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path);
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/ITCFFileService.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/ITCFFileService.java
new file mode 100644
index 000000000..c0a981cb6
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/ITCFFileService.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import com.windriver.tcf.api.services.IFileSystem;
+
+public interface ITCFFileService {
+
+ public boolean canRead(IFileSystem.FileAttrs attrs);
+
+ public boolean canWrite(IFileSystem.FileAttrs attrs);
+
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/ITCFSubSystem.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/ITCFSubSystem.java
new file mode 100644
index 000000000..c842c6f8c
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/ITCFSubSystem.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import org.eclipse.rse.core.subsystems.ISubSystem;
+
+/**
+ * Subsystem can implement this interface to indicate that it can share TCF connection with
+ * other subsystems on same host.
+ */
+public interface ITCFSubSystem extends ISubSystem {
+
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/Messages.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/Messages.java
new file mode 100644
index 000000000..57d898ebf
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/Messages.java
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import org.eclipse.osgi.util.NLS;
+
+public class Messages extends NLS {
+
+ private static final String BUNDLE_NAME = "com.windriver.tcf.rse.ui.messages"; //$NON-NLS-1$
+
+ public static String SysMonitor_AllProcesses;
+ public static String SysMonitor_Process;
+
+ // PROCESS PROPERTIES
+ public static String PROCESS_ID_LABEL;
+ public static String PROCESS_PID_LABEL;
+ public static String PROCESS_NAME_LABEL;
+ public static String PROCESS_CWD_LABEL;
+ public static String PROCESS_ROOT_LABEL;
+ public static String PROCESS_UID_LABEL;
+ public static String PROCESS_USERNAME_LABEL;
+ public static String PROCESS_GID_LABEL;
+ public static String PROCESS_GROUPNAME_LABEL;
+ public static String PROCESS_PPID_LABEL;
+ public static String PROCESS_PGRP_LABEL;
+ public static String PROCESS_STATE_LABEL;
+ public static String PROCESS_TRACERPID_LABEL;
+ public static String PROCESS_VMSIZE_LABEL;
+ public static String PROCESS_VMRSS_LABEL;
+ public static String PROCESS_SESSION_LABEL;
+ public static String PROCESS_TTY_LABEL;
+ public static String PROCESS_TGID_LABEL;
+ public static String PROCESS_FLAGS_LABEL;
+ public static String PROCESS_MINFLT_LABEL;
+ public static String PROCESS_CMINFLT_LABEL;
+ public static String PROCESS_MAJFLT_LABEL;
+ public static String PROCESS_CMAJFLT_LABEL;
+ public static String PROCESS_UTIME_LABEL;
+ public static String PROCESS_STIME_LABEL;
+ public static String PROCESS_CUTIME_LABEL;
+ public static String PROCESS_CSTIME_LABEL;
+ public static String PROCESS_PC_UTIME_LABEL;
+ public static String PROCESS_PC_STIME_LABEL;
+ public static String PROCESS_PRIORITY_LABEL;
+ public static String PROCESS_NICE_LABEL;
+ public static String PROCESS_ITREALVALUE_LABEL;
+ public static String PROCESS_STARTTIME_LABEL;
+ public static String PROCESS_RLIMIT_LABEL;
+ public static String PROCESS_CODESTART_LABEL;
+ public static String PROCESS_CODEEND_LABEL;
+ public static String PROCESS_STACKSTART_LABEL;
+ public static String PROCESS_SIGNALS_LABEL;
+ public static String PROCESS_SIGBLOCK_LABEL;
+ public static String PROCESS_SIGIGNORE_LABEL;
+ public static String PROCESS_SIGCATCH_LABEL;
+ public static String PROCESS_WCHAN_LABEL;
+ public static String PROCESS_NSWAP_LABEL;
+ public static String PROCESS_CNSWAP_LABEL;
+ public static String PROCESS_EXITSIGNAL_LABEL;
+ public static String PROCESS_PROCESSOR_LABEL;
+ public static String PROCESS_RTPRIORITY_LABEL;
+ public static String PROCESS_POLICY_LABEL;
+
+ public static String PROCESS_ID_TOOLTIP;
+ public static String PROCESS_PID_TOOLTIP;
+ public static String PROCESS_NAME_TOOLTIP;
+ public static String PROCESS_CWD_TOOLTIP;
+ public static String PROCESS_ROOT_TOOLTIP;
+ public static String PROCESS_UID_TOOLTIP;
+ public static String PROCESS_USERNAME_TOOLTIP;
+ public static String PROCESS_GID_TOOLTIP;
+ public static String PROCESS_GROUPNAME_TOOLTIP;
+ public static String PROCESS_PPID_TOOLTIP;
+ public static String PROCESS_PGRP_TOOLTIP;
+ public static String PROCESS_STATE_TOOLTIP;
+ public static String PROCESS_TRACERPID_TOOLTIP;
+ public static String PROCESS_VMSIZE_TOOLTIP;
+ public static String PROCESS_VMRSS_TOOLTIP;
+ public static String PROCESS_SESSION_TOOLTIP;
+ public static String PROCESS_TTY_TOOLTIP;
+ public static String PROCESS_TGID_TOOLTIP;
+ public static String PROCESS_FLAGS_TOOLTIP;
+ public static String PROCESS_MINFLT_TOOLTIP;
+ public static String PROCESS_CMINFLT_TOOLTIP;
+ public static String PROCESS_MAJFLT_TOOLTIP;
+ public static String PROCESS_CMAJFLT_TOOLTIP;
+ public static String PROCESS_UTIME_TOOLTIP;
+ public static String PROCESS_STIME_TOOLTIP;
+ public static String PROCESS_PC_UTIME_TOOLTIP;
+ public static String PROCESS_PC_STIME_TOOLTIP;
+ public static String PROCESS_CUTIME_TOOLTIP;
+ public static String PROCESS_CSTIME_TOOLTIP;
+ public static String PROCESS_PRIORITY_TOOLTIP;
+ public static String PROCESS_NICE_TOOLTIP;
+ public static String PROCESS_ITREALVALUE_TOOLTIP;
+ public static String PROCESS_STARTTIME_TOOLTIP;
+ public static String PROCESS_RLIMIT_TOOLTIP;
+ public static String PROCESS_CODESTART_TOOLTIP;
+ public static String PROCESS_CODEEND_TOOLTIP;
+ public static String PROCESS_STACKSTART_TOOLTIP;
+ public static String PROCESS_SIGNALS_TOOLTIP;
+ public static String PROCESS_SIGBLOCK_TOOLTIP;
+ public static String PROCESS_SIGIGNORE_TOOLTIP;
+ public static String PROCESS_SIGCATCH_TOOLTIP;
+ public static String PROCESS_WCHAN_TOOLTIP;
+ public static String PROCESS_NSWAP_TOOLTIP;
+ public static String PROCESS_CNSWAP_TOOLTIP;
+ public static String PROCESS_EXITSIGNAL_TOOLTIP;
+ public static String PROCESS_PROCESSOR_TOOLTIP;
+ public static String PROCESS_RTPRIORITY_TOOLTIP;
+ public static String PROCESS_POLICY_TOOLTIP;
+
+ public static String PROCESS_VMSIZE_VALUE;
+ public static String PROCESS_VMRSS_VALUE;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFConnectorService.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFConnectorService.java
new file mode 100644
index 000000000..ebfa0031d
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFConnectorService.java
@@ -0,0 +1,275 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.rse.core.model.IHost;
+import org.eclipse.rse.core.subsystems.AbstractConnectorService;
+import org.eclipse.rse.core.subsystems.CommunicationsEvent;
+
+import com.windriver.tcf.api.core.AbstractPeer;
+import com.windriver.tcf.api.core.ChannelTCP;
+import com.windriver.tcf.api.protocol.IChannel;
+import com.windriver.tcf.api.protocol.IPeer;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IFileSystem;
+import com.windriver.tcf.api.services.ILocator;
+import com.windriver.tcf.api.services.ISysMonitor;
+
+class TCFConnectorService extends AbstractConnectorService {
+
+ private IChannel channel;
+ private Throwable channel_error;
+ private final List<Runnable> state_change = new ArrayList<Runnable>();
+
+ public TCFConnectorService(IHost host, int port) {
+ super("TCF", "Target Communication Framework", host, port);
+ }
+
+ @Override
+ protected void internalConnect(IProgressMonitor monitor) throws Exception {
+ assert !Protocol.isDispatchThread();
+ final Exception[] res = new Exception[1];
+ monitor.beginTask("Connecting " + getHostName(), 1);
+ synchronized (res) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ connectTCFChannel(res);
+ }
+ });
+ res.wait();
+ }
+ monitor.done();
+ if (res[0] != null) throw res[0];
+ }
+
+ @Override
+ protected void internalDisconnect(IProgressMonitor monitor) throws Exception {
+ assert !Protocol.isDispatchThread();
+ final Exception[] res = new Exception[1];
+ monitor.beginTask("Disconnecting " + getHostName(), 1);
+ synchronized (res) {
+ Protocol.invokeLater(new Runnable() {
+ public void run() {
+ disconnectTCFChannel(res);
+ }
+ });
+ res.wait();
+ }
+ monitor.done();
+ if (res[0] != null) throw res[0];
+ }
+
+ public void acquireCredentials(boolean refresh) throws InterruptedException {
+ }
+
+ public void clearCredentials() {
+ }
+
+ public void clearPassword(boolean persist, boolean propagate) {
+ }
+
+ public String getUserId() {
+ return null;
+ }
+
+ public boolean hasPassword(boolean persistent) {
+ return false;
+ }
+
+ public boolean inheritsCredentials() {
+ return false;
+ }
+
+ public boolean isConnected() {
+ final boolean res[] = new boolean[1];
+ Protocol.invokeAndWait(new Runnable() {
+ public void run() {
+ res[0] = channel != null && channel.getState() == IChannel.STATE_OPEN;
+ }
+ });
+ return res[0];
+ }
+
+ public boolean isSuppressed() {
+ return false;
+ }
+
+ public void removePassword() {
+ }
+
+ public void removeUserId() {
+ }
+
+ public boolean requiresPassword() {
+ return false;
+ }
+
+ public boolean requiresUserId() {
+ return false;
+ }
+
+ public void savePassword() {
+ }
+
+ public void saveUserId() {
+ }
+
+ public void setPassword(String matchingUserId, String password,
+ boolean persist, boolean propagate) {
+ }
+
+ public void setSuppressed(boolean suppress) {
+ }
+
+ public void setUserId(String userId) {
+ }
+
+ public boolean sharesCredentials() {
+ return false;
+ }
+
+ public boolean supportsPassword() {
+ return false;
+ }
+
+ public boolean supportsUserId() {
+ return false;
+ }
+
+ private void connectTCFChannel(final Exception[] res) {
+ if (channel != null) {
+ switch (channel.getState()) {
+ case IChannel.STATE_OPEN:
+ case IChannel.STATE_CLOSED:
+ synchronized (res) {
+ if (channel_error instanceof Exception) res[0] = (Exception)channel_error;
+ else if (channel_error != null) res[0] = new Exception(channel_error);
+ else res[0] = null;
+ res.notify();
+ }
+ return;
+ }
+ }
+ if (channel == null) {
+ final String host = getHostName().toLowerCase();
+ // TODO: final int port = getPort();
+ final int port = TCFConnectorServiceManager.TCF_PORT;
+ IPeer peer = null;
+ String ports = Integer.toString(port);
+ ILocator locator = Protocol.getLocator();
+ for (Iterator<IPeer> i = locator.getPeers().values().iterator(); i.hasNext();) {
+ IPeer p = i.next();
+ Map<String, String> attrs = p.getAttributes();
+ if ("TCP".equals(attrs.get(IPeer.ATTR_TRANSPORT_NAME)) &&
+ host.equalsIgnoreCase(attrs.get(IPeer.ATTR_IP_HOST)) &&
+ ports.equals(attrs.get(IPeer.ATTR_IP_PORT))) {
+ peer = p;
+ break;
+ }
+ }
+ if (peer == null) {
+ Map<String, String> attrs = new HashMap<String, String>();
+ attrs.put(IPeer.ATTR_ID, "RSE:" + host + ":" + port);
+ attrs.put(IPeer.ATTR_NAME, getName());
+ attrs.put(IPeer.ATTR_TRANSPORT_NAME, "TCP");
+ attrs.put(IPeer.ATTR_IP_HOST, host);
+ attrs.put(IPeer.ATTR_IP_PORT, ports);
+ peer = new AbstractPeer(attrs) {
+ public IChannel openChannel() {
+ return new ChannelTCP(this, host, port);
+ }
+ };
+ }
+ channel = peer.openChannel();
+ channel.addChannelListener(new IChannel.IChannelListener() {
+
+ public void onChannelOpened() {
+ onConnected();
+ }
+
+ public void congestionLevel(int level) {
+ }
+
+ public void onChannelClosed(Throwable error) {
+ channel.removeChannelListener(this);
+ onDisconnected(error);
+ }
+
+ });
+ assert channel.getState() == IChannel.STATE_OPENNING;
+ }
+ state_change.add(new Runnable() {
+ public void run() {
+ connectTCFChannel(res);
+ }
+ });
+ }
+
+ private void disconnectTCFChannel(final Exception[] res) {
+ if (channel == null || channel.getState() == IChannel.STATE_CLOSED) {
+ synchronized (res) {
+ res[0] = null;
+ res.notify();
+ }
+ return;
+ }
+ if (channel.getState() == IChannel.STATE_OPEN) channel.close();
+ state_change.add(new Runnable() {
+ public void run() {
+ disconnectTCFChannel(res);
+ }
+ });
+ }
+
+ private void onConnected() {
+ assert channel != null;
+ if (state_change.isEmpty()) return;
+ Runnable[] r = state_change.toArray(new Runnable[state_change.size()]);
+ state_change.clear();
+ for (int i = 0; i < r.length; i++) r[i].run();
+ }
+
+ private void onDisconnected(Throwable error) {
+ assert channel != null;
+ channel_error = error;
+ if (state_change.isEmpty()) {
+ fireCommunicationsEvent(CommunicationsEvent.CONNECTION_ERROR);
+ }
+ else {
+ Runnable[] r = state_change.toArray(new Runnable[state_change.size()]);
+ state_change.clear();
+ for (int i = 0; i < r.length; i++) r[i].run();
+ }
+ channel = null;
+ channel_error = null;
+ }
+
+ public ISysMonitor getSysMonitorService() {
+ if (channel == null || channel.getState() != IChannel.STATE_OPEN) throw new Error("Not connected");
+ ISysMonitor m = channel.getRemoteService(ISysMonitor.class);
+ if (m == null) throw new Error("Remote peer does not support SysMonitor service");
+ return m;
+ }
+
+ public IFileSystem getFileSystemService() {
+ if (channel == null || channel.getState() != IChannel.STATE_OPEN) throw new Error("Not connected");
+ IFileSystem m = channel.getRemoteService(IFileSystem.class);
+ if (m == null) throw new Error("Remote peer does not support FileSystem service");
+ return m;
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFConnectorServiceManager.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFConnectorServiceManager.java
new file mode 100644
index 000000000..e13fd58d8
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFConnectorServiceManager.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import org.eclipse.rse.core.model.IHost;
+import org.eclipse.rse.core.subsystems.AbstractConnectorServiceManager;
+import org.eclipse.rse.core.subsystems.IConnectorService;
+import org.eclipse.rse.core.subsystems.ISubSystem;
+
+public class TCFConnectorServiceManager extends AbstractConnectorServiceManager {
+
+ public static int TCF_PORT = 1534;
+
+ private static final TCFConnectorServiceManager manager =
+ new TCFConnectorServiceManager();
+
+ @Override
+ public IConnectorService createConnectorService(IHost host) {
+ return new TCFConnectorService(host, TCF_PORT);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Class getSubSystemCommonInterface(ISubSystem subsystem) {
+ return ITCFSubSystem.class;
+ }
+
+ @Override
+ public boolean sharesSystem(ISubSystem otherSubSystem) {
+ return otherSubSystem instanceof ITCFSubSystem;
+ }
+
+ public static TCFConnectorServiceManager getInstance() {
+ return manager;
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileAdapter.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileAdapter.java
new file mode 100644
index 000000000..e5164df66
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileAdapter.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import org.eclipse.rse.services.files.IHostFile;
+import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystem;
+import org.eclipse.rse.subsystems.files.core.subsystems.IHostFileToRemoteFileAdapter;
+import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFile;
+import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileContext;
+
+public class TCFFileAdapter implements IHostFileToRemoteFileAdapter {
+
+ public IRemoteFile convertToRemoteFile(FileServiceSubSystem ss,
+ IRemoteFileContext ctx, IRemoteFile parent, IHostFile node) {
+ return new TCFRemoteFile(ss, ctx, parent, node);
+ }
+
+ public IRemoteFile[] convertToRemoteFiles(FileServiceSubSystem ss,
+ IRemoteFileContext ctx, IRemoteFile parent, IHostFile[] nodes) {
+ if (nodes == null) return null;
+ IRemoteFile[] res = new IRemoteFile[nodes.length];
+ for (int i = 0; i < res.length; i++) {
+ res[i] = new TCFRemoteFile(ss, ctx, parent, nodes[i]);
+ }
+ return res;
+ }
+
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileResource.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileResource.java
new file mode 100644
index 000000000..39cfa52e6
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileResource.java
@@ -0,0 +1,122 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import org.eclipse.rse.core.subsystems.AbstractResource;
+import org.eclipse.rse.services.files.IHostFile;
+
+import com.windriver.tcf.api.services.IFileSystem;
+
+public class TCFFileResource extends AbstractResource implements IHostFile {
+
+ private final ITCFFileService service;
+ private String parent;
+ private String name;
+ private final IFileSystem.FileAttrs attrs;
+ private final boolean root;
+
+ public TCFFileResource(ITCFFileService service, String parent, String name,
+ IFileSystem.FileAttrs attrs, boolean root) {
+ if (name == null) {
+ int i = parent.lastIndexOf('/');
+ if (i > 0) {
+ name = parent.substring(i + 1);
+ parent = parent.substring(0, i);
+ }
+ }
+ this.service = service;
+ this.parent = parent;
+ this.name = name;
+ this.attrs = attrs;
+ this.root = root;
+ }
+
+ private String toLocalPath(String path) {
+ if (path.length() > 1 && path.charAt(1) == ':') {
+ return path.replace('/', '\\');
+ }
+ else {
+ return path.replace('\\', '/');
+ }
+ }
+
+ public boolean canRead() {
+ return attrs != null && service.canRead(attrs);
+ }
+
+ public boolean canWrite() {
+ return attrs != null && service.canWrite(attrs);
+ }
+
+ public boolean exists() {
+ return attrs != null;
+ }
+
+ public synchronized String getAbsolutePath() {
+ if (root) return toLocalPath(name);
+ if (parent.endsWith("/")) return toLocalPath(parent + name);
+ return toLocalPath(parent + '/' + name);
+ }
+
+ public long getModifiedDate() {
+ if (attrs == null) return 0;
+ if ((attrs.flags & IFileSystem.ATTR_ACMODTIME) == 0) return 0;
+ return attrs.mtime;
+ }
+
+ public synchronized String getName() {
+ return toLocalPath(name);
+ }
+
+ public synchronized String getParentPath() {
+ return toLocalPath(parent);
+ }
+
+ public long getSize() {
+ if (attrs == null) return 0;
+ if ((attrs.flags & IFileSystem.ATTR_SIZE) == 0) return 0;
+ return attrs.size;
+ }
+
+ public boolean isArchive() {
+ return false;
+ }
+
+ public boolean isDirectory() {
+ if (attrs == null) return false;
+ return attrs.isDirectory();
+ }
+
+ public boolean isFile() {
+ if (attrs == null) return false;
+ return attrs.isFile();
+ }
+
+ public synchronized boolean isHidden() {
+ return name.startsWith(".");
+ }
+
+ public synchronized boolean isRoot() {
+ return root;
+ }
+
+ public synchronized void renameTo(String path) {
+ path = path.replace('\\', '/');
+ if (path.equals("/")) {
+ parent = name = "/";
+ return;
+ }
+ assert !path.endsWith("/");
+ int i = path.lastIndexOf('/');
+ parent = path.substring(0, i);
+ name = path.substring(i + 1);
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileService.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileService.java
new file mode 100644
index 000000000..6eb030f61
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileService.java
@@ -0,0 +1,643 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.rse.core.model.IHost;
+import org.eclipse.rse.services.clientserver.FileTypeMatcher;
+import org.eclipse.rse.services.clientserver.IMatcher;
+import org.eclipse.rse.services.clientserver.NamePatternMatcher;
+import org.eclipse.rse.services.clientserver.messages.IndicatorException;
+import org.eclipse.rse.services.clientserver.messages.SystemMessage;
+import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
+import org.eclipse.rse.services.files.AbstractFileService;
+import org.eclipse.rse.services.files.IHostFile;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.IFileSystem;
+import com.windriver.tcf.api.services.IFileSystem.DirEntry;
+import com.windriver.tcf.api.services.IFileSystem.FileAttrs;
+import com.windriver.tcf.api.services.IFileSystem.FileSystemException;
+import com.windriver.tcf.api.services.IFileSystem.IFileHandle;
+import com.windriver.tcf.api.util.TCFFileInputStream;
+import com.windriver.tcf.api.util.TCFFileOutputStream;
+
+public class TCFFileService extends AbstractFileService implements ITCFFileService {
+
+ private final TCFConnectorService connector;
+
+ private UserInfo user_info;
+
+ private static final class UserInfo {
+ final int r_uid;
+ final int e_uid;
+ final int r_gid;
+ final int e_gid;
+ final String home;
+
+ final Throwable error;
+
+ UserInfo(int r_uid, int e_uid, int r_gid, int e_gid, String home) {
+ this.r_uid = r_uid;
+ this.e_uid = e_uid;
+ this.r_gid = r_gid;
+ this.e_gid = e_gid;
+ this.home = home;
+ error = null;
+ }
+
+ UserInfo(Throwable error) {
+ this.error = error;
+ r_uid = -1;
+ e_uid = -1;
+ r_gid = -1;
+ e_gid = -1;
+ home = null;
+ }
+ }
+
+ public TCFFileService(IHost host) {
+ connector = (TCFConnectorService)TCFConnectorServiceManager
+ .getInstance().getConnectorService(host, ITCFSubSystem.class);
+ }
+
+ public String getDescription() {
+ return "The TCF File Service uses the Target Communication Framework to provide service" +
+ "for the Files subsystem. It requires a TCF agent to be running on the remote machine.";
+ }
+
+ public SystemMessage getMessage(String id) {
+ try {
+ return new SystemMessage("TCF", "C", "0001",
+ SystemMessage.ERROR, id, "");
+ }
+ catch (IndicatorException e) {
+ throw new Error(e);
+ }
+ }
+
+ public SystemMessage getMessage(Throwable x) {
+ try {
+ return new SystemMessage("TCF", "C", "0002",
+ SystemMessage.ERROR, x.getClass().getName(), x.getMessage());
+ }
+ catch (IndicatorException e) {
+ throw new Error(e);
+ }
+ }
+
+ public String getName() {
+ return "TCF File Service";
+ }
+
+ public void initService(IProgressMonitor monitor) {
+ }
+
+ public void uninitService(IProgressMonitor monitor) {
+ }
+
+ private String toRemotePath(String parent, String name) throws SystemMessageException {
+ assert !Protocol.isDispatchThread();
+ String s = null;
+ if (parent != null) parent = parent.replace('\\', '/');
+ if (name != null) name = name.replace('\\', '/');
+ if (parent == null || parent.length() == 0) s = name;
+ else if (name == null || name.equals(".")) s = parent;
+ else if (name.equals("/")) s = parent;
+ else if (parent.endsWith("/")) s = parent + name;
+ else s = parent + '/' + name;
+ if (s.startsWith("./") || s.equals(".")) {
+ UserInfo ui = getUserInfo();
+ if (ui.error != null) throw new SystemMessageException(getMessage(ui.error));
+ s = ui.home.replace('\\', '/') + s.substring(1);
+ }
+ while (s.endsWith("/.")) s = s.substring(0, s.length() - 2);
+ return s;
+ }
+
+ public boolean copy(String srcParent,
+ String srcName, String tgtParent, String tgtName, IProgressMonitor monitor)
+ throws SystemMessageException {
+ final String src = toRemotePath(srcParent, srcName);
+ final String tgt = toRemotePath(tgtParent, tgtName);
+ return new TCFRSETask<Boolean>() {
+ public void run() {
+ IFileSystem fs = connector.getFileSystemService();
+ fs.copy(src, tgt, false, false, new IFileSystem.DoneCopy() {
+ public void doneCopy(IToken token, FileSystemException error) {
+ if (error != null) error(error);
+ else done(true);
+ }
+ });
+ }
+ }.getS(monitor, "Copy: " + srcName);
+ }
+
+ public boolean copyBatch(String[] srcParents,
+ String[] srcNames, String tgtParent, IProgressMonitor monitor) throws SystemMessageException {
+ for (int i = 0; i < srcParents.length; i++) {
+ if (!copy(srcParents[i], srcNames[i], tgtParent, srcNames[i], monitor)) return false;
+ }
+ return true;
+ }
+
+ public IHostFile createFile(String parent,
+ String name, IProgressMonitor monitor) throws SystemMessageException {
+ try {
+ getOutputStream(parent, name, true, monitor).close();
+ return getFile(parent, name, monitor);
+ }
+ catch (IOException e) {
+ throw new SystemMessageException(getMessage(e));
+ }
+ }
+
+ public IHostFile createFolder(final String parent, final String name, IProgressMonitor monitor) throws SystemMessageException {
+ final String path = toRemotePath(parent, name);
+ return new TCFRSETask<IHostFile>() {
+ public void run() {
+ final IFileSystem fs = connector.getFileSystemService();
+ fs.mkdir(path, null, new IFileSystem.DoneMkDir() {
+ public void doneMkDir(IToken token, FileSystemException error) {
+ if (error != null) {
+ error(error);
+ return;
+ }
+ fs.stat(path, new IFileSystem.DoneStat() {
+ public void doneStat(IToken token,
+ FileSystemException error, FileAttrs attrs) {
+ if (error != null) error(error);
+ else done(new TCFFileResource(TCFFileService.this,
+ path, null, attrs, false));
+ }
+ });
+ }
+ });
+ }
+ }.getS(monitor, "Create folder");
+ }
+
+ public boolean delete(String parent,
+ String name, IProgressMonitor monitor) throws SystemMessageException {
+ final String path = toRemotePath(parent, name);
+ return new TCFRSETask<Boolean>() {
+ public void run() {
+ final IFileSystem fs = connector.getFileSystemService();
+ fs.stat(path, new IFileSystem.DoneStat() {
+ public void doneStat(IToken token,
+ FileSystemException error, FileAttrs attrs) {
+ if (error != null) {
+ error(error);
+ return;
+ }
+ IFileSystem.DoneRemove done = new IFileSystem.DoneRemove() {
+ public void doneRemove(IToken token, FileSystemException error) {
+ if (error != null) {
+ error(error);
+ return;
+ }
+ done(true);
+ }
+ };
+ if (attrs.isDirectory()) {
+ fs.rmdir(path, done);
+ }
+ else {
+ fs.remove(path, done);
+ }
+ }
+ });
+ }
+ }.getS(monitor, "Delete");
+ }
+
+ public boolean deleteBatch(String[] remoteParents, String[] fileNames, IProgressMonitor monitor)
+ throws SystemMessageException {
+ for (int i = 0; i < remoteParents.length; i++) {
+ delete(remoteParents[i], fileNames[i], monitor);
+ }
+ return true;
+ }
+
+ public boolean download(final String parent,
+ final String name, final File file, final boolean is_binary,
+ final String host_encoding, IProgressMonitor monitor) throws SystemMessageException {
+ monitor.beginTask("Download", 1);
+ try {
+ file.getParentFile().mkdirs();
+ InputStream inp = getInputStream(parent, name, is_binary, new NullProgressMonitor());
+ OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
+ copyStream(inp, out, is_binary, "UTF8", host_encoding);
+ return true;
+ }
+ catch (Throwable x) {
+ if (x instanceof SystemMessageException) throw (SystemMessageException)x;
+ throw new SystemMessageException(getMessage(x));
+ }
+ finally {
+ monitor.done();
+ }
+ }
+
+ public String getEncoding(IProgressMonitor monitor) throws SystemMessageException {
+ return "UTF8";
+ }
+
+ public IHostFile getFile(final String parent,
+ final String name, IProgressMonitor monitor) throws SystemMessageException {
+ final String path = toRemotePath(parent, name);
+ return new TCFRSETask<IHostFile>() {
+ public void run() {
+ IFileSystem fs = connector.getFileSystemService();
+ fs.stat(path, new IFileSystem.DoneStat() {
+ public void doneStat(IToken token,
+ FileSystemException error, FileAttrs attrs) {
+ if (error != null) {
+ if (error.getStatus() == IFileSystem.STATUS_NO_SUCH_FILE) {
+ done(new TCFFileResource(TCFFileService.this, path, null, null, false));
+ return;
+ }
+ error(error);
+ return;
+ }
+ done(new TCFFileResource(TCFFileService.this, path, null, attrs, false));
+ }
+ });
+ }
+ }.getS(monitor, "Stat");
+ }
+
+ protected IHostFile[] internalFetch(final String parent, final String filter, final int fileType, final IProgressMonitor monitor)
+ throws SystemMessageException {
+ final String path = toRemotePath(parent, null);
+ final boolean wantFiles = (fileType==FILE_TYPE_FILES_AND_FOLDERS || (fileType&FILE_TYPE_FILES)!=0);
+ final boolean wantFolders = (fileType==FILE_TYPE_FILES_AND_FOLDERS || (fileType%FILE_TYPE_FOLDERS)!=0);
+ return new TCFRSETask<IHostFile[]>() {
+ private IMatcher matcher = null;
+ public void run() {
+ if (filter == null) {
+ matcher = null;
+ }
+ else if (filter.endsWith(",")) { //$NON-NLS-1$
+ String[] types = filter.split(","); //$NON-NLS-1$
+ matcher = new FileTypeMatcher(types, true);
+ }
+ else {
+ matcher = new NamePatternMatcher(filter, true, true);
+ }
+ final List<TCFFileResource> results = new ArrayList<TCFFileResource>();
+ final IFileSystem fs = connector.getFileSystemService();
+ fs.opendir(path, new IFileSystem.DoneOpen() {
+ public void doneOpen(IToken token, FileSystemException error, final IFileHandle handle) {
+ if (error != null) {
+ error(error);
+ return;
+ }
+ fs.readdir(handle, new IFileSystem.DoneReadDir() {
+ public void doneReadDir(IToken token,
+ FileSystemException error, DirEntry[] entries, boolean eof) {
+ if (error != null) {
+ error(error);
+ return;
+ }
+ for (DirEntry e : entries) {
+ if (e.attrs == null) {
+ // Attrs are not available if, for example,
+ // the entry is a broken symbolic link
+ }
+ else if (e.attrs.isDirectory()) {
+ //dont filter folder names if getting both folders and files
+ if (wantFolders && (matcher==null || fileType==FILE_TYPE_FILES_AND_FOLDERS || matcher.matches(e.filename))) {
+ results.add(new TCFFileResource(TCFFileService.this,
+ path, e.filename, e.attrs, false));
+ }
+ }
+ else if (e.attrs.isFile()) {
+ if (wantFiles && (matcher == null || matcher.matches(e.filename))) {
+ results.add(new TCFFileResource(TCFFileService.this,
+ path, e.filename, e.attrs, false));
+ }
+ }
+ }
+ if (eof) {
+ fs.close(handle, new IFileSystem.DoneClose() {
+ public void doneClose(IToken token, FileSystemException error) {
+ if (error != null) {
+ error(error);
+ return;
+ }
+ done(results.toArray(new TCFFileResource[results.size()]));
+ }
+ });
+ }
+ else {
+ fs.readdir(handle, this);
+ }
+ }
+ });
+ }
+ });
+ }
+ }.getS(monitor, "Get files and folders");
+ }
+
+ public InputStream getInputStream(final String parent, final String name, boolean isBinary, IProgressMonitor monitor)
+ throws SystemMessageException {
+ final String path = toRemotePath(parent, name);
+ final IFileHandle handle = new TCFRSETask<IFileHandle>() {
+ public void run() {
+ IFileSystem fs = connector.getFileSystemService();
+ fs.open(path, IFileSystem.O_READ, null, new IFileSystem.DoneOpen() {
+ public void doneOpen(IToken token, FileSystemException error, IFileHandle handle) {
+ if (error != null) error(error);
+ else done(handle);
+ }
+ });
+ }
+ }.getS(monitor, "Get input stream");
+ return new TCFFileInputStream(handle);
+ }
+
+ public OutputStream getOutputStream(final String parent, final String name, boolean isBinary, IProgressMonitor monitor)
+ throws SystemMessageException {
+ final String path = toRemotePath(parent, name);
+ final IFileHandle handle = new TCFRSETask<IFileHandle>() {
+ public void run() {
+ IFileSystem fs = connector.getFileSystemService();
+ int flags = IFileSystem.O_WRITE | IFileSystem.O_CREAT | IFileSystem.O_TRUNC;
+ fs.open(path, flags, null, new IFileSystem.DoneOpen() {
+ public void doneOpen(IToken token, FileSystemException error, IFileHandle handle) {
+ if (error != null) error(error);
+ else done(handle);
+ }
+ });
+ }
+ }.getS(monitor, "Get output stream");
+ return new TCFFileOutputStream(handle);
+ }
+
+ public IHostFile[] getRoots(IProgressMonitor monitor) throws SystemMessageException {
+ return new TCFRSETask<IHostFile[]>() {
+ public void run() {
+ IFileSystem fs = connector.getFileSystemService();
+ fs.roots(new IFileSystem.DoneRoots() {
+ public void doneRoots(IToken token, FileSystemException error, DirEntry[] entries) {
+ if (error != null) {
+ error(error);
+ return;
+ }
+ List<TCFFileResource> l = new ArrayList<TCFFileResource>();
+ for (DirEntry e : entries) {
+ if (e.attrs == null) continue;
+ l.add(new TCFFileResource(TCFFileService.this, "", e.filename, e.attrs, true));
+ }
+ done(l.toArray(new IHostFile[l.size()]));
+ }
+ });
+ }
+ }.getS(monitor, "Get roots");
+ }
+
+ public IHostFile getUserHome() {
+ UserInfo ui = getUserInfo();
+ try {
+ return getFile(ui.home, ".", new NullProgressMonitor());
+ }
+ catch (SystemMessageException e) {
+ throw new Error(e);
+ }
+ }
+
+ public boolean isCaseSensitive() {
+ return true;
+ }
+
+ public boolean move(final String srcParent,
+ final String srcName, final String tgtParent, final String tgtName, IProgressMonitor monitor)
+ throws SystemMessageException {
+ final String src_path = toRemotePath(srcParent, srcName);
+ final String tgt_path = toRemotePath(tgtParent, tgtName);
+ return new TCFRSETask<Boolean>() {
+ public void run() {
+ IFileSystem fs = connector.getFileSystemService();
+ fs.rename(src_path, tgt_path, new IFileSystem.DoneRename() {
+ public void doneRename(IToken token, FileSystemException error) {
+ if (error != null) error(error);
+ else done(true);
+ }
+ });
+ }
+ }.getS(monitor, "Move");
+ }
+
+ public boolean rename(String remoteParent,
+ String oldName, String newName, IProgressMonitor monitor) throws SystemMessageException {
+ return move(remoteParent, oldName, remoteParent, newName, monitor);
+ }
+
+ public boolean rename(String remoteParent,
+ String oldName, String newName, IHostFile oldFile, IProgressMonitor monitor)
+ throws SystemMessageException {
+ boolean b = move(remoteParent, oldName, remoteParent, newName, monitor);
+ if (b) oldFile.renameTo(toRemotePath(remoteParent, newName));
+ return b;
+ }
+
+ public boolean setLastModified(final String parent,
+ final String name, final long timestamp, IProgressMonitor monitor) throws SystemMessageException {
+ final String path = toRemotePath(parent, name);
+ return new TCFRSETask<Boolean>() {
+ public void run() {
+ IFileSystem fs = connector.getFileSystemService();
+ FileAttrs attrs = new FileAttrs(IFileSystem.ATTR_ACMODTIME,
+ 0, 0, 0, 0, timestamp, timestamp, null);
+ fs.setstat(path, attrs, new IFileSystem.DoneSetStat() {
+ public void doneSetStat(IToken token, FileSystemException error) {
+ if (error != null) error(error);
+ else done(true);
+ }
+ });
+ }
+ }.getS(monitor, "Set modification time");
+ }
+
+ public boolean setReadOnly(final String parent,
+ final String name, final boolean readOnly, IProgressMonitor monitor) throws SystemMessageException {
+ final String path = toRemotePath(parent, name);
+ return new TCFRSETask<Boolean>() {
+ public void run() {
+ final IFileSystem fs = connector.getFileSystemService();
+ fs.stat(path, new IFileSystem.DoneStat() {
+ public void doneStat(IToken token, FileSystemException error, FileAttrs attrs) {
+ if (error != null) {
+ error(error);
+ return;
+ }
+ int p = attrs.permissions;
+ if (readOnly) {
+ p &= ~IFileSystem.S_IWUSR;
+ p &= ~IFileSystem.S_IWGRP;
+ p &= ~IFileSystem.S_IWOTH;
+ }
+ else {
+ p |= IFileSystem.S_IWUSR;
+ p |= IFileSystem.S_IWGRP;
+ p |= IFileSystem.S_IWOTH;
+ }
+ FileAttrs new_attrs = new FileAttrs(IFileSystem.ATTR_PERMISSIONS,
+ 0, 0, 0, p, 0, 0, null);
+ fs.setstat(path, new_attrs, new IFileSystem.DoneSetStat() {
+ public void doneSetStat(IToken token, FileSystemException error) {
+ if (error != null) error(error);
+ else done(true);
+ }
+ });
+ }
+ });
+ }
+ }.getS(monitor, "Set permissions");
+ }
+
+ public boolean upload(InputStream inp,
+ String parent, String name, boolean isBinary,
+ String hostEncoding, IProgressMonitor monitor) throws SystemMessageException {
+ monitor.beginTask("Upload", 1);
+ try {
+ OutputStream out = getOutputStream(parent, name, isBinary, new NullProgressMonitor());
+ copyStream(inp, out, isBinary, hostEncoding, "UTF8");
+ return true;
+ }
+ catch (Throwable x) {
+ if (x instanceof SystemMessageException) throw (SystemMessageException)x;
+ throw new SystemMessageException(getMessage(x));
+ }
+ finally {
+ monitor.done();
+ }
+ }
+
+ public boolean upload(File localFile,
+ String parent, String name, boolean isBinary,
+ String srcEncoding, String hostEncoding, IProgressMonitor monitor)
+ throws SystemMessageException {
+ monitor.beginTask("Upload", 1);
+ try {
+ OutputStream out = getOutputStream(parent, name, isBinary, new NullProgressMonitor());
+ InputStream inp = new BufferedInputStream(new FileInputStream(localFile));
+ copyStream(inp, out, isBinary, hostEncoding, "UTF8");
+ return true;
+ }
+ catch (Throwable x) {
+ if (x instanceof SystemMessageException) throw (SystemMessageException)x;
+ throw new SystemMessageException(getMessage(x));
+ }
+ finally {
+ monitor.done();
+ }
+ }
+
+ private void copyStream(InputStream inp, OutputStream out,
+ boolean is_binary, String inp_encoding, String out_encoding) throws IOException {
+ try {
+ if (!is_binary) {
+ if (inp_encoding.equals("UTF-8")) inp_encoding = "UTF8";
+ if (out_encoding.equals("UTF-8")) out_encoding = "UTF8";
+ }
+ if (is_binary || inp_encoding.equals(out_encoding)) {
+ byte[] buf = new byte[0x1000];
+ for (;;) {
+ int buf_len = inp.read(buf);
+ if (buf_len < 0) break;
+ out.write(buf, 0, buf_len);
+ }
+ }
+ else {
+ Reader reader = new InputStreamReader(inp, inp_encoding);
+ Writer writer = new OutputStreamWriter(out, out_encoding);
+ char[] buf = new char[0x1000];
+ for (;;) {
+ int buf_len = reader.read(buf);
+ if (buf_len < 0) break;
+ writer.write(buf, 0, buf_len);
+ }
+ writer.flush();
+ }
+ }
+ finally {
+ out.close();
+ inp.close();
+ }
+ }
+
+ private synchronized UserInfo getUserInfo() {
+ if (user_info == null || user_info.error != null) {
+ user_info = new TCFRSETask<UserInfo>() {
+ public void run() {
+ IFileSystem fs = connector.getFileSystemService();
+ fs.user(new IFileSystem.DoneUser() {
+ public void doneUser(IToken token, FileSystemException error, int real_uid,
+ int effective_uid, int real_gid, int effective_gid, String home) {
+ if (error != null) done(new UserInfo(error));
+ else done(new UserInfo(real_uid, effective_uid, real_gid, effective_gid, home));
+ }
+ });
+ }
+ }.getE();
+ }
+ return user_info;
+ }
+
+ public boolean canRead(FileAttrs attrs) {
+ if ((attrs.flags & IFileSystem.ATTR_PERMISSIONS) == 0) return false;
+ if ((attrs.flags & IFileSystem.ATTR_UIDGID) == 0) return false;
+ UserInfo ui = getUserInfo();
+ if (ui.error != null) return false;
+ if (ui.e_uid == attrs.uid) {
+ return (attrs.permissions & IFileSystem.S_IRUSR) != 0;
+ }
+ if (ui.e_gid == attrs.gid) {
+ return (attrs.permissions & IFileSystem.S_IRGRP) != 0;
+ }
+ return (attrs.permissions & IFileSystem.S_IROTH) != 0;
+ }
+
+ public boolean canWrite(FileAttrs attrs) {
+ if ((attrs.flags & IFileSystem.ATTR_PERMISSIONS) == 0) return false;
+ if ((attrs.flags & IFileSystem.ATTR_UIDGID) == 0) return false;
+ UserInfo ui = getUserInfo();
+ if (ui.error != null) return false;
+ if (ui.e_uid == attrs.uid) {
+ return (attrs.permissions & IFileSystem.S_IWUSR) != 0;
+ }
+ if (ui.e_gid == attrs.gid) {
+ return (attrs.permissions & IFileSystem.S_IWGRP) != 0;
+ }
+ return (attrs.permissions & IFileSystem.S_IWOTH) != 0;
+ }
+
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileSubSystemConfiguration.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileSubSystemConfiguration.java
new file mode 100644
index 000000000..af6678aef
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFFileSubSystemConfiguration.java
@@ -0,0 +1,116 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import java.util.Vector;
+
+import org.eclipse.rse.core.filters.ISystemFilter;
+import org.eclipse.rse.core.filters.ISystemFilterPool;
+import org.eclipse.rse.core.filters.ISystemFilterPoolManager;
+import org.eclipse.rse.core.model.IHost;
+import org.eclipse.rse.core.subsystems.IConnectorService;
+import org.eclipse.rse.core.subsystems.ISubSystem;
+import org.eclipse.rse.services.clientserver.SystemSearchString;
+import org.eclipse.rse.services.files.IFileService;
+import org.eclipse.rse.services.search.IHostSearchResultConfiguration;
+import org.eclipse.rse.services.search.IHostSearchResultSet;
+import org.eclipse.rse.services.search.ISearchService;
+import org.eclipse.rse.subsystems.files.core.ILanguageUtilityFactory;
+import org.eclipse.rse.subsystems.files.core.model.RemoteFileFilterString;
+import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystem;
+import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystemConfiguration;
+import org.eclipse.rse.subsystems.files.core.subsystems.IHostFileToRemoteFileAdapter;
+import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileSubSystem;
+import org.eclipse.rse.ui.SystemBasePlugin;
+
+public class TCFFileSubSystemConfiguration extends FileServiceSubSystemConfiguration {
+
+ private final TCFFileAdapter file_adapter = new TCFFileAdapter();
+
+ @Override
+ public ISubSystem createSubSystemInternal(IHost host) {
+ TCFConnectorService connectorService = (TCFConnectorService)getConnectorService(host);
+ return new FileServiceSubSystem(host, connectorService,
+ getFileService(host), getHostFileAdapter(), createSearchService(host));
+ }
+
+ public IFileService createFileService(IHost host) {
+ return new TCFFileService(host);
+ }
+
+ public IHostSearchResultConfiguration createSearchConfiguration(IHost host,
+ IHostSearchResultSet resultSet, Object searchTarget,
+ SystemSearchString searchString) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public ISearchService createSearchService(IHost host) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public IHostFileToRemoteFileAdapter getHostFileAdapter() {
+ return file_adapter;
+ }
+
+ public ILanguageUtilityFactory getLanguageUtilityFactory(IRemoteFileSubSystem ss) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean supportsArchiveManagement() {
+ return false;
+ }
+
+ public IConnectorService getConnectorService(IHost host) {
+ return TCFConnectorServiceManager.getInstance()
+ .getConnectorService(host, ITCFSubSystem.class);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Class getServiceImplType() {
+ return TCFFileService.class;
+ }
+
+ public void setConnectorService(IHost host, IConnectorService connectorService) {
+ TCFConnectorServiceManager.getInstance().setConnectorService(host, getServiceImplType(), connectorService);
+ }
+
+ protected ISystemFilterPool createDefaultFilterPool(ISystemFilterPoolManager mgr) {
+ ISystemFilterPool pool = null;
+ try {
+ pool = mgr.createSystemFilterPool(getDefaultFilterPoolName(mgr.getName(), getId()), true);
+
+ Vector<String> filterStrings = new Vector<String>();
+ RemoteFileFilterString myHomeFilterString = new RemoteFileFilterString(this);
+ myHomeFilterString.setPath(".");
+ myHomeFilterString.setFile("*");
+ filterStrings.add(myHomeFilterString.toString());
+ ISystemFilter filter = mgr.createSystemFilter(pool, "Home", filterStrings);
+ filter.setNonChangable(true);
+ filter.setSingleFilterStringOnly(true);
+
+ filterStrings = new Vector<String>();
+ RemoteFileFilterString rootFilesFilterString = new RemoteFileFilterString(this);
+ rootFilesFilterString.setPath("");
+ rootFilesFilterString.setFile("*");
+ filterStrings.add(rootFilesFilterString.toString());
+ filter = mgr.createSystemFilter(pool, "Root", filterStrings);
+ filter.setNonChangable(true);
+ filter.setSingleFilterStringOnly(true);
+ }
+ catch (Exception exc) {
+ SystemBasePlugin.logError("Error creating default filter pool", exc); //$NON-NLS-1$
+ }
+ return pool;
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessAdapter.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessAdapter.java
new file mode 100644
index 000000000..3748cda67
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessAdapter.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.rse.services.clientserver.processes.IHostProcess;
+import org.eclipse.rse.subsystems.processes.core.subsystem.IHostProcessToRemoteProcessAdapter;
+import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcess;
+import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcessContext;
+
+public class TCFProcessAdapter implements IHostProcessToRemoteProcessAdapter {
+
+ public IRemoteProcess convertToRemoteProcess(IRemoteProcessContext context,
+ IRemoteProcess parent, IHostProcess node) {
+ IHostProcess[] nodes = new IHostProcess[]{ node };
+ IRemoteProcess[] processes = convertToRemoteProcesses(context, parent, nodes);
+ if (processes != null && processes.length > 0) return processes[0];
+ return null;
+ }
+
+ public IRemoteProcess[] convertToRemoteProcesses(
+ IRemoteProcessContext context, IRemoteProcess parent,
+ IHostProcess[] nodes) {
+
+ if (nodes == null)return null;
+ List<IRemoteProcess> list = new ArrayList<IRemoteProcess>(nodes.length);
+ for (int idx = 0; idx < nodes.length; idx++) {
+ TCFProcessResource node = (TCFProcessResource)nodes[idx];
+ list.add(new TCFRemoteProcess(context, node));
+ }
+ return list.toArray(new IRemoteProcess[list.size()]);
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessResource.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessResource.java
new file mode 100644
index 000000000..b46d4e4a5
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessResource.java
@@ -0,0 +1,313 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import java.math.BigInteger;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.rse.core.subsystems.AbstractResource;
+import org.eclipse.rse.services.clientserver.processes.IHostProcess;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.protocol.Protocol;
+import com.windriver.tcf.api.services.ISysMonitor;
+import com.windriver.tcf.api.services.ISysMonitor.SysMonitorContext;
+
+public class TCFProcessResource extends AbstractResource implements IHostProcess {
+
+ private final TCFProcessService rse_service;
+ private final ISysMonitor tcf_service;
+ private final TCFProcessResource prev;
+ private final String id;
+ private Throwable error;
+ private ISysMonitor.SysMonitorContext context;
+
+ private final List<Runnable> children_wait_list = new ArrayList<Runnable>();
+ private boolean children_loading;
+ private boolean children_loaded;
+ private Throwable children_error;
+ private boolean running_wait_list;
+
+ private long gid = -1;
+ private String name;
+ private long ppid = -1;
+ private long pid = -1;
+ private String state;
+ private long tgid = -1;
+ private long tracepid = -1;
+ private long uid;
+ private String username;
+ private long vm_rss_kb;
+ private long vm_size_kb;
+ private String utime_pc;
+ private String stime_pc;
+ private long timestamp;
+
+ private Map<String, Object> properties = new HashMap<String, Object>();
+
+ private static final NumberFormat percent_format;
+
+ static {
+ percent_format = NumberFormat.getPercentInstance();
+ percent_format.setMaximumFractionDigits(3);
+ }
+
+ TCFProcessResource(TCFProcessService rse_service, ISysMonitor service,
+ TCFProcessResource prev, String id) {
+ this.rse_service = rse_service;
+ this.tcf_service = service;
+ this.prev = prev;
+ this.id = id;
+ }
+
+ public String getID() {
+ return id;
+ }
+
+ public String getParentID() {
+ return (String)properties.get(ISysMonitor.PROP_PARENTID);
+ }
+
+ public TCFProcessService getService() {
+ return rse_service;
+ }
+
+ public void invalidate() {
+ assert Protocol.isDispatchThread();
+ error = null;
+ context = null;
+ }
+
+ public boolean validate(final Runnable done) {
+ assert Protocol.isDispatchThread();
+ if (error != null) return true;
+ if (context != null) return true;
+ tcf_service.getContext(id, new ISysMonitor.DoneGetContext() {
+
+ public void doneGetContext(IToken token, Exception error, SysMonitorContext context) {
+ TCFProcessResource.this.error = error;
+ TCFProcessResource.this.context = context;
+ if (error != null) {
+ properties = new HashMap<String, Object>();
+ gid = -1;
+ name = null;
+ ppid = -1;
+ pid = -1;
+ state = null;
+ tgid = -1;
+ tracepid = -1;
+ uid = 0;
+ username = null;
+ vm_rss_kb = 0;
+ vm_size_kb = 0;
+ }
+ else {
+ properties = new HashMap<String, Object>(context.getProperties());
+ gid = context.getUGID();
+ name = context.getFile();
+ if (properties.containsKey(ISysMonitor.PROP_PPID)) {
+ ppid = context.getPPID();
+ }
+ pid = context.getPID();
+ state = context.getState();
+ tgid = context.getTGID();
+ if (properties.containsKey(ISysMonitor.PROP_TRACERPID)) {
+ tracepid = context.getTracerPID();
+ }
+ uid = context.getUID();
+ username = context.getUserName();
+ vm_rss_kb = context.getRSS();
+ long page_bytes = context.getPSize();
+ if (page_bytes <= 0 || vm_rss_kb < 0) {
+ vm_rss_kb = -1;
+ }
+ else {
+ vm_rss_kb = (vm_rss_kb * page_bytes + 1023) / 1024;
+ }
+ vm_size_kb = (context.getVSize() + 1023) / 1024;
+ }
+ timestamp = System.currentTimeMillis();
+ Protocol.invokeLater(done);
+ }
+
+ });
+ return false;
+ }
+
+ public Throwable getError() {
+ assert Protocol.isDispatchThread();
+ return error;
+ }
+
+ public ISysMonitor.SysMonitorContext getContext() {
+ assert Protocol.isDispatchThread();
+ return context;
+ }
+
+ // IHostProcess methods
+
+ public String getAllProperties() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public long getGid() {
+ return gid;
+ }
+
+ public String getLabel() {
+ return Long.toString(getPid()) + " " + name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public long getPPid() {
+ return ppid;
+ }
+
+ public long getPid() {
+ return pid;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public long getTgid() {
+ return tgid;
+ }
+
+ public long getTracerPid() {
+ return tracepid;
+ }
+
+ public long getUid() {
+ return uid;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public long getVmRSSInKB() {
+ return vm_rss_kb;
+ }
+
+ public long getVmSizeInKB() {
+ return vm_size_kb;
+ }
+
+ public boolean isRoot() {
+ return true;
+ }
+
+ String getStatusLine() {
+ final String STATUS_DELIMITER = "|"; //$NON-NLS-1$
+ StringBuffer s = new StringBuffer();
+ s.append(getPid()).append(STATUS_DELIMITER);
+ s.append(name).append(STATUS_DELIMITER);
+ s.append(getState()).append(STATUS_DELIMITER);
+ s.append(getTgid()).append(STATUS_DELIMITER);
+ s.append(getPPid()).append(STATUS_DELIMITER);
+ s.append('0').append(STATUS_DELIMITER);
+ s.append(getUid()).append(STATUS_DELIMITER);
+ s.append(getUsername()).append(STATUS_DELIMITER);
+ s.append(getGid()).append(STATUS_DELIMITER);
+ s.append(getVmSizeInKB()).append(STATUS_DELIMITER);
+ s.append(getVmRSSInKB()).append(STATUS_DELIMITER);
+ return s.toString();
+ }
+
+ public Map<String,Object> getProperties() {
+ return properties;
+ }
+
+ private String getTimePC(String name) {
+ if (prev == null) return null;
+ Object x = prev.properties.get(name);
+ Object y = properties.get(name);
+ if (x instanceof Number && y instanceof Number) {
+ BigInteger nx = x instanceof BigInteger ? (BigInteger)x : new BigInteger(x.toString());
+ BigInteger ny = y instanceof BigInteger ? (BigInteger)y : new BigInteger(y.toString());
+ double d = ny.subtract(nx).doubleValue() / (timestamp - prev.timestamp);
+ return percent_format.format(d);
+ }
+ return null;
+ }
+
+ public String getUserTimePC() {
+ if (utime_pc != null) return utime_pc;
+ return utime_pc = getTimePC(ISysMonitor.PROP_UTIME);
+ }
+
+ public String getSysTimePC() {
+ if (stime_pc != null) return stime_pc;
+ return stime_pc = getTimePC(ISysMonitor.PROP_STIME);
+ }
+
+ public boolean getChildrenLoading() {
+ return children_loading;
+ }
+
+ public void setChildrenLoading(boolean b) {
+ children_loading = b;
+ }
+
+ public boolean getChildrenLoaded() {
+ return children_loaded;
+ }
+
+ public void setChildrenLoaded(boolean b) {
+ children_loaded = b;
+ }
+
+ public Throwable getChildrenError() {
+ return children_error;
+ }
+
+ public void setChildrenError(Throwable error) {
+ children_error = error;
+ }
+
+ public void addChildrenWaitList(Runnable run) {
+ assert !running_wait_list;
+ assert children_loading;
+ assert !children_loaded;
+ children_wait_list.add(run);
+ }
+
+ public void runChildrenWaitList() {
+ assert !children_loading;
+ assert children_loaded;
+ try {
+ running_wait_list = true;
+ for (Runnable r : children_wait_list) r.run();
+ children_wait_list.clear();
+ }
+ finally {
+ running_wait_list = false;
+ }
+ }
+
+ public void cancelChildrenLoading() {
+ // TODO: cancelChildrenLoading
+ }
+
+ public String toString() {
+ return "[" + getStatusLine() + "]";
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessService.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessService.java
new file mode 100644
index 000000000..4f3445b9f
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessService.java
@@ -0,0 +1,275 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.rse.core.model.IHost;
+import org.eclipse.rse.services.clientserver.messages.IndicatorException;
+import org.eclipse.rse.services.clientserver.messages.SystemMessage;
+import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
+import org.eclipse.rse.services.clientserver.processes.HostProcessFilterImpl;
+import org.eclipse.rse.services.clientserver.processes.IHostProcess;
+import org.eclipse.rse.services.clientserver.processes.IHostProcessFilter;
+import org.eclipse.rse.services.processes.IProcessService;
+
+import com.windriver.tcf.api.protocol.IToken;
+import com.windriver.tcf.api.services.ISysMonitor;
+
+public class TCFProcessService implements IProcessService {
+
+ private final TCFConnectorService connector;
+ private final TCFProcessResource root;
+ private final Map<String,TCFProcessResource> id2res = new HashMap<String,TCFProcessResource>();
+ private final Map<Long,TCFProcessResource> pid2res = new HashMap<Long,TCFProcessResource>();
+
+ public TCFProcessService(IHost host) {
+ connector = (TCFConnectorService)TCFConnectorServiceManager
+ .getInstance().getConnectorService(host, ITCFSubSystem.class);
+ root = new TCFProcessResource(this, null, null, null);
+ }
+
+ public String getDescription() {
+ return "The TCF Process Service uses the Target Communication Framework to provide service for the Processes subsystem." +
+ " It requires a TCF agent to be running on the remote machine.";
+ }
+
+ public SystemMessage getMessage(String messageID) {
+ try {
+ return new SystemMessage("TCF", "C", "0001",
+ SystemMessage.ERROR, messageID, null);
+ }
+ catch (IndicatorException e) {
+ throw new Error(e);
+ }
+ }
+
+ public String getName() {
+ return "TCF Process Service";
+ }
+
+ public void initService(IProgressMonitor monitor) {
+ }
+
+ public void uninitService(IProgressMonitor monitor) {
+ }
+
+ public IHostProcess getParentProcess(long PID, IProgressMonitor monitor)
+ throws SystemMessageException {
+ return getProcess(getProcess(PID, monitor).getPPid(), monitor);
+ }
+
+ public IHostProcess getProcess(final long PID, IProgressMonitor monitor)
+ throws SystemMessageException {
+ return new TCFRSETask<IHostProcess>() {
+ public void run() {
+ if (!loadProcesses(this, root)) return;
+ if (root.getChildrenError() != null) {
+ error(root.getChildrenError());
+ return;
+ }
+ done(pid2res.get(PID));
+ }
+ }.getS(monitor, "Get process properties");
+ }
+
+ public String[] getSignalTypes() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public boolean kill(long PID, String signal, IProgressMonitor monitor)
+ throws SystemMessageException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ private void sort(IHostProcess[] arr) {
+ Comparator<IHostProcess> c = new Comparator<IHostProcess>() {
+ public int compare(IHostProcess o1, IHostProcess o2) {
+ long p1 = o1.getPid();
+ long p2 = o2.getPid();
+ if (p1 < p2) return -1;
+ if (p1 > p2) return 1;
+ return 0;
+ }
+ };
+ Arrays.sort(arr, c);
+ }
+
+ public IHostProcess[] listAllProcesses(IProgressMonitor monitor) throws SystemMessageException {
+ HostProcessFilterImpl rpfs = new HostProcessFilterImpl();
+ return listAllProcesses(rpfs, monitor);
+ }
+
+ public IHostProcess[] listAllProcesses(final IHostProcessFilter filter, IProgressMonitor monitor) throws SystemMessageException {
+ return listAllProcesses(filter, root, monitor);
+ }
+
+ private boolean eqaulIDs(String x, String y) {
+ if (x == null) return y == null;
+ return x.equals(y);
+ }
+
+ public IHostProcess[] listAllProcesses(final IHostProcessFilter filter, final IHostProcess up, IProgressMonitor monitor) throws SystemMessageException {
+ // TODO: figure out better way to flush the cache
+ final TCFProcessResource parent = new TCFRSETask<TCFProcessResource>() {
+ public void run() {
+ TCFProcessResource parent = (TCFProcessResource)up;
+ if (parent == null) {
+ error(new IOException("Invalid parent"));
+ return;
+ }
+ if (filter.getPpid() != null && filter.getPpid().equals("*") || parent.getChildrenError() != null) {
+ for (Iterator<TCFProcessResource> i = pid2res.values().iterator(); i.hasNext();) {
+ TCFProcessResource r = i.next();
+ if (eqaulIDs(parent.getID(), r.getParentID())) {
+ i.remove();
+ if (r.getChildrenLoaded()) r.cancelChildrenLoading();
+ }
+ }
+ parent.setChildrenLoaded(false);
+ parent.setChildrenError(null);
+ }
+ done(parent);
+ }
+ }.getS(monitor, "Flush processes cache");
+ return new TCFRSETask<IHostProcess[]>() {
+ public void run() {
+ if (!loadProcesses(this, parent)) return;
+ if (parent.getChildrenError() != null) {
+ error(parent.getChildrenError());
+ return;
+ }
+ List<IHostProcess> l = new ArrayList<IHostProcess>();
+ for (TCFProcessResource p : pid2res.values()) {
+ if (eqaulIDs(parent.getID(), p.getParentID())) {
+ Throwable error = p.getError();
+ if (error == null && filter.allows(p.getStatusLine())) l.add(p);
+ }
+ }
+ IHostProcess[] arr = new IHostProcess[l.size()];
+ l.toArray(arr);
+ sort(arr);
+ done(arr);
+ }
+ }.getS(monitor, "List processes");
+ }
+
+ public IHostProcess[] listAllProcesses(String exeNameFilter, String userNameFilter, String stateFilter, IProgressMonitor monitor)
+ throws SystemMessageException {
+ HostProcessFilterImpl rpfs = new HostProcessFilterImpl();
+ rpfs.setName(exeNameFilter);
+ rpfs.setUsername(userNameFilter);
+ rpfs.setSpecificState(stateFilter);
+ return listAllProcesses(rpfs, monitor);
+ }
+
+ public IHostProcess[] listChildProcesses(long parentPID, IProgressMonitor monitor) throws SystemMessageException {
+ HostProcessFilterImpl rpfs = new HostProcessFilterImpl();
+ return listChildProcesses(parentPID, rpfs, monitor);
+ }
+
+ public IHostProcess[] listChildProcesses(long parentPID, IHostProcessFilter filter, IProgressMonitor monitor)
+ throws SystemMessageException {
+ filter.setPpid(Long.toString(parentPID));
+ return listAllProcesses(filter, monitor);
+ }
+
+ public IHostProcess[] listRootProcesses(IProgressMonitor monitor)
+ throws SystemMessageException {
+ IHostProcess[] roots = new IHostProcess[1];
+ roots[0] = getProcess(1, monitor);
+ return roots;
+ }
+
+ private boolean loadProcesses(Runnable run, final TCFProcessResource parent) {
+ if (parent.getChildrenLoading()) {
+ parent.addChildrenWaitList(run);
+ return false;
+ }
+ if (parent.getChildrenLoaded()) {
+ return true;
+ }
+ parent.setChildrenLoading(true);
+ try {
+ final ISysMonitor m = connector.getSysMonitorService();
+ m.getChildren(parent.getID(), new ISysMonitor.DoneGetChildren() {
+ public void doneGetChildren(IToken token, Exception error, String[] ids) {
+ try {
+ if (error != null) {
+ loadProcessesDone(parent, error, null);
+ }
+ else if (ids == null) {
+ loadProcessesDone(parent, null, new TCFProcessResource[0]);
+ }
+ else {
+ final TCFProcessResource[] arr = new TCFProcessResource[ids.length];
+ final Set<IHostProcess> pending = new HashSet<IHostProcess>();
+ for (int i = 0; i < ids.length; i++) {
+ final TCFProcessResource r = new TCFProcessResource(
+ TCFProcessService.this, m, id2res.get(ids[i]), ids[i]);
+ if (!r.validate(new Runnable() {
+ public void run() {
+ pending.remove(r);
+ if (pending.isEmpty()) loadProcessesDone(parent, null, arr);
+ }
+ })) pending.add(r);
+ arr[i] = r;
+ }
+ if (pending.isEmpty()) loadProcessesDone(parent, null, arr);
+ }
+ }
+ catch (Throwable x) {
+ loadProcessesDone(parent, x, null);
+ }
+ }
+ });
+ parent.addChildrenWaitList(run);
+ return false;
+ }
+ catch (Throwable x) {
+ loadProcessesDone(parent, x, null);
+ return true;
+ }
+ }
+
+ private void loadProcessesDone(TCFProcessResource parent, Throwable error, TCFProcessResource[] arr) {
+ assert parent.getChildrenLoading();
+ parent.setChildrenLoading(false);
+ parent.setChildrenLoaded(true);
+ if (arr != null && error == null) {
+ for (TCFProcessResource r : arr) {
+ long pid = r.getPid();
+ if (pid > 0 && parent.getPid() != pid) {
+ pid2res.put(new Long(pid), r);
+ id2res.put(r.getID(), r);
+ }
+ }
+ }
+ for (Iterator<TCFProcessResource> i = id2res.values().iterator(); i.hasNext();) {
+ TCFProcessResource r = i.next();
+ if (pid2res.get(r.getPid()) == null) i.remove();
+ }
+ parent.setChildrenError(error);
+ parent.runChildrenWaitList();
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessSubSystemConfiguration.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessSubSystemConfiguration.java
new file mode 100644
index 000000000..0c7242051
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFProcessSubSystemConfiguration.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import org.eclipse.rse.core.model.IHost;
+import org.eclipse.rse.core.subsystems.IConnectorService;
+import org.eclipse.rse.core.subsystems.ISubSystem;
+import org.eclipse.rse.services.processes.IProcessService;
+import org.eclipse.rse.subsystems.processes.core.subsystem.IHostProcessToRemoteProcessAdapter;
+import org.eclipse.rse.subsystems.processes.servicesubsystem.ProcessServiceSubSystem;
+import org.eclipse.rse.subsystems.processes.servicesubsystem.ProcessServiceSubSystemConfiguration;
+
+public class TCFProcessSubSystemConfiguration extends ProcessServiceSubSystemConfiguration {
+
+ private final TCFProcessAdapter process_adapter = new TCFProcessAdapter();
+
+ @SuppressWarnings("unchecked")
+ public Class getServiceImplType() {
+ return TCFProcessService.class;
+ }
+
+ @Override
+ public ISubSystem createSubSystemInternal(IHost host) {
+ TCFConnectorService connectorService = (TCFConnectorService)getConnectorService(host);
+ return new ProcessServiceSubSystem(host, connectorService,
+ getProcessService(host), getHostProcessAdapter());
+ }
+
+ public IProcessService createProcessService(IHost host) {
+ return new TCFProcessService(host);
+ }
+
+ public IHostProcessToRemoteProcessAdapter getHostProcessAdapter() {
+ return process_adapter;
+ }
+
+ public IConnectorService getConnectorService(IHost host) {
+ return TCFConnectorServiceManager.getInstance()
+ .getConnectorService(host, ITCFSubSystem.class);
+ }
+
+ public void setConnectorService(IHost host, IConnectorService connectorService) {
+ TCFConnectorServiceManager.getInstance().setConnectorService(host, getServiceImplType(), connectorService);
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRSETask.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRSETask.java
new file mode 100644
index 000000000..9a37e4b6e
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRSETask.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.concurrent.ExecutionException;
+
+import com.windriver.tcf.api.util.TCFTask;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.rse.services.clientserver.messages.IndicatorException;
+import org.eclipse.rse.services.clientserver.messages.SystemMessage;
+import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
+
+public abstract class TCFRSETask<V> extends TCFTask<V> {
+
+ public V get(IProgressMonitor monitor, String task_name)
+ throws InterruptedException, ExecutionException {
+ monitor.beginTask(task_name, 1);
+ try {
+ return get();
+ }
+ finally {
+ monitor.done();
+ }
+ }
+
+ public V getS(IProgressMonitor monitor, String task_name) throws SystemMessageException {
+ if (monitor != null) monitor.beginTask(task_name, 1);
+ try {
+ return get();
+ }
+ catch (Throwable e) {
+ if (e instanceof SystemMessageException) throw (SystemMessageException)e;
+ try {
+ SystemMessage m = new SystemMessage("TCF", "C", "0001", SystemMessage.ERROR,
+ e.getClass().getName(), e.getMessage());
+ throw new SystemMessageException(m);
+ }
+ catch (IndicatorException e1) {
+ throw new Error(e1);
+ }
+ }
+ finally {
+ if (monitor != null) monitor.done();
+ }
+ }
+
+ public V getI(IProgressMonitor monitor, String task_name) throws InvocationTargetException, InterruptedException {
+ if (monitor != null) monitor.beginTask(task_name, 1);
+ try {
+ return get();
+ }
+ catch (Throwable e) {
+ if (e instanceof InvocationTargetException) throw (InvocationTargetException)e;
+ if (e instanceof InterruptedException) throw (InterruptedException)e;
+ throw new InvocationTargetException(e);
+ }
+ finally {
+ if (monitor != null) monitor.done();
+ }
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRemoteFile.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRemoteFile.java
new file mode 100644
index 000000000..6b396d610
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRemoteFile.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import org.eclipse.rse.services.files.IHostFile;
+import org.eclipse.rse.subsystems.files.core.servicesubsystem.AbstractRemoteFile;
+import org.eclipse.rse.subsystems.files.core.servicesubsystem.FileServiceSubSystem;
+import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFile;
+import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileContext;
+
+public class TCFRemoteFile extends AbstractRemoteFile {
+
+ public TCFRemoteFile(FileServiceSubSystem ss, IRemoteFileContext ctx, IRemoteFile parent, IHostFile file) {
+ super(ss, ctx, parent, file);
+ }
+
+ public String getCanonicalPath() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String getClassification() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRemoteProcess.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRemoteProcess.java
new file mode 100644
index 000000000..d44b7200c
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFRemoteProcess.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import java.util.Map;
+
+import org.eclipse.rse.services.clientserver.processes.IHostProcess;
+import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcessContext;
+import org.eclipse.rse.subsystems.processes.core.subsystem.impl.RemoteProcessImpl;
+
+public class TCFRemoteProcess extends RemoteProcessImpl {
+
+ public TCFRemoteProcess(IRemoteProcessContext context, IHostProcess process) {
+ super(context, process);
+ assert process != null;
+ }
+
+ public Object getObject() {
+ return _underlyingProcess;
+ }
+
+ public Map<String,Object> getProperties() {
+ return ((TCFProcessResource)_underlyingProcess).getProperties();
+ }
+
+ public String getUserTimePC() {
+ return ((TCFProcessResource)_underlyingProcess).getUserTimePC();
+ }
+
+ public String getSysTimePC() {
+ return ((TCFProcessResource)_underlyingProcess).getSysTimePC();
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFSystemViewProcessAdapterFactory.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFSystemViewProcessAdapterFactory.java
new file mode 100644
index 000000000..b97047796
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFSystemViewProcessAdapterFactory.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.rse.core.subsystems.IRemoteObjectIdentifier;
+import org.eclipse.rse.core.subsystems.ISystemDragDropAdapter;
+import org.eclipse.rse.ui.view.ISystemRemoteElementAdapter;
+import org.eclipse.rse.ui.view.ISystemViewElementAdapter;
+import org.eclipse.ui.IActionFilter;
+import org.eclipse.ui.model.IWorkbenchAdapter;
+import org.eclipse.ui.progress.IDeferredWorkbenchAdapter;
+import org.eclipse.ui.views.properties.IPropertySource;
+
+public class TCFSystemViewProcessAdapterFactory implements IAdapterFactory {
+
+ private final TCFSystemViewRemoteProcessAdapter adapter =
+ new TCFSystemViewRemoteProcessAdapter();
+
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Object adaptableObject, Class adapterType) {
+ assert adaptableObject instanceof TCFRemoteProcess;
+ if (adapterType == IPropertySource.class) {
+ ((ISystemViewElementAdapter)adapter).setPropertySourceInput(adaptableObject);
+ }
+ return adapter;
+ }
+
+ @SuppressWarnings("unchecked")
+ public Class[] getAdapterList() {
+ return new Class[] {
+ ISystemViewElementAdapter.class,
+ ISystemDragDropAdapter.class,
+ ISystemRemoteElementAdapter.class,
+ IPropertySource.class,
+ IWorkbenchAdapter.class,
+ IActionFilter.class,
+ IDeferredWorkbenchAdapter.class,
+ IRemoteObjectIdentifier.class,
+ };
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFSystemViewRemoteProcessAdapter.java b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFSystemViewRemoteProcessAdapter.java
new file mode 100644
index 000000000..748f262ab
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/TCFSystemViewRemoteProcessAdapter.java
@@ -0,0 +1,446 @@
+/*******************************************************************************
+ * Copyright (c) 2007 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 com.windriver.tcf.rse.ui;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.rse.core.model.ISystemMessageObject;
+import org.eclipse.rse.core.model.ISystemResourceSet;
+import org.eclipse.rse.core.model.SystemMessageObject;
+import org.eclipse.rse.core.model.SystemRemoteResourceSet;
+import org.eclipse.rse.core.subsystems.ISubSystem;
+import org.eclipse.rse.services.clientserver.processes.HostProcessFilterImpl;
+import org.eclipse.rse.services.clientserver.processes.IHostProcess;
+import org.eclipse.rse.services.clientserver.processes.IHostProcessFilter;
+import org.eclipse.rse.services.clientserver.processes.ISystemProcessRemoteTypes;
+import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcess;
+import org.eclipse.rse.subsystems.processes.core.subsystem.IRemoteProcessSubSystem;
+import org.eclipse.rse.ui.ISystemMessages;
+import org.eclipse.rse.ui.RSEUIPlugin;
+import org.eclipse.rse.ui.SystemBasePlugin;
+import org.eclipse.rse.ui.SystemMenuManager;
+import org.eclipse.rse.ui.actions.SystemCopyToClipboardAction;
+import org.eclipse.rse.ui.view.AbstractSystemViewAdapter;
+import org.eclipse.rse.ui.view.ISystemRemoteElementAdapter;
+import org.eclipse.rse.ui.view.ISystemViewElementAdapter;
+import org.eclipse.swt.dnd.Clipboard;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.views.properties.IPropertyDescriptor;
+
+import com.windriver.tcf.api.services.ISysMonitor;
+
+public class TCFSystemViewRemoteProcessAdapter extends AbstractSystemViewAdapter
+ implements ISystemViewElementAdapter, ISystemRemoteElementAdapter{
+
+ private SystemCopyToClipboardAction copyClipboardAction;
+ private static final Object[] EMPTY_LIST = new Object[0];
+ private static IPropertyDescriptor[] properties = null;
+ //private SystemKillProcessAction killProcessAction;
+
+ private static final String PROP_PC_UTIME = "PCUTime";
+ private static final String PROP_PC_STIME = "PCSTime";
+
+ public boolean canDrag(Object element) {
+ return true;
+ }
+
+ public boolean canDrag(SystemRemoteResourceSet elements) {
+ return true;
+ }
+
+ public Object doDrag(Object element, boolean sameSystemType, IProgressMonitor monitor) {
+ return getText(element);
+ }
+
+ public ISystemResourceSet doDrag(SystemRemoteResourceSet set, IProgressMonitor monitor) {
+ return set;
+ }
+
+ public void addActions(SystemMenuManager menu,
+ IStructuredSelection selection, Shell parent, String menuGroup) {
+ /*
+ if (killProcessAction == null)
+ killProcessAction = new SystemKillProcessAction(shell);
+ menu.add(ISystemContextMenuConstants.GROUP_CHANGE, killProcessAction);
+ */
+
+ if (copyClipboardAction == null) {
+ Clipboard clipboard = RSEUIPlugin.getTheSystemRegistryUI().getSystemClipboard();
+ copyClipboardAction = new SystemCopyToClipboardAction(shell, clipboard);
+ }
+ menu.add(menuGroup, copyClipboardAction);
+ }
+
+ public ISubSystem getSubSystem(Object element) {
+ if (element instanceof IRemoteProcess) {
+ IRemoteProcess process = (IRemoteProcess)element;
+ return process.getParentRemoteProcessSubSystem();
+ }
+ return super.getSubSystem(element);
+ }
+
+ public ImageDescriptor getImageDescriptor(Object element) {
+ IRemoteProcess process = (IRemoteProcess)element;
+ TCFProcessResource r = (TCFProcessResource)process.getObject();
+ String state = r.getState();
+ if (r.getParentID() != null) {
+ if (state.indexOf('R') >= 0) {
+ return Activator.getDefault().getImageDescriptorFromPath("icons/thread-r.gif"); //$NON-NLS-1$
+ }
+ return Activator.getDefault().getImageDescriptorFromPath("icons/thread-s.gif"); //$NON-NLS-1$
+ }
+ else {
+ if (state.indexOf('R') >= 0) {
+ return Activator.getDefault().getImageDescriptorFromPath("icons/process-r.gif"); //$NON-NLS-1$
+ }
+ return Activator.getDefault().getImageDescriptorFromPath("icons/process-s.gif"); //$NON-NLS-1$
+ }
+ }
+
+ public String getText(Object element) {
+ String text = ((IRemoteProcess)element).getLabel();
+ return (text == null) ? "" : text; //$NON-NLS-1$
+ }
+
+ public String getAlternateText(Object element) {
+ IRemoteProcess process = (IRemoteProcess)element;
+ String allProperties = process.getAllProperties();
+ return allProperties.replace('|', '\t');
+ }
+
+ public String getAbsoluteName(Object object) {
+ IRemoteProcess process = (IRemoteProcess) object;
+ return "" + process.getPid(); //$NON-NLS-1$
+ }
+
+ public String getType(Object element) {
+ return "Process";
+ }
+
+ public Object getParent(Object element) {
+ IRemoteProcess process = (IRemoteProcess) element;
+ IRemoteProcess parent = process.getParentRemoteProcess();
+ if ((parent != null) && parent.getAbsolutePath().equals(process.getAbsolutePath()))
+ // should never happen but sometimes it does, leading to infinite loop.
+ parent = null;
+ return parent;
+ }
+
+ public boolean hasChildren(IAdaptable element) {
+ return getChildren(element, new NullProgressMonitor()).length > 0;
+ }
+
+ public Object[] getChildren(IAdaptable element, IProgressMonitor monitor) {
+ IRemoteProcess process = (IRemoteProcess)element;
+ IRemoteProcessSubSystem ss = process.getParentRemoteProcessSubSystem();
+ IHostProcessFilter orgRpfs = process.getFilterString();
+ IHostProcessFilter newRpfs = new HostProcessFilterImpl(orgRpfs.toString());
+
+ Object[] children1 = null;
+ Object[] children2 = null;
+ newRpfs.setPpid(Long.toString(process.getPid()));
+
+ try {
+ TCFProcessResource r = (TCFProcessResource)process.getObject();
+ IHostProcess[] nodes = r.getService().listAllProcesses(orgRpfs, r, monitor);
+ TCFProcessAdapter adapter = new TCFProcessAdapter();
+ children1 = adapter.convertToRemoteProcesses(process.getContext(), process, nodes);
+ if (children1 == null) children1 = EMPTY_LIST;
+
+ children2 = ss.listAllProcesses(newRpfs, process.getContext(), monitor);
+ if (children2 == null) children2 = EMPTY_LIST;
+ }
+ catch (Exception exc) {
+ children1 = new SystemMessageObject[1];
+ children1[0] = new SystemMessageObject(RSEUIPlugin.getPluginMessage(ISystemMessages.MSG_EXPAND_FAILED), ISystemMessageObject.MSGTYPE_ERROR, element);
+ children2 = null;
+ SystemBasePlugin.logError("Exception resolving file filter strings", exc); //$NON-NLS-1$
+ }
+ if (children1 == null || children1.length == 0) return children2;
+ if (children2 == null || children2.length == 0) return children1;
+ Object[] children = new Object[children1.length + children2.length];
+ System.arraycopy(children1, 0, children, 0, children1.length);
+ System.arraycopy(children2, 0, children, children1.length, children2.length);
+ return children;
+ }
+
+ protected IPropertyDescriptor[] internalGetPropertyDescriptors() {
+ if (properties != null) return properties;
+ List<IPropertyDescriptor> l = new ArrayList<IPropertyDescriptor>();
+
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_ID, Messages.PROCESS_ID_LABEL, Messages.PROCESS_ID_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_PID, Messages.PROCESS_PID_LABEL, Messages.PROCESS_PID_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_FILE, Messages.PROCESS_NAME_LABEL, Messages.PROCESS_NAME_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CWD, Messages.PROCESS_CWD_LABEL, Messages.PROCESS_CWD_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_ROOT, Messages.PROCESS_ROOT_LABEL, Messages.PROCESS_ROOT_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_STATE, Messages.PROCESS_STATE_LABEL, Messages.PROCESS_STATE_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_UID, Messages.PROCESS_UID_LABEL, Messages.PROCESS_UID_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_USERNAME, Messages.PROCESS_USERNAME_LABEL, Messages.PROCESS_USERNAME_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_UGID, Messages.PROCESS_GID_LABEL, Messages.PROCESS_GID_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_GROUPNAME, Messages.PROCESS_GROUPNAME_LABEL, Messages.PROCESS_GROUPNAME_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_PPID, Messages.PROCESS_PPID_LABEL, Messages.PROCESS_PPID_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_PGRP, Messages.PROCESS_PGRP_LABEL, Messages.PROCESS_PGRP_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_TGID, Messages.PROCESS_TGID_LABEL, Messages.PROCESS_TGID_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_TRACERPID, Messages.PROCESS_TRACERPID_LABEL, Messages.PROCESS_TRACERPID_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_VSIZE, Messages.PROCESS_VMSIZE_LABEL, Messages.PROCESS_VMSIZE_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_RSS, Messages.PROCESS_VMRSS_LABEL, Messages.PROCESS_VMRSS_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_SESSION, Messages.PROCESS_SESSION_LABEL, Messages.PROCESS_SESSION_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_TTY, Messages.PROCESS_TTY_LABEL, Messages.PROCESS_TTY_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_FLAGS, Messages.PROCESS_FLAGS_LABEL, Messages.PROCESS_FLAGS_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_MINFLT, Messages.PROCESS_MINFLT_LABEL, Messages.PROCESS_MINFLT_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CMINFLT, Messages.PROCESS_CMINFLT_LABEL, Messages.PROCESS_CMINFLT_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_MAJFLT, Messages.PROCESS_MAJFLT_LABEL, Messages.PROCESS_MAJFLT_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CMAJFLT, Messages.PROCESS_CMAJFLT_LABEL, Messages.PROCESS_CMAJFLT_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_UTIME, Messages.PROCESS_UTIME_LABEL, Messages.PROCESS_UTIME_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_STIME, Messages.PROCESS_STIME_LABEL, Messages.PROCESS_STIME_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CUTIME, Messages.PROCESS_CUTIME_LABEL, Messages.PROCESS_CUTIME_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CSTIME, Messages.PROCESS_CSTIME_LABEL, Messages.PROCESS_CSTIME_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(PROP_PC_UTIME, Messages.PROCESS_PC_UTIME_LABEL, Messages.PROCESS_PC_UTIME_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(PROP_PC_STIME, Messages.PROCESS_PC_STIME_LABEL, Messages.PROCESS_PC_STIME_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_PRIORITY, Messages.PROCESS_PRIORITY_LABEL, Messages.PROCESS_PRIORITY_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_NICE, Messages.PROCESS_NICE_LABEL, Messages.PROCESS_NICE_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_ITREALVALUE, Messages.PROCESS_ITREALVALUE_LABEL, Messages.PROCESS_ITREALVALUE_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_STARTTIME, Messages.PROCESS_STARTTIME_LABEL, Messages.PROCESS_STARTTIME_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_RLIMIT, Messages.PROCESS_RLIMIT_LABEL, Messages.PROCESS_RLIMIT_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CODESTART, Messages.PROCESS_CODESTART_LABEL, Messages.PROCESS_CODESTART_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CODEEND, Messages.PROCESS_CODEEND_LABEL, Messages.PROCESS_CODEEND_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_STACKSTART, Messages.PROCESS_STACKSTART_LABEL, Messages.PROCESS_STACKSTART_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_SIGNALS, Messages.PROCESS_SIGNALS_LABEL, Messages.PROCESS_SIGNALS_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_SIGBLOCK, Messages.PROCESS_SIGBLOCK_LABEL, Messages.PROCESS_SIGBLOCK_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_SIGIGNORE, Messages.PROCESS_SIGIGNORE_LABEL, Messages.PROCESS_SIGIGNORE_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_SIGCATCH, Messages.PROCESS_SIGCATCH_LABEL, Messages.PROCESS_SIGCATCH_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_WCHAN, Messages.PROCESS_WCHAN_LABEL, Messages.PROCESS_WCHAN_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_NSWAP, Messages.PROCESS_NSWAP_LABEL, Messages.PROCESS_NSWAP_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_CNSWAP, Messages.PROCESS_CNSWAP_LABEL, Messages.PROCESS_CNSWAP_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_EXITSIGNAL, Messages.PROCESS_EXITSIGNAL_LABEL, Messages.PROCESS_EXITSIGNAL_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_PROCESSOR, Messages.PROCESS_PROCESSOR_LABEL, Messages.PROCESS_PROCESSOR_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_RTPRIORITY, Messages.PROCESS_RTPRIORITY_LABEL, Messages.PROCESS_RTPRIORITY_TOOLTIP));
+ l.add(createSimplePropertyDescriptor(ISysMonitor.PROP_POLICY, Messages.PROCESS_POLICY_LABEL, Messages.PROCESS_POLICY_TOOLTIP));
+
+ properties = l.toArray(new IPropertyDescriptor[l.size()]);
+ return properties;
+ }
+
+ /**
+ * Returns the current value for the named property.
+ * @return the current value of the given property
+ */
+ protected Object internalGetPropertyValue(Object key) {
+ return getPropertyValue(key, true);
+ }
+
+ /**
+ * Returns the current value for the named property.
+ *
+ * @param property the name or key of the property as named by its property descriptor
+ * @param formatted indication of whether to return the value in formatted or raw form
+ * @return the current value of the given property
+ */
+ public Object getPropertyValue(Object property, boolean formatted) {
+ String name = (String)property;
+ TCFRemoteProcess process = (TCFRemoteProcess)propertySourceInput;
+ Object p = process.getProperties().get((String)property);
+
+ if (formatted) {
+ if (name.equals(ISysMonitor.PROP_VSIZE)) {
+ return sub(Messages.PROCESS_VMSIZE_VALUE, "&1", Long.toString(process.getVmSizeInKB()));
+ }
+ if (name.equals(ISysMonitor.PROP_RSS)) {
+ return sub(Messages.PROCESS_VMRSS_VALUE, "&1", Long.toString(process.getVmRSSInKB()));
+ }
+ if (name.equals(ISysMonitor.PROP_SIGNALS))return formatBitSet(p);
+ if (name.equals(ISysMonitor.PROP_SIGBLOCK)) return formatBitSet(p);
+ if (name.equals(ISysMonitor.PROP_SIGCATCH)) return formatBitSet(p);
+ if (name.equals(ISysMonitor.PROP_SIGIGNORE)) return formatBitSet(p);
+ if (name.equals(ISysMonitor.PROP_CODESTART)) return formatHex(p);
+ if (name.equals(ISysMonitor.PROP_CODEEND)) return formatHex(p);
+ if (name.equals(ISysMonitor.PROP_STACKSTART)) return formatHex(p);
+ if (name.equals(ISysMonitor.PROP_WCHAN)) return formatHex(p);
+ if (name.equals(ISysMonitor.PROP_FLAGS)) return formatBitSet(p);
+ if (name.equals(ISysMonitor.PROP_UTIME)) return formatTime(p);
+ if (name.equals(ISysMonitor.PROP_STIME)) return formatTime(p);
+ if (name.equals(ISysMonitor.PROP_CUTIME)) return formatTime(p);
+ if (name.equals(ISysMonitor.PROP_CSTIME)) return formatTime(p);
+ if (name.equals(ISysMonitor.PROP_STARTTIME)) return formatTime(p);
+ if (name.equals(ISysMonitor.PROP_ITREALVALUE)) return formatTime(p);
+ if (name.equals(PROP_PC_UTIME)) return process.getUserTimePC();
+ if (name.equals(PROP_PC_STIME)) return process.getSysTimePC();
+ }
+
+ if (p == null) return null;
+ if (formatted) return p.toString();
+ return p;
+ }
+
+ private String formatTime(Object o) {
+ if (o instanceof Number) {
+ BigInteger n = new BigInteger(o.toString());
+ BigInteger s[] = n.divideAndRemainder(BigInteger.valueOf(1000));
+ BigInteger m[] = s[0].divideAndRemainder(BigInteger.valueOf(60));
+ BigInteger h[] = m[0].divideAndRemainder(BigInteger.valueOf(60));
+ StringBuffer buf = new StringBuffer();
+ if (!h[0].equals(BigInteger.ZERO)) {
+ buf.append(h[0]);
+ buf.append("h ");
+ }
+ if (buf.length() > 0 || !h[1].equals(BigInteger.ZERO)) {
+ buf.append(h[1]);
+ buf.append("m ");
+ }
+ buf.append(m[1]);
+ buf.append('.');
+ String ms = s[1].toString();
+ buf.append("000".substring(ms.length()));
+ buf.append(ms);
+ buf.append('s');
+ return buf.toString();
+ }
+ if (o == null) return null;
+ return o.toString();
+ }
+
+ private void formatHex(StringBuffer buf, BigInteger n, int cnt) {
+ BigInteger m[] = n.divideAndRemainder(BigInteger.valueOf(16));
+ if (cnt < 7 || !m[0].equals(BigInteger.ZERO)) {
+ formatHex(buf, m[0], cnt + 1);
+ }
+ int d = m[1].intValue();
+ buf.append((char)(d <= 9 ? '0' + d : 'a' + d - 10));
+ }
+
+ protected String formatHex(Object o) {
+ if (o instanceof Number) {
+ BigInteger n = new BigInteger(o.toString());
+ StringBuffer buf = new StringBuffer();
+ buf.append("0x");
+ formatHex(buf, n, 0);
+ return buf.toString();
+ }
+ if (o == null) return null;
+ return o.toString();
+ }
+
+ protected String formatBitSet(Object o) {
+ if (o instanceof Number) {
+ StringBuffer buf = new StringBuffer();
+ long n = ((Number)o).longValue();
+ for (int i = 0; i < 64; i++) {
+ if ((n & (1l << i)) != 0) {
+ if (buf.length() > 0) buf.append(',');
+ int i0 = i;
+ while (i < 63 && (n & (1l << (i + 1))) != 0) i++;
+ buf.append(i0);
+ if (i0 != i) {
+ buf.append("..");
+ buf.append(i);
+ }
+ }
+ }
+ return buf.toString();
+ }
+ if (o == null) return null;
+ return o.toString();
+ }
+
+ protected String formatState(String state) {
+ return state;
+ }
+
+ /**
+ * Return fully qualified name that uniquely identifies this remote object's remote parent within its subsystem
+ */
+ public String getAbsoluteParentName(Object element) {
+ IRemoteProcess process = (IRemoteProcess) element;
+ IRemoteProcess parent = process.getParentRemoteProcess();
+ if (parent != null) return parent.getAbsolutePath();
+ else return "/proc/0"; //$NON-NLS-1$
+ }
+
+ /**
+ * Given a remote object, returns it remote parent object. Eg, given a process, return the process that
+ * spawned it.
+ * <p>
+ * The shell is required in order to set the cursor to a busy state if a remote trip is required.
+ *
+ * @return an IRemoteProcess object for the parent
+ */
+ public Object getRemoteParent(Object element, IProgressMonitor monitor) throws Exception {
+ return ((IRemoteProcess) element).getParentRemoteProcess();
+ }
+
+ /**
+ * Given a remote object, return the unqualified names of the objects contained in that parent. This is
+ * used for testing for uniqueness on a rename operation, for example. Sometimes, it is not
+ * enough to just enumerate all the objects in the parent for this purpose, because duplicate
+ * names are allowed if the types are different, such as on iSeries. In this case return only
+ * the names which should be used to do name-uniqueness validation on a rename operation.
+ *
+ * @return an array of all file and folder names in the parent of the given IRemoteFile object
+ */
+ public String[] getRemoteParentNamesInUse(Object element, IProgressMonitor monitor) throws Exception {
+ String[] pids = EMPTY_STRING_LIST;
+
+ IRemoteProcess process = (IRemoteProcess) element;
+ String parentName = "" + process.getPPid(); //$NON-NLS-1$
+ if (parentName.equals("-1")) // given a root? //$NON-NLS-1$
+ return pids; // not much we can do. Should never happen: you can't rename a root!
+
+ Object[] children = getChildren(process.getParentRemoteProcess(), monitor);
+ if ((children == null) || (children.length == 0))
+ return pids;
+
+ pids = new String[children.length];
+ for (int idx = 0; idx < pids.length; idx++)
+ pids[idx] = "" + ((IRemoteProcess) children[idx]).getPid(); //$NON-NLS-1$
+
+ return pids;
+ }
+
+ public String getRemoteSubType(Object element) {
+ return null;
+ }
+
+ public String getRemoteType(Object element) {
+ IRemoteProcess process = (IRemoteProcess) element;
+ if (process.isRoot())
+ return ISystemProcessRemoteTypes.TYPE_ROOT;
+ else
+ return ISystemProcessRemoteTypes.TYPE_PROCESS;
+ }
+
+ public String getRemoteTypeCategory(Object element) {
+ return ISystemProcessRemoteTypes.TYPECATEGORY;
+ }
+
+ /**
+ * Return the subsystem factory id that owns this remote object
+ * The value must not be translated, so that property pages registered via xml can subset by it.
+ */
+ public String getSubSystemConfigurationId(Object element) {
+ IRemoteProcess process = (IRemoteProcess) element;
+ return process.getParentRemoteProcessSubSystem().getSubSystemConfiguration().getId();
+ }
+
+ public boolean refreshRemoteObject(Object oldElement, Object newElement) {
+ return false;
+ }
+
+ public boolean supportsUserDefinedActions(Object object) {
+ return false;
+ }
+}
diff --git a/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/messages.properties b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/messages.properties
new file mode 100644
index 000000000..3b48e7409
--- /dev/null
+++ b/plugins/com.windriver.tcf.rse.ui/src/com/windriver/tcf/rse/ui/messages.properties
@@ -0,0 +1,103 @@
+SysMonitor_AllProcesses=All Processes
+SysMonitor_Process=Process
+
+PROCESS_ID_LABEL=Context ID
+PROCESS_PID_LABEL=Process ID
+PROCESS_NAME_LABEL=Executable Name
+PROCESS_CWD_LABEL=CWD
+PROCESS_ROOT_LABEL=FS Root
+PROCESS_UID_LABEL=User ID
+PROCESS_USERNAME_LABEL=Username
+PROCESS_GID_LABEL=Group ID
+PROCESS_GROUPNAME_LABEL=Groupname
+PROCESS_PPID_LABEL=Parent PID
+PROCESS_PGRP_LABEL=Proucess Group
+PROCESS_STATE_LABEL=State
+PROCESS_TRACERPID_LABEL=Tracer PID
+PROCESS_VMSIZE_LABEL=VM Size
+PROCESS_VMRSS_LABEL=VM RSS
+PROCESS_SESSION_LABEL=Session
+PROCESS_TTY_LABEL=TTY
+PROCESS_TGID_LABEL=Task Group ID
+PROCESS_FLAGS_LABEL=Flags
+PROCESS_MINFLT_LABEL=Minor Faults
+PROCESS_CMINFLT_LABEL=Children Minor Faults
+PROCESS_MAJFLT_LABEL=Major Faults
+PROCESS_CMAJFLT_LABEL=Children Major Faults
+PROCESS_UTIME_LABEL=User Time
+PROCESS_STIME_LABEL=System Time
+PROCESS_CUTIME_LABEL=Children User Time
+PROCESS_CSTIME_LABEL=Children System Time
+PROCESS_PC_UTIME_LABEL=% User Time
+PROCESS_PC_STIME_LABEL=% System Time
+PROCESS_PRIORITY_LABEL=Priority
+PROCESS_NICE_LABEL=Nice
+PROCESS_ITREALVALUE_LABEL=Interval Timer
+PROCESS_STARTTIME_LABEL=Start Time
+PROCESS_RLIMIT_LABEL=RSS Limit
+PROCESS_CODESTART_LABEL=Code Start
+PROCESS_CODEEND_LABEL=Code End
+PROCESS_STACKSTART_LABEL=Stack Start
+PROCESS_SIGNALS_LABEL=Pending Signals
+PROCESS_SIGBLOCK_LABEL=Blocked Signals
+PROCESS_SIGIGNORE_LABEL=Ignored Signals
+PROCESS_SIGCATCH_LABEL=Caught Signals
+PROCESS_WCHAN_LABEL=Wait Channel
+PROCESS_NSWAP_LABEL=Swaped Pages
+PROCESS_CNSWAP_LABEL=Children Swapped Pages
+PROCESS_EXITSIGNAL_LABEL=Exit Signal
+PROCESS_PROCESSOR_LABEL=Processor
+PROCESS_RTPRIORITY_LABEL=Real Time Priority
+PROCESS_POLICY_LABEL=Scheduling Policy
+
+PROCESS_ID_TOOLTIP=TCF context ID of the process
+PROCESS_PID_TOOLTIP=The system ID number of the process
+PROCESS_NAME_TOOLTIP=The executable associated with the process
+PROCESS_CWD_TOOLTIP=Current working directory of the process
+PROCESS_ROOT_TOOLTIP=Current file system root of the process
+PROCESS_UID_TOOLTIP=The user ID of the owner of the process
+PROCESS_USERNAME_TOOLTIP=The username of the owner of the process
+PROCESS_GID_TOOLTIP=The group ID of the owner of the process
+PROCESS_GROUPNAME_TOOLTIP=The groupname of the owner of the process
+PROCESS_PPID_TOOLTIP=The process ID of the parent of the process
+PROCESS_PGRP_TOOLTIP=The process group ID
+PROCESS_STATE_TOOLTIP=The state in which the process currently is
+PROCESS_TRACERPID_TOOLTIP=The tracer process ID of the process
+PROCESS_VMSIZE_TOOLTIP=The amount of virtual memory taken up by this process
+PROCESS_VMRSS_TOOLTIP=The amount of virtual memory resident set size of this process (actual RAM taken up by the process)
+PROCESS_SESSION_TOOLTIP=The session ID of the process
+PROCESS_TTY_TOOLTIP=The TTY the process uses
+PROCESS_TGID_TOOLTIP=The task group to which process belongs
+PROCESS_FLAGS_TOOLTIP=The kernel flags word of the process.
+PROCESS_MINFLT_TOOLTIP=The number of minor faults the process has made which have not required loading a memory page from disk.
+PROCESS_CMINFLT_TOOLTIP=The number of minor faults that the process's waited-for children have made.
+PROCESS_MAJFLT_TOOLTIP=The number of major faults the process has made which have required loading a memory page from disk.
+PROCESS_CMAJFLT_TOOLTIP=Children Major Faults
+PROCESS_UTIME_TOOLTIP=User Time
+PROCESS_STIME_TOOLTIP=System Time
+PROCESS_CUTIME_TOOLTIP=Children User Time
+PROCESS_CSTIME_TOOLTIP=Children System Time
+PROCESS_PC_UTIME_TOOLTIP=% User Time
+PROCESS_PC_STIME_TOOLTIP=% System Time
+PROCESS_PRIORITY_TOOLTIP=Priority
+PROCESS_NICE_TOOLTIP=Nice
+PROCESS_ITREALVALUE_TOOLTIP=Interval Timer
+PROCESS_STARTTIME_TOOLTIP=Start Time
+PROCESS_RLIMIT_TOOLTIP=RSS Limit
+PROCESS_CODESTART_TOOLTIP=Code Start
+PROCESS_CODEEND_TOOLTIP=Code End
+PROCESS_STACKSTART_TOOLTIP=Stack Start
+PROCESS_SIGNALS_TOOLTIP=Pending Signals
+PROCESS_SIGBLOCK_TOOLTIP=Blocked Signals
+PROCESS_SIGIGNORE_TOOLTIP=Ignored Signals
+PROCESS_SIGCATCH_TOOLTIP=Caught Signals
+PROCESS_WCHAN_TOOLTIP=Wait Channel
+PROCESS_NSWAP_TOOLTIP=Swaped Pages
+PROCESS_CNSWAP_TOOLTIP=Children Swapped Pages
+PROCESS_EXITSIGNAL_TOOLTIP=Exit Signal
+PROCESS_PROCESSOR_TOOLTIP=Processor
+PROCESS_RTPRIORITY_TOOLTIP=Real Time Priority
+PROCESS_POLICY_TOOLTIP=Scheduling Policy
+
+PROCESS_VMSIZE_VALUE=&1 KB
+PROCESS_VMRSS_VALUE=&1 KB \ No newline at end of file
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 000000000..ef53380e4
--- /dev/null
+++ b/readme.txt
@@ -0,0 +1,5 @@
+TCF is Copyright (c) 2007 by Wind River Systems, Inc.
+Made available under the Eclipse Public License (EPL) v1.0
+See the file epl-v10.html for details.
+
+See docs/index.html for documentation on Target Communication Framework \ No newline at end of file

Back to the top