Friday, May 22, 2015

WebSphere MQ Client throws 2035 (MQRC_NOT_AUTHORIZED) after upgrading MQ QueueManager to version 8


It took me a while to figure out, so here is a solution to this issue:

Problem: after an upgrade (or rather uninstall/install) of an MQSeries Queue Manager to Version 8.0.0, my C application suddenly complains about being not authorized: 

MQCONNX(qmgr=,MQCNO_STANDARD_BINDING) - reason: 2035 (MQRC_NOT_AUTHORIZED)

Now, the issue, it seems is that with MQ Verson 8, by default, the administrator must have user id and password set if he uses the MQ Client connection. I'm not here to judge, but you should read this 

To be sure your issue is the same as mine, check your error log in C:\ProgramData\IBM\MQ\qmgrs\QM1\errors\AMQERR01.LOG:

----- amqzfuca.c : 4107 -------------------------------------------------------
5/22/2015 10:12:55 - Process(27776.20) User(apodehl) Program(amqzlaa0.exe)
                      Host(BERLIN) Installation(Installation1)
                      VRMF(8.0.0.0) QMgr(QM1)                     
AMQ5541: The failed authentication check was caused by the queue manager
CONNAUTH CHCKCLNT(REQDADM) configuration.
EXPLANATION:
The user ID 'apodehl' and its password were checked because the user ID is
privileged and the queue manager connection authority (CONNAUTH) configuration
refers to an authentication information (AUTHINFO) object named
'SYSTEM.DEFAULT.AUTHINFO.IDPWOS' with CHCKCLNT(REQDADM). 



Solution: be aware of the security implications, but you can change this authentication in the WebSphere MQ Explorer -> QM1 -> Authentication Information, choose SYSTEM...IDPWOS and set "Check client connections" to be "None" instead of 'Required for Adminstrators' 


Tuesday, September 16, 2014

How to secure a password file on Windows 7 (JMX interface of ActiveMQ, to be specific)

This took me a while to figure out, so here's a description of how to make use of a password-protected JMX interface with ActiveMQ (5.8 in my case).

1. Make sure your activemq.xml specifies that you actually want to allow JMX monitoring:
   <managementContext>
        <managementContext createConnector="true" connectorPort="1098"/>
   </managementContext>

2. Change activemq.bat startup script to specify an explicit password files:

set SUNJMX=-Dcom.sun.management.jmxremote.port=1098
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.password.file=%ACTIVEMQ_BASE%/conf/jmx.password
-Dcom.sun.management.jmxremote.access.file=%ACTIVEMQ_BASE%/conf/jmx.access

when you start ActiveMQ, you will probably get this error now:

> activemq.bat
Error: Password file read access must be restricted: .../conf/jmx.password

ActiveMQ requires the password file to have specific user-only permissions, see here for more information. Unfortunately this link is for Windows XP, so here's what to do on Windows 7

I've actually found two solutions, one graphical, the other one from the command line:

Solution (using Windows Explorer):

1) change the owner to be 'you' (required step!!)
Select jmx.password, Right-Mouse-Cick -> Properties -> Security -> Advanced -> Owner -> Edit
and select the single owner of this to be your username.

Note: you need to click OK and exit out of Properties for this to be effective

2) Select jmx.password, Right-Mouse-Cick -> Properties -> Security -> Advanced -> Change Permissions 

- uncheck "Include inheritable permissions" and click Remove to remove all inherited permissions
- then click Add... to add read/write permissions for only your user: Enter your username as object name, and select for example 'Full Control'. Click Ok and exit out of properties.


Solution (using Windows command line):

1) open a windows command prompt in your ActiveMQ 'conf' folder.


2) use icacls (run 'icacls' without options for help) to change the owner to be 'you', in my case:

icacls jmx.password /setowner apodehl


3) remove all inherited permissions:

icacls jmx.password /inheritance:r


4) grant minimal permissions to your user (read/write in this case):

icacls jmx.password /grant:r apodehl:(r,w)



Monday, September 8, 2014

A simple disk performance test

Test the I/O performance by writing several messages to the current directory
The files created are named writetest..dat and should be removed after the test !!

Usage: writetest
       Will write buffers of size each and print the rate every msgs.
       The test is repeated times and the used time is displayed
Example: writetest async 1000000 100000 100 1



#include
#include
#include
#include

#ifdef WIN32
#include
#else
#include
#endif

#include // for S_IRUSR and S_IWUSR

#include

#ifndef WIN32
  #include
  #include
#else
  #include
#endif

#include
#include

#pragma warning(disable : 4996)  // we want to keep the same code for Unix

using namespace std;

class MsgTimer
{
public:

  MsgTimer( const char* applname ) {
    m_startTime = 0.0;
    m_lastTime = 0.0;
    m_endTime = 0.0;
    m_numMsgs = 0;
    strcpy( m_applName, applname );
  }

  ~MsgTimer() { };

  // --- timer starts now ---
  void start() {
 
    m_startTime = getTimeInSeconds();
    m_lastTime = m_startTime;

    cerr << "\n" << m_applName << ": ###### MsgTimer started" << endl;
    printTimestamp();
  }

  // --- specify the number of processed messages ---
  void stop( long numMsgs ) {

    m_endTime = getTimeInSeconds();
    m_lastTime = m_endTime;
    m_numMsgs = numMsgs;

    cerr << "\n" << m_applName << ": ###### MsgTimer stopped after processing " << numMsgs << " messages " << endl;
    printTimestamp();
    printResult();
  }

  // --- specify the number of processed messages ---
  // returns current msgs/sec
  double  current( long numMsgs ) {

    double currentTime = getTimeInSeconds();

    double elapsedTime, mps;

    elapsedTime = currentTime - m_startTime;
    if( elapsedTime > 0.0 ) mps = (double)numMsgs / elapsedTime;
    else mps = 0.0;
    cerr << m_applName << ": ###### Accumulated Number of msgs : " << m_numMsgs << endl;
    cerr << m_applName << ": ###### Accumulated Elapsed time in sec: " << elapsedTime << endl;
    cerr << m_applName << ": ###### Accumulated Msgs-per-sec: " << mps << endl;

    elapsedTime = currentTime - m_lastTime;
    if( elapsedTime > 0.0 ) mps = (double)(numMsgs-m_numMsgs) / elapsedTime;
    else mps = 0.0;
    cerr << m_applName << ": ###### Number of msgs since last call: " << numMsgs - m_numMsgs << endl;
    cerr << m_applName << ": ###### Partial Elapsed time in sec: " << elapsedTime << endl;
    cerr << m_applName << ": ###### Partial Msgs-per-sec: " << mps << endl;

    m_numMsgs = numMsgs;
    m_lastTime = currentTime;
    return mps;
  }

  // --- prints a timestamp in a common format ---
  void printTimestamp() {

    time_t t;
    char* buf;
    t = time(NULL);
    //ctime_r(&t,buf);
    //buf[strlen(buf)-1]='\0';
    buf = ctime(&t);
    cerr << m_applName << ": ###### Timestamp: " << buf << endl;
  }


  static double getTimeInSeconds() {

    double t0,t1,t2;

#ifndef WIN32
    int r;
    struct timeval tp;
    struct timezone tzp;
    r = gettimeofday(&tp,&tzp);
    if (-1 == r) {

      cerr << "gettimeofday() failed" << endl;
      exit(-1);
    }

    t1 = (double)tp.tv_sec;
    t2 = (double)tp.tv_usec;
    t0 = t1+ t2/1000000;
#else
    struct _timeb tp;
    _ftime(&tp);

    t1 = (double)tp.time;
    t2 = (double)(tp.millitm/1000.0);
    t0 = t1+t2;
#endif

    return (t0);
  }

private:

  // --- prints the result in a common format ---
  void printResult() {

    double elapsedTime,mps;
    elapsedTime = m_endTime - m_startTime;

    if( m_numMsgs <= 0 ) {

      cerr << "MsgTimer::stop() was not called !" << endl;
      return;
    }

    if (elapsedTime > 0.0) {

      mps = (double)m_numMsgs / elapsedTime;

    }
    else {

      mps = 0.0;
    }

    cerr << m_applName << ": ###### Final Elapsed time in sec: " << elapsedTime << endl;
    cerr << m_applName << ": ###### Final Number of msgs : " << m_numMsgs << endl;
    cerr << m_applName << ": ###### Final Msgs-per-sec: " << mps << endl;
  }


  double m_startTime;
  double m_lastTime;
  double m_endTime;
  long m_numMsgs;
  char m_applName[512];
};


MsgTimer mt("writetest");

int isSync = 0;
char buffer[1024*1024];

void _testWrite( int cnt, int nummsgs, int printrate, int msgsize )
{
  char filename[30];
  int msgCount;
  int fd;

  sprintf( filename, "writetest.%d.dat", cnt );

  int oflags = O_RDWR | O_CREAT;

#ifdef WIN32
  int pmode = _S_IREAD | _S_IWRITE;
#else
  // this flag exists only on Unix
  if( isSync==1 ) oflags = oflags | O_SYNC;
  mode_t pmode = S_IRUSR | S_IWUSR;
#endif

  fd = open( filename, oflags, pmode );
  if( fd==-1 ) {
    fprintf( stderr, "writetest: Could not create file %s, maybe you did not remove a former instance ?\n", filename );
    exit(1);
  }

  mt.start();
  for( msgCount=0; msgCount< nummsgs; msgCount ++ ) {

    if( msgCount%10000==0 ) fprintf(stderr,"writetest: written %d msgs\n", msgCount );

    if( msgCount%printrate==0 ) {
      mt.current( msgCount );
    }

    write( fd, (char*)buffer, msgsize );

#ifdef WIN32
    // flush every message if sync writing (Windows NT only)
    if( isSync==1 ) _commit(fd);
#endif

  }
 
  close(fd);
  mt.stop( msgCount );
}

void usage()
{
  fprintf(stderr,"Test the I/O performance by writing several messages to the current directory\n");
  fprintf(stderr,"The files created are named writetest..dat and should be removed after the test !!\n\n");
  fprintf(stderr,"Usage: writetest \n");
  fprintf(stderr,"       Will write buffers of size each and print the rate every msgs.\n");
  fprintf(stderr,"       The test is repeated times and the used time is displayed\n");
  fprintf(stderr,"Example: writetest async 1000000 100000 100 1\n");
  exit(1);
}

int
main(int argc, char **argv)
{

  if( argc < 6 ) usage();

  if( !strcmp(argv[1],"sync") ) isSync = 1;
  else {
    if( !strcmp(argv[1],"async") ) isSync = 0;
    else usage();
  }

  int nummsgs = atoi(argv[2]); // number of messages to write
  int printrate = atoi(argv[3]); // number of tests to run
  int msgsize = atoi(argv[4]); // length of the message to write in bytes
  int numtests = atoi(argv[5]); // number of tests to run

  if( msgsize > sizeof(buffer) ) {
    fprintf(stderr,"writetest: msgsize can not be bigger than %ld\n", sizeof(buffer) );
    exit(1);
  }

  fprintf(stderr,"writetest: ARGUMENTS: sync:%d nummsgs:%d printrate:%d msgsize:%d numtests:%d\n",
        isSync, nummsgs, printrate, msgsize, numtests );
  for( int cnt=0; cnt < numtests; cnt++ ) {

    _testWrite( cnt, nummsgs, printrate, msgsize  );
  }
}

Monday, June 2, 2014

How to use JDBC-ODBC in a 64-bit JVM with a 32-bit version of Office

When using the JDBC-ODBC bridge in the JDK to access Microsoft Access files, you would set your JDBC class to sun.jdbc.odbc.JdbcOdbcDriver and your JDBC URL, for example, to:

"jdbc:odbc:Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=C:\CodeStreet\sample.accdb"

So far so good, but in case you are running a 64-bit JVM with a 32-bit Microsoft Office installation, your JVM and Access driver architecture don't match  and you would see error messages such as:
java.sql.SQLException: [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified


or
"The setup routines for the Microsoft Access Driver .. could not be found."

Fortunately, there are now 64-bit Microsoft Access drivers available, but using them in this context is quite tricky. Once you install the drivers, Microsoft Office stops working !

Opening an Excel file, for example, tries to find the 64-bit version of Office, which you don't have :-(

Instead of opening a file, you will see "Configuration Progress" and "Configuring Microsoft Office Professional Plus 2010..." - what the heck ?

But there's a neat little workaround which goes like this: 

1. Download the Microsoft Access drivers  

2. Check this registry key:
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\14.0\Common\FilesPaths 

If if currently contains an entry with mso.dll, you are using Office 64-bit, which is ok. If there is NO mso.dll key then your Office version is 32-bit. 

3. Open a command prompt and install the 64-bit driver in passive mode (it won't let you do this any other way):
    AccessDatabaseEngine_X64.exe /passive

4. If  mso.dll was not in your registry in step 2, then remove this key now from
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\14.0\Common\FilesPaths 


Microsoft Office (32-bit) should start working again and your 64-bit Access drivers are ready to go.



Good Luck!
 

Monday, December 3, 2012

Debugging Java Thread CPU usage

In case you want to quickly find out which of your Java threads is the culprit in a JVM's high CPU usage, this tool is truly helpful.

Simply download topthreads.jar from http://lsd.luminis.nl/top-threads-plugin-for-jconsole/
and run your jconsole like this:

     jconsole -pluginpath topthreads.jar

Similar to 'jtop', just a little better.




Tuesday, October 9, 2012

Eclipse and native library not found

Eclipse as Java IDE is great. But there's (at least) one part of the GUI that's a bit cumbersome. One thing that frequently pops up is the problem of not finding a native library.

For example if you use TIBCO Rendezvous, your project uses a tibrvj.jar file which is dependent on a native libary, for example tibrv.dll on Windows. Of course you can solve this by setting a Run Configurations 'VM argument' to -Djava.library.path=. But if you have many Run configurations, for example because you write JUnit tests around your software, it would be a pain to configure java.library.path for every JUnit Run Configuration.

You would think you can do Project -> Properties -> 'default java library path' - or so.
Or maybe Windows -> Preferences -> 'default VM arguments'. But neither exists :-(
That's the part where I say the GUI design of Eclipse could be improved: it's not quite obvious that you can actually edit properties of a jar file in 'Referenced Libraries'. You add jar files and they look like non-editable references to files. But you can actually change some properties.

Select your jar file and do a right-mouse-click:


In this dialog you can specify the path to a dependent native library which is then added to your java.library.path for every existing and future Run Configuration of this project.

Another interesting jar-file setting is the 'Javadoc Location'. Once you specified the path to a Javadoc's index.htm, the online documentation will be available when you program against that API (IntelliSense and F2 work). For TIBCO Rendezvous however, there's no real Javadoc part of the product.

Please note, though, that when you upgrade to another version of the jar file, these jar-file settings are lost. You have to repeat the steps above. It would be nice from Eclipse to be asked whether to keep Javadoc Location/Native Library settings when upgrading a jar file.


Tuesday, July 12, 2011

Eclipse doesn't start after crash

After a crash on Windows 7, my beloved Eclipse environment wouldn't start again! It just hung there, showing nothing but the Splash screen. eclipse -clean didn't help, monitoring files with Sysinternal's ProcMon or 'handle.exe' didn't help - quite devastating... But finally I found the solution here:
  1. cd to your Eclipse home directory
  2. cd .metadata/.plugins
  3. ren org.eclipse.core.resources BAK (Keep this directory around)
  4. Restart Eclipse, ignore the error message.
  5. Close all open editors tabs !! (in my case, playing with the .xsd file editor caused the issue)
  6. Exit Eclipse.
  7. del org.eclipse.core.resources (Delete the newly created directory.)
  8. ren BAK org.eclipse.core.resources (Restore the original directory.)
  9. Restart Eclipse.