Просмотр исходного кода

First commit (raw code) of new module: app_java (Java Native Interface support for Kamailio).

Konstantin Mosesov 12 лет назад
Родитель
Сommit
3cc85a3915

+ 23 - 0
modules/app_java/Makefile

@@ -0,0 +1,23 @@
+# $Id$
+#
+# 
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=app_java.so
+
+
+# for now is hard coded, will resolve this later
+JAVA_HOME ?= /usr/lib/jvm/java-gcj-4.7
+DEFS += $(shell pkg-config libgcj-4.7 --cflags) -I$(JAVA_HOME)/include
+LIBS += $(shell pkg-config libgcj-4.7 --libs) -L$(JAVA_HOME)/lib  -ljvm
+
+ifeq ($(OS), freebsd)
+LIBS+=-pthread
+endif
+
+DEFS+=-DKAMAILIO_MOD_INTERFACE
+
+include ../../Makefile.modules
+

+ 9 - 0
modules/app_java/build.sh

@@ -0,0 +1,9 @@
+#!/bin/bash
+
+INSTPREFIX=/opt/kamailio
+FLAVOUR=FLAVOUR=kamailio
+VERBOSE=Q=verbose
+
+rm -f /opt/kamailio/lib/kamailio/modules/app_java.so
+
+make clean && rm -f makecfg.lst *.d && make ${FLAVOUR} ${VERBOSE} && make ${FLAVOUR} install prefix=${INSTPREFIX} ${VERBOSE}

+ 53 - 0
modules/app_java/global.h

@@ -0,0 +1,53 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __GLOBAL_H__
+#define	__GLOBAL_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+
+#define	JAVA_MODULE_PKG_PATH	"org/sip-router"
+
+typedef struct threadData
+{
+    JNIEnv	*env;
+    JavaVM	*jvm;
+    char	*sClassName;
+    int		iThreadIndex;
+} tstThreadData;
+
+
+JavaVM *jvm;
+JNIEnv *env;
+tstThreadData *pThreadData;
+jclass KamailioClass;
+jclass KamailioClassInstanceRef;
+jobject KamailioClassInstance;
+jmethodID KamailioID;
+
+#endif

+ 44 - 0
modules/app_java/java_examples/Kamailio.java

@@ -0,0 +1,44 @@
+
+public class Kamailio
+{
+	static
+	{
+	    System.load("/opt/kamailio/lib/kamailio/modules/app_java.so");
+	}
+
+	private native void LM_GEN1(int logLevel, String s);
+	private native void LM_GEN2(int logFacility, int logLevel, String s);
+	private native void LM_ALERT(String s);
+	private native void LM_CRIT(String s);
+	private native void LM_WARN(String s);
+	private native void LM_NOTICE(String s);
+	private native void LM_ERR(String s);
+	private native void LM_INFO(String s);
+	private native void LM_DBG(String s);
+
+
+	public Kamailio()
+	{
+	    System.out.println("*************** constructor initialized! **********************");
+	}
+
+
+//	public static int child_init(int rank)
+	public int child_init(int rank)
+	{
+	    System.out.println("FROM JAVA: rank=" + rank);
+
+	    this.LM_GEN1(1, "oh yeah!!!\n");
+	    this.LM_GEN2(1, 2, "oh yeah!!!\n");
+	    this.LM_ALERT("oh yeah!!!\n");
+	    this.LM_CRIT("oh yeah!!!\n");
+	    this.LM_WARN("oh yeah!!!\n");
+	    this.LM_NOTICE("oh yeah!!!\n");
+	    this.LM_ERR("oh yeah!!!\n");
+	    this.LM_INFO("oh yeah!!!\n");
+	    this.LM_DBG("oh yeah!!!\n");
+
+	    return 1;
+	}
+
+}

+ 16 - 0
modules/app_java/java_examples/Makefile

@@ -0,0 +1,16 @@
+
+#JAVA_HOME=$(readlink -f $(which javac) | sed "s:bin/javac::")
+#CLASSPATH := /usr/local/lib/kamailio/modules
+
+JAVA_HOME ?= /usr/lib/jvm/java-gcj-4.7/
+
+all:
+#	export JAVA_HOME=/usr/lib/jvm/java-gcj-4.7:/opt/kamailio/lib/kamailio/modules:/opt/kamailio/java
+#	export CLASSPATH=/opt/kamailio/lib/kamailio/modules:/opt/kamailio/java
+	javac Kamailio.java
+
+clean:
+	rm -f *.class
+
+
+

+ 4 - 0
modules/app_java/java_examples/build.sh

@@ -0,0 +1,4 @@
+#!/bin/bash
+
+make clean
+make

+ 43 - 0
modules/app_java/java_iface.c

@@ -0,0 +1,43 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+#include "java_iface.h"
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+#include "java_native_methods.h"
+
+int java_exec(struct sip_msg *msg, char *method_name, char *foobar)
+{
+    LM_ERR("This is a stub only. Is not implemented yet.\n");
+    return 1;
+}
+

+ 35 - 0
modules/app_java/java_iface.h

@@ -0,0 +1,35 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __JAVA_IFACE_H__
+#define	__JAVA_IFACE_H__
+
+#include "../../parser/msg_parser.h"
+
+#include <jni.h>
+
+int java_exec(struct sip_msg *, char *, char *);
+
+
+#endif

+ 268 - 0
modules/app_java/java_mod.c

@@ -0,0 +1,268 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <libgen.h>
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+
+#include "java_native_methods.h"
+
+MODULE_VERSION
+
+static str script_name = {.s = "/usr/local/etc/sip-router/handler.java", .len = 0};
+static str class_name = {.s = "Kamailio", .len = 10};
+static str child_init_mname = { .s = "child_init", .len = 0};
+static str java_pkg_tree_path_str = { .s = "pkg_tree_path", .len = 0};
+static str java_options_str = { .s = "java_options", .len = 0};
+
+static int mod_init(void);
+static int child_init(int rank);
+static void mod_destroy(void);
+
+char *dname = NULL, *bname = NULL;
+
+/** module parameters */
+static param_export_t params[]={
+    {"script_name",        STR_PARAM, &script_name },
+    {"class_name",         STR_PARAM, &class_name },
+    {"pkg_tree_path",	   STR_PARAM, &java_pkg_tree_path_str },
+    {"child_init_method",  STR_PARAM, &child_init_mname },
+    {"java_options",	   STR_PARAM, &java_options_str },
+    {0,0,0}
+};
+
+
+/*
+ * Exported functions
+ */
+static cmd_export_t cmds[] = {
+    { "java_exec", (cmd_function)java_exec, 1,  NULL, 0,	REQUEST_ROUTE | FAILURE_ROUTE  | ONREPLY_ROUTE | BRANCH_ROUTE },
+    { 0, 0, 0, 0, 0, 0 }
+};
+
+/** module exports */
+struct module_exports exports = {
+    "app_java",                   /* module name */
+    RTLD_NOW | RTLD_GLOBAL,         /* dlopen flags */
+    cmds,                           /* exported functions */
+    params,                         /* exported parameters */
+    0,                              /* exported statistics */
+    0,                              /* exported MI functions */
+    0,                              /* exported pseudo-variables */
+    0,                              /* extra processes */
+    mod_init,                       /* module initialization function */
+    (response_function) NULL,       /* response handling function */
+    (destroy_function) mod_destroy, /* destroy function */
+    child_init                      /* per-child init function */
+};
+
+static int mod_init(void)
+{
+    JavaVMInitArgs  vm_args;
+    jint res;
+    JavaVMOption *options;
+    char **opts;
+    int nOptions;
+    char *class_object_name;
+    size_t class_object_name_len;
+
+    options = (JavaVMOption *)pkg_realloc(NULL, sizeof(JavaVMOption));
+    if (!options)
+    {
+	LM_ERR("Couldn't initialize Java VM: not enough memory\n");
+	return -1;
+    }
+    memset(options, 0, sizeof(JavaVMOption));
+
+    LM_INFO("Initializing Java VM with options: %s\n", java_options_str.s);
+
+    opts = split(java_options_str.s, " ");
+    for (nOptions=0; opts[nOptions] != NULL; nOptions++)
+    {
+	options[nOptions].optionString = opts[nOptions];
+    }
+
+    /* IMPORTANT: specify vm_args version # if you use JDK1.1.2 and beyond */
+    vm_args.version = JNI_VERSION_1_2;
+    vm_args.nOptions = nOptions;
+    vm_args.ignoreUnrecognized = JNI_FALSE;
+    vm_args.options = options;
+
+    res = JNI_CreateJavaVM(&jvm, (void **)&env, &vm_args);
+    if (res < 0)
+    {
+	handle_VM_init_failure(res);
+	return -1;
+    }
+
+    LM_INFO("app_java: Java VM initialization OK\n");
+
+    // attach to current thread
+    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
+    if ((*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	return -1;
+    }
+
+    // Loading main class
+    if (java_pkg_tree_path_str.len <= 0)
+    {
+	class_object_name_len =  strlen(JAVA_MODULE_PKG_PATH) + class_name.len + 1;	// default package name  plus  class name  plus package trailing slash
+    }
+    else
+    {
+	class_object_name_len =  java_pkg_tree_path_str.len + class_name.len + 1;	// package name  plus  class name  plus package trailing slash
+    }
+
+    class_object_name = (char *)pkg_realloc(NULL, (class_object_name_len + 1) * sizeof(char));
+    if (!class_object_name)
+    {
+	LM_ERR("pkg_realloc has failed. Not enough memory!\n");
+	return -1;
+    }
+    memset(class_object_name, 0, (class_object_name_len + 1) * sizeof(char));
+    if (java_pkg_tree_path_str.len <= 0)
+    {
+	snprintf(class_object_name, class_object_name_len, "%s%s", java_pkg_tree_path_str.s, class_name.s);
+    }
+    else
+    {
+	snprintf(class_object_name, class_object_name_len, "%s/%s", JAVA_MODULE_PKG_PATH, class_name.s);
+    }
+
+
+//    KamailioClass = (*env)->FindClass(env, class_name.s);
+    KamailioClass = (*env)->FindClass(env, class_object_name);
+    pkg_free(class_object_name);
+    if (!KamailioClass || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	if (jvm != NULL)
+	    (*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    KamailioID = (*env)->GetMethodID(env, KamailioClass, "<init>", "()V");
+    if (!KamailioID || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	if (jvm != NULL)
+	    (*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    // calling constructor
+    KamailioClassInstance = (*env)->NewObject(env, KamailioClass, KamailioID);
+    if (!KamailioClassInstance || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	if (jvm != NULL)
+	    (*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    // keep a reference to kamailio class instance
+    KamailioClassInstanceRef = (*env)->NewGlobalRef(env, KamailioClassInstance);
+    if (!KamailioClassInstanceRef || (*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	if (jvm != NULL)
+	    (*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    LM_INFO("app_java: initialization OK\n");
+
+    if (jvm != NULL)
+        (*jvm)->DetachCurrentThread(jvm);
+
+    return 0;
+}
+
+static int child_init(int rank)
+{
+    int retval;
+    jmethodID child_init_id;
+
+    // attach to current thread
+    (*jvm)->AttachCurrentThread(jvm, (void **)&env, NULL);
+    if ((*env)->ExceptionCheck(env))
+    {
+        handle_exception();
+        return -1;
+    }
+
+    child_init_id = (*env)->GetMethodID(env, KamailioClass, "child_init", "(I)I");
+    if ((*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	if (jvm != NULL)
+    	    (*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    retval = (int)(*env)->CallIntMethod(env, KamailioClassInstanceRef, child_init_id, rank);
+    if ((*env)->ExceptionCheck(env))
+    {
+	handle_exception();
+	if (jvm != NULL)
+    	    (*jvm)->DetachCurrentThread(jvm);
+	return -1;
+    }
+
+    (*env)->DeleteLocalRef(env, child_init_id);
+
+
+    if (jvm != NULL)
+        (*jvm)->DetachCurrentThread(jvm);
+
+    return retval;
+}
+
+static void mod_destroy(void)
+{
+    if (env != NULL)
+    {
+	if (KamailioClassInstanceRef != NULL)
+	    (*env)->DeleteGlobalRef(env, KamailioClassInstanceRef);
+    }
+
+    if (jvm != NULL)
+    {
+
+	(*jvm)->DetachCurrentThread(jvm);
+	(*jvm)->DestroyJavaVM(jvm);
+    }
+}

+ 40 - 0
modules/app_java/java_mod.h

@@ -0,0 +1,40 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __JAVA_MOD_H__
+#define	__JAVA_MOD_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "java_iface.h"
+
+/* The path where the class file being executed can be found */
+#define USER_CLASSPATH "."
+#define USER_LIBPATH "."
+
+
+#endif

+ 234 - 0
modules/app_java/java_native_methods.c

@@ -0,0 +1,234 @@
+/* $Id$
+ *
+ * Copyright (C) 2009 Sippy Software, Inc., http://www.sippysoft.com
+ *
+ * This file is part of SIP-Router, a free SIP server.
+ *
+ * SIP-Router is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * SIP-Router is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+*/
+
+#include <libgen.h>
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+
+#include "java_native_methods.h"
+
+
+//// native methods ////
+
+/*
+    java: native void LM_XXXXXX(Params XXXX);
+    c: JNIEXPORT void JNICALL Java_Kamailio_LM_1XXXXXX(JNIEnv *jenv, jobject this, Params XXXX)
+
+    Why (for example) Java_Kamailio_LM_1ERR but not Java_Kamailio_LM_ERR? 
+    See explaination here: http://qscribble.blogspot.ca/2012/04/underscores-in-jni-method-names.html
+*/
+
+#ifdef LM_ERR
+// java: native void LM_ERR(String s);
+JNIEXPORT void JNICALL Java_Kamailio_LM_1ERR(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_ERR("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+#endif
+
+#ifdef LM_WARN
+// java: native void LM_WARN(String s);
+JNIEXPORT void JNICALL Java_Kamailio_LM_1WARN(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_WARN("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+#endif
+
+#ifdef LM_NOTICE
+// java: native void LM_NOTICE(String s);
+JNIEXPORT void JNICALL Java_Kamailio_LM_1NOTICE(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_NOTICE("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+#endif
+
+#ifdef LM_INFO
+// java: native void LM_INFO(String s);
+JNIEXPORT void JNICALL Java_Kamailio_LM_1INFO(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_INFO("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+#endif
+
+#ifdef LM_DBG
+// java: native void LM_DBG(String s);
+JNIEXPORT void JNICALL Java_Kamailio_LM_1DBG(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_DBG("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+#endif
+
+#ifdef LM_CRIT
+// java: native void LM_CRIT(String s);
+JNIEXPORT void JNICALL Java_Kamailio_LM_1CRIT(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_CRIT("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+#endif
+
+
+#ifdef LM_ALERT
+// java: native void LM_ALERT(String s);
+JNIEXPORT void JNICALL Java_Kamailio_LM_1ALERT(JNIEnv *jenv, jobject this, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_ALERT("%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+#endif
+
+
+#ifdef LM_GEN1
+// java: native void LM_GEN1(int logLevel, String s);
+JNIEXPORT void JNICALL Java_Kamailio_LM_1GEN1(JNIEnv *jenv, jobject this, jint ll, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_GEN1(ll, "%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+#endif
+
+#ifdef LM_GEN2
+// java: native void LM_GEN2(int logLevel, int logFacility, String s);
+JNIEXPORT void JNICALL Java_Kamailio_LM_1GEN2(JNIEnv *jenv, jobject this, jint ll, jint lf, jstring js)
+{
+    const char *s;
+    jboolean iscopy;
+
+    s = (*jenv)->GetStringUTFChars(jenv, js, &iscopy);
+    if ((*jenv)->ExceptionCheck(jenv))
+    {
+	handle_exception();
+	return;
+    }
+
+    LM_GEN2(ll, lf, "%s", s == NULL ? "null\n" : s);
+
+    (*jenv)->ReleaseStringUTFChars(jenv, js, s);
+}
+#endif
+
+
+
+//// native properties ////

+ 36 - 0
modules/app_java/java_native_methods.h

@@ -0,0 +1,36 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __JAVA_NATIVE_METHODS_H__
+#define	__JAVA_NATIVE_METHODS_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+JNIEXPORT void JNICALL Java_com_kamailio___init__(JNIEnv *env, jobject);
+void assign_properties(void);
+
+#endif

+ 207 - 0
modules/app_java/java_support.c

@@ -0,0 +1,207 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <libgen.h>
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+#include "global.h"
+
+#include "utils.h"
+#include "java_mod.h"
+#include "java_iface.h"
+#include "java_support.h"
+
+
+static char *_append_exception_trace_messages(char *msg_str, jthrowable a_exception, jmethodID a_mid_throwable_getCause, jmethodID a_mid_throwable_getStackTrace, jmethodID a_mid_throwable_toString, jmethodID a_mid_frame_toString)
+{
+    jobjectArray frames;
+    jsize frames_length, i;
+    jstring msg_obj;
+    jobject frame;
+    jthrowable cause;
+    jclass exClass;
+    jmethodID mid;
+    jboolean isCopy;
+
+    const char *tmpbuf;
+
+    // Get the array of StackTraceElements.
+    frames = (jobjectArray) (*env)->CallObjectMethod(env, a_exception, a_mid_throwable_getStackTrace);
+    if (!frames)
+    {
+        exClass = (*env)->GetObjectClass(env, a_exception);
+        mid = (*env)->GetMethodID(env, exClass, "toString", "()Ljava/lang/String;");
+        msg_obj = (jstring) (*env)->CallObjectMethod(env, a_exception, mid);
+
+        isCopy = JNI_FALSE;
+	tmpbuf = (*env)->GetStringUTFChars(env, msg_obj, &isCopy);
+
+	strcat(msg_str, tmpbuf);
+	strcat(msg_str, "\n    <<No stacktrace available>>");
+
+        (*env)->ReleaseStringUTFChars(env, msg_obj, tmpbuf);
+        (*env)->DeleteLocalRef(env, msg_obj);
+
+	return msg_str;
+    }
+    else
+    {
+	frames_length = (*env)->GetArrayLength(env, frames);
+    }
+
+    // Add Throwable.toString() before descending stack trace messages.
+    if (frames != 0)
+    {
+        msg_obj = (jstring) (*env)->CallObjectMethod(env, a_exception, a_mid_throwable_toString);
+	tmpbuf = (*env)->GetStringUTFChars(env, msg_obj, 0);
+	
+	strcat(msg_str, "Exception in thread \"main\" ");
+	strcat(msg_str, tmpbuf);
+
+        (*env)->ReleaseStringUTFChars(env, msg_obj, tmpbuf);
+        (*env)->DeleteLocalRef(env, msg_obj);
+    }
+
+
+    // Append stack trace messages if there are any.
+    if (frames_length > 0)
+    {
+        for (i=0; i<frames_length; i++)
+        {
+            // Get the string returned from the 'toString()'
+            // method of the next frame and append it to
+            // the error message.
+            frame = (*env)->GetObjectArrayElement(env, frames, i);
+            msg_obj = (jstring) (*env)->CallObjectMethod(env, frame, a_mid_frame_toString);
+
+            tmpbuf = (*env)->GetStringUTFChars(env, msg_obj, 0);
+
+	    strcat(msg_str, "\n    at ");
+	    strcat(msg_str, tmpbuf);
+
+            (*env)->ReleaseStringUTFChars(env, msg_obj, tmpbuf);
+            (*env)->DeleteLocalRef(env, msg_obj);
+            (*env)->DeleteLocalRef(env, frame);
+        }
+    }
+    else
+    {
+	strcat(msg_str, "\n    <<No stacktrace available>>");
+    }
+
+
+    // If 'a_exception' has a cause then append the
+    // stack trace messages from the cause.
+    if (frames != 0)
+    {
+        cause = (jthrowable) (*env)->CallObjectMethod(env, a_exception, a_mid_throwable_getCause);
+        if (cause != 0)
+        {
+            tmpbuf = _append_exception_trace_messages(msg_str, cause, a_mid_throwable_getCause, a_mid_throwable_getStackTrace, a_mid_throwable_toString, a_mid_frame_toString);
+	    strcat(msg_str, tmpbuf);
+        }
+    }
+
+    if (msg_str != NULL)
+	return strdup(msg_str);
+    else
+	return NULL;
+}
+
+void handle_exception(void)
+{
+    char *error_msg = NULL;
+    char msg_str[8192];
+
+    jthrowable exception;
+    jclass throwable_class, frame_class;
+    jmethodID mid_throwable_getCause, mid_throwable_getStackTrace;
+    jmethodID mid_throwable_toString, mid_frame_toString;
+
+    if (!(*env)->ExceptionCheck(env))
+	return;
+
+    memset(&msg_str, 0, sizeof(msg_str));
+
+    // Get the exception and clear as no
+    // JNI calls can be made while an exception exists.
+    exception = (*env)->ExceptionOccurred(env);
+    if (exception)
+    {
+//	(*env)->ExceptionDescribe(env);
+	(*env)->ExceptionClear(env);
+
+	throwable_class = (*env)->FindClass(env, "java/lang/Throwable");
+
+	mid_throwable_getCause = (*env)->GetMethodID(env, throwable_class, "getCause", "()Ljava/lang/Throwable;");
+        mid_throwable_getStackTrace =  (*env)->GetMethodID(env, throwable_class, "getStackTrace",  "()[Ljava/lang/StackTraceElement;");
+	mid_throwable_toString = (*env)->GetMethodID(env, throwable_class, "toString", "()Ljava/lang/String;");
+
+        frame_class = (*env)->FindClass(env, "java/lang/StackTraceElement");
+	mid_frame_toString = (*env)->GetMethodID(env, frame_class, "toString", "()Ljava/lang/String;");
+
+        error_msg = _append_exception_trace_messages(msg_str, exception, mid_throwable_getCause, mid_throwable_getStackTrace, mid_throwable_toString, mid_frame_toString);    
+
+
+	(*env)->DeleteLocalRef(env, exception);
+    }
+
+    LM_ERR("Exception:\n%s\n", error_msg == NULL ? "(no info)" : error_msg);
+
+}
+
+
+void handle_VM_init_failure(int res)
+{
+    switch(res)
+    {
+	    case -1:
+		LM_ERR("Couldn't initialize Java VM: unknown error\n");
+		break;
+	    case -2:
+		LM_ERR("Couldn't initialize Java VM: thread detached from the VM\n");
+	        break;
+	    case -3:
+		LM_ERR("Couldn't initialize Java VM: JNI version error\n");
+		break;
+	    case -4:
+		LM_ERR("Couldn't initialize Java VM: not enough memory\n");
+		break;
+	    case -5:
+		LM_ERR("Couldn't initialize Java VM: VM already created\n");
+		break;
+	    case -6:
+		LM_ERR("Couldn't initialize Java VM: invalid arguments\n");
+		break;
+	    default:
+		LM_ERR("Couldn't initialize Java VM. Error code: %d\n", res);
+		break;
+    }
+}
+
+

+ 37 - 0
modules/app_java/java_support.h

@@ -0,0 +1,37 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __JAVA_SUPPORT_H__
+#define	__JAVA_SUPPORT_H__
+
+#include "../../str.h"
+#include "../../sr_module.h"
+
+#include <jni.h>
+
+void handle_exception(void);
+void handle_VM_init_failure(int res);
+
+
+#endif

+ 137 - 0
modules/app_java/utils.c

@@ -0,0 +1,137 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "utils.h"
+
+char **split(char *str, char *sep)
+{
+    char **buf = NULL;
+    char *token = NULL;
+    char *saveptr = NULL;
+    int i;
+
+    buf = (char **)calloc(1, sizeof(char *));
+    if (!buf)
+    {
+	return '\0';
+    }
+
+    if (str == NULL)
+	return buf;
+
+    if (strncmp(str, sep, strlen(sep)) <= 0)
+    {
+	// string doesn't contains a separator
+	buf[0] = strdup(str);
+	return buf;
+    }
+
+    token = strdup(str);
+    for (i=0; token != NULL; token = saveptr, i++)
+    {
+        token = strtok_r(token, (const char *)sep, &saveptr);
+
+        if (token == NULL || !strcmp(token, ""))
+            break;
+
+	buf = (char **)realloc(buf, (i+1) * sizeof(char *));
+        buf[i] = strdup(token);
+    }
+    buf[i] = '\0';
+
+    free(token);
+
+    return buf;
+}
+
+
+char *rand_string(const int len)
+{
+    char *buf;
+    const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+    int i;
+
+    buf = (char *)calloc(len+1, sizeof(char));
+    if (!buf)
+	return NULL;
+
+    srand(time(NULL));
+    for (i=0; i<len; i++)
+    {
+        buf[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
+    }
+
+    buf[len] = '\0';
+
+    return buf;
+}
+
+char *str_replace(char *original, char *pattern, char *replacement)
+{
+    char *oriptr, *patloc, *retptr, *returned;
+    size_t replen, patlen, orilen, patcnt, retlen, skplen;
+
+    replen = strlen(replacement);
+    patlen = strlen(pattern);
+    orilen = strlen(original);
+    patcnt = 0;
+
+    // find how many times the pattern occurs in the original string
+    for (oriptr = original; (patloc = strstr(oriptr, pattern)); oriptr = patloc + patlen)
+    {
+	patcnt++;
+    }
+
+    // allocate memory for the new string
+    retlen = orilen + patcnt * (replen - patlen);
+    returned = (char *)malloc((retlen+1) * sizeof(char));
+
+    if (returned != NULL)
+    {
+	// copy the original string, 
+	// replacing all the instances of the pattern
+	retptr = returned;
+	for (oriptr = original; (patloc = strstr(oriptr, pattern)); oriptr = patloc + patlen)
+	{
+    	    skplen = patloc - oriptr;
+
+    	    // copy the section until the occurence of the pattern
+    	    strncpy(retptr, oriptr, skplen);
+    	    retptr += skplen;
+
+    	    // copy the replacement 
+    	    strncpy(retptr, replacement, replen);
+    	    retptr += replen;
+	}
+
+	// copy the rest of the string.
+	strcpy(retptr, oriptr);
+    }
+
+    return returned;
+}

+ 34 - 0
modules/app_java/utils.h

@@ -0,0 +1,34 @@
+/**
+ * $Id$
+ *
+ * Copyright (C) 2013 Konstantin Mosesov
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include <string.h>
+
+char **split(char *, char *);
+char *rand_string(const int);
+char *str_replace(char *, char *, char *);
+
+#endif