NO-JIRA: merged from trunk to this branch (jni-binding) with the commands below

$ svn merge https://svn.apache.org/repos/asf/qpid/proton/trunk .
--- Merging r1441382 through r1441388 into '.':
U    proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
--- Recording mergeinfo for merge of r1421251 through r1441388 into '.':
 U   .



git-svn-id: https://svn.apache.org/repos/asf/qpid/proton/branches/jni-binding@1441390 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/.gitignore b/.gitignore
index 3a1ef22..8d9d2f9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,29 @@
 *~
 *.swp
+
+# Start of IntelliJ IDE files
 .idea
 .idea/*
 *.iml
 *.ipr
 *.iws
+# End of IntelliJ IDE files
+
+/build/
 *.class
 *.pyc
+*.pyo
 target
+
 .DS_Store
+
+# Start of Eclipse IDE files
 .project
 .classpath
 .settings
+.cproject
 eclipse-classes
+# End of Eclipse IDE files
+
+# The usual location for proton-c build files
+proton-c/build
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..83d38c7
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,59 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+cmake_minimum_required (VERSION 2.6)
+
+project (Proton C)
+
+set (PN_VERSION_MAJOR 0)
+set (PN_VERSION_MINOR 3)
+set (PN_VERSION "${PN_VERSION_MAJOR}.${PN_VERSION_MINOR}")
+
+# Start of variables used during install
+set (INCLUDE_INSTALL_DIR include CACHE PATH "Include file directory")
+set (LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "Library object file directory")
+set (SYSCONF_INSTALL_DIR etc CACHE PATH "System read only configuration directory")
+set (SHARE_INSTALL_DIR share CACHE PATH "Shared read only data directory")
+set (MAN_INSTALL_DIR share/man CACHE PATH "Manpage directory")
+
+set (PROTON_SHARE ${SHARE_INSTALL_DIR}/proton-${PN_VERSION})
+# End of variables used during install
+
+# Location of proton-api jar created by the build; used by proton-jni and proton-j-impl
+set (PROTON_API_TARGET_JAR ${CMAKE_BINARY_DIR}/proton-j/proton-api/proton-api-${PN_VERSION}.jar)
+set (PROTON_JAR_DEPEND_DIR /usr/share/java/ CACHE PATH
+      "When locating compile-time dependencies, the build system searches this location in addition to the default ones provided by find_jar")
+
+# Pull in local cmake modules
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
+
+find_package( Java )
+if (JAVA_FOUND)
+  message("Java version: ${Java_VERSION}. javac is at: ${Java_JAVAC_EXECUTABLE}")
+  include(UseJava)
+  include(UseProtonJava)
+
+  add_subdirectory(proton-j/proton-api)
+  add_subdirectory(proton-j/proton)
+endif()
+
+add_subdirectory(proton-c)
+
+install (FILES LICENSE README TODO
+         DESTINATION ${PROTON_SHARE})
+
diff --git a/README b/README
new file mode 100644
index 0000000..335fe24
--- /dev/null
+++ b/README
@@ -0,0 +1,178 @@
+Proton is a library for speaking AMQP, including:
+
+  + The AMQP Messenger API, a simple but powerful interface to send and receive
+    messages over AMQP.
+  + The AMQP Protocol Engine, a succinct encapsulation of the full
+    AMQP protocol machinery.
+
+Proton is designed for maximum embeddability:
+
+  + minimal dependencies
+  + minimal assumptions about application threading model
+
+Proton is designed to scale up and down:
+
+  + transparently supports both simple peer to peer messaging and complex
+    globally federated topologies
+
+Proton is multi-lingual:
+
+  + Proton-C - a C implementation with lanuage bindings in Python, Php, Perl,
+    Ruby, and Java (via JNI).
+  + Proton-J - a pure Java implementation
+
+Please see http://qpid.apache.org/proton for a more info.
+
+==== Build Instructions ====
+
+Proton has two separate build systems reflecting the nature of its
+two implementations.
+
+   + Proton-C and the language bindings use CMake.
+   + Proton-J uses Maven.
+
+The two build systems are independent of one and other, that is, Proton-C
+may be built independently of Proton-J, and vice-versa.
+
+=== Proton-C ===
+
+== Build Instructions (Linux) ==
+
+The following prerequesuites are required to do a full build. If you do not
+wish to build a given language binding you can omit the package for that
+language:
+
+  # required dependencies
+  yum install gcc cmake libuuid-devel
+
+  # dependencies needed for ssl support
+  yum install openssl-devel
+
+  # dependencies needed for bindings
+  yum install swig python-devel ruby-devel php-devel java-1.6.0-openjdk
+
+  # dependencies needed for python docs
+  yum install epydoc
+
+From the directory where you found this README file:
+
+  mkdir build
+  cd build
+
+  # Set the install prefix. You may need to adjust depending on your
+  # system.
+  cmake -DCMAKE_INSTALL_PREFIX=/usr ..
+
+  # Omit the docs target if you do not wish to build or install
+  # documentation.
+  make all docs
+
+  # Note that this step will require root privileges.
+  make install
+
+Note that all installed files are stored in the install_manifest.txt
+file.
+
+== Build Instructions (Windows) ==
+
+This describes how to build the Proton library on Windows using Microsoft
+Visual C++ 2010 Express (VC10).
+
+The Proton build uses the cmake tool to generate the Visual Studio project
+files.  These project files can then be loaded into Express and used to build
+the Proton library.
+
+Note that these instructions were created using a 32 bit version of Windows 7
+Professional. These instructions assume use of a command shell.
+
+The following packages must be installed:
+
+    Visual Studio 2010 Express (or equivalent)
+    Python (www.python.org)
+    Cmake (www.cmake.org)
+
+    Notes:
+        - Be sure to install MSVC Express 2010 Service Pack 1 also!
+        - python.exe _must_ be in your path
+        - cmake.exe _must_ be in your path
+
+
+Step 1: Create a 'build' directory - this must be at the same level as the 'src'
+        directory.  Example:
+
+     $ cd proton-c
+     $ mkdir build
+
+Step 2: cd into the build directory
+
+     $ cd build
+
+Step 3: Generate the Visual Studio project files using cmake.  You must provide:
+
+        1) the name of the compiler you are using [see cmake documentation],
+        2) the path to the _directory_ that contains the "CMakeLists.txt"
+           file (the parent directory, in this case).
+     Example:
+
+     $ cmake -G "Visual Studio 10" ..
+
+     Refer to the cmake documentation for more information.
+
+Step 4: Load the ALL_BUILD project into Visual C++ Express.
+
+     4a: Run the Microsoft Visual C++ Express IDE
+     4b: From within the IDE, open the ALL_BUILD project file - it should be in
+         the 'build' directory you created above.
+
+Step 5: Build the ALL_BUILD project.
+
+=== Proton-J ===
+
+== Build Instructions (All platforms) ==
+
+The following prerequesuites are required to do a full build.
+
+  + Apache Maven 3.0 (or higher) (http://maven.apache.org/)
+
+From the directory where you found this README file:
+
+  # To compile and package all Java modules (omitting the tests)
+  mvn -DskipTests package
+
+  # To install the packages in the local Maven repository (usually ~/.m2/repo)
+  mvn -DskipTests install
+
+=== Testing ===
+
+To test Proton, run the system tests (located in the tests subdirectory).
+The system tests are applicable to both the Proton-C and Proton-J
+implementations.
+
+== Test Instructions (Proton-C only) ==
+
+To run the system tests against Proton-C, from the directory where you found this
+README file:
+
+  # Source conifig.sh to set-up the Python path.
+  . config.sh
+
+  # Execute the tests
+  ./tests/python/proton-test
+
+== Test Instructions (Proton-J and Proton-C) ==
+
+To run the system tests, execute Maven specifying profile 'proton-j' to
+test Proton-J, and 'proton-jni' to test the Proton-C implementation via the
+JNI bindings.  (To test Proton-C via the JNI Bindings the JNI Binding must have
+been built with Cmake as described above).
+
+  # To test Proton-J
+  mvn test -P proton-j
+
+  # To test Proton-C via the JNI Bindings
+  mvn test -P proton-jni
+
+  # To produce a nicely formated report containing the test results
+  # (in tests/target/site/surefire-report.html)
+  mvn surefire-report:report
+
diff --git a/proton-c/TODO b/TODO
similarity index 100%
rename from proton-c/TODO
rename to TODO
diff --git a/bin/release.sh b/bin/release.sh
index afe54b1..6f8871f 100755
--- a/bin/release.sh
+++ b/bin/release.sh
@@ -19,7 +19,6 @@
 # under the License.
 #
 
-#
 # release.sh - Creates release tarballs from the upstream source
 # repository.
 #
@@ -77,44 +76,17 @@
     REVISION=$(svn info http://svn.apache.org/repos/asf/qpid/proton | fgrep Revision: | awk '{ print $2 }')
 fi
 
-echo "Using svn revision ${REVISION} for all exports."
+echo "Using svn revision ${REVISION}."
 
 ##
-## Create the C Tarball
+## Create the tarball
 ##
-rootname="qpid-proton-c-${VERSION}"
+rootname="qpid-proton-${VERSION}"
 WORKDIR=$(mktemp -d)
 mkdir -p "${WORKDIR}"
 (
     cd ${WORKDIR}
-    svn export -qr ${REVISION} ${URL}/${BRANCH}/proton-c ${rootname}
-    svn export -qr ${REVISION} ${URL}/${BRANCH}/tests ${rootname}/tests
-
-    cat <<EOF > ${rootname}/SVN_INFO
-Repo: ${URL}
-Branch: ${BRANCH}
-Revision: ${REVISION}
-EOF
-
-    ##
-    ## Remove content not for release
-    ##
-    rm -rf ${rootname}/examples/mailbox
-
-    echo "Generating Archive: ${CURRDIR}/${rootname}.tar.gz"
-    tar zcf ${CURRDIR}/${rootname}.tar.gz ${rootname}
-)
-
-##
-## Create the Java Tarball
-##
-rootname="qpid-proton-j-${VERSION}"
-WORKDIR=$(mktemp -d)
-mkdir -p "${WORKDIR}"
-(
-    cd ${WORKDIR}
-    svn export -qr ${REVISION} ${URL}/${BRANCH}/proton-j ${rootname}
-    svn export -qr ${REVISION} ${URL}/${BRANCH}/tests ${rootname}/tests
+    svn export -qr ${REVISION} ${URL}/${BRANCH}/ ${rootname}
 
     cat <<EOF > ${rootname}/SVN_INFO
 Repo: ${URL}
@@ -124,6 +96,12 @@
 
     mvn org.codehaus.mojo:versions-maven-plugin:1.2:set org.codehaus.mojo:versions-maven-plugin:1.2:commit -DnewVersion="${VERSION}" -f ${WORKDIR}/${rootname}/pom.xml
 
+    ##
+    ## Remove content not for release
+    ##
+    rm -r ${rootname}/proton-c/examples/mailbox
+    rm -r ${rootname}/design
+
     echo "Generating Archive: ${CURRDIR}/${rootname}.tar.gz"
     tar zcf ${CURRDIR}/${rootname}.tar.gz ${rootname}
 )
diff --git a/cmake/Modules/FindJava.cmake b/cmake/Modules/FindJava.cmake
new file mode 100644
index 0000000..dae56bc
--- /dev/null
+++ b/cmake/Modules/FindJava.cmake
@@ -0,0 +1,214 @@
+# - Find Java
+# This module finds if Java is installed and determines where the
+# include files and libraries are. This code sets the following
+# variables:
+#
+#  Java_JAVA_EXECUTABLE    = the full path to the Java runtime
+#  Java_JAVAC_EXECUTABLE   = the full path to the Java compiler
+#  Java_JAVAH_EXECUTABLE   = the full path to the Java header generator
+#  Java_JAVADOC_EXECUTABLE = the full path to the Java documention generator
+#  Java_JAR_EXECUTABLE     = the full path to the Java archiver
+#  Java_VERSION_STRING     = Version of the package found (java version), eg. 1.6.0_12
+#  Java_VERSION_MAJOR      = The major version of the package found.
+#  Java_VERSION_MINOR      = The minor version of the package found.
+#  Java_VERSION_PATCH      = The patch version of the package found.
+#  Java_VERSION_TWEAK      = The tweak version of the package found (after '_')
+#  Java_VERSION            = This is set to: $major.$minor.$patch(.$tweak)
+#
+# The minimum required version of Java can be specified using the
+# standard CMake syntax, e.g. find_package(Java 1.5)
+#
+# NOTE: ${Java_VERSION} and ${Java_VERSION_STRING} are not guaranteed to be
+# identical. For example some java version may return:
+# Java_VERSION_STRING = 1.5.0_17
+# and
+# Java_VERSION        = 1.5.0.17
+#
+# another example is the Java OEM, with:
+# Java_VERSION_STRING = 1.6.0-oem
+# and
+# Java_VERSION        = 1.6.0
+#
+# For these components the following variables are set:
+#
+#  Java_FOUND                    - TRUE if all components are found.
+#  Java_INCLUDE_DIRS             - Full paths to all include dirs.
+#  Java_LIBRARIES                - Full paths to all libraries.
+#  Java_<component>_FOUND        - TRUE if <component> is found.
+#
+# Example Usages:
+#  find_package(Java)
+#  find_package(Java COMPONENTS Runtime)
+#  find_package(Java COMPONENTS Development)
+#
+
+#=============================================================================
+# Copyright 2002-2009 Kitware, Inc.
+# Copyright 2009-2011 Mathieu Malaterre <mathieu.malaterre@gmail.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+# The HINTS option should only be used for values computed from the system.
+set(_JAVA_HINTS
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\2.0;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/bin"
+  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/bin"
+  $ENV{JAVA_HOME}/bin
+  )
+# Hard-coded guesses should still go in PATHS. This ensures that the user
+# environment can always override hard guesses.
+set(_JAVA_PATHS
+  /usr/lib/java/bin
+  /usr/share/java/bin
+  /usr/local/java/bin
+  /usr/local/java/share/bin
+  /usr/java/j2sdk1.4.2_04
+  /usr/lib/j2sdk1.4-sun/bin
+  /usr/java/j2sdk1.4.2_09/bin
+  /usr/lib/j2sdk1.5-sun/bin
+  /opt/sun-jdk-1.5.0.04/bin
+  )
+find_program(Java_JAVA_EXECUTABLE
+  NAMES java
+  HINTS ${_JAVA_HINTS}
+  PATHS ${_JAVA_PATHS}
+)
+
+if(Java_JAVA_EXECUTABLE)
+    execute_process(COMMAND ${Java_JAVA_EXECUTABLE} -version
+      RESULT_VARIABLE res
+      OUTPUT_VARIABLE var
+      ERROR_VARIABLE var # sun-java output to stderr
+      OUTPUT_STRIP_TRAILING_WHITESPACE
+      ERROR_STRIP_TRAILING_WHITESPACE)
+    if( res )
+      if(${Java_FIND_REQUIRED})
+        message( FATAL_ERROR "Error executing java -version" )
+      else()
+        message( STATUS "Warning, could not run java --version")
+      endif()
+    else()
+      # extract major/minor version and patch level from "java -version" output
+      # Tested on linux using
+      # 1. Sun / Sun OEM
+      # 2. OpenJDK 1.6
+      # 3. GCJ 1.5
+      # 4. Kaffe 1.4.2
+      if(var MATCHES "java version \"[0-9]+\\.[0-9]+\\.[0-9_.]+.*\".*")
+        # This is most likely Sun / OpenJDK, or maybe GCJ-java compat layer
+        string( REGEX REPLACE ".* version \"([0-9]+\\.[0-9]+\\.[0-9_.]+.*)\".*"
+                "\\1" Java_VERSION_STRING "${var}" )
+      elseif(var MATCHES "java full version \"kaffe-[0-9]+\\.[0-9]+\\.[0-9_]+\".*")
+        # Kaffe style
+        string( REGEX REPLACE "java full version \"kaffe-([0-9]+\\.[0-9]+\\.[0-9_]+).*"
+                "\\1" Java_VERSION_STRING "${var}" )
+      else()
+        if(NOT Java_FIND_QUIETLY)
+          message(WARNING "regex not supported: ${var}. Please report")
+        endif()
+      endif()
+      string( REGEX REPLACE "([0-9]+).*" "\\1" Java_VERSION_MAJOR "${Java_VERSION_STRING}" )
+      string( REGEX REPLACE "[0-9]+\\.([0-9]+).*" "\\1" Java_VERSION_MINOR "${Java_VERSION_STRING}" )
+      string( REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" Java_VERSION_PATCH "${Java_VERSION_STRING}" )
+      # warning tweak version can be empty:
+      string( REGEX REPLACE "[0-9]+\\.[0-9]+\\.[0-9]+[_\\.]?([0-9]*).*$" "\\1" Java_VERSION_TWEAK "${Java_VERSION_STRING}" )
+      if( Java_VERSION_TWEAK STREQUAL "" ) # check case where tweak is not defined
+        set(Java_VERSION ${Java_VERSION_MAJOR}.${Java_VERSION_MINOR}.${Java_VERSION_PATCH})
+      else()
+        set(Java_VERSION ${Java_VERSION_MAJOR}.${Java_VERSION_MINOR}.${Java_VERSION_PATCH}.${Java_VERSION_TWEAK})
+      endif()
+    endif()
+
+endif()
+
+
+find_program(Java_JAR_EXECUTABLE
+  NAMES jar
+  HINTS ${_JAVA_HINTS}
+  PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JAVAC_EXECUTABLE
+  NAMES javac
+  HINTS ${_JAVA_HINTS}
+  PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JAVAH_EXECUTABLE
+  NAMES javah
+  HINTS ${_JAVA_HINTS}
+  PATHS ${_JAVA_PATHS}
+)
+
+find_program(Java_JAVADOC_EXECUTABLE
+  NAMES javadoc
+  HINTS ${_JAVA_HINTS}
+  PATHS ${_JAVA_PATHS}
+)
+
+#include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake)
+include(FindPackageHandleStandardArgs)
+if(Java_FIND_COMPONENTS)
+
+  # Apache Qpid Proton doesn't support this because of find_package_handle_standard_args
+  # differences (see comment below)
+  message(FATAL_ERROR "Apache Qpid Proton FindJava does not support Java_FIND_COMPONENTS")
+
+  foreach(component ${Java_FIND_COMPONENTS})
+    # User just want to execute some Java byte-compiled
+    if(component STREQUAL "Runtime")
+      find_package_handle_standard_args(Java
+        REQUIRED_VARS Java_JAVA_EXECUTABLE
+        VERSION_VAR Java_VERSION
+        )
+    elseif(component STREQUAL "Development")
+      find_package_handle_standard_args(Java
+        REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
+                      Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
+        VERSION_VAR Java_VERSION
+        )
+    else()
+      message(FATAL_ERROR "Comp: ${component} is not handled")
+    endif()
+    set(Java_${component}_FOUND TRUE)
+  endforeach()
+else()
+  # Check for everything
+
+  # Apache Qpid Proton local change: the line below has been tweaked because
+  # the signature of find_package_handle_standard_args in cmake 2.6 lacks the
+  # REQUIRED_VARS and VERSION_VAR parameters, and specifies the error message differently.
+
+  find_package_handle_standard_args(Java DEFAULT_MSG
+                  Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE
+                  Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE
+    )
+endif()
+
+
+mark_as_advanced(
+  Java_JAVA_EXECUTABLE
+  Java_JAR_EXECUTABLE
+  Java_JAVAC_EXECUTABLE
+  Java_JAVAH_EXECUTABLE
+  Java_JAVADOC_EXECUTABLE
+  )
+
+# LEGACY
+set(JAVA_RUNTIME ${Java_JAVA_EXECUTABLE})
+set(JAVA_ARCHIVE ${Java_JAR_EXECUTABLE})
+set(JAVA_COMPILE ${Java_JAVAC_EXECUTABLE})
+
diff --git a/cmake/Modules/README b/cmake/Modules/README
new file mode 100644
index 0000000..1c679c0
--- /dev/null
+++ b/cmake/Modules/README
@@ -0,0 +1,14 @@
+CMake Modules
+=============
+
+Contents:
+
+UseJava, UseJavaSymLinks, UseJavaClassFilelist:
+
+These are Andreas Schneider's CMake Java Support.  We have our own local copy as all versions of
+CMake < 2.8.9 have defects in their Java support that affect us.  Local modifications are commented
+with "Apache Qpid Proton...".
+
+UseProtonJava:
+
+Custom support functions for the Proton Java modules
diff --git a/cmake/Modules/UseJava.cmake b/cmake/Modules/UseJava.cmake
new file mode 100644
index 0000000..cd3b1f1
--- /dev/null
+++ b/cmake/Modules/UseJava.cmake
@@ -0,0 +1,885 @@
+# - Use Module for Java
+# This file provides functions for Java. It is assumed that FindJava.cmake
+# has already been loaded.  See FindJava.cmake for information on how to
+# load Java into your CMake project.
+#
+# add_jar(TARGET_NAME SRC1 SRC2 .. SRCN RCS1 RCS2 .. RCSN)
+#
+# This command creates a <TARGET_NAME>.jar. It compiles the given source
+# files (SRC) and adds the given resource files (RCS) to the jar file.
+# If only resource files are given then just a jar file is created.
+#
+# Additional instructions:
+#   To add compile flags to the target you can set these flags with
+#   the following variable:
+#
+#       set(CMAKE_JAVA_COMPILE_FLAGS -nowarn)
+#
+#   To add a path or a jar file to the class path you can do this
+#   with the CMAKE_JAVA_INCLUDE_PATH variable.
+#
+#       set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar)
+#
+#   To use a different output name for the target you can set it with:
+#
+#       set(CMAKE_JAVA_TARGET_OUTPUT_NAME shibboleet.jar)
+#       add_jar(foobar foobar.java)
+#
+#   To use a different output directory than CMAKE_CURRENT_BINARY_DIR
+#   you can set it with:
+#
+#       set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin)
+#
+#   To define an entry point in your jar you can set it with:
+#
+#       set(CMAKE_JAVA_JAR_ENTRY_POINT com/examples/MyProject/Main)
+#
+#   To add a VERSION to the target output name you can set it using
+#   CMAKE_JAVA_TARGET_VERSION. This will create a jar file with the name
+#   shibboleet-1.0.0.jar and will create a symlink shibboleet.jar
+#   pointing to the jar with the version information.
+#
+#       set(CMAKE_JAVA_TARGET_VERSION 1.2.0)
+#       add_jar(shibboleet shibbotleet.java)
+#
+#    If the target is a JNI library, utilize the following commands to
+#    create a JNI symbolic link:
+#
+#       set(CMAKE_JNI_TARGET TRUE)
+#       set(CMAKE_JAVA_TARGET_VERSION 1.2.0)
+#       add_jar(shibboleet shibbotleet.java)
+#       install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet)
+#       install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR})
+#
+#    If a single target needs to produce more than one jar from its
+#    java source code, to prevent the accumulation of duplicate class
+#    files in subsequent jars, set/reset CMAKE_JAR_CLASSES_PREFIX prior
+#    to calling the add_jar() function:
+#
+#       set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo)
+#       add_jar(foo foo.java)
+#
+#       set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar)
+#       add_jar(bar bar.java)
+#
+# Target Properties:
+#   The add_jar() functions sets some target properties. You can get these
+#   properties with the
+#      get_property(TARGET <target_name> PROPERTY <propery_name>)
+#   command.
+#
+#   INSTALL_FILES      The files which should be installed. This is used by
+#                      install_jar().
+#   JNI_SYMLINK        The JNI symlink which should be installed.
+#                      This is used by install_jni_symlink().
+#   JAR_FILE           The location of the jar file so that you can include
+#                      it.
+#   CLASS_DIR          The directory where the class files can be found. For
+#                      example to use them with javah.
+#
+# find_jar(<VAR>
+#          name | NAMES name1 [name2 ...]
+#          [PATHS path1 [path2 ... ENV var]]
+#          [VERSIONS version1 [version2]]
+#          [DOC "cache documentation string"]
+#         )
+#
+# This command is used to find a full path to the named jar. A cache
+# entry named by <VAR> is created to stor the result of this command. If
+# the full path to a jar is found the result is stored in the variable
+# and the search will not repeated unless the variable is cleared. If
+# nothing is found, the result will be <VAR>-NOTFOUND, and the search
+# will be attempted again next time find_jar is invoked with the same
+# variable.
+# The name of the full path to a file that is searched for is specified
+# by the names listed after NAMES argument. Additional search locations
+# can be specified after the PATHS argument. If you require special a
+# version of a jar file you can specify it with the VERSIONS argument.
+# The argument after DOC will be used for the documentation string in
+# the cache.
+#
+# install_jar(TARGET_NAME DESTINATION)
+#
+# This command installs the TARGET_NAME files to the given DESTINATION.
+# It should be called in the same scope as add_jar() or it will fail.
+#
+# install_jni_symlink(TARGET_NAME DESTINATION)
+#
+# This command installs the TARGET_NAME JNI symlinks to the given
+# DESTINATION. It should be called in the same scope as add_jar()
+# or it will fail.
+#
+# create_javadoc(<VAR>
+#                PACKAGES pkg1 [pkg2 ...]
+#                [SOURCEPATH <sourcepath>]
+#                [CLASSPATH <classpath>]
+#                [INSTALLPATH <install path>]
+#                [DOCTITLE "the documentation title"]
+#                [WINDOWTITLE "the title of the document"]
+#                [AUTHOR TRUE|FALSE]
+#                [USE TRUE|FALSE]
+#                [VERSION TRUE|FALSE]
+#               )
+#
+# Create java documentation based on files or packages. For more
+# details please read the javadoc manpage.
+#
+# There are two main signatures for create_javadoc. The first
+# signature works with package names on a path with source files:
+#
+#   Example:
+#   create_javadoc(my_example_doc
+#     PACKAGES com.exmaple.foo com.example.bar
+#     SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}"
+#     CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
+#     WINDOWTITLE "My example"
+#     DOCTITLE "<h1>My example</h1>"
+#     AUTHOR TRUE
+#     USE TRUE
+#     VERSION TRUE
+#   )
+#
+# The second signature for create_javadoc works on a given list of
+# files.
+#
+#   create_javadoc(<VAR>
+#                  FILES file1 [file2 ...]
+#                  [CLASSPATH <classpath>]
+#                  [INSTALLPATH <install path>]
+#                  [DOCTITLE "the documentation title"]
+#                  [WINDOWTITLE "the title of the document"]
+#                  [AUTHOR TRUE|FALSE]
+#                  [USE TRUE|FALSE]
+#                  [VERSION TRUE|FALSE]
+#                 )
+#
+# Example:
+#   create_javadoc(my_example_doc
+#     FILES ${example_SRCS}
+#     CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH}
+#     WINDOWTITLE "My example"
+#     DOCTITLE "<h1>My example</h1>"
+#     AUTHOR TRUE
+#     USE TRUE
+#     VERSION TRUE
+#   )
+#
+# Both signatures share most of the options. These options are the
+# same as what you can find in the javadoc manpage. Please look at
+# the manpage for CLASSPATH, DOCTITLE, WINDOWTITLE, AUTHOR, USE and
+# VERSION.
+#
+# The documentation will be by default installed to
+#
+#   ${CMAKE_INSTALL_PREFIX}/share/javadoc/<VAR>
+#
+# if you don't set the INSTALLPATH.
+#
+
+#=============================================================================
+# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
+# Copyright 2010 Ben Boeckel <ben.boeckel@kitware.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+message("Loading Proton's UseJava module")
+
+function (__java_copy_file src dest comment)
+    add_custom_command(
+        OUTPUT  ${dest}
+        COMMAND cmake -E copy_if_different
+        ARGS    ${src}
+                ${dest}
+        DEPENDS ${src}
+        COMMENT ${comment})
+endfunction ()
+
+# define helper scripts
+#set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake)
+#set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake)
+set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_MODULE_PATH}/UseJavaClassFilelist.cmake)
+set(_JAVA_SYMLINK_SCRIPT ${CMAKE_MODULE_PATH}/UseJavaSymlinks.cmake)
+
+function(add_jar _TARGET_NAME)
+    set(_JAVA_SOURCE_FILES ${ARGN})
+
+    if (NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR)
+      set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
+    endif()
+
+    if (CMAKE_JAVA_JAR_ENTRY_POINT)
+      set(_ENTRY_POINT_OPTION e)
+      set(_ENTRY_POINT_VALUE ${CMAKE_JAVA_JAR_ENTRY_POINT})
+    endif ()
+
+    if (LIBRARY_OUTPUT_PATH)
+        set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH})
+    else ()
+        set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR})
+    endif ()
+
+    set(CMAKE_JAVA_INCLUDE_PATH
+        ${CMAKE_JAVA_INCLUDE_PATH}
+        ${CMAKE_CURRENT_SOURCE_DIR}
+        ${CMAKE_JAVA_OBJECT_OUTPUT_PATH}
+        ${CMAKE_JAVA_LIBRARY_OUTPUT_PATH}
+    )
+
+    if (WIN32 AND NOT CYGWIN)
+        set(CMAKE_JAVA_INCLUDE_FLAG_SEP ";")
+    else ()
+        set(CMAKE_JAVA_INCLUDE_FLAG_SEP ":")
+    endif()
+
+    foreach (JAVA_INCLUDE_DIR ${CMAKE_JAVA_INCLUDE_PATH})
+       set(CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_PATH_FINAL}${CMAKE_JAVA_INCLUDE_FLAG_SEP}${JAVA_INCLUDE_DIR}")
+    endforeach()
+
+    set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_JAVA_TARGET_OUTPUT_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir")
+
+    set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar")
+    if (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION)
+        set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar")
+        set(_JAVA_TARGET_OUTPUT_LINK "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar")
+    elseif (CMAKE_JAVA_TARGET_VERSION)
+        set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar")
+        set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar")
+    elseif (CMAKE_JAVA_TARGET_OUTPUT_NAME)
+        set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar")
+    endif ()
+    # reset
+    set(CMAKE_JAVA_TARGET_OUTPUT_NAME)
+
+    set(_JAVA_CLASS_FILES)
+    set(_JAVA_COMPILE_FILES)
+    set(_JAVA_DEPENDS)
+    set(_JAVA_RESOURCE_FILES)
+    foreach(_JAVA_SOURCE_FILE ${_JAVA_SOURCE_FILES})
+        get_filename_component(_JAVA_EXT ${_JAVA_SOURCE_FILE} EXT)
+        get_filename_component(_JAVA_FILE ${_JAVA_SOURCE_FILE} NAME_WE)
+        get_filename_component(_JAVA_PATH ${_JAVA_SOURCE_FILE} PATH)
+        get_filename_component(_JAVA_FULL ${_JAVA_SOURCE_FILE} ABSOLUTE)
+
+        file(RELATIVE_PATH _JAVA_REL_BINARY_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR} ${_JAVA_FULL})
+        file(RELATIVE_PATH _JAVA_REL_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${_JAVA_FULL})
+        string(LENGTH ${_JAVA_REL_BINARY_PATH} _BIN_LEN)
+        string(LENGTH ${_JAVA_REL_SOURCE_PATH} _SRC_LEN)
+        if (${_BIN_LEN} LESS ${_SRC_LEN})
+            set(_JAVA_REL_PATH ${_JAVA_REL_BINARY_PATH})
+        else ()
+            set(_JAVA_REL_PATH ${_JAVA_REL_SOURCE_PATH})
+        endif ()
+        get_filename_component(_JAVA_REL_PATH ${_JAVA_REL_PATH} PATH)
+
+        if (_JAVA_EXT MATCHES ".java")
+            list(APPEND _JAVA_COMPILE_FILES ${_JAVA_SOURCE_FILE})
+            set(_JAVA_CLASS_FILE "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_REL_PATH}/${_JAVA_FILE}.class")
+            set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES} ${_JAVA_CLASS_FILE})
+
+        elseif (_JAVA_EXT MATCHES ".jar"
+                OR _JAVA_EXT MATCHES ".war"
+                OR _JAVA_EXT MATCHES ".ear"
+                OR _JAVA_EXT MATCHES ".sar")
+            list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_SOURCE_FILE})
+
+        elseif (_JAVA_EXT STREQUAL "")
+            list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH})
+            list(APPEND _JAVA_DEPENDS ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}})
+
+        else ()
+            __java_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/${_JAVA_SOURCE_FILE}
+                             ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_SOURCE_FILE}
+                             "Copying ${_JAVA_SOURCE_FILE} to the build directory")
+            list(APPEND _JAVA_RESOURCE_FILES ${_JAVA_SOURCE_FILE})
+        endif ()
+    endforeach()
+
+    # create an empty java_class_filelist
+    if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist)
+        file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "")
+    endif()
+
+    if (_JAVA_COMPILE_FILES)
+        # Compile the java files and create a list of class files
+        add_custom_command(
+            # NOTE: this command generates an artificial dependency file
+            OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
+            COMMAND ${Java_JAVAC_EXECUTABLE}
+                ${CMAKE_JAVA_COMPILE_FLAGS}
+                -classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}"
+                -d ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+                ${_JAVA_COMPILE_FILES}
+            COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
+            DEPENDS ${_JAVA_COMPILE_FILES}
+            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+            COMMENT "Building Java objects for ${_TARGET_NAME}.jar"
+        )
+        add_custom_command(
+            OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
+            COMMAND ${CMAKE_COMMAND}
+                -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+                -DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}"
+                -P ${_JAVA_CLASS_FILELIST_SCRIPT}
+            DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME}
+            WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+        )
+    endif ()
+
+    # create the jar file
+    set(_JAVA_JAR_OUTPUT_PATH
+      ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME})
+    if (CMAKE_JNI_TARGET)
+        add_custom_command(
+            OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
+            COMMAND ${Java_JAR_EXECUTABLE}
+                -cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE}
+                ${_JAVA_RESOURCE_FILES} @java_class_filelist
+            COMMAND ${CMAKE_COMMAND}
+                -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
+                -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
+                -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
+                -P ${_JAVA_SYMLINK_SCRIPT}
+            COMMAND ${CMAKE_COMMAND}
+                -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
+                -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_JAR_OUTPUT_PATH}
+                -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
+                -P ${_JAVA_SYMLINK_SCRIPT}
+            DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
+            WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+            COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
+        )
+    else ()
+        add_custom_command(
+            OUTPUT ${_JAVA_JAR_OUTPUT_PATH}
+            COMMAND ${Java_JAR_EXECUTABLE}
+                -cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE}
+                ${_JAVA_RESOURCE_FILES} @java_class_filelist
+            COMMAND ${CMAKE_COMMAND}
+                -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR}
+                -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME}
+                -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK}
+                -P ${_JAVA_SYMLINK_SCRIPT}
+            WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+            DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist
+            COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}"
+        )
+    endif ()
+
+    # Add the target and make sure we have the latest resource files.
+    add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH})
+
+    set_property(
+        TARGET
+            ${_TARGET_NAME}
+        PROPERTY
+            INSTALL_FILES
+                ${_JAVA_JAR_OUTPUT_PATH}
+    )
+
+    if (_JAVA_TARGET_OUTPUT_LINK)
+        set_property(
+            TARGET
+                ${_TARGET_NAME}
+            PROPERTY
+                INSTALL_FILES
+                    ${_JAVA_JAR_OUTPUT_PATH}
+                    ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
+        )
+
+        if (CMAKE_JNI_TARGET)
+            set_property(
+                TARGET
+                    ${_TARGET_NAME}
+                PROPERTY
+                    JNI_SYMLINK
+                        ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK}
+            )
+        endif ()
+    endif ()
+
+    set_property(
+        TARGET
+            ${_TARGET_NAME}
+        PROPERTY
+            JAR_FILE
+                ${_JAVA_JAR_OUTPUT_PATH}
+    )
+
+    set_property(
+        TARGET
+            ${_TARGET_NAME}
+        PROPERTY
+            CLASSDIR
+                ${CMAKE_JAVA_CLASS_OUTPUT_PATH}
+    )
+
+endfunction()
+
+function(INSTALL_JAR _TARGET_NAME _DESTINATION)
+    get_property(__FILES
+        TARGET
+            ${_TARGET_NAME}
+        PROPERTY
+            INSTALL_FILES
+    )
+
+    if (__FILES)
+        install(
+            FILES
+                ${__FILES}
+            DESTINATION
+                ${_DESTINATION}
+        )
+    else ()
+        message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
+    endif ()
+endfunction()
+
+function(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION)
+    get_property(__SYMLINK
+        TARGET
+            ${_TARGET_NAME}
+        PROPERTY
+            JNI_SYMLINK
+    )
+
+    if (__SYMLINK)
+        install(
+            FILES
+                ${__SYMLINK}
+            DESTINATION
+                ${_DESTINATION}
+        )
+    else ()
+        message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.")
+    endif ()
+endfunction()
+
+function (find_jar VARIABLE)
+    set(_jar_names)
+    set(_jar_files)
+    set(_jar_versions)
+    set(_jar_paths
+        /usr/share/java/
+        /usr/local/share/java/
+        ${Java_JAR_PATHS})
+    set(_jar_doc "NOTSET")
+
+    set(_state "name")
+
+    foreach (arg ${ARGN})
+        if (${_state} STREQUAL "name")
+            if (${arg} STREQUAL "VERSIONS")
+                set(_state "versions")
+            elseif (${arg} STREQUAL "NAMES")
+                set(_state "names")
+            elseif (${arg} STREQUAL "PATHS")
+                set(_state "paths")
+            elseif (${arg} STREQUAL "DOC")
+                set(_state "doc")
+            else ()
+                set(_jar_names ${arg})
+                if (_jar_doc STREQUAL "NOTSET")
+                    set(_jar_doc "Finding ${arg} jar")
+                endif ()
+            endif ()
+        elseif (${_state} STREQUAL "versions")
+            if (${arg} STREQUAL "NAMES")
+                set(_state "names")
+            elseif (${arg} STREQUAL "PATHS")
+                set(_state "paths")
+            elseif (${arg} STREQUAL "DOC")
+                set(_state "doc")
+            else ()
+                set(_jar_versions ${_jar_versions} ${arg})
+            endif ()
+        elseif (${_state} STREQUAL "names")
+            if (${arg} STREQUAL "VERSIONS")
+                set(_state "versions")
+            elseif (${arg} STREQUAL "PATHS")
+                set(_state "paths")
+            elseif (${arg} STREQUAL "DOC")
+                set(_state "doc")
+            else ()
+                set(_jar_names ${_jar_names} ${arg})
+                if (_jar_doc STREQUAL "NOTSET")
+                    set(_jar_doc "Finding ${arg} jar")
+                endif ()
+            endif ()
+        elseif (${_state} STREQUAL "paths")
+            if (${arg} STREQUAL "VERSIONS")
+                set(_state "versions")
+            elseif (${arg} STREQUAL "NAMES")
+                set(_state "names")
+            elseif (${arg} STREQUAL "DOC")
+                set(_state "doc")
+            else ()
+                set(_jar_paths ${_jar_paths} ${arg})
+            endif ()
+        elseif (${_state} STREQUAL "doc")
+            if (${arg} STREQUAL "VERSIONS")
+                set(_state "versions")
+            elseif (${arg} STREQUAL "NAMES")
+                set(_state "names")
+            elseif (${arg} STREQUAL "PATHS")
+                set(_state "paths")
+            else ()
+                set(_jar_doc ${arg})
+            endif ()
+        endif ()
+    endforeach ()
+
+    if (NOT _jar_names)
+        message(FATAL_ERROR "find_jar: No name to search for given")
+    endif ()
+
+    foreach (jar_name ${_jar_names})
+        foreach (version ${_jar_versions})
+            set(_jar_files ${_jar_files} ${jar_name}-${version}.jar)
+        endforeach ()
+        set(_jar_files ${_jar_files} ${jar_name}.jar)
+    endforeach ()
+
+    find_file(${VARIABLE}
+        NAMES   ${_jar_files}
+        PATHS   ${_jar_paths}
+        DOC     ${_jar_doc}
+        NO_DEFAULT_PATH)
+endfunction ()
+
+function(create_javadoc _target)
+    set(_javadoc_packages)
+    set(_javadoc_files)
+    set(_javadoc_sourcepath)
+    set(_javadoc_classpath)
+    set(_javadoc_installpath "${CMAKE_INSTALL_PREFIX}/share/javadoc")
+    set(_javadoc_doctitle)
+    set(_javadoc_windowtitle)
+    set(_javadoc_author FALSE)
+    set(_javadoc_version FALSE)
+    set(_javadoc_use FALSE)
+
+    set(_state "package")
+
+    foreach (arg ${ARGN})
+        if (${_state} STREQUAL "package")
+            if (${arg} STREQUAL "PACKAGES")
+                set(_state "packages")
+            elseif (${arg} STREQUAL "FILES")
+                set(_state "files")
+            elseif (${arg} STREQUAL "SOURCEPATH")
+                set(_state "sourcepath")
+            elseif (${arg} STREQUAL "CLASSPATH")
+                set(_state "classpath")
+            elseif (${arg} STREQUAL "INSTALLPATH")
+                set(_state "installpath")
+            elseif (${arg} STREQUAL "DOCTITLE")
+                set(_state "doctitle")
+            elseif (${arg} STREQUAL "WINDOWTITLE")
+                set(_state "windowtitle")
+            elseif (${arg} STREQUAL "AUTHOR")
+                set(_state "author")
+            elseif (${arg} STREQUAL "USE")
+                set(_state "use")
+            elseif (${arg} STREQUAL "VERSION")
+                set(_state "version")
+            else ()
+                set(_javadoc_packages ${arg})
+                set(_state "packages")
+            endif ()
+        elseif (${_state} STREQUAL "packages")
+            if (${arg} STREQUAL "FILES")
+                set(_state "files")
+            elseif (${arg} STREQUAL "SOURCEPATH")
+                set(_state "sourcepath")
+            elseif (${arg} STREQUAL "CLASSPATH")
+                set(_state "classpath")
+            elseif (${arg} STREQUAL "INSTALLPATH")
+                set(_state "installpath")
+            elseif (${arg} STREQUAL "DOCTITLE")
+                set(_state "doctitle")
+            elseif (${arg} STREQUAL "WINDOWTITLE")
+                set(_state "windowtitle")
+            elseif (${arg} STREQUAL "AUTHOR")
+                set(_state "author")
+            elseif (${arg} STREQUAL "USE")
+                set(_state "use")
+            elseif (${arg} STREQUAL "VERSION")
+                set(_state "version")
+            else ()
+                list(APPEND _javadoc_packages ${arg})
+            endif ()
+        elseif (${_state} STREQUAL "files")
+            if (${arg} STREQUAL "PACKAGES")
+                set(_state "packages")
+            elseif (${arg} STREQUAL "SOURCEPATH")
+                set(_state "sourcepath")
+            elseif (${arg} STREQUAL "CLASSPATH")
+                set(_state "classpath")
+            elseif (${arg} STREQUAL "INSTALLPATH")
+                set(_state "installpath")
+            elseif (${arg} STREQUAL "DOCTITLE")
+                set(_state "doctitle")
+            elseif (${arg} STREQUAL "WINDOWTITLE")
+                set(_state "windowtitle")
+            elseif (${arg} STREQUAL "AUTHOR")
+                set(_state "author")
+            elseif (${arg} STREQUAL "USE")
+                set(_state "use")
+            elseif (${arg} STREQUAL "VERSION")
+                set(_state "version")
+            else ()
+                list(APPEND _javadoc_files ${arg})
+            endif ()
+        elseif (${_state} STREQUAL "sourcepath")
+            if (${arg} STREQUAL "PACKAGES")
+                set(_state "packages")
+            elseif (${arg} STREQUAL "FILES")
+                set(_state "files")
+            elseif (${arg} STREQUAL "CLASSPATH")
+                set(_state "classpath")
+            elseif (${arg} STREQUAL "INSTALLPATH")
+                set(_state "installpath")
+            elseif (${arg} STREQUAL "DOCTITLE")
+                set(_state "doctitle")
+            elseif (${arg} STREQUAL "WINDOWTITLE")
+                set(_state "windowtitle")
+            elseif (${arg} STREQUAL "AUTHOR")
+                set(_state "author")
+            elseif (${arg} STREQUAL "USE")
+                set(_state "use")
+            elseif (${arg} STREQUAL "VERSION")
+                set(_state "version")
+            else ()
+                list(APPEND _javadoc_sourcepath ${arg})
+            endif ()
+        elseif (${_state} STREQUAL "classpath")
+            if (${arg} STREQUAL "PACKAGES")
+                set(_state "packages")
+            elseif (${arg} STREQUAL "FILES")
+                set(_state "files")
+            elseif (${arg} STREQUAL "SOURCEPATH")
+                set(_state "sourcepath")
+            elseif (${arg} STREQUAL "INSTALLPATH")
+                set(_state "installpath")
+            elseif (${arg} STREQUAL "DOCTITLE")
+                set(_state "doctitle")
+            elseif (${arg} STREQUAL "WINDOWTITLE")
+                set(_state "windowtitle")
+            elseif (${arg} STREQUAL "AUTHOR")
+                set(_state "author")
+            elseif (${arg} STREQUAL "USE")
+                set(_state "use")
+            elseif (${arg} STREQUAL "VERSION")
+                set(_state "version")
+            else ()
+                list(APPEND _javadoc_classpath ${arg})
+            endif ()
+        elseif (${_state} STREQUAL "installpath")
+            if (${arg} STREQUAL "PACKAGES")
+                set(_state "packages")
+            elseif (${arg} STREQUAL "FILES")
+                set(_state "files")
+            elseif (${arg} STREQUAL "SOURCEPATH")
+                set(_state "sourcepath")
+            elseif (${arg} STREQUAL "DOCTITLE")
+                set(_state "doctitle")
+            elseif (${arg} STREQUAL "WINDOWTITLE")
+                set(_state "windowtitle")
+            elseif (${arg} STREQUAL "AUTHOR")
+                set(_state "author")
+            elseif (${arg} STREQUAL "USE")
+                set(_state "use")
+            elseif (${arg} STREQUAL "VERSION")
+                set(_state "version")
+            else ()
+                set(_javadoc_installpath ${arg})
+            endif ()
+        elseif (${_state} STREQUAL "doctitle")
+            if (${arg} STREQUAL "PACKAGES")
+                set(_state "packages")
+            elseif (${arg} STREQUAL "FILES")
+                set(_state "files")
+            elseif (${arg} STREQUAL "SOURCEPATH")
+                set(_state "sourcepath")
+            elseif (${arg} STREQUAL "INSTALLPATH")
+                set(_state "installpath")
+            elseif (${arg} STREQUAL "CLASSPATH")
+                set(_state "classpath")
+            elseif (${arg} STREQUAL "WINDOWTITLE")
+                set(_state "windowtitle")
+            elseif (${arg} STREQUAL "AUTHOR")
+                set(_state "author")
+            elseif (${arg} STREQUAL "USE")
+                set(_state "use")
+            elseif (${arg} STREQUAL "VERSION")
+                set(_state "version")
+            else ()
+                set(_javadoc_doctitle ${arg})
+            endif ()
+        elseif (${_state} STREQUAL "windowtitle")
+            if (${arg} STREQUAL "PACKAGES")
+                set(_state "packages")
+            elseif (${arg} STREQUAL "FILES")
+                set(_state "files")
+            elseif (${arg} STREQUAL "SOURCEPATH")
+                set(_state "sourcepath")
+            elseif (${arg} STREQUAL "CLASSPATH")
+                set(_state "classpath")
+            elseif (${arg} STREQUAL "INSTALLPATH")
+                set(_state "installpath")
+            elseif (${arg} STREQUAL "DOCTITLE")
+                set(_state "doctitle")
+            elseif (${arg} STREQUAL "AUTHOR")
+                set(_state "author")
+            elseif (${arg} STREQUAL "USE")
+                set(_state "use")
+            elseif (${arg} STREQUAL "VERSION")
+                set(_state "version")
+            else ()
+                set(_javadoc_windowtitle ${arg})
+            endif ()
+        elseif (${_state} STREQUAL "author")
+            if (${arg} STREQUAL "PACKAGES")
+                set(_state "packages")
+            elseif (${arg} STREQUAL "FILES")
+                set(_state "files")
+            elseif (${arg} STREQUAL "SOURCEPATH")
+                set(_state "sourcepath")
+            elseif (${arg} STREQUAL "CLASSPATH")
+                set(_state "classpath")
+            elseif (${arg} STREQUAL "INSTALLPATH")
+                set(_state "installpath")
+            elseif (${arg} STREQUAL "DOCTITLE")
+                set(_state "doctitle")
+            elseif (${arg} STREQUAL "WINDOWTITLE")
+                set(_state "windowtitle")
+            elseif (${arg} STREQUAL "AUTHOR")
+                set(_state "author")
+            elseif (${arg} STREQUAL "USE")
+                set(_state "use")
+            elseif (${arg} STREQUAL "VERSION")
+                set(_state "version")
+            else ()
+                set(_javadoc_author ${arg})
+            endif ()
+        elseif (${_state} STREQUAL "use")
+            if (${arg} STREQUAL "PACKAGES")
+                set(_state "packages")
+            elseif (${arg} STREQUAL "FILES")
+                set(_state "files")
+            elseif (${arg} STREQUAL "SOURCEPATH")
+                set(_state "sourcepath")
+            elseif (${arg} STREQUAL "CLASSPATH")
+                set(_state "classpath")
+            elseif (${arg} STREQUAL "INSTALLPATH")
+                set(_state "installpath")
+            elseif (${arg} STREQUAL "DOCTITLE")
+                set(_state "doctitle")
+            elseif (${arg} STREQUAL "WINDOWTITLE")
+                set(_state "windowtitle")
+            elseif (${arg} STREQUAL "AUTHOR")
+                set(_state "author")
+            elseif (${arg} STREQUAL "USE")
+                set(_state "use")
+            elseif (${arg} STREQUAL "VERSION")
+                set(_state "version")
+            else ()
+                set(_javadoc_use ${arg})
+            endif ()
+        elseif (${_state} STREQUAL "version")
+            if (${arg} STREQUAL "PACKAGES")
+                set(_state "packages")
+            elseif (${arg} STREQUAL "FILES")
+                set(_state "files")
+            elseif (${arg} STREQUAL "SOURCEPATH")
+                set(_state "sourcepath")
+            elseif (${arg} STREQUAL "CLASSPATH")
+                set(_state "classpath")
+            elseif (${arg} STREQUAL "INSTALLPATH")
+                set(_state "installpath")
+            elseif (${arg} STREQUAL "DOCTITLE")
+                set(_state "doctitle")
+            elseif (${arg} STREQUAL "WINDOWTITLE")
+                set(_state "windowtitle")
+            elseif (${arg} STREQUAL "AUTHOR")
+                set(_state "author")
+            elseif (${arg} STREQUAL "USE")
+                set(_state "use")
+            elseif (${arg} STREQUAL "VERSION")
+                set(_state "version")
+            else ()
+                set(_javadoc_version ${arg})
+            endif ()
+        endif ()
+    endforeach ()
+
+    set(_javadoc_builddir ${CMAKE_CURRENT_BINARY_DIR}/javadoc/${_target})
+    set(_javadoc_options -d ${_javadoc_builddir})
+
+    if (_javadoc_sourcepath)
+        set(_start TRUE)
+        foreach(_path ${_javadoc_sourcepath})
+            if (_start)
+                set(_sourcepath ${_path})
+                set(_start FALSE)
+            else ()
+                set(_sourcepath ${_sourcepath}:${_path})
+            endif ()
+        endforeach()
+        set(_javadoc_options ${_javadoc_options} -sourcepath ${_sourcepath})
+    endif ()
+
+    if (_javadoc_classpath)
+        set(_start TRUE)
+        foreach(_path ${_javadoc_classpath})
+            if (_start)
+                set(_classpath ${_path})
+                set(_start FALSE)
+            else ()
+                set(_classpath ${_classpath}:${_path})
+            endif ()
+        endforeach()
+        set(_javadoc_options ${_javadoc_options} -classpath "${_classpath}")
+    endif ()
+
+    if (_javadoc_doctitle)
+        set(_javadoc_options ${_javadoc_options} -doctitle '${_javadoc_doctitle}')
+    endif ()
+
+    if (_javadoc_windowtitle)
+        set(_javadoc_options ${_javadoc_options} -windowtitle '${_javadoc_windowtitle}')
+    endif ()
+
+    if (_javadoc_author)
+        set(_javadoc_options ${_javadoc_options} -author)
+    endif ()
+
+    if (_javadoc_use)
+        set(_javadoc_options ${_javadoc_options} -use)
+    endif ()
+
+    if (_javadoc_version)
+        set(_javadoc_options ${_javadoc_options} -version)
+    endif ()
+
+    add_custom_target(${_target}_javadoc ALL
+        COMMAND ${Java_JAVADOC_EXECUTABLE} ${_javadoc_options}
+                            ${_javadoc_files}
+                            ${_javadoc_packages}
+        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+    )
+
+    install(
+        DIRECTORY ${_javadoc_builddir}
+        DESTINATION ${_javadoc_installpath}
+    )
+endfunction()
diff --git a/cmake/Modules/UseJavaClassFilelist.cmake b/cmake/Modules/UseJavaClassFilelist.cmake
new file mode 100644
index 0000000..6f3a4e7
--- /dev/null
+++ b/cmake/Modules/UseJavaClassFilelist.cmake
@@ -0,0 +1,52 @@
+#
+# This script create a list of compiled Java class files to be added to a
+# jar file. This avoids including cmake files which get created in the
+# binary directory.
+#
+
+#=============================================================================
+# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+if (CMAKE_JAVA_CLASS_OUTPUT_PATH)
+    if (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}")
+
+        set(_JAVA_GLOBBED_FILES)
+        if (CMAKE_JAR_CLASSES_PREFIX)
+            foreach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX})
+                message(STATUS "JAR_CLASS_PREFIX: ${JAR_CLASS_PREFIX}")
+
+                file(GLOB_RECURSE _JAVA_GLOBBED_TMP_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${JAR_CLASS_PREFIX}/*.class")
+                if (_JAVA_GLOBBED_TMP_FILES)
+                    list(APPEND _JAVA_GLOBBED_FILES ${_JAVA_GLOBBED_TMP_FILES})
+                endif ()
+            endforeach()
+        else()
+            file(GLOB_RECURSE _JAVA_GLOBBED_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/*.class")
+        endif ()
+
+        set(_JAVA_CLASS_FILES)
+        # file(GLOB_RECURSE foo RELATIVE) is broken so we need this.
+        foreach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES})
+            file(RELATIVE_PATH _JAVA_CLASS_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ${_JAVA_GLOBBED_FILE})
+            set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES}${_JAVA_CLASS_FILE}\n)
+        endforeach()
+
+        # write to file
+        file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist ${_JAVA_CLASS_FILES})
+
+    else ()
+        message(SEND_ERROR "FATAL: Java class output path doesn't exist")
+    endif ()
+else ()
+    message(SEND_ERROR "FATAL: Can't find CMAKE_JAVA_CLASS_OUTPUT_PATH")
+endif ()
diff --git a/cmake/Modules/UseJavaSymlinks.cmake b/cmake/Modules/UseJavaSymlinks.cmake
new file mode 100644
index 0000000..88dd768
--- /dev/null
+++ b/cmake/Modules/UseJavaSymlinks.cmake
@@ -0,0 +1,32 @@
+#
+# Helper script for UseJava.cmake
+#
+
+#=============================================================================
+# Copyright 2010-2011 Andreas schneider <asn@redhat.com>
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+#  License text for the above reference.)
+
+if (UNIX AND _JAVA_TARGET_OUTPUT_LINK)
+    if (_JAVA_TARGET_OUTPUT_NAME)
+        find_program(LN_EXECUTABLE
+            NAMES
+                ln
+        )
+
+        execute_process(
+            COMMAND ${LN_EXECUTABLE} -sf "${_JAVA_TARGET_OUTPUT_NAME}" "${_JAVA_TARGET_OUTPUT_LINK}"
+            WORKING_DIRECTORY ${_JAVA_TARGET_DIR}
+        )
+    else ()
+        message(SEND_ERROR "FATAL: Can't find _JAVA_TARGET_OUTPUT_NAME")
+    endif ()
+endif ()
diff --git a/cmake/Modules/UseProtonJava.cmake b/cmake/Modules/UseProtonJava.cmake
new file mode 100644
index 0000000..4b011ef
--- /dev/null
+++ b/cmake/Modules/UseProtonJava.cmake
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+
+# Adds a custom command to rebuild the JAR to include resources and the
+# directory entries that are missed by add_jar()
+
+function (rebuild_jar upstream_target jar_name)
+  add_custom_command(TARGET ${upstream_target} POST_BUILD
+                     COMMAND ${Java_JAR_EXECUTABLE} cf ${jar_name}
+                                -C ${CMAKE_CURRENT_SOURCE_DIR}/src/main/resources .
+                                -C ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${upstream_target}.dir/ org
+                     COMMENT "Rebuilding ${jar_name} to include missing resources")
+endfunction ()
+
diff --git a/config.sh b/config.sh
index 5ab1e3b..dbc59a8 100644
--- a/config.sh
+++ b/config.sh
@@ -23,8 +23,8 @@
 cd - > /dev/null
 
 if [ -z "$CPROTON_BUILD" ]; then
-    if [ -d $PROTON_HOME/proton-c/build ]; then
-        PROTON_BINDINGS=$PROTON_HOME/proton-c/build/bindings
+    if [ -d $PROTON_HOME/build/proton-c ]; then
+        PROTON_BINDINGS=$PROTON_HOME/build/proton-c/bindings
     else
         PROTON_BINDINGS=$PROTON_HOME/proton-c/bindings
     fi
@@ -34,9 +34,8 @@
 
 # Python & Jython
 export PYTHON_BINDINGS=$PROTON_BINDINGS/python
-export COMMON_PYPATH=$PROTON_HOME/tests
+export COMMON_PYPATH=$PROTON_HOME/tests/python
 export PYTHONPATH=$COMMON_PYPATH:$PROTON_HOME/proton-c/bindings/python:$PYTHON_BINDINGS
-export JYTHONPATH=$COMMON_PYPATH:$PROTON_HOME/proton-j/proton/src/main/scripts:$PROTON_HOME/proton-j/proton/target/classes:$PROTON_HOME/proton-j/proton-api/target/classes
 
 # PHP
 export PHP_BINDINGS=$PROTON_BINDINGS/php
diff --git a/design/api-reconciliation/README b/design/api-reconciliation/README
new file mode 100644
index 0000000..74aec08
--- /dev/null
+++ b/design/api-reconciliation/README
@@ -0,0 +1,4 @@
+Tool to generate a report mapping proton-c functions to proton-j class methods.
+On Linux, the list of proton-c functions can be generated using generate-c-functions.sh
+
+See pom.xml for more details.
diff --git a/tests/jproton-test b/design/api-reconciliation/generate-c-functions.sh
similarity index 70%
copy from tests/jproton-test
copy to design/api-reconciliation/generate-c-functions.sh
index e26394a..e5cd9d2 100755
--- a/tests/jproton-test
+++ b/design/api-reconciliation/generate-c-functions.sh
@@ -1,5 +1,5 @@
-#!/bin/bash
-#
+#!/bin/sh
+
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -7,9 +7,9 @@
 # to you 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
@@ -18,5 +18,11 @@
 # under the License.
 #
 
-TEST_HOME=$(dirname $(readlink -f ${BASH_SOURCE[0]}))
-exec jython ${TEST_HOME}/proton-test "$@"
+# Script to generate a list of proton-c functions for use as input to the api-reconciliation tool.
+
+BASE_DIR=`dirname $0`
+INCLUDE_DIR=$BASE_DIR/../../proton-c/include/proton
+OUTPUT_DIR=$BASE_DIR/target
+
+mkdir -p $OUTPUT_DIR
+ctags --c-kinds=p -x $INCLUDE_DIR/*.h | awk '{print $1'} > $OUTPUT_DIR/cfunctions.txt
diff --git a/design/api-reconciliation/pom.xml b/design/api-reconciliation/pom.xml
new file mode 100644
index 0000000..d4b59c5
--- /dev/null
+++ b/design/api-reconciliation/pom.xml
@@ -0,0 +1,113 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements.  See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership.  The ASF licenses this file
+ - to you 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.
+ -
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.apache.qpid</groupId>
+  <artifactId>proton-api-reconciliation</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <properties>
+    <proton-c-build-dir>${basedir}/../../proton-c/build</proton-c-build-dir>
+    <jni-jar>${proton-c-build-dir}/bindings/java/proton-jni.jar</jni-jar>
+  </properties>
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.6</source>
+          <target>1.6</target>
+          <optimize>true</optimize>
+          <showDeprecation>true</showDeprecation>
+          <showWarnings>true</showWarnings>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <version>1.2.1</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>java</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <mainClass>org.apache.qpid.proton.apireconciliation.Main</mainClass>
+          <includePluginDependencies>true</includePluginDependencies>
+          <arguments>
+            <argument>org.apache.qpid.proton</argument>
+            <argument>target/cfunctions.txt</argument>
+            <argument>org.apache.qpid.proton.ProtonCEquivalent</argument>
+            <argument>target/apireconciliation.csv</argument>
+          </arguments>
+        </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>proton-jni</artifactId>
+            <version>${project.version}</version>
+            <scope>system</scope>
+            <systemPath>${jni-jar}</systemPath>
+          </dependency>
+          <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>proton-api</artifactId>
+            <version>1.0-SNAPSHOT</version>
+          </dependency>
+        </dependencies>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.10</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.reflections</groupId>
+      <artifactId>reflections</artifactId>
+      <version>0.9.8</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <version>2.6</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <version>2.4</version>
+    </dependency>
+  </dependencies>
+  <description>Tool to generate a report mapping proton-c functions to proton-j class methods.
+Can be run using sensible defaults using &quot;mvn exec:java&quot;</description>
+  <parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>12</version>
+    <relativePath></relativePath>
+  </parent>
+</project>
diff --git a/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/CFunctionNameListReader.java b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/CFunctionNameListReader.java
new file mode 100644
index 0000000..e726801
--- /dev/null
+++ b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/CFunctionNameListReader.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.apireconciliation;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+
+public class CFunctionNameListReader
+{
+
+    public List<String> readCFunctionNames(String fileContainingFunctionNames) throws IOException
+    {
+        File functionNameFile = new File(fileContainingFunctionNames);
+        if (!functionNameFile.canRead())
+        {
+            throw new FileNotFoundException("File " + functionNameFile + " cannot be found or is not readable.");
+        }
+
+        List<String> cFunctionNames = FileUtils.readLines(functionNameFile);
+        return cFunctionNames;
+    }
+
+}
diff --git a/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Joiner.java b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Joiner.java
new file mode 100644
index 0000000..9d73308
--- /dev/null
+++ b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Joiner.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.apireconciliation;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.qpid.proton.apireconciliation.reportwriter.AnnotationAccessor;
+
+public class Joiner
+{
+    private final AnnotationAccessor _annotationAccessor;
+
+    public Joiner(AnnotationAccessor annotationAccessor)
+    {
+        _annotationAccessor = annotationAccessor;
+    }
+
+    /**
+     * Does an outer join of the supplied C functions with those named by the
+     * annotations on the Java methods.
+     */
+    public ReconciliationReport join(List<String> protonCFunctions, Set<Method> javaMethods)
+    {
+        ReconciliationReport report = new ReconciliationReport();
+
+        Map<String, Method> cFunctionToJavaMethodMap = createOneToOneMappingBetweenCFunctionNameAndJavaMethodMap(javaMethods);
+
+        Set<Method> unannotatedMethods = new HashSet<Method>(javaMethods);
+        unannotatedMethods.removeAll(cFunctionToJavaMethodMap.values());
+
+        for (Method unannotatedMethod : unannotatedMethods)
+        {
+            report.addRow(null, unannotatedMethod);
+        }
+
+        for (String protonCFunction : protonCFunctions)
+        {
+            Method javaMethod = cFunctionToJavaMethodMap.remove(protonCFunction);
+            report.addRow(protonCFunction, javaMethod);
+        }
+
+        // add anything remaining in annotatedNameToMethod to report as Java methods with an unknown annotation
+        for (Method method : cFunctionToJavaMethodMap.values())
+        {
+            report.addRow(null, method);
+        }
+
+        return report;
+    }
+
+    private Map<String, Method> createOneToOneMappingBetweenCFunctionNameAndJavaMethodMap(Set<Method> javaMethods)
+    {
+        Map<String, Method> annotatedNameToMethod = new HashMap<String, Method>();
+        Set<String> functionsWithDuplicateJavaMappings = new HashSet<String>();
+
+        for (Method method : javaMethods)
+        {
+            String functionName = _annotationAccessor.getAnnotationValue(method);
+            if (functionName != null)
+            {
+                if (annotatedNameToMethod.containsKey(functionName))
+                {
+                    functionsWithDuplicateJavaMappings.add(functionName);
+                }
+                annotatedNameToMethod.put(functionName, method);
+            }
+        }
+
+        // Any functions that had duplicate java method names are removed.
+        for (String functionName : functionsWithDuplicateJavaMappings)
+        {
+            annotatedNameToMethod.remove(functionName);
+        }
+
+        return annotatedNameToMethod;
+    }
+
+}
diff --git a/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Main.java b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Main.java
new file mode 100644
index 0000000..92557c9
--- /dev/null
+++ b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Main.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.apireconciliation;
+
+import java.util.List;
+
+import org.apache.qpid.proton.apireconciliation.reportwriter.AnnotationAccessor;
+import org.apache.qpid.proton.apireconciliation.reportwriter.ReconciliationReportWriter;
+
+public class Main
+{
+
+    public static void main(String[] args) throws Exception
+    {
+        if (args.length != 4)
+        {
+            System.err.println("Unexpected number of arguments. Usage:");
+            System.err.println("    java " + Main.class.getName() + " packageRootName cFunctionFile annotationClassName outputFile");
+            Runtime.getRuntime().exit(-1);
+        }
+
+        String packageRootName = args[0];
+        String cFunctionFile = args[1];
+        String annotationClassName = args[2];
+        String outputFile = args[3];
+
+        CFunctionNameListReader cFunctionNameListReader = new CFunctionNameListReader();
+
+        AnnotationAccessor annotationAccessor = new AnnotationAccessor(annotationClassName);
+        Reconciliation reconciliation = new Reconciliation(annotationAccessor);
+
+        List<String> cFunctionNames = cFunctionNameListReader.readCFunctionNames(cFunctionFile);
+        ReconciliationReport report = reconciliation.reconcile(cFunctionNames, packageRootName);
+
+        ReconciliationReportWriter writer = new ReconciliationReportWriter(annotationAccessor);
+        writer.write(outputFile, report);
+        System.err.println("Written : " + outputFile);
+    }
+
+}
diff --git a/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Reconciliation.java b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Reconciliation.java
new file mode 100644
index 0000000..7f27b4d
--- /dev/null
+++ b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Reconciliation.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.apireconciliation;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.qpid.proton.apireconciliation.packagesearcher.PackageSearcher;
+import org.apache.qpid.proton.apireconciliation.reportwriter.AnnotationAccessor;
+
+public class Reconciliation
+{
+    private final PackageSearcher _packageSearcher = new PackageSearcher();
+    private final Joiner _joiner;
+
+    public Reconciliation(AnnotationAccessor annotationAccessor)
+    {
+        _joiner = new Joiner(annotationAccessor);
+    }
+
+    public ReconciliationReport reconcile(List<String> protonCFunctions, String packageRootName)
+    {
+        Set<Method> javaMethods = _packageSearcher.findMethods(packageRootName);
+        ReconciliationReport report = _joiner.join(protonCFunctions, javaMethods);
+        return report;
+    }
+
+}
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/ReconciliationReport.java
similarity index 62%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/ReconciliationReport.java
index fd9b0c2..e5bfbaa 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/ReconciliationReport.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,30 +15,26 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
  */
+package org.apache.qpid.proton.apireconciliation;
 
-package org.apache.qpid.proton.engine;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 
-public class ProtonException extends RuntimeException
+public class ReconciliationReport
 {
-    public ProtonException()
+    private List<ReportRow> _reportRows = new ArrayList<ReportRow>();
+
+    public Iterator<ReportRow> rowIterator()
     {
+        return _reportRows.iterator();
     }
 
-    public ProtonException(String message)
+    public void addRow(String declaredProtonCFunction, Method javaMethod)
     {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
+        _reportRows.add(new ReportRow(declaredProtonCFunction, javaMethod));
     }
 
 }
diff --git a/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/ReportRow.java b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/ReportRow.java
new file mode 100644
index 0000000..23ff7ab
--- /dev/null
+++ b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/ReportRow.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.apireconciliation;
+
+import java.lang.reflect.Method;
+
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+public class ReportRow
+{
+    private final String _declaredProtonCFunction;
+    private final Method _javaMethod;
+
+    public ReportRow(String declaredProtonCFunction, Method javaMethod)
+    {
+        _declaredProtonCFunction = declaredProtonCFunction;
+        _javaMethod = javaMethod;
+    }
+
+    public String getCFunction()
+    {
+        return _declaredProtonCFunction;
+    }
+
+    public Method getJavaMethod()
+    {
+        return _javaMethod;
+    }
+
+    @Override
+    public int hashCode()
+    {
+        return new HashCodeBuilder().append(_declaredProtonCFunction)
+                                    .append(_javaMethod)
+                                    .toHashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj)
+    {
+        if (obj == null)
+        {
+            return false;
+        }
+        if (obj == this)
+        {
+            return true;
+        }
+        if (obj.getClass() != getClass())
+        {
+            return false;
+        }
+        ReportRow rhs = (ReportRow) obj;
+        return new EqualsBuilder()
+                      .append(_declaredProtonCFunction, rhs._declaredProtonCFunction)
+                      .append(_javaMethod, rhs._javaMethod)
+                      .isEquals();
+    }
+
+    @Override
+    public String toString()
+    {
+        return new ToStringBuilder(this)
+                .append("_declaredProtonCFunction", _declaredProtonCFunction)
+                .append("_javaMethod", _javaMethod)
+                .toString();
+    }
+
+}
diff --git a/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/packagesearcher/PackageSearcher.java b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/packagesearcher/PackageSearcher.java
new file mode 100644
index 0000000..6a824ae
--- /dev/null
+++ b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/packagesearcher/PackageSearcher.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.apireconciliation.packagesearcher;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import org.reflections.Reflections;
+import org.reflections.scanners.SubTypesScanner;
+
+public class PackageSearcher
+{
+    private final static Logger LOGGER = Logger.getLogger(PackageSearcher.class.getName());
+
+    public Set<Method> findMethods(String packageName)
+    {
+        Reflections reflections = new Reflections(packageName, new SubTypesScanner(false));
+
+        Set<Class<?>> allInterfaces = getAllApiInterfaces(reflections);
+
+        Set<Method> allImplMethods = new HashSet<Method>();
+        for (Class<?> apiInterface : allInterfaces)
+        {
+            List<Method> apiMethodList = Arrays.asList(apiInterface.getMethods());
+            Set<?> impls = reflections.getSubTypesOf(apiInterface);
+            if (impls.size() == 0)
+            {
+                // In the case where there are no implementations of apiInterface, we add the methods of
+                // apiInterface so they appear on the final report.
+                for (Method apiMethod : apiMethodList)
+                {
+                    allImplMethods.add(apiMethod);
+                }
+            }
+            else
+            {
+                for (Object implementingClassObj : impls)
+                {
+                    Class implementingClass = (Class) implementingClassObj;
+                    LOGGER.fine("Found implementation " + implementingClass.getName() + " for " + apiInterface.getName());
+
+                    for (Method apiMethod : apiMethodList)
+                    {
+                        Method implMethod = findImplMethodOfApiMethod(apiMethod, implementingClass);
+                        allImplMethods.add(implMethod);
+                    }
+                }
+            }
+        }
+        return allImplMethods;
+    }
+
+    private Method findImplMethodOfApiMethod(Method apiMethod, Class<?> impl)
+    {
+        try
+        {
+            Method implMethod = impl.getMethod(apiMethod.getName(), apiMethod.getParameterTypes());
+            return implMethod;
+        }
+        catch (Exception e)
+        {
+            // Should not happen
+            throw new IllegalStateException("Could not find implementation of method " + apiMethod
+                    + " on the impl. " + impl, e);
+        }
+    }
+
+    @SuppressWarnings("rawtypes")
+    private Set<Class<?>> getAllApiInterfaces(Reflections reflections)
+    {
+        Set<Class<?>> classes = reflections.getSubTypesOf(Object.class);
+        Set<Class<?>> interfaces = new HashSet<Class<?>>();
+
+        for (Class clazz : classes)
+        {
+            if(clazz.isInterface())
+            {
+                interfaces.add(clazz);
+            }
+        }
+
+        return interfaces;
+    }
+
+}
diff --git a/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/reportwriter/AnnotationAccessor.java b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/reportwriter/AnnotationAccessor.java
new file mode 100644
index 0000000..71a1a91
--- /dev/null
+++ b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/reportwriter/AnnotationAccessor.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.apireconciliation.reportwriter;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+public class AnnotationAccessor
+{
+    private static final String VALUE_METHOD = "value";
+    private final Class<Annotation> _annotationClass;
+    private final Method _functionNameMethod;
+
+    @SuppressWarnings("unchecked")
+    public AnnotationAccessor(String annotationClassName)
+    {
+        try
+        {
+            _annotationClass = (Class<Annotation>) Class.forName(annotationClassName);
+        }
+        catch (ClassNotFoundException e)
+        {
+            throw new IllegalArgumentException("Couldn't find annotation class " + annotationClassName, e);
+        }
+
+        try
+        {
+            _functionNameMethod = _annotationClass.getMethod(VALUE_METHOD);
+        }
+        catch (SecurityException e)
+        {
+            throw new IllegalArgumentException("Couldn't find method " + VALUE_METHOD + " on annotation " + _annotationClass, e);
+        }
+        catch (NoSuchMethodException e)
+        {
+            throw new IllegalArgumentException("Couldn't find method " + VALUE_METHOD + " on annotation " + _annotationClass, e);
+        }
+    }
+
+    public String getAnnotationValue(Method javaMethod)
+    {
+        Annotation annotation = javaMethod.getAnnotation(_annotationClass);
+        if (javaMethod != null && annotation != null)
+        {
+            return getProtonCFunctionName(annotation);
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    private String getProtonCFunctionName(Annotation annotation)
+    {
+        try
+        {
+            return String.valueOf(_functionNameMethod.invoke(annotation));
+        }
+        catch (IllegalArgumentException e)
+        {
+            throw new RuntimeException("Couldn't invoke method " + _functionNameMethod + " on annotation " + annotation, e);
+        }
+        catch (IllegalAccessException e)
+        {
+            throw new RuntimeException("Couldn't invoke method " + _functionNameMethod + " on annotation " + annotation, e);
+        }
+        catch (InvocationTargetException e)
+        {
+            throw new RuntimeException("Couldn't invoke method " + _functionNameMethod + " on annotation " + annotation, e);
+        }
+    }
+}
diff --git a/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/reportwriter/ReconciliationReportWriter.java b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/reportwriter/ReconciliationReportWriter.java
new file mode 100644
index 0000000..efb4cce
--- /dev/null
+++ b/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/reportwriter/ReconciliationReportWriter.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.apireconciliation.reportwriter;
+
+import static java.lang.String.format;
+import static org.apache.commons.lang.StringUtils.defaultString;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.qpid.proton.apireconciliation.ReconciliationReport;
+import org.apache.qpid.proton.apireconciliation.ReportRow;
+
+public class ReconciliationReportWriter
+{
+    private static final String ROW_FORMAT="%s,%s,%s";
+    private static final String REPORT_TITLE = format(ROW_FORMAT, "C function","Java Method","Java Annotation");
+    private final AnnotationAccessor _annotationAccessor;
+
+    public ReconciliationReportWriter(AnnotationAccessor annotationAccessor)
+    {
+        _annotationAccessor = annotationAccessor;
+    }
+
+    public void write(String outputFile, ReconciliationReport report) throws IOException
+    {
+        File output = new File(outputFile);
+        List<String> reportLines = new ArrayList<String>();
+
+        reportLines.add(REPORT_TITLE);
+
+        Iterator<ReportRow> itr = report.rowIterator();
+        while (itr.hasNext())
+        {
+            ReportRow row = itr.next();
+            Method javaMethod = row.getJavaMethod();
+            String cFunction = defaultString(row.getCFunction());
+
+            String fullyQualifiedMethodName = "";
+            String annotationCFunction = "";
+            if (javaMethod != null)
+            {
+                fullyQualifiedMethodName = createFullyQualifiedJavaMethodName(javaMethod);
+                annotationCFunction = defaultString(_annotationAccessor.getAnnotationValue(javaMethod));
+            }
+            reportLines.add(format(ROW_FORMAT, cFunction, fullyQualifiedMethodName, annotationCFunction));
+        }
+
+        FileUtils.writeLines(output, reportLines);
+    }
+
+    private String createFullyQualifiedJavaMethodName(Method javaMethod)
+    {
+        return javaMethod.getDeclaringClass().getName() +  "#" + javaMethod.getName();
+    }
+
+}
diff --git a/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/CFunctionNameListReaderTest.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/CFunctionNameListReaderTest.java
new file mode 100644
index 0000000..4e36a90
--- /dev/null
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/CFunctionNameListReaderTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.apireconciliation;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.Test;
+
+public class CFunctionNameListReaderTest
+{
+
+    private CFunctionNameListReader _cFunctionDeclarationReader = new CFunctionNameListReader();
+
+    @Test
+    public void testReadFileContainingSingleCFunction() throws Exception
+    {
+        String declarationFile = createTestFileContaining("function1", "function2", "function3");
+
+        List<String> functions = _cFunctionDeclarationReader.readCFunctionNames(declarationFile);
+        assertEquals(3, functions.size());
+        assertEquals("function1", functions.get(0));
+        assertEquals("function3", functions.get(2));
+    }
+
+    private String createTestFileContaining(String... functionNames) throws Exception
+    {
+        File file = File.createTempFile(CFunctionNameListReader.class.getSimpleName(), "txt");
+        file.deleteOnExit();
+        FileUtils.writeLines(file, Arrays.asList(functionNames));
+        return file.getAbsolutePath();
+    }
+}
diff --git a/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/JoinerTest.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/JoinerTest.java
new file mode 100644
index 0000000..134d4fe
--- /dev/null
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/JoinerTest.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.apireconciliation;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.qpid.proton.apireconciliation.reportwriter.AnnotationAccessor;
+import org.junit.Before;
+import org.junit.Test;
+
+public class JoinerTest
+{
+    private static final String C_FUNCTION1 = "cFunction1";
+    private static final String C_FUNCTION2 = "cFunction2";
+    private Joiner _joiner;
+    private Method _method1 = null;
+    private Method _method2 = null;
+    private Method _methodSharingFunctionNameAnnotationWithMethod2 = null;
+    private Method _methodWithoutAnnotation;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        _method1 = getClass().getMethod("javaMethodWithMapping1");
+        _method2 = getClass().getMethod("javaMethodWithMapping2");
+        _methodSharingFunctionNameAnnotationWithMethod2 = getClass().getMethod("javaMethodSharingFunctionNameAnnotationWithMethod2");
+        _methodWithoutAnnotation = getClass().getMethod("javaMethodWithoutAnnotation");
+
+        AnnotationAccessor annotationAccessor = new AnnotationAccessor(TestAnnotation.class.getName());
+
+        _joiner = new Joiner(annotationAccessor);
+    }
+
+    @Test
+    public void testSingleRowReport() throws Exception
+    {
+        List<String> protonCFunctions = asList(C_FUNCTION1);
+        Set<Method> javaMethods = new HashSet<Method>(asList(_method1));
+
+        ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods);
+        assertSingleRowEquals(reconciliationReport, C_FUNCTION1, _method1);
+    }
+
+    @Test
+    public void testCFunctionWithoutCorrespondingAnnotatedJavaMethod() throws Exception
+    {
+        List<String> protonCFunctions = asList("functionX");
+        Set<Method> javaMethods = Collections.emptySet();
+
+        ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods);
+        assertSingleRowEquals(reconciliationReport, "functionX", null);
+    }
+
+    @Test
+    public void testJavaMethodAnnotatedWithUnknownCFunctionName() throws Exception
+    {
+        List<String> protonCFunctions = Collections.emptyList();
+        Set<Method> javaMethods = new HashSet<Method>(asList(_method1));
+
+        ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods);
+        assertSingleRowEquals(reconciliationReport, null, _method1);
+    }
+
+    @Test
+    public void testJavaMethodWithoutAnnotation() throws Exception
+    {
+        List<String> protonCFunctions = Collections.emptyList();
+        Set<Method> javaMethods = new HashSet<Method>(asList(_methodWithoutAnnotation));
+
+        ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods);
+        assertSingleRowEquals(reconciliationReport, null, _methodWithoutAnnotation);
+    }
+
+    @Test
+    public void testJavaMethodsWithAnnotationToSameFunction() throws Exception
+    {
+        List<String> protonCFunctions = asList(C_FUNCTION2);
+        Set<Method> javaMethods = new HashSet<Method>(asList(_method2, _methodSharingFunctionNameAnnotationWithMethod2));
+
+        ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods);
+        Set<ReportRow> rowSet = TestUtils.getReportRowsFrom(reconciliationReport);
+
+        Set<ReportRow> expectedRowSet = new HashSet<ReportRow>(asList(
+                new ReportRow(C_FUNCTION2, null),
+                new ReportRow(null, _method2),
+                new ReportRow(null, _methodSharingFunctionNameAnnotationWithMethod2)));
+
+        assertEquals(expectedRowSet, rowSet);
+    }
+
+    @Test
+    public void testMultipleRowReport() throws Exception
+    {
+        List<String> protonCFunctions = asList(C_FUNCTION1, C_FUNCTION2);
+        Set<Method> javaMethods = new HashSet<Method>(asList(_method1, _method2));
+
+        ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods);
+
+        Set<ReportRow> rowSet = TestUtils.getReportRowsFrom(reconciliationReport);
+
+        Set<ReportRow> expectedRowSet = new HashSet<ReportRow>(asList(
+                new ReportRow(C_FUNCTION1, _method1),
+                new ReportRow(C_FUNCTION2, _method2)));
+
+        assertEquals(expectedRowSet,rowSet);
+    }
+
+    private void assertSingleRowEquals(ReconciliationReport reconciliationReport, String expectedCFunctionName, Method expectedJavaMethod)
+    {
+        Iterator<ReportRow> rowIterator = reconciliationReport.rowIterator();
+        ReportRow row = rowIterator.next();
+        assertReportRowEquals(row, expectedCFunctionName, expectedJavaMethod);
+
+        assertFalse(rowIterator.hasNext());
+    }
+
+    private void assertReportRowEquals(ReportRow row, String expectedCFunctionName, Method expectedMethod)
+    {
+        assertEquals(expectedCFunctionName, row.getCFunction());
+        assertEquals(expectedMethod, row.getJavaMethod());
+    }
+
+    @TestAnnotation(C_FUNCTION1)
+    public void javaMethodWithMapping1()
+    {
+    }
+
+    @TestAnnotation(C_FUNCTION2)
+    public void javaMethodWithMapping2()
+    {
+    }
+
+    @TestAnnotation(C_FUNCTION2)
+    public void javaMethodSharingFunctionNameAnnotationWithMethod2()
+    {
+    }
+
+    public void javaMethodWithoutAnnotation()
+    {
+    }
+}
diff --git a/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/ReportRowTest.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/ReportRowTest.java
new file mode 100644
index 0000000..65613d3
--- /dev/null
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/ReportRowTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.apireconciliation;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.Method;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class ReportRowTest
+{
+
+    private Method _javaMethod1;
+    private Method _javaMethod2;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        _javaMethod1 = getClass().getMethod("javaMethod1");
+        _javaMethod2 = getClass().getMethod("javaMethod2");
+    }
+
+    @Test
+    public void testSames() throws Exception
+    {
+
+        ReportRow reportRow = new ReportRow("cfunction", _javaMethod1);
+        Object other = new Object();
+
+        assertTrue(reportRow.equals(reportRow));
+        assertFalse(reportRow.equals(other));
+    }
+
+    @Test
+    public void testEquals() throws Exception
+    {
+
+        assertTrue(new ReportRow("cfunction", _javaMethod1).equals(new ReportRow("cfunction", _javaMethod1)));
+
+        assertFalse(new ReportRow("cfunction", _javaMethod1).equals(new ReportRow("cfunction2", _javaMethod1)));
+        assertFalse(new ReportRow("cfunction2", _javaMethod1).equals(new ReportRow("cfunction2", _javaMethod2)));
+
+        assertFalse(new ReportRow("cfunction", _javaMethod1).equals(null));
+
+    }
+
+    @Test
+    public void testEqualsWithNulls() throws Exception
+    {
+        assertTrue(new ReportRow("cfunction", null).equals(new ReportRow("cfunction", null)));
+        assertTrue(new ReportRow(null, _javaMethod1).equals(new ReportRow(null, _javaMethod1)));
+
+        assertFalse(new ReportRow("cfunction", _javaMethod1).equals(new ReportRow("cfunction", null)));
+        assertFalse(new ReportRow("cfunction", _javaMethod1).equals(new ReportRow(null, _javaMethod1)));
+    }
+
+    // Used by reflection by test methods
+    public void javaMethod1()
+    {
+    }
+
+    // Used by reflection by test methods
+    public void javaMethod2()
+    {
+    }
+}
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/TestAnnotation.java
similarity index 66%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/TestAnnotation.java
index fd9b0c2..146e397 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/TestAnnotation.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,16 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.apireconciliation;
 
-package org.apache.qpid.proton.engine;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
-public class ProtonException extends RuntimeException
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface TestAnnotation
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
-}
+    String value();
+}
\ No newline at end of file
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/TestUtils.java
similarity index 62%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/TestUtils.java
index fd9b0c2..19ba849 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/TestUtils.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,22 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.apireconciliation;
 
-package org.apache.qpid.proton.engine;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
 
-public class ProtonException extends RuntimeException
+public class TestUtils
 {
-    public ProtonException()
+    public static Set<ReportRow> getReportRowsFrom(ReconciliationReport reconciliationReport)
     {
+        Iterator<ReportRow> rowIterator = reconciliationReport.rowIterator();
+        Set<ReportRow> rows = new HashSet<ReportRow>();
+        while (rowIterator.hasNext())
+        {
+            rows.add(rowIterator.next());
+        }
+        return rows;
     }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
 }
diff --git a/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/PackageSearcherTest.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/PackageSearcherTest.java
new file mode 100644
index 0000000..b85cacb
--- /dev/null
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/PackageSearcherTest.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.apireconciliation.packagesearcher;
+
+import static org.junit.Assert.assertEquals;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.manyimpls.Impl1;
+import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.manyimpls.Impl2;
+import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.manyimpls.InterfaceWithManyImpls;
+import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.noimpl.InterfaceWithoutImpl;
+import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.tree.ImplAtTreeTop;
+import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.tree.InterfaceAtTreeTop;
+import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.tree.leaf.ImplAtLeaf;
+import org.junit.Test;
+
+public class PackageSearcherTest
+{
+    private PackageSearcher _packageSearcher = new PackageSearcher();
+
+    @Test
+    public void testFindDescendsPackageTree() throws Exception
+    {
+        String testDataPackage = InterfaceAtTreeTop.class.getPackage().getName();
+        Set<Method> actualMethods = _packageSearcher.findMethods(testDataPackage);
+        assertEquals(2, actualMethods.size());
+
+        Set<Method> expectedMethods = new HashSet<Method>(Arrays.asList(
+                ImplAtTreeTop.class.getMethod("method"),
+                ImplAtLeaf.class.getMethod("method")));
+
+        assertEquals(expectedMethods, actualMethods);
+    }
+
+    @Test
+    public void testZeroImplenentationsOfInterface() throws Exception
+    {
+        String testDataPackage = InterfaceWithoutImpl.class.getPackage().getName();
+
+        Method expectedMethod = InterfaceWithoutImpl.class.getMethod("method");
+
+        Set<Method> actualMethods = _packageSearcher.findMethods(testDataPackage);
+        assertEquals(1, actualMethods.size());
+
+        Method actualMethod = actualMethods.iterator().next();
+        assertEquals(expectedMethod, actualMethod);
+    }
+
+    @Test
+    public void testManyImplenentationsOfInterface() throws Exception
+    {
+        String testDataPackage = InterfaceWithManyImpls.class.getPackage().getName();
+
+        Set<Method> actualMethods = _packageSearcher.findMethods(testDataPackage);
+        assertEquals(2, actualMethods.size());
+
+        String methodName = "method";
+        Set<Method> expectedMethods = new HashSet<Method>(Arrays.asList(
+                Impl1.class.getMethod(methodName),
+                Impl2.class.getMethod(methodName)));
+
+        assertEquals(expectedMethods, actualMethods);
+    }
+}
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/Impl1.java
similarity index 67%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/Impl1.java
index fd9b0c2..6f9c539 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/Impl1.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,13 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.manyimpls;
 
-package org.apache.qpid.proton.engine;
-
-public class ProtonException extends RuntimeException
+public class Impl1 implements InterfaceWithManyImpls
 {
-    public ProtonException()
-    {
-    }
 
-    public ProtonException(String message)
+    public void method()
     {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
     }
 
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/Impl2.java
similarity index 67%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/Impl2.java
index fd9b0c2..97ac514 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/Impl2.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,13 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.manyimpls;
 
-package org.apache.qpid.proton.engine;
-
-public class ProtonException extends RuntimeException
+public class Impl2 implements InterfaceWithManyImpls
 {
-    public ProtonException()
-    {
-    }
 
-    public ProtonException(String message)
+    public void method()
     {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
     }
 
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/InterfaceWithManyImpls.java
similarity index 66%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/InterfaceWithManyImpls.java
index fd9b0c2..d5f01fa 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/InterfaceWithManyImpls.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,10 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.manyimpls;
 
-package org.apache.qpid.proton.engine;
-
-public class ProtonException extends RuntimeException
+public interface InterfaceWithManyImpls
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
+    void method();
 
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/noimpl/InterfaceWithoutImpl.java
similarity index 66%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/noimpl/InterfaceWithoutImpl.java
index fd9b0c2..8d8302f 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/noimpl/InterfaceWithoutImpl.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,9 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.noimpl;
 
-package org.apache.qpid.proton.engine;
-
-public class ProtonException extends RuntimeException
+public interface InterfaceWithoutImpl
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
+    void method();
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/subpackage/InterfaceInSubPackage.java
similarity index 66%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/subpackage/InterfaceInSubPackage.java
index fd9b0c2..c2b5530 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/subpackage/InterfaceInSubPackage.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,30 +15,10 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
  */
+package org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.subpackage;
 
-package org.apache.qpid.proton.engine;
-
-public class ProtonException extends RuntimeException
+public interface InterfaceInSubPackage
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
+    void methodWithinSubpackage();
 }
diff --git a/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/subpackage/impl/ImplOfInterfaceInSubPackage.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/subpackage/impl/ImplOfInterfaceInSubPackage.java
new file mode 100644
index 0000000..dfda90d
--- /dev/null
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/subpackage/impl/ImplOfInterfaceInSubPackage.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.subpackage.impl;
+
+import org.apache.qpid.proton.apireconciliation.TestAnnotation;
+import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.subpackage.InterfaceInSubPackage;
+
+public class ImplOfInterfaceInSubPackage implements InterfaceInSubPackage
+{
+
+    public static final String VALUE_WITHIN_SUBPACKAGE = "subpackageFunction";
+    public static final String METHOD_WITHIN_SUBPACKAGE = "methodWithinSubpackage";
+
+    @TestAnnotation(VALUE_WITHIN_SUBPACKAGE)
+    public void methodWithinSubpackage()
+    {
+    }
+
+}
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/ImplAtTreeTop.java
similarity index 67%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/ImplAtTreeTop.java
index fd9b0c2..8660d68 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/ImplAtTreeTop.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,13 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.tree;
 
-package org.apache.qpid.proton.engine;
-
-public class ProtonException extends RuntimeException
+public class ImplAtTreeTop implements InterfaceAtTreeTop
 {
-    public ProtonException()
-    {
-    }
 
-    public ProtonException(String message)
+    public void method()
     {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
     }
 
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/InterfaceAtTreeTop.java
similarity index 66%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/InterfaceAtTreeTop.java
index fd9b0c2..9b85666 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/InterfaceAtTreeTop.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,10 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.tree;
 
-package org.apache.qpid.proton.engine;
-
-public class ProtonException extends RuntimeException
+public interface InterfaceAtTreeTop
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
+    void method();
 
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/leaf/ImplAtLeaf.java
similarity index 67%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/leaf/ImplAtLeaf.java
index fd9b0c2..511cd76 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/leaf/ImplAtLeaf.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,13 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.tree.leaf;
 
-package org.apache.qpid.proton.engine;
-
-public class ProtonException extends RuntimeException
+public class ImplAtLeaf implements InterfaceAtLeaf
 {
-    public ProtonException()
-    {
-    }
 
-    public ProtonException(String message)
+    public void method()
     {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
     }
 
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/leaf/InterfaceAtLeaf.java
similarity index 66%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/leaf/InterfaceAtLeaf.java
index fd9b0c2..b12d794 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/leaf/InterfaceAtLeaf.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,9 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.tree.leaf;
 
-package org.apache.qpid.proton.engine;
-
-public class ProtonException extends RuntimeException
+public interface InterfaceAtLeaf
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
+    void method();
 }
diff --git a/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/reportwriter/AnnotationAccessorTest.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/reportwriter/AnnotationAccessorTest.java
new file mode 100644
index 0000000..7df2640
--- /dev/null
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/reportwriter/AnnotationAccessorTest.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.apireconciliation.reportwriter;
+
+import static org.junit.Assert.*;
+
+import java.lang.reflect.Method;
+
+import org.apache.qpid.proton.apireconciliation.TestAnnotation;
+import org.junit.Before;
+import org.junit.Test;
+
+public class AnnotationAccessorTest
+{
+    private static final String ANNOTATION_VALUE_1 = "value1";
+    private static final String ANNOTATED_METHOD_NAME = "annotatedMethod";
+    private static final String UNANNOTATED_METHOD_NAME = "unannotatedMethod";
+
+    private Method _annotatedMethod;
+    private Method _unannotatedMethod;
+
+    private String _annotationClassName;
+
+    private AnnotationAccessor _annotationAccessor;
+
+    @Before
+    public void setUp() throws Exception
+    {
+        _annotatedMethod = getClass().getMethod(ANNOTATED_METHOD_NAME);
+        _unannotatedMethod = getClass().getMethod(UNANNOTATED_METHOD_NAME);
+        _annotationClassName = TestAnnotation.class.getName();
+        _annotationAccessor = new AnnotationAccessor(_annotationClassName);
+    }
+
+    @Test
+    public void testGetAnnotationValue()
+    {
+        assertEquals(ANNOTATION_VALUE_1, _annotationAccessor.getAnnotationValue(_annotatedMethod));
+    }
+
+    @Test
+    public void testGetAnnotationValueWithoutAnnotationReturnsNull()
+    {
+        assertNull(_annotationAccessor.getAnnotationValue(_unannotatedMethod));
+    }
+
+    @TestAnnotation(ANNOTATION_VALUE_1)
+    public void annotatedMethod()
+    {
+    }
+
+    public void unannotatedMethod()
+    {
+    }
+}
diff --git a/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/reportwriter/ReconciliationReportWriterTest.java b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/reportwriter/ReconciliationReportWriterTest.java
new file mode 100644
index 0000000..331c9fe
--- /dev/null
+++ b/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/reportwriter/ReconciliationReportWriterTest.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.apireconciliation.reportwriter;
+
+import static org.junit.Assert.*;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.qpid.proton.apireconciliation.ReconciliationReport;
+import org.apache.qpid.proton.apireconciliation.TestAnnotation;
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class ReconciliationReportWriterTest
+{
+    private ReconciliationReportWriter _writer;
+    private ReconciliationReport _report = new ReconciliationReport();
+
+    @Before
+    public void setUp()
+    {
+        _writer = new ReconciliationReportWriter(new AnnotationAccessor(TestAnnotation.class.getName()));
+    }
+
+    @Test
+    public void testReportWithSingleFullyMappedRow() throws Exception
+    {
+        File expectedReport = getClasspathResource("expectedsingle.csv");
+        File outputFile = createTemporaryFile();
+
+        _report.addRow("function1", getClass().getMethod("methodWithMapping"));
+        _writer.write(outputFile.getAbsolutePath(), _report);
+
+        assertFilesSame(expectedReport, outputFile);
+    }
+
+    @Test
+    public void testReportWithManyRowsSomeUnmapped() throws Exception
+    {
+        File expectedReport = getClasspathResource("expectedmany.csv");
+        File outputFile = createTemporaryFile();
+
+        _report.addRow("function1", getClass().getMethod("methodWithMapping"));
+        _report.addRow("function2", getClass().getMethod("anotherMethodWithMapping"));
+        _report.addRow(null, getClass().getMethod("methodWithoutMapping"));
+        _report.addRow("function4", null);
+        _writer.write(outputFile.getAbsolutePath(), _report);
+
+        assertFilesSame(expectedReport, outputFile);
+    }
+
+    private File getClasspathResource(String filename) throws URISyntaxException
+    {
+        URL resource = getClass().getResource(filename);
+        assertNotNull("Resource " + filename + " could not be found",resource);
+        return new File(resource.toURI());
+    }
+
+    private File createTemporaryFile() throws Exception
+    {
+        File tmpFile = File.createTempFile(getClass().getSimpleName(), "csv");
+        tmpFile.deleteOnExit();
+        return tmpFile;
+    }
+
+    private void assertFilesSame(File expectedReport, File actualReport) throws IOException
+    {
+        assertTrue(expectedReport.canRead());
+        assertTrue(actualReport.canRead());
+        assertEquals("Report contents unexpected",
+                FileUtils.readFileToString(expectedReport),
+                FileUtils.readFileToString(actualReport));
+    }
+
+    @TestAnnotation("function1")
+    public void methodWithMapping()
+    {
+    }
+
+    @TestAnnotation("function2")
+    public void anotherMethodWithMapping()
+    {
+    }
+
+    public void methodWithoutMapping()
+    {
+    }
+}
diff --git a/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconciliation/reportwriter/expectedmany.csv b/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconciliation/reportwriter/expectedmany.csv
new file mode 100644
index 0000000..8c8ba3e
--- /dev/null
+++ b/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconciliation/reportwriter/expectedmany.csv
@@ -0,0 +1,5 @@
+C function,Java Method,Java Annotation
+function1,org.apache.qpid.proton.apireconciliation.reportwriter.ReconciliationReportWriterTest#methodWithMapping,function1
+function2,org.apache.qpid.proton.apireconciliation.reportwriter.ReconciliationReportWriterTest#anotherMethodWithMapping,function2
+,org.apache.qpid.proton.apireconciliation.reportwriter.ReconciliationReportWriterTest#methodWithoutMapping,
+function4,,
diff --git a/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconciliation/reportwriter/expectedsingle.csv b/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconciliation/reportwriter/expectedsingle.csv
new file mode 100644
index 0000000..082f623
--- /dev/null
+++ b/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconciliation/reportwriter/expectedsingle.csv
@@ -0,0 +1,2 @@
+C function,Java Method,Java Annotation
+function1,org.apache.qpid.proton.apireconciliation.reportwriter.ReconciliationReportWriterTest#methodWithMapping,function1
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..73242a7
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>12</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.qpid</groupId>
+  <artifactId>proton-project</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <properties>
+    <junit-version>4.10</junit-version>
+  </properties>
+
+  <build>
+    <plugins>
+    <plugin>
+      <groupId>org.apache.maven.plugins</groupId>
+      <artifactId>maven-compiler-plugin</artifactId>
+      <configuration>
+        <source>1.6</source>
+        <target>1.6</target>
+        <optimize>true</optimize>
+        <showDeprecation>true</showDeprecation>
+        <showWarnings>true</showWarnings>
+      </configuration>
+    </plugin>
+    </plugins>
+  </build>
+
+  <profiles>
+    <profile>
+      <id>proton-j</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <modules>
+        <module>proton-j</module>
+        <module>tests</module>
+      </modules>
+    </profile>
+    <profile>
+      <id>proton-jni</id>
+      <modules>
+        <module>proton-j/proton-api</module>
+        <module>tests</module>
+      </modules>
+    </profile>
+  </profiles>
+
+</project>
diff --git a/proton-c/CMakeLists.txt b/proton-c/CMakeLists.txt
index cb6b957..12c2fb7 100644
--- a/proton-c/CMakeLists.txt
+++ b/proton-c/CMakeLists.txt
@@ -16,17 +16,10 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-cmake_minimum_required (VERSION 2.6)
 
 include(CheckLibraryExists)
 include(CheckSymbolExists)
 
-project (Proton C)
-
-set (PN_VERSION_MAJOR 0)
-set (PN_VERSION_MINOR 3)
-set (PN_VERSION "${PN_VERSION_MAJOR}.${PN_VERSION_MINOR}")
-
 include(soversion.cmake)
 
 if(WIN32 AND NOT CYGWIN)
@@ -54,14 +47,6 @@
     endif()
 endif()
 
-set (INCLUDE_INSTALL_DIR include CACHE PATH "Include file directory")
-set (LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "Library object file directory")
-set (SYSCONF_INSTALL_DIR etc CACHE PATH "System read only configuration directory")
-set (SHARE_INSTALL_DIR share CACHE PATH "Shared read only data directory")
-set (MAN_INSTALL_DIR share/man CACHE PATH "Manpage directory")
-
-set (PROTON_SHARE ${SHARE_INSTALL_DIR}/proton-${PN_VERSION})
-
 # Can't use ${CMAKE_VERSION) as it is not available in all versions of cmake 2.6
 if ("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSION_LESS "2.8.0")
     # OPTIONAL does not exist in install before 2.8 so always make docs and install
@@ -85,23 +70,23 @@
 set(SSL_IMPL ${ssl_impl} CACHE STRING "Library to use for SSL/TLS support. Valid values: 'none','openssl'")
 
 configure_file (
-  "${PROJECT_SOURCE_DIR}/pn_config.h.in"
-  "${PROJECT_BINARY_DIR}/pn_config.h"
+  "${CMAKE_CURRENT_SOURCE_DIR}/pn_config.h.in"
+  "${CMAKE_CURRENT_BINARY_DIR}/pn_config.h"
 )
 
-include_directories ("${PROJECT_BINARY_DIR}")
-include_directories ("${PROJECT_SOURCE_DIR}/include")
+include_directories ("${CMAKE_CURRENT_BINARY_DIR}")
+include_directories ("${CMAKE_CURRENT_SOURCE_DIR}/include")
 
 add_custom_command (
-  OUTPUT ${PROJECT_BINARY_DIR}/encodings.h
-  COMMAND python ${PROJECT_SOURCE_DIR}/env.py PYTHONPATH=${PROJECT_SOURCE_DIR} python ${PROJECT_SOURCE_DIR}/src/codec/encodings.h.py > ${PROJECT_BINARY_DIR}/encodings.h
-  DEPENDS ${PROJECT_SOURCE_DIR}/src/codec/encodings.h.py
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
+  COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/env.py PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} python ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py > ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
+  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/codec/encodings.h.py
 )
 
 add_custom_command (
-  OUTPUT ${PROJECT_BINARY_DIR}/protocol.h
-  COMMAND python ${PROJECT_SOURCE_DIR}/env.py PYTHONPATH=${PROJECT_SOURCE_DIR} python ${PROJECT_SOURCE_DIR}/src/protocol.h.py > ${PROJECT_BINARY_DIR}/protocol.h
-  DEPENDS ${PROJECT_SOURCE_DIR}/src/protocol.h.py
+  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
+  COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/env.py PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR} python ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol.h.py > ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
+  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/protocol.h.py
 )
 
 # Select driver
@@ -245,8 +230,8 @@
 
   src/messenger.c
 
-  ${PROJECT_BINARY_DIR}/encodings.h
-  ${PROJECT_BINARY_DIR}/protocol.h
+  ${CMAKE_CURRENT_BINARY_DIR}/encodings.h
+  ${CMAKE_CURRENT_BINARY_DIR}/protocol.h
 )
 
 set_source_files_properties (
@@ -300,10 +285,6 @@
 file(GLOB headers "include/proton/*.[hi]")
 install (FILES ${headers} DESTINATION ${INCLUDE_INSTALL_DIR}/proton)
 
-# Install documentation files
-install (FILES LICENSE README TODO
-         DESTINATION ${PROTON_SHARE})
-
 # Pkg config file
 # Compatible variable names used in the pkg config files also for autoconf
 get_filename_component (PREFIX ${CMAKE_INSTALL_PREFIX} ABSOLUTE)
@@ -311,7 +292,7 @@
 get_filename_component (LIBDIR ${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR} ABSOLUTE)
 get_filename_component (INCLUDEDIR ${CMAKE_INSTALL_PREFIX}/${INCLUDE_INSTALL_DIR} ABSOLUTE)
 
-configure_file(${PROJECT_SOURCE_DIR}/src/libqpid-proton.pc.in
-         ${PROJECT_BINARY_DIR}/libqpid-proton.pc @ONLY)
-install (FILES ${PROJECT_BINARY_DIR}/libqpid-proton.pc
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/libqpid-proton.pc.in
+         ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton.pc @ONLY)
+install (FILES ${CMAKE_CURRENT_BINARY_DIR}/libqpid-proton.pc
          DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
diff --git a/proton-c/LICENSE b/proton-c/LICENSE
deleted file mode 100644
index 6b0b127..0000000
--- a/proton-c/LICENSE
+++ /dev/null
@@ -1,203 +0,0 @@
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!)  The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright [yyyy] [name of copyright owner]
-
-   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.
-
diff --git a/proton-c/README b/proton-c/README
deleted file mode 100644
index db90e41..0000000
--- a/proton-c/README
+++ /dev/null
@@ -1,119 +0,0 @@
-Proton is library for speaking AMQP, including:
-
-  + The AMQP Messenger API, a simple but powerful interface to send
-    and receive messages over AMQP.
-
-  + The AMQP Protocol Engine, a succinct encapsulation of the full
-    AMQP protocol machinery.
-
-Proton is designed for maximum embeddability:
-
-  + minimal dependencies
-
-  + minimal assumptions about application threading model
-
-Proton is designed to scale up and down:
-
-  + transparently supports both simple peer to peer messaging and
-    complex globally federated topologies
-
-Proton is multi-lingual:
-
-  + designed for easy language bindings
-     - includes full fidelity data exchange:
-         maps, lists, strings, custom data structures, and more
-
-Please see http://qpid.apache.org/proton for a more info.
-
-== Build Instructions (Linux) ==
-
-The following prerequesuites are required to do a full build. If you
-do not wish to build a given language binding you can ommit the -devel
-package for that language:
-
-  # required dependencies
-  yum install gcc cmake libuuid-devel
-
-  # dependencies needed for ssl support
-  yum install openssl-devel
-
-  # dependencies needed for bindings
-  yum install swig python-devel ruby-devel php-devel
-
-  # dependencies needed for python docs
-  yum install epydoc
-
-From the directory where you found this README file:
-
-  mkdir build
-  cd build
-
-  # Set the install prefix. You may need to adjust depending on your
-  # system.
-  cmake -DCMAKE_INSTALL_PREFIX=/usr ..
-
-  # Omit the docs target if you do not wish to build or install
-  # documentation.
-  make all docs
-
-  # Note that this step will require root privileges.
-  make install
-
-Note that all installed files are stored in the install_manifest.txt
-file.
-
-
-== Build Instructions (Windows) ==
-
-This describes how to build the Proton library on Windows using Microsoft Visual C++ 2010
-Express (VC10).
-
-The Proton build uses the cmake tool to generate the Visual Studio project files.  These
-project files can then be loaded into Express and used to build the Proton library.
-
-Note that these instructions were created using a 32 bit version of Windows 7
-Professional. These instructions assume use of a command shell.
-
-The following packages must be installed:
-
-    Visual Studio 2010 Express (or equivalent)
-    Python (www.python.org)
-    Cmake (www.cmake.org)
-
-    Notes:
-        - Be sure to install MSVC Express 2010 Service Pack 1 also!
-        - python.exe _must_ be in your path
-        - cmake.exe _must_ be in your path
-
-
-Step 1: Create a 'build' directory - this must be at the same level as the 'src'
-        directory.  Example:
-
-     $ cd proton-c
-     $ mkdir build
-
-Step 2: cd into the build directory
-
-     $ cd build
-
-Step 3: Generate the Visual Studio project files using cmake.  You must provide:
-
-        1) the name of the compiler you are using [see cmake documentation],
-        2) the path to the _directory_ that contains the "CMakeLists.txt"
-           file (the parent directory, in this case).
-     Example:
-
-     $ cmake -G "Visual Studio 10" ..
-
-     Refer to the cmake documentation for more information.
-
-Step 4: Load the ALL_BUILD project into Visual C++ Express.
-
-     4a: Run the Microsoft Visual C++ Express IDE
-     4b: From within the IDE, open the ALL_BUILD project file - it should be in the
-         'build' directory you created above.
-
-Step 5: Build the ALL_BUILD project.
-
-
-
diff --git a/proton-c/bindings/CMakeLists.txt b/proton-c/bindings/CMakeLists.txt
index 44682d6..7ef2314 100644
--- a/proton-c/bindings/CMakeLists.txt
+++ b/proton-c/bindings/CMakeLists.txt
@@ -20,7 +20,7 @@
 include(UseSWIG)
 
 # Add any new bindings here - the directory name must be the same as the binding name
-set (BINDINGS python ruby php perl)
+set (BINDINGS python ruby php perl java)
 
 set (BINDING_DEPS qpid-proton)
 
@@ -58,6 +58,13 @@
   set (DEFAULT_PERL ON)
 endif (PERLLIBS_FOUND)
 
+if (JAVA_FOUND)
+  find_package( JNI )
+  if (JNI_FOUND OR JNI_LIBRARIES)
+    set (DEFAULT_JAVA ON)
+  endif ()
+endif ()
+
 # Shouldn't need to modify below here when adding new language binding
 foreach(BINDING ${BINDINGS})
   string(TOUPPER ${BINDING} UBINDING)
diff --git a/proton-c/bindings/java/CMakeLists.txt b/proton-c/bindings/java/CMakeLists.txt
new file mode 100644
index 0000000..dd07197
--- /dev/null
+++ b/proton-c/bindings/java/CMakeLists.txt
@@ -0,0 +1,48 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+
+SET(CMAKE_SWIG_FLAGS -package org.apache.qpid.proton.jni)
+SET(CMAKE_SWIG_OUTDIR ${CMAKE_CURRENT_BINARY_DIR}/src/main/java/org/apache/qpid/proton/jni)
+
+message( "Using JNI libraries: ${JNI_LIBRARIES}" )
+
+swig_add_module(proton-swig java java.i)
+include_directories(${JNI_INCLUDE_DIRS})
+swig_link_libraries(proton-swig ${BINDING_DEPS}  )
+
+set_target_properties(proton-swig
+    PROPERTIES
+    PREFIX "lib")
+
+add_custom_command(OUTPUT ${CMAKE_SWIG_OUTDIR} COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_SWIG_OUTDIR} COMMENT "Creating target directory for Proton-JNI sources")
+add_custom_target(protonjnioutdir ALL DEPENDS ${CMAKE_SWIG_OUTDIR})
+add_dependencies(proton-swig protonjnioutdir)
+
+set(CMAKE_JAVA_TARGET_VERSION ${PN_VERSION})
+
+file(GLOB_RECURSE THUNKING_SOURCES_ABS "src/main/java/*.java")
+
+set(CMAKE_JAVA_INCLUDE_PATH ${PROTON_API_TARGET_JAR})
+
+add_jar(proton-jni ${CMAKE_SWIG_OUTDIR}/*.java ${THUNKING_SOURCES_ABS})
+
+include(UseProtonJava)
+rebuild_jar(proton-jni proton-jni-${PN_VERSION}.jar)
+
+add_dependencies(proton-jni proton-api proton-swig)
diff --git a/proton-c/bindings/java/java.i b/proton-c/bindings/java/java.i
new file mode 100644
index 0000000..554f924
--- /dev/null
+++ b/proton-c/bindings/java/java.i
@@ -0,0 +1,435 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+%module Proton
+%include "arrays_java.i"
+%include "typemaps.i"
+%include "various.i"
+
+
+%{
+/* Includes the header in the wrapper code */
+#include <proton/engine.h>
+#include <proton/message.h>
+#include <proton/sasl.h>
+#include <proton/ssl.h>
+
+#include <proton/driver.h>
+#include <proton/driver_extras.h>
+#include <proton/messenger.h>
+
+%}
+
+
+%typemap(in) (char *DATA, size_t SIZE) (char *data, jobject arr, jboolean isDirect) {
+  /* %typemap(in) void * */
+  jclass bbclass = JCALL1(GetObjectClass,jenv, $input);
+  jmethodID isDirectId = JCALL3(GetMethodID,jenv, bbclass, "isDirect", "()Z");
+  jmethodID positionId = JCALL3(GetMethodID,jenv, bbclass, "position", "()I");
+  jmethodID remainingId= JCALL3(GetMethodID,jenv, bbclass, "remaining", "()I");
+  isDirect = JCALL2(CallBooleanMethod,jenv, $input, isDirectId);
+  jint position = JCALL2(CallIntMethod,jenv, $input, positionId);
+  $2 = (long)(JCALL2(CallIntMethod,jenv, $input, remainingId));
+
+  if(isDirect) {
+    $1 = JCALL1(GetDirectBufferAddress,jenv, $input) + position;
+    data = (char *)0;
+    arr = (jobject) 0;
+  } else {
+    jmethodID arrayId= JCALL3(GetMethodID,jenv, bbclass, "array", "()[B");
+    jmethodID arrayOffsetId= JCALL3(GetMethodID,jenv, bbclass, "arrayOffset", "()I");
+    jobject a = JCALL2(CallObjectMethod,jenv, $input, arrayId);
+    arr = a;
+    data = JCALL2(GetPrimitiveArrayCritical, jenv, a, NULL);
+    $1 = data + JCALL2(CallIntMethod,jenv, $input, arrayOffsetId) + position;
+
+  }
+}
+
+%typemap(jni) (char *DATA, size_t SIZE) "jobject"
+%typemap(jtype) (char *DATA, size_t SIZE) "java.nio.ByteBuffer"
+%typemap(jstype) (char *DATA, size_t SIZE) "java.nio.ByteBuffer"
+%typemap(javain) (char *DATA, size_t SIZE) "$javainput"
+%typemap(javaout) (char *DATA, size_t SIZE) {
+
+  return $jnicall;
+}
+
+%typemap(freearg) (char *DATA, size_t SIZE)  {
+
+  if(!isDirect$argnum) {
+    JCALL3(ReleasePrimitiveArrayCritical, jenv, arr$argnum, data$argnum,0);
+  }
+}
+
+
+
+
+%typemap(in) (char *DATA, size_t *SIZE) (char *data, jobject array, jboolean isDirect, jclass bbclass) {
+  /* %typemap(in) void * */
+  bbclass = JCALL1(GetObjectClass,jenv, $input);
+  jmethodID isDirectId = JCALL3(GetMethodID,jenv, bbclass, "isDirect", "()Z");
+  jmethodID positionId = JCALL3(GetMethodID,jenv, bbclass, "position", "()I");
+  jmethodID remainingId= JCALL3(GetMethodID,jenv, bbclass, "remaining", "()I");
+  isDirect = JCALL2(CallBooleanMethod,jenv, $input, isDirectId);
+  jint position = JCALL2(CallIntMethod,jenv, $input, positionId);
+  long size = (long)(JCALL2(CallIntMethod,jenv, $input, remainingId));
+  $2 = &size;
+
+  if(isDirect) {
+    $1 = JCALL1(GetDirectBufferAddress,jenv, $input) + position;
+    data = (char *)0;
+    array = (jobject) 0;
+  } else {
+    jmethodID arrayId= JCALL3(GetMethodID,jenv, bbclass, "array", "()[B");
+    jmethodID arrayOffsetId= JCALL3(GetMethodID,jenv, bbclass, "arrayOffset", "()I");
+    array = JCALL2(CallObjectMethod,jenv, $input, arrayId);
+    //data = JCALL2(GetByteArrayElements, jenv, array, NULL);
+    jobject a = array;
+    data = (char *) JCALL2(GetPrimitiveArrayCritical, jenv, a, NULL);
+    //data = (char *) (*jenv)->GetPrimitiveArrayCritical(jenv, array, NULL);
+    //printf("Acquired  %p from %p\n", data, a);
+
+    $1 = data + JCALL2(CallIntMethod,jenv, $input, arrayOffsetId) + position;
+
+  }
+}
+%typemap(jni) (char *DATA, size_t *SIZE) "jobject"
+%typemap(jtype) (char *DATA, size_t *SIZE) "java.nio.ByteBuffer"
+%typemap(jstype) (char *DATA, size_t *SIZE) "java.nio.ByteBuffer"
+%typemap(javain) (char *DATA, size_t *SIZE) "$javainput"
+%typemap(javaout) (char *DATA, size_t *SIZE) {
+  return $jnicall;
+}
+
+%typemap(freearg) (char *DATA, size_t *SIZE) {
+
+
+  if(!isDirect$argnum) {
+
+    //JCALL3(ReleaseByteArrayElements, jenv, array, $1 - ((*jenv)->CallIntMethod(jenv, $input, arrayOffsetId) + position),0);
+    JCALL3(ReleasePrimitiveArrayCritical, jenv, array$argnum, data$argnum,0);
+    //printf("Releasing %p from %p\n", data$argnum, array$argnum);
+  }
+
+  jmethodID setpositionId = (*jenv)->GetMethodID(jenv, bbclass$argnum, "position", "(I)Ljava/nio/Buffer;");
+
+  jint pos = (int)*$2;
+  // todo - need to increment not just set
+  JCALL3(CallObjectMethod,jenv,$input,setpositionId,pos);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+%rename(pn_connection_get_context) wrap_pn_connection_get_context;
+%inline {
+  jobject wrap_pn_connection_get_context(pn_connection_t *c) {
+    jobject result = (jobject) pn_connection_get_context(c);
+    return result;
+  }
+}
+%ignore pn_connection_get_context;
+
+%native (pn_connection_set_context) void pn_connection_set_context(pn_connection_t, jobject);
+%{
+JNIEXPORT void JNICALL Java_org_apache_qpid_proton_jni_ProtonJNI_pn_1connection_1set_1context(JNIEnv *jenv, jclass jcls,
+                                                              jlong jarg1, jobject context)
+{
+    pn_connection_t *c = *(pn_connection_t **)&jarg1;
+
+    jobject oldContext = (jobject) pn_connection_get_context(c);
+    if(oldContext) {
+      (*jenv)->DeleteGlobalRef(jenv, oldContext);
+    }
+    jobject newContext = NULL;
+    if(context)
+    {
+        newContext = (*jenv)->NewGlobalRef(jenv, context);
+    }
+    pn_connection_set_context(c, newContext);
+
+}
+%}
+%ignore pn_connection_set_context;
+
+
+%rename(pn_session_get_context) wrap_pn_session_get_context;
+%inline {
+  jobject wrap_pn_session_get_context(pn_session_t *c) {
+    jobject result = (jobject) pn_session_get_context(c);
+    return result;
+  }
+}
+%ignore pn_session_get_context;
+
+%native (pn_session_set_context) void pn_session_set_context(pn_session_t, jobject);
+%{
+JNIEXPORT void JNICALL Java_org_apache_qpid_proton_jni_ProtonJNI_pn_1session_1set_1context(JNIEnv *jenv, jclass jcls,
+                                                              jlong jarg1, jobject context)
+{
+    pn_session_t *c = *(pn_session_t **)&jarg1;
+
+    jobject oldContext = (jobject) pn_session_get_context(c);
+    if(oldContext) {
+      (*jenv)->DeleteGlobalRef(jenv, oldContext);
+    }
+    jobject newContext = NULL;
+    if(context)
+    {
+        newContext = (*jenv)->NewGlobalRef(jenv, context);
+    }
+    pn_session_set_context(c, newContext);
+
+}
+%}
+%ignore pn_session_set_context;
+
+%rename(pn_link_get_context) wrap_pn_link_get_context;
+%inline {
+  jobject wrap_pn_link_get_context(pn_link_t *c) {
+    jobject result = (jobject) pn_link_get_context(c);
+    return result;
+  }
+}
+%ignore pn_link_get_context;
+
+%native (pn_link_set_context) void pn_link_set_context(pn_link_t, jobject);
+%{
+JNIEXPORT void JNICALL Java_org_apache_qpid_proton_jni_ProtonJNI_pn_1link_1set_1context(JNIEnv *jenv, jclass jcls,
+                                                              jlong jarg1, jobject context)
+{
+    pn_link_t *c = *(pn_link_t **)&jarg1;
+    void* oldContext = pn_link_get_context(c);
+
+    if(oldContext!=NULL) {
+      (*jenv)->DeleteGlobalRef(jenv, (jobject)oldContext);
+    }
+    jobject newContext = NULL;
+    if(context!=NULL)
+    {
+        newContext = (*jenv)->NewGlobalRef(jenv, context);
+    }
+    pn_link_set_context(c, newContext);
+
+}
+%}
+%ignore pn_link_set_context;
+
+%rename(pn_delivery_get_context) wrap_pn_delivery_get_context;
+%inline {
+  jobject wrap_pn_delivery_get_context(pn_delivery_t *c) {
+    jobject result = (jobject) pn_delivery_get_context(c);
+    return result;
+  }
+}
+%ignore pn_delivery_get_context;
+
+%native (pn_delivery_set_context) void pn_delivery_set_context(pn_delivery_t, jobject);
+%{
+JNIEXPORT void JNICALL Java_org_apache_qpid_proton_jni_ProtonJNI_pn_1delivery_1set_1context(JNIEnv *jenv, jclass jcls,
+                                                              jlong jarg1, jobject context)
+{
+
+    pn_delivery_t *c = *(pn_delivery_t **)&jarg1;
+    jobject oldContext = (jobject) pn_delivery_get_context(c);
+    if(oldContext) {
+      (*jenv)->DeleteGlobalRef(jenv, oldContext);
+    }
+    jobject newContext = NULL;
+    if(context)
+    {
+        newContext = (*jenv)->NewGlobalRef(jenv, context);
+    }
+    pn_delivery_set_context(c, newContext);
+
+}
+%}
+%ignore pn_delivery_set_context;
+
+%native (pn_delivery_tag) jbyteArray pn_delivery_tag(pn_delivery_t);
+%{
+JNIEXPORT jbyteArray JNICALL Java_org_apache_qpid_proton_jni_ProtonJNI_pn_1delivery_1tag(JNIEnv *jenv, jclass jcls,
+                                                              jlong jarg1)
+{
+
+    pn_delivery_t *c = *(pn_delivery_t **)&jarg1;
+    pn_delivery_tag_t tag = pn_delivery_tag(c);
+    jbyteArray rval = (*jenv)->NewByteArray(jenv, tag.size);
+    jbyte* barr = (*jenv)->GetByteArrayElements(jenv, rval, NULL);
+    jint i = 0;
+    for(i=0;i<tag.size;i++)
+    {
+      barr[i] = tag.bytes[i];
+    }
+    (*jenv)->ReleaseByteArrayElements(jenv, rval, barr, 0);
+
+    return (jbyteArray) (*jenv)->NewGlobalRef(jenv, rval);
+
+}
+%}
+%ignore pn_delivery_tag;
+
+%native (pn_bytes_to_array) jbyteArray pn_bytes_to_array(pn_bytes_t);
+%{
+JNIEXPORT jbyteArray JNICALL Java_org_apache_qpid_proton_jni_ProtonJNI_pn_1bytes_1to_1array(JNIEnv *jenv, jclass jcls, jlong jarg1)
+{
+    pn_bytes_t* b = *(pn_bytes_t **)&jarg1;
+    jbyteArray rval = (*jenv)->NewByteArray(jenv, b->size);
+    jbyte* barr = (*jenv)->GetByteArrayElements(jenv, rval, NULL);
+    jint i = 0;
+    for(i=0;i<b->size;i++)
+    {
+      barr[i] = b->start[i];
+    }
+    (*jenv)->ReleaseByteArrayElements(jenv, rval, barr, 0);
+
+    return (jbyteArray) (*jenv)->NewGlobalRef(jenv, rval);
+
+}
+%}
+
+
+
+ssize_t  pn_transport_input(pn_transport_t *transport, char *DATA, size_t SIZE);
+%ignore pn_transport_input;
+
+ssize_t pn_transport_output(pn_transport_t *transport, char *DATA, size_t SIZE);
+%ignore pn_transport_output;
+
+ssize_t pn_link_recv(pn_link_t *receiver, char *DATA, size_t SIZE);
+%ignore pn_link_recv;
+
+ssize_t pn_link_send(pn_link_t *sender, char *DATA, size_t SIZE);
+%ignore pn_link_send;
+
+ssize_t pn_sasl_recv(pn_sasl_t *sasl, char *DATA, size_t SIZE);
+%ignore pn_sasl_recv;
+
+ssize_t pn_sasl_send(pn_sasl_t *sasl, char *DATA, size_t SIZE);
+%ignore pn_sasl_send;
+
+%typemap(jni) char *start "jbyteArray"
+%typemap(jtype) char *start "byte[]"
+%typemap(jstype) char *start "byte[]"
+%typemap(javaout) char *start {
+    return $jnicall;
+}
+
+%typemap(out) char *start {
+    // TODO - RG
+    $result = JCALL1(NewByteArray, jenv, arg1->size);
+    JCALL4(SetByteArrayRegion, jenv, $result, 0, arg1->size, $1);
+}
+
+%typemap(in) char *start {
+    jbyte* barr = (*jenv)->GetByteArrayElements(jenv, $input, NULL);
+    jsize length = (*jenv)->GetArrayLength(jenv, $input);
+    char *buf = malloc(length);
+    jint i = 0;
+    for(i=0;i<length;i++)
+    {
+      buf[i] = barr[i];
+    }
+    (*jenv)->ReleaseByteArrayElements(jenv, $input, barr, 0);
+    $1 = buf;
+}
+%typemap(freearg) char *start  {
+
+}
+
+
+%rename(pn_delivery) wrap_pn_delivery;
+%inline %{
+  pn_delivery_t *wrap_pn_delivery(pn_link_t *link, char *STRING, size_t LENGTH) {
+    return pn_delivery(link, pn_dtag(STRING, LENGTH));
+  }
+%}
+%ignore pn_delivery;
+
+int pn_data_encode(pn_data_t *data, char *DATA, size_t SIZE);
+%ignore pn_data_encode;
+
+int pn_data_decode(pn_data_t *data, char *DATA, size_t SIZE);
+%ignore pn_data_decode;
+
+int pn_message_decode(pn_message_t *msg, char *DATA, size_t SIZE);
+%ignore pn_message_decode;
+
+int pn_message_encode(pn_message_t *msg, char *DATA, size_t *SIZE);
+%ignore pn_message_encode;
+
+int pn_message_load(pn_message_t *msg, char *DATA, size_t SIZE);
+%ignore pn_message_load;
+
+int pn_message_load_data(pn_message_t *msg, char *DATA, size_t SIZE);
+%ignore pn_message_load_data;
+
+int pn_message_load_text(pn_message_t *msg, char *DATA, size_t SIZE);
+%ignore pn_message_load_text;
+
+int pn_message_load_amqp(pn_message_t *msg, char *DATA, size_t SIZE);
+%ignore pn_message_load_amqp;
+
+int pn_message_load_json(pn_message_t *msg, char *DATA, size_t SIZE);
+%ignore pn_message_load_json;
+
+int pn_message_save(pn_message_t *message, char *DATA, size_t *SIZE);
+%ignore pn_message_save;
+
+int pn_message_encode(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_encode;
+
+int pn_message_save(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_save;
+
+int pn_message_save_data(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_save_data;
+
+int pn_message_save_text(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_save_text;
+
+int pn_message_save_amqp(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_save_amqp;
+
+int pn_message_save_json(pn_message_t *msg, char *OUTPUT, size_t *OUTPUT_SIZE);
+%ignore pn_message_save_json;
+
+bool pn_ssl_get_cipher_name(pn_ssl_t *ssl, char *DATA, size_t SIZE);
+%ignore pn_ssl_get_cipher_name;
+
+bool pn_ssl_get_protocol_name(pn_ssl_t *ssl, char *DATA, size_t SIZE);
+%ignore pn_ssl_get_protocol_name;
+
+int pn_ssl_get_peer_hostname(pn_ssl_t *ssl, char *DATA, size_t *SIZE);
+%ignore pn_ssl_get_peer_hostname;
+
+
+%include "proton/cproton.i"
+
+
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/ProtonCEquivalent.java
similarity index 64%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-c/bindings/java/src/main/java/org/apache/qpid/proton/ProtonCEquivalent.java
index fd9b0c2..c9e8e36 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/ProtonCEquivalent.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,30 +15,21 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
  */
+package org.apache.qpid.proton;
 
-package org.apache.qpid.proton.engine;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 
-public class ProtonException extends RuntimeException
+/**
+ * Used to mark which function in Proton-C a Proton-J method corresponds to,
+ * for API reconciliation purposes.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface ProtonCEquivalent
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
+    String value();
 }
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIConnection.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIConnection.java
new file mode 100644
index 0000000..0007929
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIConnection.java
@@ -0,0 +1,205 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.engine.jni;
+
+import java.util.EnumSet;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.engine.Connection;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.EndpointError;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.Link;
+import org.apache.qpid.proton.engine.Session;
+import org.apache.qpid.proton.jni.Proton;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_connection_t;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_delivery_t;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_link_t;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_session_t;
+
+public class JNIConnection implements Connection
+{
+    private SWIGTYPE_p_pn_connection_t _impl;
+    private Object _context;
+
+    public JNIConnection()
+    {
+        this(Proton.pn_connection());
+    }
+
+    public JNIConnection(SWIGTYPE_p_pn_connection_t connection_t)
+    {
+        _impl = connection_t;
+        Proton.pn_connection_set_context(_impl, this);
+    }
+
+
+
+    @Override
+    @ProtonCEquivalent("pn_session")
+    public Session session()
+    {
+        return new JNISession(Proton.pn_session(_impl));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_session_head")
+    public Session sessionHead(EnumSet<EndpointState> local, EnumSet<EndpointState> remote)
+    {
+        return JNISession.getSession(Proton.pn_session_head(_impl, StateConverter.getStateMask(local, remote)));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_head")
+    public Link linkHead(EnumSet<EndpointState> local, EnumSet<EndpointState> remote)
+    {
+        return JNILink.getLink(Proton.pn_link_head(_impl, StateConverter.getStateMask(local, remote)));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_work_head")
+    public Delivery getWorkHead()
+    {
+        return JNIDelivery.getDelivery(Proton.pn_work_head(_impl));
+
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_connection_set_container")
+    public void setContainer(String container)
+    {
+        Proton.pn_connection_set_container(_impl, container);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_connection_set_hostname")
+    public void setHostname(String hostname)
+    {
+        Proton.pn_connection_set_hostname(_impl, hostname);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_connection_remote_container")
+    public String getRemoteContainer()
+    {
+        return Proton.pn_connection_remote_container(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_connection_remote_hostname")
+    public String getRemoteHostname()
+    {
+        return Proton.pn_connection_remote_hostname(_impl);
+    }
+
+    @Override
+    public EndpointState getLocalState()
+    {
+        return StateConverter.getLocalState(Proton.pn_connection_state(_impl));
+    }
+
+    @Override
+    public EndpointState getRemoteState()
+    {
+        return StateConverter.getRemoteState(Proton.pn_connection_state(_impl));
+    }
+
+    @Override
+    public EndpointError getLocalError()
+    {
+        //TODO
+        return null;
+    }
+
+    @Override
+    public EndpointError getRemoteError()
+    {
+        //TODO
+        return null;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_connection_free")
+    public void free()
+    {
+        if(_impl != null)
+        {
+            Proton.pn_connection_set_context(_impl, null);
+            Proton.pn_connection_free(_impl);
+            _impl = null;
+        }
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_connection_open")
+    public void open()
+    {
+        Proton.pn_connection_open(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_connection_close")
+    public void close()
+    {
+        Proton.pn_connection_close(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_connection_set_context")
+
+    public void setContext(Object o)
+    {
+        _context = o;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_connection_get_context")
+    public Object getContext()
+    {
+        return _context;
+    }
+
+    @Override
+    protected void finalize() throws Throwable
+    {
+        free();
+        super.finalize();
+    }
+
+    SWIGTYPE_p_pn_connection_t getImpl()
+    {
+        return _impl;
+    }
+
+    public static JNIConnection getConnection(SWIGTYPE_p_pn_connection_t connection_t)
+    {
+        if(connection_t != null)
+        {
+            JNIConnection connectionObj = (JNIConnection) Proton.pn_connection_get_context(connection_t);
+            if(connectionObj == null)
+            {
+                connectionObj = new JNIConnection(connection_t);
+            }
+            return connectionObj;
+        }
+        return null;
+    }
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIDelivery.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIDelivery.java
new file mode 100644
index 0000000..cb4d899
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIDelivery.java
@@ -0,0 +1,247 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.engine.jni;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.ProtonUnsupportedOperationException;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.Link;
+import org.apache.qpid.proton.jni.Proton;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_delivery_t;
+import org.apache.qpid.proton.jni.pn_delivery_tag_t;
+import org.apache.qpid.proton.jni.pn_disposition_t;
+import org.apache.qpid.proton.amqp.messaging.Accepted;
+import org.apache.qpid.proton.amqp.messaging.Modified;
+import org.apache.qpid.proton.amqp.messaging.Received;
+import org.apache.qpid.proton.amqp.messaging.Rejected;
+import org.apache.qpid.proton.amqp.messaging.Released;
+import org.apache.qpid.proton.amqp.transport.DeliveryState;
+
+public class JNIDelivery implements Delivery
+{
+    private SWIGTYPE_p_pn_delivery_t _impl;
+    private Object _context;
+    private JNILink _link;
+
+    public JNIDelivery(SWIGTYPE_p_pn_delivery_t delivery_t)
+    {
+        _impl = delivery_t;
+        Proton.pn_delivery_set_context(_impl, this);
+        _link = JNILink.getLink(Proton.pn_delivery_link(_impl));
+    }
+
+    static Delivery getDelivery(SWIGTYPE_p_pn_delivery_t delivery_t)
+    {
+        if(delivery_t != null)
+        {
+            Delivery deliveryObj = (Delivery) Proton.pn_delivery_get_context(delivery_t);
+            if(deliveryObj == null)
+            {
+                deliveryObj = new JNIDelivery(delivery_t);
+            }
+            return deliveryObj;
+        }
+        return null;
+    }
+
+    @ProtonCEquivalent("pn_delivery_get_context")
+    public Object getContext()
+    {
+        return _context;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_delivery_tag")
+    public byte[] getTag()
+    {
+        // TODO - pn_delivery_tag_t should be bytes not string
+        return Proton.pn_delivery_tag(_impl);
+
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_delivery_link")
+    public Link getLink()
+    {
+        return _link;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_delivery_local_state")
+    public DeliveryState getLocalState()
+    {
+        return convertDisposition(Proton.pn_delivery_local_state(_impl));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_delivery_remote_state")
+    public DeliveryState getRemoteState()
+    {
+        return convertDisposition(Proton.pn_delivery_remote_state(_impl));
+    }
+
+    @Override
+    public boolean remotelySettled()
+    {
+        return Proton.pn_delivery_settled(_impl);
+    }
+
+    @Override
+    public int getMessageFormat()
+    {
+        return 0;  //TODO
+    }
+
+    @Override
+    public void disposition(DeliveryState state)
+    {
+        Proton.pn_delivery_update(_impl, convertState(state));
+        //TODO
+    }
+
+    private static pn_disposition_t convertState(DeliveryState state)
+    {
+        //TODO - disposition properties conversion
+        if(state instanceof Accepted)
+        {
+            return pn_disposition_t.PN_ACCEPTED;
+        }
+        else if(state instanceof Rejected)
+        {
+            return pn_disposition_t.PN_REJECTED;
+        }
+        else if(state instanceof Modified)
+        {
+            return pn_disposition_t.PN_MODIFIED;
+        }
+        else if(state instanceof Received)
+        {
+            return pn_disposition_t.PN_RECEIVED;
+        }
+        else if(state instanceof Released)
+        {
+            return pn_disposition_t.PN_RELEASED;
+        }
+
+        return null;
+    }
+
+    private static DeliveryState convertDisposition(pn_disposition_t disposition)
+    {
+        //TODO - disposition properties conversion
+        if(pn_disposition_t.PN_ACCEPTED.equals(disposition))
+        {
+            return Accepted.getInstance();
+        }
+        else if(pn_disposition_t.PN_REJECTED.equals(disposition))
+        {
+            return new Rejected();
+        }
+        else if(pn_disposition_t.PN_MODIFIED.equals(disposition))
+        {
+            return new Modified();
+        }
+        else if(pn_disposition_t.PN_MODIFIED.equals(disposition))
+        {
+            return new Modified();
+        }
+        else if(pn_disposition_t.PN_RELEASED.equals(disposition))
+        {
+            return new Released();
+        }
+
+        return null;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_delivery_settle")
+    public void settle()
+    {
+        Proton.pn_delivery_settle(_impl);
+    }
+
+    @Override
+    public void free()
+    {
+        if(_impl != null)
+        {
+            Proton.pn_delivery_set_context(_impl, null);
+//            Proton.pn_delivery_free(_impl);
+            _impl = null;
+        }
+    }
+
+    @Override
+    public Delivery getWorkNext()
+    {
+        return getDelivery(Proton.pn_work_next(_impl));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_delivery_writable")
+    public boolean isWritable()
+    {
+        return Proton.pn_delivery_writable(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_delivery_readable")
+    public boolean isReadable()
+    {
+        return Proton.pn_delivery_readable(_impl);
+    }
+
+    @ProtonCEquivalent("pn_delivery_set_context")
+    public void setContext(Object context)
+    {
+        _context = context;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_delivery_updated")
+    public boolean isUpdated()
+    {
+        return Proton.pn_delivery_updated(_impl);
+    }
+
+    @Override
+    public boolean isPartial()
+    {
+        throw new ProtonUnsupportedOperationException();
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_delivery_settled")
+    public boolean isSettled()
+    {
+        return Proton.pn_delivery_settled(_impl);
+    }
+
+    @Override
+    protected void finalize() throws Throwable
+    {
+        if(isSettled())
+        {
+            free();
+        }
+        super.finalize();
+    }
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIEngineFactory.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIEngineFactory.java
new file mode 100644
index 0000000..55936a4
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIEngineFactory.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.engine.jni;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.engine.Connection;
+import org.apache.qpid.proton.engine.EngineFactory;
+import org.apache.qpid.proton.engine.SslDomain;
+import org.apache.qpid.proton.engine.SslPeerDetails;
+import org.apache.qpid.proton.engine.Transport;
+import org.apache.qpid.proton.jni.JNIFactory;
+
+public class JNIEngineFactory extends JNIFactory implements EngineFactory
+{
+    @Override
+    @ProtonCEquivalent("pn_connection")
+    public Connection createConnection()
+    {
+        return new JNIConnection();
+    }
+
+    @Override
+    public Transport createTransport()
+    {
+        return new JNITransport();
+    }
+
+    @Override
+    public SslDomain createSslDomain()
+    {
+        return new JNISslDomain();
+    }
+
+    @Override
+    public SslPeerDetails createSslPeerDetails(final String hostname, final int port)
+    {
+        return new SslPeerDetails()
+        {
+
+            @Override
+            public int getPort()
+            {
+                return port;
+            }
+
+            @Override
+            public String getHostname()
+            {
+                return hostname;
+            }
+        };
+    }
+
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNILink.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNILink.java
new file mode 100644
index 0000000..6807042
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNILink.java
@@ -0,0 +1,494 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.engine.jni;
+
+import java.util.EnumSet;
+import java.util.Iterator;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.engine.Delivery;
+import org.apache.qpid.proton.engine.EndpointError;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.Link;
+import org.apache.qpid.proton.engine.Session;
+import org.apache.qpid.proton.jni.Proton;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_link_t;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_session_t;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_terminus_t;
+import org.apache.qpid.proton.jni.pn_durability_t;
+import org.apache.qpid.proton.jni.pn_expiry_policy_t;
+import org.apache.qpid.proton.jni.pn_terminus_type_t;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedByte;
+import org.apache.qpid.proton.amqp.UnsignedInteger;
+import org.apache.qpid.proton.amqp.messaging.TerminusDurability;
+import org.apache.qpid.proton.amqp.messaging.TerminusExpiryPolicy;
+import org.apache.qpid.proton.amqp.transaction.Coordinator;
+import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
+import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
+import org.apache.qpid.proton.amqp.transport.Source;
+import org.apache.qpid.proton.amqp.transport.Target;
+
+abstract class JNILink implements Link
+{
+    private SWIGTYPE_p_pn_link_t _impl;
+    private Object _context;
+    private JNISession _session;
+
+    public JNILink(SWIGTYPE_p_pn_link_t link_t)
+    {
+        _impl = link_t;
+        Proton.pn_link_set_context(_impl, this);
+        _session = JNISession.getSession(Proton.pn_link_session(_impl));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_name")
+    public String getName()
+    {
+        return Proton.pn_link_name(_impl);
+    }
+
+    @Override
+    public Delivery delivery(byte[] tag, int offset, int length)
+    {
+        byte[] dup = new byte[length];
+        System.arraycopy(tag,offset,dup,0,length);
+        return JNIDelivery.getDelivery(Proton.pn_delivery(_impl, dup));
+    }
+
+    @Override
+    public Delivery delivery(byte[] tag)
+    {
+        return JNIDelivery.getDelivery(Proton.pn_delivery(_impl, tag));
+    }
+
+    @Override
+    public Iterator<Delivery> unsettled()
+    {
+
+        return null;  //TODO
+    }
+
+    @Override
+    public Delivery current()
+    {
+        return JNIDelivery.getDelivery(Proton.pn_link_current(_impl));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_advance")
+    public boolean advance()
+    {
+        return Proton.pn_link_advance(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_source")
+    public Source getSource()
+    {
+        return convertSource(Proton.pn_link_source(_impl));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_target")
+
+    public Target getTarget()
+    {
+        return convertTarget(Proton.pn_link_target(_impl));
+    }
+
+    @Override
+    public void setSource(Source source)
+    {
+        SWIGTYPE_p_pn_terminus_t source_t = Proton.pn_link_source(_impl);
+
+        org.apache.qpid.proton.amqp.messaging.Source s = (org.apache.qpid.proton.amqp.messaging.Source) source;
+        Proton.pn_terminus_set_address(source_t,s.getAddress());
+        Proton.pn_terminus_set_dynamic(source_t,s.getDynamic());
+        setDurability(source_t, s.getDurable() == null ? null : s.getDurable().getValue());
+        setExpiryPolicy(source_t, s.getExpiryPolicy() == null ? null : s.getExpiryPolicy().getPolicy());
+        if(s.getTimeout() != null)
+        {
+            Proton.pn_terminus_set_timeout(source_t, s.getTimeout().longValue());
+        }
+        Proton.pn_terminus_set_type(source_t, pn_terminus_type_t.PN_SOURCE);
+
+        //TODO - capabilities
+
+    }
+
+    private static void setDurability(SWIGTYPE_p_pn_terminus_t terminus, UnsignedInteger durable)
+    {
+        if(durable != null)
+        {
+            if(durable.equals(TerminusDurability.NONE))
+            {
+                Proton.pn_terminus_set_durability(terminus, pn_durability_t.PN_NONDURABLE);
+            }
+            else if(durable.equals(TerminusDurability.CONFIGURATION))
+            {
+                Proton.pn_terminus_set_durability(terminus, pn_durability_t.PN_CONFIGURATION);
+            }
+            else if(durable.equals(TerminusDurability.UNSETTLED_STATE))
+            {
+                Proton.pn_terminus_set_durability(terminus, pn_durability_t.PN_DELIVERIES);
+            }
+        }
+    }
+
+    private static void setExpiryPolicy(SWIGTYPE_p_pn_terminus_t terminus, Symbol policy)
+    {
+
+            if(TerminusExpiryPolicy.NEVER.equals(policy))
+            {
+                Proton.pn_terminus_set_expiry_policy(terminus, pn_expiry_policy_t.PN_NEVER);
+            }
+            else if(TerminusExpiryPolicy.CONNECTION_CLOSE.equals(policy))
+            {
+                Proton.pn_terminus_set_expiry_policy(terminus, pn_expiry_policy_t.PN_CONNECTION_CLOSE);
+            }
+            else if(TerminusExpiryPolicy.SESSION_END.equals(policy))
+            {
+                Proton.pn_terminus_set_expiry_policy(terminus, pn_expiry_policy_t.PN_SESSION_CLOSE);
+            }
+            else if(TerminusExpiryPolicy.LINK_DETACH.equals(policy))
+            {
+                Proton.pn_terminus_set_expiry_policy(terminus, pn_expiry_policy_t.PN_LINK_CLOSE);
+            }
+
+    }
+
+    @Override
+    public void setTarget(Target target)
+    {
+        SWIGTYPE_p_pn_terminus_t target_t = Proton.pn_link_target(_impl);
+
+        if(target instanceof org.apache.qpid.proton.amqp.messaging.Target)
+        {
+            org.apache.qpid.proton.amqp.messaging.Target t = (org.apache.qpid.proton.amqp.messaging.Target) target;
+            Proton.pn_terminus_set_address(target_t, t.getAddress());
+            Proton.pn_terminus_set_dynamic(target_t, t.getDynamic());
+            setDurability(target_t, t.getDurable() == null ? null : t.getDurable().getValue());
+            setExpiryPolicy(target_t, t.getExpiryPolicy() == null ? null : t.getExpiryPolicy().getPolicy());
+            if(t.getTimeout() != null)
+            {
+                Proton.pn_terminus_set_timeout(target_t, t.getTimeout().longValue());
+            }
+            Proton.pn_terminus_set_type(target_t, pn_terminus_type_t.PN_TARGET);
+        }
+        else if(target instanceof Coordinator)
+        {
+            //TODO
+            Proton.pn_terminus_set_type(target_t, pn_terminus_type_t.PN_COORDINATOR);
+        }
+
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_remote_source")
+    public Source getRemoteSource()
+    {
+        return convertSource(Proton.pn_link_remote_source(_impl));
+    }
+
+    private Source convertSource(SWIGTYPE_p_pn_terminus_t source_t)
+    {
+        if(source_t != null)
+        {
+            org.apache.qpid.proton.amqp.messaging.Source s = new org.apache.qpid.proton.amqp.messaging.Source();
+
+            s.setAddress(Proton.pn_terminus_get_address(source_t));
+            s.setDynamic(Proton.pn_terminus_is_dynamic(source_t));
+            s.setTimeout(UnsignedInteger.valueOf(Proton.pn_terminus_get_timeout(source_t)));
+            s.setDurable(convertDurability(source_t));
+            s.setExpiryPolicy(convertExpiryPolicy(source_t));
+
+
+
+            return s;
+        }
+        else
+        {
+            return null;
+        }//TODO
+    }
+
+    private static TerminusExpiryPolicy convertExpiryPolicy(SWIGTYPE_p_pn_terminus_t source_t)
+    {
+        pn_expiry_policy_t expiry = Proton.pn_terminus_get_expiry_policy(source_t);
+        TerminusExpiryPolicy policy = null;
+        if(pn_expiry_policy_t.PN_NEVER.equals(expiry))
+        {
+            policy = TerminusExpiryPolicy.NEVER;
+        }
+        else if(pn_expiry_policy_t.PN_CONNECTION_CLOSE.equals(expiry))
+        {
+            policy = TerminusExpiryPolicy.CONNECTION_CLOSE;
+        }
+        else if (pn_expiry_policy_t.PN_SESSION_CLOSE.equals(expiry))
+        {
+            policy = TerminusExpiryPolicy.SESSION_END;
+        }
+        else if (pn_expiry_policy_t.PN_LINK_CLOSE.equals(expiry))
+        {
+            policy = TerminusExpiryPolicy.LINK_DETACH;
+        }
+        return policy;
+    }
+
+    private static TerminusDurability convertDurability(SWIGTYPE_p_pn_terminus_t source_t)
+    {
+        pn_durability_t durability = Proton.pn_terminus_get_durability(source_t);
+        if(pn_durability_t.PN_NONDURABLE.equals(durability))
+        {
+            return TerminusDurability.NONE;
+        }
+        else if(pn_durability_t.PN_CONFIGURATION.equals(durability))
+        {
+            return TerminusDurability.CONFIGURATION;
+        }
+        else if(pn_durability_t.PN_DELIVERIES.equals(durability))
+        {
+            return TerminusDurability.UNSETTLED_STATE;
+        }
+
+        return null;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_remote_target")
+    public Target getRemoteTarget()
+    {
+        return convertTarget(Proton.pn_link_remote_target(_impl));
+    }
+
+    private Target convertTarget(SWIGTYPE_p_pn_terminus_t target_t)
+    {
+        if(target_t != null)
+        {
+            pn_terminus_type_t pn_terminus_type = Proton.pn_terminus_get_type(target_t);
+            if(pn_terminus_type_t.PN_TARGET.equals(pn_terminus_type) || pn_terminus_type_t.PN_UNSPECIFIED.equals(pn_terminus_type))
+            {
+                org.apache.qpid.proton.amqp.messaging.Target t = new org.apache.qpid.proton.amqp.messaging.Target();
+
+                t.setAddress(Proton.pn_terminus_get_address(target_t));
+                t.setDynamic(Proton.pn_terminus_is_dynamic(target_t));
+                t.setTimeout(UnsignedInteger.valueOf(Proton.pn_terminus_get_timeout(target_t)));
+                t.setDurable(convertDurability(target_t));
+                t.setExpiryPolicy(convertExpiryPolicy(target_t));
+
+                return t;
+            }
+            else if(pn_terminus_type_t.PN_COORDINATOR.equals(pn_terminus_type))
+            {
+                Coordinator c = new Coordinator();
+
+                // TODO
+
+                return c;
+            }
+        }
+
+        return null;
+        //TODO
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_next")
+    public Link next(EnumSet<EndpointState> local, EnumSet<EndpointState> remote)
+    {
+        return getLink(Proton.pn_link_next(_impl, StateConverter.getStateMask(local, remote)));
+    }
+
+    static JNILink getLink(SWIGTYPE_p_pn_link_t link_t)
+    {
+        if(link_t != null)
+        {
+            JNILink link = (JNILink) Proton.pn_link_get_context(link_t);
+            if(link == null)
+            {
+                if(Proton.pn_link_is_receiver(link_t))
+                {
+                    link = new JNIReceiver(link_t);
+                }
+                else if(Proton.pn_link_is_sender(link_t))
+                {
+                    link = new JNISender(link_t);
+                }
+
+            }
+            return link;
+        }
+        return null;
+    }
+
+
+    @Override
+    @ProtonCEquivalent("pn_link_credit")
+    public int getCredit()
+    {
+        return Proton.pn_link_credit(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_queued")
+    public int getQueued()
+    {
+        return Proton.pn_link_queued(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_unsettled")
+    public int getUnsettled()
+    {
+        return Proton.pn_link_unsettled(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_session")
+    public Session getSession()
+    {
+        return _session;
+    }
+
+    @Override
+    public SenderSettleMode getSenderSettleMode()
+    {
+        // TODO
+        return null;
+    }
+
+    @Override
+    public void setSenderSettleMode(SenderSettleMode senderSettleMode)
+    {
+        //TODO
+    }
+
+    @Override
+    public SenderSettleMode getRemoteSenderSettleMode()
+    {
+        return null;  //TODO
+    }
+
+    @Override
+    public void setRemoteSenderSettleMode(SenderSettleMode remoteSenderSettleMode)
+    {
+        //TODO
+    }
+
+    @Override
+    public ReceiverSettleMode getReceiverSettleMode()
+    {
+        return null;  //TODO
+    }
+
+    @Override
+    public void setReceiverSettleMode(ReceiverSettleMode receiverSettleMode)
+    {
+        //TODO
+    }
+
+    @Override
+    public ReceiverSettleMode getRemoteReceiverSettleMode()
+    {
+        return null;  //TODO
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_state")
+    public EndpointState getLocalState()
+    {
+        return StateConverter.getLocalState(Proton.pn_link_state(_impl));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_state")
+    public EndpointState getRemoteState()
+    {
+        return StateConverter.getRemoteState(Proton.pn_link_state(_impl));
+    }
+
+    @Override
+    public EndpointError getLocalError()
+    {
+        return null;  //TODO
+    }
+
+    @Override
+    public EndpointError getRemoteError()
+    {
+        return null;  //TODO
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_free")
+    public void free()
+    {
+        if(_impl != null)
+        {
+            Proton.pn_link_set_context(_impl, null);
+            Proton.pn_link_free(_impl);
+            _impl = null;
+        }
+
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_open")
+    public void open()
+    {
+        Proton.pn_link_open(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_close")
+    public void close()
+    {
+        Proton.pn_link_close(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_set_context")
+    public void setContext(Object o)
+    {
+        _context = o;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_get_context")
+    public Object getContext()
+    {
+        return _context;
+    }
+
+    SWIGTYPE_p_pn_link_t getImpl()
+    {
+        return _impl;
+    }
+
+    @Override
+    protected void finalize() throws Throwable
+    {
+        free();
+        super.finalize();
+    }
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIReceiver.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIReceiver.java
new file mode 100644
index 0000000..f618f70
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNIReceiver.java
@@ -0,0 +1,57 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.engine.jni;
+
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.engine.Receiver;
+import org.apache.qpid.proton.jni.Proton;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_link_t;
+
+public class JNIReceiver extends JNILink implements Receiver
+{
+    public JNIReceiver(SWIGTYPE_p_pn_link_t link_t)
+    {
+        super(link_t);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_flow")
+    public void flow(int credits)
+    {
+        Proton.pn_link_flow(getImpl(), credits);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_recv")
+    public int recv(byte[] bytes, int offset, int size)
+    {
+        return Proton.pn_link_recv(getImpl(), ByteBuffer.wrap(bytes,offset,size));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_drain")
+    public void drain(int credit)
+    {
+        Proton.pn_link_drain(getImpl(), credit);
+    }
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISasl.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISasl.java
new file mode 100644
index 0000000..a208d0c
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISasl.java
@@ -0,0 +1,189 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.engine.jni;
+
+import java.nio.ByteBuffer;
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.engine.Sasl;
+import org.apache.qpid.proton.jni.Proton;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_sasl_t;
+import org.apache.qpid.proton.jni.pn_sasl_outcome_t;
+import org.apache.qpid.proton.jni.pn_sasl_state_t;
+
+public class JNISasl implements Sasl
+{
+    private final SWIGTYPE_p_pn_sasl_t _impl;
+
+    JNISasl(SWIGTYPE_p_pn_sasl_t sasl)
+    {
+        _impl = sasl;
+    }
+
+    @Override
+    public int input(byte[] bytes, int offset, int size)
+    {
+        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public int output(byte[] bytes, int offset, int size)
+    {
+        return 0;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl_state")
+    public SaslState getState()
+    {
+        return convertState(Proton.pn_sasl_state(_impl));
+    }
+
+    private static final Map<pn_sasl_state_t, SaslState> _states = new HashMap<pn_sasl_state_t, SaslState>();
+
+    static
+    {
+        _states.put(pn_sasl_state_t.PN_SASL_CONF, SaslState.PN_SASL_CONF);
+        _states.put(pn_sasl_state_t.PN_SASL_FAIL, SaslState.PN_SASL_FAIL);
+        _states.put(pn_sasl_state_t.PN_SASL_IDLE, SaslState.PN_SASL_IDLE);
+        _states.put(pn_sasl_state_t.PN_SASL_PASS, SaslState.PN_SASL_PASS);
+        _states.put(pn_sasl_state_t.PN_SASL_STEP, SaslState.PN_SASL_STEP);
+    }
+
+    private SaslState convertState(pn_sasl_state_t pn_sasl_state_t)
+    {
+        return _states.get(pn_sasl_state_t);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl_mechanisms")
+    public void setMechanisms(String[] mechanisms)
+    {
+        StringBuilder build = new StringBuilder();
+        for(String mech : mechanisms)
+        {
+            if(build.length() > 0)
+            {
+                build.append(' ');
+            }
+            build.append(mech);
+        }
+        build.append((char)0);
+
+        Proton.pn_sasl_mechanisms(_impl, build.toString());
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl_remote_mechanisms")
+    public String[] getRemoteMechanisms()
+    {
+        String mechs = Proton.pn_sasl_remote_mechanisms(_impl);
+        return mechs == null ? null : mechs.split(" ");
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl_pending")
+    public int pending()
+    {
+        return (int) Proton.pn_sasl_pending(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl_recv")
+    public int recv(byte[] bytes, int offset, int size)
+    {
+        return Proton.pn_sasl_recv(_impl, ByteBuffer.wrap(bytes, offset, size));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl_send")
+    public int send(byte[] bytes, int offset, int size)
+    {
+        return Proton.pn_sasl_send(_impl, ByteBuffer.wrap(bytes, offset, size));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl_done")
+    public void done(SaslOutcome outcome)
+    {
+        Proton.pn_sasl_done(_impl, convertOutcome(outcome));
+    }
+
+
+    private static final EnumMap<SaslOutcome, pn_sasl_outcome_t> _outcomes =
+            new EnumMap<SaslOutcome,pn_sasl_outcome_t>(SaslOutcome.class);
+
+    private static final Map<pn_sasl_outcome_t, SaslOutcome> _pn_outcomes =
+                new HashMap<pn_sasl_outcome_t, SaslOutcome>();
+
+    private static void mapOutcome(SaslOutcome a, pn_sasl_outcome_t b)
+    {
+        _outcomes.put(a,b);
+        _pn_outcomes.put(b,a);
+    }
+
+    static
+    {
+        mapOutcome(SaslOutcome.PN_SASL_AUTH, pn_sasl_outcome_t.PN_SASL_AUTH);
+        mapOutcome(SaslOutcome.PN_SASL_NONE, pn_sasl_outcome_t.PN_SASL_NONE);
+        mapOutcome(SaslOutcome.PN_SASL_OK, pn_sasl_outcome_t.PN_SASL_OK);
+        mapOutcome(SaslOutcome.PN_SASL_PERM, pn_sasl_outcome_t.PN_SASL_PERM);
+        mapOutcome(SaslOutcome.PN_SASL_SYS, pn_sasl_outcome_t.PN_SASL_SYS);
+        mapOutcome(SaslOutcome.PN_SASL_TEMP, pn_sasl_outcome_t.PN_SASL_TEMP);
+    }
+
+    private static pn_sasl_outcome_t convertOutcome(SaslOutcome outcome)
+    {
+        return _outcomes.get(outcome);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl_plain")
+
+    public void plain(String username, String password)
+    {
+        Proton.pn_sasl_plain(_impl, username, password);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl_outcome")
+    public SaslOutcome getOutcome()
+    {
+        return _pn_outcomes.get(Proton.pn_sasl_outcome(_impl));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl_client")
+    public void client()
+    {
+        Proton.pn_sasl_client(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl_server")
+    public void server()
+    {
+        Proton.pn_sasl_server(_impl);
+    }
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISender.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISender.java
new file mode 100644
index 0000000..8db529b
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISender.java
@@ -0,0 +1,64 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.engine.jni;
+
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.engine.Sender;
+import org.apache.qpid.proton.jni.Proton;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_link_t;
+
+public class JNISender extends JNILink implements Sender
+{
+    JNISender(SWIGTYPE_p_pn_link_t link_t)
+    {
+        super(link_t);
+
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_offered")
+    public void offer(int credits)
+    {
+        // TODO
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_send")
+    public int send(byte[] bytes, int offset, int length)
+    {
+        return Proton.pn_link_send(getImpl(), ByteBuffer.wrap(bytes,offset,length));
+    }
+
+    @Override
+    public void abort()
+    {
+        // TODO
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_link_drained")
+    public void drained()
+    {
+        Proton.pn_link_drained(getImpl());
+    }
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISession.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISession.java
new file mode 100644
index 0000000..67a4f39
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISession.java
@@ -0,0 +1,171 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.engine.jni;
+
+import java.util.EnumSet;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.engine.Connection;
+import org.apache.qpid.proton.engine.EndpointError;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.Receiver;
+import org.apache.qpid.proton.engine.Sender;
+import org.apache.qpid.proton.engine.Session;
+import org.apache.qpid.proton.jni.Proton;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_session_t;
+
+public class JNISession implements Session
+{
+    private SWIGTYPE_p_pn_session_t _impl;
+    private Object _context;
+    private JNIConnection _connection;
+
+    JNISession(SWIGTYPE_p_pn_session_t session_t)
+    {
+        _impl = session_t;
+        Proton.pn_session_set_context(_impl, this);
+        _connection = JNIConnection.getConnection(Proton.pn_session_connection(_impl));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sender")
+    public Sender sender(String name)
+    {
+        return new JNISender(Proton.pn_sender(_impl, name));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_receiver")
+    public Receiver receiver(String name)
+    {
+        //TODO
+        return new JNIReceiver(Proton.pn_receiver(_impl, name));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_session_next")
+    public Session next(EnumSet<EndpointState> local, EnumSet<EndpointState> remote)
+    {
+        SWIGTYPE_p_pn_session_t session = Proton.pn_session_next(_impl, StateConverter.getStateMask(local, remote));
+        if(session != null)
+        {
+            return (Session) Proton.pn_session_get_context(session);
+        }
+        return null;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_session_connection")
+    public Connection getConnection()
+    {
+        return _connection;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_session_state")
+    public EndpointState getLocalState()
+    {
+        return StateConverter.getLocalState(Proton.pn_session_state(_impl));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_session_state")
+    public EndpointState getRemoteState()
+    {
+        return StateConverter.getRemoteState(Proton.pn_session_state(_impl));
+    }
+
+    @Override
+    public EndpointError getLocalError()
+    {
+        //TODO
+        return null;
+    }
+
+    @Override
+    public EndpointError getRemoteError()
+    {
+        //TODO
+        return null;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_session_free")
+    public void free()
+    {
+        if(_impl != null)
+        {
+            Proton.pn_session_set_context(_impl, null);
+            Proton.pn_session_free(_impl);
+            _impl = null;
+        }
+
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_session_open")
+    public void open()
+    {
+        Proton.pn_session_open(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_session_close")
+    public void close()
+    {
+        Proton.pn_session_close(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_session_set_context")
+    public void setContext(Object o)
+    {
+        _context = o;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_session_get_context")
+    public Object getContext()
+    {
+        return _context;
+    }
+
+    @Override
+    protected void finalize() throws Throwable
+    {
+        free();
+        super.finalize();
+    }
+
+    static JNISession getSession(SWIGTYPE_p_pn_session_t session_t)
+    {
+        if(session_t != null)
+        {
+            JNISession sessionObj = (JNISession) Proton.pn_session_get_context(session_t);
+            if(sessionObj == null)
+            {
+                sessionObj = new JNISession(session_t);
+            }
+            return sessionObj;
+        }
+        return null;
+    }
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISsl.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISsl.java
new file mode 100644
index 0000000..0d9d389
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISsl.java
@@ -0,0 +1,91 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+
+package org.apache.qpid.proton.engine.jni;
+
+import static org.apache.qpid.proton.jni.ExceptionHelper.checkProtonCReturnValue;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.engine.Ssl;
+import org.apache.qpid.proton.jni.Proton;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_ssl_t;
+
+class JNISsl implements Ssl
+{
+    private final SWIGTYPE_p_pn_ssl_t _impl;
+
+    JNISsl(SWIGTYPE_p_pn_ssl_t impl)
+    {
+        _impl = impl;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_ssl_get_cipher_name")
+    public String getCipherName()
+    {
+        byte[] data = new byte[1024];
+        boolean b = Proton.pn_ssl_get_cipher_name(_impl, ByteBuffer.wrap(data));
+        return b ? asString(data) : null;
+
+    }
+
+    private String asString(byte[] data)
+    {
+        int i = -1;
+        while(data[++i] != 0);
+        if(i == 0)
+        {
+            return null;
+        }
+        else
+        {
+            return new String(data,0,i,Charset.forName("US-ASCII"));
+        }
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_ssl_get_protocol_name")
+    public String getProtocolName()
+    {
+        byte[] data = new byte[1024];
+        boolean b = Proton.pn_ssl_get_protocol_name(_impl, ByteBuffer.wrap(data));
+        return b ? asString(data) : null;
+    }
+
+    @Override
+    public void setPeerHostname(String hostname)
+    {
+        int retVal = Proton.pn_ssl_set_peer_hostname(_impl, hostname);
+        checkProtonCReturnValue(retVal);
+    }
+
+    @Override
+    public String getPeerHostname()
+    {
+        byte[] data = new byte[256]; // hostnames are a maximum of 255 characters long (see http://tools.ietf.org/html/rfc1034#section-3.1)
+        int retVal = Proton.pn_ssl_get_peer_hostname(_impl, ByteBuffer.wrap(data));
+        checkProtonCReturnValue(retVal);
+        return asString(data);
+    }
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISslDomain.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISslDomain.java
new file mode 100644
index 0000000..607e909
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNISslDomain.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.engine.jni;
+
+import static org.apache.qpid.proton.jni.ExceptionHelper.checkProtonCReturnValue;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.engine.SslDomain;
+import org.apache.qpid.proton.jni.Proton;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_ssl_domain_t;
+import org.apache.qpid.proton.jni.pn_ssl_mode_t;
+import org.apache.qpid.proton.jni.pn_ssl_verify_mode_t;
+
+public class JNISslDomain implements SslDomain
+{
+    private SWIGTYPE_p_pn_ssl_domain_t _impl;
+    private Mode _mode;
+    private VerifyMode _verifyMode;
+    private String _certificateFile;
+    private String _trustedCaDb;
+    private String _privateKeyFile;
+    private String _privateKeyPassword;
+    private boolean _allowUnsecured;
+
+    @Override
+    @ProtonCEquivalent("pn_ssl_init")
+    public void init(Mode mode)
+    {
+        _impl = Proton.pn_ssl_domain(convertMode(mode));
+    }
+
+    private pn_ssl_mode_t convertMode(Mode mode)
+    {
+        _mode = mode;
+        pn_ssl_mode_t cMode = null;
+        switch(mode)
+        {
+            case CLIENT:
+                cMode = pn_ssl_mode_t.PN_SSL_MODE_CLIENT;
+                break;
+            case SERVER:
+                cMode = pn_ssl_mode_t.PN_SSL_MODE_SERVER;
+                break;
+        }
+        return cMode;
+    }
+
+    @Override
+    public Mode getMode()
+    {
+        return _mode;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_ssl_domain_set_credentials")
+    public void setCredentials(String certificate_file, String private_key_file, String password)
+    {
+        _certificateFile = certificate_file;
+        _privateKeyFile = private_key_file;
+        _privateKeyPassword = password;
+        int retVal = Proton.pn_ssl_domain_set_credentials(_impl,certificate_file,private_key_file,password);
+        checkProtonCReturnValue(retVal);
+    }
+
+    @Override
+    public String getPrivateKeyFile()
+    {
+        return _privateKeyFile;
+    }
+
+    @Override
+    public String getPrivateKeyPassword()
+    {
+        return _privateKeyPassword;
+    }
+
+    @Override
+    public String getCertificateFile()
+    {
+        return _certificateFile;
+    }
+
+
+    @Override
+    @ProtonCEquivalent("pn_ssl_domain_set_trusted_ca_db")
+    public void setTrustedCaDb(String certificate_db)
+    {
+        _trustedCaDb = certificate_db;
+        int retVal = Proton.pn_ssl_domain_set_trusted_ca_db(_impl, certificate_db);
+        checkProtonCReturnValue(retVal);
+    }
+
+    @Override
+    public String getTrustedCaDb()
+    {
+        return _trustedCaDb;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_ssl_domain_allow_unsecured_client")
+    public void allowUnsecuredClient(boolean unused)
+    {
+        _allowUnsecured = true;
+        int retVal = Proton.pn_ssl_domain_allow_unsecured_client(_impl);
+        checkProtonCReturnValue(retVal);
+    }
+
+    @Override
+    public boolean allowUnsecuredClient()
+    {
+        return _allowUnsecured;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_ssl_domain_set_peer_authentication")
+    public void setPeerAuthentication(VerifyMode mode)
+    {
+        _verifyMode = mode;
+        int retVal = Proton.pn_ssl_domain_set_peer_authentication(_impl,convertVerifyMode(mode),_trustedCaDb);
+        checkProtonCReturnValue(retVal);
+    }
+
+    private pn_ssl_verify_mode_t convertVerifyMode(VerifyMode mode)
+    {
+        pn_ssl_verify_mode_t cMode = null;
+        switch(mode)
+        {
+            case ANONYMOUS_PEER:
+                cMode = pn_ssl_verify_mode_t.PN_SSL_ANONYMOUS_PEER;
+                break;
+            case VERIFY_PEER:
+                cMode = pn_ssl_verify_mode_t.PN_SSL_VERIFY_PEER;
+                break;
+            case VERIFY_PEER_NAME:
+                cMode = pn_ssl_verify_mode_t.PN_SSL_VERIFY_PEER_NAME;
+                break;
+            default:
+                throw new IllegalArgumentException("Unsupported verify mode " + mode);
+        }
+
+        return cMode;
+    }
+
+    @Override
+    public VerifyMode getPeerAuthentication()
+    {
+        return _verifyMode;
+    }
+
+    SWIGTYPE_p_pn_ssl_domain_t getImpl()
+    {
+        if (_impl == null)
+        {
+            throw new IllegalStateException("init has not been called");
+        }
+        return _impl;
+    }
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNITransport.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNITransport.java
new file mode 100644
index 0000000..5f5de02
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/JNITransport.java
@@ -0,0 +1,182 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.engine.jni;
+
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.engine.*;
+import org.apache.qpid.proton.jni.Proton;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_connection_t;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_error_t;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_ssl_t;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_transport_t;
+
+public class JNITransport implements Transport
+{
+
+    private SWIGTYPE_p_pn_transport_t _impl;
+    private JNISasl _sasl;
+    private Object _context;
+    private JNISsl _ssl;
+
+
+    public JNITransport()
+    {
+        _impl = Proton.pn_transport();
+//        Proton.pn_transport_trace(_impl,Proton.PN_TRACE_FRM);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_transport_bind")
+    public void bind(Connection connection)
+    {
+        JNIConnection jniConn = (JNIConnection)connection;
+        SWIGTYPE_p_pn_connection_t connImpl = jniConn.getImpl();
+        Proton.pn_transport_bind(_impl, connImpl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_transport_input")
+    public int input(byte[] bytes, int offset, int size)
+    {
+        int i = Proton.pn_transport_input(_impl, ByteBuffer.wrap(bytes, offset, size));
+        if(i == Proton.PN_ERR)
+        {
+            SWIGTYPE_p_pn_error_t err = Proton.pn_transport_error(_impl);
+            String errorText = Proton.pn_error_text(err);
+            Proton.pn_error_clear(err);
+            throw new TransportException(errorText);
+        }
+        //System.err.println("**RG**  input: " + i);
+        return i;
+    }
+
+    @Override
+    public int output(byte[] bytes, int offset, int size)
+    {
+        /*int i = Proton.pn_transport_output(_impl, ByteBuffer.wrap(bytes, offset, size));
+        return i;*/
+        return Proton.pn_transport_output(_impl, ByteBuffer.wrap(bytes, offset, size));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_sasl")
+    public Sasl sasl()
+    {
+        if(_sasl == null)
+        {
+            _sasl = new JNISasl( Proton.pn_sasl(_impl));
+        }
+        return _sasl;
+
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_ssl")
+    public Ssl ssl(SslDomain sslDomain, SslPeerDetails sslPeerDetails)
+    {
+        if(_ssl == null)
+        {
+            // TODO move this code to SslPeerDetails or its factory
+            final String sessionId;
+            if (sslPeerDetails == null)
+            {
+                sessionId = null;
+            }
+            else
+            {
+                sessionId = sslPeerDetails.getHostname() + ":" + sslPeerDetails.getPort();
+            }
+
+            SWIGTYPE_p_pn_ssl_t pn_ssl = Proton.pn_ssl( _impl );
+            _ssl = new JNISsl( pn_ssl);
+            Proton.pn_ssl_init(pn_ssl, ((JNISslDomain)sslDomain).getImpl(), sessionId);
+            // TODO is the returned int an error code??
+        }
+        return _ssl;
+    }
+
+    @Override
+    public Ssl ssl(SslDomain sslDomain)
+    {
+        return ssl(sslDomain, null);
+    }
+
+    @Override
+    public EndpointState getLocalState()
+    {
+        return null; //TODO
+    }
+
+    @Override
+    public EndpointState getRemoteState()
+    {
+        return null; //TODO
+    }
+
+    @Override
+    public EndpointError getLocalError()
+    {
+        return null; //TODO
+    }
+
+    @Override
+    public EndpointError getRemoteError()
+    {
+        return null; //TODO
+    }
+
+    @Override
+    public void free()
+    {
+        Proton.pn_transport_free(_impl);
+    }
+
+    @Override
+    public void open()
+    {
+    }
+
+    @Override
+    public void close()
+    {
+    }
+
+    @Override
+    public void setContext(Object o)
+    {
+        _context = o;
+    }
+
+    @Override
+    public Object getContext()
+    {
+        return _context;
+    }
+
+    @Override
+    protected void finalize() throws Throwable
+    {
+        free();
+        super.finalize();
+    }
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/StateConverter.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/StateConverter.java
new file mode 100644
index 0000000..6758366
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/engine/jni/StateConverter.java
@@ -0,0 +1,98 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.engine.jni;
+
+import java.util.EnumSet;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.jni.Proton;
+
+class StateConverter
+{
+    public static EndpointState getLocalState(int state)
+    {
+        state =  state & Proton.PN_LOCAL_MASK;
+        if(state == Proton.PN_LOCAL_UNINIT)
+        {
+            return EndpointState.UNINITIALIZED;
+        }
+        else if(state == Proton.PN_LOCAL_ACTIVE)
+        {
+            return EndpointState.ACTIVE;
+        }
+        else if(state == Proton.PN_LOCAL_CLOSED)
+        {
+            return EndpointState.CLOSED;
+        }
+        //TODO
+        return null;
+    }
+
+
+    public static EndpointState getRemoteState(int state)
+    {
+        state =  state & Proton.PN_REMOTE_MASK;
+        if(state == Proton.PN_REMOTE_UNINIT)
+        {
+            return EndpointState.UNINITIALIZED;
+        }
+        else if(state == Proton.PN_REMOTE_ACTIVE)
+        {
+            return EndpointState.ACTIVE;
+        }
+        else if(state == Proton.PN_REMOTE_CLOSED)
+        {
+            return EndpointState.CLOSED;
+        }
+        //TODO
+        return null;
+    }
+
+    public static int getStateMask(EnumSet<EndpointState> local, EnumSet<EndpointState> remote)
+    {
+        int state = 0;
+        if(local.contains(EndpointState.UNINITIALIZED))
+        {
+            state &= Proton.PN_LOCAL_UNINIT;
+        }
+        if(local.contains(EndpointState.ACTIVE))
+        {
+            state &= Proton.PN_LOCAL_ACTIVE;
+        }
+        if(local.contains(EndpointState.CLOSED))
+        {
+            state &= Proton.PN_LOCAL_CLOSED;
+        }
+        if(remote.contains(EndpointState.UNINITIALIZED))
+        {
+            state &= Proton.PN_REMOTE_UNINIT;
+        }
+        if(remote.contains(EndpointState.ACTIVE))
+        {
+            state &= Proton.PN_REMOTE_ACTIVE;
+        }
+        if(remote.contains(EndpointState.CLOSED))
+        {
+            state &= Proton.PN_REMOTE_CLOSED;
+        }
+
+        return state;
+    }
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/jni/ExceptionHelper.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/jni/ExceptionHelper.java
new file mode 100644
index 0000000..d895925
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/jni/ExceptionHelper.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.jni;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class ExceptionHelper
+{
+    private static final Logger LOGGER = Logger.getLogger(ExceptionHelper.class.getName());
+
+    /**
+     * Check the return value from a Proton function call and throw
+     * an exception if it's non-zero.
+     * @throws JNIException
+     */
+    public static void checkProtonCReturnValue(int retVal)
+    {
+        if(retVal != 0)
+        {
+            if(LOGGER.isLoggable(Level.FINE))
+            {
+                LOGGER.log(Level.FINE, "Non-zero return value: " + retVal, new Exception("<dummy exception to generate stack trace>"));
+            }
+            throw new JNIException(retVal);
+        }
+    }
+}
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/jni/JNIException.java
similarity index 67%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-c/bindings/java/src/main/java/org/apache/qpid/proton/jni/JNIException.java
index fd9b0c2..ce086de 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/jni/JNIException.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,17 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.jni;
 
-package org.apache.qpid.proton.engine;
+import org.apache.qpid.proton.ProtonException;
 
-public class ProtonException extends RuntimeException
+/**
+ * Indicates that a Proton function called via JNI returned an error code.
+ */
+public class JNIException extends ProtonException
 {
-    public ProtonException()
+    public JNIException(int returnValue)
     {
+        super("Unexpected Proton C return value: " + returnValue);
     }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
 }
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/jni/JNIFactory.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/jni/JNIFactory.java
new file mode 100644
index 0000000..6959733
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/jni/JNIFactory.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.jni;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public abstract class JNIFactory
+{
+    private static final Logger LOGGER = Logger.getLogger(JNIFactory.class.getName());
+
+    static
+    {
+        String libname = "proton-swig";
+
+        if(LOGGER.isLoggable(Level.FINE))
+        {
+            LOGGER.fine("About to load library " + libname);
+        }
+
+        System.loadLibrary(libname);
+
+        if(LOGGER.isLoggable(Level.FINE))
+        {
+            LOGGER.fine("Successfully loaded library " + libname);
+        }
+    }
+
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/message/jni/JNIMessage.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/message/jni/JNIMessage.java
new file mode 100644
index 0000000..5ffb3e0
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/message/jni/JNIMessage.java
@@ -0,0 +1,841 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.message.jni;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.util.Date;
+import java.util.UUID;
+
+import org.apache.qpid.proton.ProtonCEquivalent;
+import org.apache.qpid.proton.amqp.Binary;
+import org.apache.qpid.proton.amqp.Symbol;
+import org.apache.qpid.proton.amqp.UnsignedByte;
+import org.apache.qpid.proton.amqp.UnsignedInteger;
+import org.apache.qpid.proton.amqp.UnsignedLong;
+import org.apache.qpid.proton.amqp.UnsignedShort;
+import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
+import org.apache.qpid.proton.amqp.messaging.DeliveryAnnotations;
+import org.apache.qpid.proton.amqp.messaging.Footer;
+import org.apache.qpid.proton.amqp.messaging.Header;
+import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
+import org.apache.qpid.proton.amqp.messaging.Properties;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.jni.Proton;
+import org.apache.qpid.proton.jni.SWIGTYPE_p_pn_message_t;
+import org.apache.qpid.proton.jni.pn_atom_t;
+import org.apache.qpid.proton.jni.pn_atom_t_u;
+import org.apache.qpid.proton.jni.pn_bytes_t;
+import org.apache.qpid.proton.jni.pn_format_t;
+import org.apache.qpid.proton.jni.pn_type_t;
+import org.apache.qpid.proton.message.Message;
+import org.apache.qpid.proton.message.MessageError;
+import org.apache.qpid.proton.message.MessageFormat;
+
+public class JNIMessage implements Message
+{
+
+    public static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
+    public static final Charset ASCII_CHARSET = Charset.forName("US-ASCII");
+    private SWIGTYPE_p_pn_message_t _impl;
+
+    JNIMessage()
+    {
+        _impl = Proton.pn_message();
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_is_durable")
+    public boolean isDurable()
+    {
+        return Proton.pn_message_is_durable(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_delivery_count")
+    public long getDeliveryCount()
+    {
+        return Proton.pn_message_get_delivery_count(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_priority")
+    public short getPriority()
+    {
+        return Proton.pn_message_get_priority(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_is_first_acquirer")
+    public boolean isFirstAcquirer()
+    {
+        return Proton.pn_message_is_first_acquirer(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_ttl")
+    public long getTtl()
+    {
+        return Proton.pn_message_get_ttl(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_durable")
+    public void setDurable(boolean durable)
+    {
+        Proton.pn_message_set_durable(_impl, durable);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_ttl")
+    public void setTtl(long ttl)
+    {
+        Proton.pn_message_set_ttl(_impl, ttl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_delivery_count")
+    public void setDeliveryCount(long deliveryCount)
+    {
+        Proton.pn_message_set_delivery_count(_impl, deliveryCount);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_first_acquirer")
+    public void setFirstAcquirer(boolean firstAcquirer)
+    {
+        Proton.pn_message_set_first_acquirer(_impl, firstAcquirer);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_priority")
+    public void setPriority(short priority)
+    {
+        Proton.pn_message_set_priority(_impl, priority);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_id")
+    public Object getMessageId()
+    {
+        return convert(Proton.pn_message_get_id(_impl));
+    }
+
+    private pn_atom_t convertToAtom(Object o)
+    {
+        pn_atom_t atom = new pn_atom_t();
+
+//PN_NULL
+        if(o == null)
+        {
+            atom.setType(pn_type_t.PN_NULL);
+        }
+//PN_BOOL
+        else if(o instanceof Boolean)
+        {
+            atom.setType(pn_type_t.PN_BOOL);
+            atom.getU().setAs_bool((Boolean)o);
+        }
+//PN_UBYTE
+        else if(o instanceof UnsignedByte)
+        {
+            atom.setType(pn_type_t.PN_UBYTE);
+            atom.getU().setAs_ubyte(((UnsignedByte) o).shortValue());
+        }
+//PN_BYTE
+        else if(o instanceof Byte)
+        {
+            atom.setType(pn_type_t.PN_BYTE);
+            atom.getU().setAs_byte((Byte) o);
+        }
+//PN_USHORT
+        else if(o instanceof UnsignedShort)
+        {
+            atom.setType(pn_type_t.PN_USHORT);
+            atom.getU().setAs_ushort(((UnsignedShort) o).intValue());
+        }
+//PN_SHORT
+        else if(o instanceof Short)
+        {
+            atom.setType(pn_type_t.PN_SHORT);
+            atom.getU().setAs_short((Short) o);
+        }
+//PN_UINT
+        else if(o instanceof UnsignedInteger)
+        {
+            atom.setType(pn_type_t.PN_UINT);
+            atom.getU().setAs_uint(((UnsignedInteger) o).longValue());
+        }
+//PN_INT
+        else if(o instanceof Integer)
+        {
+            atom.setType(pn_type_t.PN_INT);
+            atom.getU().setAs_int((Integer) o);
+        }
+//PN_CHAR
+        else if(o instanceof Character)
+        {
+            atom.setType(pn_type_t.PN_CHAR);
+            atom.getU().setAs_char((Character) o);
+        }
+//PN_ULONG
+        else if(o instanceof UnsignedLong)
+        {
+            atom.setType(pn_type_t.PN_ULONG);
+            atom.getU().setAs_ulong(((UnsignedLong) o).bigIntegerValue());
+        }
+//PN_LONG
+        else if(o instanceof Long)
+        {
+            atom.setType(pn_type_t.PN_LONG);
+            atom.getU().setAs_long((Long) o);
+        }
+//PN_TIMESTAMP
+        else if(o instanceof Date)
+        {
+            atom.setType(pn_type_t.PN_TIMESTAMP);
+            atom.getU().setAs_timestamp(((Date)o).getTime());
+        }
+//PN_FLOAT
+        else if(o instanceof Float)
+        {
+            atom.setType(pn_type_t.PN_FLOAT);
+            atom.getU().setAs_float((Float) o);
+        }
+//PN_DOUBLE
+        else if(o instanceof Double)
+        {
+            atom.setType(pn_type_t.PN_DOUBLE);
+            atom.getU().setAs_double((Double) o);
+        }
+//PN_DECIMAL32
+        // TODO
+//PN_DECIMAL64
+        // TODO
+//PN_DECIMAL128
+        // TODO
+//PN_UUID
+        else if (o instanceof UUID)
+        {
+            byte[] bytes = new byte[16];
+            ByteBuffer buf = ByteBuffer.wrap(bytes);
+            UUID uuid = (UUID) o;
+            buf.putLong(uuid.getMostSignificantBits());
+            buf.putLong(uuid.getLeastSignificantBits());
+            atom.setType(pn_type_t.PN_UUID);
+            pn_bytes_t val = Proton.pn_bytes(bytes.length, bytes);
+            atom.getU().setAs_bytes(val);
+            val.delete();
+        }
+//PN_BINARY
+        else if(o instanceof byte[] || o instanceof Binary)
+        {
+            byte[] bytes = (o instanceof byte[]) ? (byte[])o : ((Binary)o).getArray();
+            atom.setType(pn_type_t.PN_BINARY);
+            pn_bytes_t val = Proton.pn_bytes(bytes.length, bytes);
+            atom.getU().setAs_bytes(val);
+            val.delete();
+        }
+//PN_STRING
+        else if(o instanceof String)
+        {
+            byte[] bytes = ((String)o).getBytes(UTF8_CHARSET);
+            atom.setType(pn_type_t.PN_STRING);
+            pn_bytes_t val = Proton.pn_bytes(bytes.length, bytes);
+            atom.getU().setAs_bytes(val);
+            val.delete();
+        }
+//PN_SYMBOL
+        else if(o instanceof Symbol)
+        {
+            byte[] bytes = ((Symbol)o).toString().getBytes(ASCII_CHARSET);
+            atom.setType(pn_type_t.PN_STRING);
+            pn_bytes_t val = Proton.pn_bytes(bytes.length, bytes);
+            atom.getU().setAs_bytes(val);
+            val.delete();
+        }
+//PN_DESCRIBED
+        // TODO
+//PN_ARRAY
+        // TODO
+//PN_LIST
+        // TODO
+//PN_MAP
+        // TODO
+
+        return atom;
+    }
+
+    private Object convert(pn_atom_t atom)
+    {
+        if(atom != null)
+        {
+            pn_type_t type = atom.getType();
+            pn_atom_t_u value = atom.getU();
+
+            if(pn_type_t.PN_BINARY.equals(type))
+            {
+                new Binary(Proton.pn_bytes_to_array(value.getAs_bytes()));
+            }
+            else if(pn_type_t.PN_STRING.equals(type))
+            {
+                return new String(Proton.pn_bytes_to_array(value.getAs_bytes()), UTF8_CHARSET);
+            }
+            else if(pn_type_t.PN_SYMBOL.equals(type))
+            {
+                return Symbol.valueOf(new String(Proton.pn_bytes_to_array(value.getAs_bytes()), ASCII_CHARSET));
+            }
+            else if(pn_type_t.PN_ARRAY.equals(type))
+            {
+               // TODO
+            }
+            else if(pn_type_t.PN_BOOL.equals(type))
+            {
+                return value.getAs_bool();
+            }
+            else if(pn_type_t.PN_BYTE.equals(type))
+            {
+                return value.getAs_byte();
+            }
+            else if(pn_type_t.PN_CHAR.equals(type))
+            {
+                return (char) value.getAs_char();
+            }
+            else if(pn_type_t.PN_DECIMAL128.equals(type))
+            {
+                // TODO
+            }
+            else if(pn_type_t.PN_DECIMAL64.equals(type))
+            {
+                // TODO
+            }
+            else if(pn_type_t.PN_DECIMAL32.equals(type))
+            {
+                // TODO
+            }
+            else if(pn_type_t.PN_DESCRIBED.equals(type))
+            {
+                // TODO
+            }
+            else if(pn_type_t.PN_DOUBLE.equals(type))
+            {
+                return value.getAs_double();
+            }
+            else if(pn_type_t.PN_FLOAT.equals(type))
+            {
+                return value.getAs_float();
+            }
+            else if(pn_type_t.PN_INT.equals(type))
+            {
+                return value.getAs_int();
+            }
+            else if(pn_type_t.PN_LIST.equals(type))
+            {
+                // TODO
+            }
+            else if(pn_type_t.PN_LONG.equals(type))
+            {
+                return value.getAs_long();
+            }
+            else if(pn_type_t.PN_MAP.equals(type))
+            {
+                // TODO
+            }
+            else if(pn_type_t.PN_NULL.equals(type))
+            {
+                return null;
+            }
+            else if(pn_type_t.PN_SHORT.equals(type))
+            {
+                return value.getAs_short();
+            }
+            else if(pn_type_t.PN_TIMESTAMP.equals(type))
+            {
+                return new Date(value.getAs_timestamp());
+            }
+            else if(pn_type_t.PN_UBYTE.equals(type))
+            {
+                return UnsignedByte.valueOf((byte) value.getAs_ubyte());
+            }
+            else if(pn_type_t.PN_UINT.equals(type))
+            {
+                return UnsignedInteger.valueOf(value.getAs_uint());
+            }
+            else if(pn_type_t.PN_ULONG.equals(type))
+            {
+                return new UnsignedLong(value.getAs_ulong().longValue());
+            }
+            else if(pn_type_t.PN_USHORT.equals(type))
+            {
+                return UnsignedShort.valueOf((short) value.getAs_ushort());
+            }
+            else if(pn_type_t.PN_UUID.equals(type))
+            {
+                byte[] b = Proton.pn_bytes_to_array(value.getAs_bytes());
+                ByteBuffer buf = ByteBuffer.wrap(b);
+                return new UUID(buf.getLong(), buf.getLong());
+            }
+
+        }
+        return null;  //TODO
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_group_sequence")
+    public long getGroupSequence()
+    {
+        return Proton.pn_message_get_group_sequence(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_reply_to_group_id")
+    public String getReplyToGroupId()
+    {
+        return Proton.pn_message_get_reply_to_group_id(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_creation_time")
+    public long getCreationTime()
+    {
+        return Proton.pn_message_get_creation_time(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_address")
+    public String getAddress()
+    {
+        return Proton.pn_message_get_address(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_user_id")
+    public byte[] getUserId()
+    {
+
+        return Proton.pn_bytes_to_array(Proton.pn_message_get_user_id(_impl));
+
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_reply_to")
+    public String getReplyTo()
+    {
+        return Proton.pn_message_get_reply_to(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_group_id")
+    public String getGroupId()
+    {
+        return Proton.pn_message_get_group_id(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_content_type")
+    public String getContentType()
+    {
+        return Proton.pn_message_get_content_type(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_expiry_time")
+    public long getExpiryTime()
+    {
+        return Proton.pn_message_get_expiry_time(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_correlation_id")
+    public Object getCorrelationId()
+    {
+        return convert(Proton.pn_message_get_correlation_id(_impl));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_content_encoding")
+    public String getContentEncoding()
+    {
+        return Proton.pn_message_get_content_encoding(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_subject")
+    public String getSubject()
+    {
+        return Proton.pn_message_get_subject(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_group_sequence")
+    public void setGroupSequence(long groupSequence)
+    {
+        Proton.pn_message_set_group_sequence(_impl, (int) groupSequence);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_user_id")
+    public void setUserId(byte[] userId)
+    {
+        pn_bytes_t val = Proton.pn_bytes(userId.length, userId);
+
+        Proton.pn_message_set_user_id(_impl, val);
+
+        val.delete();
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_creation_time")
+    public void setCreationTime(long creationTime)
+    {
+        Proton.pn_message_set_creation_time(_impl, creationTime);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_subject")
+    public void setSubject(String subject)
+    {
+        Proton.pn_message_set_subject(_impl, subject);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_group_id")
+    public void setGroupId(String groupId)
+    {
+        Proton.pn_message_set_group_id(_impl, groupId);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_address")
+    public void setAddress(String to)
+    {
+        Proton.pn_message_set_address(_impl, to);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_expiry_time")
+    public void setExpiryTime(long absoluteExpiryTime)
+    {
+        Proton.pn_message_set_expiry_time(_impl,absoluteExpiryTime);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_reply_to_group_id")
+    public void setReplyToGroupId(String replyToGroupId)
+    {
+        Proton.pn_message_set_reply_to_group_id(_impl, replyToGroupId);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_content_encoding")
+    public void setContentEncoding(String contentEncoding)
+    {
+        Proton.pn_message_set_content_encoding(_impl, contentEncoding);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_content_type")
+    public void setContentType(String contentType)
+    {
+        Proton.pn_message_set_content_type(_impl, contentType);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_reply_to")
+    public void setReplyTo(String replyTo)
+    {
+        Proton.pn_message_set_reply_to(_impl, replyTo);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_correlation_id")
+    public void setCorrelationId(Object correlationId)
+    {
+        Proton.pn_message_set_correlation_id(_impl, convertToAtom(correlationId));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_id")
+    public void setMessageId(Object messageId)
+    {
+
+        Proton.pn_message_set_id(_impl, convertToAtom(messageId));
+
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_decode")
+    public int decode(byte[] data, int offset, int length)
+    {
+        return Proton.pn_message_decode(_impl, ByteBuffer.wrap(data,offset,length));
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_encode")
+    public int encode(byte[] data, int offset, int length)
+    {
+        ByteBuffer buffer = ByteBuffer.wrap(data, offset, length);
+        int status = Proton.pn_message_encode(_impl, buffer);
+        return status == 0 ? buffer.position() : status;
+
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_set_format")
+    public void setMessageFormat(MessageFormat format)
+    {
+        Proton.pn_message_set_format(_impl, convertMessageFormat(format));
+    }
+
+    private pn_format_t convertMessageFormat(MessageFormat format)
+    {
+        switch(format)
+        {
+            case AMQP:
+                return pn_format_t.PN_AMQP;
+            case DATA:
+                return pn_format_t.PN_DATA;
+            case JSON:
+                return pn_format_t.PN_JSON;
+            case TEXT:
+                return pn_format_t.PN_TEXT;
+        }
+        // TODO
+        return pn_format_t.PN_AMQP;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_get_format")
+    public MessageFormat getMessageFormat()
+    {
+        return convertMessageFormat(Proton.pn_message_get_format(_impl));
+    }
+
+    private MessageFormat convertMessageFormat(pn_format_t format)
+    {
+        if(format == pn_format_t.PN_AMQP)
+        {
+            return MessageFormat.AMQP;
+        }
+        if(format == pn_format_t.PN_DATA)
+        {
+            return MessageFormat.DATA;
+        }
+        if(format == pn_format_t.PN_JSON)
+        {
+            return MessageFormat.JSON;
+        }
+        if(format == pn_format_t.PN_TEXT)
+        {
+            return MessageFormat.TEXT;
+        }
+        // TODO
+        return MessageFormat.AMQP;
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_clear")
+    public void clear()
+    {
+        Proton.pn_message_clear(_impl);
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_error")
+    public MessageError getError()
+    {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+
+    @Override
+    @ProtonCEquivalent("pn_message_load")
+    public void load(Object data)
+    {
+        byte[] bytes;
+
+        if(data instanceof byte[])
+        {
+            bytes = (byte[])data;
+        }
+        else if(data instanceof Binary)
+        {
+            bytes = ((Binary)data).getArray();
+        }
+        else if(data instanceof String)
+        {
+
+            byte[] temp = ((String)data).getBytes(UTF8_CHARSET);
+            if(getMessageFormat() == MessageFormat.DATA)
+            {
+                bytes = temp;
+            }
+            else
+            {
+                // String needs to be null terminated
+                bytes = new byte[temp.length+1];
+                System.arraycopy(temp,0,bytes,0,temp.length);
+            }
+
+        }
+        else
+        {
+            bytes = new byte[getMessageFormat() == MessageFormat.DATA ? 0 : 1];
+        }
+        int rval = Proton.pn_message_load(_impl, ByteBuffer.wrap(bytes));
+
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_save")
+    public Object save()
+    {
+
+        int size;
+        int sz = 16;
+        ByteBuffer buf;
+        byte[] data;
+        do
+        {
+            sz = sz*2;
+            data = new byte[sz];
+            buf = ByteBuffer.wrap(data);
+            size = Proton.pn_message_save(_impl, buf);
+        }
+        while(size == Proton.PN_OVERFLOW);
+
+        byte[] rval = new byte[buf.position()];
+        buf.flip();
+        buf.get(rval);
+
+        return rval;
+    }
+
+    @Override
+    public String toAMQPFormat(Object value)
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Object parseAMQPFormat(String value)
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void setFooter(Footer footer)
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Header getHeader()
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DeliveryAnnotations getDeliveryAnnotations()
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_annotations")
+    public MessageAnnotations getMessageAnnotations()
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_properties")
+    public Properties getProperties()
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public ApplicationProperties getApplicationProperties()
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    @ProtonCEquivalent("pn_message_body")
+    public Section getBody()
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    public Footer getFooter()
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    public void setHeader(Header header)
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    public void setDeliveryAnnotations(DeliveryAnnotations deliveryAnnotations)
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    public void setMessageAnnotations(MessageAnnotations messageAnnotations)
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    public void setProperties(Properties properties)
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    public void setApplicationProperties(ApplicationProperties applicationProperties)
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+    public void setBody(Section body)
+    {
+        //TODO
+        throw new UnsupportedOperationException();
+    }
+
+
+}
diff --git a/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/message/jni/JNIMessageFactory.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/message/jni/JNIMessageFactory.java
new file mode 100644
index 0000000..e64cd11
--- /dev/null
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/message/jni/JNIMessageFactory.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.message.jni;
+
+import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
+import org.apache.qpid.proton.amqp.messaging.DeliveryAnnotations;
+import org.apache.qpid.proton.amqp.messaging.Footer;
+import org.apache.qpid.proton.amqp.messaging.Header;
+import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
+import org.apache.qpid.proton.amqp.messaging.Properties;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.jni.JNIFactory;
+import org.apache.qpid.proton.message.Message;
+import org.apache.qpid.proton.message.MessageFactory;
+
+public class JNIMessageFactory extends JNIFactory implements MessageFactory
+{
+
+    @Override
+    public Message createMessage()
+    {
+        return new JNIMessage();
+    }
+
+    @Override
+    public Message createMessage(Header header,
+                                 DeliveryAnnotations deliveryAnnotations, MessageAnnotations messageAnnotations,
+                                 Properties properties, ApplicationProperties applicationProperties,
+                                 Section body, Footer footer)
+    {
+        Message message = new JNIMessage();
+        message.setHeader(header);
+        message.setDeliveryAnnotations(deliveryAnnotations);
+        message.setMessageAnnotations(messageAnnotations);
+        message.setProperties(properties);
+        message.setApplicationProperties(applicationProperties);
+        message.setBody(body);
+        message.setFooter(footer);
+
+        return message;
+    }
+
+}
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/messenger/jni/JNIMessengerFactory.java
similarity index 61%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-c/bindings/java/src/main/java/org/apache/qpid/proton/messenger/jni/JNIMessengerFactory.java
index fd9b0c2..09dad43 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-c/bindings/java/src/main/java/org/apache/qpid/proton/messenger/jni/JNIMessengerFactory.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,25 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.messenger.jni;
 
-package org.apache.qpid.proton.engine;
+import org.apache.qpid.proton.ProtonUnsupportedOperationException;
+import org.apache.qpid.proton.messenger.Messenger;
+import org.apache.qpid.proton.messenger.MessengerFactory;
 
-public class ProtonException extends RuntimeException
+public class JNIMessengerFactory implements MessengerFactory
 {
-    public ProtonException()
+
+    @Override
+    public Messenger createMessenger()
     {
+        throw new ProtonUnsupportedOperationException();
     }
 
-    public ProtonException(String message)
+    @Override
+    public Messenger createMessenger(String name)
     {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
+        throw new ProtonUnsupportedOperationException();
     }
 
 }
diff --git a/proton-c/bindings/java/src/main/resources/META-INF/services/org.apache.qpid.proton.engine.EngineFactory b/proton-c/bindings/java/src/main/resources/META-INF/services/org.apache.qpid.proton.engine.EngineFactory
new file mode 100644
index 0000000..0472f37
--- /dev/null
+++ b/proton-c/bindings/java/src/main/resources/META-INF/services/org.apache.qpid.proton.engine.EngineFactory
@@ -0,0 +1 @@
+org.apache.qpid.proton.engine.jni.JNIEngineFactory
\ No newline at end of file
diff --git a/proton-c/bindings/java/src/main/resources/META-INF/services/org.apache.qpid.proton.message.MessageFactory b/proton-c/bindings/java/src/main/resources/META-INF/services/org.apache.qpid.proton.message.MessageFactory
new file mode 100644
index 0000000..8fe1e57
--- /dev/null
+++ b/proton-c/bindings/java/src/main/resources/META-INF/services/org.apache.qpid.proton.message.MessageFactory
@@ -0,0 +1 @@
+org.apache.qpid.proton.message.jni.JNIMessageFactory
\ No newline at end of file
diff --git a/proton-c/bindings/java/src/main/resources/META-INF/services/org.apache.qpid.proton.messenger.MessengerFactory b/proton-c/bindings/java/src/main/resources/META-INF/services/org.apache.qpid.proton.messenger.MessengerFactory
new file mode 100644
index 0000000..bbb4a7c
--- /dev/null
+++ b/proton-c/bindings/java/src/main/resources/META-INF/services/org.apache.qpid.proton.messenger.MessengerFactory
@@ -0,0 +1 @@
+org.apache.qpid.proton.messenger.jni.JNIMessengerFactory
\ No newline at end of file
diff --git a/proton-c/docs/api/user.doxygen.in b/proton-c/docs/api/user.doxygen.in
index 43152cd..a2fbaa7 100644
--- a/proton-c/docs/api/user.doxygen.in
+++ b/proton-c/docs/api/user.doxygen.in
@@ -648,7 +648,7 @@
 # directories like "/usr/src/myproject". Separate the files or directories
 # with spaces.
 
-INPUT = @CMAKE_SOURCE_DIR@/include
+INPUT = @CMAKE_SOURCE_DIR@/proton-c/include
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
diff --git a/proton-j/contrib/proton-hawtdispatch/pom.xml b/proton-j/contrib/proton-hawtdispatch/pom.xml
index 226fea3..82fbc8b 100644
--- a/proton-j/contrib/proton-hawtdispatch/pom.xml
+++ b/proton-j/contrib/proton-hawtdispatch/pom.xml
@@ -18,15 +18,13 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <parent>
     <groupId>org.apache.qpid</groupId>
-    <artifactId>proton-project</artifactId>
+    <artifactId>proton-j</artifactId>
     <version>1.0-SNAPSHOT</version>
     <relativePath>../..</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
-  <groupId>org.apache.qpid</groupId>
   <artifactId>proton-hawtdispatch</artifactId>
-  <version>1.0-SNAPSHOT</version>
 
   <properties>
     <hawtbuf-version>1.9</hawtbuf-version>
@@ -36,8 +34,8 @@
   <dependencies>
     <dependency>
       <groupId>org.apache.qpid</groupId>
-      <artifactId>proton</artifactId>
-      <version>1.0-SNAPSHOT</version>
+      <artifactId>proton-j-impl</artifactId>
+      <version>${project.parent.version}</version>
     </dependency>
     <dependency>
       <groupId>org.fusesource.hawtdispatch</groupId>
diff --git a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnection.java b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnection.java
index bc827ba..1c0eb1c 100644
--- a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnection.java
+++ b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpConnection.java
@@ -22,9 +22,9 @@
 import org.apache.qpid.proton.engine.Delivery;
 import org.apache.qpid.proton.engine.Endpoint;
 import org.apache.qpid.proton.engine.EndpointError;
-import org.apache.qpid.proton.engine.impl.ConnectionImpl;
+import org.apache.qpid.proton.engine.ProtonJConnection;
+import org.apache.qpid.proton.engine.ProtonJSession;
 import org.apache.qpid.proton.engine.impl.ProtocolTracer;
-import org.apache.qpid.proton.engine.impl.SessionImpl;
 import org.fusesource.hawtdispatch.DispatchQueue;
 import org.fusesource.hawtdispatch.Task;
 
@@ -37,7 +37,7 @@
 public class AmqpConnection extends AmqpEndpointBase  {
 
     AmqpTransport transport;
-    ConnectionImpl connection;
+    ProtonJConnection connection;
     HashSet<AmqpSender> senders = new HashSet<AmqpSender>();
     boolean closing = false;
 
@@ -106,7 +106,7 @@
 
     public AmqpSession createSession() {
         assertExecuting();
-        SessionImpl session = connection.session();
+        ProtonJSession session = connection.session();
         session.open();
         pumpOut();
         return new AmqpSession(this, session);
diff --git a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpReceiver.java b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpReceiver.java
index 2631ea0..644f72a 100644
--- a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpReceiver.java
+++ b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpReceiver.java
@@ -19,8 +19,7 @@
 
 import org.apache.qpid.proton.hawtdispatch.impl.Defer;
 import org.apache.qpid.proton.engine.Delivery;
-import org.apache.qpid.proton.engine.impl.DeliveryImpl;
-import org.apache.qpid.proton.engine.impl.ReceiverImpl;
+import org.apache.qpid.proton.engine.Receiver;
 import org.apache.qpid.proton.amqp.messaging.Accepted;
 import org.fusesource.hawtbuf.Buffer;
 import org.fusesource.hawtbuf.ByteArrayOutputStream;
@@ -33,16 +32,16 @@
 public class AmqpReceiver extends AmqpLink {
 
     final AmqpSession parent;
-    final ReceiverImpl receiver;
+    final Receiver receiver;
 
-    public AmqpReceiver(AmqpSession parent, ReceiverImpl receiver, QoS qos) {
+    public AmqpReceiver(AmqpSession parent, Receiver receiver2, QoS qos) {
         this.parent = parent;
-        this.receiver = receiver;
+        this.receiver = receiver2;
         attach();
     }
 
     @Override
-    protected ReceiverImpl getEndpoint() {
+    protected Receiver getEndpoint() {
         return receiver;
     }
     @Override
@@ -99,7 +98,7 @@
                 drain();
             }
         };
-        md.delivery = (DeliveryImpl) delivery;
+        md.delivery = delivery;
         delivery.setContext(md);
         inbound.add(md);
         drainInbound();
diff --git a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java
index 9c17017..9a672d5 100644
--- a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java
+++ b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSender.java
@@ -20,15 +20,13 @@
 import org.apache.qpid.proton.hawtdispatch.impl.Defer;
 import org.apache.qpid.proton.hawtdispatch.impl.Watch;
 import org.apache.qpid.proton.engine.Delivery;
-import org.apache.qpid.proton.engine.impl.DeliveryImpl;
-import org.apache.qpid.proton.engine.impl.SenderImpl;
+import org.apache.qpid.proton.engine.Sender;
 import org.apache.qpid.proton.message.Message;
 import org.apache.qpid.proton.amqp.messaging.Accepted;
 import org.apache.qpid.proton.amqp.messaging.Modified;
 import org.apache.qpid.proton.amqp.messaging.Rejected;
 import org.apache.qpid.proton.amqp.messaging.Released;
 import org.apache.qpid.proton.amqp.transport.DeliveryState;
-import org.apache.qpid.proton.message.impl.MessageImpl;
 import org.fusesource.hawtbuf.Buffer;
 
 import java.io.UnsupportedEncodingException;
@@ -47,11 +45,11 @@
 
     final AmqpSession parent;
     private final QoS qos;
-    final SenderImpl sender;
+    final Sender sender;
 
-    public AmqpSender(AmqpSession parent, SenderImpl sender, QoS qos) {
+    public AmqpSender(AmqpSession parent, Sender sender2, QoS qos) {
         this.parent = parent;
-        this.sender = sender;
+        this.sender = sender2;
         this.qos = qos;
         attach();
         getConnection().senders.add(this);
@@ -64,7 +62,7 @@
     }
 
     @Override
-    protected SenderImpl getEndpoint() {
+    protected Sender getEndpoint() {
         return sender;
     }
 
@@ -100,7 +98,7 @@
     }
 
     Buffer currentBuffer;
-    DeliveryImpl currentDelivery;
+    Delivery currentDelivery;
 
     Defer deferedPumpDeliveries = new Defer() {
         public void run() {
@@ -121,7 +119,7 @@
                         int sent = sender.send(currentBuffer.data, currentBuffer.offset, currentBuffer.length);
                         currentBuffer.moveHead(sent);
                         if( currentBuffer.length == 0 ) {
-                            DeliveryImpl current = currentDelivery;
+                            Delivery current = currentDelivery;
                             MessageDelivery md = (MessageDelivery) current.getContext();
                             currentBuffer = null;
                             currentDelivery = null;
diff --git a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSession.java b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSession.java
index 863e14f..3bf0ce6 100644
--- a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSession.java
+++ b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/AmqpSession.java
@@ -21,27 +21,28 @@
 import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
 import org.apache.qpid.proton.engine.Endpoint;
 import org.apache.qpid.proton.engine.Link;
-import org.apache.qpid.proton.engine.impl.ReceiverImpl;
-import org.apache.qpid.proton.engine.impl.SenderImpl;
-import org.apache.qpid.proton.engine.impl.SessionImpl;
+import org.apache.qpid.proton.engine.ProtonJSession;
+import org.apache.qpid.proton.engine.Receiver;
+import org.apache.qpid.proton.engine.Sender;
 import org.apache.qpid.proton.message.Message;
+import org.apache.qpid.proton.message.impl.MessageFactoryImpl;
 import org.apache.qpid.proton.amqp.Binary;
 import org.apache.qpid.proton.amqp.messaging.*;
 import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
 
 import java.util.UUID;
-import org.apache.qpid.proton.message.impl.MessageImpl;
 
 /**
  * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
  */
 public class AmqpSession extends AmqpEndpointBase {
 
+    private final MessageFactoryImpl messageFactory = new MessageFactoryImpl();
     final AmqpConnection parent;
-    final SessionImpl session;
+    final ProtonJSession session;
 
 
-    public AmqpSession(AmqpConnection parent, SessionImpl session) {
+    public AmqpSession(AmqpConnection parent, ProtonJSession session) {
         this.parent = parent;
         this.session = session;
         attach();
@@ -67,7 +68,7 @@
 
     public AmqpSender createSender(Target target, QoS qos, String name) {
         assertExecuting();
-        SenderImpl sender = session.sender(name);
+        Sender sender = session.sender(name);
         attach();
 //        Source source = new Source();
 //        source.setAddress(UUID.randomUUID().toString());
@@ -93,7 +94,7 @@
 
     public AmqpReceiver createReceiver(Source source, QoS qos, int prefetch, String name) {
         assertExecuting();
-        ReceiverImpl receiver = session.receiver(name);
+        Receiver receiver = session.receiver(name);
         receiver.setSource(source);
 //        Target target = new Target();
 //        target.setAddress(UUID.randomUUID().toString());
@@ -123,7 +124,7 @@
     }
 
     public Message createTextMessage(String value) {
-        Message msg = new MessageImpl();
+        Message msg = messageFactory.createMessage();
         Section body = new AmqpValue(value);
         msg.setBody(body);
         return msg;
@@ -134,7 +135,7 @@
     }
 
     public Message createBinaryMessage(byte value[], int offset, int len) {
-        Message msg = new MessageImpl();
+        Message msg = messageFactory.createMessage();
         Data body = new Data(new Binary(value, offset,len));
         msg.setBody(body);
         return msg;
diff --git a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java
index bd73022..e3a9f67 100644
--- a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java
+++ b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/api/MessageDelivery.java
@@ -18,11 +18,12 @@
 package org.apache.qpid.proton.hawtdispatch.api;
 
 import org.apache.qpid.proton.amqp.transport.DeliveryState;
-import org.apache.qpid.proton.engine.impl.DeliveryImpl;
+import org.apache.qpid.proton.engine.Delivery;
 import org.apache.qpid.proton.hawtdispatch.impl.Watch;
 import org.apache.qpid.proton.hawtdispatch.impl.WatchBase;
 import org.apache.qpid.proton.message.Message;
-import org.apache.qpid.proton.message.impl.MessageImpl;
+import org.apache.qpid.proton.message.ProtonJMessage;
+import org.apache.qpid.proton.message.impl.MessageFactoryImpl;
 import org.fusesource.hawtbuf.Buffer;
 import org.fusesource.hawtdispatch.Task;
 
@@ -31,15 +32,16 @@
  */
 public abstract class MessageDelivery extends WatchBase {
 
+    private static final  MessageFactoryImpl MESSAGE_FACTORY = new MessageFactoryImpl();
     final int initialSize;
     private Message message;
     private Buffer encoded;
-    public DeliveryImpl delivery;
+    public Delivery delivery;
     private int sizeHint = 1024*4;
 
     static Buffer encode(Message message, int sizeHint) {
         byte[] buffer = new byte[sizeHint];
-        int size = ((MessageImpl)message).encode2(buffer, 0, sizeHint);
+        int size = ((ProtonJMessage)message).encode2(buffer, 0, sizeHint);
         if( size > sizeHint ) {
             buffer = new byte[size];
             size = message.encode(buffer, 0, size);
@@ -48,7 +50,7 @@
     }
 
     static Message decode(Buffer buffer) {
-        Message msg = new MessageImpl();
+        Message msg = MESSAGE_FACTORY.createMessage();
         int offset = buffer.offset;
         int len = buffer.length;
         while( len > 0 ) {
diff --git a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpListener.java b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpListener.java
index 286a47d..88579a9 100644
--- a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpListener.java
+++ b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpListener.java
@@ -18,18 +18,17 @@
 package org.apache.qpid.proton.hawtdispatch.impl;
 
 import org.apache.qpid.proton.engine.*;
-import org.apache.qpid.proton.engine.impl.EndpointImpl;
-import org.apache.qpid.proton.engine.impl.TransportImpl;
 import org.fusesource.hawtdispatch.Task;
 
 import java.io.IOException;
 
+
 /**
 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
 */
 public class AmqpListener {
 
-    public Sasl processSaslConnect(TransportImpl transport) {
+    public Sasl processSaslConnect(ProtonJTransport protonTransport) {
         return null;
     }
 
@@ -38,7 +37,7 @@
     }
 
     public void processRemoteOpen(Endpoint endpoint, Task onComplete) {
-        ((EndpointImpl)endpoint).setLocalError(new EndpointError("error", "Not supported"));
+        ((ProtonJEndpoint)endpoint).setLocalError(new EndpointError("error", "Not supported"));
         endpoint.close();
         onComplete.run();
     }
diff --git a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpTransport.java b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpTransport.java
index 8b5383a..2898be2 100644
--- a/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpTransport.java
+++ b/proton-j/contrib/proton-hawtdispatch/src/main/java/org/apache/qpid/proton/hawtdispatch/impl/AmqpTransport.java
@@ -21,9 +21,8 @@
 import org.apache.qpid.proton.hawtdispatch.api.ChainedCallback;
 import org.apache.qpid.proton.hawtdispatch.api.TransportState;
 import org.apache.qpid.proton.engine.*;
-import org.apache.qpid.proton.engine.impl.ConnectionImpl;
+import org.apache.qpid.proton.engine.impl.EngineFactoryImpl;
 import org.apache.qpid.proton.engine.impl.ProtocolTracer;
-import org.apache.qpid.proton.engine.impl.TransportImpl;
 import org.fusesource.hawtbuf.Buffer;
 import org.fusesource.hawtbuf.DataByteArrayOutputStream;
 import org.fusesource.hawtbuf.UTF8Buffer;
@@ -51,9 +50,10 @@
     private TransportState state = CREATED;
 
     final DispatchQueue queue;
-    final ConnectionImpl connection = new ConnectionImpl();
+    final ProtonJConnection connection;
+    private final EngineFactoryImpl engineFactory = new EngineFactoryImpl();
     Transport hawtdispatchTransport;
-    TransportImpl protonTransport;
+    ProtonJTransport protonTransport;
     Throwable failure;
     CustomDispatchSource<Defer,LinkedList<Defer>> defers;
 
@@ -61,6 +61,8 @@
 
     private AmqpTransport(DispatchQueue queue) {
         this.queue = queue;
+        this.connection = engineFactory.createConnection();
+
         defers = Dispatch.createSource(EventAggregators.<Defer>linkedList(), this.queue);
         defers.setEventHandler(new Task(){
             public void run() {
@@ -315,7 +317,7 @@
 
     private void bind(final Transport transport) {
         this.hawtdispatchTransport = transport;
-        this.protonTransport = new TransportImpl();
+        this.protonTransport = engineFactory.createTransport();
         this.protonTransport.bind(connection);
         if( transport.getProtocolCodec()==null ) {
             try {
@@ -411,7 +413,7 @@
     }
 
 
-    public ConnectionImpl connection() {
+    public ProtonJConnection connection() {
         return connection;
     }
 
diff --git a/proton-j/contrib/proton-jms/pom.xml b/proton-j/contrib/proton-jms/pom.xml
index 64c236f..7cf43ea 100644
--- a/proton-j/contrib/proton-jms/pom.xml
+++ b/proton-j/contrib/proton-jms/pom.xml
@@ -18,21 +18,19 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <parent>
     <groupId>org.apache.qpid</groupId>
-    <artifactId>proton-project</artifactId>
+    <artifactId>proton-j</artifactId>
     <version>1.0-SNAPSHOT</version>
     <relativePath>../..</relativePath>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
-  <groupId>org.apache.qpid</groupId>
   <artifactId>proton-jms</artifactId>
-  <version>1.0-SNAPSHOT</version>
 
   <dependencies>
     <dependency>
       <groupId>org.apache.qpid</groupId>
-      <artifactId>proton</artifactId>
-      <version>1.0-SNAPSHOT</version>
+      <artifactId>proton-j-impl</artifactId>
+      <version>${project.parent.version}</version>
     </dependency>
     <dependency>
       <groupId>org.apache.geronimo.specs</groupId>
diff --git a/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java b/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java
index 6af11a8..63537fe 100644
--- a/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java
+++ b/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/AMQPNativeOutboundTransformer.java
@@ -26,13 +26,16 @@
 import javax.jms.Message;
 import javax.jms.MessageFormatException;
 import java.nio.ByteBuffer;
-import org.apache.qpid.proton.message.impl.MessageImpl;
 
+import org.apache.qpid.proton.message.ProtonJMessage;
+import org.apache.qpid.proton.message.impl.MessageFactoryImpl;
 /**
 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
 */
 public class AMQPNativeOutboundTransformer extends OutboundTransformer {
 
+    private static final MessageFactoryImpl MESSAGE_FACTORY = new MessageFactoryImpl();
+
     public AMQPNativeOutboundTransformer(JMSVendor vendor) {
         super(vendor);
     }
@@ -70,7 +73,7 @@
             if( count > 1 ) {
 
                 // decode...
-                MessageImpl amqp = new MessageImpl();
+                ProtonJMessage amqp = MESSAGE_FACTORY.createMessage();
                 int offset = 0;
                 int len = data.length;
                 while( len > 0 ) {
diff --git a/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/EncodedMessage.java b/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/EncodedMessage.java
index 0508f43..485b975 100644
--- a/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/EncodedMessage.java
+++ b/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/EncodedMessage.java
@@ -18,13 +18,14 @@
 
 import org.apache.qpid.proton.message.Message;
 import org.apache.qpid.proton.amqp.Binary;
-import org.apache.qpid.proton.message.impl.MessageImpl;
+import org.apache.qpid.proton.message.impl.MessageFactoryImpl;
 
 /**
  * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
  */
 public class EncodedMessage
 {
+    private final MessageFactoryImpl messageFactory = new MessageFactoryImpl();
 
     private final Binary data;
     final long messageFormat;
@@ -39,7 +40,7 @@
     }
 
     public Message decode() throws Exception {
-        Message amqp = new MessageImpl();
+        Message amqp = messageFactory.createMessage();
 
         int offset = getArrayOffset();
         int len = getLength();
diff --git a/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java b/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java
index 17724c2..1bb7aca 100644
--- a/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java
+++ b/proton-j/contrib/proton-jms/src/main/java/org/apache/qpid/proton/jms/JMSMappingOutboundTransformer.java
@@ -20,6 +20,8 @@
 import org.apache.qpid.proton.codec.CompositeWritableBuffer;
 import org.apache.qpid.proton.codec.WritableBuffer;
 import org.apache.qpid.proton.codec.DroppingWritableBuffer;
+import org.apache.qpid.proton.message.ProtonJMessage;
+import org.apache.qpid.proton.message.impl.MessageFactoryImpl;
 import org.apache.qpid.proton.amqp.Binary;
 import org.apache.qpid.proton.amqp.Symbol;
 import org.apache.qpid.proton.amqp.UnsignedByte;
@@ -33,13 +35,14 @@
 import java.util.Date;
 import java.util.Enumeration;
 import java.util.HashMap;
-import org.apache.qpid.proton.message.impl.MessageImpl;
 
 /**
 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
 */
 public class JMSMappingOutboundTransformer extends OutboundTransformer {
 
+    private static final MessageFactoryImpl MESSAGE_FACTORY = new MessageFactoryImpl();
+
     String prefixDeliveryAnnotations = "DA_";
     String prefixMessageAnnotations= "MA_";
     String prefixFooter = "FT_";
@@ -209,7 +212,7 @@
         Footer footer=null;
         if( footerMap!=null ) footer = new Footer(footerMap);
 
-        MessageImpl amqp = new MessageImpl(header, da, ma, props, ap, body, footer);
+        ProtonJMessage amqp = MESSAGE_FACTORY.createMessage(header, da, ma, props, ap, body, footer);
 
         ByteBuffer buffer = ByteBuffer.wrap(new byte[1024*4]);
         final DroppingWritableBuffer overflow = new DroppingWritableBuffer();
diff --git a/proton-j/pom.xml b/proton-j/pom.xml
index 5654f82..8bde900 100644
--- a/proton-j/pom.xml
+++ b/proton-j/pom.xml
@@ -17,25 +17,15 @@
 -->
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <parent>
-    <groupId>org.apache</groupId>
-    <artifactId>apache</artifactId>
-    <version>12</version>
+    <groupId>org.apache.qpid</groupId>
+    <artifactId>proton-project</artifactId>
+    <version>1.0-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
-  <groupId>org.apache.qpid</groupId>
-  <artifactId>proton-project</artifactId>
-  <version>1.0-SNAPSHOT</version>
+  <artifactId>proton-j</artifactId>
   <packaging>pom</packaging>
 
-  <properties>
-    <junit-version>4.10</junit-version>
-  </properties>
-
-  <prerequisites>
-    <maven>3.0</maven>
-  </prerequisites>
-
   <dependencies>
     <dependency>
       <groupId>junit</groupId>
@@ -45,23 +35,6 @@
     </dependency>
   </dependencies>
 
-  <build>    
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-compiler-plugin</artifactId>
-        <configuration>
-          <source>1.6</source>
-          <target>1.6</target>
-          <optimize>true</optimize>
-          <debug>true</debug>
-          <showDeprecation>true</showDeprecation>
-          <showWarnings>true</showWarnings>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-  
   <modules>
     <module>proton-api</module>
     <module>proton</module>
diff --git a/tests/jproton-test b/proton-j/proton-api/CMakeLists.txt
old mode 100755
new mode 100644
similarity index 79%
rename from tests/jproton-test
rename to proton-j/proton-api/CMakeLists.txt
index e26394a..bb975b2
--- a/tests/jproton-test
+++ b/proton-j/proton-api/CMakeLists.txt
@@ -1,4 +1,3 @@
-#!/bin/bash
 #
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
@@ -7,9 +6,9 @@
 # to you 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
@@ -18,5 +17,9 @@
 # under the License.
 #
 
-TEST_HOME=$(dirname $(readlink -f ${BASH_SOURCE[0]}))
-exec jython ${TEST_HOME}/proton-test "$@"
+set(CMAKE_JAVA_TARGET_VERSION ${PN_VERSION})
+
+file(GLOB_RECURSE SOURCES_ABS "src/main/java/*.java")
+
+add_jar(proton-api ${SOURCES_ABS})
+rebuild_jar(proton-api proton-api-${PN_VERSION}.jar)
\ No newline at end of file
diff --git a/proton-j/proton-api/pom.xml b/proton-j/proton-api/pom.xml
index 16224a3..4f8432c 100644
--- a/proton-j/proton-api/pom.xml
+++ b/proton-j/proton-api/pom.xml
@@ -18,17 +18,11 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <parent>
     <groupId>org.apache.qpid</groupId>
-    <artifactId>proton-project</artifactId>
+    <artifactId>proton-j</artifactId>
     <version>1.0-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
-  <groupId>org.apache.qpid</groupId>
   <artifactId>proton-api</artifactId>
-  <version>1.0-SNAPSHOT</version>
-
-  <build>
-  </build>
-
 
 </project>
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/ProtonException.java
similarity index 96%
rename from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
rename to proton-j/proton-api/src/main/java/org/apache/qpid/proton/ProtonException.java
index fd9b0c2..14f5e6e 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/ProtonException.java
@@ -19,7 +19,7 @@
  *
  */
 
-package org.apache.qpid.proton.engine;
+package org.apache.qpid.proton;
 
 public class ProtonException extends RuntimeException
 {
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/ProtonFactoryLoader.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/ProtonFactoryLoader.java
new file mode 100644
index 0000000..9b305e8
--- /dev/null
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/ProtonFactoryLoader.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A thin wrapper around {@link ServiceLoader} intended for loading Proton object factories.
+ */
+public class ProtonFactoryLoader<C>
+{
+    private static final Logger LOGGER = Logger.getLogger(ProtonFactoryLoader.class.getName());
+    private Class<C> _factoryInterface;
+
+    /**
+     * Use this constructor if you intend to explicitly provide factory interface later,
+     * i.e. by calling {@link #loadFactory(Class)}. This is useful if you want to use the same
+     * ProtonFactoryLoader instance for loading multiple factory types.
+     */
+    public ProtonFactoryLoader()
+    {
+    }
+
+    /**
+     * @param factoryInterface will be used as the factory interface class in calls to {@link #loadFactory()}.
+     */
+    public ProtonFactoryLoader(Class<C> factoryInterface)
+    {
+        _factoryInterface = factoryInterface;
+    }
+
+    /**
+     * Returns the Proton factory that implements the stored {@link ProtonFactoryLoader#_factoryInterface} class.
+     */
+    public C loadFactory()
+    {
+        return loadFactory(_factoryInterface);
+    }
+
+    public C loadFactory(Class<C> factoryInterface)
+    {
+        if(factoryInterface == null)
+        {
+            throw new IllegalStateException("factoryInterface has not been set.");
+        }
+        ServiceLoader<C> serviceLoader = ServiceLoader.load(factoryInterface);
+        Iterator<C> serviceLoaderIterator = serviceLoader.iterator();
+        if(!serviceLoaderIterator.hasNext())
+        {
+            throw new IllegalStateException("Can't find service loader for " + factoryInterface.getName());
+        }
+        C factory = serviceLoaderIterator.next();
+        if(LOGGER.isLoggable(Level.FINE))
+        {
+            LOGGER.fine("loadFactory returning " + factory);
+        }
+        return factory;
+    }
+
+}
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/ProtonUnsupportedOperationException.java
similarity index 64%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton-api/src/main/java/org/apache/qpid/proton/ProtonUnsupportedOperationException.java
index fd9b0c2..3fc7c48 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/ProtonUnsupportedOperationException.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,26 +17,29 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton;
 
-package org.apache.qpid.proton.engine;
-
-public class ProtonException extends RuntimeException
+/**
+ * Use to indicate that a feature of the Proton API is not supported by a particular implementation
+ * (e.g. proton-j or proton-c-via-JNI).
+ */
+public class ProtonUnsupportedOperationException extends UnsupportedOperationException
 {
-    public ProtonException()
+    public ProtonUnsupportedOperationException()
     {
     }
 
-    public ProtonException(String message)
+    public ProtonUnsupportedOperationException(String message)
     {
         super(message);
     }
 
-    public ProtonException(String message, Throwable cause)
+    public ProtonUnsupportedOperationException(String message, Throwable cause)
     {
         super(message, cause);
     }
 
-    public ProtonException(Throwable cause)
+    public ProtonUnsupportedOperationException(Throwable cause)
     {
         super(cause);
     }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/driver/DriverFactory.java
similarity index 66%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton-api/src/main/java/org/apache/qpid/proton/driver/DriverFactory.java
index fd9b0c2..6dc3a50 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/driver/DriverFactory.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,11 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.driver;
 
-package org.apache.qpid.proton.engine;
+import java.io.IOException;
 
-public class ProtonException extends RuntimeException
+public interface DriverFactory
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
+    Driver createDriver() throws IOException;
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/EngineFactory.java
similarity index 69%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/EngineFactory.java
index fd9b0c2..45608fd 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/EngineFactory.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,30 +15,13 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
  */
-
 package org.apache.qpid.proton.engine;
 
-public class ProtonException extends RuntimeException
+public interface EngineFactory
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
+    Connection createConnection();
+    Transport createTransport();
+    SslDomain createSslDomain();
+    SslPeerDetails createSslPeerDetails(String hostname, int port);
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Sender.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Sender.java
index 0037400..60f209f 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Sender.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Sender.java
@@ -48,9 +48,9 @@
     /**
      * Abort the current delivery.
      *
+     * Note "pn_link_abort" is commented out in the .h
      */
     public void abort();
 
-
     public void drained();
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Ssl.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Ssl.java
index 3e23d18..8d3bab7 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Ssl.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Ssl.java
@@ -44,4 +44,8 @@
      * @return the name of the protocol in use, or null if none
      */
     String getProtocolName();
+
+    void setPeerHostname(String hostname);
+
+    String getPeerHostname();
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/SslDomain.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/SslDomain.java
index b1a7c4f..937d650 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/SslDomain.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/SslDomain.java
@@ -47,7 +47,7 @@
          * by a trusted CA and are using an authenticated cipher
          */
         VERIFY_PEER,
-
+        VERIFY_PEER_NAME,
         /**
          * does not require a valid certificate, and permits use of ciphers that
          * do not provide authentication
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Transport.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Transport.java
index 4af1426..62a9913 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Transport.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/Transport.java
@@ -29,6 +29,7 @@
 public interface Transport extends Endpoint
 {
 
+    public int SESSION_WINDOW = 1024;
     public int END_OF_STREAM = -1;
 
     public void bind(Connection connection);
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/TransportException.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/TransportException.java
index 9bfb855..c1c9d74 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/TransportException.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/TransportException.java
@@ -21,6 +21,8 @@
 
 package org.apache.qpid.proton.engine;
 
+import org.apache.qpid.proton.ProtonException;
+
 public class TransportException extends ProtonException
 {
     public TransportException()
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/message/Message.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/message/Message.java
index 1ca5d7a..bfbb03a 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/message/Message.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/message/Message.java
@@ -30,6 +30,8 @@
 
 public interface Message
 {
+    short DEFAULT_PRIORITY = 4;
+
     boolean isDurable();
 
     long getDeliveryCount();
@@ -56,6 +58,7 @@
 
     String getReplyToGroupId();
 
+
     long getCreationTime();
 
     String getAddress();
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/message/MessageFactory.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/message/MessageFactory.java
new file mode 100644
index 0000000..6bc9135
--- /dev/null
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/message/MessageFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.message;
+
+import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
+import org.apache.qpid.proton.amqp.messaging.DeliveryAnnotations;
+import org.apache.qpid.proton.amqp.messaging.Footer;
+import org.apache.qpid.proton.amqp.messaging.Header;
+import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
+import org.apache.qpid.proton.amqp.messaging.Properties;
+import org.apache.qpid.proton.amqp.messaging.Section;
+
+public interface MessageFactory
+{
+    Message createMessage();
+    Message createMessage(Header header,
+                          DeliveryAnnotations deliveryAnnotations, MessageAnnotations messageAnnotations,
+                          Properties properties, ApplicationProperties applicationProperties,
+                          Section body, Footer footer);
+}
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/messenger/Messenger.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
index 77b60f6..f7348b0 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/messenger/Messenger.java
@@ -22,6 +22,7 @@
 
 import java.io.IOException;
 import java.util.concurrent.TimeoutException;
+
 import org.apache.qpid.proton.message.Message;
 
 /**
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/messenger/MessengerFactory.java
similarity index 66%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton-api/src/main/java/org/apache/qpid/proton/messenger/MessengerFactory.java
index fd9b0c2..bd09b34 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton-api/src/main/java/org/apache/qpid/proton/messenger/MessengerFactory.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,10 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.messenger;
 
-package org.apache.qpid.proton.engine;
-
-public class ProtonException extends RuntimeException
+public interface MessengerFactory
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
+    Messenger createMessenger();
+    Messenger createMessenger(String name);
 }
diff --git a/proton-j/proton/src/main/scripts/proton.py b/proton-j/proton-api/src/main/resources/proton.py
similarity index 89%
rename from proton-j/proton/src/main/scripts/proton.py
rename to proton-j/proton-api/src/main/resources/proton.py
index 40be4a0..71987fa 100644
--- a/proton-j/proton/src/main/scripts/proton.py
+++ b/proton-j/proton-api/src/main/resources/proton.py
@@ -18,14 +18,14 @@
 
 from uuid import UUID
 
-from org.apache.qpid.proton.engine import EndpointState, TransportException, Sasl, SslDomain
-from org.apache.qpid.proton.engine.impl import ConnectionImpl, SessionImpl, \
-    SenderImpl, ReceiverImpl, TransportImpl
-from org.apache.qpid.proton.engine.impl.ssl import SslDomainImpl, SslPeerDetailsImpl
-from org.apache.qpid.proton.message import MessageFormat
-from org.apache.qpid.proton.message.impl import MessageImpl
-from org.apache.qpid.proton.messenger import MessengerException, Status
-from org.apache.qpid.proton.messenger.impl import MessengerImpl
+from org.apache.qpid.proton import ProtonFactoryLoader, ProtonUnsupportedOperationException
+from org.apache.qpid.proton.engine import \
+    EngineFactory, Transport as JTransport, Sender as JSender, Receiver as JReceiver, \
+    Sasl, SslDomain as JSslDomain, \
+    EndpointState, TransportException
+from org.apache.qpid.proton.message import \
+    MessageFormat, MessageFactory, Message as JMessage
+from org.apache.qpid.proton.messenger import MessengerFactory, MessengerException, Status
 from org.apache.qpid.proton.amqp.messaging import Source, Target, Accepted, AmqpValue
 from org.apache.qpid.proton.amqp import UnsignedInteger
 from jarray import zeros
@@ -37,7 +37,7 @@
 class Skipped(Exception):
   skipped = True
 
-PN_SESSION_WINDOW = TransportImpl.SESSION_WINDOW
+PN_SESSION_WINDOW = JTransport.SESSION_WINDOW
 
 PENDING = "PENDING"
 ACCEPTED = "ACCEPTED"
@@ -53,6 +53,12 @@
 MANUAL = "MANUAL"
 AUTOMATIC = "AUTOMATIC"
 
+protonFactoryLoader = ProtonFactoryLoader()
+engineFactory = protonFactoryLoader.loadFactory(EngineFactory)
+messageFactory = protonFactoryLoader.loadFactory(MessageFactory)
+messengerFactory = protonFactoryLoader.loadFactory(MessengerFactory)
+
+
 class Endpoint(object):
 
   LOCAL_UNINIT = 1
@@ -142,7 +148,7 @@
 class Connection(Endpoint):
 
   def __init__(self, _impl=None):
-    self.impl = _impl or ConnectionImpl()
+    self.impl = _impl or engineFactory.createConnection()
 
   @property
   def writable(self):
@@ -213,9 +219,9 @@
 
 def wrap_link(impl):
   if impl is None: return None
-  elif isinstance(impl, SenderImpl):
+  elif isinstance(impl, JSender):
     return Sender(impl)
-  elif isinstance(impl, ReceiverImpl):
+  elif isinstance(impl, JReceiver):
     return Receiver(impl)
   else:
     raise Exception("unknown type")
@@ -342,7 +348,7 @@
     n = self.impl.recv(output, 0, size)
     if n >= 0:
       return output.tostring()[:n]
-    elif n == TransportImpl.END_OF_STREAM:
+    elif n == JTransport.END_OF_STREAM:
       return None
     else:
       raise Exception(n)
@@ -418,7 +424,7 @@
   TRACE_DRV = 4
 
   def __init__(self):
-    self.impl = TransportImpl()
+    self.impl = engineFactory.createTransport()
 
   def trace(self, mask):
     # XXX: self.impl.trace(mask)
@@ -434,13 +440,19 @@
     n = self.impl.output(output, 0, size)
     if n >= 0:
       return output.tostring()[:n]
-    elif n == TransportImpl.END_OF_STREAM:
+    elif n == JTransport.END_OF_STREAM:
       return None
     else:
-      raise Exception("XXX: %s" % n)
+      raise Exception("Unexpected return value from output: %s" % n)
 
   def input(self, bytes):
-    return self.impl.input(bytes, 0, len(bytes))
+    n = self.impl.input(bytes, 0, len(bytes))
+    if n >= 0:
+      return n
+    elif n == JTransport.END_OF_STREAM:
+      return None
+    else:
+      raise Exception("Unexpected return value from input: %s" % n)
 
   def _get_max_frame_size(self):
     #return pn_transport_get_max_frame(self._trans)
@@ -504,7 +516,11 @@
 class Messenger(object):
 
   def __init__(self, *args, **kwargs):
-    self.impl = MessengerImpl()
+    try:
+      self.impl = messengerFactory.createMessenger()
+    except ProtonUnsupportedOperationException:
+      raise Skipped()
+
 
   def start(self):
     self.impl.start()
@@ -592,10 +608,10 @@
   DATA = MessageFormat.DATA
   JSON = MessageFormat.JSON
 
-  DEFAULT_PRIORITY = MessageImpl.DEFAULT_PRIORITY
+  DEFAULT_PRIORITY = JMessage.DEFAULT_PRIORITY
 
   def __init__(self):
-    self.impl = MessageImpl()
+    self.impl = messageFactory.createMessage()
 
   def clear(self):
     self.impl.clear()
@@ -788,7 +804,7 @@
     n = self._sasl.recv(output, 0, size)
     if n >= 0:
       return output.tostring()[:n]
-    elif n == TransportImpl.END_OF_STREAM:
+    elif n == JTransport.END_OF_STREAM:
       return None
     else:
       raise Exception(n)
@@ -818,14 +834,14 @@
 
 class SSLDomain(object):
 
-  MODE_SERVER = SslDomain.Mode.SERVER
-  MODE_CLIENT = SslDomain.Mode.CLIENT
-  VERIFY_PEER = SslDomain.VerifyMode.VERIFY_PEER
-  ANONYMOUS_PEER = SslDomain.VerifyMode.ANONYMOUS_PEER
-  VERIFY_PEER_NAME = None  # TBD
+  MODE_SERVER = JSslDomain.Mode.SERVER
+  MODE_CLIENT = JSslDomain.Mode.CLIENT
+  VERIFY_PEER = JSslDomain.VerifyMode.VERIFY_PEER
+  VERIFY_PEER_NAME = JSslDomain.VerifyMode.VERIFY_PEER_NAME
+  ANONYMOUS_PEER = JSslDomain.VerifyMode.ANONYMOUS_PEER
 
   def __init__(self, mode):
-    self._domain = SslDomainImpl()
+    self._domain = engineFactory.createSslDomain()
     self._domain.init(mode)
 
   def set_credentials(self, cert_file, key_file, password):
@@ -835,9 +851,14 @@
     self._domain.setTrustedCaDb(certificate_db)
 
   def set_peer_authentication(self, verify_mode, trusted_CAs=None):
-    self._domain.setPeerAuthentication(verify_mode)
+    # TODO the method calls (setTrustedCaDb/setPeerAuthentication) have to occur in
+    # that order otherwise tests fail with proton-jni.  It is not clear yet why.
     if trusted_CAs is not None:
       self._domain.setTrustedCaDb(trusted_CAs)
+    try:
+      self._domain.setPeerAuthentication(verify_mode)
+    except ProtonUnsupportedOperationException:
+      raise Skipped()
 
   def allow_unsecured_client(self, allow_unsecured = True):
     self._domain.allowUnsecuredClient(allow_unsecured)
@@ -845,7 +866,7 @@
 class SSLSessionDetails(object):
 
   def __init__(self, session_id):
-    self._session_details = SslPeerDetailsImpl(session_id, 1)
+    self._session_details = engineFactory.createSslPeerDetails(session_id, 1)
 
 class SSL(object):
 
@@ -868,9 +889,17 @@
     return self._ssl.getProtocolName()
 
   def _set_peer_hostname(self, hostname):
-    raise Skipped()
+    try:
+      self._ssl.setPeerHostname(hostname)
+    except ProtonUnsupportedOperationException:
+      raise Skipped()
+
   def _get_peer_hostname(self):
-    raise Skipped()
+    try:
+      return self._ssl.getPeerHostname()
+    except ProtonUnsupportedOperationException:
+      raise Skipped()
+
   peer_hostname = property(_get_peer_hostname, _set_peer_hostname)
 
 
diff --git a/proton-j/proton/CMakeLists.txt b/proton-j/proton/CMakeLists.txt
new file mode 100644
index 0000000..0d6eb4b
--- /dev/null
+++ b/proton-j/proton/CMakeLists.txt
@@ -0,0 +1,60 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you 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.
+#
+
+set(BOUNCYCASTLE_VERSION 1.47 CACHE STRING "Version of Bouncycastle to compile proton-j-impl against")
+
+find_jar(BOUNCYCASTLE_BCPKIX_JAR
+         NAMES bcpkix-jdk15on
+         PATHS ${PROTON_JAR_DEPEND_DIR}
+         VERSIONS ${BOUNCYCASTLE_VERSION}
+         DOC "Full path to Bouncycastle PKIX jar")
+find_jar(BOUNCYCASTLE_BCPROV_JAR
+         NAMES bcprov-jdk15on
+         PATHS ${PROTON_JAR_DEPEND_DIR}
+         VERSIONS ${BOUNCYCASTLE_VERSION}
+         DOC "Full path to Bouncycastle Provider jar")
+
+if (${BOUNCYCASTLE_BCPKIX_JAR} MATCHES "^.*-NOTFOUND$" OR ${BOUNCYCASTLE_BCPROV_JAR} MATCHES "^.*-NOTFOUND$")
+  set(BOUNCYCASTLE_FOUND FALSE)
+else()
+  set(BOUNCYCASTLE_FOUND TRUE)
+endif()
+
+message("Locations of Bouncycastle ${BOUNCYCASTLE_VERSION} jars: "
+        "${BOUNCYCASTLE_BCPROV_JAR} ${BOUNCYCASTLE_BCPKIX_JAR}")
+
+if (BOUNCYCASTLE_FOUND)
+  message("Will build proton-j-impl")
+  set(CMAKE_JAVA_TARGET_VERSION ${PN_VERSION})
+
+  file(GLOB_RECURSE SOURCES_ABS "src/main/java/*.java")
+
+  set(CMAKE_JAVA_INCLUDE_PATH
+        ${PROTON_API_TARGET_JAR}
+        ${BOUNCYCASTLE_BCPROV_JAR}
+        ${BOUNCYCASTLE_BCPKIX_JAR})
+
+  add_jar(proton-j-impl ${SOURCES_ABS})
+
+  rebuild_jar(proton-j-impl proton-j-impl-${PN_VERSION}.jar)
+
+  add_dependencies(proton-j-impl proton-api)
+else()
+    message("Won't build proton-j-impl because one or more Bouncycastle jars were not found. PROTON_JAR_DEPEND_DIR was: ${PROTON_JAR_DEPEND_DIR}")
+endif()
\ No newline at end of file
diff --git a/proton-j/proton/README b/proton-j/proton/README
deleted file mode 100644
index a101ae7..0000000
--- a/proton-j/proton/README
+++ /dev/null
@@ -1,45 +0,0 @@
-Proton is library for speaking AMQP, including:
-
-  + The AMQP Messenger API, a simple but powerful interface to send
-    and receive messages over AMQP.
-
-  + The AMQP Protocol Engine, a succinct encapsulation of the full
-    AMQP protocol machinery.
-
-Proton is designed for maximum embeddability:
-
-  + minimal dependencies
-
-  + minimal assumptions about application threading model
-
-Proton is designed to scale up and down:
-
-  + transparently supports both simple peer to peer messaging and
-    complex globally federated topologies
-
-Proton is multi-lingual:
-
-  + designed for easy language bindings
-     - includes full fidelity data exchange:
-         maps, lists, strings, custom data structures, and more
-
-Please see http://qpid.apache.org/proton for a more info.
-
-== Build Instructions ==
-
-To use the java implementation via jython, follow these instructions
-from the directory containing this file:
-
-  mvn compile
-  export JYTHONPATH=$PWD/target/classes
-
-Once this is done you can run the python test suite via jython to
-validate the java implementation:
-
-  tests/jython-test
-
-You can also set the PROTON_TESTS environment variable if you wish to
-run the test suite as part of the maven build:
-
-  export PROTON_TESTS=$PWD/tests
-  mvn test
diff --git a/proton-j/proton/pom.xml b/proton-j/proton/pom.xml
index fc22647..0b17e5c 100644
--- a/proton-j/proton/pom.xml
+++ b/proton-j/proton/pom.xml
@@ -18,20 +18,18 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <parent>
     <groupId>org.apache.qpid</groupId>
-    <artifactId>proton-project</artifactId>
+    <artifactId>proton-j</artifactId>
     <version>1.0-SNAPSHOT</version>
   </parent>
   <modelVersion>4.0.0</modelVersion>
 
-  <groupId>org.apache.qpid</groupId>
-  <artifactId>proton</artifactId>
-  <version>1.0-SNAPSHOT</version>
+  <artifactId>proton-j-impl</artifactId>
 
   <dependencies>
     <dependency>
       <groupId>org.apache.qpid</groupId>
       <artifactId>proton-api</artifactId>
-      <version>1.0-SNAPSHOT</version>
+      <version>${project.parent.version}</version>
     </dependency>
 
     <dependency>
@@ -41,13 +39,6 @@
     </dependency>
 
     <dependency>
-        <groupId>org.python</groupId>
-        <artifactId>jython-standalone</artifactId>
-        <version>2.5.3</version>
-      <scope>test</scope>
-    </dependency>
-
-    <dependency>
       <groupId>org.mockito</groupId>
       <artifactId>mockito-core</artifactId>
       <version>1.9.5</version>
@@ -55,15 +46,4 @@
     </dependency>
   </dependencies>
 
-  <build> 
-    <resources>
-      <resource>
-        <directory>${basedir}/src/main/resources</directory>
-      </resource>
-      <resource>
-        <directory>${basedir}/src/main/scripts</directory>
-      </resource>
-    </resources>
-  </build>
-
 </project>
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/driver/impl/DriverFactoryImpl.java
similarity index 67%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton/src/main/java/org/apache/qpid/proton/driver/impl/DriverFactoryImpl.java
index fd9b0c2..8885819 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/driver/impl/DriverFactoryImpl.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,21 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.driver.impl;
 
-package org.apache.qpid.proton.engine;
+import java.io.IOException;
 
-public class ProtonException extends RuntimeException
+import org.apache.qpid.proton.driver.Driver;
+import org.apache.qpid.proton.driver.DriverFactory;
+
+public class DriverFactoryImpl implements DriverFactory
 {
-    public ProtonException()
+
+    @Override
+    public Driver createDriver() throws IOException
     {
+        return new DriverImpl();
     }
 
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
 
 }
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java
index 77a0c81..d26e55e 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/driver/impl/DriverImpl.java
@@ -49,7 +49,7 @@
     private Collection<Connector> _connectors = new LinkedList();
     private Logger _logger = Logger.getLogger("proton.driver");
 
-    public DriverImpl() throws IOException
+    DriverImpl() throws IOException
     {
         _selector = Selector.open();
     }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJConnection.java
similarity index 69%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJConnection.java
index fd9b0c2..bf44a3c 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJConnection.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,30 +15,20 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
  */
-
 package org.apache.qpid.proton.engine;
 
-public class ProtonException extends RuntimeException
+import org.apache.qpid.proton.engine.Connection;
+
+/**
+ * Extends {@link Connection} with functionality that is specific to proton-j
+ */
+public interface ProtonJConnection extends Connection, ProtonJEndpoint
 {
-    public ProtonException()
-    {
-    }
+    void setLocalContainerId(String localContainerId);
 
-    public ProtonException(String message)
-    {
-        super(message);
-    }
+    @Override
+    ProtonJSession session();
 
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
+    int getMaxChannels();
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJEndpoint.java
similarity index 70%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJEndpoint.java
index fd9b0c2..5feb654 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJEndpoint.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,14 @@
  * under the License.
  *
  */
-
 package org.apache.qpid.proton.engine;
 
-public class ProtonException extends RuntimeException
+import org.apache.qpid.proton.engine.Endpoint;
+import org.apache.qpid.proton.engine.EndpointError;
+
+public interface ProtonJEndpoint extends Endpoint
 {
-    public ProtonException()
-    {
-    }
 
-    public ProtonException(String message)
-    {
-        super(message);
-    }
+    void setLocalError(EndpointError localError);
 
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
-}
+}
\ No newline at end of file
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJSession.java
similarity index 69%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJSession.java
index fd9b0c2..f939d93 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJSession.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,30 +15,16 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
  */
-
 package org.apache.qpid.proton.engine;
 
-public class ProtonException extends RuntimeException
+import org.apache.qpid.proton.engine.Sender;
+import org.apache.qpid.proton.engine.Session;
+
+/**
+ * Extends {@link Session} with functionality that is specific to proton-j
+ */
+public interface ProtonJSession extends Session, ProtonJEndpoint
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
+    Sender sender(String name);
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJSslDomain.java
similarity index 69%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJSslDomain.java
index fd9b0c2..e1960fc 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJSslDomain.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,30 +15,15 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
  */
-
 package org.apache.qpid.proton.engine;
 
-public class ProtonException extends RuntimeException
+import org.apache.qpid.proton.engine.SslDomain;
+
+/**
+ * Extends {@link SslDomain} with functionality that is specific to proton-j
+ */
+public interface ProtonJSslDomain extends SslDomain
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
 
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJSslPeerDetails.java
similarity index 69%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJSslPeerDetails.java
index fd9b0c2..ea5aae8 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJSslPeerDetails.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,30 +15,15 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
  */
-
 package org.apache.qpid.proton.engine;
 
-public class ProtonException extends RuntimeException
+import org.apache.qpid.proton.engine.SslPeerDetails;
+
+/**
+ * Extends {@link SslPeerDetails} with functionality specific to proton-j
+ */
+public interface ProtonJSslPeerDetails extends SslPeerDetails
 {
-    public ProtonException()
-    {
-    }
-
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
 
 }
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJTransport.java
similarity index 69%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJTransport.java
index fd9b0c2..8bd24b3 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/ProtonJTransport.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -16,30 +15,18 @@
  * KIND, either express or implied.  See the License for the
  * specific language governing permissions and limitations
  * under the License.
- *
  */
-
 package org.apache.qpid.proton.engine;
 
-public class ProtonException extends RuntimeException
+import org.apache.qpid.proton.engine.Transport;
+import org.apache.qpid.proton.engine.impl.ProtocolTracer;
+
+/**
+ * Extends {@link Transport} with functionality that is specific to proton-j
+ */
+public interface ProtonJTransport extends Transport
 {
-    public ProtonException()
-    {
-    }
+    void setProtocolTracer(ProtocolTracer protocolTracer);
 
-    public ProtonException(String message)
-    {
-        super(message);
-    }
-
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
-
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
+    ProtocolTracer getProtocolTracer();
 }
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java
index b6be81b..997c747 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ConnectionImpl.java
@@ -27,7 +27,7 @@
 import org.apache.qpid.proton.engine.*;
 import org.apache.qpid.proton.amqp.transport.Open;
 
-public class ConnectionImpl extends EndpointImpl implements Connection
+public class ConnectionImpl extends EndpointImpl implements ProtonJConnection
 {
 
     public static final int MAX_CHANNELS = 255;
@@ -55,7 +55,11 @@
     private String _remoteContainer;
     private String _remoteHostname;
 
-    public ConnectionImpl()
+    /**
+     * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
+     * Client code outside this module should use a {@link EngineFactory} instead
+     */
+    @Deprecated public ConnectionImpl()
     {
     }
 
@@ -242,6 +246,7 @@
         return _localContainerId;
     }
 
+    @Override
     public void setLocalContainerId(String localContainerId)
     {
         _localContainerId = localContainerId;
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/DeliveryImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/DeliveryImpl.java
index b7811ae..76c8736 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/DeliveryImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/DeliveryImpl.java
@@ -57,7 +57,7 @@
     private boolean _done;
     private int _offset;
 
-    public DeliveryImpl(final byte[] tag, final LinkImpl link, DeliveryImpl previous)
+    DeliveryImpl(final byte[] tag, final LinkImpl link, DeliveryImpl previous)
     {
         _tag = tag;
         _link = link;
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java
index c02497f..2baf373 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImpl.java
@@ -21,11 +21,11 @@
 
 package org.apache.qpid.proton.engine.impl;
 
-import org.apache.qpid.proton.engine.Endpoint;
 import org.apache.qpid.proton.engine.EndpointError;
 import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.ProtonJEndpoint;
 
-public abstract class EndpointImpl implements Endpoint
+public abstract class EndpointImpl implements ProtonJEndpoint
 {
     private EndpointState _localState = EndpointState.UNINITIALIZED;
     private EndpointState _remoteState = EndpointState.UNINITIALIZED;
@@ -94,6 +94,7 @@
         _remoteState = remoteState;
     }
 
+    @Override
     public void setLocalError(EndpointError localError)
     {
         _localError = localError;
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImplQuery.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImplQuery.java
index 3c5f5ad..33519b1 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImplQuery.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/EndpointImplQuery.java
@@ -29,7 +29,7 @@
     private final EnumSet<EndpointState> _local;
     private final EnumSet<EndpointState> _remote;
 
-    public EndpointImplQuery(EnumSet<EndpointState> local, EnumSet<EndpointState> remote)
+    EndpointImplQuery(EnumSet<EndpointState> local, EnumSet<EndpointState> remote)
     {
         _local = local;
         _remote = remote;
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/EngineFactoryImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/EngineFactoryImpl.java
new file mode 100644
index 0000000..6233251
--- /dev/null
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/EngineFactoryImpl.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.engine.impl;
+
+import org.apache.qpid.proton.engine.EngineFactory;
+import org.apache.qpid.proton.engine.ProtonJConnection;
+import org.apache.qpid.proton.engine.ProtonJSslDomain;
+import org.apache.qpid.proton.engine.ProtonJSslPeerDetails;
+import org.apache.qpid.proton.engine.ProtonJTransport;
+import org.apache.qpid.proton.engine.impl.ssl.SslDomainImpl;
+import org.apache.qpid.proton.engine.impl.ssl.SslPeerDetailsImpl;
+
+public class EngineFactoryImpl implements EngineFactory
+{
+    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
+    @Override
+    public ProtonJConnection createConnection()
+    {
+        return new ConnectionImpl();
+    }
+
+    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
+    @Override
+    public ProtonJTransport createTransport()
+    {
+        return new TransportImpl();
+    }
+
+    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
+    @Override
+    public ProtonJSslDomain createSslDomain()
+    {
+        return new SslDomainImpl();
+    }
+
+    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
+    @Override
+    public ProtonJSslPeerDetails createSslPeerDetails(String hostname, int port)
+    {
+        return new SslPeerDetailsImpl(hostname, port);
+    }
+
+}
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
index bc33ea1..8239f46 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/LinkImpl.java
@@ -56,7 +56,7 @@
     private boolean _drain;
 
 
-    public LinkImpl(SessionImpl session, String name)
+    LinkImpl(SessionImpl session, String name)
     {
         _session = session;
         _name = name;
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ReceiverImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ReceiverImpl.java
index a76bde8..3fb6d7d 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ReceiverImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ReceiverImpl.java
@@ -47,7 +47,7 @@
     private int _unsentCredits;
 
 
-    public ReceiverImpl(SessionImpl session, String name)
+    ReceiverImpl(SessionImpl session, String name)
     {
         super(session, name);
     }
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java
index 9cbc2cb..d8ef67a 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SaslImpl.java
@@ -75,7 +75,7 @@
 
     private Role _role;
 
-    public SaslImpl()
+    SaslImpl()
     {
         _frameParser = new SaslFrameParser(this);
         AMQPDefinedTypes.registerAllTypes(_decoder,_encoder);
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java
index 3e1e189..dee073e 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SenderImpl.java
@@ -31,7 +31,7 @@
     private TransportSender _transportLink;
     private boolean _drained;
 
-    public SenderImpl(SessionImpl session, String name)
+    SenderImpl(SessionImpl session, String name)
     {
         super(session, name);
     }
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
index a7171fb..3998774 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/SessionImpl.java
@@ -22,9 +22,10 @@
 
 import java.util.*;
 import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.ProtonJSession;
 import org.apache.qpid.proton.engine.Session;
 
-public class SessionImpl extends EndpointImpl implements Session
+public class SessionImpl extends EndpointImpl implements ProtonJSession
 {
     private final ConnectionImpl _connection;
 
@@ -35,7 +36,7 @@
     private LinkNode<SessionImpl> _node;
 
 
-    public SessionImpl(ConnectionImpl connection)
+    SessionImpl(ConnectionImpl connection)
     {
         _connection = connection;
         _node = _connection.addSessionEndpoint(this);
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportDelivery.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportDelivery.java
index 0a59a15..0120b0b 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportDelivery.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportDelivery.java
@@ -30,7 +30,7 @@
     private TransportLink _transportLink;
     private int _sessionSize = 1;
 
-    public TransportDelivery(UnsignedInteger currentDeliveryId, DeliveryImpl delivery, TransportLink transportLink)
+    TransportDelivery(UnsignedInteger currentDeliveryId, DeliveryImpl delivery, TransportLink transportLink)
     {
         _deliveryId = currentDeliveryId;
         _delivery = delivery;
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactoryImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactoryImpl.java
index ba7ca87..6657440 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactoryImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportFactoryImpl.java
@@ -25,6 +25,11 @@
 
 class TransportFactoryImpl extends TransportFactory
 {
+    TransportFactoryImpl()
+    {
+    }
+
+    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
     public Transport transport(Connection c)
     {
         TransportImpl t = new TransportImpl();
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
index 6319f69..50950bf 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportImpl.java
@@ -32,11 +32,12 @@
 import org.apache.qpid.proton.engine.Connection;
 import org.apache.qpid.proton.engine.EndpointError;
 import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.EngineFactory;
+import org.apache.qpid.proton.engine.ProtonJTransport;
 import org.apache.qpid.proton.engine.Sasl;
 import org.apache.qpid.proton.engine.Ssl;
 import org.apache.qpid.proton.engine.SslDomain;
 import org.apache.qpid.proton.engine.SslPeerDetails;
-import org.apache.qpid.proton.engine.Transport;
 import org.apache.qpid.proton.engine.TransportException;
 import org.apache.qpid.proton.engine.impl.ssl.ProtonSslEngineProvider;
 import org.apache.qpid.proton.engine.impl.ssl.SslImpl;
@@ -54,10 +55,8 @@
 import org.apache.qpid.proton.amqp.transport.Role;
 import org.apache.qpid.proton.amqp.transport.Transfer;
 
-public class TransportImpl extends EndpointImpl implements Transport, FrameBody.FrameBodyHandler<Integer>,FrameTransport
+public class TransportImpl extends EndpointImpl implements ProtonJTransport, FrameBody.FrameBodyHandler<Integer>,FrameTransport
 {
-    public static final int SESSION_WINDOW = 1024;
-
     public static final byte[] HEADER = new byte[8];
     public static final org.apache.qpid.proton.amqp.messaging.Accepted ACCEPTED =
             new org.apache.qpid.proton.amqp.messaging.Accepted();
@@ -110,7 +109,11 @@
         _overflowBuffer.flip();
     }
 
-    public TransportImpl()
+    /**
+     * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
+     * Client code outside this module should use a {@link EngineFactory} instead
+     */
+    @Deprecated public TransportImpl()
     {
         FrameParser frameParser = new FrameParser(this);
 
@@ -125,6 +128,7 @@
                     };
     }
 
+    @Override
     public void bind(Connection conn)
     {
         // TODO - check if already bound
@@ -147,6 +151,7 @@
         }
     }
 
+    @Override
     public int input(byte[] bytes, int offset, int length)
     {
         if(_inputException != null)
@@ -174,7 +179,7 @@
     //==================================================================================================================
     // Process model state to generate output
 
-
+    @Override
     public int output(byte[] bytes, final int offset, final int size)
     {
         try
@@ -962,6 +967,7 @@
         return _connectionEndpoint;
     }
 
+    @Override
     public void free()
     {
         super.free();
@@ -971,6 +977,7 @@
     // handle incoming amqp data
 
 
+    @Override
     public void handleOpen(Open open, Binary payload, Integer channel)
     {
         setRemoteState(EndpointState.ACTIVE);
@@ -989,6 +996,7 @@
         }
     }
 
+    @Override
     public void handleBegin(Begin begin, Binary payload, Integer channel)
     {
         // TODO - check channel < max_channel
@@ -1022,6 +1030,7 @@
 
     }
 
+    @Override
     public void handleAttach(Attach attach, Binary payload, Integer channel)
     {
         TransportSession transportSession = _remoteSessions[channel];
@@ -1074,6 +1083,7 @@
         }
     }
 
+    @Override
     public void handleFlow(Flow flow, Binary payload, Integer channel)
     {
         TransportSession transportSession = _remoteSessions[channel];
@@ -1088,6 +1098,7 @@
 
     }
 
+    @Override
     public void handleTransfer(Transfer transfer, Binary payload, Integer channel)
     {
         // TODO - check channel < max_channel
@@ -1102,6 +1113,7 @@
         }
     }
 
+    @Override
     public void handleDisposition(Disposition disposition, Binary payload, Integer channel)
     {
         TransportSession transportSession = _remoteSessions[channel];
@@ -1115,6 +1127,7 @@
         }
     }
 
+    @Override
     public void handleDetach(Detach detach, Binary payload, Integer channel)
     {
         TransportSession transportSession = _remoteSessions[channel];
@@ -1141,6 +1154,7 @@
         }
     }
 
+    @Override
     public void handleEnd(End end, Binary payload, Integer channel)
     {
         TransportSession transportSession = _remoteSessions[channel];
@@ -1157,6 +1171,7 @@
         }
     }
 
+    @Override
     public void handleClose(Close close, Binary payload, Integer channel)
     {
         _closeReceived = true;
@@ -1168,6 +1183,7 @@
 
     }
 
+    @Override
     public boolean input(TransportFrame frame)
     {
         if( _protocolTracer!=null )
@@ -1200,11 +1216,13 @@
         }
     }
 
+    @Override
     public ProtocolTracer getProtocolTracer()
     {
         return _protocolTracer;
     }
 
+    @Override
     public void setProtocolTracer(ProtocolTracer protocolTracer)
     {
         this._protocolTracer = protocolTracer;
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportSession.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportSession.java
index 1908d63..a91793b 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportSession.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/TransportSession.java
@@ -62,7 +62,7 @@
     private boolean _endReceived;
     private boolean _beginSent;
 
-    public TransportSession(SessionImpl session)
+    TransportSession(SessionImpl session)
     {
         _session = session;
     }
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/ByteHolder.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/ByteHolder.java
index 553369d..35d2b5b 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/ByteHolder.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/ByteHolder.java
@@ -34,7 +34,7 @@
     private final ByteBuffer _bytes;
 
     /** Creates me, initially in a writeable state */
-    public ByteHolder(int capacity)
+    ByteHolder(int capacity)
     {
         _bytes = ByteBuffer.allocate(capacity);
     }
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/DefaultSslEngineFacade.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/DefaultSslEngineFacade.java
index ec8b9d3..d38a3a0 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/DefaultSslEngineFacade.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/DefaultSslEngineFacade.java
@@ -31,7 +31,7 @@
 {
     private final SSLEngine _sslEngine;
 
-    public DefaultSslEngineFacade(SSLEngine sslEngine)
+    DefaultSslEngineFacade(SSLEngine sslEngine)
     {
         _sslEngine = sslEngine;
     }
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java
index 7ab7aa2..b9ec972 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslDomainImpl.java
@@ -18,10 +18,13 @@
  */
 package org.apache.qpid.proton.engine.impl.ssl;
 
+import org.apache.qpid.proton.ProtonUnsupportedOperationException;
+import org.apache.qpid.proton.engine.EngineFactory;
+import org.apache.qpid.proton.engine.ProtonJSslDomain;
 import org.apache.qpid.proton.engine.SslDomain;
 import org.apache.qpid.proton.engine.SslPeerDetails;
 
-public class SslDomainImpl implements SslDomain, ProtonSslEngineProvider
+public class SslDomainImpl implements SslDomain, ProtonSslEngineProvider, ProtonJSslDomain
 {
     private Mode _mode;
     private VerifyMode _verifyMode = VerifyMode.ANONYMOUS_PEER;
@@ -33,6 +36,14 @@
 
     private final SslEngineFacadeFactory _sslEngineFacadeFactory = new SslEngineFacadeFactory();
 
+    /**
+     * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
+     * Client code outside this module should use a {@link EngineFactory} instead
+     */
+    @Deprecated public SslDomainImpl()
+    {
+    }
+
     @Override
     public void init(Mode mode)
     {
@@ -71,6 +82,10 @@
     @Override
     public void setPeerAuthentication(VerifyMode verifyMode)
     {
+        if(verifyMode == VerifyMode.VERIFY_PEER_NAME)
+        {
+            throw new ProtonUnsupportedOperationException();
+        }
         _verifyMode = verifyMode;
         _sslEngineFacadeFactory.resetCache();
     }
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java
index 3d820f5..cbd2960 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslEngineFacadeFactory.java
@@ -71,6 +71,10 @@
         Security.addProvider(new BouncyCastleProvider());
     }
 
+    SslEngineFacadeFactory()
+    {
+    }
+
     /**
      * This is a list of all anonymous cipher suites supported by Java 6, excluding those that
      * use MD5.  These are all supported by both Oracle's and IBM's Java 6 implementation.
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslHandshakeSniffingTransportWrapper.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslHandshakeSniffingTransportWrapper.java
index f121df2..e78c808 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslHandshakeSniffingTransportWrapper.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslHandshakeSniffingTransportWrapper.java
@@ -30,7 +30,7 @@
     private boolean _determinationMade = false;
     private boolean _isSecure;
 
-    public SslHandshakeSniffingTransportWrapper(
+    SslHandshakeSniffingTransportWrapper(
             SslTransportWrapper secureTransportWrapper,
             TransportWrapper plainTransportWrapper)
     {
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java
index a7f69e0..910dd82 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslImpl.java
@@ -20,6 +20,7 @@
  */
 package org.apache.qpid.proton.engine.impl.ssl;
 
+import org.apache.qpid.proton.ProtonUnsupportedOperationException;
 import org.apache.qpid.proton.engine.Ssl;
 import org.apache.qpid.proton.engine.SslDomain;
 import org.apache.qpid.proton.engine.SslPeerDetails;
@@ -156,4 +157,24 @@
             }
         }
     }
+
+    /**
+     * {@inheritDoc}
+     * @throws ProtonUnsupportedOperationException
+     */
+    @Override
+    public void setPeerHostname(String hostname)
+    {
+        throw new ProtonUnsupportedOperationException();
+    }
+
+    /**
+     * {@inheritDoc}
+     * @throws ProtonUnsupportedOperationException
+     */
+    @Override
+    public String getPeerHostname()
+    {
+        throw new ProtonUnsupportedOperationException();
+    }
 }
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslPeerDetailsImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslPeerDetailsImpl.java
index 1da0322..a873e8e 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslPeerDetailsImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/engine/impl/ssl/SslPeerDetailsImpl.java
@@ -18,14 +18,20 @@
  */
 package org.apache.qpid.proton.engine.impl.ssl;
 
-import org.apache.qpid.proton.engine.SslPeerDetails;
+import org.apache.qpid.proton.engine.EngineFactory;
+import org.apache.qpid.proton.engine.ProtonJSslPeerDetails;
 
-public class SslPeerDetailsImpl implements SslPeerDetails
+
+public class SslPeerDetailsImpl implements ProtonJSslPeerDetails
 {
     private final String _hostname;
     private final int _port;
 
-    public SslPeerDetailsImpl(String hostname, int port)
+    /**
+     * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
+     * Client code outside this module should use a {@link EngineFactory} instead
+     */
+    @Deprecated public SslPeerDetailsImpl(String hostname, int port)
     {
         _hostname = hostname;
         _port = port;
diff --git a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/message/ProtonJMessage.java
similarity index 66%
copy from proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
copy to proton-j/proton/src/main/java/org/apache/qpid/proton/message/ProtonJMessage.java
index fd9b0c2..b22ef2a 100644
--- a/proton-j/proton-api/src/main/java/org/apache/qpid/proton/engine/ProtonException.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/message/ProtonJMessage.java
@@ -1,5 +1,4 @@
 /*
- *
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
  * distributed with this work for additional information
@@ -18,28 +17,16 @@
  * under the License.
  *
  */
+package org.apache.qpid.proton.message;
 
-package org.apache.qpid.proton.engine;
+import org.apache.qpid.proton.codec.WritableBuffer;
+import org.apache.qpid.proton.message.Message;
 
-public class ProtonException extends RuntimeException
+public interface ProtonJMessage extends Message
 {
-    public ProtonException()
-    {
-    }
 
-    public ProtonException(String message)
-    {
-        super(message);
-    }
+    int encode2(byte[] data, int offset, int length);
 
-    public ProtonException(String message, Throwable cause)
-    {
-        super(message, cause);
-    }
+    int encode(WritableBuffer buffer);
 
-    public ProtonException(Throwable cause)
-    {
-        super(cause);
-    }
-
-}
+}
\ No newline at end of file
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/message/impl/MessageFactoryImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/message/impl/MessageFactoryImpl.java
new file mode 100644
index 0000000..5fe1dce
--- /dev/null
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/message/impl/MessageFactoryImpl.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.message.impl;
+
+import org.apache.qpid.proton.amqp.messaging.ApplicationProperties;
+import org.apache.qpid.proton.amqp.messaging.DeliveryAnnotations;
+import org.apache.qpid.proton.amqp.messaging.Footer;
+import org.apache.qpid.proton.amqp.messaging.Header;
+import org.apache.qpid.proton.amqp.messaging.MessageAnnotations;
+import org.apache.qpid.proton.amqp.messaging.Properties;
+import org.apache.qpid.proton.amqp.messaging.Section;
+import org.apache.qpid.proton.message.MessageFactory;
+import org.apache.qpid.proton.message.ProtonJMessage;
+
+public class MessageFactoryImpl implements MessageFactory
+{
+
+    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
+    @Override
+    public ProtonJMessage createMessage()
+    {
+        return new MessageImpl();
+    }
+
+    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
+    @Override
+    public ProtonJMessage createMessage(Header header,
+                                 DeliveryAnnotations deliveryAnnotations, MessageAnnotations messageAnnotations,
+                                 Properties properties, ApplicationProperties applicationProperties,
+                                 Section body, Footer footer)
+    {
+        return new MessageImpl(header,
+                               deliveryAnnotations, messageAnnotations,
+                               properties, applicationProperties,
+                               body, footer);
+    }
+}
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
index d042612..560c137 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/message/impl/MessageImpl.java
@@ -1,4 +1,3 @@
-package org.apache.qpid.proton.message.impl;
 /*
  *
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -20,6 +19,7 @@
  *
 */
 
+package org.apache.qpid.proton.message.impl;
 
 import java.nio.ByteBuffer;
 import java.util.Date;
@@ -32,10 +32,8 @@
 import org.apache.qpid.proton.codec.*;
 import org.apache.qpid.proton.message.*;
 
-public class MessageImpl implements Message
+public class MessageImpl implements ProtonJMessage
 {
-    public static final short DEFAULT_PRIORITY = 4;
-
     private final AMQPMessageFormat _parser = new AMQPMessageFormat();
 
     private Header _header;
@@ -47,11 +45,19 @@
     private Footer _footer;
     private MessageFormat _format = MessageFormat.DATA;
 
-    public MessageImpl()
+    /**
+     * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
+     * Client code outside this module should use a {@link MessageFactory} instead
+     */
+    @Deprecated public MessageImpl()
     {
     }
 
-    public MessageImpl(Header header, DeliveryAnnotations deliveryAnnotations, MessageAnnotations messageAnnotations,
+    /**
+     * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
+     * Client code outside this module should use a {@link MessageFactory} instead
+     */
+    @Deprecated public MessageImpl(Header header, DeliveryAnnotations deliveryAnnotations, MessageAnnotations messageAnnotations,
                        Properties properties, ApplicationProperties applicationProperties, Section body, Footer footer)
     {
         _header = header;
@@ -673,6 +679,7 @@
         return encode(new WritableBuffer.ByteBufferWrapper(buffer));
     }
 
+    @Override
     public int encode2(byte[] data, int offset, int length)
     {
         ByteBuffer buffer = ByteBuffer.wrap(data, offset, length);
@@ -684,6 +691,7 @@
         return composite.position() - start;
     }
 
+    @Override
     public int encode(WritableBuffer buffer)
     {
         int length = buffer.remaining();
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerFactoryImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerFactoryImpl.java
new file mode 100644
index 0000000..e41bae5
--- /dev/null
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerFactoryImpl.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton.messenger.impl;
+
+import org.apache.qpid.proton.messenger.Messenger;
+import org.apache.qpid.proton.messenger.MessengerFactory;
+
+public class MessengerFactoryImpl implements MessengerFactory
+{
+    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
+    @Override
+    public Messenger createMessenger()
+    {
+        return new MessengerImpl();
+    }
+
+    @SuppressWarnings("deprecation") // TODO remove once the constructor is made non-public (and therefore non-deprecated)
+    @Override
+    public Messenger createMessenger(String name)
+    {
+        return new MessengerImpl(name);
+    }
+
+}
diff --git a/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java b/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
index 14fce6f..9048de5 100644
--- a/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
+++ b/proton-j/proton/src/main/java/org/apache/qpid/proton/messenger/impl/MessengerImpl.java
@@ -28,23 +28,26 @@
 import java.util.concurrent.TimeoutException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+
+import org.apache.qpid.proton.ProtonFactoryLoader;
 import org.apache.qpid.proton.driver.Connector;
 import org.apache.qpid.proton.driver.Driver;
+import org.apache.qpid.proton.driver.DriverFactory;
 import org.apache.qpid.proton.driver.Listener;
 import org.apache.qpid.proton.engine.Connection;
 import org.apache.qpid.proton.engine.Delivery;
 import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.EngineFactory;
 import org.apache.qpid.proton.engine.Link;
 import org.apache.qpid.proton.engine.Receiver;
 import org.apache.qpid.proton.engine.Sasl;
 import org.apache.qpid.proton.engine.Sender;
 import org.apache.qpid.proton.engine.Session;
-import org.apache.qpid.proton.driver.impl.DriverImpl;
-import org.apache.qpid.proton.engine.impl.ConnectionImpl;
 import org.apache.qpid.proton.message.Message;
-import org.apache.qpid.proton.message.impl.MessageImpl;
+import org.apache.qpid.proton.message.MessageFactory;
 import org.apache.qpid.proton.messenger.Messenger;
 import org.apache.qpid.proton.messenger.MessengerException;
+import org.apache.qpid.proton.messenger.MessengerFactory;
 import org.apache.qpid.proton.messenger.Status;
 import org.apache.qpid.proton.messenger.Tracker;
 import org.apache.qpid.proton.amqp.messaging.Accepted;
@@ -53,6 +56,8 @@
 
 public class MessengerImpl implements Messenger
 {
+    private static ProtonFactoryLoader protonFactoryLoader = new ProtonFactoryLoader();
+
     private static final EnumSet<EndpointState> UNINIT = EnumSet.of(EndpointState.UNINITIALIZED);
     private static final EnumSet<EndpointState> ACTIVE = EnumSet.of(EndpointState.ACTIVE);
     private static final EnumSet<EndpointState> CLOSED = EnumSet.of(EndpointState.CLOSED);
@@ -61,6 +66,9 @@
 
     private final Logger _logger = Logger.getLogger("proton.messenger");
     private final String _name;
+    private final EngineFactory _engineFactory;
+    private final DriverFactory _driverFactory;
+    private final MessageFactory _messageFactory;
     private long _timeout = -1;
     private long _nextTag = 1;
     private byte[] _buffer = new byte[5*1024];
@@ -70,14 +78,35 @@
     private TrackerQueue _incoming = new TrackerQueue();
     private TrackerQueue _outgoing = new TrackerQueue();
 
-    public MessengerImpl()
+
+    /**
+     * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
+     * Client code outside this module should use a {@link MessengerFactory} instead
+     */
+    @Deprecated public MessengerImpl()
     {
         this(java.util.UUID.randomUUID().toString());
     }
 
-    public MessengerImpl(String name)
+    /**
+     * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
+     * Client code outside this module should use a {@link MessengerFactory} instead
+     */
+    @Deprecated public MessengerImpl(String name)
+    {
+        this(name, defaultEngineFactory(), defaultDriverFactory(), defaultMessageFactory());
+    }
+
+    /**
+     * @deprecated This constructor's visibility will be reduced to the default scope in a future release.
+     * Client code outside this module should use a {@link MessengerFactory} instead
+     */
+    @Deprecated public MessengerImpl(String name, EngineFactory engineFactory, DriverFactory driverFactory, MessageFactory messageFactory)
     {
         _name = name;
+        _engineFactory = engineFactory;
+        _driverFactory = driverFactory;
+        _messageFactory = messageFactory;
     }
 
     public void setTimeout(long timeInMillis)
@@ -92,7 +121,7 @@
 
     public void start() throws IOException
     {
-        _driver = new DriverImpl();
+        _driver = _driverFactory.createDriver();
     }
 
     public void stop()
@@ -197,7 +226,7 @@
                 {
                     _logger.log(Level.FINE, "Readable delivery found: " + delivery);
                     int size = read((Receiver) delivery.getLink());
-                    Message message = new MessageImpl();
+                    Message message = _messageFactory.createMessage();
                     message.decode(_buffer, 0, size);
                     _incoming.add(delivery);
                     _distributed--;
@@ -375,7 +404,7 @@
         for (Listener l = _driver.listener(); l != null; l = _driver.listener())
         {
             Connector c = l.accept();
-            Connection connection = new ConnectionImpl();
+            Connection connection = _engineFactory.createConnection();
             connection.setContainer(_name);
             c.setConnection(connection);
             //TODO: SSL and full SASL
@@ -735,7 +764,7 @@
         {
             Connector connector = _driver.createConnector(host, port, null);
             _logger.log(Level.FINE, "Connecting to " + host + ":" + port);
-            connection = new ConnectionImpl();
+            connection = _engineFactory.createConnection();
             connection.setContainer(_name);
             connection.setHostname(host);
             connection.setContext(service);
@@ -914,4 +943,20 @@
         if ("amqps".equals(scheme)) return 5671;
         else return 5672;
     }
+
+    private static EngineFactory defaultEngineFactory()
+    {
+        return (EngineFactory) protonFactoryLoader.loadFactory(EngineFactory.class);
+    }
+
+    private static DriverFactory defaultDriverFactory()
+    {
+        return (DriverFactory) protonFactoryLoader.loadFactory(DriverFactory.class);
+    }
+
+    private static MessageFactory defaultMessageFactory()
+    {
+        return (MessageFactory) protonFactoryLoader.loadFactory(MessageFactory.class);
+    }
+
 }
diff --git a/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.driver.DriverFactory b/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.driver.DriverFactory
new file mode 100644
index 0000000..00e7a60
--- /dev/null
+++ b/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.driver.DriverFactory
@@ -0,0 +1 @@
+org.apache.qpid.proton.driver.impl.DriverFactoryImpl
\ No newline at end of file
diff --git a/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.engine.EngineFactory b/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.engine.EngineFactory
new file mode 100644
index 0000000..33f9865
--- /dev/null
+++ b/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.engine.EngineFactory
@@ -0,0 +1 @@
+org.apache.qpid.proton.engine.impl.EngineFactoryImpl
\ No newline at end of file
diff --git a/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.message.MessageFactory b/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.message.MessageFactory
new file mode 100644
index 0000000..99eb726
--- /dev/null
+++ b/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.message.MessageFactory
@@ -0,0 +1 @@
+org.apache.qpid.proton.message.impl.MessageFactoryImpl
\ No newline at end of file
diff --git a/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.messenger.MessengerFactory b/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.messenger.MessengerFactory
new file mode 100644
index 0000000..d0beeb4
--- /dev/null
+++ b/proton-j/proton/src/main/resources/META-INF/services/org.apache.qpid.proton.messenger.MessengerFactory
@@ -0,0 +1 @@
+org.apache.qpid.proton.messenger.impl.MessengerFactoryImpl
\ No newline at end of file
diff --git a/proton-j/proton/src/test/java/org/apache/qpid/proton/test/JythonTest.java b/proton-j/proton/src/test/java/org/apache/qpid/proton/test/JythonTest.java
deleted file mode 100644
index 4c6c978..0000000
--- a/proton-j/proton/src/test/java/org/apache/qpid/proton/test/JythonTest.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- *
- */
-package org.apache.qpid.proton.test;
-
-import org.junit.Test;
-import static org.junit.Assert.*;
-
-import org.python.core.PyException;
-import org.python.util.PythonInterpreter;
-import java.io.File;
-
-/**
- * Runs all the python tests.
- */
-public class JythonTest
-{
-
-    static final private String PROTON_TESTS = "PROTON_TESTS";
-
-    @Test
-    public void test() throws Exception
-    {
-
-        File basedir = new File(getClass().getProtectionDomain().getCodeSource().getLocation().getFile(), "../../..").getCanonicalFile();
-        File testDir;
-        String protonTestsVar = System.getenv(PROTON_TESTS);
-        if( protonTestsVar != null && protonTestsVar.trim().length()>0 )
-        {
-            testDir = new File(protonTestsVar).getCanonicalFile();
-            assertTrue(PROTON_TESTS + " env variable set incorrectly: " + protonTestsVar, testDir.isDirectory());
-        }
-        else
-        {
-            testDir = new File(basedir, "../tests");
-            if( !testDir.isDirectory() )
-            {
-                // The tests might not be there if the proton-j module is released independently
-                // from the main proton project.
-                return;
-            }
-        }
-
-        File classesDir = new File(basedir, "target/classes");
-        PythonInterpreter interp = new PythonInterpreter();
-
-        interp.exec(
-        "import sys\n"+
-        "sys.path.insert(0,\""+classesDir.getCanonicalPath()+"\")\n"+
-        "sys.path.insert(0,\""+testDir.getCanonicalPath()+"\")\n"
-        );
-
-        try
-        {
-            interp.execfile(new File(testDir, "proton-test").getCanonicalPath());
-        }
-        catch (PyException e)
-        {
-            if( e.type.toString().equals("<type 'exceptions.SystemExit'>") && e.value.toString().equals("0") )
-            {
-                // Build succeeded.
-            }
-            else
-            {
-                throw e;
-            }
-        }
-    }
-
-}
diff --git a/tests/java/org/apache/qpid/proton/JythonTest.java b/tests/java/org/apache/qpid/proton/JythonTest.java
new file mode 100644
index 0000000..e61f345
--- /dev/null
+++ b/tests/java/org/apache/qpid/proton/JythonTest.java
@@ -0,0 +1,106 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ *
+ */
+package org.apache.qpid.proton;
+
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.junit.Test;
+import org.python.core.PyException;
+import org.python.core.PyString;
+import org.python.core.PySystemState;
+import org.python.util.PythonInterpreter;
+
+/**
+ * Runs all the python tests, or just those that match the system property {@value #TEST_PATTERN_SYSTEM_PROPERTY}
+ * if it exists
+ */
+public class JythonTest
+{
+    private static final Logger LOGGER = Logger.getLogger(JythonTest.class.getName());
+
+    private static final String TEST_PATTERN_SYSTEM_PROPERTY = "proton.pythontest.pattern";
+    private static final String PROTON_TEST_SCRIPT_CLASSPATH_LOCATION = "/proton-test";
+
+    @Test
+    public void test() throws Exception
+    {
+        File protonScriptFile = getPythonTestScript();
+        String parentDirectory = protonScriptFile.getParent();
+
+        PythonInterpreter interp = createInterpreterWithArgs();
+
+        LOGGER.info("About to call Jython test script: " + protonScriptFile + " with parent directory added to Jython path");
+
+        interp.exec(
+        "import sys\n"+
+        "sys.path.insert(0,\""+parentDirectory+"\")\n"
+        );
+
+        try
+        {
+            String protonTestPyPath = protonScriptFile.getAbsolutePath();
+            interp.execfile(protonTestPyPath);
+        }
+        catch (PyException e)
+        {
+            if( e.type.toString().equals("<type 'exceptions.SystemExit'>") && e.value.toString().equals("0") )
+            {
+                // Build succeeded.
+            }
+            else
+            {
+                if (LOGGER.isLoggable(Level.FINE))
+                {
+                    LOGGER.log(Level.FINE, "Jython interpreter failed. Test failures?", e);
+                }
+
+                // This unusual code is necessary because PyException toString() contains the useful Python traceback
+                // and getMessage() is usually null
+                fail("Caught PyException: " + e.toString() + " with message: " + e.getMessage());
+            }
+        }
+    }
+
+    private PythonInterpreter createInterpreterWithArgs()
+    {
+        PySystemState systemState = new PySystemState();
+        String testPattern = System.getProperty(TEST_PATTERN_SYSTEM_PROPERTY);
+        if(testPattern != null)
+        {
+            systemState.argv.append(new PyString(testPattern));
+        }
+        PythonInterpreter interp = new PythonInterpreter(null, systemState);
+        return interp;
+    }
+
+    private File getPythonTestScript() throws URISyntaxException
+    {
+        URL protonScriptUrl = getClass().getResource(PROTON_TEST_SCRIPT_CLASSPATH_LOCATION);
+        File protonScriptFile = new File(protonScriptUrl.toURI());
+        return protonScriptFile;
+    }
+}
diff --git a/tests/java/org/apache/qpid/proton/systemtests/ProtonFactoryTest.java b/tests/java/org/apache/qpid/proton/systemtests/ProtonFactoryTest.java
new file mode 100644
index 0000000..9fd770f
--- /dev/null
+++ b/tests/java/org/apache/qpid/proton/systemtests/ProtonFactoryTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.systemtests;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.apache.qpid.proton.ProtonFactoryLoader;
+import org.apache.qpid.proton.engine.EngineFactory;
+import org.apache.qpid.proton.message.MessageFactory;
+import org.apache.qpid.proton.messenger.MessengerFactory;
+import org.junit.Test;
+
+public class ProtonFactoryTest
+{
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Test
+    public void testLoadFactoryWithExplicitClass()
+    {
+        ProtonFactoryLoader factoryLoader = new ProtonFactoryLoader();
+        MessageFactory messageFactory = (MessageFactory) factoryLoader.loadFactory(MessageFactory.class);
+        assertNotNull(messageFactory);
+    }
+
+    @Test
+    public void testMessageFactory()
+    {
+        ProtonFactoryLoader<MessageFactory> factoryLoader = new ProtonFactoryLoader<MessageFactory>(MessageFactory.class);
+        assertNotNull(factoryLoader.loadFactory());
+    }
+
+    @Test
+    public void testEngineFactory()
+    {
+        ProtonFactoryLoader<EngineFactory> factoryLoader = new ProtonFactoryLoader<EngineFactory>(EngineFactory.class);
+        assertNotNull(factoryLoader.loadFactory());
+    }
+
+    @Test
+    public void testMessengerFactory()
+    {
+        ProtonFactoryLoader<MessengerFactory> factoryLoader = new ProtonFactoryLoader<MessengerFactory>(MessengerFactory.class);
+        assertNotNull(factoryLoader.loadFactory());
+    }
+}
diff --git a/tests/java/org/apache/qpid/proton/systemtests/SimpleTest.java b/tests/java/org/apache/qpid/proton/systemtests/SimpleTest.java
new file mode 100644
index 0000000..a334606
--- /dev/null
+++ b/tests/java/org/apache/qpid/proton/systemtests/SimpleTest.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+package org.apache.qpid.proton.systemtests;
+
+import static org.junit.Assert.assertEquals;
+
+import org.apache.qpid.proton.ProtonFactoryLoader;
+import org.apache.qpid.proton.engine.Connection;
+import org.apache.qpid.proton.engine.EndpointState;
+import org.apache.qpid.proton.engine.EngineFactory;
+import org.apache.qpid.proton.engine.Transport;
+import org.junit.Test;
+
+public class SimpleTest
+{
+
+    @Test
+    public void test()
+    {
+        EngineFactory engineFactory = new ProtonFactoryLoader<EngineFactory>(EngineFactory.class).loadFactory();
+
+        Connection connection1 = engineFactory.createConnection();
+        Connection connection2 = engineFactory.createConnection();;
+        Transport transport1 = engineFactory.createTransport();
+        transport1.bind(connection1);
+
+        Transport transport2 = engineFactory.createTransport();
+        transport2.bind(connection2);
+
+        assertEquals(EndpointState.UNINITIALIZED, connection1.getLocalState());
+        assertEquals(EndpointState.UNINITIALIZED, connection1.getRemoteState());
+
+        connection1.open();
+        connection2.open();
+    }
+
+
+}
diff --git a/tests/pom.xml b/tests/pom.xml
new file mode 100644
index 0000000..45de85e
--- /dev/null
+++ b/tests/pom.xml
@@ -0,0 +1,118 @@
+<!--
+ -
+ - Licensed to the Apache Software Foundation (ASF) under one
+ - or more contributor license agreements.  See the NOTICE file
+ - distributed with this work for additional information
+ - regarding copyright ownership.  The ASF licenses this file
+ - to you 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.
+ -
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>tests</artifactId>
+
+  <description>The Proton system tests execute against either the Java or the C implementations, based on the chosen profile.
+
+To execute, run either &quot;mvn test -P proton-j&quot; or &quot;mvn test -P proton-jni&quot;.
+
+To reduce the set of Python tests run, set system property proton.pythontest.pattern, for example:
+
+mvn test -Dproton.pythontest.pattern='proton_tests.transport.TransportTest.*'
+
+The proton-jni profile looks for the JNI jar and native libraries under directory &lt;basedir&gt;/build/proton-c.
+To override this, run Maven like so: &quot;mvn test -P proton-jni -Dproton-c-build-dir=/path/to/build/dir&quot;.</description>
+
+  <build>
+    <!-- System tests are arranged by language, hence the non-default location of the JUnit tests. -->
+    <testSourceDirectory>java</testSourceDirectory>
+    <resources>
+      <resource><directory>python</directory></resource>
+    </resources>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>${junit-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.qpid</groupId>
+      <artifactId>proton-api</artifactId>
+      <version>1.0-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+        <groupId>org.python</groupId>
+        <artifactId>jython-standalone</artifactId>
+        <version>2.5.3</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <profiles>
+    <profile>
+      <id>proton-j</id>
+      <activation>
+        <activeByDefault>true</activeByDefault>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.qpid</groupId>
+          <artifactId>proton-j-impl</artifactId>
+          <version>1.0-SNAPSHOT</version>
+          <scope>runtime</scope>
+        </dependency>
+      </dependencies>
+    </profile>
+    <profile>
+      <id>proton-jni</id>
+      <properties>
+        <!-- Uses the JNI jar and the native libraries, neither of which are built by Maven,
+             therefore their location needs to be set explicitly in the following properties. -->
+        <proton-c-build-dir>${basedir}/../build/proton-c</proton-c-build-dir>
+        <jni-native-path>${proton-c-build-dir}:${proton-c-build-dir}/bindings/java</jni-native-path>
+        <jni-jar>${proton-c-build-dir}/bindings/java/proton-jni.jar</jni-jar>
+      </properties>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <configuration>
+              <forkMode>once</forkMode>
+              <argLine>-Djava.library.path=${jni-native-path}</argLine>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.qpid</groupId>
+          <artifactId>proton-jni</artifactId>
+          <version>${project.parent.version}</version>
+          <scope>system</scope>
+          <systemPath>${jni-jar}</systemPath>
+        </dependency>
+      </dependencies>
+    </profile>
+  </profiles>
+
+  <parent>
+    <groupId>org.apache.qpid</groupId>
+    <artifactId>proton-project</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+</project>
diff --git a/tests/proton-test b/tests/python/proton-test
similarity index 100%
rename from tests/proton-test
rename to tests/python/proton-test
diff --git a/tests/proton_tests/__init__.py b/tests/python/proton_tests/__init__.py
similarity index 100%
rename from tests/proton_tests/__init__.py
rename to tests/python/proton_tests/__init__.py
diff --git a/tests/proton_tests/codec.py b/tests/python/proton_tests/codec.py
similarity index 100%
rename from tests/proton_tests/codec.py
rename to tests/python/proton_tests/codec.py
diff --git a/tests/proton_tests/common.py b/tests/python/proton_tests/common.py
similarity index 100%
rename from tests/proton_tests/common.py
rename to tests/python/proton_tests/common.py
diff --git a/tests/proton_tests/engine.py b/tests/python/proton_tests/engine.py
similarity index 100%
rename from tests/proton_tests/engine.py
rename to tests/python/proton_tests/engine.py
diff --git a/tests/proton_tests/message.py b/tests/python/proton_tests/message.py
similarity index 100%
rename from tests/proton_tests/message.py
rename to tests/python/proton_tests/message.py
diff --git a/tests/proton_tests/messenger.py b/tests/python/proton_tests/messenger.py
similarity index 100%
rename from tests/proton_tests/messenger.py
rename to tests/python/proton_tests/messenger.py
diff --git a/tests/proton_tests/sasl.py b/tests/python/proton_tests/sasl.py
similarity index 100%
rename from tests/proton_tests/sasl.py
rename to tests/python/proton_tests/sasl.py
diff --git a/tests/proton_tests/ssl.py b/tests/python/proton_tests/ssl.py
similarity index 100%
rename from tests/proton_tests/ssl.py
rename to tests/python/proton_tests/ssl.py
diff --git a/tests/proton_tests/ssl_db/README.txt b/tests/python/proton_tests/ssl_db/README.txt
similarity index 100%
rename from tests/proton_tests/ssl_db/README.txt
rename to tests/python/proton_tests/ssl_db/README.txt
diff --git a/tests/proton_tests/ssl_db/bad-server-certificate.pem b/tests/python/proton_tests/ssl_db/bad-server-certificate.pem
similarity index 100%
rename from tests/proton_tests/ssl_db/bad-server-certificate.pem
rename to tests/python/proton_tests/ssl_db/bad-server-certificate.pem
diff --git a/tests/proton_tests/ssl_db/bad-server-private-key.pem b/tests/python/proton_tests/ssl_db/bad-server-private-key.pem
similarity index 100%
rename from tests/proton_tests/ssl_db/bad-server-private-key.pem
rename to tests/python/proton_tests/ssl_db/bad-server-private-key.pem
diff --git a/tests/proton_tests/ssl_db/ca-certificate.pem b/tests/python/proton_tests/ssl_db/ca-certificate.pem
similarity index 100%
rename from tests/proton_tests/ssl_db/ca-certificate.pem
rename to tests/python/proton_tests/ssl_db/ca-certificate.pem
diff --git a/tests/proton_tests/ssl_db/client-certificate.pem b/tests/python/proton_tests/ssl_db/client-certificate.pem
similarity index 100%
rename from tests/proton_tests/ssl_db/client-certificate.pem
rename to tests/python/proton_tests/ssl_db/client-certificate.pem
diff --git a/tests/proton_tests/ssl_db/client-private-key.pem b/tests/python/proton_tests/ssl_db/client-private-key.pem
similarity index 100%
rename from tests/proton_tests/ssl_db/client-private-key.pem
rename to tests/python/proton_tests/ssl_db/client-private-key.pem
diff --git a/tests/proton_tests/ssl_db/server-certificate.pem b/tests/python/proton_tests/ssl_db/server-certificate.pem
similarity index 100%
rename from tests/proton_tests/ssl_db/server-certificate.pem
rename to tests/python/proton_tests/ssl_db/server-certificate.pem
diff --git a/tests/proton_tests/ssl_db/server-private-key.pem b/tests/python/proton_tests/ssl_db/server-private-key.pem
similarity index 100%
rename from tests/proton_tests/ssl_db/server-private-key.pem
rename to tests/python/proton_tests/ssl_db/server-private-key.pem
diff --git a/tests/proton_tests/ssl_db/server-wc-certificate.pem b/tests/python/proton_tests/ssl_db/server-wc-certificate.pem
similarity index 100%
rename from tests/proton_tests/ssl_db/server-wc-certificate.pem
rename to tests/python/proton_tests/ssl_db/server-wc-certificate.pem
diff --git a/tests/proton_tests/ssl_db/server-wc-private-key.pem b/tests/python/proton_tests/ssl_db/server-wc-private-key.pem
similarity index 100%
rename from tests/proton_tests/ssl_db/server-wc-private-key.pem
rename to tests/python/proton_tests/ssl_db/server-wc-private-key.pem
diff --git a/tests/proton_tests/transport.py b/tests/python/proton_tests/transport.py
similarity index 100%
rename from tests/proton_tests/transport.py
rename to tests/python/proton_tests/transport.py