Page 1 of 1

Linux problem with RMIR

Posted: Wed Aug 05, 2020 8:24 am
by mathdon
I have started to learn more about Linux, and to do so I now have set up a machine with 64-bit Ubuntu 20.04. I am having the following problem with RMIR and should like to fix it. I have found that the three shortcuts created by setup.sh all open the intended applications but that the alternative way of opening RM from RMIR with the menu item File > New > Device Upgrade does not work. The relevant bits of code are:

Code: Select all

  public static File getJreExecutable()
  { 
    String jreDirectory = System.getProperty( "java.home" ); 
    File javaExe = null; 
    if ( System.getProperty( "os.name" ).startsWith( "Windows" ) )
    { 
      javaExe = new File( jreDirectory, "bin/javaw.exe" ); 
    }
    else 
    { 
      javaExe = new File( jreDirectory, "bin/javaw" ); 
    } 
    if ( !javaExe.exists() )
    { 
      return null; 
    } 
    return javaExe;
  } 
  
  private static void runKM( String filename )
  {
    File javaExe = getJreExecutable();
    if ( javaExe == null )
    {
      System.err.println( "Unable to find java executable" );
      return;
    }
    try
    {
      Runtime r = Runtime.getRuntime();
      String classPath = System.getProperty( "java.class.path" );
      r.exec( new String[] { javaExe.getCanonicalPath(), "-cp", classPath, "com.hifiremote.jp1.RemoteMaster", "-rm", "-home", workDir.getAbsolutePath(), filename } );
    }
    catch ( IOException e )
    {
      e.printStackTrace();
    }
  }

A search of the web found one issue. Apparently javaw does not exist in Linux and one should use java instead. So before the line if ( !javaExe.exists() ) I have added

Code: Select all

    if ( !javaExe.exists() )
    {
      javaExe = new File( jreDirectory, "bin/java" ); 
    }
This has got rid of the error "Unable to find java executable" that I was getting, but it still does not work. Can any Linux expert help me on this?

Edit: I am using openJDK build 1.8.0_252.

Posted: Wed Aug 05, 2020 8:51 am
by gfb107
I'm no Linux expert, but it seems to me the fix is to try to find "bin/java" when the OS is not Windows:

Code: Select all

    if ( System.getProperty( "os.name" ).startsWith( "Windows" ) )
    {
      javaExe = new File( jreDirectory, "bin/javaw.exe" );
    }
    else
    {
      javaExe = new File( jreDirectory, "bin/java" );
    }

Beyond that, I would start by checking the value of classPath.

Posted: Wed Aug 05, 2020 9:22 am
by Barf
Actually, I noted the problem a few months ago, but never got around to complain...

With the fix, I cannot tell on top on my head why it does not work. The debugger is your friend... If you need help, point me to the exact version.

BUT, this is not a very good way to solve that problem. The normal way would be to start the RM as a thread (java.lang.Thread) within the same JVM. To start another JVM with Runtime.exec is extremely error prone. For example, there is nothing that guarantees that the JVM binary is found as System.getProperty( "java.home" )/bin/java[w.exe]. The (original) JVM can have arguments, these are not propagated, etc. You cannot communicate with the child process, neither can you know if it is finished or not.

Posted: Wed Aug 05, 2020 10:52 am
by mathdon
Barf wrote:You cannot communicate with the child process, neither can you know if it is finished or not.
That is the intention. The idea is that this will open a completely stand-alone instance of RM, so you can close the original RMIR and just work with the new RM. It used to be done differently, a (very) long time ago. There is still a note in RemoteMaster.java that says:

Code: Select all

     // Opening KM as a new instance of KeyMapMaster makes it share the same
      // ProtocolManager as RM, which results in crosstalk when one edits the protocol
      // used by the other.  Replaced now by opening KM as a new application.
      
//    KeyMapMaster km = new KeyMapMaster( properties );
//    km.loadUpgrade( file );
I'm unclear exactly what opening a new thread would do, but something in between the old and new versions, I suspect.

I will continue to investigate.

Posted: Thu Aug 06, 2020 6:23 am
by mathdon
Solved. The problem appears to have been caused by a difference of behaviour between Java in Windows and Linux. RMIR main(...) processes its arguments with the loop

Code: Select all

    for ( String arg : args )
    {
      if ( "-version".startsWith( arg ) )
      {
        System.out.println( getFullVersion() );
        return;
      }
      else
      {
        parms.add( arg );
      }
    }
runKm(String filename) opens its new instance of RMIR with a final argument of filename. File > New > Device Upgrade calls runKm(""). "-version".startsWith("") evaluates true in Linux but presumably false in Windows, so in Linux this menu item outputs the full version and then returns, rather than opening RM. I have added

Code: Select all

    if ( arg.isEmpty() )
        continue;
at the beginning of this loop and it now works as intended.

Is this matching behaviour to an empty string a known difference between Java in Windows and Linux?

Posted: Thu Aug 06, 2020 11:40 am
by mathdon
The fix is in development build 10, in the usual folder and also in the SVN. I realize now that there are various Java distros in use in Linux. Mine, with the behaviour I described, is openJDK build 1.8.0_252. The fix will work whichever way string matching handles empty strings.