feature: port some 23.1 code
diff --git a/org.eclipse.ote.bytemessage/META-INF/MANIFEST.MF b/org.eclipse.ote.bytemessage/META-INF/MANIFEST.MF
index b901543..d200083 100644
--- a/org.eclipse.ote.bytemessage/META-INF/MANIFEST.MF
+++ b/org.eclipse.ote.bytemessage/META-INF/MANIFEST.MF
@@ -6,6 +6,7 @@
 Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Import-Package: org.eclipse.osee.framework.jdk.core.persistence,
  org.eclipse.osee.framework.logging,
+ org.eclipse.osee.framework.plugin.core.util,
  org.eclipse.osee.ote.message,
  org.eclipse.osee.ote.message.data,
  org.eclipse.osee.ote.message.elements,
diff --git a/org.eclipse.ote.bytemessage/src/org/eclipse/ote/bytemessage/OteByteMessageListener.java b/org.eclipse.ote.bytemessage/src/org/eclipse/ote/bytemessage/OteByteMessageListener.java
new file mode 100644
index 0000000..66e2f14
--- /dev/null
+++ b/org.eclipse.ote.bytemessage/src/org/eclipse/ote/bytemessage/OteByteMessageListener.java
@@ -0,0 +1,7 @@
+package org.eclipse.ote.bytemessage;
+
+public interface OteByteMessageListener<T extends OteByteMessage> {
+   
+   void onDataAvailable(T message);
+
+}
diff --git a/org.eclipse.ote.bytemessage/src/org/eclipse/ote/bytemessage/OteByteMessageUtil.java b/org.eclipse.ote.bytemessage/src/org/eclipse/ote/bytemessage/OteByteMessageUtil.java
index 7c90250..3d2e665 100644
--- a/org.eclipse.ote.bytemessage/src/org/eclipse/ote/bytemessage/OteByteMessageUtil.java
+++ b/org.eclipse.ote.bytemessage/src/org/eclipse/ote/bytemessage/OteByteMessageUtil.java
@@ -10,12 +10,17 @@
  *******************************************************************************/
 package org.eclipse.ote.bytemessage;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Map;
 import java.util.UUID;
+import java.util.logging.Level;
 
+import org.eclipse.osee.framework.logging.OseeLog;
+import org.eclipse.osee.framework.plugin.core.util.ExportClassLoader;
 import org.eclipse.ote.services.core.ServiceUtility;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
@@ -28,7 +33,7 @@
    public final static String BYTE_KEY = "oteeventbytes";
 
    public final static String BYTE_KEY_2 = "bytes";
-
+   
    public static void sendEvent(OteByteMessage message) {
       EventAdmin eventAdmin = ServiceUtility.getService(EventAdmin.class);
       sendEvent(message, eventAdmin);
@@ -43,7 +48,10 @@
       sendEvent(message);
    }
 
-   public static void sendEvent(OteByteMessage message, EventAdmin eventAdmin) {
+   public static void sendEvent(final OteByteMessage message, final EventAdmin eventAdmin) {
+      if(isUIThread()){
+         OseeLog.logf(OteByteMessageUtil.class, Level.INFO, "sending [%s] from the UI thread.", message.getHeader().TOPIC.getValue());
+      } 
       message.getHeader().UUID_HIGH.setNoLog((long) 0x0);
       message.getHeader().UUID_LOW.setNoLog((long) 0x0);
       Map<String, Object> data = new HashMap<String, Object>();
@@ -52,12 +60,35 @@
       eventAdmin.sendEvent(newevent);
    }
 
+   private static boolean isUIThread()
+   {
+      Object display = null;
+      ClassLoader loader = ExportClassLoader.getInstance();
+      try
+      {
+         Class displayClass = loader.loadClass("org.eclipse.swt.widgets.Display");
+         Field[] fields = displayClass.getDeclaredFields();
+
+         Method getDefaultMethod = displayClass.getDeclaredMethod("findDisplay", new Class[] { Thread.class });
+         display = getDefaultMethod.invoke(null, new Object[] { Thread.currentThread() });
+
+      }
+      catch(Exception e)
+      {
+         return false;
+      }
+      return (display != null);
+   }
+   
    public static void postEvent(OteByteMessage message) {
       EventAdmin eventAdmin = ServiceUtility.getService(EventAdmin.class);
       postEvent(message, eventAdmin);
    }
 
-   public static void postEvent(OteByteMessage message, EventAdmin eventAdmin) {
+   public static void postEvent(final OteByteMessage message, final EventAdmin eventAdmin) {
+      if(isUIThread()){
+         OseeLog.logf(OteByteMessageUtil.class, Level.INFO, "sending [%s] from the UI thread.", message.getHeader().TOPIC.getValue());
+      } 
       message.getHeader().UUID_HIGH.setNoLog((long) 0x0);
       message.getHeader().UUID_LOW.setNoLog((long) 0x0);
       Map<String, Object> data = new HashMap<String, Object>();
@@ -138,5 +169,37 @@
       props.put("event.topics", signal.getHeader().TOPIC.getValue());
       return context.registerService(EventHandler.class, eventHandler, props);
    }
+   
+   public static <T extends OteByteMessage> ServiceRegistration<EventHandler> subscribe(T signal, OteByteMessageListener<T> eventHandler) {
+      BundleContext context = ServiceUtility.getContext();
+      if (context == null) {
+         return null;
+      }
+      Hashtable<String, Object> props = new Hashtable<String, Object>();
+      props.put("event.topics", signal.getHeader().TOPIC.getValue());
+      return context.registerService(EventHandler.class, new EventHandlerForOteByteMessage<T>(signal, eventHandler), props);
+   }
+   
+   private static class EventHandlerForOteByteMessage<T extends OteByteMessage> implements EventHandler {
+
+      private final T message;
+      private OteByteMessageListener<T> listener;
+      
+      public EventHandlerForOteByteMessage(T message, OteByteMessageListener<T> listener){
+         this.message = message;
+         this.listener = listener;
+      }
+      
+      @Override
+      public void handleEvent(Event arg0) {
+         try{
+            message.getActiveDataSource().getMem().setData(OteByteMessageUtil.getBytes(arg0));
+            listener.onDataAvailable(message);
+         } catch (Throwable th){
+            th.printStackTrace();
+         }
+      }
+      
+   }
 
 }