diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..0d20b6487c61e7d1bde93acf4a14b7a89083a16d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2590ccb41a9f7512e9a1c4cf287910d615043e70..eae70f34b6f957a8065672eba8e6f4011207ec52 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,13 +6,13 @@ cmake_minimum_required(VERSION 2.8.3)
 project(genjava)
 
 ##############################################################################
-# Dependencies
+# Find Package
 ##############################################################################
 
 find_package(catkin REQUIRED COMPONENTS genmsg)
 
 ##############################################################################
-# Package
+# Catkin
 ##############################################################################
 
 catkin_package(
@@ -20,16 +20,23 @@ catkin_package(
   CFG_EXTRAS genjava-extras.cmake
 )
 
+catkin_python_setup()
+
+##############################################################################
+# Installs
+##############################################################################
+
 add_subdirectory(scripts)
 
-message(STATUS "GENMSG_LANGS_DESTINATION...........${GENMSG_LANGS_DESTINATION}")
 file(WRITE ${CATKIN_DEVEL_PREFIX}/${GENMSG_LANGS_DESTINATION}/genjava "Java")
 install(FILES ${CATKIN_DEVEL_PREFIX}/${GENMSG_LANGS_DESTINATION}/genjava
   DESTINATION ${GENMSG_LANGS_DESTINATION})
 
-catkin_python_setup()
+##############################################################################
+# Tests
+##############################################################################
 
-if(CATKIN_ENABLE_TESTING)
-  catkin_add_nosetests(test)
-endif()
+#if(CATKIN_ENABLE_TESTING)
+#  catkin_add_nosetests(test)
+#endif()
 
diff --git a/cmake/genjava-extras.cmake.em b/cmake/genjava-extras.cmake.em
index 8bcc5a768c2f2689613044c1bb9e00cc3e1d2533..f08631de343a63d6c26c4ad5753cd015eabc1847 100644
--- a/cmake/genjava-extras.cmake.em
+++ b/cmake/genjava-extras.cmake.em
@@ -6,118 +6,91 @@ set(GENJAVA_BIN_DIR "@(CMAKE_CURRENT_SOURCE_DIR)/scripts")
 set(GENJAVA_BIN_DIR "${GENJAVA_DIR}/../../../@(CATKIN_PACKAGE_BIN_DESTINATION)")
 @[end if]@
 
-set(GENMSG_JAVA_BIN ${GENJAVA_BIN_DIR}/genmsg_java.py)
-set(GENSRV_JAVA_BIN ${GENJAVA_BIN_DIR}/gensrv_java.py)
+set(GENJAVA_BIN ${GENJAVA_BIN_DIR}/genjava_gradle_project.py)
+set(genjava_INSTALL_DIR "maven/org/ros/rosjava_messages")
 
-# genmsg usually uses this variable to configure the install location. we typically pick
-# it up from the environment configured by rosjava_build_tools.
-#set(genjava_INSTALL_DIR "maven/org/ros/rosjava_messages")
-set(ROS_MAVEN_DEPLOYMENT_REPOSITORY $ENV{ROS_MAVEN_DEPLOYMENT_REPOSITORY})
-if(NOT ROS_MAVEN_DEPLOYMENT_REPOSITORY)
-  set(ROS_MAVEN_DEPLOYMENT_REPOSITORY "${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_MAVEN_DESTINATION}")
-endif()
-
-# Generate .msg->.h for py
-# The generated .h files should be added ALL_GEN_OUTPUT_FILES_py
-#
-# Example arguments:
-#
-#   ARG_PKG      : foo_msgs
-#   ARG_MSG      : /mnt/zaphod/ros/rosjava/hydro/src/foo_msgs/msg/Foo.msg
-#   ARG_IFLAGS   : -Ifoo_msgs:/mnt/zaphod/ros/rosjava/hydro/src/foo_msgs/msg;-Istd_msgs:/opt/ros/hydro/share/std_msgs/cmake/../msg
-#   ARG_MSG_DEPS : ???
-#   ARG_GEN_OUTPUT_DIR : /mnt/zaphod/ros/rosjava/hydro/devel/${genjava_INSTALL_DIR}/foo_msgs
 macro(_generate_msg_java ARG_PKG ARG_MSG ARG_IFLAGS ARG_MSG_DEPS ARG_GEN_OUTPUT_DIR)
-
-  message(STATUS "GEN_MSG_JAVA..........._generate_msg_java")
-  message(STATUS "  ARG_PKG..............${ARG_PKG}")
-  message(STATUS "  ARG_MSG..............${ARG_MSG}")
-  message(STATUS "  ARG_IFLAGS...........${ARG_IFLAGS}")
-  message(STATUS "  ARG_MSG_DEPS.........${ARG_MSG_DEPS}")
-  message(STATUS "  ARG_GEN_OUTPUT_DIR...${ARG_GEN_OUTPUT_DIR}")
-  message(STATUS "GEN_MSG_JAVA...........done")
-  message(STATUS "CMAKE_CURRENT_BINARY_DIR.......${CMAKE_CURRENT_BINARY_DIR}")
-
-  #Append msg to output dir
-  #set(GEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
-  #file(MAKE_DIRECTORY ${GEN_OUTPUT_DIR})
-  #Create input and output filenames
-  get_filename_component(MSG_SHORT_NAME ${ARG_MSG} NAME_WE)
-
-  file(REMOVE_RECURSE ${CMAKE_CURRENT_BINARY_DIR}/gradle)
-
-  #set(MSG_GENERATED_NAME ${MSG_SHORT_NAME}.java)
-  #set(GEN_OUTPUT_FILE ${GEN_OUTPUT_DIR}/${MSG_GENERATED_NAME})
-  #message(STATUS "GEN_OUTPUT_FILE..........${GEN_OUTPUT_FILE}")
-  #add_custom_command(OUTPUT ${GEN_OUTPUT_FILE}
-  #  DEPENDS ${GENMSG_JAVA_BIN} ${ARG_MSG} ${ARG_MSG_DEPS}
-  #  COMMAND ${CATKIN_ENV} cmake
-  #  -E remove_directory ${CMAKE_CURRENT_BINARY_DIR}
-  #  -m ${ARG_MSG}
-  #  ${ARG_IFLAGS}
-  #  -p ${ARG_PKG}
-  #  -o ${GEN_OUTPUT_DIR}
-  #  COMMENT "Generating Java code from MSG ${ARG_PKG}/${MSG_SHORT_NAME}"
-  #)
-
-  #list(APPEND ALL_GEN_OUTPUT_FILES_java ${GEN_OUTPUT_FILE})
-
+  list(APPEND ALL_GEN_OUTPUT_FILES_java ${ARG_MSG} ${ARG_MSG_DEPS})
+
+    # Example arguments:
+    #
+    #   ARG_PKG      : foo_msgs
+    #   ARG_MSG      : /mnt/zaphod/ros/rosjava/hydro/src/foo_msgs/msg/Foo.msg
+    #   ARG_IFLAGS   : -Ifoo_msgs:/mnt/zaphod/ros/rosjava/hydro/src/foo_msgs/msg;-Istd_msgs:/opt/ros/hydro/share/std_msgs/cmake/../msg
+    #   ARG_MSG_DEPS : ???
+    #   ARG_GEN_OUTPUT_DIR : /mnt/zaphod/ros/rosjava/hydro/devel/${genjava_INSTALL_DIR}/foo_msgs
+    
+    #message(STATUS "Java generator for [${ARG_PKG}][${ARG_MSG}]")
+    #message(STATUS "  ARG_IFLAGS...........${ARG_IFLAGS}")
+    #message(STATUS "  ARG_MSG_DEPS.........${ARG_MSG_DEPS}")
+    #message(STATUS "  ARG_GEN_OUTPUT_DIR...${ARG_GEN_OUTPUT_DIR}")
+    #message(STATUS "GEN_MSG_JAVA...........done")
+    #message(STATUS "CMAKE_CURRENT_BINARY_DIR.......${CMAKE_CURRENT_BINARY_DIR}")
 endmacro()
 
-#todo, these macros are practically equal. Check for input file extension instead
 macro(_generate_srv_java ARG_PKG ARG_SRV ARG_IFLAGS ARG_MSG_DEPS ARG_GEN_OUTPUT_DIR)
-
-  message(STATUS "GEN_SRV_JAVA..........._generate_srv_java")
-  #Append msg to output dir
-#  set(GEN_OUTPUT_DIR "${ARG_GEN_OUTPUT_DIR}/srv")
-#  file(MAKE_DIRECTORY ${GEN_OUTPUT_DIR})
-#
-  #Create input and output filenames
-#  get_filename_component(SRV_SHORT_NAME ${ARG_SRV} NAME_WE)
-#
-#  set(SRV_GENERATED_NAME _${SRV_SHORT_NAME}.py)
-#  set(GEN_OUTPUT_FILE ${GEN_OUTPUT_DIR}/${SRV_GENERATED_NAME})
-#
-#  add_custom_command(OUTPUT ${GEN_OUTPUT_FILE}
-#    DEPENDS ${GENSRV_PY_BIN} ${ARG_SRV} ${ARG_MSG_DEPS}
-#    COMMAND ${CATKIN_ENV} ${PYTHON_EXECUTABLE} ${GENSRV_PY_BIN} ${ARG_SRV}
-#    ${ARG_IFLAGS}
-#    -p ${ARG_PKG}
-#    -o ${GEN_OUTPUT_DIR}
-#    COMMENT "Generating Python code from SRV ${ARG_PKG}/${SRV_SHORT_NAME}"
-#    )
-#
-#  list(APPEND ALL_GEN_OUTPUT_FILES_py ${GEN_OUTPUT_FILE})
-
+  list(APPEND ALL_GEN_OUTPUT_FILES_java ${ARG_SRV} ${ARG_MSG_DEPS})
 endmacro()
 
+# This is a bit different to the other generators - it generates the whole message package together
+# (unless there's another api I'm not aware of yet in the generator jar). It's a few milliseconds
+# of overkill generating all .java files if only one msg changed, but it's not worth the effort to
+# break that down yet.
+# 
+# To facilitate this, the ARG_GENERATED_FILES is actually just the underlying ARG_MSG and ARG_SRV
+# files which we feed the commands as DEPENDS to trigger their execution.
 macro(_generate_module_java ARG_PKG ARG_GEN_OUTPUT_DIR ARG_GENERATED_FILES)
 
-  message(STATUS "GEN_MODULE_JAVA..........._generate_module_java")
-  # generate empty __init__ to make parent folder of msg/srv a python module
-  if(NOT EXISTS ${ARG_GEN_OUTPUT_DIR}/__init__.py)
-    file(WRITE ${ARG_GEN_OUTPUT_DIR}/__init__.py "")
-  endif()
-
-  #Append msg to output dir
-  foreach(type "msg" "srv")
-    set(GEN_OUTPUT_DIR "${ARG_GEN_OUTPUT_DIR}/${type}")
-    set(GEN_OUTPUT_FILE ${GEN_OUTPUT_DIR}/__init__.py)
-
-    if(IS_DIRECTORY ${GEN_OUTPUT_DIR})
-      add_custom_command(OUTPUT ${GEN_OUTPUT_FILE}
-        DEPENDS ${GENMSG_PY_BIN} ${ARG_GENERATED_FILES}
-        COMMAND ${CATKIN_ENV} ${PYTHON_EXECUTABLE} ${GENMSG_PY_BIN}
-        -o ${GEN_OUTPUT_DIR}
-        --initpy
-        COMMENT "Generating Python ${type} __init__.py for ${ARG_PKG}")
-      list(APPEND ALL_GEN_OUTPUT_FILES_py ${GEN_OUTPUT_FILE})
+    ################################
+    # Gradle Subproject
+    ################################
+    set(GRADLE_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/java")
+    set(GRADLE_BUILD_FILE "${GRADLE_BUILD_DIR}/${ARG_PKG}/build.gradle")
+    list(APPEND ALL_GEN_OUTPUT_FILES_java ${GRADLE_BUILD_FILE})
+
+    add_custom_command(OUTPUT ${GRADLE_BUILD_FILE}
+        DEPENDS ${GENJAVA_BIN}
+        COMMAND ${CATKIN_ENV} ${PYTHON_EXECUTABLE} ${GENJAVA_BIN}
+            -o ${GRADLE_BUILD_DIR}
+            -p ${ARG_PKG}
+        COMMENT "Generating Java gradle project from ${ARG_PKG}"
+    )
+
+    ################################
+    # Compile Gradle Subproject
+    ################################
+    set(ROS_GRADLE_VERBOSE $ENV{ROS_GRADLE_VERBOSE})
+    if(ROS_GRADLE_VERBOSE)
+        set(GRADLE_CMD "./gradlew")
+    else()
+        set(GRADLE_CMD "./gradlew;-q")
     endif()
-
-  endforeach()
-
+    set(GEN_OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/generated_java_messages.flag)
+
+    add_custom_command(OUTPUT ${GEN_OUTPUT_FILE}
+        DEPENDS ${GRADLE_BUILD_FILE} ${ARG_GENERATED_FILES}
+        COMMAND ${CATKIN_ENV} ${GRADLE_CMD}
+        COMMAND touch ${GEN_OUTPUT_FILE}
+        WORKING_DIRECTORY ${GRADLE_BUILD_DIR}/${ARG_PKG}
+        COMMENT "Generating Java code for ${ARG_PKG}")
+    list(APPEND ALL_GEN_OUTPUT_FILES_java ${GEN_OUTPUT_FILE})
+
+    ################################
+    # Debugging
+    ################################
+    #foreach(gen_output_file ${ALL_GEN_OUTPUT_FILES_java})
+    #    message(STATUS "ALL_GEN_OUTPUT_FILES_java..........${gen_output_file}")
+    #endforeach()
+
+    ################################
+    # Dependent Targets
+    ################################
+    # Make sure we have built gradle-rosjava_bootstrap if it is in the source workspace
+    # (otherwise package.xml will make sure it has installed via rosdep/deb.
+    #if(TARGET gradle-rosjava_bootstrap)
+        # Preference would be to add it to ${ARG_PKG}_generate_messages_java but that
+        # is not defined till after this module is parsed, so add it all
+        #add_dependencies(${ARG_PKG}_generate_messages gradle-rosjava_bootstrap)
+    #endif()
 endmacro()
 
-if(NOT EXISTS @(PROJECT_NAME)_SOURCE_DIR)
-  set(GENJAVA_INSTALL_DIR ${PYTHON_INSTALL_DIR})
-endif()
\ No newline at end of file
diff --git a/package.xml b/package.xml
index 84622fd1fd74c59d1500b4f9684cb9c854793fbb..e40e2e9f3beb098ef6e108c1a8c22fae5e39f1e3 100644
--- a/package.xml
+++ b/package.xml
@@ -18,8 +18,14 @@
   <buildtool_depend version_gte="0.5.78">catkin</buildtool_depend>
 
   <build_depend>genmsg</build_depend>
+  <build_depend>python-catkin-pkg</build_depend>
+  <build_depend>python-rospkg</build_depend>
+  <build_depend>rosjava_bootstrap</build_depend>
 
   <run_depend>genmsg</run_depend>
+  <run_depend>python-catkin-pkg</run_depend>
+  <run_depend>python-rospkg</run_depend>
+  <run_depend>rosjava_bootstrap</run_depend>
 
   <export>
     <message_generator>java</message_generator>
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index 044a96f9ce5c9cda24318b647bf041d0b6089129..5f1a2b4f4339d6d62bf1b6795e3fa0f6fa7f867b 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -1,3 +1,8 @@
+##############################################################################
+# Installs
+##############################################################################
+
 catkin_install_python(
-  PROGRAMS genjava.py gensrv_java.py
-  DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
+    PROGRAMS genjava_gradle_project.py
+    DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
+)
diff --git a/scripts/genjava.py b/scripts/genjava_gradle_project.py
similarity index 57%
rename from scripts/genjava.py
rename to scripts/genjava_gradle_project.py
index 769db0b14884bfc85a256052f9d5bb115b9e5da8..3039c43c3d732bbd0f919528d0de0fa2ecf3b353 100755
--- a/scripts/genjava.py
+++ b/scripts/genjava_gradle_project.py
@@ -8,9 +8,8 @@ Converts ROS .msg files in a package into Java source code implementations.
 import os
 import sys
 
-#import genjava.generator
-import genjava.genjava_main
+import genjava
 
 if __name__ == "__main__":
-    genjava.genjava_main.genmain(sys.argv, 'genmsg_java.py') #, genpy.generator.MsgGenerator())
+    genjava.main(sys.argv)
 
diff --git a/scripts/gensrv_java.py b/scripts/gensrv_java.py
deleted file mode 100755
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/genjava/__init__.py b/src/genjava/__init__.py
index ce7b434e8f3d0f975c262118ce6769823ff0d6c7..f79a649d0272459914a7a1361228d147f3d6b9e6 100644
--- a/src/genjava/__init__.py
+++ b/src/genjava/__init__.py
@@ -35,3 +35,5 @@
 
 #__all__ = ['Time', 'Duration', 'TVal',
 #        'Message', 'SerializationError', 'DeserializationError', 'MessageException', 'struct_I']
+
+from .genjava_main import main
diff --git a/src/genjava/genjava_main.py b/src/genjava/genjava_main.py
index e75a67c897f332b50fc1e318e49ccace98317b06..3d947ae8e0da6d1eb451c5803246c06a30b9d088 100644
--- a/src/genjava/genjava_main.py
+++ b/src/genjava/genjava_main.py
@@ -36,46 +36,49 @@
 
 from __future__ import print_function
 import argparse
-import os
+#import os
 #import sys
 #import traceback
 #import genmsg
-import genmsg.command_line
+#import genmsg.command_line
 
 #from genmsg import MsgGenerationException
 #from . generate_initpy import write_modules
+from . import gradle_project
 
 ##############################################################################
 # Methods
 ##############################################################################
 
 
-def parse_arguments():
+def parse_arguments(argv):
     '''
       The include path has a special format, e.g.
          -Ifoo_msgs:/mnt/zaphod/ros/rosjava/hydro/src/foo_msgs/msg;-Istd_msgs:/opt/ros/hydro/share/std_msgs/cmake/../msg
     '''
     parser = argparse.ArgumentParser(description='Generate java code for a single ros message.')
-    parser.add_argument('-m', '--message', action='store', help='the message file')
+    #parser.add_argument('-m', '--message', action='store', help='the message file')
     parser.add_argument('-p', '--package', action='store', help='package to find the message file')
     parser.add_argument('-o', '--output-dir', action='store', help='output directory for the java code (e.g. build/foo_msgs)')
-    parser.add_argument('-I', '--include-path', action='append', help="include paths to the package and deps msg files")
+    #parser.add_argument('-I', '--include-path', action='append', help="include paths to the package and deps msg files")
     #myargs = rospy.myargv(argv=sys.argv)
     #return parser.parse_args(args=myargs[1:])
-    return parser.parse_args()
+    return parser.parse_args(argv)
 
 ##############################################################################
 # Main
 ##############################################################################
 
-def genmain(argv, progname):  # , gen):
-    args = parse_arguments()
-    print("genjava %s/%s" % (args.package, args.message))
+
+def main(argv):
+    args = parse_arguments(argv[1:])
+    #print("genjava %s/%s" % (args.package, args.message))
     print("  output dir..........%s" % args.output_dir)
-    search_path = genmsg.command_line.includepath_to_dict(args.include_path)
-    print("  search path.......%s" % search_path)
-    gradle_project_dir = os.path.join(args.output_dir, 'gradle')
-    os.mkdir(gradle_project_dir)
+    gradle_project.create(args.package, args.output_dir)
+    #search_path = genmsg.command_line.includepath_to_dict(args.include_path)
+    #print("  search path.......%s" % search_path)
+    #gradle_project_dir = os.path.join(args.output_dir, 'gradle')
+    #os.mkdir(gradle_project_dir)
 
 #     try:
 #         if options.initpy:
diff --git a/src/genjava/genjava_main.pyc b/src/genjava/genjava_main.pyc
index 149ebb8c4b88e6f5a172ae7269e8c91f6ee6e832..364d7ce18054d258b89d3bb490bdc694b672a559 100644
Binary files a/src/genjava/genjava_main.pyc and b/src/genjava/genjava_main.pyc differ
diff --git a/src/genjava/gradle/Readme.md b/src/genjava/gradle/Readme.md
new file mode 100644
index 0000000000000000000000000000000000000000..4068f0ceab10aabf2d3d5e787adb590552a6fdc7
--- /dev/null
+++ b/src/genjava/gradle/Readme.md
@@ -0,0 +1,3 @@
+This is not installed, but it gets used to generate the gradle wrapper for a project.
+
+It is currently the gradle wrapper supporting gradle 1.9.
\ No newline at end of file
diff --git a/src/genjava/gradle/gradle/wrapper/gradle-wrapper.jar b/src/genjava/gradle/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000000000000000000000000000000000..3c7abdf12790879c06b07176de29647f77aa4129
Binary files /dev/null and b/src/genjava/gradle/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/src/genjava/gradle/gradle/wrapper/gradle-wrapper.properties b/src/genjava/gradle/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000000000000000000000000000000000..46530efbac96746779f33e4394b92287ab7e6ce1
--- /dev/null
+++ b/src/genjava/gradle/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Mar 19 17:27:39 KST 2014
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-bin.zip
diff --git a/src/genjava/gradle/gradlew b/src/genjava/gradle/gradlew
new file mode 100755
index 0000000000000000000000000000000000000000..91a7e269e19dfc62e27137a0b57ef3e430cee4fd
--- /dev/null
+++ b/src/genjava/gradle/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/src/genjava/gradle_project.py b/src/genjava/gradle_project.py
new file mode 100644
index 0000000000000000000000000000000000000000..da8e2c7340d5046ce18d0de2c6a4d276523111b9
--- /dev/null
+++ b/src/genjava/gradle_project.py
@@ -0,0 +1,161 @@
+#!/usr/bin/env python
+
+##############################################################################
+# Imports
+##############################################################################
+
+from __future__ import print_function
+
+import os
+import shutil
+
+# local imports
+#import utils
+from catkin_pkg.packages import find_packages
+import rospkg
+
+##############################################################################
+# Utils
+##############################################################################
+
+import pwd
+
+
+def author_name():
+    """
+    Utility to compute logged in user name
+
+    :returns: name of current user, ``str``
+    """
+    import getpass
+    name = getpass.getuser()
+    try:
+        login = name
+        name = pwd.getpwnam(login)[4]
+        name = ''.join(name.split(','))  # strip commas
+        # in case pwnam is not set
+        if not name:
+            name = login
+    except:
+        #pwd failed
+        pass
+    #if type(name) == str:
+    #    name = name.decode('utf-8')
+    return name
+
+
+import subprocess
+
+
+def create_gradle_wrapper(repo_path):
+    gradle_binary = os.path.join(os.path.dirname(__file__), 'gradle', 'gradlew')
+    cmd = [gradle_binary, '-p', repo_path, 'wrapper']
+    print("Creating gradle wrapper: %s" % ' '.join(cmd))
+    try:
+        subprocess.check_call(cmd)
+    except subprocess.CalledProcessError:
+        raise subprocess.CalledProcessError("failed to create the gradle wrapper.")
+
+
+def read_template(tmplf):
+    f = open(tmplf, 'r')
+    try:
+        t = f.read()
+    finally:
+        f.close()
+    return t
+
+##############################################################################
+# Methods acting on classes
+##############################################################################
+
+
+def instantiate_genjava_template(template, project_name, project_version, pkg_directory, author, msg_dependencies):
+    return template % locals()
+
+
+def get_templates():
+    template_dir = os.path.join(os.path.dirname(__file__), 'templates', 'genjava_project')
+    templates = {}
+    templates['build.gradle'] = read_template(os.path.join(template_dir, 'build.gradle.in'))
+    return templates
+
+
+def populate_project(project_name, project_version, pkg_directory, gradle_project_dir, msg_dependencies):
+    author = author_name()
+    for filename, template in get_templates().iteritems():
+        contents = instantiate_genjava_template(template, project_name, project_version, pkg_directory, author, msg_dependencies)
+        try:
+            p = os.path.abspath(os.path.join(gradle_project_dir, filename))
+            f = open(p, 'w')
+            f.write(contents)
+            #console.pretty_print("Created file: ", console.cyan)
+            #console.pretty_println("%s" % p, console.yellow)
+        finally:
+            f.close()
+
+
+def create_dependency_string(project_name, msg_package_index):
+    package = msg_package_index[project_name]
+    gradle_dependency_string = ""
+    for dep in package.build_depends:
+        try:
+            dependency_package = msg_package_index[dep.name]
+        except KeyError:
+            continue  # it's not a message package
+        gradle_dependency_string += "compile 'org.ros.rosjava_messages:" + dependency_package.name + ":" + dependency_package.version + "'\n"
+    return gradle_dependency_string
+
+
+def create_msg_package_index():
+    """
+      Scans the package paths and creates a package index always taking the
+      highest in the workspace chain (i.e. takes an overlay in preference when
+      there are multiple instances of the package).
+
+      :returns: the package index
+      :rtype: { name : catkin_pkg.Package }
+    """
+    # should use this, but it doesn't sequence them properly, so we'd have to make careful version checks
+    # this is inconvenient since it would always mean we should bump the version number in an overlay
+    # when all that is necessary is for it to recognise that it is in an overlay
+    # ros_paths = rospkg.get_ros_paths()
+    package_index = {}
+    ros_paths = rospkg.get_ros_package_path()
+    ros_paths = [x for x in ros_paths.split(':') if x]
+    for path in reversed(ros_paths):  # make sure we pick up the source overlays last
+        for unused_package_path, package in find_packages(path).items():
+            if 'message_generation' in [dep.name for dep in package.build_depends]:
+#                 print(package.name)
+#                 print("  version: %s" % package.version)
+#                 print("  dependencies: ")
+#                 for dep in package.build_depends:
+#                     if not (dep.name == 'message_generation'):
+#                         print("         : %s" % dep)
+                package_index[package.name] = package
+    return package_index
+
+
+def create(msg_pkg_name, output_dir):
+    '''
+    Creates a standalone single project gradle build instance in the specified output directory and
+    populates it with gradle wrapper and build.gradle file that will enable building of the artifact later.
+
+    :param str project_name:
+    :param dict msg_package_index:  { name : catkin_pkg.Package }
+    :param str output_dir:
+    '''
+    if os.path.exists(output_dir):
+        shutil.rmtree(output_dir)
+    genjava_gradle_dir = os.path.join(output_dir, msg_pkg_name)
+    os.makedirs(genjava_gradle_dir)
+    msg_package_index = create_msg_package_index()
+    if msg_pkg_name not in msg_package_index.keys():
+        raise IOError("could not find %s on the ros package path" % msg_pkg_name)
+
+    msg_dependencies = create_dependency_string(msg_pkg_name, msg_package_index)
+
+    create_gradle_wrapper(genjava_gradle_dir)
+    pkg_directory = os.path.dirname(msg_package_index[msg_pkg_name].filename)
+    msg_pkg_version = msg_package_index[msg_pkg_name].version
+    populate_project(msg_pkg_name, msg_pkg_version, pkg_directory, genjava_gradle_dir, msg_dependencies)
diff --git a/src/genjava/templates/genjava_project/build.gradle.in b/src/genjava/templates/genjava_project/build.gradle.in
new file mode 100644
index 0000000000000000000000000000000000000000..c0896ea326e38648dd01345806e55256d955ba11
--- /dev/null
+++ b/src/genjava/templates/genjava_project/build.gradle.in
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 %(author)s
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+task wrapper(type: Wrapper) {
+    gradleVersion = '1.11'
+}
+
+buildscript {
+    def rosMavenPath = "$System.env.ROS_MAVEN_PATH".split(':').collect { 'file://' + it }
+    def rosMavenRepository = "$System.env.ROS_MAVEN_REPOSITORY"
+    repositories {
+        rosMavenPath.each { p ->
+            maven {
+                url p
+            }
+        }
+        mavenLocal()
+        maven {
+            url rosMavenRepository
+        }
+    }
+    dependencies {
+        classpath group: 'org.ros.rosjava_bootstrap', name: 'gradle_plugins', version: '[0.1,0.2)'
+    }
+}
+
+apply plugin: 'ros-java'
+group 'org.ros.rosjava_messages'
+version = '%(project_version)s'
+
+ext {
+    generated_sources_directory = "${projectDir}/src/main/java"
+}
+
+task generateSources (type: JavaExec) {
+    description = "Generate sources for %(project_name)s"
+    outputs.dir(file(generated_sources_directory))
+    args = new ArrayList<String>([generated_sources_directory, '--package-path=%(pkg_directory)s', '%(project_name)s'])
+    classpath = configurations.runtime
+    main = 'org.ros.internal.message.GenerateInterfaces'
+    tasks.compileJava.source outputs.files
+}
+
+dependencies {
+  compile 'org.ros.rosjava_bootstrap:message_generation:[0.1,)'
+  %(msg_dependencies)s
+}
+
+task info << {
+    println "\nProject Info"
+    println "============\n"
+    println "Name          : ${rootProject}"
+    println "Dir           : ${projectDir}"
+    println "Group         : ${group}"
+    println "Version       : ${version}"
+    println "Configurations: " + configurations
+
+    println "\nPackage Info"
+    println "============\n"
+    println "Name          : %(project_name)s"
+    println "Dir           : %(pkg_directory)s"
+
+    println "\nGenerate Info"
+    println "============\n"
+    println "Output Dir    : ${generated_sources_directory}"
+    println "Task Args     : " + tasks["generateSources"].args
+    tasks["generateSources"].outputs.getFiles().getAsFileTree().each {
+        println "Files         : ${it}"
+    }
+}
+
+defaultTasks 'publishMavenJavaPublicationToMavenRepository'