Announcement

Collapse
No announcement yet.

Question to Mirth pro's! How to set TCP Listener port and encoding programatically?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Question to Mirth pro's! How to set TCP Listener port and encoding programatically?

    In the Mirth GUI it's not possible to use a velocity variable like ${port} in a TCP Listener's port field even though it's a text field. Also, the encoding is a dropdown menu so I cannot input a variable there.

    Or did I miss something?

    That's why I have an idea for a different approach: Is it possible to modify the channel's settings programatically = during runtime?

    Example: Read the channel's TCP Listener port (source connector setting) in the deploy script, compare it with a variable's value (e.g. from the configMap like $cfg('port')) and if both don't match, re-set the port setting and re-deploy the channel.

    Partly this can be done by ChannelUtil (re-deploy): http://javadocs.mirthcorp.com/connec...annelUtil.html

    But how to get/set a connector setting?

  • #2
    You can use a velocity variable for the port, but only certain maps are available to the source connector. You should have access to the configurationMap, globalMap, and globalChannelMap. I just tested on mirth 3.5.1 using $gc('port', '65321') in the deploy script to verify. The configurationMap values are always strings, but be careful about putting numeric values into one of the global maps or it may get read as a floating point number and add '.0' to the end of your port number when converting to a string.

    You are right about the encoding not being variable. What is your use case where you need to change this in the channel definition programatically at deploy time? Maybe you could set it to binary and encode it in the pre-processor?

    Binary will base64 encode the data, so your pre-processor script could be:
    Code:
    var encoding = 'UTF-8'; // or read from map
    return new java.lang.String(FileUtil.decode(message), encoding);

    Comment


    • #3
      Regarding $gc('port'): yeah it works! But only if you put in a Java integer into the $gc map. Examples in the deploy script:

      Will NOT work: $gc('port', '43210')
      Will work: $gc('port', 43210)

      Means I have to convert strings from configMap to Java Interger like this: $gc('port', java.lang.Integer($cfg('PORT')));

      Great, thanks!

      Regarding encoding: I had the same idea... will try it! But then I also need to check how I do the encoding for a TCP Sender.

      Comment


      • #4
        I'm doing now this is the Preprocessor script:
        Code:
        // set dynamic decoding e.g. using configMap
        // http://www.mirthproject.org/community/forums/showthread.php?p=272041
        // requires that Source connector receives binary data type (message will be base64-encoded), NOT text
        var decoding = $cfg('_DECODING'); // set decoding, here from configMap
        var rawString = FileUtil.decode(message); // decode base64 encoded message (returns bytes)
        return new java.lang.String(rawString, decoding); // decode bytes using dynamic decoding (returns string)
        The problem is that the inbound message at the source connector is like this:
        Code:
        TVNIfF5+XCZ8Rk9PfHxCQVJ8fDIwMjAwMzMwMTczMTUyfHxBRFReQTAxfEhNQnBLOGM4UUtnWnlx
        VFRaMm5rVFhTdHxQfDIuNy4xDVBJRHx8fHx8w7zDpMO2w5zDhMOWw5/DocOgw6LDqcOow6rDrcOs
        w67Ds8Oyw7TDusO5w7sN
        Now Mirth does "Auto-generate (Before processing)" the ACK response. The problem is that the ACK is created from the original inbound message (base64 encoded) instead of the preprocessed string. The ACK looks like this and is invalid:
        Code:
        MSHIfF5+IMIRTHIIwMjAwMzMwMTczMTUyII20200331101252.168IIACKffACKI20200331101252.168IPI2.4
        MSAIAAI1
        Of course, I could now also manually create the ACK instead of auto-create... but all of this shows that a lot of effort is needed to override Mirth's default behavior.

        Also, I want to control even more channel settings dynamically, not just decoding/encoding and port. I have some cases where the customer's sender will produce errors if it receives an ACK reponse... so I need to disable the response in the source connector (don't ask why, I have to adapt to this situation).

        Overall: My goal is to have one single channel that I can rollout to many customers.

        Back to the question: Does Mirth provide a package/class to control the channel settings, similar to `ChannelUtil`?


        Another idea is to query Mirth's REST APIs in order to read the channel's settings. From there I could programatically change some settings and use the API to modify the channel. But this is a long way round... I thought a built-in package could solve this with less effort.

        Comment


        • #5
          Took me a wile and still don't find it the best approach... but now I'm reading the channels' own settings using Mirth's client API (result is XML) in its deploy script and compare the settings against my desired values (like port, encoding, etc.). If they don't match I modify the XML, write it back using the client API and re-deploy the channel using `ChannelUtil`.

          At least, using this approach, I can modify any channel settings programatically and I'm happy so far because I don't have these workarounds.

          If anyone here knows if there's also an "internal" and more Java/Mirth-like way how to get/set channel settings then I'd be glad to hear.

          Or at least if anyone knows where I could lookup this I'd be also thankful. I found some undocumented packages like com.mirth.connect.server.controllers but still unsure, also see links here and here.
          Last edited by droptix; 03-31-2020, 12:41 PM. Reason: added links

          Comment


          • #6
            You can definitely do it with the controllers. The Client API ends up calling the controllers behind the scenes, but they are not part of a public API and are subject to change without notice, though they rarely do. The biggest benefit to calling the controllers directly is that you don't need to log in, but you can only access the local instance.

            If you want to stick with the public API and have a more Java/mirth way of doing it rather than working with http and xml, you can use the com.mirth.connect.client.core.Client class. That is how both the Administrator GUI and CLI clients call the Client API. It will convert between xml and java objects so you don't need to work with the xml directly. These are the same java objects you would be getting from the controllers.

            Comment


            • #7
              Great, I found this and it's very helpful:

              https://www.mirthcorp.com/community/...d.php?t=219379

              If I knew this earlier then it would have save me lots of hours... Here's my code:
              Code:
              // https://www.mirthcorp.com/community/forums/showthread.php?t=219379
              // https://github.com/nextgenhealthcare/connect/blob/3.8.x/server/src/com/mirth/connect/model/ChannelExportData.java
              
              var client = new com.mirth.connect.client.core.Client("https://localhost:8443");
              client.login("admin", "admin");
              
              var channel = client.getChannel(channelId);
              logger.debug("channel: " + channel.getExportData());
              How can I serialize the result to XML?

              (I found `Serializable` but cannot find it in the source code)

              Comment


              • #8
                Code:
                var serializer = com.mirth.connect.model.converters.ObjectXMLSerializer.getInstance();
                logger.debug("channel: " + serializer.serialize(channel.getExportData()));
                You should be able to modify the java objects and call the appropriate Client update methods without serializing to xml. The Client class will take care of that for you.

                Comment


                • #9
                  Hum, doesn't really help. It returns:
                  Code:
                  <com.mirth.connect.model.ChannelExportData/>
                  Instead I need wither an XML object (node) or the XML as string.

                  I'd like to solve this on my own but don't have a browseable documentation... I mean where object types are linked so I can directly jump to their docs. Is this available somewhere? Or a "full" mirth java doc?

                  Comment


                  • #10
                    I'm not aware of a full javadoc. I think the actual source code is going to be your friend here. I have a local clone of the git repo and use vscode for browsing. It helps in jumping to references and definitions.

                    See this thread for a little more info about the problem you are experiencing.

                    Comment


                    • #11
                      The linked thread shows that `ChannelExportData`is not the full representation of the channel as XML but only a part of it... if this is true then I'm doing completely wrong :-/

                      The docs also show that the export data seem to contain some metadata and properties but not the channel settings itself.

                      Then I need to modify my request: Can I retrieve the same XML structure of the channel like I'm getting from the REST API but using Mirth-internal classes instead of API?

                      Sorry, as I'm a Java newbie it's really hard to "browse" the source code without having linked references... it's also a pity that the source doesn't include any docstrings so it's hard to understand how everything is linked and what each component is meant for.

                      Comment


                      • #12
                        I'm not sure if I understand what you're after, then. You are getting the same results as the REST API. If you serialize channel, rather than channel.getExportData() is that what you're looking for?

                        Comment


                        • #13
                          Originally posted by agermano View Post
                          I'm not sure if I understand what you're after, then. You are getting the same results as the REST API. If you serialize channel, rather than channel.getExportData() is that what you're looking for?
                          Yes sometimes it's so easy, great and thanks!

                          So, for the next one looking for this, my code is as follows:
                          Code:
                          var client = new com.mirth.connect.client.core.Client("https://localhost:8443");
                          client.login("admin", "admin");
                          
                          var channel = client.getChannel(channelId);
                          
                          var serializer = com.mirth.connect.model.converters.ObjectXMLSerializer.getInstance();
                          var xml = serializer.serialize(channel);
                          logger.debug("xml: " + xml.toString());
                          var channelSettings = new XML(xml);
                          
                          // now you can "browse" the xml nodes...
                          Last edited by droptix; 05-25-2020, 11:59 PM.

                          Comment


                          • #14
                            OK, now even better without using the client (which I guess is using a HTTP connection in the background) but the server's controller classes instead:

                            Code:
                            var channelController = Packages.com.mirth.connect.server.controllers.ChannelController.getInstance();
                            var channel = channelController.getChannelById(channelId);
                            var serializer = com.mirth.connect.model.converters.ObjectXMLSerializer.getInstance();
                            var xml = serializer.serialize(channel);
                            logger.debug("xml: " + xml.toString());

                            Comment


                            • #15
                              OK, great, now I can READ a channel into XML and modify any settings. Happy so far.

                              The last missing piece for me is now how can I do the reverse thing? Imagine I have a XML representing a channel and want to update an existing channel...

                              ... no, wait, I think I can now read the source code and found the following solution -> happy to share:

                              Code:
                              // De-serialize XML to channel object
                              var obj = serializer.deserialize(xml, Packages.com.mirth.connect.model.Channel);
                              channelController.updateChannel(obj, null, true);
                              ChannelUtil.deployChannel(channelId);
                              IT WORKS!!!

                              Would be happy if you pro's can take a look at the code and give some advise or suggestions for optimization. Thanks!

                              Comment

                              Working...
                              X