Making your class Non-Copyable and Non-Assignable

I was working on removing Coverity defects. My product is written such that we do not do any copy and assignment of the C++ classes .
So Coverity starting giving errors of following kind.

CID 28711: Other violation (MISSING_ASSIGN) and CID 28711: Other violation (MISSING_COPY)

Solution to this problem was to add private copy constructor and private assignment operator.
But since I had more than 500 classes do edit. I wrote a two new classes NonCopyable and NonAssignable
and inherit all the problem classes from the same.

class NonCopyable 
{
protected:
    NonCopyable() {}
    ~NonCopyable() {}
private:  
    NonCopyable( const NonCopyable& );
};

and

class  NonAssignable
{
protected:
    NonAssignable() {}
    ~NonAssignable() {}
private:  
    const NonAssignable& operator=( const NonAssignable& );
};

If you want to make your class Non copyable inherit from NonCopyable and If you want to make your class Non assignable inherit from NonAssignable

Advertisements

Launching JVM from C++

Recently I have to write small utility to launch my product Java server using C++. So thought to share the generic class I wrote for launching JVM using C++/Jni.

#include <stdexcept>
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#include <include/jni.h>

#include <string>
#include <stdlib.h>
#include <vector>
#include <iostream>


class JVMLauncherException : public std::runtime_error {
public:
    JVMLauncherException(const std::string& message) : std::runtime_error(message) 
    { 
    };
};

class JVMLauncher {
public:
    JVMLauncher();
    void addJars(std::string inJar);
    void LaunchJVM();
    void StartJVMServer();
    void AddServerArguments(std::string);
private:
    typedef jint (JNICALL *CreateJavaVM)(JavaVM **pvm, void **penv, void *args);

    HINSTANCE     m_hDllInstance;

    std::string   m_JavaHome;
    std::string   m_ProductLibDir;
    std::string   m_JvmDllLocation;

    CreateJavaVM  m_JVMInstance;
    jclass        m_CacheServerLauncherClass;
    jmethodID     m_MainMethodID;
    JNIEnv       *m_JVMEnv;
    JavaVM       *m_RunningJVMInstance;    

    std::vector<std::string> m_listOfJars;
    std::vector<std::string> m_ServerArguments;

    void CheckForJNIException();
protected:
};

JVMLauncher::JVMLauncher() {
    // Check for JAVA_HOME
    char *pValue;
    size_t len;
    errno_t err = _dupenv_s( &pValue, &len, "JAVA_HOME" );
    if ( err ) {
        throw JVMLauncherException("JAVA_HOME not defined");
    }    
    m_JavaHome       = pValue;
    m_JvmDllLocation = m_JavaHome + "\\jre\\bin\\server\\jvm.dll";

    err = _dupenv_s( &pValue, &len, "PRODUCT HOME PATH" );
    if ( err ) {
        throw JVMLauncherException("PRODUCT HOME PATH not defined");
    }
    m_ProductLibDir = pValue;

    m_listOfJars.push_back("depedent1.jar");
    m_listOfJars.push_back("depedent2.jar");
    m_listOfJars.push_back("depedent3.jar");
    m_listOfJars.push_back("depedent4.jar");
    m_listOfJars.push_back("depedent5.jar");    
}
void JVMLauncher::AddServerArguments(std::string inParam) {
    m_ServerArguments.push_back(inParam);
}
void JVMLauncher::LaunchJVM() {
    // Construct the product specific class path.
    std::string strJavaClassPath = "-Djava.class.path=";
    for ( std::size_t idx = 0; idx < m_listOfJars.size() - 1 ; idx++) {
        strJavaClassPath += m_ProductLibDir + "\\lib\\" + m_listOfJars[idx] + ";";
    }
    strJavaClassPath += m_ProductLibDir + "\\lib\\" + m_listOfJars[m_listOfJars.size() - 1] ;

    // consruct java.library.path
    std::string strJavaLibraryPath =  "-Djava.library.path=";
    strJavaLibraryPath             += m_JavaHome + "\\lib" + "," + m_JavaHome + "\\jre\\lib";

    
    // try loading jvm dll
    m_hDllInstance = LoadLibraryA(m_JvmDllLocation.c_str());
    if( m_hDllInstance == 0) {
        throw JVMLauncherException("Cannot load jvm.dll");
    }
    m_JVMInstance = (CreateJavaVM)GetProcAddress(m_hDllInstance, "JNI_CreateJavaVM");
    if ( m_JVMInstance == NULL )  {
        throw JVMLauncherException("Cannot load jvm.dll");
    }

    JavaVMOption options[3];
    options[0].optionString  = const_cast<char*>(strJavaClassPath.c_str());
    options[1].optionString  = const_cast<char*>(strJavaLibraryPath.c_str());
    options[2].optionString  = "-verbose:jni";

    JavaVMInitArgs vm_args;
    vm_args.version            = JNI_VERSION_1_6; //JNI Version 1.4 and above
    vm_args.options            = options;    
    vm_args.nOptions           = 3;       
    vm_args.ignoreUnrecognized = JNI_TRUE;

    //Create the JVM
    
    jint res = m_JVMInstance(&m_RunningJVMInstance, (void **)&m_JVMEnv, &vm_args);
    if (res < 0)  {
    	throw JVMLauncherException("Could not launch the JVM");
    }

    m_CacheServerLauncherClass = m_JVMEnv->FindClass("<your main class>");    
    CheckForJNIException();

    m_MainMethodID = m_JVMEnv->GetStaticMethodID(m_CacheServerLauncherClass, "main", "([Ljava/lang/String;)V");
    CheckForJNIException();
}

void JVMLauncher::StartJVMServer() {

    if ( m_RunningJVMInstance->AttachCurrentThread((LPVOID *)&m_JVMEnv, NULL) ) {
        std::cout << "Fail to attach the current thread " << std::endl;
    }

    jclass StringClass = m_JVMEnv->FindClass("java/lang/String");
    int numOfArguments = (int)m_ServerArguments.size() + 4 ;
    int argumentIndex = 0;

    jobjectArray jargs = m_JVMEnv->NewObjectArray(numOfArguments, StringClass, NULL);    

    m_JVMEnv->SetObjectArrayElement(jargs, argumentIndex++, m_JVMEnv->NewStringUTF("start"));

    std::string strJavaClassPath = "-classpath=";
    strJavaClassPath             += "\"";
    for ( std::size_t idx = 0; idx < m_listOfJars.size() - 1 ; idx++) {
        strJavaClassPath += m_ProductLibDir + "\\lib\\" + m_listOfJars[idx] + ";";
    }
    strJavaClassPath      += m_ProductLibDir + "\\lib\\" + m_listOfJars[m_listOfJars.size() - 1] ;
    strJavaClassPath      += "\"";

    m_JVMEnv->SetObjectArrayElement(jargs, argumentIndex++, m_JVMEnv->NewStringUTF(strJavaClassPath.c_str()));

    for ( std::vector<std::string>::iterator iter = m_ServerArguments.begin(); iter != m_ServerArguments.end(); ++iter) {
        std::string argument = *iter;
        m_JVMEnv->SetObjectArrayElement(jargs, argumentIndex++, m_JVMEnv->NewStringUTF(argument.c_str()));
    }
    m_JVMEnv->SetObjectArrayElement(jargs, argumentIndex++, m_JVMEnv->NewStringUTF("argument1"));    
    m_JVMEnv->SetObjectArrayElement(jargs, argumentIndex, m_JVMEnv->NewStringUTF("argument2"));    

    m_JVMEnv->CallStaticVoidMethod(m_CacheServerLauncherClass, m_MainMethodID, jargs);

    m_RunningJVMInstance->DestroyJavaVM();

    CheckForJNIException();
}

void JVMLauncher::CheckForJNIException() {
    jthrowable expt = m_JVMEnv->ExceptionOccurred();
    if (expt != NULL) {
        m_JVMEnv->ExceptionClear();
        jmethodID toString = m_JVMEnv->GetMethodID(m_JVMEnv->FindClass("java/lang/Object"), "toString", "()Ljava/lang/String;");
        jstring estring = (jstring) m_JVMEnv->CallObjectMethod(expt, toString);
        jboolean isCopy;
        std::string message = m_JVMEnv->GetStringUTFChars(estring, &isCopy);
        throw JVMLauncherException(message);
    }
}

vFabric GemFire Service Launcher – GemfireSvcLauncher

VMware vFabricTMGemFire® is a data management platform that provides real-time, consistent access to data throughout widely distributed cloud architectures. It is available as a standalone product and as a component of vFabric Suite. Here is the link for more details on the product. VMware vFabricTMGemFire®
Here is how you start GemFire® server.

cacheserver start [-J<vmarg>]* [<attName>=<attValue>]* [-dir=<workingdir>] [-classpath=<classpath>] [-disable-default-server] [-rebalance] [-server-port=<server-port>] [-server-bind-address= <server-bind-address>]

If you want to start GemFire® as a Windows Service. I have created a Command line utility for the same. Download from here GemfireSvcLauncher

How to use GemfireSvcLauncher
This is nothing different from the way you launch cacheserver
Assume that you want to pass following parameter to JVM -J-Xmx1024m -J-Xms128m and your cache-xml-file file is at location E:\XMLs and E:\workingdir is your Cacheserver Working directory. For this configuration following option will create required Windows GemFire® service.

GemfireSvcLauncher.exe --install --type cacheserver --name BasicOperation --params -J-Xmx1024m -J-Xms128m cache-xml-file=E:\XMLs\cacheserver.xml -dir=E:\workingdir mcast-port=0  log-level=config

This command will create a Windows service with name BasicOperation as shown below

Service_Image

How to start the service
You can use Windows Service Control Manager to start the service or use following commands from command line to start the service.

sc start BasicOperation

or

net start BasicOperation

How to stop the service
You can use Windows Service Control Manager to stop the service or use following commands from command line to stop the service.

sc stop BasicOperation

or

net stop BasicOperation

How to delete the service

sc delete BasicOperation

Where the logs are created related to service
It will be your working directory where log file with name GemfireSvcLauncher.log will be created.

If you want to know what is happening more with this utility development follow GemfireSvcLauncher on GitHub