Java Code to Open a Web Page

Some times the simplest things drive you nuts. 🙂

The Desktop class (java.awt.Desktop) was introduced in Java v1.6. There are occasions when you are running a Java application in JVM 1.6 or higher that the Desktop class is not available or fails to load.

It is just weird and very frustrating. Its not just me. If you do an internet search, you will find lots of people with the same problem and weirdly, Ubuntu is an operating system that has this problem a lot.

I decided to create a simple “wrapper” class to open a web page (URL). First, it will attempt to load the Java Desktop class and if it fails or is not available then it will use the Runtime class to open the web page. My Java class should be able to run in any release of Java (JVM) and on pretty much any platform.

You can download the source code from here. Enjoy. 🙂

/**
 * A simple class to open a web page (URL) in the default web browser.
 * First, it will attempt to use the Desktop class that is available in
 * Java 1.6 or higher.  If it fails or is not available then it will attempt
 * to open the web page using the Runtime class.
 *
 * @author Roger Lacroix
 * @version 1.0.0
 * @license Apache 2 License
 */
public class WebPage
{
   public static void main(String[] args)
   {
        String url = "https://www.google.com";
        WebPage.open(url);
   }

   /**
    * Open a URL in the default web browser.
    * @param url
    * @return true/false
    */
   public static boolean open(String url)
   {
      boolean flag = false;

      try
      {
         /**
          *  Try to load the Desktop Class - only available in Java 1.6 or higher
          *  The code performs the following call:
          *  <code>java.awt.Desktop.getDesktop().browse(url)</code>
          */
         Class<?> cc = Class.forName("java.awt.Desktop");
         cc.getDeclaredMethod("browse", new Class[] { java.net.URI.class }).invoke(
               cc.getDeclaredMethod("getDesktop").invoke(null),
               new Object[] { java.net.URI.create(url) } );

         flag = true;
      }
      catch (Exception skip)
      {  // The Desktop Class either failed to load or is not available.
         String OS = System.getProperty("os.name").toLowerCase();
         Runtime rt = Runtime.getRuntime();
         try
         {
            if (OS.contains("win"))
            {
               rt.exec("rundll32 url.dll,FileProtocolHandler " + url).waitFor();
               flag = true;
            }
            else if (OS.contains("mac"))
            {
               String[] cmd = { "open", url };
               rt.exec(cmd).waitFor();
               flag = true;
            }
            else if (OS.contains("nix") || OS.contains("nux"))
            {
               String[] cmd = { "xdg-open", url };
               rt.exec(cmd).waitFor();
               flag = true;
            }
            else
            {
               System.out.println("Unknown operating system: "+ OS + " : cannot open web page.");
            }
         }
         catch (Exception e)
         {
            e.printStackTrace();
         }
      }

      return flag;
   }
}

Regards,
Roger Lacroix
Capitalware Inc.

Java, Linux, macOS (Mac OS X), Open Source, Programming, Raspberry Pi, Unix, Windows Comments Off on Java Code to Open a Web Page

Java MQ Code to List Channel Status

I thought I posted this code sample but I guess I forgot to do it. 😉

If you have done the runmqsc command for Channel Status for all channels of a queue manager as follows:

DIS CHS(*) ALL

And you wanted to do the same thing via a program, here is a fully functioning Java MQ example that will connect to a remote queue manager, issue a PCF “Inquire Channel Status” command, get the PCF response messages, loop through the PCF responses and output the information. You can download the source code from here.

For more information about the PCF “Inquire Channel Status” command, go to MQ KnowLedge Center here.

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;

import com.ibm.mq.MQException;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.CMQC;
import com.ibm.mq.constants.CMQCFC;
import com.ibm.mq.headers.MQDataException;
import com.ibm.mq.headers.pcf.PCFMessage;
import com.ibm.mq.headers.pcf.PCFMessageAgent;

/**
 * Program Name
 *  MQListChannelStatus01
 *
 * Description
 *  This java class issues a PCF "inquire channel status" request message for all ("*") channels 
 *  of a remote queue manager. 
 *
 * Sample Command Line Parameters
 *  -m MQA1 -h 127.0.0.1 -p 1414 -c TEST.CHL -q TEST.Q1 -u UserID -x Password
 *
 * @author Roger Lacroix
 */
public class MQListChannelStatus01
{
   private static final SimpleDateFormat  LOGGER_TIMESTAMP = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");

   private Hashtable<String,String> params;
   private Hashtable<String,Object> mqht;
   private String qMgrName;

   public MQListChannelStatus01()
   {
      super();
      params = new Hashtable<String,String>();
      mqht = new Hashtable<String,Object>();
   }

   /**
    * Make sure the required parameters are present.
    * @return true/false
    */
   private boolean allParamsPresent()
   {
      boolean b = params.containsKey("-h") && params.containsKey("-p") &&
                  params.containsKey("-c") && params.containsKey("-m") &&
                  params.containsKey("-u") && params.containsKey("-x");
      if (b)
      {
         try
         {
            Integer.parseInt((String) params.get("-p"));
         }
         catch (NumberFormatException e)
         {
            b = false;
         }
      }

      return b;
   }

   /**
    * Extract the command-line parameters and initialize the MQ HashTable.
    * @param args
    * @throws IllegalArgumentException
    */
   private void init(String[] args) throws IllegalArgumentException
   {
      int port = 1414;
      if (args.length > 0 && (args.length % 2) == 0)
      {
         for (int i = 0; i < args.length; i += 2)
         {
            params.put(args[i], args[i + 1]);
         }
      }
      else
      {
         throw new IllegalArgumentException();
      }

      if (allParamsPresent())
      {
         qMgrName = (String) params.get("-m");
         
         try
         {
            port = Integer.parseInt((String) params.get("-p"));
         }
         catch (NumberFormatException e)
         {
            port = 1414;
         }
         
         mqht.put(CMQC.CHANNEL_PROPERTY, params.get("-c"));
         mqht.put(CMQC.HOST_NAME_PROPERTY, params.get("-h"));
         mqht.put(CMQC.PORT_PROPERTY, new Integer(port));
         mqht.put(CMQC.USER_ID_PROPERTY, params.get("-u"));
         mqht.put(CMQC.PASSWORD_PROPERTY, params.get("-x"));

         // I don't want to see MQ exceptions at the console.
         MQException.log = null;
      }
      else
      {
         throw new IllegalArgumentException();
      }
   }
   
   private void doPCF()
   {
      MQQueueManager qMgr = null;
      PCFMessageAgent agent = null;
      PCFMessage   request = null;
      PCFMessage[] responses = null;
      String chlStatus = "Inactive"; 

      try
      {
         qMgr = new MQQueueManager(qMgrName, mqht);
         MQListChannelStatus01.logger("successfully connected to "+ qMgrName);

         agent = new PCFMessageAgent(qMgr);
         MQListChannelStatus01.logger("successfully created agent");
      
         // https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.1.0/com.ibm.mq.ref.adm.doc/q087540_.htm
         request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_CHANNEL_STATUS);
         
         /**
          * You can explicitly set a channel name like "TEST.CHL" or
          * use a wild card like "TEST.*"
          */
         request.addParameter(CMQCFC.MQCACH_CHANNEL_NAME, "*");
         
         // Add a parameter to select the instance type (current)
         request.addParameter(CMQCFC.MQIACH_CHANNEL_INSTANCE_TYPE, CMQC.MQOT_CURRENT_CHANNEL);

         // Add a parameter that selects all of the attributes we want
         request.addParameter(CMQCFC.MQIACH_CHANNEL_INSTANCE_ATTRS, 
                              new int [] { CMQCFC.MQCACH_CHANNEL_NAME,
                                           CMQCFC.MQCACH_CONNECTION_NAME,
                                           CMQCFC.MQIACH_MSGS,
                                           CMQCFC.MQCACH_LAST_MSG_DATE,
                                           CMQCFC.MQCACH_LAST_MSG_TIME,
                                           CMQCFC.MQIACH_CHANNEL_STATUS
                              });

         responses = agent.send(request);
         
         for (int i = 0; i < responses.length; i++)
         {
            if ( ((responses[i]).getCompCode() == CMQC.MQCC_OK) &&
                 ((responses[i]).getParameterValue(CMQCFC.MQCACH_CHANNEL_NAME) != null) )
            {
               //  get the channel name and trim the spaces               
               String name = responses[i].getStringParameterValue(CMQCFC.MQCACH_CHANNEL_NAME);
               if (name != null)
                  name = name.trim();
               
               //  get the channel name and trim the spaces
               String connName = responses[i].getStringParameterValue(CMQCFC.MQCACH_CONNECTION_NAME);
               if (connName != null)
                  connName = connName.trim();
               
               //  get the channel last message date/time
               String lastMsgDate = responses[i].getStringParameterValue(CMQCFC.MQCACH_LAST_MSG_DATE);
               if (lastMsgDate != null)
                  lastMsgDate = lastMsgDate.trim();
               
               String lastMsgTime = responses[i].getStringParameterValue(CMQCFC.MQCACH_LAST_MSG_TIME);
               if (lastMsgTime != null)
                  lastMsgTime = lastMsgTime.trim();

               //  get the channel current messages total
               int totalMsgs = responses [i].getIntParameterValue(CMQCFC.MQIACH_MSGS);

               //  get the channel status
               chlStatus = getChannelStatus(responses [i].getIntParameterValue(CMQCFC.MQIACH_CHANNEL_STATUS));
               
               MQListChannelStatus01.logger("Name=" + name + " : Connection Name=" + connName  + " : Total Messages=" + totalMsgs +  
                                            " : Last Message Date='" + lastMsgDate +  "' : Last Message Time='" + lastMsgTime +
                                          "' : Status='" + chlStatus+"'");
            }
         }
      }
      catch (MQException e)
      {
         MQListChannelStatus01.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
      }
      catch (IOException e)
      {
         MQListChannelStatus01.logger("IOException:" +e.getLocalizedMessage());
      }
      catch (MQDataException e)
      {
         MQListChannelStatus01.logger("MQDataException:" +e.getLocalizedMessage());
      }
      finally
      {
         try
         {
            if (agent != null)
            {
               agent.disconnect();
               MQListChannelStatus01.logger("disconnected from agent");
            }
         }
         catch (MQDataException e)
         {
            MQListChannelStatus01.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
         }

         try
         {
            if (qMgr != null)
            {
               qMgr.disconnect();
               MQListChannelStatus01.logger("disconnected from "+ qMgrName);
            }
         }
         catch (MQException e)
         {
            MQListChannelStatus01.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
         }
      }
   }
   
   private String getChannelStatus(int cs)
   {
      String chlStatus = "Inactive"; 

      switch (cs)
      {
         case CMQCFC.MQCHS_INACTIVE:
            chlStatus = "Inactive";
            break;
         case CMQCFC.MQCHS_BINDING:
            chlStatus = "Binding";
            break;
         case CMQCFC.MQCHS_STARTING:
            chlStatus = "Starting";
            break;
         case CMQCFC.MQCHS_RUNNING:
            chlStatus = "Running";
            break;
         case CMQCFC.MQCHS_STOPPING:
            chlStatus = "Stopping";
            break;
         case CMQCFC.MQCHS_RETRYING:
            chlStatus = "Retrying";
            break;
         case CMQCFC.MQCHS_STOPPED:
            chlStatus = "Stopped";
            break;
         case CMQCFC.MQCHS_REQUESTING:
            chlStatus = "Requesting";
            break;
         case CMQCFC.MQCHS_PAUSED:
            chlStatus = "Paused";
            break;
         case CMQCFC.MQCHS_DISCONNECTED:
            chlStatus = "Disconnected";
            break;
         case CMQCFC.MQCHS_INITIALIZING:
            chlStatus = "Initializing";
            break;
         case CMQCFC.MQCHS_SWITCHING:
            chlStatus = "Switching";
            break;
         default:
            chlStatus = "Unknown ["+cs+"]";
            break;
      }
      
      return chlStatus;
   }

   /**
    * A simple logger method
    * @param data
    */
   public static void logger(String data)
   {
      String className = Thread.currentThread().getStackTrace()[2].getClassName();

      // Remove the package info.
      if ( (className != null) && (className.lastIndexOf('.') != -1) )
         className = className.substring(className.lastIndexOf('.')+1);

      System.out.println(LOGGER_TIMESTAMP.format(new Date())+" "+className+": "+Thread.currentThread().getStackTrace()[2].getMethodName()+": "+data);
   }

   public static void main(String[] args)
   {
      MQListChannelStatus01 mqlqs = new MQListChannelStatus01();
      
      try
      {
         mqlqs.init(args);
         mqlqs.doPCF();
      }
      catch (IllegalArgumentException e)
      {
         MQListChannelStatus01.logger("Usage: java MQListChannelStatus01 -m QueueManagerName -h host -p port -c channel -u UserID -x Password");
         System.exit(1);
      }

      System.exit(0);
   }
}

Regards,
Roger Lacroix
Capitalware Inc.

Capitalware, HPE NonStop, IBM i (OS/400), IBM MQ, Java, Linux, macOS (Mac OS X), Open Source, PCF, Programming, Unix, Windows 3 Comments

Red Hat Enterprise Linux 7.6 Released

Red Hat has just released Red Hat Enterprise Linux 7.6.
https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html-single/7.6_release_notes/

Red Hat Enterprise Linux (RHEL) is a Linux distribution developed by Red Hat and targeted toward the commercial market. Red Hat Enterprise Linux is released in server versions for x86, x86-64, Itanium, PowerPC and IBM Z, and desktop versions for x86 and x86-64. All of the Red Hat’s official support and training, together with the Red Hat Certification Program, focuses on the Red Hat Enterprise Linux platform. Red Hat Enterprise Linux is often abbreviated to RHEL, although this is not an official designation.

Regards,
Roger Lacroix
Capitalware Inc.

Linux, Open Source, Operating Systems Comments Off on Red Hat Enterprise Linux 7.6 Released

Fedora 29 Released

Fedora Project has just released Fedora 29.
https://fedoramagazine.org/announcing-fedora-29/

Fedora is a Linux distribution developed by the community-supported Fedora Project and sponsored by Red Hat. Fedora contains software distributed under various free and open-source licenses and aims to be on the leading edge of such technologies. Fedora is the upstream source of the commercial Red Hat Enterprise Linux distribution.

Regards,
Roger Lacroix
Capitalware Inc.

Linux, Open Source, Operating Systems Comments Off on Fedora 29 Released

IBM announced plans to buy Red Hat

This is interesting. IBM announced it will buy Red Hat for $34 Billion.
https://arstechnica.com/information-technology/2018/10/ibm-buys-red-hat-with-eye-on-cloud-dominance/

Regards,
Roger Lacroix
Capitalware Inc.

Linux, Open Source, Operating Systems Comments Off on IBM announced plans to buy Red Hat

So You Secured MQ But How Do You Know It Is Secure?

As the MQ Technical Conference V2.0.1.8 t-shirts said “MQAdmin: the superhero of middleware messaging!“. Since, you are a “superhero”, you have secured your MQ environment. You have implemented CHLAUTH and/or CONNAUTH features in IBM MQ. So, give yourself a pat on the back, a gold star or have another cold one on you because you deserve it – you’re the middleware superhero who has implemented security for IBM MQ.

Question: How do you know it is secure? Seriously! MQ does not tell you it is secure. If someone connects with a valid UserId and Password but shouldn’t have connected to the production queue manager, the “superhero” will never know. Why? Because MQ doesn’t care about successful connections.

On the other hand, a good security auditor will care. They will want to know who is connecting – both successfully and unsuccessfully. If your company’s security auditor decided that your company’s MQ environment needed a security review, you can extract the error messages related to unsuccessful login attempts from the queue manager’s AMQERR01.LOG file (which may only hold the last few hours of information) but that is it. There is no information about successful connections.

Now some people will say, I’ll just issue the MQSC command to display the connections. Sure, that will let you see who is currently connected to the queue manager but it will not tell you who was connected 5 minutes ago or 1 hour ago or at 3:00AM. You will have absolutely no clue that a rogue user previously successfully connected, get and/or put messages to 1 or more queues, then disconnected.

So, still feeling “super”?

Around a year ago, a couple of Capitalware’s MQ Authenticate User Security Exit (MQAUSX) customers said that their management wanted them to start to use CHLAUTH and CONNAUTH which are included free with MQ rather than continue to use MQAUSX and pay for support. I would point out that MQAUSX has far more features and more robust features than what CHLAUTH and CONNAUTH offer but alas management only looks at the price and free is better than paying.

The MQAdmins came back to me and said that they missed having the MQAUSX logging of connection attempts. Since, their management won’t pay for MQAUSX, they have no way to verify that connections were legitimate. I suggested to them that they use MQ Auditor but they only wanted to track connections not everything in MQ and others said they need it on z/OS (mainframe). Since, MQ Auditor is an MQ API Exit, IBM does not support API Exits on z/OS, that was a no go.

I decided to create MQ Channel Connection Inspector (MQCCI). MQCCI uses a MQ Channel Security Exit like MQAUSX. A channel security exit is ONLY invoked/called by the queue manager’s MCA (Message Channel Agent) for MQCONN/X and MQDISC API calls (so it is very light-weight) and channel security exit is available on z/OS.

I decided to use the audit record format from MQ Auditor for MQCCI. And like MQ Auditor, MQCCI can write the audit information to either a file or to a queue. For each connection attempt, MQCCI will output 1 plain text CSV (Comma Separate Value) line.

If the MQAdmin uses the default values for MQCCI, this is what the audit record would look like for a connection attempt:

2018/09/14 18:07:00.654884, CONN, Tag=F4Evlx0T6ComjD20, CD_QMgrName=MQWT1, CD_ChannelName=TEST.CHL, CD_ConnectionName=127.0.0.1, , CD_ShortConnectionName=127.0.0.1, CD_MaxMsgLength=4194304, CD_PutAuthority=MQPA_DEFAULT, CD_MCAUserIdentifier=roger, CD_RemoteUserIdentifier=roger, CD_RemotePassword_Length=0, CD_SSLCipherSpec=, CD_SSLClientAuth=MQSCA_REQUIRED, CD_CertificateLabel=, CXP_PartnerName=roger, CXP_SSLCertUserid=, CXP_SecurityParms_AuthenticationType=MQCSP_AUTH_USER_ID_AND_PWD, CXP_SecurityParms_UserId=roger, CXP_SecurityParms_Password_Length=8, CXP_SharingConversations=TRUE, CXP_MCAUserSource=MQUSRC_MAP, CXP_RemoteProduct=MQJB, CXP_RemoteVersion=0800,

Optionally, the MQAdmin can select to have the MQDISC audit records as well. And this it what it would look like:

2018/09/14 18:07:02.161509, DISC, Tag=F4Evlx0T6ComjD20, CD_QMgrName=MQWT1, CD_ChannelName=TEST.CHL, CD_ConnectionName=127.0.0.1, Duration=1.506625,

For the default MQCD and MQCXP fields outputted by MQCCI, I tried to select the most relevant fields but the MQAdmin can have MQCCI outputted any field from the MQCD and MQCXP structures.

Here is an interesting footnote but not related to a security audit. Generally speaking, before an application is deployed, the MQAdmin will ask the application team “if the application connects and stays connected to the queue manager“. The application team will say “Yes“. But how do you verify this statement?

With MQCCI, you can review the audit file and see if the application only connected once or did it “connect then disconnect”, “connect then disconnect”, “connect then disconnect”, etc..

Not only is MQCCI good for security audits but it can also be used to identify poorly written applications.

  • MQCCI is available for AIX, HP-UX, IBM i (OS/400), Linux (x86, x86_64, Power and System z), Solaris (SPARC and x86_64) and Windows.
  • MQCCI for z/OS is available for z/OS v1.4 or higher.

For more information about MQCCI, please go to:
https://www.capitalware.com/mqcci_overview.html or MQCCI for z/OS

Note: We offer free a 60-day trial of MQCCI and MQCCI for z/OS which includes free support. If you interesting in trying it out, please send an email to support@capitalware.com to request a trial of it.

Regards,
Roger Lacroix
Capitalware Inc.

Capitalware, IBM i (OS/400), IBM MQ, Linux, MQ Channel Connection Inspector, Security, Unix, Windows, z/OS Comments Off on So You Secured MQ But How Do You Know It Is Secure?

OpenBSD v6.4 Released

Theo de Raadt has just released OpenBSD v6.4.
http://www.openbsd.org/64.html

The OpenBSD project produces a FREE, multi-platform 4.4BSD-based UNIX-like operating system. Our efforts emphasize portability, standardization, correctness, proactive security and integrated cryptography.

Regards,
Roger Lacroix
Capitalware Inc.

Open Source, Operating Systems Comments Off on OpenBSD v6.4 Released

Ubuntu 18.10 Released

Ubuntu has just released Ubuntu v18.10.
http://releases.ubuntu.com/18.10/

Super-fast, easy to use and free, the Ubuntu operating system powers millions of desktops, netbooks and servers around the world. Ubuntu does everything you need it to. It’ll work with your existing PC files, printers, cameras and MP3 players. And it comes with thousands of free apps.

Regards,
Roger Lacroix
Capitalware Inc.

Linux, Open Source, Operating Systems Comments Off on Ubuntu 18.10 Released

Language Wars – Maybe Enough Already

Maybe I’m just old and grumpy, but I’m tired of surfing the internet and seeing language wars. I just saw this line “100% Java free!” the other day, listed as a product feature and it makes me shake my head. Of all the product features that would sell a product, you want to include that one?!?

There are programming languages for: scripting, back-end applications, front-applications, web containers, cloud, utilities, etc. One programming language does not cover all these use-cases. Although, someone people like to think so. 🙂

Most of my work day, I write code. 47% of my programming time is writing ‘C’ code, 47% of my programming time is writing ‘Java’ code and the remaining time is writing ‘C#’, ‘REXX’ and ‘PHP’ code. REXX is a great scripting language. It just doesn’t get the love it desires, probably because it originated on the mainframe – lack of exposure.

The programming language I use will depend on what I’m trying to accomplish. If it is a GUI desktop application or requires threading, I will choose Java because it is so much easier to do than ‘C’. This is especially true if I want it to run on other non-Windows desktops (ie. Linux or macOS). Of course, I can if/def the hell out of my ‘C’ code to accomplish it but why go through the aggravation.

The biggest complaint people have against Java is the JVM (Java Virtual Machine) load/startup time. There are thousands of web pages that talk about the startup of a JVM taking longer to load/start than a native ‘C’ application. Eclipse is usually the poster-child of this issue. This is all true. But who in the world cares if a desktop application loads in 0.5 seconds vs 2.0 seconds. Maybe you would care if it was a back-end application that was being launched every second but on the other hand, what the hell kind of application design is that? It should start and use threading. There are far, far too many novice/newbie programmers creating junk applications that somehow end up in production. I digress. Ok, back to JVM startup time. If you are using a desktop application during your work day (i.e. 8 hours), is there really an issue with the startup time? Maybe, just take another sip of your coffee, soda, green tea or water and then it will be loaded/started. 🙂

I created and sell 4 Java desktop applications: MQ Visual Edit, MQ Visual Browse, MQ Batch Toolkit and MQTT Message Viewer. Plus I have many helper (utilities) Java desktop applications for the various back-end solutions that I sell. Why Java? I want cross-platform execution and the ability to easily code “good looking” (aka modern) GUI applications.

A long time ago, I had some customers doing things with my Java applications that they shouldn’t have been doing. So, I decided to spend the money and purchase Excelsior Jet. Excelsior Jet compiles and links Java applications into native executables. I originally just purchased Excelsior Jet for Windows and Linux. After using it for a while, I decided to take the plunge and purchase it for macOS too. Besides IP (Intellectual Property) protection, using Excelsior Jet to compile and link the Java applications to native executables means that the startup/load times is on par with regular native applications.

Why macOS for an MQ application? Because shocking as it may seem, the break down of MQ Visual Edit end-user desktops is: 80% Windows, 13% macOS and 7% Linux. Yes, there are far more people using MQ Visual Edit on macOS than on Linux. Rather shocking if you ask me!

I use Eclipse to write all of my C and Java code. I use makefiles for my C applications and Eclipse executes the build process (makefile) as I save my code. For Java, everything is built into it for compiling Java code to classes and for testing (very nice). I have a separate makefile which I use to build the native executable using Excelsior Jet on Windows. For Linux and macOS, I copy the updated JAR to the respective OS and then run a similar makefile to create the native executable for that particular OS.

When Excelsior Jet compiles an application, it sucks in everything required to build the native application. So, what does that mean?

  1. It means that MQ is NOT required on the end-user’s desktop PC/laptop.
  2. Nor is Java. That’s right, Java/JVM is NOT required on the end-user’s desktop PC/laptop. It is because the Java application is compiled as a native application. 🙂

So, when I see comments like “100% Java free!“, I think that someone is stuck in the 90’s. There are millions of Java applications available that do thousands and thousands of useful things including games. (Of course, there are lots of poorly written Java, C/C++, C#, Python, PHP, Swift, etc. applications.) Over the years, first Sun then Oracle improved the startup/load time of the JVM. Hence, the slow load/startup time is not as much of an issue as it use to be but it is still there. For developers, who want to go that extra mile, there is always Excelsior Jet.

Can we stop with the language wars? Because for every complaint about Java applications, I can point to just as many poorly written and/or designed C/C++, C#, Python, PHP, Swift, etc. applications. So, lets move on. There is no need to go to war over which language to use or which is better. Use a language that is best suited for the job and don’t try to fit a square peg into a round hole.

Regards,
Roger Lacroix
Capitalware Inc.

.NET, Assembler, C, C#, C++, IBM MQ, Java, JMS, Linux, macOS (Mac OS X), MQ Batch Toolkit, MQ Visual Browse, MQ Visual Edit, MQTT, MQTT Message Viewer, Perl, Programming, Raspberry Pi, Rexx, Swift, Unix, Windows 2 Comments

SSL/TLS for capitalware.com

Capitalware’s web site has been available as a secure (“https”) web site for several months. In the Summer, I tried turning on the auto redirection from “http” to “https” but it broke my online registration code in MQ Visual Edit, MQ Visual Browse, MQ Batch Toolkit and MQTT Message Viewer. I fixed the issue a couple of months ago and now the code uses a secure connection to capitalware.com.

Note: The issue does NOT affect regular use of any of the products just the online registration via the Registration window in the product (or register command for MQ Batch Toolkit).

Therefore, on November 1st, 2018, I will be turning on the auto redirection from “http” to “https” for capitalware.com web site.

Hence, if you want to perform a product registration after November 1st, 2018, you MUST be running the following version of the product:

  • MQ Visual Edit v2.4.0.1 or higher
  • MQ Visual Browse v2.4.01 or higher
  • MQ Batch Toolkit v3.1.0.1 or higher
  • MQTT Message Viewer v1.3.0.1 or higher

Yes, I will be sending out email alerts to all activate users of the below mentioned products.

To activate users, you have the download link with the UserId and Password for the commercial release of the product, simply follow the instructions in Appendix B of the product’s User Guide on how to handle the upgrade (i.e. un-install then install).

Regards,
Roger Lacroix
Capitalware Inc.

Capitalware, MQ Batch Toolkit, MQ Visual Browse, MQ Visual Edit, MQTT Message Viewer, Security Comments Off on SSL/TLS for capitalware.com