[savara-commits] savara SVN: r98 - in trunk/org.pi4soa.monitor: META-INF and 9 other directories.

do-not-reply at jboss.org do-not-reply at jboss.org
Sat Dec 5 05:50:51 EST 2009


Author: objectiser
Date: 2009-12-05 05:50:50 -0500 (Sat, 05 Dec 2009)
New Revision: 98

Added:
   trunk/org.pi4soa.monitor/.classpath
   trunk/org.pi4soa.monitor/.project
   trunk/org.pi4soa.monitor/LICENSE.txt
   trunk/org.pi4soa.monitor/META-INF/
   trunk/org.pi4soa.monitor/META-INF/MANIFEST.MF
   trunk/org.pi4soa.monitor/build.properties
   trunk/org.pi4soa.monitor/plugin.xml
   trunk/org.pi4soa.monitor/src/
   trunk/org.pi4soa.monitor/src/java/
   trunk/org.pi4soa.monitor/src/java/org/
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/CorrelationManagerListener.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ExchangeEvent.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/TxnMonitor.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/Activator.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorAction.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorLaunchConfigurationConstants.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorLauncher.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorMainTab.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorTabGroup.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ChannelJPanel.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ExchangeEventWrapper.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ExchangeEventsData.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/Monitor.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorExchangeEvent.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorFileFilter.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorMainPanel.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorMenuBar.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorTreeModelListener.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/SpringUtilities.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/XmlPrettyPrinter.java
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelclosed.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelempty.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelleaf.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelopen.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/errorsleaf.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/issuesclosed.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/issuesempty.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/issuesopen.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/monitor.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnclosed.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnempty.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnleaf.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnopen.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/unexpectedleaf.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/warningsleaf.png
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/table/
   trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/table/TableSorter.java
Log:
Temporary inclusion until SAM solution available.

Added: trunk/org.pi4soa.monitor/.classpath
===================================================================
--- trunk/org.pi4soa.monitor/.classpath	                        (rev 0)
+++ trunk/org.pi4soa.monitor/.classpath	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src/java"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+	<classpathentry kind="output" path="classes"/>
+</classpath>

Added: trunk/org.pi4soa.monitor/.project
===================================================================
--- trunk/org.pi4soa.monitor/.project	                        (rev 0)
+++ trunk/org.pi4soa.monitor/.project	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>org.pi4soa.monitor</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>

Added: trunk/org.pi4soa.monitor/LICENSE.txt
===================================================================
--- trunk/org.pi4soa.monitor/LICENSE.txt	                        (rev 0)
+++ trunk/org.pi4soa.monitor/LICENSE.txt	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" 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. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

Added: trunk/org.pi4soa.monitor/META-INF/MANIFEST.MF
===================================================================
--- trunk/org.pi4soa.monitor/META-INF/MANIFEST.MF	                        (rev 0)
+++ trunk/org.pi4soa.monitor/META-INF/MANIFEST.MF	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,26 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: pi4soa Monitor Plug-in
+Bundle-SymbolicName: org.pi4soa.monitor;singleton:=true
+Bundle-Version: 2.1.0.qualifier
+Bundle-Activator: org.pi4soa.monitor.eclipse.Activator
+Bundle-Vendor: www.pi4soa.org
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.pi4soa.service,
+ org.pi4soa.cdl,
+ org.eclipse.core.resources,
+ org.eclipse.debug.core,
+ org.eclipse.jdt.launching,
+ org.eclipse.core.resources,
+ org.eclipse.ui.ide,
+ org.eclipse.jface,
+ org.eclipse.jdt.debug.ui,
+ org.eclipse.ui.console,
+ org.eclipse.debug.ui,
+ org.eclipse.ui,
+ org.eclipse.jdt.core,
+ org.eclipse.emf.ecore,
+ org.pi4soa.common
+Eclipse-LazyStart: true
+Bundle-ClassPath: .

Added: trunk/org.pi4soa.monitor/build.properties
===================================================================
--- trunk/org.pi4soa.monitor/build.properties	                        (rev 0)
+++ trunk/org.pi4soa.monitor/build.properties	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,5 @@
+source.. = src/java/
+output.. = classes/
+bin.includes = META-INF/,\
+               .,\
+               plugin.xml

Added: trunk/org.pi4soa.monitor/plugin.xml
===================================================================
--- trunk/org.pi4soa.monitor/plugin.xml	                        (rev 0)
+++ trunk/org.pi4soa.monitor/plugin.xml	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.2"?>
+<plugin>
+  <extension point="org.eclipse.debug.core.launchConfigurationTypes">
+    <launchConfigurationType
+       id="org.pi4soa.monitor.eclipse.MonitorLauncher"
+       delegate="org.pi4soa.monitor.eclipse.MonitorLauncher"
+       modes="run"
+       name="Monitor">
+      <fileExtension extension="cdm" default="true"/>
+    </launchConfigurationType>
+  </extension>
+
+  <extension point="org.eclipse.debug.ui.launchConfigurationTabGroups">
+    <launchConfigurationTabGroup
+        type="org.pi4soa.monitor.eclipse.MonitorLauncher"
+        class="org.pi4soa.monitor.eclipse.MonitorTabGroup"
+        id="org.eclipse.jdt.debug.ui.launchConfigurationTabGroup.monitor">
+    </launchConfigurationTabGroup>
+  </extension>
+   
+  <extension point="org.eclipse.ui.popupMenus"> 
+	<objectContribution 
+      id="org.pi4soa.service.generation.contribution2"
+   			objectClass="org.eclipse.core.resources.IFile"
+   				nameFilter="*.cdm">
+	  <menu
+         id="org.pi4soa.menu"
+         label="Choreography"
+         path="additions">
+      	<separator name="group1"/>
+      </menu>
+      <action
+           label="Monitor"
+           class="org.pi4soa.monitor.eclipse.MonitorAction"
+           menubarPath="org.pi4soa.menu/group1"
+           enablesFor="1"
+           id="org.pi4soa.monitor.MonitorAction">
+     </action> 
+    </objectContribution> 
+  </extension>
+ 
+</plugin>

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/CorrelationManagerListener.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/CorrelationManagerListener.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/CorrelationManagerListener.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor;
+
+import org.pi4soa.service.correlator.CorrelationSession;
+
+/**
+ * This interface represents a listener interested in changes
+ * that occur within the correlation manager.
+ *
+ */
+public interface CorrelationManagerListener {
+
+	/**
+	 * This method indicates that a correlation session has
+	 * started.
+	 * 
+	 * @param session The correlation session
+	 */
+	public void correlationSessionStarted(CorrelationSession session);
+	
+	/**
+	 * This method indicates that a correlation session has
+	 * finished.
+	 * 
+	 * @param session The correlation session
+	 */
+	public void correlationSessionFinished(CorrelationSession session);
+
+    /**
+     * A new exchange event has been added to a correlation session.
+     *
+     * @param exchangeEvent The exchange event.
+     */
+    public void exchangeEventAdded(ExchangeEvent exchangeEvent);
+
+
+    /**
+     * An exchange event has been updated.
+     *
+     * @param exchangeEvent The exchange event.
+     */
+    public void exchangeEventUpdated(ExchangeEvent exchangeEvent);
+    
+    /**
+     * An unexpected event has occured
+     * 
+     * @param exchangeEvent. The exchange event.
+     * @param serviceName The service reporting the error
+     */
+    public void unexpectedExchangeEventAdded(ExchangeEvent exchangeEvent,
+    					String serviceName);
+
+    /**
+     * An error occurred related to the specified correlation
+     * session.
+     * 
+     * @param session The correlation session
+     * @param mesg The error message
+     * @param exception The optional exception trace
+     * @param serviceName The service reporting the error
+     */
+    public void error(CorrelationSession session, String mesg,
+    						String exception, String serviceName);
+    
+    /**
+     * A warning occurred related to the specified correlation
+     * session.
+     * 
+     * @param session The correlation session
+     * @param mesg The warning message
+     * @param exception The optional exception trace
+     * @param serviceName The service reporting the warning
+     */
+    public void warning(CorrelationSession session, String mesg,
+							String exception, String serviceName);
+    
+    /**
+     * An information event occurred related to the specified correlation
+     * session.
+     * 
+     * @param session The correlation session
+     * @param mesg The information message
+     * @param serviceName The service reporting the information
+     */
+    public void information(CorrelationSession session,
+    					String mesg, String serviceName);
+    
+}
\ No newline at end of file

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ExchangeEvent.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ExchangeEvent.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ExchangeEvent.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor;
+
+import java.io.Serializable;
+import java.util.logging.Logger;
+import java.util.logging.Level;
+
+import org.pi4soa.cdl.ExchangeDetails;
+import org.pi4soa.service.Message;
+import org.pi4soa.service.Channel;
+import org.pi4soa.service.correlator.CorrelationSession;
+
+/**
+ * This class represents the 'exchange' correlation event.
+ *
+ */
+public class ExchangeEvent implements Serializable {
+
+    /**
+	 * 
+	 */
+	private static final long serialVersionUID = -1984285030410307153L;
+
+	Message m_message = null;
+
+	/**
+	 * This class represents the 'exchange' correlation event.
+	 * 
+	 * @param exchange The exchange details
+	 * @param channel The channel
+	 * @param session The session
+	 * @param serviceDescriptionName The service description name
+	 */
+	public ExchangeEvent(ExchangeDetails exchange,
+				Channel channel, CorrelationSession session,
+						String serviceDescriptionName, Message message) {
+		m_exchange = exchange;
+		m_channel = channel;
+		m_session = session;
+		m_serviceDescriptionName = serviceDescriptionName;
+                this.m_message = message;
+	}
+	
+	/**
+	 * This method returns the exchange details.
+	 * 
+	 * @return The exchange details
+	 */
+	public ExchangeDetails getExchange() {
+		return(m_exchange);
+	}
+	
+	/**
+	 * This method returns the channel.
+	 * 
+	 * @return The channel
+	 */
+	public Channel getChannel() {
+		return(m_channel);
+	}
+	
+	/**
+	 * This method returns the correlation session.
+	 * 
+	 * @return The correlation session
+	 */
+	public CorrelationSession getCorrelationSession() {
+		return(m_session);
+	}
+	
+	/**
+	 * This method returns the service description name.
+	 * 
+	 * @return The service description name
+	 */
+	public String getServiceDescriptionName() {
+		return(m_serviceDescriptionName);
+	}
+
+	/**
+	 * This method returns the message.
+	 * 
+	 * @return The service description name
+	 */
+	public Message getMessage() {
+		return m_message;
+	}
+	
+	/**
+	 * This method returns whether the exchange has been
+	 * initiated and completed.
+	 * 
+	 * @return The 'complete' status of the exchange event
+	 */
+	public boolean isExchangeComplete() {
+		return(m_initiated && m_completed);
+	}
+
+	/**
+	 * This method determines whether the event has been
+	 * initiated.
+	 * 
+	 * @return Whether event has been initiated
+	 */
+    public boolean getInitiated(){
+		return m_initiated;
+    }
+
+	/**
+	 * This method determines whether the event has been
+	 * completed.
+	 * 
+	 * @return Whether event has been completed
+	 */
+    public boolean getCompleted(){
+		return m_completed;
+    }
+	
+	/**
+	 * This method indicates that the exchange associated with
+	 * the event has initiated.
+	 *
+	 */
+	public void initiated() {
+		m_initiated = true;
+                checkIfExchangeCorrelated();
+	}
+	
+	/**
+	 * This method indicates that the exchange associated with
+	 * the event has completed.
+	 *
+	 */
+	public void completed() {
+		m_completed = true;
+                checkIfExchangeCorrelated();
+	}
+
+
+    protected void checkIfExchangeCorrelated() {
+        if (isExchangeComplete()) {
+            //            logger.fine("EXCHANGE CORRELATED: "+this);
+        }
+    }
+
+    public int hashCode() {
+        return(m_message.getOperationName().hashCode());
+    }
+
+    public boolean equals(Object obj) {
+        boolean ret=false;
+        if (obj instanceof ExchangeEvent) {
+            ExchangeEvent other=(ExchangeEvent)obj;
+            if (m_exchange == null || other.getExchange() == null) {
+                // Compare on message basis
+                if (m_message.isRPCStyle() &&
+                				other.getMessage().isRPCStyle()) {
+                	if (m_message.getOperationName().equals(
+                            other.getMessage().getOperationName()) &&
+                            m_message.isRequest() == other.getMessage().isRequest() &&
+                            m_message.getServiceType().equals(
+                             other.getMessage().getServiceType())) {
+                		ret = true;
+                	}
+                } else if (m_message.isRPCStyle() == false &&
+        				other.getMessage().isRPCStyle() == false) {
+                	if (m_message.getType().equals(
+                			other.getMessage().getType())) {
+                		ret = true;
+                	}
+                }
+            } else if (other.getExchange() == m_exchange &&
+                       other.getChannel().getName().equals(m_channel.getName()) &&
+                       other.getCorrelationSession() == m_session) {
+                ret = true;
+            }
+            
+            if (ret) {
+            	
+            	// Check identities
+            	if (other.getMessage().getMessageIdentities().size()
+            			== getMessage().getMessageIdentities().size()) {
+            		
+            		for (int i=0; ret &&
+            				i < getMessage().getMessageIdentities().size(); i++) {
+            			ret = false;
+            			
+            			org.pi4soa.service.Identity id=
+            					getMessage().getMessageIdentities().get(i);
+            			
+                		if (logger.isLoggable(Level.FINEST)) {
+                			logger.finest("Checking message identity ("+i+
+                					"): "+id);
+                		}
+
+                		for (int j=0; ret == false &&
+            					j < other.getMessage().getMessageIdentities().size(); j++) {
+
+                    		if (id.equals(other.getMessage().getMessageIdentities().get(j))) {
+            					ret = true;
+            				}
+            				
+                    		if (logger.isLoggable(Level.FINEST)) {
+                    			logger.finest("Against message identity ("+j+
+                    					"): "+other.getMessage().getMessageIdentities().get(j)+
+                    					" = "+ret);
+                    		}
+            			}
+            		}
+            	} else {
+            		if (logger.isLoggable(Level.FINEST)) {
+            			logger.finest("Message identity list length mismatch");
+            		}
+
+            		ret = false;
+            	}
+            }
+        }
+        return(ret);
+    }
+	
+    public String toString() {
+        StringBuffer ret=new StringBuffer();
+        ret.append("ExchangeEvent[");
+        if (m_exchange != null) {
+
+            //            if (NamesUtil.isSet(m_exchange.getDescription())) {
+
+
+            if (m_exchange.getDescription() != null && "".equals(m_exchange.getDescription()) == false) {
+
+                ret.append(m_exchange.getDescription());
+            } else {
+                ret.append(m_exchange.getName());
+            }
+            ret.append(", ");
+        }
+        ret.append(m_message.toString()+"]");
+        return(ret.toString());
+    }
+
+    private static Logger logger = Logger.getLogger("org.pi4soa.monitor");
+
+    private ExchangeDetails m_exchange=null;
+	private Channel m_channel=null;
+	private CorrelationSession m_session;
+	private String m_serviceDescriptionName=null;
+	private boolean m_initiated=false;
+	private boolean m_completed=false;
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/TxnMonitor.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/TxnMonitor.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/TxnMonitor.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,593 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor;
+
+import java.util.logging.Logger;
+
+import org.pi4soa.cdl.ExchangeDetails;
+import org.pi4soa.service.Channel;
+import org.pi4soa.service.Message;
+import org.pi4soa.service.ServiceException;
+import org.pi4soa.service.correlator.CorrelationSession;
+import org.pi4soa.service.correlator.ServiceCorrelator;
+import org.pi4soa.service.correlator.ServiceCorrelatorFactory;
+import org.pi4soa.service.correlator.ServiceCorrelatorListener;
+import org.pi4soa.service.tracker.ServiceTrackerClient;
+import org.pi4soa.service.tracker.jms.JMSServiceTrackerClient;
+
+/**
+ * The TxnMonitor class is a generic transaction monitor class that
+ * takes in a CDL description and monitors the progress of transactions,
+ * which are long lived interactions, against the CDL description.
+ * A TxnMonitor MAY be used as a generic monitor for any CDL description.
+ *
+ */
+public class TxnMonitor {
+
+    public TxnMonitor(String fname)
+    {
+        m_cdlFile = fname;
+    }
+    
+    public void initialize() throws ServiceException
+    {
+        
+        m_correlator=ServiceCorrelatorFactory.getServiceCorrelator();
+        m_correlator.addServiceCorrelatorListener(new CorrelatorListener());
+        
+        // Obtain service tracker client
+        m_trackerClient = new JMSServiceTrackerClient();
+        
+        m_trackerClient.addServiceTrackerListener(m_correlator);
+        
+        //System.err.println("");            
+        //System.err.println("Staring to monitor events against " + m_cdlFile + " .... ");
+        //System.err.println("");
+        try {
+        	monitor(m_cdlFile);
+        } catch(java.io.IOException ioe) {
+        	throw new ServiceException("Failed to initialize monitor for '"+
+        			m_cdlFile+"'", ioe);
+        }
+    }
+    
+    /**
+     * This method returns the singleton for the TxnMonitor.
+     * 
+     * @return The singleton
+     * @exception ServiceException Failed to obtain monitor
+     */
+    public static TxnMonitor getInstance(String fname) throws ServiceException {
+        // TODO: See if there is a better way to make an instance
+        // available to a view
+        if (m_instance == null) {
+            m_instance = new TxnMonitor(fname);
+            m_instance.initialize();
+        }
+        
+        return(m_instance);
+    }
+    
+    /**
+     * This method loads the choreography description associated
+     * with the supplied filename, and then monitors it, before
+     * returning it to the caller.
+     * 
+     * @param filename The choreography description filename
+     * @return The choreography description being monitored
+     * @throws java.io.IOException Failed to load
+     * @throws ServiceException Failed to monitor
+     */
+    public org.pi4soa.cdl.Package monitor(String filename)
+                        throws java.io.IOException, ServiceException {
+        org.pi4soa.cdl.Package ret=
+            org.pi4soa.cdl.CDLManager.load(filename);
+        
+        monitor(ret);
+        
+        return(ret);
+    }
+    
+    /**
+     * This method initializes the correlator with the choreography
+     * description to be monitored.
+     * 
+     * @param cdl The choreography description
+     * @exception ServiceException Failed to monitor choreography
+     *                         description
+     */
+    public void monitor(org.pi4soa.cdl.Package cdl)
+                        throws ServiceException {        
+        m_correlator.register(cdl);
+    }
+    
+    /**
+     * This method disassociates the correlator from the choreography
+     * description being monitored.
+     * 
+     * @param cdl The choreography description
+     * @exception ServiceException Failed to stop monitor choreography
+     *                         description
+     */
+    public void unmonitor(org.pi4soa.cdl.Package cdl)
+                        throws ServiceException {        
+        m_correlator.unregister(cdl);
+    }
+    
+    /**
+     * @param args - the first argument in args is the location of the
+     * CDM file that will be used to drive the monitoring.
+     */
+    public static void main(String[] args) 
+    {
+        // TODO Auto-generated method stub
+        String s = "Constructing a monitor for " + args[0];
+        logger.fine(s);
+        
+        try {
+        	TxnMonitor mon = TxnMonitor.getInstance(args[0]);
+        } catch(Exception e) {
+        	e.printStackTrace();
+        }
+    }
+
+    /**
+     * This method will return an existing list, associated with the
+     * supplied session, or if not found, will create one - unless
+     * the session's event list has previously been removed and
+     * therefore a null will be returned (i.e. events to be
+     * ignored).
+     * 
+     * @param session The session
+     * @return The list, or null if session to be ignored
+     */
+    protected java.util.List createEventList(CorrelationSession session) {
+        java.util.List ret=null;
+        
+        logger.fine("createEventList for session - " + session);
+        
+        synchronized(m_eventLists) {
+            ret = (java.util.List)m_eventLists.get(session);
+        
+            if (ret == null) {
+                ret = new java.util.Vector();
+
+                logger.fine("Creating event list for session: "+session);
+                
+                m_eventLists.put(session, ret);
+            }
+        }
+        
+        logger.fine("createEventList returning - " + ret);
+
+        return(ret);
+    }
+    
+    /**
+     * This method will remove the event list associated with
+     * the supplied session, and add the session to the list
+     * of sessions to be ignored from now on.
+     * 
+     * @param session The session
+     */
+    protected void removeEventList(CorrelationSession session) {
+        
+        synchronized(m_eventLists) {
+
+            logger.fine("Remove correlation session: "+session);
+            
+            m_eventLists.remove(session);
+        }
+    }
+
+    protected void fireSessionStarted(CorrelationSession session) {
+            System.err.println(">>>> fireSessionStarted");
+        for (int i=0; i < m_listeners.size(); i++) {
+            CorrelationManagerListener l=
+                    (CorrelationManagerListener)m_listeners.get(i);
+            
+            l.correlationSessionStarted(session);
+        }
+            System.err.println(">>>> finished fireSessionStarted");
+    }
+    
+    protected void fireSessionFinished(CorrelationSession session) {
+            System.err.println(">>>> fireSessionFinished");
+        for (int i=0; i < m_listeners.size(); i++) {
+            CorrelationManagerListener l=
+                    (CorrelationManagerListener)m_listeners.get(i);
+            
+            l.correlationSessionFinished(session);
+        }
+            logger.fine(">>>> finished fireSessionFinished");
+    }
+    
+    protected void fireUpdatedSession(CorrelationSession session) {
+            logger.fine(">>>> fireSessionUpdated");
+        for (int i=0; i < m_listeners.size(); i++) {
+            CorrelationManagerListener l=
+                    (CorrelationManagerListener)m_listeners.get(i);
+            
+                        //            l.correlationSessionUpdated(session);
+        }
+            logger.fine(">>>> finished fireSessionUpdated");
+    }
+
+
+    protected void fireAddedExchangeEvent(ExchangeEvent exchangeEvent) {
+        for (int i=0; i < m_listeners.size(); i++) {
+            CorrelationManagerListener l=
+                    (CorrelationManagerListener)m_listeners.get(i);
+            
+            l.exchangeEventAdded(exchangeEvent);
+        }
+    }
+
+    protected void fireUpdatedExchangeEvent(ExchangeEvent exchangeEvent) {
+        for (int i=0; i < m_listeners.size(); i++) {
+            CorrelationManagerListener l=
+                    (CorrelationManagerListener)m_listeners.get(i);
+            
+            l.exchangeEventUpdated(exchangeEvent);
+        }
+    }
+    
+    protected void fireAddedUnexpectedExchangeEvent(ExchangeEvent exchangeEvent,
+    				String serviceName) {
+    	logger.fine(">>>> fireAddedUnexpectedExchangeEvent");
+        for (int i=0; i < m_listeners.size(); i++) {
+            CorrelationManagerListener l=
+                    (CorrelationManagerListener)m_listeners.get(i);
+            
+            l.unexpectedExchangeEventAdded(exchangeEvent, serviceName);
+        }
+    	logger.fine("<<<< fireAddedUnexpectedExchangeEvent");
+    }
+    
+    protected void fireErrorEvent(CorrelationSession session,
+    				String mesg, String exception, String serviceName) {
+    	logger.fine(">>>> fireErrorEvent");
+        for (int i=0; i < m_listeners.size(); i++) {
+            CorrelationManagerListener l=
+                    (CorrelationManagerListener)m_listeners.get(i);
+            
+            l.error(session, mesg, exception, serviceName);
+        }
+    	logger.fine("<<<< fireErrorEvent");
+    }
+    
+    protected void fireWarningEvent(CorrelationSession session,
+    					String mesg, String exception, String serviceName) {
+    	logger.fine(">>>> fireWarningEvent");
+        for (int i=0; i < m_listeners.size(); i++) {
+            CorrelationManagerListener l=
+                    (CorrelationManagerListener)m_listeners.get(i);
+            
+            l.warning(session, mesg, exception, serviceName);
+        }
+    	logger.fine("<<<< fireWarningEvent");
+    }
+    
+    protected void fireInformationEvent(CorrelationSession session,
+    						String mesg, String serviceName) {
+    	logger.fine(">>>> fireInformationEvent");
+        for (int i=0; i < m_listeners.size(); i++) {
+            CorrelationManagerListener l=
+                    (CorrelationManagerListener)m_listeners.get(i);
+            
+            l.information(session, mesg, serviceName);
+        }
+    	logger.fine("<<<< fireInformationEvent");
+    }
+    
+    public void addCorrelationManagerListener(CorrelationManagerListener l) {
+            logger.fine(">>>> addCorrelationManagerListener");
+        m_listeners.add(l);
+    }
+    
+    public void removeCorrelationManagerListener(CorrelationManagerListener l) {
+            logger.fine(">>>> removeCorrelationManagerListener");
+        m_listeners.remove(l);
+    }
+    
+    private static Logger logger = Logger.getLogger("org.pi4soa.monitor");
+    
+    private static TxnMonitor m_instance=null;
+    private ServiceCorrelator m_correlator=null;
+    private ServiceTrackerClient m_trackerClient=null;
+    private java.util.Hashtable m_eventLists=new java.util.Hashtable();
+    private java.util.Vector m_listeners=new java.util.Vector();
+    private String m_cdlFile = null;
+    
+    
+    public class CorrelatorListener implements ServiceCorrelatorListener {
+        
+        /**
+         * This method indicates that the supplied choreography
+         * description has been registered with the service
+         * correlator.
+         * 
+         * @param cdlpack The choreography description
+         */
+        public void choreographyDescriptionRegistered(org.pi4soa.cdl.Package cdlpack) {
+                    logger.fine(">>>> choreographyDescriptionRegistered");            
+        }
+        
+        /**
+         * This method indicates that the supplied choreography
+         * description has been unregistered from the service
+         * correlator.
+         * 
+         * @param cdlpack The choreography description
+         */
+        public void choreographyDescriptionUnregistered(org.pi4soa.cdl.Package cdlpack) {
+                    logger.fine(">>>> choreographyDescriptionUnregistered");                        
+        }
+        
+        /**
+         * This method indicates that a new correlated session has
+         * been started.
+         * 
+         * @param session The session
+         */
+        public void sessionStarted(CorrelationSession session) {
+                    logger.fine(">>>> sessionStarted");
+            fireSessionStarted(session);
+        }
+        
+        /**
+         * This method indicates that a correlated session has
+         * been finished.
+         * 
+         * @param session The session
+         */
+        public void sessionFinished(CorrelationSession session) {
+                    logger.fine(">>>> sessionFinished");
+            fireSessionFinished(session);
+        }
+        
+        /**
+         * This method is invoked to indicate that a choreography
+         * exchange has been initiated by one participant.
+         * 
+         * @param exchange The exchange details
+         * @param channel The channel associated with the exchange
+         * @param session The session
+         * @param serviceDescriptionName The name of the service
+         *                 description that caused this exchange to
+         *                 be initiated
+         */
+        public synchronized void exchangeInitiated(ExchangeDetails exchange,
+                Channel channel, Message message, CorrelationSession session,
+                        String serviceDescriptionName) {
+
+            logger.fine(">>>> exchangeInitiated");
+
+            java.util.List list = createEventList(session);
+            
+            if(list != null){
+                ExchangeEvent event = new ExchangeEvent(exchange, channel, session, serviceDescriptionName, message);
+                int index = 0;
+                boolean f_updated=false;
+                
+                if ((index=list.indexOf(event)) == -1) {
+                    logger.fine("Add new event '"+event+ "' to correlation session "+session);
+                    list.add(event);
+                } 
+                else{
+                    logger.fine("Retrieve existing event for index "+index);
+                    ExchangeEvent existingEvent=
+                    		(ExchangeEvent)list.get(index);
+                    
+                    if (existingEvent.getInitiated() == false) {
+                    	event = existingEvent;
+                    	
+                    	// Remove event from list
+                    	list.remove(index);
+                    	
+                    	if (list.size() == 0) {
+                    		// Remove list
+                    		removeEventList(session);
+                    	}
+                    	
+                    	f_updated = true;
+                    } else {
+                        logger.fine("Add new event '"+event+ "' to correlation session "+session);
+                        list.add(event);
+                    }
+                }
+                
+                event.initiated();
+                logger.fine("EXCHANGE INITIATED: ");
+                logger.fine("    CHANNEL DETAILS: " + channel + " (" + channel.getName() + ") session " + session);
+                logger.fine("    EXCHANGE DETAILS: " + exchange);
+
+                if(f_updated == false){
+                    fireAddedExchangeEvent(event);
+                }
+                else{
+                    fireUpdatedExchangeEvent(event);
+                }
+                //                fireUpdatedSession(session);
+            }
+        }
+
+        /**
+         * This method is invoked to indicate that a choreography
+         * exchange has been completed by the target participant.
+         * 
+         * @param exchange The exchange details
+         * @param channel The channel associated with the exchange
+         * @param session The session
+         * @param serviceDescriptionName The name of the service
+         *                 description that caused this exchange to
+         *                 be completed
+         */
+        public synchronized void exchangeCompleted(ExchangeDetails exchange,
+                Channel channel, Message message, CorrelationSession session,
+                        String serviceDescriptionName) {
+
+            logger.fine(">>>> exchangeCompleted");
+            
+            java.util.List list=createEventList(session);
+            
+            if (list != null) {
+                ExchangeEvent event=new ExchangeEvent(exchange, channel, session, serviceDescriptionName, message);
+                
+                int index = 0;
+                
+                if ((index=list.indexOf(event)) == -1) {
+                    logger.fine("Add new event '"+event+ "' to correlation session "+session);
+                    list.add(event);
+                } 
+                else{
+                    logger.fine("Retrieve existing event for index "+index);
+                    ExchangeEvent existingEvent=
+                    		(ExchangeEvent)list.get(index);
+                    
+                    if (existingEvent.getCompleted() == false) {
+                    	event = existingEvent;
+                    	
+                    	// Remove event from list
+                    	list.remove(index);
+                    	
+                    	if (list.size() == 0) {
+                    		// Remove list
+                    		removeEventList(session);
+                    	}
+                    } else {
+                        logger.fine("Add new event '"+event+ "' to correlation session "+session);
+                        list.add(event);
+                    }
+                }
+                
+                event.completed();
+                logger.fine("EXCHANGE COMPLETED: ");
+                                //                logger.fine("    CHANNEL DETAILS: " + channel);
+                logger.fine("    CHANNEL DETAILS: " + channel + " (" + channel.getName() + ") session " + session);
+                logger.fine("    EXCHANGE DETAILS: " + exchange);
+
+                if(index == -1){
+                    fireAddedExchangeEvent(event);
+                }
+                else{
+                    fireUpdatedExchangeEvent(event);
+                }
+                //                fireUpdatedSession(session);
+                logger.fine("<<<< exchangeCompleted");
+            }
+        }
+        
+        /**
+         * This method is invoked to indicate that a message
+         * was unexpected at a participant.
+         * 
+         * @param message The message
+         * @param session The session
+         * @param serviceDescriptionName The name of the service
+         *                 description that caused this unexpected
+         *                 message error
+         */
+        public synchronized void unexpectedMessage(Message message,
+                CorrelationSession session, String serviceDescriptionName) {
+
+            logger.fine(">>>> unexpectedMessage");
+            logger.fine("MESSAGE: " + message + " SESSION: " + session + " SERVICE: " + serviceDescriptionName);
+            logger.fine("MESSAGE: " + message);
+            logger.fine("Identities: " + message.getChannelIdentity());
+            //java.util.List list = createEventList(session);
+
+            //if(list != null){
+                ExchangeDetails exchange = null;
+                Channel channel = null;
+
+                logger.fine(">>>> creating unexpected event");
+
+                ExchangeEvent event = new ExchangeEvent(exchange, channel, session, serviceDescriptionName, message);
+
+                logger.fine(">>>> created unexpected event");
+                
+                logger.fine("Add unexpected new event '"+event+ "' to correlation session "+session);
+                //list.add(event);
+ 
+                logger.fine(">>>> UNEXPECTED EVENT for session: " + session);
+                
+                fireAddedUnexpectedExchangeEvent(event, serviceDescriptionName);
+
+
+                logger.fine(">>>> HANDLED UNEXPECTED EVENT for session: " + session);
+            //}
+            logger.fine("<<<< unexpectedMessage");
+        }
+        
+        /**
+         * An error occurred related to the specified correlation
+         * session.
+         * 
+         * @param mesg The error message
+         * @param exception The optional exception details
+         * @param session The correlation session
+         * @param serviceDescriptionName The service name
+         */
+        public void error(String mesg, String exception,
+        		CorrelationSession session, String serviceDescriptionName) {
+            logger.fine(">>>> error");
+
+            fireErrorEvent(session, mesg, exception, serviceDescriptionName);
+
+            logger.fine("<<<< error");
+        }
+        
+        /**
+         * A warning occurred related to the specified correlation
+         * session.
+         * 
+         * @param mesg The warning message
+         * @param exception The optional exception details
+         * @param session The correlation session
+         * @param serviceDescriptionName The service name
+         */
+        public void warning(String mesg, String exception,
+        		CorrelationSession session, String serviceDescriptionName) {
+            logger.fine(">>>> warning");
+
+            fireWarningEvent(session, mesg, exception, serviceDescriptionName);
+
+            logger.fine("<<<< warning");
+        }
+        
+        /**
+         * An information event occurred related to the specified correlation
+         * session.
+         * 
+         * @param mesg The information message
+         * @param session The correlation session
+         * @param serviceDescriptionName The service name
+         */
+        public void information(String mesg, CorrelationSession session,
+    			String serviceDescriptionName) {
+            logger.fine(">>>> information");
+
+            fireInformationEvent(session, mesg, serviceDescriptionName);
+
+            logger.fine("<<<< information");
+        }
+    }
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/Activator.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/Activator.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/Activator.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by gary
+ */
+package org.pi4soa.monitor.eclipse;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+import org.pi4soa.common.eclipse.BundleUtil;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class Activator extends AbstractUIPlugin {
+
+	// The plug-in ID
+	public static final String PLUGIN_ID = "org.pi4soa.monitor";
+
+	// 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;
+	}
+
+	
+	static {		
+		BundleUtil.registerClasspathEntries(PLUGIN_ID, false);
+	}
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorAction.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorAction.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorAction.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 17 Jan, 2008 : Initial version created by gary
+ */
+package org.pi4soa.monitor.eclipse;
+
+import java.util.logging.Logger;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.MessageBox;
+import org.eclipse.ui.IObjectActionDelegate;
+import org.eclipse.ui.IWorkbenchPart;
+import org.pi4soa.common.resource.eclipse.ResourceUtil;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationType;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.Launch;
+import org.eclipse.debug.core.DebugPlugin;
+
+/**
+ * This class invokes the monitor action on the selected
+ * choreography file.
+ * 
+ */
+public class MonitorAction implements IObjectActionDelegate {
+
+	/**
+	 * This method implements the action's run method.
+	 * 
+	 * @param action The action
+	 */
+	public void run(IAction action) {
+		
+		if (m_selection instanceof StructuredSelection) {
+			StructuredSelection sel=(StructuredSelection)m_selection;
+			
+			IResource res=(IResource)sel.getFirstElement();
+			
+            // Make sure there are no markers associated
+            // with the resource
+			if (ResourceUtil.hasErrors(res) == false) {
+			
+				launch(res.getProject().getName(),
+							res.getProjectRelativePath().toString());
+							
+			} else {
+				error(ERRORS_NO_TEST);
+			}
+		}
+	}
+	
+	/**
+	 * This method invokes the launch action.
+	 * 
+	 * @param project The project
+	 * @param relativePath The relative path within the project
+	 */
+	protected void launch(String project, String relativePath) {
+		
+		MonitorLauncher launcher=new MonitorLauncher();
+				
+		try {
+			ILaunchManager manager =
+				DebugPlugin.getDefault().getLaunchManager();
+			
+			ILaunchConfigurationType type =
+				manager.getLaunchConfigurationType(
+			      	MonitorLaunchConfigurationConstants.LAUNCH_CONFIG_TYPE);
+			ILaunchConfiguration[] configurations =
+			      manager.getLaunchConfigurations(type);
+			
+			for (int i = 0; i < configurations.length; i++) {
+				ILaunchConfiguration configuration = configurations[i];
+				if (configuration.getName().equals(PI4SOA_MONITOR)) {
+					configuration.delete();
+					break;
+				}
+			}
+			
+			ILaunchConfigurationWorkingCopy workingCopy =
+			      type.newInstance(null, PI4SOA_MONITOR);
+
+			workingCopy.setAttribute(MonitorLaunchConfigurationConstants.ATTR_PROJECT_NAME,
+					project);
+			workingCopy.setAttribute(MonitorLaunchConfigurationConstants.ATTR_CHOREOGRAPHY_DESCRIPTION,
+					relativePath);
+			
+			ILaunchConfiguration configuration=workingCopy.doSave();
+		
+
+			Launch launch=new Launch(configuration, LAUNCH_MODE, null);
+			
+			launcher.launch(configuration, LAUNCH_MODE, launch, null);
+
+		} catch(Exception e) {
+			logger.severe("Failed to launch monitor: "+e);
+			
+			e.printStackTrace();
+		}
+	}
+	
+	/**
+	 * This method is used to report an error.
+	 * 
+	 * @param mesg The error message
+	 */
+	public void error(String mesg) {
+		
+		logger.severe("Error occurred: "+mesg);
+		
+		MessageBox mbox=new MessageBox(m_targetPart.getSite().getShell(),
+				SWT.ICON_ERROR|SWT.OK);
+		
+		if (mesg == null) {
+			mesg = "Null pointer exception has occurred";
+		}
+
+		mbox.setMessage(mesg);
+		mbox.open();
+	}
+	
+	/**
+	 * This method indicates that the selection has changed.
+	 * 
+	 * @param action The action
+	 * @param selection The selection
+	 */
+	public void selectionChanged(IAction action,
+            ISelection selection) {
+		m_selection = selection;
+	}
+
+	/**
+	 * This method sets the currently active workbench part.
+	 * 
+	 * @param action The action
+	 * @param targetPart The active workbench part
+	 */
+	public void setActivePart(IAction action,
+            IWorkbenchPart targetPart) {
+		m_targetPart = targetPart;
+	}
+	
+	private static Logger logger = Logger.getLogger("org.pi4soa.monitor.eclipse");
+
+	private ISelection m_selection=null;
+    private IWorkbenchPart m_targetPart=null;
+
+	private static final String ERRORS_NO_TEST = "Choreography Description has errors, so cannot run monitor";
+
+	private static final String LAUNCH_MODE = "run";
+	private static final String PI4SOA_MONITOR = "Pi4SOA Monitor";
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorLaunchConfigurationConstants.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorLaunchConfigurationConstants.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorLaunchConfigurationConstants.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 17 Jan, 2008 : Initial version created by gary
+ */
+package org.pi4soa.monitor.eclipse;
+
+/**
+ * This interface defines the constants for the monitor
+ * launch configuration.
+ */
+public interface MonitorLaunchConfigurationConstants {
+
+	public static final String ATTR_PROJECT_NAME="project";
+	
+	public static final String ATTR_CHOREOGRAPHY_DESCRIPTION="choreography";
+	
+	public static final String LAUNCH_CONFIG_TYPE=
+			"org.pi4soa.monitor.eclipse.MonitorLauncher";
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorLauncher.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorLauncher.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorLauncher.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 17 Jan, 2008 : Initial version created by gary
+ */
+package org.pi4soa.monitor.eclipse;
+
+import java.io.File;
+import java.text.MessageFormat;
+import java.util.Map;
+import java.util.Vector;
+import java.util.logging.Logger;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.IStreamListener;
+import org.eclipse.debug.core.model.IStreamMonitor;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.jdt.core.IClasspathEntry;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate;
+import org.eclipse.jdt.launching.ExecutionArguments;
+import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
+import org.eclipse.jdt.launching.IVMInstall;
+import org.eclipse.jdt.launching.IVMRunner;
+import org.eclipse.jdt.launching.VMRunnerConfiguration;
+import org.pi4soa.common.eclipse.BundleUtil;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.Path;
+
+/**
+ * This class is responsible for launching a monitor against
+ * a choreography description.
+ */
+public class MonitorLauncher
+			extends AbstractJavaLaunchConfigurationDelegate {
+
+	/**
+	 * This is the default constructor.
+	 *
+	 */
+	public MonitorLauncher() {
+	}
+	
+	/**
+	 * This method launches the monitor.
+	 * 
+	 * @param configuration The launch configuration
+	 * @param mode The mode (run or debug)
+	 * @param launch The launch object
+	 * @param monitor The optional progress monitor
+	 */
+	public void launch(ILaunchConfiguration configuration,
+            String mode, ILaunch launch, IProgressMonitor monitor)
+						throws CoreException {
+		if (monitor == null) {
+			monitor = new NullProgressMonitor();
+		}
+		
+		monitor.beginTask(MessageFormat.format("{0}...", new String[]{configuration.getName()}), 3); //$NON-NLS-1$
+		// check for cancellation
+		if (monitor.isCanceled()) {
+			return;
+		}
+		
+		monitor.subTask("Verifying launch configuration....");
+						
+		String mainTypeName = org.pi4soa.monitor.ui.Monitor.class.getName(); 
+
+		IVMInstall vm = verifyVMInstall(configuration);
+
+		IVMRunner runner = vm.getVMRunner(mode);
+		if (runner == null) {
+			abort("VM runner does not exist",
+					null, IJavaLaunchConfigurationConstants.ERR_VM_RUNNER_DOES_NOT_EXIST); //$NON-NLS-1$
+		}
+
+		File workingDir = verifyWorkingDirectory(configuration);
+		String workingDirName = null;
+		if (workingDir != null) {
+			workingDirName = workingDir.getAbsolutePath();
+		}
+		
+		// Environment variables
+		String[] envp= DebugPlugin.getDefault().getLaunchManager().getEnvironment(configuration);
+		
+		// Program & VM args
+		String filename=configuration.getAttribute(
+				MonitorLaunchConfigurationConstants.ATTR_PROJECT_NAME, "")+
+				"/"+configuration.getAttribute(
+				MonitorLaunchConfigurationConstants.ATTR_CHOREOGRAPHY_DESCRIPTION, "");
+		
+		String pgmArgs="\""+getPathForResource(filename);
+		
+		logger.fine("Launching monitor with args: "+pgmArgs);
+			
+		String vmArgs = getVMArguments(configuration);
+		ExecutionArguments execArgs = new ExecutionArguments(vmArgs, pgmArgs);
+		
+		// VM-specific attributes
+		Map vmAttributesMap = getVMSpecificAttributesMap(configuration);
+		
+		// Classpath
+		String[] classpath = getClasspath(configuration);
+			
+		// Create VM config
+		VMRunnerConfiguration runConfig = new VMRunnerConfiguration(mainTypeName, classpath);
+		runConfig.setProgramArguments(execArgs.getProgramArgumentsArray());
+		runConfig.setEnvironment(envp);
+		runConfig.setVMArguments(execArgs.getVMArgumentsArray());
+		runConfig.setWorkingDirectory(workingDirName);
+		runConfig.setVMSpecificAttributesMap(vmAttributesMap);
+
+		// Bootpath
+		runConfig.setBootClassPath(getBootpath(configuration));
+				
+		// check for cancellation
+		if (monitor.isCanceled()) {
+			return;
+		}		
+		
+		// stop in main
+		prepareStopInMain(configuration);
+		
+		// done the verification phase
+		monitor.worked(1);
+		
+		// Launch the configuration - 1 unit of work
+		runner.run(runConfig, launch, monitor);
+		
+		IProcess[] processes=launch.getProcesses();
+		if (processes.length > 0) {
+			processes[0].getStreamsProxy().getOutputStreamMonitor().
+						addListener(new IStreamListener() {
+				public void streamAppended(String str, IStreamMonitor mon) {
+					handleResults(str, false);
+				}
+			});
+			processes[0].getStreamsProxy().getErrorStreamMonitor().
+						addListener(new IStreamListener() {
+				public void streamAppended(String str, IStreamMonitor mon) {
+					handleResults(str, true);
+				}
+			});
+		}
+		
+		// check for cancellation
+		if (monitor.isCanceled()) {
+			return;
+		}	
+		
+		monitor.done();
+	}
+	
+	/**
+	 * This method handles the results produced by the launched
+	 * monitor.
+	 * 
+	 * @param results The results
+	 * @param errorStream Whether the results are from the error
+	 * 						stream
+	 */
+	protected void handleResults(String results, boolean errorStream) {
+		//System.out.println(results);
+	}
+	
+	/**
+	 * This method returns the full path to the resource.
+	 * 
+	 * @param relativePath The is the resource path beginning at
+	 * 					the project
+	 * @return The full path
+	 */
+	protected String getPathForResource(String relativePath) {
+		String ret=null;
+		
+		IFile file=ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(relativePath));
+		if (file != null && file.exists()) {
+			ret = file.getLocation().toString();
+		}
+		
+		return(ret);
+	}
+	
+	/**
+	 * This method derives the classpath required to run the 
+	 * Monitor.
+	 * 
+	 * @param configuration The launch configuation
+	 * @return The list of classpath entries
+	 */
+	public String[] getClasspath(ILaunchConfiguration configuration) {
+		String[] ret=null;
+		Vector classpathEntries=new Vector();
+					
+		// Add classpath entry for current Java project
+		try {
+			String projname=configuration.getAttribute(
+				MonitorLaunchConfigurationConstants.ATTR_PROJECT_NAME, "");
+		
+			IProject project=
+				ResourcesPlugin.getWorkspace().getRoot().getProject(projname);
+
+			IJavaProject jproject=JavaCore.create(project); 
+			
+			// Add output location
+			IPath outputLocation=jproject.getOutputLocation();
+			
+			IFolder folder=
+				ResourcesPlugin.getWorkspace().getRoot().getFolder(outputLocation);
+			
+			String path=folder.getLocation().toString();
+
+			classpathEntries.add(path);
+			
+			// Add other libraries to the classpath
+			IClasspathEntry[] curclspath=jproject.getRawClasspath();
+			for (int i=0; curclspath != null &&
+						i < curclspath.length; i++) {
+				
+				if (curclspath[i].getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
+					IFile file=
+						ResourcesPlugin.getWorkspace().
+							getRoot().getFile(curclspath[i].getPath());
+
+					if (file.exists()) {
+						// Library is within the workspace
+						classpathEntries.add(file.getLocation().toString());
+					} else {
+						// Assume library is external to workspace
+						classpathEntries.add(curclspath[i].getPath().toString());
+					}
+					
+				} else if (curclspath[i].getEntryKind() ==
+								IClasspathEntry.CPE_CONTAINER) {
+					// Container's not currently handled - but
+					// problem need to retrieve from project and
+					// iterate over container entries
+				}
+			}
+			
+		} catch(Exception e) {
+			// TODO: report error
+		}
+		
+		String[] cpes=BundleUtil.getClasspathEntries();
+		
+		for (int i=0; i < cpes.length; i++) {
+			classpathEntries.add(cpes[i]);
+		}
+		
+		ret = new String[classpathEntries.size()];
+		classpathEntries.copyInto(ret);
+		
+		return(ret);
+	}
+	
+	private static Logger logger = Logger.getLogger("org.pi4soa.monitor.eclipse");
+}
\ No newline at end of file

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorMainTab.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorMainTab.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorMainTab.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,516 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 17 Jan, 2008 : Initial version created by gary
+ */
+package org.pi4soa.monitor.eclipse;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.window.Window;
+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.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.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.dialogs.ElementListSelectionDialog;
+
+/**
+ * This class represents the first main tab within the tab group
+ * associated with the monitor launch configuration.
+ */
+public class MonitorMainTab extends AbstractLaunchConfigurationTab {
+	
+	/**
+	 * @see ILaunchConfigurationTab#createControl(org.eclipse.swt.widgets.Composite)
+	 */
+	public void createControl(Composite parent) {		
+		Composite comp = new Composite(parent, SWT.NONE);
+		setControl(comp);
+
+		GridLayout topLayout = new GridLayout();
+		topLayout.numColumns= 3;
+		comp.setLayout(topLayout);		
+		
+		Label label = new Label(comp, SWT.NONE);
+		GridData gd = new GridData();
+		gd.horizontalSpan = 3;
+		label.setLayoutData(gd);
+		
+		createChoreographySection(comp);
+		
+		label = new Label(comp, SWT.NONE);
+		gd = new GridData();
+		gd.horizontalSpan = 3;
+		label.setLayoutData(gd);
+		
+		Dialog.applyDialogFont(comp);
+		validatePage();
+	}
+	
+	/**
+	 * This method creates the GUI components for the
+	 * monitor tab.
+	 * 
+	 * @param comp The composite
+	 */
+	protected void createChoreographySection(Composite comp) {
+		GridData gd = new GridData();
+		gd.horizontalSpan = 3;
+		
+		m_projectLabel = new Label(comp, SWT.NONE);
+		m_projectLabel.setText("Project");
+		gd= new GridData();
+		gd.horizontalIndent = 25;
+		m_projectLabel.setLayoutData(gd);
+		
+		m_project= new Text(comp, SWT.SINGLE | SWT.BORDER);
+		m_project.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		m_project.addModifyListener(new ModifyListener() {
+			public void modifyText(ModifyEvent evt) {
+				validatePage();
+				updateLaunchConfigurationDialog();				
+				m_choreographySearch.setEnabled(m_project.getText().length() > 0);
+			}
+		});
+			
+		m_projectButton = new Button(comp, SWT.PUSH);
+		m_projectButton.setText("Browse");
+		m_projectButton.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent evt) {
+				handleProjectButtonSelected();
+			}
+		});
+		setButtonGridData(m_projectButton);
+		
+		m_choreographyLabel = new Label(comp, SWT.NONE);
+		gd = new GridData();
+		gd.horizontalIndent = 25;
+		m_choreographyLabel.setLayoutData(gd);
+		m_choreographyLabel.setText("Choreography");
+		
+		m_choreography = new Text(comp, SWT.SINGLE | SWT.BORDER);
+		m_choreography.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+		m_choreography.addModifyListener(new ModifyListener() {
+			public void modifyText(ModifyEvent evt) {
+				validatePage();
+				updateLaunchConfigurationDialog();
+			}
+		});
+		
+		m_choreographySearch = new Button(comp, SWT.PUSH);
+		m_choreographySearch.setEnabled(m_project.getText().length() > 0);		
+		m_choreographySearch.setText("Search");
+		m_choreographySearch.addSelectionListener(new SelectionAdapter() {
+			public void widgetSelected(SelectionEvent evt) {
+				handleSearchButtonSelected();
+			}
+		});
+		setButtonGridData(m_choreographySearch);
+	}
+
+	protected static Image createImage(String path) {
+		return null;
+	}
+
+
+	/**
+	 * @see ILaunchConfigurationTab#initializeFrom(ILaunchConfiguration)
+	 */
+	public void initializeFrom(ILaunchConfiguration config) {
+		String projectName= "";
+		String choreography= "";
+
+		try {
+			projectName = config.getAttribute(MonitorLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""); //$NON-NLS-1$
+		} catch (CoreException ce) {
+		}
+		m_project.setText(projectName);
+		
+		try {
+			choreography = config.getAttribute(MonitorLaunchConfigurationConstants.ATTR_CHOREOGRAPHY_DESCRIPTION, ""); //$NON-NLS-1$
+		} catch (CoreException ce) {			
+		}
+		m_choreography.setText(choreography);
+	}
+
+	/**
+	 * @see ILaunchConfigurationTab#performApply(ILaunchConfigurationWorkingCopy)
+	 */
+	public void performApply(ILaunchConfigurationWorkingCopy config) {
+	}
+
+	/**
+	 * @see ILaunchConfigurationTab#dispose()
+	 */
+	public void dispose() {
+		super.dispose();
+	}
+
+	/**
+	 * @see AbstractLaunchConfigurationTab#getImage()
+	 */
+	public Image getImage() {
+		return(null);
+	}
+
+	/**
+	 * This method sets the grid data for the button.
+	 * 
+	 * @param button The button
+	 */
+	protected void setButtonGridData(Button button) {
+		GridData gridData= new GridData();
+		button.setLayoutData(gridData);
+		//SWTUtil.setButtonDimensionHint(button);
+	}
+
+	/**
+	 * Show a dialog that lists all choreography files within the
+	 * selected project
+	 */
+	protected void handleSearchButtonSelected() {
+		
+		IProject project = getProject();
+
+		ILabelProvider labelProvider=new LabelProvider() {
+			public String getText(Object obj) {
+				String ret="<unknown>";
+				if (obj instanceof IResource) {
+					String filename=((IResource)obj).getName();
+					if (filename.endsWith(org.pi4soa.cdl.CDLDefinitions.CDL_FILE_EXTENSION)) {
+						filename = filename.substring(0, filename.length()-
+								org.pi4soa.cdl.CDLDefinitions.CDL_FILE_EXTENSION.length()-1);
+					}
+					ret = filename+" ["+
+						((IResource)obj).getParent().
+						getProjectRelativePath()+"]";
+				}
+				return(ret);
+			}
+		};
+		
+		IResource[] choreos=null;
+		
+		if (project.exists() == false) {
+			choreos = new IResource[0];
+		} else {
+			choreos = getChoreographies(project);
+		}
+
+		ElementListSelectionDialog dialog= new ElementListSelectionDialog(getShell(), labelProvider);
+		dialog.setTitle("Choreographies");
+		dialog.setMessage("Select the relevant choreography");
+		dialog.setElements(choreos);
+		
+		if (dialog.open() == Window.OK) {			
+			IResource file=(IResource)dialog.getFirstResult();
+			m_choreography.setText(file.getProjectRelativePath().toString());
+		}
+	}
+	
+	/**
+	 * This method returns the list of choreography resource files within
+	 * the supplied project.
+	 * 
+	 * @param project The project
+	 * @return The list of choreography resource files
+	 */
+	protected IResource[] getChoreographies(IProject project) {
+		IResource[] ret=null;
+		final java.util.Vector list=new java.util.Vector();
+		
+		try {
+			project.accept(new org.eclipse.core.resources.IResourceVisitor() {
+				public boolean visit(IResource res) {
+
+					if (res.getFileExtension() != null &&
+							res.getFileExtension().equals(
+									org.pi4soa.cdl.CDLDefinitions.CDL_FILE_EXTENSION)) {
+						list.add(res);
+					}
+
+					return(true);
+				}
+			});
+			
+			ret = new IResource[list.size()];
+			list.copyInto(ret);
+			
+		} catch(Exception e) {
+			e.printStackTrace();
+		}
+		
+		return(ret);
+	}
+		
+	/**
+	 * Show a dialog that lets the user select a project.  This in turn provides
+	 * context for the main type, allowing the user to key a main type name, or
+	 * constraining the search for main types to the specified project.
+	 */
+	protected void handleProjectButtonSelected() {
+		IProject project = chooseProject();
+		if (project == null) {
+			return;
+		}
+		
+		String projectName = project.getName();
+		m_project.setText(projectName);		
+	}
+	
+	/**
+	 * Realize a Java Project selection dialog and return the first selected project,
+	 * or null if there was none.
+	 */
+	protected IProject chooseProject() {
+		IProject[] projects;
+		try {
+			projects= getWorkspaceRoot().getProjects();
+		} catch (Exception e) {
+			projects= new IProject[0];
+		}
+		
+		ILabelProvider labelProvider=new LabelProvider() {
+			public String getText(Object obj) {
+				String ret="<unknown>";
+				if (obj instanceof IResource) {
+					ret = ((IResource)obj).getName();
+				}
+				return(ret);
+			}
+		};
+
+		ElementListSelectionDialog dialog= new ElementListSelectionDialog(getShell(), labelProvider);
+		dialog.setTitle("Projects");
+		dialog.setMessage("Select the relevant project");
+		dialog.setElements(projects);
+		
+		IProject project = getProject();
+		if (project != null) {
+			dialog.setInitialSelections(new Object[] { project });
+		}
+		if (dialog.open() == Window.OK) {			
+			return (IProject) dialog.getFirstResult();
+		}			
+		return null;		
+	}
+	
+	/**
+	 * Return the IProject corresponding to the project name in the project name
+	 * text field, or null if the text does not match a project name.
+	 */
+	protected IProject getProject() {
+		String projectName = m_project.getText().trim();
+		if (projectName.length() < 1) {
+			return null;
+		}
+		return(getWorkspaceRoot().getProject(projectName));
+	}
+	
+	/**
+	 * Convenience method to get the workspace root.
+	 */
+	private IWorkspaceRoot getWorkspaceRoot() {
+		return ResourcesPlugin.getWorkspace().getRoot();
+	}
+	
+	/**
+	 * @see ILaunchConfigurationTab#isValid(ILaunchConfiguration)
+	 */
+	public boolean isValid(ILaunchConfiguration config) {		
+		return getErrorMessage() == null;
+	}
+	
+	/**
+	 * This method validates the page.
+	 *
+	 */
+	private void validatePage() {
+		setErrorMessage(null);
+		setMessage(null);
+		
+		String projectName = m_project.getText().trim();
+		if (projectName.length() == 0) {
+			setErrorMessage("Project name not specified");
+			return;
+		}
+			
+		IProject project = getWorkspaceRoot().getProject(projectName);
+		if (!project.exists()) {
+			setErrorMessage("Project '"+projectName+"' does not exist");
+			return;
+		}
+		
+		try {
+			String choreographyName = m_choreography.getText().trim();
+			if (choreographyName.length() == 0) {
+				setErrorMessage("Choreography has not been defined");
+				return;
+			}
+			IResource resource = project.findMember(choreographyName);
+			if (resource == null) {
+				setErrorMessage("Could not find choreography '"+choreographyName+"'");
+			} else {
+				
+				// TODO: Check is valid choreography model
+			}
+		} catch (Exception e) {
+		}
+	}
+
+	/**
+	 * @see ILaunchConfigurationTab#setDefaults(ILaunchConfigurationWorkingCopy)
+	 */
+	public void setDefaults(ILaunchConfigurationWorkingCopy config) {
+		
+		IResource resource = getContext();
+		if (resource != null) {
+			initializeProject(resource, config);
+		} else {
+			config.setAttribute(MonitorLaunchConfigurationConstants.ATTR_PROJECT_NAME, "");
+			config.setAttribute(MonitorLaunchConfigurationConstants.ATTR_CHOREOGRAPHY_DESCRIPTION, "");
+		}
+		initializeTestAttributes(resource, config);
+	}
+
+	/**
+	 * This method identifies the context associated with the
+	 * monitor.
+	 * 
+	 * @return The context resource
+	 */
+	protected IResource getContext() {
+		IResource ret=null;
+		IWorkbenchPage page =
+			org.eclipse.ui.PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+				
+		if (page != null) {
+			ISelection selection = page.getSelection();
+			if (selection instanceof IStructuredSelection) {
+				IStructuredSelection ss = (IStructuredSelection)selection;
+				if (!ss.isEmpty()) {
+					Object obj = ss.getFirstElement();
+					if (obj instanceof IResource) {
+						ret = (IResource)obj;
+					}
+				}
+			}
+			
+			if (ret == null) {
+				IEditorPart part = page.getActiveEditor();
+				if (part != null) {
+					IEditorInput input = part.getEditorInput();
+					ret =(IResource)input.getAdapter(IResource.class);
+				}
+			}
+		}
+		
+		return(ret);
+	}
+
+	/**
+	 * This method initializes the project details.
+	 * 
+	 * @param resource The resource
+	 * @param config The configuration
+	 */
+	protected void initializeProject(IResource resource, ILaunchConfigurationWorkingCopy config) {
+		IProject project = resource.getProject();
+		String name = null;
+		if (project != null && project.exists()) {
+			name = project.getName();
+		}
+		config.setAttribute(MonitorLaunchConfigurationConstants.ATTR_PROJECT_NAME, name);
+	}
+	
+	/**
+	 * This method initializes the choreography details.
+	 * 
+	 * @param resource The selected resource
+	 * @param config The configuration
+	 */
+	private void initializeTestAttributes(IResource resource, ILaunchConfigurationWorkingCopy config) {
+		if (resource != null && (resource.getType() == IResource.FOLDER ||
+				(resource.getType() == IResource.FILE &&
+				resource.getFileExtension().equals(
+						org.pi4soa.cdl.CDLDefinitions.CDL_FILE_EXTENSION)))) {
+			
+			config.setAttribute(MonitorLaunchConfigurationConstants.ATTR_CHOREOGRAPHY_DESCRIPTION,
+					resource.getProjectRelativePath().toString());
+		
+			initializeName(config, resource.getName());
+		}
+	}
+
+	/**
+	 * This method initializes the launch configuration name.
+	 * 
+	 * @param config The configuration
+	 * @param name The name
+	 */
+	private void initializeName(ILaunchConfigurationWorkingCopy config, String name) {
+		if (name == null) {
+			name= "";
+		}
+		if (name.length() > 0) {
+			
+			int index = name.lastIndexOf('.');
+			if (index > 0) {
+				name = name.substring(0, index);
+			}
+			name= getLaunchConfigurationDialog().generateName(name);
+			config.rename(name);
+		}
+	}
+
+	/**
+	 * @see ILaunchConfigurationTab#getName()
+	 */
+	public String getName() {
+		return("Monitor");
+	}
+
+	private Label m_projectLabel=null;
+	private Text m_project=null;
+	private Button m_projectButton=null;
+	private Label m_choreographyLabel=null;
+	private Text m_choreography=null;
+	private Button m_choreographySearch=null;	
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorTabGroup.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorTabGroup.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/eclipse/MonitorTabGroup.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 17 Jan, 2008 : Initial version created by gary
+ */
+package org.pi4soa.monitor.eclipse;
+
+import org.eclipse.debug.ui.AbstractLaunchConfigurationTabGroup;
+import org.eclipse.debug.ui.CommonTab;
+import org.eclipse.debug.ui.ILaunchConfigurationDialog;
+import org.eclipse.debug.ui.ILaunchConfigurationTab;
+import org.eclipse.jdt.debug.ui.launchConfigurations.JavaJRETab;
+
+/**
+ * This class represents the UI tab group for the Scenario Test
+ * launcher.
+ */
+public class MonitorTabGroup extends
+			AbstractLaunchConfigurationTabGroup {
+
+	/**
+	 * The default constructor for the scenario type tab group.
+	 */
+	public MonitorTabGroup() {
+	}
+
+	/**
+	 * This method creates the tabs for the scenario test launch
+	 * configuration.
+	 * 
+	 * @param dialog The launch configuration dialog
+	 * @param mode The mode
+	 */
+	public void createTabs(ILaunchConfigurationDialog dialog, String mode) {
+		ILaunchConfigurationTab[] tabs = new ILaunchConfigurationTab[] {
+			new MonitorMainTab(),
+			new JavaJRETab(),
+			new CommonTab()
+		};
+		setTabs(tabs);
+	}
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ChannelJPanel.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ChannelJPanel.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ChannelJPanel.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,556 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
+import org.pi4soa.service.Identity;
+import org.pi4soa.service.correlator.CorrelationSession;
+
+
+/**
+ * The left hand pane contains a tree whose root is the
+ * choreography, and whose leaves are channels and transactions.
+ *
+ * Selecting a channel filters the exchange events list (or should
+ * do).
+ */
+public class ChannelJPanel extends JPanel{
+
+    public final static String UNEXPECTED_MESSAGES_NAME = "Unexpected Messages";
+    public final static String ERROR_NAME="Errors";
+    public final static String WARNING_NAME="Warnings";
+    public final static String INFORMATION_NAME="Information";
+    
+    private static Logger 	logger = Logger.getLogger("org.pi4soa.monitor.ui");
+  
+    JTree 					tree = null;
+    TreeSelectionListener 	listener = null;
+    JScrollPane 			treeView = null;
+
+    ImageIcon 				channelLeafIcon = null;
+    ImageIcon 				channelOpenIcon = null;
+    ImageIcon 				channelClosedIcon = null;
+    ImageIcon 				channelEmptyIcon = null;
+    ImageIcon 				errorsLeafIcon = null;
+    ImageIcon 				unexpectedLeafIcon = null;
+    ImageIcon 				warningsLeafIcon = null;
+    ImageIcon 				issuesOpenIcon = null;
+    ImageIcon 				issuesClosedIcon = null;
+    ImageIcon 				issuesEmptyIcon = null;
+    ImageIcon 				txnLeafIcon = null;
+    ImageIcon 				txnOpenIcon = null;
+    ImageIcon 				txnClosedIcon = null;
+    ImageIcon 				txnEmptyIcon = null;
+    
+    //    Vector exchangeEvents = null;
+    ExchangeEventsData 		exchangeEventsData = null;
+    
+    DefaultTreeModel 		treeModel = null;
+    DefaultMutableTreeNode 	rootNode = null;
+    
+    DefaultMutableTreeNode  channelRoot = null;
+    DefaultMutableTreeNode  issuesRoot = null;
+    DefaultMutableTreeNode  errorsRoot = null;
+    DefaultMutableTreeNode  warningsRoot = null;
+    DefaultMutableTreeNode  unexpectedMessagesRoot = null;
+    DefaultMutableTreeNode  sessionRoot = null;
+    
+    String	sessionRootName = "Sessions";
+    String	channelRootName = "Channels";
+    String	unexpectedMessagesRootName = UNEXPECTED_MESSAGES_NAME;
+    String 	errorsRootName = ERROR_NAME;
+    String 	warningsRootName = WARNING_NAME;
+    String 	issuesRootName = "Issues";
+    
+
+
+    /**
+     * Creates a new ChannelJPanel.
+     *
+     * @param listener The listener for tree selection changes.
+     */
+    public ChannelJPanel(TreeSelectionListener listener){
+
+        this.listener = listener;
+        this.setBackground(Color.white);
+        this.setLayout(new BorderLayout());
+    }
+    
+    public ChannelJPanel(ExchangeEventsData eed, TreeSelectionListener listener){
+        this.listener = listener;
+        this.setBackground(Color.white);
+        this.setLayout(new BorderLayout());
+        exchangeEventsData = eed;
+    }
+
+    ////////////////////////////////////////////
+
+    static public String getUnexpectedMessagesName()
+    {	
+    	return UNEXPECTED_MESSAGES_NAME;
+    }
+    
+    static public String getErrorName() {
+    	return(ERROR_NAME);
+    }
+    
+    static public String getWarningName() {
+    	return(WARNING_NAME);
+    }
+    
+    static public String getInformationName() {
+    	return(INFORMATION_NAME);
+    }
+    
+    public void addedSession(CorrelationSession s)
+    {
+    	logger.fine("ADD SESSION TO PANEL " + s);
+    	logger.fine("rootNote child count is: " + rootNode.getChildCount());
+    	String name = ChannelJPanel.getSessionIdentity(s);
+    	if (name == null)
+    	{
+    		name = "Session :" + s.toString().substring(s.getClass().getName().length());
+    	}
+		logger.info("ADDING SESSION FOR TXN: " + name);
+		
+		addObject(sessionRoot,new ProxyTreeNode(name, s),true);
+    }
+     
+    static public String getSessionIdentity(CorrelationSession s)
+    {
+    	String identityString = null;
+    	java.util.List<Identity> messageIdentityArray = s.getIdentities();
+    	if (messageIdentityArray != null)
+    		logger.info("sessionIdentArray length is: " + messageIdentityArray.size());
+    	else
+    		logger.info("messageIdentityArray was null");
+        if(messageIdentityArray == null || messageIdentityArray.size() == 0)
+        {
+                return identityString;
+        } else {
+                Identity firstMessageIdentity = messageIdentityArray.get(0);
+                //                    messageIdentityString = firstMessageIdentity.toText();
+                String tokens[] = firstMessageIdentity.getTokens();
+                // value
+                Object values_obj[] = firstMessageIdentity.getValues();
+                
+                String[] values = new String[values_obj.length];
+                
+                for (int values_index=0; values_index < values_obj.length; values_index++)
+                {
+                	values[values_index] = values_obj[values_index].toString();
+                	if (values_obj[values_index] instanceof String) 
+                	{
+                	    values[values_index] = (String)values_obj[values_index];
+                	} 
+                	else if (values_obj[values_index] instanceof java.util.List) 
+                	{
+                		java.util.List list = (java.util.List)values_obj[values_index];
+                	    values[values_index] = "{";
+                	    for (int i=0; (i < list.size()); i++ ) 
+                	    {
+                	    	values[values_index] += (String)list.get(i);
+                	    }
+                	    values[values_index] += "}";
+                	} else {
+                		logger.severe("Problem creating an identity string, values is of unknown type.");
+                	}
+
+                }
+
+                if(tokens == null || values == null)
+                {
+                    if(tokens == null)
+                    {
+                        logger.fine("identity.getTokens() returned null");
+                        //                        messageIdentityString = "null tokens";
+                    }
+
+                    if(values == null)
+                    {
+                        logger.fine("identity.getValues() returned null");
+                        //                        messageIdentityString = "null values";
+                    }
+
+                    identityString = firstMessageIdentity.toString();
+                } else {
+                    if(tokens != null && values != null && tokens.length == values.length)
+                    {
+                        identityString = "";
+                        for(int i = 0; i < tokens.length - 1; i++)
+                        {
+                            identityString += values[i] + " (" + tokens[i] + "), ";
+                        }
+                        identityString += values[tokens.length - 1] + " (" + tokens[tokens.length - 1]+")";
+                    } else {
+                        identityString = "tokens/values mismatch";
+                    }
+                }
+        }
+        
+        return identityString;
+    }
+    
+    /**
+     * Adds the channel nodes to the tree, sorted in name order.
+     */
+    public void createAndAddTree(org.pi4soa.cdl.Package choreography){        
+        if(tree != null){
+            // remove the current tree ...
+            this.remove(treeView);
+            treeView = null;
+            tree = null;
+        }
+        
+        rootNode = new DefaultMutableTreeNode(choreography.getName());
+    	if (treeModel == null){
+    		treeModel = new DefaultTreeModel(rootNode);
+    		treeModel.addTreeModelListener(new MonitorTreeModelListener());
+    	}
+    	
+        createChannelNodes(treeModel, choreography);
+
+        tree = new JTree(treeModel); // instead of rootNode instead of treeModel
+        ChannelTreeCellRenderer renderer = new ChannelTreeCellRenderer();
+
+        if(txnLeafIcon == null) txnLeafIcon = MonitorMainPanel.createImageIcon("icons/txnleaf.png");
+        if(txnOpenIcon == null) txnOpenIcon = MonitorMainPanel.createImageIcon("icons/txnopen.png");
+        if(txnClosedIcon == null) txnClosedIcon = MonitorMainPanel.createImageIcon("icons/txnclosed.png");
+        if(txnEmptyIcon == null) txnEmptyIcon = MonitorMainPanel.createImageIcon("icons/txnempty.png");
+        if(channelLeafIcon == null) channelLeafIcon = MonitorMainPanel.createImageIcon("icons/channelleaf.png");
+        if(channelOpenIcon == null) channelOpenIcon = MonitorMainPanel.createImageIcon("icons/channelopen.png");
+        if(channelClosedIcon == null) channelClosedIcon = MonitorMainPanel.createImageIcon("icons/channelclosed.png");
+        if(channelEmptyIcon == null) channelEmptyIcon = MonitorMainPanel.createImageIcon("icons/channelempty.png");
+        if(errorsLeafIcon == null) errorsLeafIcon = MonitorMainPanel.createImageIcon("icons/errorsleaf.png");
+        if(warningsLeafIcon == null) warningsLeafIcon = MonitorMainPanel.createImageIcon("icons/warningsleaf.png");
+        if(unexpectedLeafIcon == null) unexpectedLeafIcon = MonitorMainPanel.createImageIcon("icons/unexpectedleaf.png");
+        if(issuesOpenIcon == null) issuesOpenIcon = MonitorMainPanel.createImageIcon("icons/issuesopen.png");
+        if(issuesClosedIcon == null) issuesClosedIcon = MonitorMainPanel.createImageIcon("icons/issuesclosed.png");
+        if(issuesEmptyIcon == null) issuesEmptyIcon = MonitorMainPanel.createImageIcon("icons/issuesempty.png");
+
+        tree.setCellRenderer(renderer);
+        
+        tree.setRootVisible(false);
+
+        tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+
+        // Listen for when the selection changes.
+        tree.addTreeSelectionListener(listener);
+
+        treeView = new JScrollPane(this.tree);
+        this.add(treeView, BorderLayout.CENTER);
+
+        // hack.
+        this.revalidate();
+    }
+    
+    /**
+     * Adds the channel nodes to the tree, sorted in name order.
+     */
+    private void createChannelNodes(DefaultTreeModel t, org.pi4soa.cdl.Package choreography){
+
+        issuesRoot = addObject(null, issuesRootName);
+        unexpectedMessagesRoot = addObject(issuesRoot,unexpectedMessagesRootName); // was nullChannel
+        errorsRoot = addObject(issuesRoot,errorsRootName); // was nullChannel
+        warningsRoot = addObject(issuesRoot,warningsRootName); // was nullChannel
+
+        sessionRoot = addObject(null,sessionRootName); // was sessionRoot   
+    	    	
+    	logger.fine("createChannelNodes(new)");
+    	
+    	channelRoot = addObject(null,channelRootName); // was channelRoot
+
+        org.pi4soa.cdl.TypeDefinitions typeDefinitions = choreography.getTypeDefinitions();
+        org.eclipse.emf.common.util.EList channelTypes = typeDefinitions.getChannelTypes();
+
+        // we would like to sort the list of channels first
+
+        org.eclipse.emf.common.util.ECollections.sort(channelTypes, new Comparator() {
+                public int compare(Object o1, Object o2) {
+                    return ((org.pi4soa.cdl.ChannelType) o1).getName().compareTo(
+                                             ((org.pi4soa.cdl.ChannelType) o2).getName()
+                                             );
+                }
+            });
+
+        Iterator listIterator = channelTypes.iterator();
+        while(listIterator.hasNext()){
+            org.pi4soa.cdl.ChannelType channelType = (org.pi4soa.cdl.ChannelType) listIterator.next();
+            ProxyTreeNode node = new ProxyTreeNode(channelType.getName(),
+            					channelType);
+            logger.fine("Adding channel type to tree: " + channelType.getName());
+            addObject(channelRoot,node);
+        }
+    }
+    
+    
+    /** Add child to the currently selected node. */
+    public DefaultMutableTreeNode addObject(Object child) {
+    	logger.fine("addObject " + child.toString() + " to child");
+        DefaultMutableTreeNode parentNode = null;
+        TreePath parentPath = tree.getSelectionPath();
+
+        if (parentPath == null) {
+            parentNode = rootNode;
+        } else {
+            parentNode = (DefaultMutableTreeNode)
+                         (parentPath.getLastPathComponent());
+        }
+
+        return addObject(parentNode, child, true);
+    }
+
+    public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent,
+                                            Object child) {
+    	logger.fine("addObject " + child.toString() + " to parent");
+        return addObject(parent, child, false);
+    }
+
+    public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent,
+                                            Object child, 
+                                            boolean shouldBeVisible) {
+    	logger.fine("addObject " + child.toString() + " to parent with visibility " + shouldBeVisible);
+        DefaultMutableTreeNode childNode = 
+                new DefaultMutableTreeNode(child);
+
+        if (parent == null) {
+            parent = rootNode;
+        }
+
+        treeModel.insertNodeInto(childNode, parent, 
+                                 parent.getChildCount());
+
+        //Make sure the user can see the lovely new node.
+        if (shouldBeVisible) {
+            tree.scrollPathToVisible(new TreePath(childNode.getPath()));
+        }
+        return childNode;
+    }
+
+
+    /**
+     * Adds the channel nodes to the tree, sorted in name order.
+     */
+    public void setChannelSelectionOn(boolean channelSelection){
+        if(channelSelection == true){
+            tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+        }
+        else{
+
+        }
+    }
+
+
+    /**
+     *
+     */
+    public JTree getTree(){
+        return tree;
+    }
+
+
+    /**
+     *
+     */
+    public void redraw(){
+        tree.setSelectionPaths(tree.getSelectionPaths());
+        tree.revalidate();
+        tree.repaint();
+    }
+    
+    public class ProxyTreeNode {
+    	
+    	public ProxyTreeNode(String label, Object obj) {
+    		m_label = label;
+    		m_object = obj;
+    	}
+    	
+    	public String getLabel() {
+    		return(m_label);
+    	}
+    	
+    	public Object getObject() {
+    		return(m_object);
+    	}
+    	
+    	public String toString() {
+    		return(m_label);
+    	}
+    	
+    	private String m_label=null;
+    	private Object m_object=null;
+    }
+    
+    public class ChannelTreeCellRenderer extends DefaultTreeCellRenderer{
+
+        private Color originalTextNonSelectionColor = null;
+        private Color originalTextSelectionColor = null;
+
+        /**
+         *
+         */
+        public Component getTreeCellRendererComponent(JTree tree,
+                                                      Object value,
+                                                      boolean selected,
+                                                      boolean expanded,
+                                                      boolean leaf,
+                                                      int row,
+                                                      boolean hasFocus){
+        	
+        	logger.fine("getTreeCellRendererComponent(" + value.toString() + ")");
+
+            if(originalTextNonSelectionColor == null) originalTextNonSelectionColor = this.getTextNonSelectionColor();
+            if(originalTextSelectionColor == null) originalTextSelectionColor = this.getTextSelectionColor();
+
+            boolean nodeHasErrors = false;
+            boolean nodeHasWarnings = false;
+            boolean nodeHasUnexpectedMessage = false;
+
+            if(leaf == true){
+                if(exchangeEventsData.getHasErrorsForChannel(value.toString()) == true ||
+                		exchangeEventsData.getHasErrorsForSession(value.toString())) {
+                    nodeHasErrors = true;
+                }
+                else if(exchangeEventsData.getHasWarningsForChannel(value.toString()) == true ||
+                		exchangeEventsData.getHasWarningsForSession(value.toString())) {
+                    nodeHasWarnings = true;
+                }
+                else if (exchangeEventsData.getHasUnexpectedExchangeEventsForChannel(value.toString()) == true ||
+                		exchangeEventsData.getHasUnexpectedExchangeEventsForSession(value.toString())) {
+                	nodeHasUnexpectedMessage = true;
+                }
+            }
+            else{
+                //nodeHasErrors = exchangeEventsData.getHasErrors();
+                //nodeHasWarnings = exchangeEventsData.getHasWarnings();
+                //nodeHasUnexpectedMessage = exchangeEventsData.getHasUnexpectedMessages();
+            }
+
+            //
+            // Sets the left panel colors
+            //
+            if(nodeHasErrors == true){
+            	logger.fine("hasErrors - dark red");
+                this.setTextNonSelectionColor(Color.red.darker());
+                this.setTextSelectionColor(Color.red.darker());
+            }
+            else if(nodeHasWarnings == true){
+            	logger.fine("hasWarnings - orange");
+                this.setTextNonSelectionColor(Color.orange);
+                this.setTextSelectionColor(Color.orange);
+            }
+            else if (nodeHasUnexpectedMessage == true) {
+            	logger.fine("hasUnexpectedMessages - red");
+                this.setTextNonSelectionColor(Color.red);
+                this.setTextSelectionColor(Color.red);            	
+            }
+            else{
+            	logger.fine("hasOkay");
+                this.setTextNonSelectionColor(originalTextNonSelectionColor);
+                this.setTextSelectionColor(originalTextSelectionColor);
+            }
+
+            if (value instanceof DefaultMutableTreeNode) {
+                m_lastValue = ((DefaultMutableTreeNode)value).getUserObject();
+            } else {
+                m_lastValue = value;
+            }
+            
+            return super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
+        }
+
+        public Icon getOpenIcon() {
+        	Icon ret=super.getOpenIcon();
+        	
+        	if (m_lastValue.toString().equals(sessionRootName)) {
+        		ret = txnOpenIcon;
+        	} else if (m_lastValue.toString().equals(channelRootName)) {
+        		ret = channelOpenIcon;
+        	} else if (m_lastValue.toString().equals(issuesRootName)) {
+        		ret = issuesOpenIcon;
+        	}
+        	
+        	logger.info("Returning open icon for "+m_lastValue);
+        	return(ret);
+        }
+
+        public Icon getClosedIcon() {
+        	Icon ret=super.getClosedIcon();
+
+        	if (m_lastValue.toString().equals(sessionRootName)) {
+        		ret = txnClosedIcon;
+        	} else if (m_lastValue.toString().equals(channelRootName)) {
+        		ret = channelClosedIcon;
+        	} else if (m_lastValue.toString().equals(issuesRootName)) {
+        		ret = issuesClosedIcon;
+        	}
+        	
+        	logger.info("Returning closed icon for "+m_lastValue);
+        	return(ret);
+        }
+
+        public Icon getLeafIcon() {
+        	Icon ret=super.getLeafIcon();
+
+        	if (m_lastValue instanceof ProxyTreeNode) {
+        		if (((ProxyTreeNode)m_lastValue).getObject() instanceof CorrelationSession) {
+        			ret = txnLeafIcon;
+        		} else if (((ProxyTreeNode)m_lastValue).getObject()
+        					instanceof org.pi4soa.cdl.ChannelType) {
+        			ret = channelLeafIcon;
+        		}
+        	} else if (m_lastValue.toString().equals(sessionRootName)) {
+        		ret = txnEmptyIcon;
+        	} else if (m_lastValue.toString().equals(channelRootName)) {
+        		ret = channelEmptyIcon;
+        	} else if (m_lastValue.toString().equals(unexpectedMessagesRootName)) {
+        		ret = unexpectedLeafIcon;
+        	} else if (m_lastValue.toString().equals(errorsRootName)) {
+        		ret = errorsLeafIcon;
+        	} else if (m_lastValue.toString().equals(warningsRootName)) {
+        		ret = warningsLeafIcon;
+        	}
+        	logger.info("Returning leaf icon for "+m_lastValue+" of type "+m_lastValue.getClass());
+        	return(ret);
+        }
+        
+        private Object m_lastValue=null;
+    }
+    
+}
+

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ExchangeEventWrapper.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ExchangeEventWrapper.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ExchangeEventWrapper.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,797 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui;
+
+import org.pi4soa.monitor.ExchangeEvent; 
+
+import org.pi4soa.cdl.Interaction;
+import org.pi4soa.cdl.RoleType;
+import org.pi4soa.cdl.Variable;
+
+import org.pi4soa.service.Message;
+import org.pi4soa.service.Identity;
+
+import org.pi4soa.service.correlator.CorrelationSession;
+
+import java.io.Serializable;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.util.logging.Logger;
+
+
+
+/**
+ *
+ */
+public class ExchangeEventWrapper implements Serializable{
+	
+    Integer index = null;
+
+    String realSessionName = null;
+    String sessionName = null;
+    String description = null;
+    String toRoleTypeName = null;
+    String fromRoleTypeName = null;
+    String serviceName=null;
+    String sendVariableString = null;
+    String sendVariableTypeString = null;
+    String messageTypeString = "";
+    String messageTypeNoNamespaceString = "";
+    String operationString = null;
+    String messageValueString = null;
+    String exceptionValueString = null;
+    String messageIdentityString = null;
+    String channelType = null;
+    String correlationSessionString = null;
+
+    // don't serialize this one ...
+    transient private ExchangeEvent exchangeEvent = null;
+
+    String status = null;
+    boolean hasFrozenStatus = false;
+
+    boolean hasSetErrorsAndWarnings = false;
+    boolean isError = false;
+    boolean isWarning = false;
+    
+    boolean isErrorMessage=false;
+    boolean isWarningMessage=false;
+    boolean isInformationMessage=false;
+
+    boolean isFault = false;
+    boolean hasSetIsFault = false;
+
+    boolean isRequest;
+    
+    boolean isUnexpected = false;
+    
+    private static Logger logger = Logger.getLogger("org.pi4soa.monitor.ui");
+
+    public ExchangeEventWrapper(CorrelationSession session,
+    		Integer index, String mesgValue, String exception){
+        this.index = index;
+
+        correlationSessionString = (session == null?
+    			"<unknown>":session.toString());
+        
+        setMessageValue(mesgValue);
+        
+        if (messageValueString == null) {
+        	messageValueString = "";
+        }
+        
+       	exceptionValueString = exception;
+        
+        messageIdentityString = "";
+        operationString = "";
+        description = "";
+        sendVariableString="";
+
+        setRealSessionName(session);
+        setSessionName(session);
+    }
+    
+    /**
+     *
+     */
+    public ExchangeEventWrapper(ExchangeEvent event, Integer index){
+        this.index = index;
+        this.exchangeEvent = event;
+
+        correlationSessionString = (event.getCorrelationSession() == null?
+        			"<unknown>":event.getCorrelationSession().toString());
+
+        Message message = exchangeEvent.getMessage();
+        if(message != null){
+        	
+        	if (exchangeEvent.getExchange() != null) {
+        		isRequest = (exchangeEvent.getExchange().getAction()
+        					== org.pi4soa.cdl.ExchangeActionType.REQUEST);
+        	} else {
+        		isRequest = message.isRequest();
+        	}
+            
+            messageTypeString = message.getType();
+            
+            messageTypeNoNamespaceString = 
+            	org.pi4soa.common.xml.NameSpaceUtil.getLocalPart(message.getType());
+
+        }
+        else{
+            logger.fine(">>>> Null message");
+            isRequest = true;
+        }
+
+        setRealSessionName(event.getCorrelationSession());
+        setSessionName(event.getCorrelationSession());
+        setDescription(event);
+        setFromRoleTypeName(event);
+        setToRoleTypeName(event);
+        setSendVariableName(event);
+        setSendVariableTypeName(event);
+        setOperationString(event);
+        setMessageValue(event);
+        setMessageIdentity(event);
+        setChannelType(event);
+    }
+
+    /**
+     *
+     */
+    public Integer getIndex(){ return index; }
+
+
+    /**
+     * 
+     */
+    public String getRealSessionName() { return realSessionName; }
+    public String getSessionName() { return sessionName; }
+    
+    /**
+     * 
+     */
+    public void setRealSessionName(CorrelationSession s){
+    	
+    	if (s == null) {
+    		realSessionName = "Session:unknown";
+    	} else {
+    		realSessionName = "Session:" + s.toString().substring(s.getClass().getName().length());
+    	}
+    	
+    	logger.fine("Set real session name in wrapper: " + realSessionName);
+    }
+    
+    public void setSessionName(CorrelationSession s){
+    	
+    	if (s == null) {
+    		sessionName = "unknown";
+    	} else {
+    		sessionName = ChannelJPanel.getSessionIdentity(s);
+    	}
+    	
+    	logger.fine("Set session name alias in wrapper: " + sessionName);
+    }
+    /**
+     *
+     */
+    public String getDescription(){ return description; }
+
+    /**
+     *
+     */
+    protected void setDescription(ExchangeEvent exchangeEvent){
+        if(exchangeEvent == null || exchangeEvent.getExchange() == null){
+            description = "null exchange";
+        }
+        else{
+            description = exchangeEvent.getExchange().getDescription();
+            if(description != null){
+                String newDescription = description.replaceAll("\\s+", " ");
+                description = newDescription;
+            }
+            else{
+                description = "";
+            }
+        }
+    }
+
+
+    /**
+     *
+     */
+    public String getStatus(){
+        String returnValue = null;
+        if(hasFrozenStatus == true){
+            returnValue = status;
+        } else {
+        	if (exchangeEvent == null) {
+        		returnValue = "";
+        	} else if (exchangeEvent.getChannel() == null) {
+        		returnValue = "Unexpected";
+        	} else if(exchangeEvent.isExchangeComplete()) {
+                returnValue = "Completed";
+            } else{
+                returnValue = "Initiated";
+            }
+        }
+
+        return returnValue;
+    }
+
+
+    /**
+     *
+     */
+    public void freezeStatus(){
+        status = getStatus();
+        hasFrozenStatus = true;
+    }
+
+
+    /**
+     *
+     */
+    public boolean equals(Object object){
+        boolean result = false;
+
+        if (object != null && object instanceof ExchangeEventWrapper) {
+            ExchangeEventWrapper other = (ExchangeEventWrapper) object;
+            if(other.exchangeEvent != null && this.exchangeEvent != null){
+                if(other.exchangeEvent.equals(this.exchangeEvent)){
+                    result = true;
+                }
+            }
+            else{
+                result = other.getDescription().equals(this.getDescription()) &&
+                    other.getFromRoleTypeName().equals(this.getFromRoleTypeName()) &&
+                    other.getToRoleTypeName().equals(this.getToRoleTypeName()) &&
+                    other.getSendVariableName().equals(this.getSendVariableName()) &&
+                    other.getOperationString().equals(this.getOperationString()) &&
+                    other.getMessageValue().equals(this.getMessageValue()) &&
+                    other.getMessageIdentity().equals(this.getMessageIdentity()) &&
+                    other.getChannelType().equals(this.getChannelType());
+            }
+
+        }
+
+        return result;
+    }
+
+
+
+    /**
+     *
+     */
+    public String getFromRoleTypeName(){
+    	if (exchangeEvent == null || exchangeEvent.getChannel() == null)
+    	{
+    		return(""); // "Unknown From Role";
+    	}
+        if(isRequest){
+            return fromRoleTypeName;
+        }
+        else{
+            return toRoleTypeName;
+        }
+    }
+
+
+    /**
+     *
+     */
+    protected void setFromRoleTypeName(ExchangeEvent exchangeEvent){
+        if(exchangeEvent.getExchange() == null){
+            fromRoleTypeName = ""; //"Unknown From Role";
+        }
+        else{
+            Interaction interaction = exchangeEvent.getExchange().getInteraction();
+            if(interaction != null){
+                RoleType fromRoleType = interaction.getFromRoleType();
+                if(fromRoleType != null){
+                    fromRoleTypeName = fromRoleType.getName() != null ? fromRoleType.getName() : "";
+                }
+                else{
+                    fromRoleTypeName = ""; //"null fromRoleType";
+                }
+            }
+            else{
+                fromRoleTypeName = ""; //"null interaction";
+            }
+        }
+    }
+    
+    protected void setServiceName(String name) {
+    	serviceName = name;
+    }
+    
+    public String getServiceName() { return serviceName; }
+
+    /**
+     *
+     */
+    public String getToRoleTypeName(){
+    	if (exchangeEvent == null || exchangeEvent.getChannel() == null)
+    	{
+    		return(""); // "Unknown To Role";
+    	}
+        if(isRequest){
+            return toRoleTypeName;
+        }
+        else{
+            return fromRoleTypeName;
+        }
+    }
+
+
+    /**
+     *
+     */
+    protected void setToRoleTypeName(ExchangeEvent exchangeEvent){
+        if(exchangeEvent == null || exchangeEvent.getExchange() == null){
+            toRoleTypeName = ""; //"Unknown To Role";
+        }
+        else{
+            Interaction interaction = exchangeEvent.getExchange().getInteraction();
+            if(interaction != null){
+                RoleType toRoleType = interaction.getToRoleType();
+                if(toRoleType != null){
+                    toRoleTypeName = toRoleType.getName() != null ? toRoleType.getName() : "";
+                }
+                else{
+                    toRoleTypeName = ""; //"null toRoleType";
+                }
+            }
+            else{
+                toRoleTypeName = ""; //"null interaction";
+            }
+        }
+    }
+
+
+    /**
+     *
+     */
+    public String getSendVariableName(){ return sendVariableString; }
+    public String getSendVariableTypeName() { return sendVariableTypeString; }
+
+    /**
+     * 
+     */
+    protected void setSendVariableTypeName(ExchangeEvent exchangeEvent)
+    {
+        if(exchangeEvent.getExchange() == null){
+        	if (exchangeEvent.getMessage().getType() != null) {
+        		String tmp = exchangeEvent.getMessage().getType();
+        		sendVariableTypeString = tmp.substring(tmp.indexOf("}")+1);
+        		// Need to abberivate after the last "{"
+        	} else {
+        		sendVariableTypeString = "Unknown type";
+        	}
+        }
+        else{
+            Variable sendVariable = exchangeEvent.getExchange().getSendVariable();
+            if(sendVariable != null){
+            	//sendVariableString = sendVariable.getName() != null ? sendVariable.getName()  : "Type: " + sendVariable.getType().getName();
+                sendVariableTypeString = sendVariable.getType().getName();
+            }
+        }
+    }
+    /**
+     *
+     */
+    protected void setSendVariableName(ExchangeEvent exchangeEvent){
+        if(exchangeEvent.getExchange() == null){
+        	if (exchangeEvent.getMessage().getType() != null) {
+        		String tmp = exchangeEvent.getMessage().getType();
+        		sendVariableString = "None : " + tmp.substring(tmp.indexOf("}")+1);
+        		// Need to abberivate after the last "{"
+        	} else
+        		sendVariableString = "null exchange";
+        }
+        else{
+            Variable sendVariable = exchangeEvent.getExchange().getSendVariable();
+            if(sendVariable != null){
+            	//sendVariableString = sendVariable.getName() != null ? sendVariable.getName()  : "Type: " + sendVariable.getType().getName();
+                sendVariableString = sendVariable.getName() != null ? sendVariable.getName()  : " : " + sendVariable.getType().getName();
+            }
+            else{
+            	sendVariableString = "None : " + exchangeEvent.getExchange().getType().getName();
+                //sendVariableString = "null sendVariable";
+            }
+        }
+    }
+
+
+    /**
+     *
+     */
+    public String getOperationString(){ return operationString; }
+
+
+
+    /**
+     *
+     */
+    protected void setOperationString(ExchangeEvent exchangeEvent){
+        if(exchangeEvent.getExchange() == null){
+        	operationString = ""; //"Unknown Operation";
+        }
+        Message message = exchangeEvent.getMessage();
+        if(message == null){
+            operationString = ""; //"null message";
+        }
+        else{
+            operationString = message.getOperationName();
+            if(operationString == null){
+                operationString = ""; //"null operation";
+            }
+        }
+    }
+
+    public String getMessageSummary() {
+    	String ret="";
+    	
+    	if (exchangeEvent != null) {
+	    	String op=getOperationString();
+	    	if (op != null && op.trim().length() > 0) {
+	    		ret += op+"(";
+	        }
+	
+	    	ret += getMessageTypeNoNamespace();
+	    	if (op != null && op.trim().length() > 0) {
+	    		ret += ")";
+	    	}
+    	} else {
+    		ret = getMessageValue();
+    	}
+    	
+    	if (ret != null && ret.length() > 0 &&
+    			ret.charAt(0) == '<') {
+    		ret = getChannelType()+" ...";
+    	}
+    	
+    	return(ret);
+    }
+
+    /**
+     *
+     */
+    public String getMessageValue(){ return messageValueString; }
+
+    public String getExceptionValue() { return exceptionValueString; }
+
+    /**
+     *
+     */
+    protected void setMessageValue(ExchangeEvent exchangeEvent){
+        logger.fine("**** Setting message value");
+        messageValueString = "";
+        Message message = exchangeEvent.getMessage();
+        if(message == null){
+            logger.fine("**** null message");
+            messageValueString = "null message";
+        }
+        else{
+            Serializable messageValue = message.getValue();
+            if(messageValue == null){
+                messageValueString = "null message value";
+                logger.fine("**** null message value");
+            }
+            else{
+                setMessageValue(messageValue.toString());
+            }
+        }
+    }
+    
+    protected void setMessageValue(String originalMessageValueString) {
+        logger.fine("**** original message = " + originalMessageValueString);
+
+        logger.fine("**** prettifying");
+
+        messageValueString = XmlPrettyPrinter.prettify(originalMessageValueString);
+
+        logger.fine("**** prettified");
+
+        logger.fine(messageValueString);
+
+        if(messageValueString == null) {
+
+            logger.fine("**** prettified string was null");
+
+            // messageValueString = originalMessageValueString;
+            //                        messageValueString = "prettyprinting failed";
+            messageValueString = originalMessageValueString.replaceAll("[ \\t]+", " ");
+
+            logger.fine("**** reprettified");
+            logger.fine(messageValueString);
+        }
+    }
+
+
+    /**
+     *
+     */
+    public String getMessageIdentity(){ return messageIdentityString; }
+
+    public String getMessageType() { return messageTypeString; }
+    
+    public String getMessageTypeNoNamespace() { return messageTypeNoNamespaceString; }
+
+    /**
+     *
+     */
+    protected void setMessageIdentity(ExchangeEvent exchangeEvent){
+        Message message = exchangeEvent.getMessage();
+        if(message == null){
+            messageIdentityString = "null message";
+        }
+        else{
+        	java.util.List<Identity> messageIdentityArray=message.getMessageIdentities();
+            if(messageIdentityArray == null || messageIdentityArray.size() == 0){
+                messageIdentityString = "no identities";
+            }
+            else{
+                Identity firstMessageIdentity = messageIdentityArray.get(0);
+                //                    messageIdentityString = firstMessageIdentity.toText();
+                String tokens[] = firstMessageIdentity.getTokens();
+                // valu
+                Object values_obj[] = firstMessageIdentity.getValues();
+                
+                String[] values = new String[values_obj.length];
+                
+                for (int values_index=0; values_index < values_obj.length; values_index++)
+                {
+                	values[values_index] = values_obj[values_index].toString();
+                }
+
+                if(tokens == null || values == null){
+                    if(tokens == null){
+                        logger.fine("identity.getTokens() returned null");
+                        //                        messageIdentityString = "null tokens";
+                    }
+
+                    if(values == null){
+                        logger.fine("identity.getValues() returned null");
+                        //                        messageIdentityString = "null values";
+                    }
+
+                    messageIdentityString = firstMessageIdentity.toString();
+                }
+                else{
+                    if(tokens != null && values != null && tokens.length == values.length){
+                        messageIdentityString = "";
+                        for(int i = 0; i < tokens.length - 1; i++){
+                            messageIdentityString += values[i] + " (" + tokens[i] + "), ";
+                        }
+                        messageIdentityString += values[tokens.length - 1] + " (" + tokens[tokens.length - 1]+")";
+                    }
+                    else{
+                        messageIdentityString = "tokens/values mismatch";
+                    }
+                }
+            }
+        }
+    }
+    
+    public void setMessageIdentity(String ident)
+    {
+    	messageIdentityString = ident;
+    }
+
+
+    /**
+     *
+     */
+    public boolean isFault(){
+        if(hasSetIsFault == false){
+            if(exchangeEvent != null && exchangeEvent.getExchange() != null){
+                isFault = exchangeEvent.getExchange().isFault();
+            }
+            //else{
+            //    isFault = true;
+            //}
+            hasSetIsFault = true;
+        }
+        return isFault;
+    }
+
+
+    /**
+     *
+     */
+    private void setErrorsAndWarnings(){
+        if(hasSetErrorsAndWarnings == false){
+            if(getToRoleTypeName().toLowerCase().matches("exception")){
+                if(getOperationString().toLowerCase().matches("fatal")){
+                    isError = true;
+                }
+                else{
+                    isWarning = true;
+                }
+            }
+            else if(getFromRoleTypeName().toLowerCase().matches("exception")){
+                if(isFault()){
+                    isError = true;
+                }
+            }
+            else{
+                if(exchangeEvent != null && exchangeEvent.getExchange() == null){
+                	isUnexpected = true;
+                }
+                else if(isFault()){
+                    isWarning = true;
+                }
+
+                // if the session was terminated early. color me red.
+            }
+            hasSetErrorsAndWarnings = true;
+        }
+    }
+
+    public void setErrorMessage(boolean b) {
+    	isErrorMessage = b;
+    	
+    	if (b) {
+    		channelType = ChannelJPanel.getErrorName();
+    	}
+    }
+    
+    public boolean isErrorMessage() {
+    	return(isErrorMessage);
+    }
+
+    public void setWarningMessage(boolean b) {
+    	isWarningMessage = b;
+    	
+    	if (b) {
+    		channelType = ChannelJPanel.getWarningName();
+    	}
+    }
+    
+    public boolean isWarningMessage() {
+    	return(isWarningMessage);
+    }
+
+    public void setInformationMessage(boolean b) {
+    	isInformationMessage = b;
+    	
+    	if (b) {
+    		channelType = ChannelJPanel.getInformationName();
+    	}
+    }
+    
+    public boolean isInformationMessage() {
+    	return(isInformationMessage);
+    }
+
+    /**
+     *
+     */
+    public boolean isError(){
+        if(hasSetErrorsAndWarnings == false){
+            setErrorsAndWarnings();
+        }
+        return(isError || isErrorMessage());
+    }
+
+    public boolean isUnexpected(){
+    	return isUnexpected;
+    }
+    
+    public void setUnexpected(boolean b){
+    	isUnexpected = b;
+    }
+
+    /**
+     *
+     */
+    public boolean isWarning(){
+        if(hasSetErrorsAndWarnings == false){
+            setErrorsAndWarnings();
+        }
+        return(isWarning || isWarningMessage());
+    }
+
+
+    /**
+     *
+     */
+    public String getChannelType(){ return channelType; }
+
+    protected void setChannelType(String ctype) {
+    	channelType = ctype;
+    }
+    
+    /**
+     *
+     */
+    public String getCorrelationSession(){ return correlationSessionString; }
+
+    /**
+     *
+     */
+    public String toString()
+    {
+        String s = "EXCHANGE EVENT WRAPPER: " +
+				"<sessionName = " + sessionName + ">" +
+				"<realSessionName = " + realSessionName + ">" +
+				"<serviceName = " + serviceName + ">" +
+				"<description = " + description + ">" +
+				"<toRoleTypeName = " + toRoleTypeName + ">" +
+				"<fromRoleTypeName = " + fromRoleTypeName + ">" +
+				"<sendVariableString = " + sendVariableString + ">" +
+				"<operationString = " + operationString + ">" +
+				"<messageValueString = " + messageValueString + ">" +
+				"<messageIdentityString = " + messageIdentityString + ">" +
+				"<channelType = " + channelType + ">" +
+				"<correlationSessionString = " + correlationSessionString + ">" +
+				"<status = " + status + ">" +
+				"<hasFrozenStatus = " + hasFrozenStatus + ">" +
+				"<hasSetErrorsAndWarnings = " + hasSetErrorsAndWarnings + ">" +
+				"<isError = " + isError + ">" +
+				"<isWarning = " + isWarning + ">" +
+				"<isFault = " + isFault + ">" +
+				"<hasSetIsFault = " + hasSetIsFault + ">" +
+				"<isRequest = " + isRequest + ">" +
+				"<isUnexpected = " + isUnexpected + ">";
+        
+        return s;
+    }
+    /**
+     * 
+     */
+    
+    protected void setChannelType(ExchangeEvent exchangeEvent){
+        if(exchangeEvent.getChannel() == null){
+            channelType = ChannelJPanel.getUnexpectedMessagesName();
+        }
+        else{
+            channelType = exchangeEvent.getExchange().getInteraction().getChannelVariable().getType().getName(); // Not getType
+        	logger.fine("Channel type name: " + channelType);
+        	logger.fine("Channel service type name: " + exchangeEvent.getChannel().getServiceType());
+        	logger.fine("Channel instance name: " + exchangeEvent.getChannel().getName());
+        	logger.fine("OR Channel instance name: " + exchangeEvent.getExchange().getInteraction().getChannelVariable().getType().getName());
+        }
+    }
+
+    // Serialization support
+
+
+    /**
+     *
+     */
+    private void writeObject(ObjectOutputStream out) throws IOException{
+        // to make sure that this has been set.
+        boolean myIsError = this.isError();
+        boolean myIsFault = this.isFault();
+        freezeStatus();
+        out.defaultWriteObject();
+    }
+
+
+    /**
+     *
+     */
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
+        in.defaultReadObject();
+    }
+
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ExchangeEventsData.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ExchangeEventsData.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/ExchangeEventsData.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,449 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui;
+
+import java.util.Vector;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.logging.Logger;
+
+import java.io.FileOutputStream;
+import java.io.ObjectOutputStream;
+
+import java.io.FileInputStream;
+import java.io.ObjectInputStream;
+
+
+import org.pi4soa.monitor.ExchangeEvent;
+import org.pi4soa.service.correlator.CorrelationSession;
+
+/**
+ *
+ */
+public class ExchangeEventsData{
+
+	private static Logger logger = Logger.getLogger("org.pi4soa.monitor.ui");
+	
+    Vector exchangeEvents = null;
+
+    Vector warningAndErrorExchangeEvents = null;
+
+    Vector errorExchangeEvents = null;
+
+    Vector warningExchangeEvents = null;
+    
+    Vector unexpectedExchangeEvents = null;
+
+    Hashtable exchangeEventsByChannelTable = null;
+    
+    Hashtable exchangeEventsBySessionTable = null;
+
+    Hashtable sessionHasErrorsTable = null;
+    Hashtable sessionHasWarningsTable = null;    
+    Hashtable sessionHasUnexpectedMessagesTable = null;
+    Hashtable channelHasErrorsTable = null;
+    Hashtable channelHasWarningsTable = null;    
+    Hashtable channelHasUnexpectedMessagesTable = null;
+
+    Hashtable exchangeEventToWrapperMap = null;
+
+    boolean hasErrors = false;
+
+    boolean hasWarnings = false;
+    
+    boolean hasUnexpectedMessages = false;
+
+    /**
+     *
+     */
+    public ExchangeEventsData(){
+        exchangeEvents = new Vector();
+        warningAndErrorExchangeEvents = new Vector();
+        errorExchangeEvents = new Vector();
+        warningExchangeEvents = new Vector();
+        unexpectedExchangeEvents = new Vector();
+        exchangeEventsByChannelTable = new Hashtable();
+        exchangeEventsBySessionTable = new Hashtable();
+        exchangeEventToWrapperMap = new Hashtable();
+        channelHasErrorsTable = new Hashtable();
+        channelHasUnexpectedMessagesTable = new Hashtable();
+        channelHasWarningsTable = new Hashtable();
+        sessionHasErrorsTable = new Hashtable();
+        sessionHasUnexpectedMessagesTable = new Hashtable();
+        sessionHasWarningsTable = new Hashtable();
+    }
+
+
+
+    /**
+     *
+     */
+    public void clear(){
+        exchangeEvents.clear();
+        exchangeEventsByChannelTable.clear();
+        exchangeEventsBySessionTable.clear();
+        exchangeEventToWrapperMap.clear();
+        warningAndErrorExchangeEvents.clear();
+        errorExchangeEvents.clear();
+        warningExchangeEvents.clear();
+        unexpectedExchangeEvents.clear();
+        channelHasErrorsTable.clear();
+        channelHasWarningsTable.clear();
+        channelHasUnexpectedMessagesTable.clear();
+        sessionHasErrorsTable.clear();
+        sessionHasWarningsTable.clear();
+        sessionHasUnexpectedMessagesTable.clear();
+        hasErrors = false;
+        hasWarnings = false;
+    }
+
+
+    /**
+     *
+     */
+    public boolean exportEvents(String path){
+        try{
+            FileOutputStream fileOutputStream = new FileOutputStream(path);
+            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
+            objectOutputStream.writeObject(exchangeEvents);
+            objectOutputStream.close();
+        }
+        catch(Exception e){
+            logger.severe("Exception: " + e);
+            return false;
+        }
+
+        return true;
+    }
+
+
+
+    /**
+     *
+     */
+    public boolean importEvents(String path){
+        clear();
+
+        Vector v = null;
+
+        try{
+            FileInputStream fileInputStream = new FileInputStream(path);
+            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
+            v = (Vector) objectInputStream.readObject();
+            objectInputStream.close();
+        }
+        catch(Exception e){
+            logger.severe("Exception: " + e);
+            return false;
+        }
+
+        Iterator iterator = v.iterator();
+        int i = 0;
+        while(iterator.hasNext()){
+            ExchangeEventWrapper wrapper = (ExchangeEventWrapper) iterator.next();
+
+            logger.fine("Getting wrapper message value");
+
+            String wrapperMessageValue = wrapper.getMessageValue();
+
+            logger.fine("Imported event wrapper message value = " + wrapperMessageValue);
+
+            Integer key = new Integer(i);
+            i++;
+            exchangeEventToWrapperMap.put(key, wrapper);
+            addExchangeEvent(wrapper);
+        }
+
+        return true;
+    }
+
+
+
+
+    /**
+     *
+     */
+    public ExchangeEventWrapper createExchangeEventWrapper(ExchangeEvent exchangeEvent){
+        ExchangeEventWrapper wrapper=null;
+        
+        logger.fine(">>>> creating new wrapper");
+        wrapper = new ExchangeEventWrapper(exchangeEvent, new Integer(exchangeEvents.size()));
+        logger.fine(">>>> created new wrapper");
+    	
+        java.util.List list=(java.util.List)
+        		exchangeEventToWrapperMap.get(exchangeEvent);
+        	
+        if (list == null) {
+        	list = new java.util.Vector();
+        	exchangeEventToWrapperMap.put(exchangeEvent, list);
+    		logger.fine("Added new list for map entry: "+exchangeEvent);
+        }
+        
+        list.add(wrapper);
+    	
+        return wrapper;
+    }
+
+    public ExchangeEventWrapper matchExchangeEventWrapper(ExchangeEvent exchangeEvent){
+    	logger.info("getExchangeEventWrapper for " + exchangeEvent);
+        logger.fine(">>>> looking for pre-existing wrapper for " + exchangeEvent);
+        
+        java.util.List list=
+        	(java.util.List)exchangeEventToWrapperMap.get(exchangeEvent);
+ 
+        ExchangeEventWrapper wrapper=null;
+        
+        if (list != null && list.size() > 0) {
+        	wrapper = (ExchangeEventWrapper)list.remove(0);
+        	
+        	if (list.size() == 0) {
+        		exchangeEventToWrapperMap.remove(exchangeEvent);
+        		
+        		logger.fine("Cleaned up map entry for: "+exchangeEvent);
+        	}
+        }
+        
+        if(wrapper == null){
+            logger.severe(">>>> Failed to find existing wrapper: "+exchangeEvent);
+        }
+        else{
+            logger.fine(">>>> found old wrapper");
+            
+            // Remove from map
+            exchangeEventToWrapperMap.remove(exchangeEvent);
+        }
+        
+        return wrapper;
+    }
+
+    public ExchangeEventWrapper errorExchangeEventWrapper(ExchangeEvent exchangeEvent){
+        ExchangeEventWrapper wrapper=null;
+        
+        logger.fine(">>>> creating new error wrapper");
+        wrapper = new ExchangeEventWrapper(exchangeEvent, new Integer(exchangeEvents.size()));
+        logger.fine(">>>> created new error wrapper");
+    	
+        return wrapper;
+    }
+
+    public ExchangeEventWrapper simpleWrapper(CorrelationSession session,
+    			String text, String exception) {
+        ExchangeEventWrapper wrapper=null;
+        
+        logger.fine(">>>> creating new empty wrapper");
+        wrapper = new ExchangeEventWrapper(session,
+        		new Integer(exchangeEvents.size()), text, exception);
+        logger.fine(">>>> created new empty wrapper");
+    	
+        return wrapper;
+    }
+
+    /**
+     *
+     */
+    public void addExchangeEvent(ExchangeEventWrapper wrapper){
+
+        String channelType = wrapper.getChannelType();
+        String sessionName = wrapper.getSessionName();   
+        
+        Vector exchangeEventsByChannel = (Vector) exchangeEventsByChannelTable.get(channelType);
+        Vector exchangeEventsBySession = (Vector) exchangeEventsBySessionTable.get(sessionName);
+
+
+        if(exchangeEventsByChannel == null){
+            exchangeEventsByChannel = new Vector();
+        }
+        logger.info("addExchangeEvent for CHANNEL TYPE: " + channelType);
+        exchangeEventsByChannel.add(wrapper);
+
+        if (exchangeEventsBySession == null){
+        	exchangeEventsBySession = new Vector();
+        }
+        logger.info("addExchangeEvent for SESSION: " + sessionName);
+        exchangeEventsBySession.add(wrapper);
+        
+        // is this necessary if we already had an entry?
+        exchangeEventsByChannelTable.put(channelType, exchangeEventsByChannel);
+        exchangeEventsBySessionTable.put(sessionName, exchangeEventsBySession);
+        
+        exchangeEvents.add(wrapper);
+
+        logger.fine(">>>> added to exchange events list. size = " + exchangeEvents.size());
+
+        // OLD fault handling.
+        //        if(wrapper.isFault() == true){
+        //            channelHasErrorsTable.put(channelType, new Boolean(true));
+        //            hasErrors = true;
+        //        }
+
+        // NEW fault handling.
+logger.warning("Checking if error....");        
+        if(wrapper.isWarning() == true || wrapper.isError() == true || wrapper.isUnexpected() == true){
+            //            channelHasErrorsTable.put(channelType, new Boolean(true));
+            //            hasErrors = true;
+
+            warningAndErrorExchangeEvents.add(wrapper);
+
+        	if (wrapper.isError() == true) {
+        		errorExchangeEvents.add(wrapper);
+logger.warning("RECORD ERROR channel="+channelType);                
+				channelHasErrorsTable.put(channelType, new Boolean(true));
+				sessionHasErrorsTable.put(sessionName, new Boolean(true));
+				hasErrors = true;
+        	} else if(wrapper.isWarning() == true){
+                warningExchangeEvents.add(wrapper);
+                channelHasWarningsTable.put(channelType, new Boolean(true));
+				sessionHasWarningsTable.put(sessionName, new Boolean(true));
+logger.warning("RECORD WARNING channel="+channelType);                
+                hasWarnings = true;
+            } else if (wrapper.isUnexpected() == true) {
+            	unexpectedExchangeEvents.add(wrapper);
+            	channelHasUnexpectedMessagesTable.put(channelType, new Boolean(true));
+				sessionHasUnexpectedMessagesTable.put(sessionName, new Boolean(true));
+            	hasUnexpectedMessages = true;
+            	logger.info("ADDED UNEXPECTED WRAPPER TO ExchangeEventData for channelType " + channelType);
+            }
+logger.warning("Checked");            
+        }
+    }
+
+
+    /**
+     *
+     */
+    public ExchangeEventWrapper getWrapper(int i){ return (ExchangeEventWrapper) exchangeEvents.elementAt(i); }
+
+
+
+    /**
+     *
+     */
+    public Vector getExchangeEventsForChannel(String channel){
+        return (Vector) exchangeEventsByChannelTable.get(channel);
+    }
+    
+    public Vector getExchangeEventsForSession(String session) {
+    	return (Vector)exchangeEventsBySessionTable.get(session);
+    }
+
+
+    /**
+     *
+     */
+    public Vector getExchangeEvents(){ return exchangeEvents; }
+
+    /**
+     *
+     */
+    public Vector getWarningAndErrorExchangeEvents(){ return warningAndErrorExchangeEvents; }
+
+    /**
+     *
+     */
+    public Vector getErrorExchangeEvents(){ return errorExchangeEvents; }
+
+    /**
+     *
+     */
+    public Vector getWarningExchangeEvents(){ return warningExchangeEvents; }
+
+    /**
+     * 
+     */
+    public Vector getUnexpectedExchangeEvents() { return unexpectedExchangeEvents; }
+
+    /**
+     * 
+     */
+    public boolean getHasUnexpectedExchangeEventsForChannel(String channel){
+        if(hasUnexpectedMessages == true){
+            Boolean hasUnexpectedMessagesForChannel = (Boolean) channelHasUnexpectedMessagesTable.get(channel);
+            if (hasUnexpectedMessagesForChannel != null) return true;
+        }
+        return false;
+    }
+
+    public boolean getHasUnexpectedExchangeEventsForSession(String session){
+        if(hasUnexpectedMessages == true){
+            Boolean hasUnexpectedMessagesForSession = (Boolean) sessionHasUnexpectedMessagesTable.get(session);
+            if (hasUnexpectedMessagesForSession != null) return true;
+        }
+        return false;
+    }
+
+    /**
+     *
+     */
+    public boolean getHasErrorsForChannel(String channel){
+        if(hasErrors == true){
+            Boolean hasErrorsForChannel = (Boolean) channelHasErrorsTable.get(channel);
+            if (hasErrorsForChannel != null) return true;
+        }
+        return false;
+    }
+
+    public boolean getHasErrorsForSession(String session){
+        if(hasErrors == true){
+            Boolean hasErrorsForSession = (Boolean) sessionHasErrorsTable.get(session);
+            if (hasErrorsForSession != null) return true;
+        }
+        return false;
+    }
+
+    /**
+     *
+     */
+    public boolean getHasWarningsForChannel(String channel){
+        if(hasWarnings == true){
+            Boolean hasWarningsForChannel = (Boolean) channelHasWarningsTable.get(channel);
+            if (hasWarningsForChannel != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public boolean getHasWarningsForSession(String session){
+        if(hasWarnings == true){
+            Boolean hasWarningsForSession = (Boolean) sessionHasWarningsTable.get(session);
+            if (hasWarningsForSession != null) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * 
+     */
+    public boolean getHasUnexpectedMessages(){ return hasUnexpectedMessages; }
+    /**
+     *
+     */
+    public boolean getHasErrors(){ return hasErrors; }
+
+
+    /**
+     *
+     */
+    public boolean getHasWarnings(){ return hasWarnings; }
+
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/Monitor.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/Monitor.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/Monitor.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,502 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui;
+
+import javax.swing.*;
+
+import java.awt.BorderLayout;
+
+import java.io.IOException;
+import java.util.logging.Logger;
+
+import org.pi4soa.service.correlator.CorrelationSession;
+import org.pi4soa.monitor.CorrelationManagerListener;
+import org.pi4soa.monitor.TxnMonitor;
+import org.pi4soa.monitor.ExchangeEvent;
+
+/**
+ * Monitor user interface class.
+ */
+public class Monitor extends JApplet implements CorrelationManagerListener /* , TreeSelectionListener */{
+
+	private static final long serialVersionUID = -4323114698930604980L;
+
+	private static Logger logger = Logger.getLogger("org.pi4soa.monitor.ui");
+    
+    static final int NEW_FRAME_WIDTH = 800;
+    static final int NEW_FRAME_HEIGHT = 600;
+
+    MonitorMainPanel smPanel = null;
+
+    String choreographyPath = null;
+
+    org.pi4soa.cdl.Package choreography = null;
+
+    TxnMonitor txnMonitor = null;
+
+    ExchangeEventsData exchangeEventsData = null;
+
+    boolean isMonitoring = false;
+    boolean choreographyProvided = false;
+
+    /**
+     * Initialisation.
+     */
+    public Monitor(boolean choreoProvided) {
+
+        exchangeEventsData = new ExchangeEventsData();
+
+        smPanel = new MonitorMainPanel(exchangeEventsData, choreoProvided);
+
+        this.getContentPane().setLayout(new BorderLayout());
+        this.getContentPane().add(smPanel, BorderLayout.CENTER);
+
+        smPanel.setApplet(this);
+    }
+
+
+    /**
+     * Initialisation.
+     */
+    public void init() {
+        // hack to get around system event queue check - which doesn't work, of course
+        this.getRootPane().putClientProperty("defeatSystemEventQueueCheck", Boolean.TRUE);
+    }
+
+
+    /**
+     * Returns info about the acceptable parameters
+     */
+    public String[][] getParameterInfo()
+    {
+        String pinfo[][] = {
+            // actual parameters might include
+            // ip address, directories, colors
+            // etc.
+
+            // properties should be used for
+            // most stuff
+
+            {"parameter1", "String", "A String."},
+            {"parameter2", "String",    "Another String."},
+            {"parameter3", "integer",    "An integer."},
+        };
+
+        return pinfo;
+    }
+
+    /**
+     *
+     */
+    public static void main(String args[]){
+        Monitor monitor = new Monitor(args.length > 0);
+        JFrame jFrame = new JFrame("Choreography Monitor");
+        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+        jFrame.getContentPane().setLayout(new BorderLayout());
+        jFrame.getContentPane().add(monitor, BorderLayout.CENTER);
+        monitor.init();
+
+        jFrame.setIconImage(MonitorMainPanel.createImageIcon("icons/monitor.png").getImage());
+        
+        jFrame.setSize(NEW_FRAME_WIDTH, NEW_FRAME_HEIGHT);
+
+        java.awt.Dimension screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
+        java.awt.Dimension frameSize = jFrame.getSize();
+        if (frameSize.height > screenSize.height) {
+          frameSize.height = screenSize.height;
+        }
+        if (frameSize.width > screenSize.width) {
+          frameSize.width = screenSize.width;
+        }
+        jFrame.setLocation( (screenSize.width - frameSize.width) / 2,
+                         (screenSize.height - frameSize.height) / 2);
+        jFrame.setVisible(true);
+        
+        if(args.length > 0){
+            if(monitor.loadChoreography(args[0])){
+                monitor.startMonitoring();
+            } else {
+            	System.exit(1);
+            }
+        }
+    }
+
+    //////////////////////////
+
+
+    /**
+     *
+     */
+    public boolean isMonitoring(){ return isMonitoring; }
+
+    public boolean isChoreographyLoaded() { return choreography!=null; }
+
+    /**
+     *
+     */
+    public void setIsMonitoring(boolean isMonitoring){ this.isMonitoring = isMonitoring; }
+
+    public void close() {
+    	this.destroy();
+    	System.exit(0);
+    }
+
+    /**
+     *
+     */
+    public boolean loadChoreography(String choreographyPath){
+
+        logger.info("Loading " + choreographyPath);
+        smPanel.setStatus("Loading " + choreographyPath);
+
+        // try and read the new one ...
+        org.pi4soa.cdl.Package newChoreography = null;
+
+        try{
+            newChoreography = org.pi4soa.cdl.CDLManager.load(choreographyPath);
+        }
+        catch(IOException e){
+            logger.severe("Exception: " + e);
+            smPanel.setStatus("Failed to load " + choreographyPath);
+
+            JOptionPane.showMessageDialog(null,
+            		"Failed to load "+choreographyPath,
+            		 "Error", JOptionPane.ERROR_MESSAGE);
+            
+            return false;
+        }
+
+        // ok, we were successful ...
+        if(this.choreographyPath != null){
+            if(this.isMonitoring() == true){
+                // stop monitoring
+            }
+
+            exchangeEventsData.clear();
+        }
+
+        this.choreographyPath = choreographyPath;
+        this.choreography = newChoreography;
+
+        // tell the panel we loaded a new choreography ...
+        smPanel.loadedChoreography(choreography);
+
+        return true;
+    }
+
+
+    /**
+     *
+     */
+    public boolean startMonitoring(){
+
+        logger.info("Starting monitoring");
+
+        if(this.isMonitoring() == true){
+            logger.info("Already monitoring");
+            return false;
+        }
+
+        if(this.choreography == null){
+            logger.info("No choreography to monitor");
+            return false;
+        }
+
+        smPanel.setStatus("Trying to monitor " + choreography.getName());
+        logger.info("Trying to monitor " + choreography.getName());
+
+        try{
+            this.txnMonitor = TxnMonitor.getInstance(choreographyPath);
+            this.txnMonitor.addCorrelationManagerListener(this);
+        }
+        catch(Exception e){
+            // hack
+            logger.severe("Exception while trying to monitor choreography " + e);
+            
+            JOptionPane.showMessageDialog(null,
+            		"Failed to initialize monitor: "+e.getLocalizedMessage(),
+            		 "Error", JOptionPane.ERROR_MESSAGE);
+        }
+
+        logger.fine("Past txnMonitor calls");
+
+        this.setIsMonitoring(true);
+
+        // tell the panel
+        smPanel.startedMonitoring();
+
+        return true;
+    }
+
+
+    /**
+     *
+     */
+    public boolean stopMonitoring(){
+        if(this.isMonitoring() == false){
+            logger.info("Not monitoring");
+            return false;
+        }
+
+        this.txnMonitor.removeCorrelationManagerListener(this);
+
+        try{
+            this.txnMonitor.unmonitor(this.choreography);
+        }
+        catch(Exception e){
+            logger.severe("Exception: " + e);
+            return false;
+        }
+
+        this.setIsMonitoring(false);
+
+        // tell the panel
+        smPanel.stoppedMonitoring();
+
+        return true;
+    }
+
+
+    /**
+     *
+     */
+    public boolean importEvents(String path){
+        boolean result = exchangeEventsData.importEvents(path);
+        smPanel.importedEvents();
+        return result;
+    }
+
+
+    /**
+     *
+     */
+    public boolean exportEvents(String path){
+        return exchangeEventsData.exportEvents(path);
+        //
+        //        try{
+        //            FileOutputStream fileOutputStream = new FileOutputStream(path);
+        //            ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
+        //            objectOutputStream.writeObject(exchangeEvents);
+        //            objectOutputStream.close();
+        //        }
+        //        catch(Exception e){
+        //            System.err.println("Exception: " + e);
+        //            return false;
+        //        }
+        //
+        //        return true;
+    }
+
+
+    // CorrelationManagerListener interface
+
+   /**
+    * This method indicates that a correlation session has
+    * started.
+    *
+    * @param session The correlation session
+    */
+    public void correlationSessionStarted(CorrelationSession session){
+        logger.info(">>>> CORRELATION SESSION STARTED: " + session );
+        
+        // TO DO: Need to add something to the sessionPanel at this point.
+        ChannelJPanel cp = smPanel.getChannelPanel();
+        cp.addedSession(session);
+    }
+
+
+    /**
+     * This method indicates that a correlation session has
+     * finished.
+     *
+     * @param session The correlation session
+     */
+    public void correlationSessionFinished(CorrelationSession session){
+        logger.info(">>>> CORRELATION SESSION FINSIHED: " + session);
+        smPanel.getChannelPanel().addedSession(session);
+        // TO DO: Need to change colour for the same session item in the session Panel
+    }
+
+
+    /**
+     * A new exchange event has been added to a correlation session.
+     *
+     * @param exchangeEvent The exchange event.
+     */
+    public void exchangeEventAdded(ExchangeEvent exchangeEvent){
+    	logger.fine(">>>> ADDING EXCHANGE EVENT" + exchangeEvent);
+        // System.err.println(">>>> Adding exchange event");
+        //        System.err.println(">>>> Getting correlation session");
+        CorrelationSession session = exchangeEvent.getCorrelationSession();
+        logger.fine("Identity for new exchange is: " + ChannelJPanel.getSessionIdentity(exchangeEvent.getCorrelationSession()));
+        //        System.err.println(">>>> Getting wrapper");
+        ExchangeEventWrapper wrapper = exchangeEventsData.createExchangeEventWrapper(exchangeEvent);
+        //        System.err.println(">>>> Adding to data");
+        exchangeEventsData.addExchangeEvent(wrapper);
+        //        System.err.println(">>>> updating smPanel");
+        smPanel.addedExchangeEvent(wrapper);
+        logger.fine(">>>> ADDED EXCHANGE EVENT FOR SESSION: " + session);
+    }
+
+
+    /**
+     * An exchange event has been updated.
+     *
+     * @param exchangeEvent The exchange event.
+     */
+    public void exchangeEventUpdated(ExchangeEvent exchangeEvent){
+        ExchangeEventWrapper wrapper = exchangeEventsData.matchExchangeEventWrapper(exchangeEvent);
+        logger.fine("Identity for updated exchange is: " + ChannelJPanel.getSessionIdentity(exchangeEvent.getCorrelationSession()));
+        smPanel.updatedExchangeEvent(wrapper);
+    }
+    
+    /**
+     * An unexpcted exchange event has occured
+     * 
+     * @param exchangeEvent. The exchange event.
+     * @param serviceName The service reporting the error
+     */
+    public void unexpectedExchangeEventAdded(ExchangeEvent exchangeEvent,
+    						String serviceName)
+    {
+    	logger.info(">>>> unexpectedExchangeEventAdded");
+    	
+    	//CorrelationSession session = exchangeEvent.getCorrelationSession();
+    	String ident = null;
+    	
+    	if (exchangeEvent.getCorrelationSession() != null) {
+    		ident = ChannelJPanel.getSessionIdentity(exchangeEvent.getCorrelationSession());
+    	}
+    	
+    	logger.info("Identity for unexpected is: " + ident);
+        ExchangeEventWrapper wrapper = exchangeEventsData.errorExchangeEventWrapper(exchangeEvent);
+        wrapper.setUnexpected(true);
+        wrapper.setMessageIdentity(ident);
+        wrapper.setServiceName(serviceName);
+        exchangeEventsData.addExchangeEvent(wrapper);
+        smPanel.addedUnexpectedExchangeEvent(wrapper);
+        
+    	logger.fine("<<<< unexpectedExchangeEventAdded");
+    }
+    
+    /**
+     * An error occurred related to the specified correlation
+     * session.
+     * 
+     * @param session The correlation session
+     * @param mesg The error message
+     * @param exception The optional exception
+     * @param serviceName The service reporting the error
+     */
+    public void error(CorrelationSession session, String mesg,
+    					String exception, String serviceName) {
+    	logger.info(">>>> error");
+    	
+    	//CorrelationSession session = exchangeEvent.getCorrelationSession();
+    	String ident = null;
+    	
+    	if (session != null) {
+    		ident = ChannelJPanel.getSessionIdentity(session);
+    	}
+    	
+    	logger.info("Identity for unexpected is: " + ident);
+        ExchangeEventWrapper wrapper =
+        		exchangeEventsData.simpleWrapper(session, mesg,
+        					exception);
+        wrapper.setErrorMessage(true);
+        wrapper.setMessageIdentity(ident);
+        wrapper.setChannelType(ChannelJPanel.getErrorName());
+        wrapper.setServiceName(serviceName);
+        exchangeEventsData.addExchangeEvent(wrapper);
+        smPanel.addedErrorEvent(wrapper);
+        
+    	logger.fine("<<<< error");
+    }
+    
+    /**
+     * A warning occurred related to the specified correlation
+     * session.
+     * 
+     * @param session The correlation session
+     * @param mesg The warning message
+     * @param exception The optional exception
+     * @param serviceName The service reporting the warning
+     */
+    public void warning(CorrelationSession session, String mesg,
+    				String exception, String serviceName) {
+    	logger.info(">>>> warning");
+    	
+    	//CorrelationSession session = exchangeEvent.getCorrelationSession();
+    	String ident = null;
+    	
+    	if (session != null) {
+    		ident = ChannelJPanel.getSessionIdentity(session);
+    	}
+    	
+    	logger.info("Identity for unexpected is: " + ident);
+        ExchangeEventWrapper wrapper =
+        		exchangeEventsData.simpleWrapper(session, mesg,
+        					exception);
+        wrapper.setWarningMessage(true);
+        wrapper.setMessageIdentity(ident);
+        wrapper.setChannelType(ChannelJPanel.getWarningName());
+        wrapper.setServiceName(serviceName);
+        exchangeEventsData.addExchangeEvent(wrapper);
+        smPanel.addedErrorEvent(wrapper);
+        
+    	logger.fine("<<<< warning");
+    }
+    
+    /**
+     * An information event occurred related to the specified correlation
+     * session.
+     * 
+     * @param session The correlation session
+     * @param mesg The information message
+     * @param serviceName The service reporting the information
+     */
+    public void information(CorrelationSession session, String mesg,
+    					String serviceName) {
+    	logger.info(">>>> information");
+    	
+    	//CorrelationSession session = exchangeEvent.getCorrelationSession();
+    	String ident = null;
+    	
+    	if (session != null) {
+    		ident = ChannelJPanel.getSessionIdentity(session);
+    	}
+    	
+    	logger.info("Identity for unexpected is: " + ident);
+        ExchangeEventWrapper wrapper =
+        		exchangeEventsData.simpleWrapper(session, mesg, null);
+        wrapper.setInformationMessage(true);
+        wrapper.setMessageIdentity(ident);
+        wrapper.setChannelType(ChannelJPanel.getInformationName());
+        wrapper.setServiceName(serviceName);
+        exchangeEventsData.addExchangeEvent(wrapper);
+        smPanel.addedErrorEvent(wrapper);
+        
+    	logger.fine("<<<< information");
+    }
+    
+
+} // End of Applet
+
+// EOF

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorExchangeEvent.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorExchangeEvent.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorExchangeEvent.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui;
+
+
+import java.util.Date;
+
+import org.pi4soa.cdl.ExchangeDetails;
+import org.pi4soa.service.Channel;
+import org.pi4soa.cdl.ExchangeActionType;
+
+/**
+ * Convenience class for representing an exchange, and providing
+ * convenient access to data for display.
+ */
+public class MonitorExchangeEvent {
+
+    Date initiatedDate = null;
+    Date completedDate = null;
+
+    Channel channel = null;
+    ExchangeDetails exchangeDetails = null;
+
+    /**
+     *
+     */
+    public MonitorExchangeEvent(Channel channel, ExchangeDetails exchangeDetails){
+        this.channel = channel;
+        this.exchangeDetails = exchangeDetails;
+    }
+
+    /**
+     *
+     */
+    public String getChannelName(){
+        return channel.getName();
+    }
+
+    /**
+     *
+     */
+    public String getAction(){
+        if(exchangeDetails.getAction() == ExchangeActionType.REQUEST) return "Request";
+        else return "Response";
+    }
+
+
+    /**
+     *
+     */
+    public String getName(){
+        return exchangeDetails.getName();
+    }
+
+
+    /**
+     *
+     */
+    public String getDescription(){
+        return exchangeDetails.getDescription();
+    }
+
+
+    /**
+     *
+     */
+    public Date getInitiatedDate(){
+        return initiatedDate;
+    }
+
+
+    /**
+     *
+     */
+    public Date getCompletedDate(){
+        return completedDate;
+    }
+
+
+    /**
+     *
+     */
+    public String getStatus(){
+        if(completedDate != null) return "Completed";
+        else return "Initiated";
+    }
+
+
+    /**
+     *
+     */
+    public int hashCode(){
+        return exchangeDetails.hashCode();
+    }
+    
+
+    /**
+     *
+     */
+    public boolean equals(Object object){
+        boolean result = false;
+        
+        if(object instanceof MonitorExchangeEvent){
+            MonitorExchangeEvent other = (MonitorExchangeEvent) object;
+        
+            if(other.exchangeDetails == this.exchangeDetails &&
+               other.getChannelName().equals(this.getChannelName())){
+                   /*                    other.getCorrelationSession() == m_session) { */
+                result = true;
+            }
+        }
+        
+        return result;
+    }
+
+
+} // End of class

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorFileFilter.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorFileFilter.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorFileFilter.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,253 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui;
+
+import java.io.File;
+import java.util.Hashtable;
+import java.util.Enumeration;
+import javax.swing.filechooser.*;
+
+/**
+ * A convenience implementation of FileFilter that filters out
+ * all files except for those type extensions that it knows about.
+ *
+ * Extensions are of the type ".foo", which is typically found on
+ * Windows and Unix boxes, but not on Macinthosh. Case is ignored.
+ *
+ * Example - create a new filter that filerts out all files
+ * but gif and jpg image files:
+ *
+ *     JFileChooser chooser = new JFileChooser();
+ *     ExampleFileFilter filter = new ExampleFileFilter(
+ *                   new String{"gif", "jpg"}, "JPEG & GIF Images")
+ *     chooser.addChoosableFileFilter(filter);
+ *     chooser.showOpenDialog(this);
+ *
+ * @version 1.9 04/23/99
+ * @author Jeff Dinkins
+ */
+public class MonitorFileFilter extends FileFilter {
+
+    //private static String TYPE_UNKNOWN = "Type Unknown";
+    //private static String HIDDEN_FILE = "Hidden File";
+
+    private Hashtable filters = null;
+    private String description = null;
+    private String fullDescription = null;
+    private boolean useExtensionsInDescription = true;
+
+    /**
+     * Creates a file filter. If no filters are added, then all
+     * files are accepted.
+     *
+     * @see #addExtension
+     */
+    public MonitorFileFilter() {
+        this.filters = new Hashtable();
+    }
+
+    /**
+     * Creates a file filter that accepts files with the given extension.
+     * Example: new ExampleFileFilter("jpg");
+     *
+     * @see #addExtension
+     */
+    public MonitorFileFilter(String extension) {
+        this(extension,null);
+    }
+
+    /**
+     * Creates a file filter that accepts the given file type.
+     * Example: new ExampleFileFilter("jpg", "JPEG Image Images");
+     *
+     * Note that the "." before the extension is not needed. If
+     * provided, it will be ignored.
+     *
+     * @see #addExtension
+     */
+    public MonitorFileFilter(String extension, String description) {
+        this();
+        if(extension!=null) addExtension(extension);
+        if(description!=null) setDescription(description);
+    }
+
+    /**
+     * Creates a file filter from the given string array.
+     * Example: new ExampleFileFilter(String {"gif", "jpg"});
+     *
+     * Note that the "." before the extension is not needed adn
+     * will be ignored.
+     *
+     * @see #addExtension
+     */
+    public MonitorFileFilter(String[] filters) {
+        this(filters, null);
+    }
+
+    /**
+     * Creates a file filter from the given string array and description.
+     * Example: new ExampleFileFilter(String {"gif", "jpg"}, "Gif and JPG Images");
+     *
+     * Note that the "." before the extension is not needed and will be ignored.
+     *
+     * @see #addExtension
+     */
+    public MonitorFileFilter(String[] filters, String description) {
+        this();
+        for (int i = 0; i < filters.length; i++) {
+            // add filters one by one
+            addExtension(filters[i]);
+        }
+        if(description!=null) setDescription(description);
+    }
+
+    /**
+     * Return true if this file should be shown in the directory pane,
+     * false if it shouldn't.
+     *
+     * Files that begin with "." are ignored.
+     *
+     * @see #getExtension
+     * @see FileFilter#accepts
+     */
+    public boolean accept(File f) {
+        if(f != null) {
+            if(f.isDirectory()) {
+                return true;
+            }
+            String extension = getExtension(f);
+            if(extension != null && filters.get(getExtension(f)) != null) {
+                return true;
+            };
+        }
+        return false;
+    }
+
+    /**
+     * Return the extension portion of the file's name .
+     *
+     * @see #getExtension
+     * @see FileFilter#accept
+     */
+    public String getExtension(File f) {
+        if(f != null) {
+            String filename = f.getName();
+            int i = filename.lastIndexOf('.');
+            if(i>0 && i<filename.length()-1) {
+                return filename.substring(i+1).toLowerCase();
+            };
+        }
+        return null;
+    }
+
+    /**
+     * Adds a filetype "dot" extension to filter against.
+     *
+     * For example: the following code will create a filter that filters
+     * out all files except those that end in ".jpg" and ".tif":
+     *
+     *   ExampleFileFilter filter = new ExampleFileFilter();
+     *   filter.addExtension("jpg");
+     *   filter.addExtension("tif");
+     *
+     * Note that the "." before the extension is not needed and will be ignored.
+     */
+    public void addExtension(String extension) {
+        if(filters == null) {
+            filters = new Hashtable(5);
+        }
+        filters.put(extension.toLowerCase(), this);
+        fullDescription = null;
+    }
+
+
+    /**
+     * Returns the human readable description of this filter. For
+     * example: "JPEG and GIF Image Files (*.jpg, *.gif)"
+     *
+     * @see setDescription
+     * @see setExtensionListInDescription
+     * @see isExtensionListInDescription
+     * @see FileFilter#getDescription
+     */
+    public String getDescription() {
+        if(fullDescription == null) {
+            if(description == null || isExtensionListInDescription()) {
+                fullDescription = description==null ? "(" : description + " (";
+                // build the description from the extension list
+                Enumeration extensions = filters.keys();
+                if(extensions != null) {
+                    fullDescription += "." + (String) extensions.nextElement();
+                    while (extensions.hasMoreElements()) {
+                        fullDescription += ", " + (String) extensions.nextElement();
+                    }
+                }
+                fullDescription += ")";
+            } else {
+                fullDescription = description;
+            }
+        }
+        return fullDescription;
+    }
+
+    /**
+     * Sets the human readable description of this filter. For
+     * example: filter.setDescription("Gif and JPG Images");
+     *
+     * @see setDescription
+     * @see setExtensionListInDescription
+     * @see isExtensionListInDescription
+     */
+    public void setDescription(String description) {
+        this.description = description;
+        fullDescription = null;
+    }
+
+    /**
+     * Determines whether the extension list (.jpg, .gif, etc) should
+     * show up in the human readable description.
+     *
+     * Only relevent if a description was provided in the constructor
+     * or using setDescription();
+     *
+     * @see getDescription
+     * @see setDescription
+     * @see isExtensionListInDescription
+     */
+    public void setExtensionListInDescription(boolean b) {
+        useExtensionsInDescription = b;
+        fullDescription = null;
+    }
+
+    /**
+     * Returns whether the extension list (.jpg, .gif, etc) should
+     * show up in the human readable description.
+     *
+     * Only relevent if a description was provided in the constructor
+     * or using setDescription();
+     *
+     * @see getDescription
+     * @see setDescription
+     * @see setExtensionListInDescription
+     */
+    public boolean isExtensionListInDescription() {
+        return useExtensionsInDescription;
+    }
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorMainPanel.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorMainPanel.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorMainPanel.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,1038 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui;
+
+import java.awt.Component;
+
+import java.util.Vector;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.Comparator;
+import java.util.Hashtable;
+import java.util.logging.Logger;
+
+import javax.swing.JTree;
+import javax.swing.JTable;
+import javax.swing.JScrollPane;
+import javax.swing.JLabel;
+import javax.swing.JSplitPane;
+import javax.swing.JPanel;
+import javax.swing.ImageIcon;
+import javax.swing.JTextArea;
+import javax.swing.JEditorPane;
+
+import javax.swing.ListSelectionModel;
+import javax.swing.SpringLayout;
+import javax.swing.JCheckBox;
+//import javax.swing.JPopupMenu;
+import javax.swing.JComboBox;
+
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.ListSelectionEvent;
+
+import javax.swing.event.ListSelectionListener;
+
+import javax.swing.tree.TreeSelectionModel;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableCellRenderer;  
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.Dimension;
+import java.awt.Color;
+
+import java.awt.event.ItemListener;
+import java.awt.event.ItemEvent;
+
+import java.awt.event.ActionListener;
+import java.awt.event.ActionEvent;
+
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import java.io.StringWriter;
+import java.io.StringReader;
+
+//import org.pi4soa.cdl.ExchangeDetails;
+import org.pi4soa.service.correlator.CorrelationSession;
+import org.pi4soa.cdl.ExchangeActionType;
+import org.pi4soa.monitor.ExchangeEvent;
+
+import org.pi4soa.monitor.ui.table.TableSorter;
+
+/**
+ * This is the main user interface for the swing monitor.
+ *
+ * It comprises a three-panel display, listing Channels, Exchange
+ * Events, and Exchange Event Details.
+ *
+ * @author Martin Redington
+ */
+public class MonitorMainPanel extends JPanel{
+
+    private static Logger logger = Logger.getLogger("org.pi4soa.monitor.ui");
+
+    //    Vector exchangeEvents = null;
+    ExchangeEventsData exchangeEventsData = null;
+    
+    MonitorMenuBar menuBar =null;
+
+    ControlPanel controlPanel = null;
+
+    ChannelJPanel channelPanel = null;
+    StatusPanel statusPanel = null;
+
+    ExchangeEventsTableModel exchangeEventsTableModel = null;
+    TableSorter sorter = null;
+
+    String choreographyName = null;
+
+    ExchangeJPanel exchangePanel = null;
+
+    public static final Comparator INTEGER_COMPARATOR = new Comparator() {
+            public int compare(Object o1, Object o2) {
+                return ((Integer) o1).intValue() - ((Integer) o2).intValue();
+            }
+        };
+
+    /**
+     * Constructor.
+     */
+    public MonitorMainPanel(ExchangeEventsData exchangeEventsData,
+    					boolean choreoProvided){
+
+    	this.menuBar = new MonitorMenuBar(choreoProvided);
+    	
+        this.exchangeEventsData = exchangeEventsData;
+
+        this.setLayout(new BorderLayout());
+        this.add(menuBar, BorderLayout.PAGE_START);
+
+        JPanel layoutPanel = new JPanel();
+        layoutPanel.setLayout(new BorderLayout());
+
+        controlPanel = new ControlPanel();
+        layoutPanel.add(controlPanel, BorderLayout.PAGE_START);
+
+        MessageJPanel exchangeDetailPanel = null;
+
+        if(true){
+            exchangeDetailPanel = new MessageJPanel(true);
+        }
+
+        exchangeDetailPanel.setPreferredSize(new Dimension(600, 100));
+        exchangeDetailPanel.setMinimumSize(new Dimension(400, 100));
+
+        exchangePanel = new ExchangeJPanel(exchangeDetailPanel);
+        exchangePanel.setPreferredSize(new Dimension(600, 350));
+        exchangePanel.setMinimumSize(new Dimension(400, 200));
+
+        channelPanel = new ChannelJPanel(this.exchangeEventsData,exchangeEventsTableModel);
+        channelPanel.setPreferredSize(new Dimension(200, 580));
+        channelPanel.setMinimumSize(new Dimension(180, 400));
+
+        statusPanel = new StatusPanel();
+
+
+        JSplitPane otherPanel = new JSplitPane(JSplitPane.VERTICAL_SPLIT, exchangePanel, exchangeDetailPanel);
+        JSplitPane mainPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, channelPanel, otherPanel);
+        layoutPanel.add(mainPanel, BorderLayout.CENTER);
+        layoutPanel.add(statusPanel, BorderLayout.SOUTH);
+
+        this.add(layoutPanel, BorderLayout.CENTER);
+    }
+
+    ////////////////////////////////////////////////////////////
+    
+    /** Returns the Channel Panel **/
+    public ChannelJPanel getChannelPanel()
+    {
+    	return channelPanel;
+    }
+
+    /** Returns an ImageIcon, or null if the path was invalid. */
+    protected static ImageIcon createImageIcon(String path) {
+        java.net.URL imgURL = MonitorMainPanel.class.getResource(path);
+        if (imgURL != null) {
+            return new ImageIcon(imgURL);
+        } else {
+            System.err.println("Couldn't find file: " + path);
+            return null;
+        }
+    }
+
+    ////////////////////////////////////////////////////////////
+
+    /**
+     *
+     */
+    public void loadedChoreography(org.pi4soa.cdl.Package choreography){
+        channelPanel.createAndAddTree(choreography);
+        exchangeEventsTableModel.fireTableDataChanged();
+        menuBar.loadedChoreography();
+        choreographyName = choreography.getName();
+        setStatus("Loaded " + choreographyName);
+    }
+
+    ////////////////////////////////////////////////////////////
+
+    /**
+     *
+     */
+    public void startedMonitoring(){
+        menuBar.startedMonitoring();
+        setStatus("Monitoring " + choreographyName);
+    }
+
+    ////////////////////////////////////////////////////////////
+
+    /**
+     *
+     */
+    public void stoppedMonitoring(){
+        menuBar.stoppedMonitoring();
+        setStatus("Stopped monitoring " + choreographyName);
+    }
+
+    ////////////////////////////////////////////////////////////
+
+    /**
+     *
+     */
+    public void importedEvents(){
+        exchangeEventsTableModel.cancelFiltering();
+        exchangeEventsTableModel.fireTableDataChanged();
+    }
+
+    ////////////////////////////////////////////////////////////
+
+    /**
+     * Can't remember what this is for.
+     */
+    public void setApplet(Monitor applet) {
+        //        ui.setApplet(applet);
+        menuBar.setMonitor(applet);
+    }
+    
+
+
+    ////////////////////////////////////////////
+
+    /**
+     * Called by the SwingMonitor when a new exchange event occurs.
+     *
+     * The event will already have been added to the vector or
+     * exchange events.
+     */
+    public void addedExchangeEvent(ExchangeEventWrapper wrapper){
+    	logger.fine(">>>> addedExchangeEvent");
+
+        String selectedChannelName = (String) exchangeEventsTableModel.getSelectedChannelName();
+        logger.fine("channel is: " + selectedChannelName);
+
+        // we are trying to fix the flickering updates here ...
+        if(selectedChannelName == null || wrapper.getChannelType().equals(selectedChannelName)){
+        	logger.fine("fix flickering ...");
+            int index = -1;
+            if((index = exchangeEventsTableModel.indexOfExchangeEventWrapperInFilteredList(wrapper)) != -1){
+            	logger.fine("inner ...");
+                // This might not work when we hack the table ...
+                //                exchangeEventsTableModel.fireTableRowsInserted(index, index);
+                int newIndex = exchangeEventsTableModel.getRowCount() - 1 - index;
+                exchangeEventsTableModel.fireTableRowsInserted(newIndex, newIndex);
+            }
+        }
+
+        updateTreeIfEventIsFault(wrapper);
+        logger.fine("<<<< addedExchangeEvent");
+    }
+    
+    ////////////////////////////////////////////
+
+    /**
+     * Called by the SwingMonitor when a new exchange event occurs.
+     *
+     * The event will already have been added to the vector or
+     * exchange events.
+     */
+    public void addedUnexpectedExchangeEvent(ExchangeEventWrapper wrapper){
+    	logger.fine(">>>> addedUnexpectedExchangeEvent");
+        String selectedChannelName = ChannelJPanel.getUnexpectedMessagesName();
+        logger.fine("channel is: " + selectedChannelName);
+        // we are trying to fix the flickering updates here ...
+        if(selectedChannelName == null || wrapper.getChannelType().equals(selectedChannelName)){
+        	logger.fine("fix flickering ...");
+            int index = -1;
+            if((index = exchangeEventsTableModel.indexOfExchangeEventWrapperInFilteredList(wrapper)) != -1){
+                // This might not work when we hack the table ...
+                //                exchangeEventsTableModel.fireTableRowsInserted(index, index);
+            	logger.fine("inner ...");
+                int newIndex = exchangeEventsTableModel.getRowCount() - 1 - index;
+                exchangeEventsTableModel.fireTableRowsInserted(newIndex, newIndex);
+            } else {
+            	exchangeEventsTableModel.fireTableDataChanged();
+            }
+        }
+        exchangeEventsTableModel.fireTableDataChanged();
+        updateTreeIfEventIsFault(wrapper);
+        
+    	logger.fine("<<<< addedUnexpectedExchangeEvent");
+    }
+
+    public void addedErrorEvent(ExchangeEventWrapper wrapper){
+    	logger.fine(">>>> addedErrorEvent");
+        String selectedChannelName = ChannelJPanel.getErrorName();
+        logger.fine("channel is: " + selectedChannelName);
+        // we are trying to fix the flickering updates here ...
+        if(selectedChannelName == null || wrapper.getChannelType().equals(selectedChannelName)){
+        	logger.fine("fix flickering ...");
+            int index = -1;
+            if((index = exchangeEventsTableModel.indexOfExchangeEventWrapperInFilteredList(wrapper)) != -1){
+                // This might not work when we hack the table ...
+                //                exchangeEventsTableModel.fireTableRowsInserted(index, index);
+            	logger.fine("inner ...");
+                int newIndex = exchangeEventsTableModel.getRowCount() - 1 - index;
+                exchangeEventsTableModel.fireTableRowsInserted(newIndex, newIndex);
+            } else {
+            	exchangeEventsTableModel.fireTableDataChanged();
+            }
+        }
+        exchangeEventsTableModel.fireTableDataChanged();
+        updateTreeIfEventIsFault(wrapper);
+        
+    	logger.fine("<<<< addedErrorEvent");
+    }
+
+    public void addedWarningEvent(ExchangeEventWrapper wrapper){
+    	logger.fine(">>>> addedErrorEvent");
+        String selectedChannelName = ChannelJPanel.getWarningName();
+        logger.fine("channel is: " + selectedChannelName);
+        // we are trying to fix the flickering updates here ...
+        if(selectedChannelName == null || wrapper.getChannelType().equals(selectedChannelName)){
+        	logger.fine("fix flickering ...");
+            int index = -1;
+            if((index = exchangeEventsTableModel.indexOfExchangeEventWrapperInFilteredList(wrapper)) != -1){
+                // This might not work when we hack the table ...
+                //                exchangeEventsTableModel.fireTableRowsInserted(index, index);
+            	logger.fine("inner ...");
+                int newIndex = exchangeEventsTableModel.getRowCount() - 1 - index;
+                exchangeEventsTableModel.fireTableRowsInserted(newIndex, newIndex);
+            } else {
+            	exchangeEventsTableModel.fireTableDataChanged();
+            }
+        }
+        exchangeEventsTableModel.fireTableDataChanged();
+        updateTreeIfEventIsFault(wrapper);
+        
+    	logger.fine("<<<< addedErrorEvent");
+    }
+
+    public void addedInformationEvent(ExchangeEventWrapper wrapper){
+    	logger.fine(">>>> addedErrorEvent");
+        String selectedChannelName = ChannelJPanel.getInformationName();
+        logger.fine("channel is: " + selectedChannelName);
+        // we are trying to fix the flickering updates here ...
+        if(selectedChannelName == null || wrapper.getChannelType().equals(selectedChannelName)){
+        	logger.fine("fix flickering ...");
+            int index = -1;
+            if((index = exchangeEventsTableModel.indexOfExchangeEventWrapperInFilteredList(wrapper)) != -1){
+                // This might not work when we hack the table ...
+                //                exchangeEventsTableModel.fireTableRowsInserted(index, index);
+            	logger.fine("inner ...");
+                int newIndex = exchangeEventsTableModel.getRowCount() - 1 - index;
+                exchangeEventsTableModel.fireTableRowsInserted(newIndex, newIndex);
+            } else {
+            	exchangeEventsTableModel.fireTableDataChanged();
+            }
+        }
+        exchangeEventsTableModel.fireTableDataChanged();
+        updateTreeIfEventIsFault(wrapper);
+        
+    	logger.fine("<<<< addedErrorEvent");
+    }
+    
+    ////////////////////////////////////////////
+
+    /**
+     * Called by the SwingMonitor when an existing exchange event is updated.
+     *
+     */
+    public void updatedExchangeEvent(ExchangeEventWrapper wrapper){
+
+        String selectedChannelName = (String) exchangeEventsTableModel.getSelectedChannelName();
+
+        // we are trying to fix the flickering updates here ...
+        if(selectedChannelName == null || wrapper.getChannelType().equals(selectedChannelName)){
+            int index = -1;
+            if((index = exchangeEventsTableModel.indexOfExchangeEventWrapperInFilteredList(wrapper)) != -1){
+                int newIndex = exchangeEventsTableModel.getRowCount() - 1 - index;
+                exchangeEventsTableModel.fireTableRowsUpdated(newIndex, newIndex);
+            }
+        }
+
+        updateTreeIfEventIsFault(wrapper);
+    }
+
+    ////////////////////////////////////////////
+
+    /**
+     *
+     */
+    void updateTreeIfEventIsFault(ExchangeEventWrapper wrapper){
+        if(wrapper.isFault()){
+            channelPanel.revalidate();
+            channelPanel.redraw();
+        }
+    }
+
+    ////////////////////////////////////////////
+
+    /**
+     *
+     */
+    public void setStatus(String status){
+        statusPanel.setStatus(status);
+    }
+
+    ////////////////// Inner classes
+
+
+
+    ////////////////////////////////////////////
+
+    /**
+     *
+     */
+  
+    ////////////////////////////////////////////
+
+    /**
+     * The upper pane contains a table listing the exchange events.
+     */
+    public class ExchangeJPanel extends JPanel{
+
+        /**
+         *
+         */
+        public ExchangeJPanel(ListSelectionListener listSelectionListener){
+
+            exchangeEventsTableModel = new ExchangeEventsTableModel();
+
+            final ExchangeEventRenderer exchangeEventRenderer = new ExchangeEventRenderer(true);
+            
+            JTable table = new JTable() {
+                public TableCellRenderer getCellRenderer(int row, int column) {
+                    return exchangeEventRenderer;
+                }
+            };
+            table.setModel(exchangeEventsTableModel);
+
+            table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+            table.setColumnSelectionAllowed(false);
+            table.getTableHeader().setReorderingAllowed(false);
+            
+            table.getColumnModel().getColumn(0).setPreferredWidth(40);
+            table.getColumnModel().getColumn(3).setPreferredWidth(200);
+            table.getColumnModel().getColumn(4).setPreferredWidth(40);
+            
+            ListSelectionModel rowSM = table.getSelectionModel();
+            rowSM.addListSelectionListener(listSelectionListener);
+
+            JScrollPane scrollpane = new JScrollPane(table);
+            this.setLayout(new BorderLayout());
+            this.add(scrollpane, BorderLayout.CENTER);
+        }
+    }
+
+    ////////////////////////////////////////////
+
+    /**
+     *
+     */
+    public class ExchangeEventRenderer extends JLabel implements TableCellRenderer{
+
+        public ExchangeEventRenderer(boolean isBordered) {
+            //            this.isBordered = isBordered;
+            setOpaque(true); //MUST do this for background to show up.
+        }
+
+        public Component getTableCellRendererComponent(JTable table, Object object,
+                                                       boolean isSelected, boolean hasFocus,
+                                                       int row, int column) {
+            Integer index = exchangeEventsTableModel.getEventIndexForRow(row);
+
+            ExchangeEventWrapper wrapper = exchangeEventsData.getWrapper(index.intValue());
+            
+            logger.fine("RENDERING EXCHANGE:");
+            logger.fine("EXCHANGE IS: " + wrapper);
+
+            if(isSelected){
+                setForeground(table.getSelectionForeground());
+                setBackground(table.getSelectionBackground());
+            }
+            else{
+                setForeground(table.getForeground());
+                setBackground(table.getBackground());
+            }
+
+            if (object != null) {
+            	setText(object.toString());
+            } else {
+            	setText("");
+            }
+
+            //
+            // Sets the individual exchange color
+            //
+            if(wrapper.isError()){
+            	logger.info("isError - setting color dark red");
+                setForeground(Color.red.darker());
+            }
+            else if (wrapper.isUnexpected()){
+            	logger.info("isUnexpected - setting color red");
+            	setForeground(Color.red);
+            }
+            else if(wrapper.isWarning()){
+            	logger.info("isWarning - setting color orange");
+                setForeground(Color.orange);
+            }
+            else if(wrapper.isInformationMessage() && column == 3){
+            	logger.info("isInformationMessage - setting color blue");
+                setForeground(Color.blue);            	
+            }
+            if (wrapper.isUnexpected())
+            	setToolTipText("This message, '" + wrapper.getSendVariableTypeName()+ "' is invalid for this choreography.");
+            else
+            	setToolTipText(wrapper.getDescription()); //Discussed in the following section
+
+            return this;
+        }
+    }
+
+    ////////////////////////////////////////////
+
+    /**
+     *
+     */
+    public class ExchangeEventsTableModel extends AbstractTableModel implements TreeSelectionListener{
+
+        String selectedChannelName = null;
+
+        Vector filteredExchangeEvents = null;
+
+        Vector emptyVector = new Vector();
+
+        boolean filterByChannel = true;
+
+        ////////////////////////////////////////////
+
+        /**
+         *
+         */
+        public ExchangeEventsTableModel(){
+            this.filteredExchangeEvents = exchangeEventsData.getExchangeEvents();
+        }
+
+        ////////////////////////////////////////////
+
+        public int getColumnCount() {
+            return 5;
+        }
+
+        ////////////////////////////////////////////
+
+        public int getRowCount() {
+            return filteredExchangeEvents.size();
+        }
+
+        ////////////////////////////////////////////
+
+        public String getColumnName(int col) {
+            return getColumnNameSTP(col);
+        }
+
+        ////////////////////////////////////////////
+
+        public String getColumnNameSTP(int col) {
+            if(col == 0){ return "Session Id"; }
+            else if(col == 1){ return "From"; }
+            else if(col == 2){ return "To"; }
+            else if(col == 3){ return "Msg"; }
+            else return "Status";
+            //            else return "Priority";
+        }
+
+        ////////////////////////////////////////////
+
+        /**
+         *
+         */
+        public Object getValueAt(int row, int col) {
+            return getValueAtSTP(row, col);
+        }
+
+        ////////////////////////////////////////////
+
+        /**
+         *
+         */
+        public Class getColumnClass(int col) {
+            return Object.class;
+        }
+
+        ////////////////////////////////////////////
+
+        /**
+         *
+         */
+        protected ExchangeEventWrapper getWrapperForRow(int row) {
+            return (ExchangeEventWrapper) filteredExchangeEvents.elementAt(filteredExchangeEvents.size() - (row + 1));
+        }
+
+        ////////////////////////////////////////////
+
+
+        /**
+         *
+         */
+        public Integer getEventIndexForRow(int row) {
+            ExchangeEventWrapper wrapper = getWrapperForRow(row);
+            return wrapper.getIndex();
+        }
+
+        ////////////////////////////////////////////
+
+        /**
+         *
+         */
+        public Object getValueAtSTP(int row, int col) {
+            ExchangeEventWrapper wrapper = getWrapperForRow(row);
+            //            ExchangeEvent exchangeEvent = wrapper.getExchangeEvent();
+
+            Object result = null;
+
+            switch(col){
+               case 0:
+                   result = wrapper.getMessageIdentity();
+                   break;
+               case 1:
+            	   result="";
+      
+            	   if (wrapper.getFromRoleTypeName() != null &&
+            			   wrapper.getFromRoleTypeName().trim().length() > 0) {
+            		   result = wrapper.getFromRoleTypeName();
+            	   } else if (wrapper.getServiceName() != null) {
+            		   result = org.pi4soa.common.xml.NameSpaceUtil.getLocalPart(
+            				   		wrapper.getServiceName());
+            	   }
+                   break;
+               case 2:
+            	   result="";
+            	      
+            	   if (wrapper.getToRoleTypeName() != null) {
+            		   result = wrapper.getToRoleTypeName();
+            	   }
+                   break;
+               case 3:
+                   result = wrapper.getMessageSummary();
+                   break;
+               case 4:
+                   result = wrapper.getStatus();
+                   break;
+               default:
+                   break;
+            }
+
+            return result;
+        }
+
+        ////////////////////////////////////////////
+
+
+        /**
+         *
+         */
+        public void cancelFiltering(){
+            JTree tree = channelPanel.getTree();
+
+            Vector exchangeEvents = exchangeEventsData.getExchangeEvents();
+            if(this.filteredExchangeEvents != exchangeEvents){
+                this.filteredExchangeEvents = exchangeEvents;
+            }
+            selectedChannelName = null;
+            fireTableDataChanged();
+            tree.clearSelection();
+        }
+
+        ////////////////////////////////////////////
+
+        /**
+         *
+         */
+        public void setFilterByChannel(boolean filterByChannel){
+            this.filterByChannel = filterByChannel;
+            JTree tree = channelPanel.getTree();
+
+            if(filterByChannel == true){
+                valueChangedForTree(tree);
+            }
+            else{
+                Vector exchangeEvents = exchangeEventsData.getExchangeEvents();
+                if(this.filteredExchangeEvents != exchangeEvents){
+                    this.filteredExchangeEvents = exchangeEvents;
+                }
+                selectedChannelName = null;
+                fireTableDataChanged();
+
+                tree.clearSelection();
+            }
+        }
+
+        ////////////////////////////////////////////////////////////
+
+        /**
+         *
+         */
+        public void setFilterByEventType(int index, ControlPanel controlPanel){
+
+            Vector oldFilteredExchangeEvents = filteredExchangeEvents;
+            Vector newFilteredExchangeEvents = null;
+
+            switch(index){
+               case 0:
+                   newFilteredExchangeEvents = exchangeEventsData.getExchangeEvents();
+                   break;
+               case 1:
+                   newFilteredExchangeEvents = exchangeEventsData.getWarningAndErrorExchangeEvents();
+                   break;
+               case 2:
+                   newFilteredExchangeEvents = exchangeEventsData.getErrorExchangeEvents();
+                   break;
+               case 3:
+                   newFilteredExchangeEvents = exchangeEventsData.getWarningExchangeEvents();
+                   break;
+              default:
+                // this ain't gonna happen
+                  return;
+                  //break;
+            }
+            /*
+            if(oldFilteredExchangeEvents != newFilteredExchangeEvents){
+                // we should also reset the enablement of the channel filtering ...
+                if(index == 0){
+                    controlPanel.setFilterEventsByChannelIsEnabled(true);
+                }
+                else{
+                    controlPanel.setFilterEventsByChannelIsEnabled(false);
+                }
+
+                this.filteredExchangeEvents = newFilteredExchangeEvents;
+                fireTableDataChanged();
+            }
+            */
+        }
+
+        ////////////////////////////////////////////////////////////
+
+        /**
+         * When the channel panel selection changes, we (should) filter
+         * the exchange event list.
+         *
+         * Right now, we simply print the selection name to stderr.
+         */
+        public void valueChanged(TreeSelectionEvent e) {
+
+        	logger.fine("valueChanged");
+            if(filterByChannel == false){
+                return;
+            }
+
+            JTree tree = (JTree) e.getSource();
+
+            valueChangedForTree(tree);
+        }
+
+
+        /**
+         *
+         */
+        public void valueChangedForTree(JTree tree) {
+        	logger.fine("valueChangedForTree");
+            DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
+
+            if(node == null) {
+                selectedChannelName = null;
+                return;
+            }
+
+            Vector oldFilteredExchangeEvents = filteredExchangeEvents;
+
+            if (node.isLeaf()) {
+            	logger.fine("Selected is: " + node.getUserObject().toString());
+            	selectedChannelName = (String) node.getUserObject().toString();
+                logger.fine("SelectedChannelName is " + selectedChannelName);
+                Vector newVector = exchangeEventsData.getExchangeEventsForChannel(selectedChannelName);
+
+                // avoid npe's
+                if(newVector == null) {
+                	newVector = exchangeEventsData.getExchangeEventsForSession(selectedChannelName);
+                    if (newVector == null) {
+                    	this.filteredExchangeEvents = emptyVector;
+                    	logger.fine("emptyVector");
+                    } else {
+                        this.filteredExchangeEvents = newVector;
+                        logger.fine("newVector (" + newVector.size() + ")");
+                    }
+                } else {
+                    this.filteredExchangeEvents = newVector;
+                    logger.fine("newVector (" + newVector.size() + ")");
+                }
+
+                
+
+            } else {
+                this.filteredExchangeEvents = exchangeEventsData.getExchangeEvents();
+                selectedChannelName = null;
+            }
+
+            if(oldFilteredExchangeEvents != filteredExchangeEvents) {
+                fireTableDataChanged();
+            }
+        }
+
+        ////////////////////////////////////////////////////////////
+
+        /**
+         *
+         */
+        public String getSelectedChannelName(){
+            return selectedChannelName;
+        }
+
+        ////////////////////////////////////////////////////////////
+
+        /**
+         *
+         */
+        public int indexOfExchangeEventWrapperInFilteredList(Object o){
+            return filteredExchangeEvents.indexOf(o);
+        }
+    }
+
+    ////////////////////////////////////////////
+
+    public class StatusPanel extends JPanel{
+        JLabel statusJLabel = new JLabel();
+
+        public StatusPanel(){
+            this.setLayout(new BorderLayout());
+            this.add(statusJLabel, BorderLayout.LINE_START);
+            setStatus("No choreography loaded");
+        }
+
+        public void setStatus(String status){
+            statusJLabel.setText(status);
+        }
+    }
+
+    ////////////////////////////////////////////
+
+    /**
+     *
+     */
+    public class ControlPanel extends JPanel implements ItemListener, ActionListener{
+        //JCheckBox filterEventsByChannelJCheckBox = new JCheckBox("Filter by channel", true);
+
+        Object sessionItems[] = { "All sessions" };
+        //JComboBox sessionPopupMenu = new JComboBox(sessionItems);
+
+        // add the sessions to the jpopup menu ...
+        //        JComboBox sessionPopupMenu = new JComboBox(sessionItems);
+
+        //Object showItems[] = { "All Events", "Errors and Warnings", "Errors", "Warnings" };
+        //JComboBox showPopupMenu = new JComboBox(showItems);
+
+        //        JComboBox showPopupMenu = new JComboBox("Show: ");
+
+
+
+        /**
+         *
+         */
+        public ControlPanel(){
+            this.setLayout(new BorderLayout());
+            //this.add(filterEventsByChannelJCheckBox, BorderLayout.WEST);
+
+            //filterEventsByChannelJCheckBox.addItemListener(this);
+
+            //            this.add(sessionPopupMenu, BorderLayout.CENTER);
+            //JPanel layoutPanel = new JPanel();
+           // layoutPanel.setLayout(new FlowLayout());
+
+            //layoutPanel.add(new JLabel("Show: "));
+            //layoutPanel.add(showPopupMenu);
+            //showPopupMenu.addActionListener(this);
+
+            //this.add(layoutPanel, BorderLayout.EAST);
+        }
+
+
+        /**
+         *
+         *
+        public void itemStateChanged(ItemEvent e) {
+            Object source = e.getItemSelectable();
+            if(source == filterEventsByChannelJCheckBox){
+                boolean filterByChannel = filterEventsByChannelJCheckBox.isSelected();
+                exchangeEventsTableModel.setFilterByChannel(filterByChannel);
+            }
+        }
+	    */
+        public void itemStateChanged(ItemEvent e) {}
+        
+
+        /**
+         *
+         *
+        public void actionPerformed(ActionEvent e) {
+            Object source = e.getSource();
+            if(source == showPopupMenu){
+                int index = showPopupMenu.getSelectedIndex();
+                exchangeEventsTableModel.setFilterByEventType(index, this);
+            }
+        }
+        */
+        public void actionPerformed(ActionEvent e) {}
+        
+
+
+        /**
+         *
+         *
+        public void setFilterEventsByChannelIsEnabled(boolean setFilterEventsByChannelIsEnabled){
+            if(setFilterEventsByChannelIsEnabled == false){
+                filterEventsByChannelJCheckBox.setSelected(false);
+            }
+            filterEventsByChannelJCheckBox.setEnabled(setFilterEventsByChannelIsEnabled);
+        }
+        */
+        public void setFilterEventsByChannelIsEnabled(boolean setFilterEventsByChannelIsEnabled){}
+
+    }
+
+    ////////////////////////////////////////////
+
+    /**
+     *
+     */
+    //    public class MessageJPanel extends ExchangeDetailJPanel implements ListSelectionListener{
+    public class MessageJPanel extends JPanel implements ListSelectionListener{
+
+        JTextArea msgTextArea = null;
+
+        /**
+         *
+         */
+        public MessageJPanel(boolean dummy){
+            msgTextArea = new JTextArea();
+            msgTextArea.setEditable(false);
+            JScrollPane scrollpane = new JScrollPane(msgTextArea);
+            this.setLayout(new BorderLayout());
+            this.add(scrollpane, BorderLayout.CENTER);
+        }
+
+
+        public void valueChanged(ListSelectionEvent e) {
+
+            logger.fine(">>>> valueChanged - new message selected");
+
+            //Ignore extra messages.
+            if (e.getValueIsAdjusting()) {
+               logger.fine(">>>> just adjusting - returning early");
+               return;
+            }
+
+            ListSelectionModel lsm = (ListSelectionModel)e.getSource();
+
+            if (lsm.isSelectionEmpty()){
+               logger.fine(">>>> no rows selected");
+                // no rows are selected
+            }
+            else{
+                // selectedRow is selected
+                // harhar. grab the first value ...
+                int selectedRowIndex = lsm.getMinSelectionIndex();
+
+               logger.fine(">>>> selectedIndex = " + selectedRowIndex);
+
+                Integer index = (Integer) exchangeEventsTableModel.getEventIndexForRow(selectedRowIndex);
+
+                // ExchangeEventWrapper wrapper = (ExchangeEventWrapper) exchangeEvents.elementAt(index.intValue());
+                ExchangeEventWrapper wrapper = exchangeEventsData.getWrapper(index.intValue());
+
+
+                // avoid NPE's
+                if(wrapper != null){
+                    this.updateDetails(wrapper);
+                }
+                else{
+                    logger.fine(">>>> null exception wrapper");
+                }
+            }
+        }
+
+
+        /**
+         *
+         */
+        public void updateDetails(ExchangeEventWrapper exchangeEventWrapper){
+            String text = exchangeEventWrapper.getMessageValue();
+            logger.info("MESSAGE PAYLOAD: " + text);
+            
+            try {
+            	org.w3c.dom.Node node=org.pi4soa.common.xml.XMLUtils.getNode(text);
+            	
+            	text = org.pi4soa.common.xml.XMLUtils.getText(node, true);
+            	
+            } catch (Exception e) {
+            	//text = "Unable to display message\r\n\r\n"+e;
+            }
+            
+            if (exchangeEventWrapper.getExceptionValue() != null) {
+            	text += "\r\n\r\nException Trace:\r\n"+
+            			exchangeEventWrapper.getExceptionValue();
+            }
+            
+            msgTextArea.setText(text);
+            msgTextArea.setBackground(Color.lightGray);
+            msgTextArea.setCaretPosition(0);
+        }
+    }
+
+}
+
+
+// EOF

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorMenuBar.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorMenuBar.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorMenuBar.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,318 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui;
+
+import javax.swing.*;
+import java.awt.event.*;
+import java.io.*;
+
+/**
+ *
+ */
+public class MonitorMenuBar extends JMenuBar {
+
+    MonitorMenuBar menuBar = this;
+
+    static final int NEW_FRAME_WIDTH = 415;
+    static final int NEW_FRAME_HEIGHT = 330;    
+
+    JMenu fileMenu = new JMenu("File");
+    JMenu editMenu = new JMenu("Edit");
+    JMenu monitorMenu = new JMenu("Monitor");
+    JMenu helpMenu = new JMenu("Help");
+    
+    JMenuItem openItem = new JMenuItem("Open Choreography...");
+    JMenuItem importItem = new JMenuItem("Import Events...");
+    JMenuItem exportItem = new JMenuItem("Export Events...");
+    JMenuItem exitItem = new JMenuItem("Exit");
+    
+    JMenuItem undoItem = new JMenuItem("Undo");
+    JMenuItem cutItem = new JMenuItem("Cut");
+    JMenuItem copyItem = new JMenuItem("Copy");               
+    JMenuItem pasteItem = new JMenuItem("Paste");               
+    JMenuItem selectAllItem = new JMenuItem("Select All");               
+    JMenuItem clearItem = new JMenuItem("Clear");
+    JMenuItem preferencesItem = new JMenuItem("Preferences...");
+
+    JMenuItem startMonitoringItem = new JMenuItem("Start Monitoring");
+    JMenuItem stopMonitoringItem = new JMenuItem("Stop Monitoring");
+
+    JMenuItem helpItem = new JMenuItem("About Choreography Monitor");
+   
+    Monitor monitor;
+
+    /**
+     * 
+     */
+    public MonitorMenuBar(boolean choreoProvided){
+        setUpFileMenu(choreoProvided);
+        setUpEditMenu(choreoProvided);
+        setUpMonitorMenu(choreoProvided);
+        setUpHelpMenu(choreoProvided);        
+    }
+
+
+    /**
+     *
+     */
+    private void setUpFileMenu(boolean choreoProvided){
+        openItem.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.Event.META_MASK));
+        exitItem.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_X, java.awt.Event.META_MASK));
+        
+        openItem.setEnabled(true);
+        importItem.setEnabled(true);
+        exportItem.setEnabled(false);
+        exitItem.setEnabled(true);
+
+        openItem.addActionListener(new ActionListener() {            
+            public void actionPerformed(ActionEvent e) {
+                JFileChooser chooser = new JFileChooser();
+                chooser.setDialogTitle("Open Choreography");
+
+                // Note: source for ExampleFileFilter can be found in FileChooserDemo,
+                // under the demo/jfc directory in the Java 2 SDK, Standard Edition.
+                MonitorFileFilter filter = new MonitorFileFilter();
+                filter.addExtension("cdm");
+                filter.setDescription("CDM Files");
+                chooser.setFileFilter(filter);
+                int returnVal = chooser.showOpenDialog(menuBar);
+                if(returnVal == JFileChooser.APPROVE_OPTION) {
+                    File directory = chooser.getCurrentDirectory();
+                    String fileName = chooser.getSelectedFile().getName();
+                    File path = new File(directory, fileName);
+                    monitor.loadChoreography(path.getPath());
+
+                    // now that we've opened, start monitoring should be enabled.
+                }
+            }
+        });
+
+
+        importItem.addActionListener(new ActionListener() {            
+            public void actionPerformed(ActionEvent e) {
+                JFileChooser chooser = new JFileChooser();
+                chooser.setDialogTitle("Import Events");
+
+                // Note: source for ExampleFileFilter can be found in FileChooserDemo,
+                // under the demo/jfc directory in the Java 2 SDK, Standard Edition.
+                MonitorFileFilter filter = new MonitorFileFilter();
+                filter.addExtension("data");
+                filter.setDescription("Exchange Events");
+                chooser.setFileFilter(filter);
+                int returnVal = chooser.showOpenDialog(menuBar);
+                if(returnVal == JFileChooser.APPROVE_OPTION) {
+                    File directory = chooser.getCurrentDirectory();
+                    String fileName = chooser.getSelectedFile().getName();
+                    File path = new File(directory, fileName);
+                    monitor.importEvents(path.getPath());
+                }
+            }
+        });
+
+
+        exportItem.addActionListener(new ActionListener() {            
+            public void actionPerformed(ActionEvent e) {
+                JFileChooser chooser = new JFileChooser();
+                chooser.setDialogTitle("Export Events");
+
+                // Note: source for ExampleFileFilter can be found in FileChooserDemo,
+                // under the demo/jfc directory in the Java 2 SDK, Standard Edition.
+                //                ExampleFileFilter filter = new ExampleFileFilter();
+                //                filter.addExtension("data");
+                //                filter.setDescription("Exchange Events");
+                //                chooser.setFileFilter(filter);
+                int returnVal = chooser.showSaveDialog(menuBar);
+                if(returnVal == JFileChooser.APPROVE_OPTION) {
+                    File directory = chooser.getCurrentDirectory();
+                    String fileName = chooser.getSelectedFile().getName();
+                    File path = new File(directory, fileName);
+                    monitor.exportEvents(path.getPath());
+                }
+            }
+        });
+
+        exitItem.addActionListener(new ActionListener() {            
+            public void actionPerformed(ActionEvent e) {
+            	monitor.close();
+            }
+        });
+
+        if (!choreoProvided) {
+        	fileMenu.add(openItem);
+        	fileMenu.add(new JSeparator());
+        }
+        
+        // Disable import/export in this version
+        // If re-enabled, need to sort out message summary
+        // persistence, as it uses the exchange event which
+        // is transient
+        //fileMenu.add(importItem);                
+        //fileMenu.add(exportItem);                
+        //fileMenu.add(new JSeparator());                        
+        
+        fileMenu.add(exitItem);
+
+        this.add(fileMenu);
+    }
+
+
+    /**
+     *
+     */
+    private void setUpEditMenu(boolean choreoProvided){
+
+        undoItem.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Z, java.awt.Event.META_MASK));
+        cutItem.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_X, java.awt.Event.META_MASK));
+        copyItem.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_C, java.awt.Event.META_MASK));
+        pasteItem.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_V, java.awt.Event.META_MASK));
+        selectAllItem.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_A, java.awt.Event.META_MASK));
+        preferencesItem.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_P /* was VK_SEMICOLON */, 
+                                                              java.awt.Event.META_MASK));
+
+        undoItem.setEnabled(false);
+        cutItem.setEnabled(false);
+        copyItem.setEnabled(false);
+        pasteItem.setEnabled(false);
+        selectAllItem.setEnabled(false);
+        clearItem.setEnabled(false);
+        
+        // preferences menu implementation
+        preferencesItem.addActionListener(new ActionListener() {            
+            public void actionPerformed(ActionEvent e) {
+                //                preferences.setVisible(true);
+            }
+        });
+        
+        editMenu.add(undoItem);
+        editMenu.add(new JSeparator());                        
+        editMenu.add(cutItem);
+        editMenu.add(copyItem);
+        editMenu.add(pasteItem);                                                
+        editMenu.add(selectAllItem);                                                        
+        editMenu.add(clearItem);
+        editMenu.add(new JSeparator());                        
+        editMenu.add(preferencesItem);
+
+        /*
+        this.add(editMenu);
+        */
+    }
+
+
+    /**
+     *
+     */
+    private void setUpMonitorMenu(boolean choreoProvided){
+        startMonitoringItem.setEnabled(false);
+        stopMonitoringItem.setEnabled(false);
+
+        startMonitoringItem.addActionListener(new ActionListener() {            
+            public void actionPerformed(ActionEvent e) {
+                monitor.startMonitoring();
+            }
+        });
+
+        stopMonitoringItem.addActionListener(new ActionListener() {
+            public void actionPerformed(ActionEvent e) {
+                monitor.stopMonitoring();
+            }
+        });
+
+        monitorMenu.add(startMonitoringItem);
+        monitorMenu.add(stopMonitoringItem);
+
+        if (!choreoProvided) {
+        	this.add(monitorMenu);
+        }
+    }        
+
+
+    /**
+     *
+     */
+    private void setUpHelpMenu(boolean choreoProvided){
+        helpItem.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F1, 0));
+        helpMenu.add(helpItem);
+        helpItem.setEnabled(true);
+
+        helpItem.addActionListener(new ActionListener() {            
+            public void actionPerformed(ActionEvent e) {
+                JOptionPane.showMessageDialog(null,
+                		"pi4soa Choreography Monitor\r\n\r\n" +
+                		"Version 1\r\n\r\n" +
+                		"(c) Pi4 Technologies Ltd, 2005-8",
+                		"About ...", JOptionPane.INFORMATION_MESSAGE);
+            }
+        });
+
+        this.add(helpMenu);
+    }
+    
+
+    /**
+     * 
+     */
+    public void setMonitor(Monitor monitor) {
+        this.monitor = monitor;
+    }
+
+
+    /**
+     *
+     */
+    public void loadedChoreography(){
+        startMonitoringItem.setEnabled(true);
+    }
+
+
+    /**
+     *
+     */
+    public void startedMonitoring(){
+        openItem.setEnabled(false);
+        importItem.setEnabled(false);
+        exportItem.setEnabled(true);
+        startMonitoringItem.setEnabled(false);
+        stopMonitoringItem.setEnabled(true);
+    }
+
+
+    /**
+     *
+     */
+    public void stoppedMonitoring(){
+        openItem.setEnabled(true);
+        importItem.setEnabled(true);
+        exportItem.setEnabled(true);
+        startMonitoringItem.setEnabled(true);
+        stopMonitoringItem.setEnabled(false);
+    }
+
+    /**
+     *
+     */
+    public void importedEvents(){
+        exportItem.setEnabled(true);
+    }
+
+} // End of class
+
+
+// EOF

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorTreeModelListener.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorTreeModelListener.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/MonitorTreeModelListener.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui;
+
+import java.util.logging.Logger;
+
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.DefaultTreeCellRenderer;
+import javax.swing.tree.DefaultTreeModel;
+import javax.swing.tree.TreeSelectionModel;
+
+import org.pi4soa.service.correlator.CorrelationSession;
+
+
+/**
+ * The left hand pane contains a tree whose root is the
+ * choreography, and whose leaves are channels.
+ *
+ * Selecting a channel filters the exchange events list (or should
+ * do).
+ */
+class MonitorTreeModelListener implements TreeModelListener {
+	
+	private static Logger logger = Logger.getLogger("org.pi4soa.monitor.ui");
+	  
+    public void treeNodesChanged(TreeModelEvent e) {
+        DefaultMutableTreeNode node;
+        node = (DefaultMutableTreeNode)
+                 (e.getTreePath().getLastPathComponent());
+
+        /*
+         * If the event lists children, then the changed
+         * node is the child of the node we've already
+         * gotten.  Otherwise, the changed node and the
+         * specified node are the same.
+         */
+        try {
+            int index = e.getChildIndices()[0];
+            node = (DefaultMutableTreeNode)
+                   (node.getChildAt(index));
+        } catch (NullPointerException exc) {}
+
+        logger.fine(">>> CHANGED NODE");
+        logger.fine("The user has finished editing the node.");
+        logger.fine("New value: " + node.getUserObject());
+    }
+    public void treeNodesInserted(TreeModelEvent e) {
+    	logger.fine(">>> INSERTED NODE");
+    }
+    public void treeNodesRemoved(TreeModelEvent e) {
+    	logger.fine(">>> REMOVED NODE");
+    }
+    public void treeStructureChanged(TreeModelEvent e) {
+    	logger.fine(">>> TREE STRUCTURE CHANGED");
+    }
+}
\ No newline at end of file

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/SpringUtilities.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/SpringUtilities.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/SpringUtilities.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui;
+
+import javax.swing.*;
+import javax.swing.SpringLayout;
+import java.awt.*;
+
+/**
+ * A 1.4 file that provides utility methods for
+ * creating form- or grid-style layouts with SpringLayout.
+ * These utilities are used by several programs, such as
+ * SpringBox and SpringCompactGrid.
+ */
+public class SpringUtilities {
+    /**
+     * A debugging utility that prints to stdout the component's
+     * minimum, preferred, and maximum sizes.
+     */
+    public static void printSizes(Component c) {
+        System.out.println("minimumSize = " + c.getMinimumSize());
+        System.out.println("preferredSize = " + c.getPreferredSize());
+        System.out.println("maximumSize = " + c.getMaximumSize());
+    }
+
+    /**
+     * Aligns the first <code>rows</code> * <code>cols</code>
+     * components of <code>parent</code> in
+     * a grid. Each component is as big as the maximum
+     * preferred width and height of the components.
+     * The parent is made just big enough to fit them all.
+     *
+     * @param rows number of rows
+     * @param cols number of columns
+     * @param initialX x location to start the grid at
+     * @param initialY y location to start the grid at
+     * @param xPad x padding between cells
+     * @param yPad y padding between cells
+     */
+    public static void makeGrid(Container parent,
+                                int rows, int cols,
+                                int initialX, int initialY,
+                                int xPad, int yPad) {
+        SpringLayout layout;
+        try {
+            layout = (SpringLayout)parent.getLayout();
+        } catch (ClassCastException exc) {
+            System.err.println("The first argument to makeGrid must use SpringLayout.");
+            return;
+        }
+
+        Spring xPadSpring = Spring.constant(xPad);
+        Spring yPadSpring = Spring.constant(yPad);
+        Spring initialXSpring = Spring.constant(initialX);
+        Spring initialYSpring = Spring.constant(initialY);
+        int max = rows * cols;
+
+        //Calculate Springs that are the max of the width/height so that all
+        //cells have the same size.
+        Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)).
+            getWidth();
+        Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)).
+            getWidth();
+        for (int i = 1; i < max; i++) {
+            SpringLayout.Constraints cons = layout.getConstraints(
+                                                                  parent.getComponent(i));
+
+            maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
+            maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
+        }
+
+        //Apply the new width/height Spring. This forces all the
+        //components to have the same size.
+        for (int i = 0; i < max; i++) {
+            SpringLayout.Constraints cons = layout.getConstraints(
+                                                                  parent.getComponent(i));
+
+            cons.setWidth(maxWidthSpring);
+            cons.setHeight(maxHeightSpring);
+        }
+
+        //Then adjust the x/y constraints of all the cells so that they
+        //are aligned in a grid.
+        SpringLayout.Constraints lastCons = null;
+        SpringLayout.Constraints lastRowCons = null;
+        for (int i = 0; i < max; i++) {
+            SpringLayout.Constraints cons = layout.getConstraints(
+                                                                  parent.getComponent(i));
+            if (i % cols == 0) { //start of new row
+                lastRowCons = lastCons;
+                cons.setX(initialXSpring);
+            } else { //x position depends on previous component
+                cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST),
+                                     xPadSpring));
+            }
+
+            if (i / cols == 0) { //first row
+                cons.setY(initialYSpring);
+            } else { //y position depends on previous row
+                cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH),
+                                     yPadSpring));
+            }
+            lastCons = cons;
+        }
+
+        //Set the parent's size.
+        SpringLayout.Constraints pCons = layout.getConstraints(parent);
+        pCons.setConstraint(SpringLayout.SOUTH,
+                            Spring.sum(
+                                       Spring.constant(yPad),
+                                       lastCons.getConstraint(SpringLayout.SOUTH)));
+        pCons.setConstraint(SpringLayout.EAST,
+                            Spring.sum(
+                                       Spring.constant(xPad),
+                                       lastCons.getConstraint(SpringLayout.EAST)));
+    }
+
+    /* Used by makeCompactGrid. */
+    private static SpringLayout.Constraints getConstraintsForCell(
+                                                                  int row, int col,
+                                                                  Container parent,
+                                                                  int cols) {
+        SpringLayout layout = (SpringLayout) parent.getLayout();
+        Component c = parent.getComponent(row * cols + col);
+        return layout.getConstraints(c);
+    }
+
+    /**
+     * Aligns the first <code>rows</code> * <code>cols</code>
+     * components of <code>parent</code> in
+     * a grid. Each component in a column is as wide as the maximum
+     * preferred width of the components in that column;
+     * height is similarly determined for each row.
+     * The parent is made just big enough to fit them all.
+     *
+     * @param rows number of rows
+     * @param cols number of columns
+     * @param initialX x location to start the grid at
+     * @param initialY y location to start the grid at
+     * @param xPad x padding between cells
+     * @param yPad y padding between cells
+     */
+    public static void makeCompactGrid(Container parent,
+                                       int rows, int cols,
+                                       int initialX, int initialY,
+                                       int xPad, int yPad) {
+        SpringLayout layout;
+        try {
+            layout = (SpringLayout)parent.getLayout();
+        } catch (ClassCastException exc) {
+            System.err.println("The first argument to makeCompactGrid must use SpringLayout.");
+            return;
+        }
+
+        //Align all cells in each column and make them the same width.
+        Spring x = Spring.constant(initialX);
+        for (int c = 0; c < cols; c++) {
+            Spring width = Spring.constant(0);
+            for (int r = 0; r < rows; r++) {
+                width = Spring.max(width,
+                                   getConstraintsForCell(r, c, parent, cols).
+                                   getWidth());
+            }
+            for (int r = 0; r < rows; r++) {
+                SpringLayout.Constraints constraints =
+                    getConstraintsForCell(r, c, parent, cols);
+                constraints.setX(x);
+                constraints.setWidth(width);
+            }
+            x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad)));
+        }
+
+        //Align all cells in each row and make them the same height.
+        Spring y = Spring.constant(initialY);
+        for (int r = 0; r < rows; r++) {
+            Spring height = Spring.constant(0);
+            for (int c = 0; c < cols; c++) {
+                height = Spring.max(height,
+                                    getConstraintsForCell(r, c, parent, cols).
+                                    getHeight());
+            }
+            for (int c = 0; c < cols; c++) {
+                SpringLayout.Constraints constraints =
+                    getConstraintsForCell(r, c, parent, cols);
+                constraints.setY(y);
+                constraints.setHeight(height);
+            }
+            y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad)));
+        }
+
+        //Set the parent's size.
+        SpringLayout.Constraints pCons = layout.getConstraints(parent);
+        pCons.setConstraint(SpringLayout.SOUTH, y);
+        pCons.setConstraint(SpringLayout.EAST, x);
+    }
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/XmlPrettyPrinter.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/XmlPrettyPrinter.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/XmlPrettyPrinter.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui;
+
+
+import org.w3c.dom.Document;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.ParserConfigurationException;
+
+//import org.apache.xml.serialize.OutputFormat;
+//import org.apache.xml.serialize.XMLSerializer;
+
+import java.io.IOException;
+import java.io.StringBufferInputStream;
+import java.io.ByteArrayOutputStream;
+
+import org.xml.sax.SAXException;
+
+/**
+ *
+ */
+public class XmlPrettyPrinter{
+
+    /**
+     *
+     */
+    public static String prettify(String input){
+
+        // Find the implementation
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        DocumentBuilder builder = null;
+
+        try{
+            builder = factory.newDocumentBuilder();
+        }
+        catch(ParserConfigurationException pce){
+            System.err.println("Exception: " + pce);
+            return null;
+        }
+
+        StringBufferInputStream stringBufferInputStream = new StringBufferInputStream(input);
+
+        Document doc = null;
+
+        try{
+            doc = builder.parse(stringBufferInputStream);
+        }
+        catch(SAXException se){
+            System.err.println("Exception: " + se);
+            return null;
+        }
+        catch(IOException ioe){
+            System.err.println("Exception: " + ioe);
+            return null;
+        }
+        
+        String text=null;
+        
+        try {
+        	text = org.pi4soa.common.xml.XMLUtils.getText(doc, true);
+        } catch(Exception e) {
+        	System.err.println("Exception: " + e);
+        }
+        
+        return(text);
+
+        /*
+        OutputFormat format = new OutputFormat(doc);
+        format.setLineWidth(65);
+        format.setIndenting(true);
+        format.setIndent(2);
+        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+        XMLSerializer serializer = new XMLSerializer(byteArrayOutputStream, format);
+
+        try{
+            serializer.serialize(doc);
+        }
+        catch(IOException ioe){
+            System.err.println("Exception: " + ioe);
+            return null;
+        }
+
+        return byteArrayOutputStream.toString();
+        */
+    }
+
+}

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelclosed.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelclosed.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelempty.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelempty.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelleaf.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelleaf.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelopen.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/channelopen.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/errorsleaf.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/errorsleaf.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/issuesclosed.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/issuesclosed.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/issuesempty.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/issuesempty.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/issuesopen.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/issuesopen.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/monitor.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/monitor.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnclosed.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnclosed.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnempty.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnempty.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnleaf.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnleaf.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnopen.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/txnopen.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/unexpectedleaf.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/unexpectedleaf.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/warningsleaf.png
===================================================================
(Binary files differ)


Property changes on: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/icons/warningsleaf.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/table/TableSorter.java
===================================================================
--- trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/table/TableSorter.java	                        (rev 0)
+++ trunk/org.pi4soa.monitor/src/java/org/pi4soa/monitor/ui/table/TableSorter.java	2009-12-05 10:50:50 UTC (rev 98)
@@ -0,0 +1,450 @@
+/*
+ * Copyright 2005-8 Pi4 Technologies Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *
+ * Change History:
+ * 16 Jan, 2008 : Initial version created by martin
+ */
+package org.pi4soa.monitor.ui.table;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.List;
+
+import javax.swing.*;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.*;
+
+public class TableSorter extends AbstractTableModel {
+    protected TableModel tableModel;
+
+    public static final int DESCENDING = -1;
+    public static final int NOT_SORTED = 0;
+    public static final int ASCENDING = 1;
+
+    private static Directive EMPTY_DIRECTIVE = new Directive(-1, NOT_SORTED);
+
+    public static final Comparator COMPARABLE_COMAPRATOR = new Comparator() {
+            public int compare(Object o1, Object o2) {
+                return ((Comparable) o1).compareTo(o2);
+            }
+        };
+    public static final Comparator LEXICAL_COMPARATOR = new Comparator() {
+            public int compare(Object o1, Object o2) {
+                return o1.toString().compareTo(o2.toString());
+            }
+        };
+
+    private Row[] viewToModel;
+    private int[] modelToView;
+
+    private JTableHeader tableHeader;
+    private MouseListener mouseListener;
+    private TableModelListener tableModelListener;
+    private Map columnComparators = new HashMap();
+    private List sortingColumns = new ArrayList();
+
+    public TableSorter() {
+        this.mouseListener = new MouseHandler();
+        this.tableModelListener = new TableModelHandler();
+    }
+
+    public TableSorter(TableModel tableModel) {
+        this();
+        setTableModel(tableModel);
+    }
+
+    public TableSorter(TableModel tableModel, JTableHeader tableHeader) {
+        this();
+        setTableHeader(tableHeader);
+        setTableModel(tableModel);
+    }
+
+    private void clearSortingState() {
+        viewToModel = null;
+        modelToView = null;
+    }
+
+    public TableModel getTableModel() {
+        return tableModel;
+    }
+
+    public void setTableModel(TableModel tableModel) {
+        if (this.tableModel != null) {
+            this.tableModel.removeTableModelListener(tableModelListener);
+        }
+
+        this.tableModel = tableModel;
+        if (this.tableModel != null) {
+            this.tableModel.addTableModelListener(tableModelListener);
+        }
+
+        clearSortingState();
+        fireTableStructureChanged();
+    }
+
+    public JTableHeader getTableHeader() {
+        return tableHeader;
+    }
+
+    public void setTableHeader(JTableHeader tableHeader) {
+        if (this.tableHeader != null) {
+            this.tableHeader.removeMouseListener(mouseListener);
+            TableCellRenderer defaultRenderer = this.tableHeader.getDefaultRenderer();
+            if (defaultRenderer instanceof SortableHeaderRenderer) {
+                this.tableHeader.setDefaultRenderer(((SortableHeaderRenderer) defaultRenderer).tableCellRenderer);
+            }
+        }
+        this.tableHeader = tableHeader;
+        if (this.tableHeader != null) {
+            this.tableHeader.addMouseListener(mouseListener);
+            this.tableHeader.setDefaultRenderer(
+                                                new SortableHeaderRenderer(this.tableHeader.getDefaultRenderer()));
+        }
+    }
+
+    public boolean isSorting() {
+        return sortingColumns.size() != 0;
+    }
+
+    private Directive getDirective(int column) {
+        for (int i = 0; i < sortingColumns.size(); i++) {
+            Directive directive = (Directive)sortingColumns.get(i);
+            if (directive.column == column) {
+                return directive;
+            }
+        }
+        return EMPTY_DIRECTIVE;
+    }
+
+    public int getSortingStatus(int column) {
+        return getDirective(column).direction;
+    }
+
+    private void sortingStatusChanged() {
+        clearSortingState();
+        fireTableDataChanged();
+        if (tableHeader != null) {
+            tableHeader.repaint();
+        }
+    }
+
+    public void setSortingStatus(int column, int status) {
+        Directive directive = getDirective(column);
+        if (directive != EMPTY_DIRECTIVE) {
+            sortingColumns.remove(directive);
+        }
+        if (status != NOT_SORTED) {
+            sortingColumns.add(new Directive(column, status));
+        }
+        sortingStatusChanged();
+    }
+
+    protected Icon getHeaderRendererIcon(int column, int size) {
+        Directive directive = getDirective(column);
+        if (directive == EMPTY_DIRECTIVE) {
+            return null;
+        }
+        return new Arrow(directive.direction == DESCENDING, size, sortingColumns.indexOf(directive));
+    }
+
+    private void cancelSorting() {
+        sortingColumns.clear();
+        sortingStatusChanged();
+    }
+
+    public void setColumnComparator(Class type, Comparator comparator) {
+        if (comparator == null) {
+            columnComparators.remove(type);
+        } else {
+            columnComparators.put(type, comparator);
+        }
+    }
+
+    protected Comparator getComparator(int column) {
+        Class columnType = tableModel.getColumnClass(column);
+        Comparator comparator = (Comparator) columnComparators.get(columnType);
+        if (comparator != null) {
+            return comparator;
+        }
+        if (Comparable.class.isAssignableFrom(columnType)) {
+            return COMPARABLE_COMAPRATOR;
+        }
+        return LEXICAL_COMPARATOR;
+    }
+
+    private Row[] getViewToModel() {
+        if (viewToModel == null) {
+            int tableModelRowCount = tableModel.getRowCount();
+            viewToModel = new Row[tableModelRowCount];
+            for (int row = 0; row < tableModelRowCount; row++) {
+                viewToModel[row] = new Row(row);
+            }
+
+            if (isSorting()) {
+                Arrays.sort(viewToModel);
+            }
+        }
+        return viewToModel;
+    }
+
+    public int modelIndex(int viewIndex) {
+        return getViewToModel()[viewIndex].modelIndex;
+    }
+
+    private int[] getModelToView() {
+        if (modelToView == null) {
+            int n = getViewToModel().length;
+            modelToView = new int[n];
+            for (int i = 0; i < n; i++) {
+                modelToView[modelIndex(i)] = i;
+            }
+        }
+        return modelToView;
+    }
+
+    // TableModel interface methods 
+
+    public int getRowCount() {
+        return (tableModel == null) ? 0 : tableModel.getRowCount();
+    }
+
+    public int getColumnCount() {
+        return (tableModel == null) ? 0 : tableModel.getColumnCount();
+    }
+
+    public String getColumnName(int column) {
+        return tableModel.getColumnName(column);
+    }
+
+    public Class getColumnClass(int column) {
+        return tableModel.getColumnClass(column);
+    }
+
+    public boolean isCellEditable(int row, int column) {
+        return tableModel.isCellEditable(modelIndex(row), column);
+    }
+
+    public Object getValueAt(int row, int column) {
+        return tableModel.getValueAt(modelIndex(row), column);
+    }
+
+    public void setValueAt(Object aValue, int row, int column) {
+        tableModel.setValueAt(aValue, modelIndex(row), column);
+    }
+
+    // Helper classes
+    
+    private class Row implements Comparable {
+        private int modelIndex;
+
+        public Row(int index) {
+            this.modelIndex = index;
+        }
+
+        public int compareTo(Object o) {
+            int row1 = modelIndex;
+            int row2 = ((Row) o).modelIndex;
+
+            for (Iterator it = sortingColumns.iterator(); it.hasNext();) {
+                Directive directive = (Directive) it.next();
+                int column = directive.column;
+                Object o1 = tableModel.getValueAt(row1, column);
+                Object o2 = tableModel.getValueAt(row2, column);
+
+                int comparison = 0;
+                // Define null less than everything, except null.
+                if (o1 == null && o2 == null) {
+                    comparison = 0;
+                } else if (o1 == null) {
+                    comparison = -1;
+                } else if (o2 == null) {
+                    comparison = 1;
+                } else {
+                    comparison = getComparator(column).compare(o1, o2);
+                }
+                if (comparison != 0) {
+                    return directive.direction == DESCENDING ? -comparison : comparison;
+                }
+            }
+            return 0;
+        }
+    }
+
+    private class TableModelHandler implements TableModelListener {
+        public void tableChanged(TableModelEvent e) {
+            // If we're not sorting by anything, just pass the event along.             
+            if (!isSorting()) {
+                clearSortingState();
+                fireTableChanged(e);
+                return;
+            }
+                
+            // If the table structure has changed, cancel the sorting; the             
+            // sorting columns may have been either moved or deleted from             
+            // the model. 
+            if (e.getFirstRow() == TableModelEvent.HEADER_ROW) {
+                cancelSorting();
+                fireTableChanged(e);
+                return;
+            }
+
+            // We can map a cell event through to the view without widening             
+            // when the following conditions apply: 
+            // 
+            // a) all the changes are on one row (e.getFirstRow() == e.getLastRow()) and, 
+            // b) all the changes are in one column (column != TableModelEvent.ALL_COLUMNS) and,
+            // c) we are not sorting on that column (getSortingStatus(column) == NOT_SORTED) and, 
+            // d) a reverse lookup will not trigger a sort (modelToView != null)
+            //
+            // Note: INSERT and DELETE events fail this test as they have column == ALL_COLUMNS.
+            // 
+            // The last check, for (modelToView != null) is to see if modelToView 
+            // is already allocated. If we don't do this check; sorting can become 
+            // a performance bottleneck for applications where cells  
+            // change rapidly in different parts of the table. If cells 
+            // change alternately in the sorting column and then outside of             
+            // it this class can end up re-sorting on alternate cell updates - 
+            // which can be a performance problem for large tables. The last 
+            // clause avoids this problem. 
+            int column = e.getColumn();
+            if (e.getFirstRow() == e.getLastRow()
+                    && column != TableModelEvent.ALL_COLUMNS
+                && getSortingStatus(column) == NOT_SORTED
+                && modelToView != null) {
+                int viewIndex = getModelToView()[e.getFirstRow()];
+                fireTableChanged(new TableModelEvent(TableSorter.this, 
+                                                     viewIndex, viewIndex, 
+                                                     column, e.getType()));
+                return;
+            }
+
+            // Something has happened to the data that may have invalidated the row order. 
+            clearSortingState();
+            fireTableDataChanged();
+            return;
+        }
+    }
+
+    private class MouseHandler extends MouseAdapter {
+        public void mouseClicked(MouseEvent e) {
+            JTableHeader h = (JTableHeader) e.getSource();
+            TableColumnModel columnModel = h.getColumnModel();
+            int viewColumn = columnModel.getColumnIndexAtX(e.getX());
+            int column = columnModel.getColumn(viewColumn).getModelIndex();
+            if (column != -1) {
+                int status = getSortingStatus(column);
+                if (!e.isControlDown()) {
+                    cancelSorting();
+                }
+                // Cycle the sorting states through {NOT_SORTED, ASCENDING, DESCENDING} or 
+                // {NOT_SORTED, DESCENDING, ASCENDING} depending on whether shift is pressed. 
+                status = status + (e.isShiftDown() ? -1 : 1);
+                status = (status + 4) % 3 - 1; // signed mod, returning {-1, 0, 1}
+                setSortingStatus(column, status);
+            }
+        }
+    }
+
+    private static class Arrow implements Icon {
+        private boolean descending;
+        private int size;
+        private int priority;
+
+        public Arrow(boolean descending, int size, int priority) {
+            this.descending = descending;
+            this.size = size;
+            this.priority = priority;
+        }
+
+        public void paintIcon(Component c, Graphics g, int x, int y) {
+            Color color = c == null ? Color.GRAY : c.getBackground();             
+            // In a compound sort, make each succesive triangle 20% 
+            // smaller than the previous one. 
+            int dx = (int)(size/2*Math.pow(0.8, priority));
+            int dy = descending ? dx : -dx;
+            // Align icon (roughly) with font baseline. 
+            y = y + 5*size/6 + (descending ? -dy : 0);
+            int shift = descending ? 1 : -1;
+            g.translate(x, y);
+
+            // Right diagonal. 
+            g.setColor(color.darker());
+            g.drawLine(dx / 2, dy, 0, 0);
+            g.drawLine(dx / 2, dy + shift, 0, shift);
+            
+            // Left diagonal. 
+            g.setColor(color.brighter());
+            g.drawLine(dx / 2, dy, dx, 0);
+            g.drawLine(dx / 2, dy + shift, dx, shift);
+            
+            // Horizontal line. 
+            if (descending) {
+                g.setColor(color.darker().darker());
+            } else {
+                g.setColor(color.brighter().brighter());
+            }
+            g.drawLine(dx, 0, 0, 0);
+
+            g.setColor(color);
+            g.translate(-x, -y);
+        }
+
+        public int getIconWidth() {
+            return size;
+        }
+
+        public int getIconHeight() {
+            return size;
+        }
+    }
+
+    private class SortableHeaderRenderer implements TableCellRenderer {
+        private TableCellRenderer tableCellRenderer;
+
+        public SortableHeaderRenderer(TableCellRenderer tableCellRenderer) {
+            this.tableCellRenderer = tableCellRenderer;
+        }
+
+        public Component getTableCellRendererComponent(JTable table, 
+                                                       Object value,
+                                                       boolean isSelected, 
+                                                       boolean hasFocus,
+                                                       int row, 
+                                                       int column) {
+            Component c = tableCellRenderer.getTableCellRendererComponent(table, 
+                                                                          value, isSelected, hasFocus, row, column);
+            if (c instanceof JLabel) {
+                JLabel l = (JLabel) c;
+                l.setHorizontalTextPosition(JLabel.LEFT);
+                int modelColumn = table.convertColumnIndexToModel(column);
+                l.setIcon(getHeaderRendererIcon(modelColumn, l.getFont().getSize()));
+            }
+            return c;
+        }
+    }
+
+    private static class Directive {
+        private int column;
+        private int direction;
+
+        public Directive(int column, int direction) {
+            this.column = column;
+            this.direction = direction;
+        }
+    }
+}



More information about the savara-commits mailing list