Initial commit of etch c-binding. 
The main parts are
- etch c-binding runtime
- etch c-binding compiler
- etch c-binding examples
- changes to etch config files to include also the c-binding

git-svn-id: https://svn.apache.org/repos/asf/incubator/etch/branches/etch-c@966314 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/NOTICE.txt b/NOTICE.txt
index ad3daf3..9fac40f 100644
--- a/NOTICE.txt
+++ b/NOTICE.txt
@@ -2,6 +2,7 @@
 
 Copyright (C) 2008-2009 The Apache Software Foundation
 Copyright (C) 2007-2008 Cisco Systems Inc.
+Copyright (C) 2009-2010 BMW Car IT GmbH
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/binding-c/build.xml b/binding-c/build.xml
new file mode 100644
index 0000000..5b24337
--- /dev/null
+++ b/binding-c/build.xml
@@ -0,0 +1,78 @@
+<?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 name="etch-c-binding" basedir="." default="help">
+    <description>Etch-to-C Binding</description>
+    <property name="Etch.basedir" location="${basedir}/.." />
+    <import file="${Etch.basedir}/build-support/etch.common.xml" />
+
+    <!-- standard, supported targets -->
+    <target name="Debug"         depends="debug" />
+    <target name="Release"       depends="release" />
+    <target name="Clean"         depends="clean" />
+    <target name="debug"         depends="init-debug,component-all,post-debug"   />
+    <target name="release"       depends="init-release,component-all,post-release" />
+    <target name="clean"         depends="init-clean,component-all,post-clean" />
+    <target name="maven-install" depends="init-maven,release" />
+
+    <target name="init-maven" >
+        <property name="DO.maven.install" value="true" />
+    </target>
+
+    <target name="validate-dependencies" >
+        <mkdir dir="${Etch.logDirectory}" />
+    </target>
+
+    <target name="init-debug" depends="validate-dependencies" >
+        <property name="Etch.build.target" value="Debug" />
+        <property name="Etch.javac.debug" value="on" />
+        <property name="Etch.javac.optimize" value="off" />
+    </target>
+
+    <target name="post-debug" >
+    </target>
+
+    <target name="init-release" depends="validate-dependencies">
+        <!-- For now, keep debug-symbols and no-optimize, even for release builds -->
+        <property name="Etch.build.target" value="Release" />
+        <property name="Etch.javac.debug"  value="on" />
+        <property name="Etch.javac.optimize" value="off" />
+        <!--
+        <property name="Etch.javac.debug"  value="off" />
+        <property name="Etch.javac.optimize" value="on" />
+        -->
+    </target>
+    
+    <target name="post-release" >
+    </target>
+
+    <target name="init-clean" depends="validate-dependencies">
+        <property name="Etch.build.target" value="Clean" />
+    </target>
+
+    <target name="post-clean" >
+        <echo message="Executing clean" />
+    </target>
+
+    <target name="component-all" >
+        <build_component dir="compiler" />
+        <!--<build_component dir="runtime" />-->
+    </target>
+
+</project>
diff --git a/binding-c/compiler/build.xml b/binding-c/compiler/build.xml
new file mode 100644
index 0000000..20a77f8
--- /dev/null
+++ b/binding-c/compiler/build.xml
@@ -0,0 +1,227 @@
+<?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 name="etch-c-compiler" basedir="." default="help">
+    <description>Etch-to-C compiler implementation</description>
+    <property name="Etch.basedir" location="${basedir}/../.." />
+    <import file="${Etch.basedir}/build-support/etch.includes.xml" />
+
+    <!-- Static properties of the sub-project -->
+    <property name="proj"                 location="${Etch.basedir}/binding-c/compiler" />
+    <property name="target"               location="${proj}/target" />
+    <property name="src"                  location="${proj}/src" />        
+    <property name="generatedSrc"         location="${target}/generated-sources" />
+    <property name="classesDirectory"     location="${target}/classes" />
+    <property name="resourcesDirectory"   location="${target}/resources" />
+    <property name="testResultsDirectory" location="${target}/test-results" />
+
+    <!-- MACRO: init-target -->
+    <macrodef name="init-target" >
+        <sequential>
+            <delete dir="${classesDirectory}"   failonerror="false" quiet="true" />
+            <delete dir="${resourcesDirectory}" failonerror="false" quiet="true" />
+            <mkdir dir="${classesDirectory}" />
+            <mkdir dir="${classesDirectory}/main" />
+            <mkdir dir="${classesDirectory}/test" />
+            <mkdir dir="${resourcesDirectory}" />
+        </sequential>
+    </macrodef>
+
+    <!-- MACRO: compile-sources -->
+    <macrodef name="compile-sources" >
+        <sequential>            
+            <!-- compile compiler plugin -->
+            <javac  debug="${Etch.javac.debug}"
+                    target="1.5"
+                    optimize="${Etch.javac.optimize}"
+                    destdir="${classesDirectory}/main" >
+                <src path="${src}/main/java" />
+                <exclude name="**/.svn/**" />
+                <classpath refid="Etch.dependencies.jar.paths" />
+                <classpath>
+                    <pathelement location="${Etch.HOME}/lib/${etch-compiler.jar}" />
+                </classpath>
+            </javac>
+
+            <!-- compiler plugin resources -->
+            <copy todir="${classesDirectory}/main" >
+                <fileset dir="${src}/main/resources">
+                    <include name="**/*.kwd" />
+                    <include name="**/*.vm" />
+                </fileset>
+            </copy>
+
+            <!--
+            <javac  debug="${Etch.javac.debug}"
+                    target="1.5"
+                    optimize="${Etch.javac.optimize}"
+                    destdir="${classesDirectory}/test" >
+                <src path="${src}/test/java" />
+                <exclude name="**/.svn/**" />
+                <classpath refid="Etch.dependencies.jar.paths" />
+                <classpath>
+                    <pathelement location="${classesDirectory}/main" />
+                    <pathelement location="${Etch.HOME}/lib/${etch-compiler.jar}" />
+                </classpath>
+            </javac>
+            -->
+
+        </sequential>
+    </macrodef>
+    
+    <!-- MACRO: bundle-jars -->
+    <macrodef name="bundle-jars" >
+        <attribute name="dist" default="${Etch.dist}" />
+        <sequential>
+            <mkdir dir="@{dist}/lib" />
+            
+            <!-- CREATE jars -->
+
+            <!-- Package up etch-java-compiler jar -->
+            <jar jarfile="@{dist}/lib/${etch-c-compiler.jar}" >
+                <manifest>
+                    <attribute name="Copyright"    value="${Etch.copyrightNotice}" />
+                    <attribute name="Version"      value="${Etch.version}" />
+                    <attribute name="LongVersion"  value="${Etch.longversion}" />
+                    <attribute name="Build-Tag"    value="${Etch.buildTag}" />
+                    <attribute name="SVN-Revision" value="${Etch.runtime.revisionNumber}" />
+                </manifest>
+                <metainf dir="${Etch.basedir}" >
+                    <include name="NOTICE.txt" />
+                    <include name="LICENSE.txt" />
+                </metainf>
+                <fileset dir="${classesDirectory}/main">
+                    <include name="org/apache/etch/bindings/**" />
+                    <!-- <include name="resources/**" /> -->
+                </fileset>
+            </jar>
+
+            <!-- CREATE source archives -->
+            
+            <!-- package up etch-java-compiler src -->
+            <zip destfile="@{dist}/lib/${etch-c-compiler-src.zip}" >
+                <fileset dir="${src}/main/java" >
+                    <include name="org/apache/etch/bindings/**/*.java" />
+                </fileset>
+                <fileset dir="${src}/main/resources" >
+                    <include name="**/*" />
+                </fileset>
+            </zip>
+
+        </sequential>
+    </macrodef>
+    
+    <!-- INIT TARGET -->
+    <!-- Modify this target to define project specific properties that can only be set at runtime -->
+    <target name="do-init">
+        <delete dir="${target}" failonerror="false" quiet="true" />
+
+        <mkdir dir="${target}" />
+        <mkdir dir="${generatedSrc}" />
+        <mkdir dir="${classesDirectory}" />
+        <mkdir dir="${resourcesDirectory}" />
+        <mkdir dir="${testResultsDirectory}" />
+    </target>
+
+    <!-- CLEAN TARGET -->
+    <target name="do-clean">
+        <delete dir="${target}" />
+    </target>
+
+    <!-- BUILD TARGET -->
+    
+    <target name="generate-sources" >
+        <!-- Generate version info -->
+        <update-tokens filename="${src}/main/java/org/apache/etch/bindings/c/compiler/CompilerVersion.java" />  
+    </target>
+
+    <target name="compile-for-dist" >
+        <!-- Initialize target directories -->
+        <init-target />
+
+        <!-- Compile Source -->
+        <compile-sources />
+
+        <!-- Bundle Jars -->
+        <bundle-jars dist="${Etch.dist}" />
+    </target>
+    
+    <target name="compile-for-clover" if="Clover.enabled" >
+
+        <echo message="Rebuilding with clover" />
+
+        <!-- initialize-clover -->
+        <initialize-clover suffix="etchccompiler" >
+            <fileset dir="${src}/main/java">
+                <include name="**/*.java" />
+            </fileset>
+            <!--
+            <testsources dir="${src}/test/java">
+                <include name="**/*.java" />
+            </testsources>
+            -->
+        </initialize-clover>
+        
+        <!-- Initialize target directories -->
+        <init-target />
+        
+        <!-- Compile Source -->
+        <compile-sources />
+        
+        <!-- Bundle Jars -->
+        <bundle-jars dist="${Etch.clover-dist}" />
+
+    </target>
+    
+    <target name="do-build" depends="generate-sources,compile-for-dist,compile-for-clover" />
+
+    <!-- TEST TARGET -->
+    <target name="do-test">
+        
+        <!-- Run Unit Tests -->
+        <!--
+        <junit printsummary="yes" haltonfailure="no" dir="${classesDirectory}"
+            errorProperty="build.tests.fail" failureProperty="build.tests.fail">
+            <classpath>
+                <pathelement location="${classesDirectory}/main" />
+                <pathelement location="${classesDirectory}/test" />
+                <pathelement location="${Etch.dependency.junit.jar}" />
+                <pathelement location="${Etch.HOME}/lib/${etch-compiler.jar}" />
+                <pathelement location="${Etch.dependency.clover.jar}"/>
+            </classpath>
+            <formatter type="xml"/>
+            <batchtest fork="true" todir="${testResultsDirectory}">
+                <fileset dir="${src}/test/java">
+                    <include name="**/*.java" />
+                </fileset>
+            </batchtest>
+        </junit>
+        -->
+    </target>
+
+    <!-- POSTBUILD TARGET -->
+    <target name="do-postbuild">
+    </target>
+
+    <target name="do-publish" if="build.tests.fail">
+        <!-- Set flag file if any tests failed -->
+        <touch file="${Etch.runtime.tests.fail}"/>
+    </target>
+
+</project>
diff --git a/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/Compiler.java b/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/Compiler.java
new file mode 100644
index 0000000..6ace32b
--- /dev/null
+++ b/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/Compiler.java
@@ -0,0 +1,1837 @@
+/* $Id$
+ *
+ * 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.etch.bindings.c.compiler;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.etch.compiler.Backend;
+import org.apache.etch.compiler.CmdLineOptions;
+import org.apache.etch.compiler.EtchGrammar;
+import org.apache.etch.compiler.EtchGrammarConstants;
+import org.apache.etch.compiler.EtchHelper;
+import org.apache.etch.compiler.LogHandler;
+import org.apache.etch.compiler.Output;
+import org.apache.etch.compiler.ParseException;
+import org.apache.etch.compiler.Token;
+import org.apache.etch.compiler.Version;
+import org.apache.etch.compiler.ast.Builtin;
+import org.apache.etch.compiler.ast.Except;
+import org.apache.etch.compiler.ast.Item;
+import org.apache.etch.compiler.ast.Message;
+import org.apache.etch.compiler.ast.MessageDirection;
+import org.apache.etch.compiler.ast.Module;
+import org.apache.etch.compiler.ast.MsgDirHelper;
+import org.apache.etch.compiler.ast.Name;
+import org.apache.etch.compiler.ast.Named;
+import org.apache.etch.compiler.ast.ParamList;
+import org.apache.etch.compiler.ast.Parameter;
+import org.apache.etch.compiler.ast.ReservedWordChecker;
+import org.apache.etch.compiler.ast.Service;
+import org.apache.etch.compiler.ast.Struct;
+import org.apache.etch.compiler.ast.Thrown;
+import org.apache.etch.compiler.ast.TypeRef;
+import org.apache.etch.compiler.opt.ToString;
+import org.apache.etch.compiler.opt.ToString.FieldItem;
+import org.apache.etch.compiler.opt.ToString.FmtItem;
+import org.apache.etch.compiler.opt.ToString.StringItem;
+import org.apache.etch.util.Assertion;
+import org.apache.etch.util.Hash;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.exception.ResourceNotFoundException;
+import org.apache.velocity.runtime.RuntimeServices;
+import org.apache.velocity.runtime.log.LogChute;
+
+/**
+ * Compiler is a helper class not only for Backend, but also for the templates.
+ * They call methods here to perform "hard" tasks.
+ */
+public class Compiler extends Backend {
+
+	private final static String tmplPath1 = "org/apache/etch/bindings/c/compiler/";
+
+	private final static String tmplPath2 = "resources/org/apache/etch/bindings/c/compiler/";
+
+	private final static String fnSuffixH = ".h";
+	private final static String fnSuffixI = ".c";
+
+	private final static String VERSION = Version.VERSION + " / "
+			+ CompilerVersion.VERSION;
+
+	/**
+	 * Constructs the Compiler. This is a helper class not only for Backend, but
+	 * also for the templates. They call methods here to perform "hard" tasks.
+	 * 
+	 * @throws Exception
+	 */
+	public Compiler() throws Exception {
+		initVelocity();
+
+		String[] path = { tmplPath1, tmplPath2 };
+
+		// value factory templates
+		vf_h_vm = getTemplate(path, "vf_h.vm");
+		vf_c_vm = getTemplate(path, "vf_c.vm");
+
+		// interface templates
+		intf_h_vm = getTemplate(path, "intf_h.vm");
+		intf_c_vm = getTemplate(path, "intf_c.vm");
+		implx_c_vm = getTemplate(path, "implx_c.vm");
+
+		// remote interface templates
+		remote_h_vm = getTemplate(path, "remote_h.vm");
+		remote_c_vm = getTemplate(path, "remote_c.vm");
+		remote_server_h_vm = getTemplate(path, "remote_server_h.vm");
+		remote_server_c_vm = getTemplate(path, "remote_server_c.vm");
+		remote_client_h_vm = getTemplate(path, "remote_client_h.vm");
+		remote_client_c_vm = getTemplate(path, "remote_client_c.vm");
+
+		// interface stub templates
+		stub_h_vm = getTemplate(path, "stub_h.vm");
+		stub_c_vm = getTemplate(path, "stub_c.vm");
+
+		// helper templates
+		helper_h_vm = getTemplate(path, "helper_h.vm");
+		helper_c_vm = getTemplate(path, "helper_c.vm");
+
+		// readme template
+		readme_vm = getTemplate(path, "readme.vm");
+
+		// Main template
+		main_h_vm = getTemplate(path, "main_h.vm");
+		main_c_vm = getTemplate(path, "main_c.vm");
+
+		// Base template
+		base_h_vm = getTemplate(path, "base_h.vm");
+		base_c_vm = getTemplate(path, "base_c.vm");
+
+		// Implementation template
+		impl_h_vm = getTemplate(path, "impl_h.vm");
+		impl_c_vm = getTemplate(path, "impl_c.vm");
+
+		etch_keywords_vm = getTemplate(path, "etch_keywords.vm");
+		
+		// Keyword list
+		local_kwd = getPath(path, "cKeywords.kwd");
+	}
+
+	// Value Factory
+	private final Template vf_h_vm;
+	private final Template vf_c_vm;
+
+	// interface templates
+	private final Template intf_h_vm;
+	private final Template intf_c_vm;
+
+	// remote interface templates
+	private final Template remote_h_vm;
+	private final Template remote_c_vm;
+	private final Template remote_server_h_vm;
+	private final Template remote_server_c_vm;
+	private final Template remote_client_h_vm;
+	private final Template remote_client_c_vm;
+
+	// interface stub templates
+	private final Template stub_h_vm;
+	private final Template stub_c_vm;
+
+	// helper templates
+	private final Template helper_h_vm;
+	private final Template helper_c_vm;
+
+	// readme template
+	private final Template readme_vm;
+
+	// Main template
+	private final Template main_h_vm;
+	private final Template main_c_vm;
+
+	// Base template
+	private final Template base_h_vm;
+	private final Template base_c_vm;
+
+	// Implementation template
+	private final Template impl_h_vm;
+	private final Template impl_c_vm;
+	private final Template implx_c_vm;
+
+	private final Template etch_keywords_vm;
+	
+	private final String local_kwd;
+
+	private LogHandler lh;
+
+	/**
+	 * Initializes use of velocity engine and sets up resource loaders.
+	 * 
+	 * @throws Exception
+	 */
+	private void initVelocity() throws Exception {
+		Velocity.setProperty(Velocity.RUNTIME_LOG_LOGSYSTEM, new MyLogger());
+
+		Velocity.setProperty(Velocity.RESOURCE_LOADER, "file, class");
+
+		Velocity.setProperty("file.resource.loader.description",
+				"Velocity File Resource Loader");
+		Velocity
+				.setProperty("file.resource.loader.class",
+						"org.apache.velocity.runtime.resource.loader.FileResourceLoader");
+		Velocity.setProperty("file.resource.loader.path", ".");
+		Velocity.setProperty("class.resource.loader.description",
+				"Velocity Classpath Resource Loader");
+		Velocity
+				.setProperty("class.resource.loader.class",
+						"org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+		Velocity.init();
+	}
+
+	private static class MyLogger implements LogChute {
+		private final LogHandler lh = null;
+
+		public void init(RuntimeServices rts) throws Exception {
+			// ignore.
+		}
+
+		public boolean isLevelEnabled(int level) {
+			return level >= 2;
+		}
+
+		public void log(int level, String msg) {
+			if (level < 2)
+				return;
+
+			if (lh != null)
+				lh.report(level == 2 ? LogHandler.LEVEL_WARNING
+						: LogHandler.LEVEL_ERROR, null, msg);
+			else
+				System.out.printf("Velocity msg (%d): %s\n", level, msg);
+		}
+
+		public void log(int level, String msg, Throwable e) {
+			if (level < 2)
+				return;
+
+			if (lh != null)
+				lh.report(level == 2 ? LogHandler.LEVEL_WARNING
+						: LogHandler.LEVEL_ERROR, null, msg);
+			else
+				System.out.printf("Velocity msg (%d): %s: %s\n", level, msg, e);
+		}
+	}
+
+	/**
+	 * @param path
+	 * @param fn
+	 * @return the velocity template
+	 * @throws Exception
+	 */
+	private Template getTemplate(String[] path, String fn) throws Exception {
+		ResourceNotFoundException rnfe = null;
+
+		for (String p : path) {
+			if (p == null)
+				continue;
+
+			// System.out.println( "trying to load template "+(p+fn) );
+			try {
+				if (Velocity.resourceExists(p + fn))
+					return Velocity.getTemplate(p + fn);
+			} catch (ResourceNotFoundException e) {
+				rnfe = e;
+			} catch (Exception e) {
+				System.out.println("ignoring " + e);
+			}
+		}
+
+		if (rnfe != null)
+			throw rnfe;
+
+		throw new ResourceNotFoundException("could not find resource: " + fn);
+	}
+
+	@Override
+	public void generate(Module module, CmdLineOptions options)
+			throws Exception {
+		// java always wants to not flatten packages:
+		options.noFlattenPackages = true;
+
+		lh = options.lh;
+
+		boolean ignoreGlobal = options.ignoreGlobalWordsList;
+		boolean ignoreLocal = options.ignoreLocalWordsList;
+		String userWords = options.userWordsList != null ? options.userWordsList
+				.getPath()
+				: null;
+		Set<String> what = options.what;
+
+		// Load the reserved words lists if any have been provided.
+		Map<String, String> words = new HashMap<String, String>();
+		if (!ignoreGlobal)
+			mapWords(global_kwd, words);
+		if (!ignoreLocal)
+			mapWords(local_kwd, words);
+		if (userWords != null)
+			mapWords(userWords, words);
+
+		// check for collisions with the reserved word list.
+		ReservedWordChecker checker = new ReservedWordChecker(words, false, lh);
+		module.treewalk(checker);
+		if (!checker.ok()) {
+			lh.report(LogHandler.LEVEL_ERROR, null,
+					"Encountered errors during c generation.");
+			return;
+		}
+
+		// ok, we're ready to generate code. make sure the
+		// output directories exist.
+
+		Output dir = options.output;
+		Output templateDir = options.templateOutput;
+
+		// generate code for each service.
+
+		for (Service intf : module) {
+			generate(intf, what, dir, templateDir);
+		}
+	}
+
+	public boolean isGenerateImpl() {
+		return isGenerateImpl;
+	}
+
+	public boolean isGenerateMain() {
+		return isGenerateMain;
+	}
+
+	boolean isGenerateImpl;
+	boolean isGenerateMain;
+
+	private void generate(final Service intf, Set<String> what, Output dir,
+			Output templateDir) throws Exception {
+		what = populateWhat(what);
+
+		if (what.isEmpty()) {
+			return;
+		}
+
+		final MessageDirection msgDir = getMessageDirection(what);
+
+		if (what.contains(WHAT_INTF)) {
+			// Generate the value factory file.
+
+			generateVf(intf, dir);
+
+			// Generate the interface, remote, and stub files.
+			generateIntfRemoteStub(intf, dir, msgDir, MessageDirection.BOTH,
+					false);
+			generateIntfRemoteStub(intf, dir, msgDir, MessageDirection.SERVER,
+					true);
+			generateIntfRemoteStub(intf, dir, msgDir, MessageDirection.CLIENT,
+					true);
+
+			// Generate helper file.
+			generateHelper(intf, dir, msgDir);
+
+			// Generate base file.
+			generateBase(intf, dir, msgDir, MessageDirection.SERVER, true);
+			generateBase(intf, dir, msgDir, MessageDirection.CLIENT, true);
+
+			// Generate readme file.
+			generateReadme(intf, dir, msgDir);
+			
+			generateKeywordList(intf, dir, msgDir, MessageDirection.BOTH, true);
+		}
+
+		// Generate main template file.
+		if (what.contains(WHAT_MAIN)) {
+			isGenerateMain = true;
+			generateMain(intf, templateDir, msgDir);
+		}
+
+		// Generate impl template file.
+		if (what.contains(WHAT_IMPL)) {
+			isGenerateImpl = true;
+			generateImpl(intf, templateDir, msgDir);
+		}
+	}
+
+	private void generateReadme(final Service intf, Output dir,
+			final MessageDirection msgDir) throws Exception {
+		doFile(dir, "readme-etch-c-files.txt", lh, new Gen() {
+			public void run(PrintWriter pw) throws Exception {
+				generateReadme(pw, intf, msgDir);
+			}
+		});
+	}
+
+	private void generateVf(final Service intf, Output dir) throws Exception {
+
+		doFile(dir, getVfName(intf) + fnSuffixH, lh, new Gen() {
+			public void run(PrintWriter pw) throws Exception {
+				generateVfH(pw, intf);
+			}
+		});
+
+		doFile(dir, getVfName(intf) + fnSuffixI, lh, new Gen() {
+			public void run(PrintWriter pw) throws Exception {
+				generateVfI(pw, intf);
+			}
+		});
+
+	}
+
+	private void generateHelper(final Service intf, Output dir,
+			final MessageDirection msgDir) throws Exception {
+		doFile(dir, getHelperName(intf) + fnSuffixH, lh, new Gen() {
+			public void run(PrintWriter pw) throws Exception {
+				generateHelperH(pw, intf, msgDir);
+			}
+		});
+
+		doFile(dir, getHelperName(intf) + fnSuffixI, lh, new Gen() {
+			public void run(PrintWriter pw) throws Exception {
+				generateHelperI(pw, intf, msgDir);
+			}
+		});
+
+	}
+
+	private void generateMain(final Service intf, Output dir,
+			MessageDirection msgDir) throws Exception {
+		if (msgDir == MessageDirection.BOTH
+				|| msgDir == MessageDirection.CLIENT) {
+			doFile(dir, getMainName(intf, MessageDirection.CLIENT) + fnSuffixH,
+					lh, new Gen() {
+						public void run(PrintWriter pw) throws Exception {
+							generateMainH(pw, intf, MessageDirection.CLIENT,
+									false);
+						}
+					});
+
+			doFile(dir, getMainName(intf, MessageDirection.CLIENT) + fnSuffixI,
+					lh, new Gen() {
+						public void run(PrintWriter pw) throws Exception {
+							generateMainI(pw, intf, MessageDirection.CLIENT,
+									false);
+						}
+					});
+
+		}
+
+		if (msgDir == MessageDirection.BOTH
+				|| msgDir == MessageDirection.SERVER) {
+			doFile(dir, getMainName(intf, MessageDirection.SERVER) + fnSuffixH,
+					lh, new Gen() {
+						public void run(PrintWriter pw) throws Exception {
+							generateMainH(pw, intf, MessageDirection.SERVER,
+									false);
+						}
+					});
+
+			doFile(dir, getMainName(intf, MessageDirection.SERVER) + fnSuffixI,
+					lh, new Gen() {
+						public void run(PrintWriter pw) throws Exception {
+							generateMainI(pw, intf, MessageDirection.SERVER,
+									false);
+						}
+					});
+		}
+	}
+
+	private void generateKeywordList(final Service intf, Output dir,
+			final MessageDirection what, final MessageDirection mc,
+			final boolean hasBaseClass) throws Exception {
+		doFile(dir, getKeywordFilename(intf), lh,
+				new Gen() {
+					public void run(PrintWriter pw) throws Exception {
+						generateKeywords(pw, intf, mc, hasBaseClass);
+					}
+				});
+	}
+	
+	private void generateBase(final Service intf, Output dir,
+			final MessageDirection what, final MessageDirection mc,
+			final boolean hasBaseClass) throws Exception {
+		doFile(dir, getBaseFileNameH(intf, getDirectionName(mc)), lh,
+				new Gen() {
+					public void run(PrintWriter pw) throws Exception {
+						generateBaseH(pw, intf, mc, hasBaseClass);
+					}
+				});
+
+		doFile(dir, getBaseFileNameI(intf, getDirectionName(mc)), lh,
+				new Gen() {
+					public void run(PrintWriter pw) throws Exception {
+						generateBaseI(pw, intf, mc, hasBaseClass);
+					}
+				});
+	}
+
+	private void generateImpl(final Service intf, Output dir,
+			MessageDirection msgDir) throws Exception {
+		if (msgDir == MessageDirection.BOTH
+				|| msgDir == MessageDirection.CLIENT) {
+			doFile(dir, getImplFileNameH(intf,
+					getDirectionName(MessageDirection.CLIENT)), lh, new Gen() {
+				public void run(PrintWriter pw) throws Exception {
+					generateImplH(pw, intf, MessageDirection.CLIENT, false);
+				}
+			});
+
+			doFile(dir, getImplFileNameI(intf,
+					getDirectionName(MessageDirection.CLIENT)), lh, new Gen() {
+				public void run(PrintWriter pw) throws Exception {
+					generateImplI(pw, intf, MessageDirection.CLIENT, false);
+				}
+			});
+
+			doFile(dir, getImplXFileNameI(intf,
+					getDirectionName(MessageDirection.CLIENT)), lh, new Gen() {
+				public void run(PrintWriter pw) throws Exception {
+					generateImplXI(pw, intf, MessageDirection.CLIENT, false);
+				}
+			});
+		}
+
+		if (msgDir == MessageDirection.BOTH
+				|| msgDir == MessageDirection.SERVER) {
+			doFile(dir, getImplFileNameH(intf,
+					getDirectionName(MessageDirection.SERVER)), lh, new Gen() {
+				public void run(PrintWriter pw) throws Exception {
+					generateImplH(pw, intf, MessageDirection.SERVER, false);
+				}
+			});
+
+			doFile(dir, getImplFileNameI(intf,
+					getDirectionName(MessageDirection.SERVER)), lh, new Gen() {
+				public void run(PrintWriter pw) throws Exception {
+					generateImplI(pw, intf, MessageDirection.SERVER, false);
+				}
+			});
+
+			doFile(dir, getImplXFileNameI(intf,
+					getDirectionName(MessageDirection.SERVER)), lh, new Gen() {
+				public void run(PrintWriter pw) throws Exception {
+					generateImplXI(pw, intf, MessageDirection.SERVER, false);
+				}
+			});
+		}
+
+	}
+
+	private void generateIntfRemoteStub(final Service intf, Output dir,
+			final MessageDirection what, final MessageDirection mc,
+			final boolean hasBaseClass) throws Exception {
+		// Generate interface file
+
+		if (mc == MessageDirection.BOTH) {
+			doFile(dir, getIntfFileNameH(intf), lh, new Gen() {
+				public void run(PrintWriter pw) throws Exception {
+					generateIntfH(pw, intf, mc, hasBaseClass);
+				}
+			});
+
+			doFile(dir, getIntfFileNameI(intf), lh, new Gen() {
+				public void run(PrintWriter pw) throws Exception {
+					generateIntfI(pw, intf, mc, hasBaseClass);
+				}
+			});
+		}
+
+		// Generate remote file
+
+		if (mc == MessageDirection.BOTH || what == MessageDirection.BOTH
+				|| mc != what) {
+			doFile(dir, getRemoteFileNameH(intf, getDirectionName(mc)), lh,
+					new Gen() {
+						public void run(PrintWriter pw) throws Exception {
+							generateRemoteH(pw, intf, mc, hasBaseClass);
+						}
+					});
+
+			doFile(dir, getRemoteFileNameI(intf, getDirectionName(mc)), lh,
+					new Gen() {
+						public void run(PrintWriter pw) throws Exception {
+							generateRemoteI(pw, intf, mc, hasBaseClass);
+						}
+					});
+		}
+
+		// Generate stub file
+
+		if (mc != what) {
+			doFile(dir, getStubFileNameH(intf, getDirectionName(mc)), lh,
+					new Gen() {
+						public void run(PrintWriter pw) throws Exception {
+							generateStubH(pw, intf, mc, hasBaseClass);
+						}
+					});
+
+			doFile(dir, getStubFileNameI(intf, getDirectionName(mc)), lh,
+					new Gen() {
+						public void run(PrintWriter pw) throws Exception {
+							generateStubI(pw, intf, mc, hasBaseClass);
+						}
+					});
+		}
+	}
+
+	/**
+	 * Generate the value factory header for the service.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @throws Exception
+	 */
+	void generateVfH(PrintWriter pw, Service intf) throws Exception {
+		// params keeps track of the total set of parameters
+		// named (for enums, structs, exceptions, and messages).
+		Set<String> params = new HashSet<String>();
+
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("params", params);
+		vf_h_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generate the value factory implementation for the service.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @throws Exception
+	 */
+	void generateVfI(PrintWriter pw, Service intf) throws Exception {
+		// params keeps track of the total set of parameters
+		// named (for enums, structs, exceptions, and messages).
+		Set<String> params = new HashSet<String>();
+
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("params", params);
+		vf_c_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generate the interface header for the service.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateIntfH(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		intf_h_vm.merge(context, pw);
+
+	}
+
+	/**
+	 * Generate the interface implementation for the service.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateIntfI(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		intf_c_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generate the call to message implementation of the interface. This class
+	 * turns calls on its methods into messages which are sent to the remote
+	 * stub. For two-way calls, it then waits for a response message, returning
+	 * the result therein to the caller.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateRemoteH(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		context.put("methodList", new ArrayList<String>());
+		switch (mc) {
+		case BOTH:
+			remote_h_vm.merge(context, pw);
+			break;
+		case SERVER:
+			remote_server_h_vm.merge(context, pw);
+			break;
+		case CLIENT:
+			remote_client_h_vm.merge(context, pw);
+			break;
+		default:
+			break;
+		}
+	}
+
+	/**
+	 * Generate the call to message implementation of the interface. This class
+	 * turns calls on its methods into messages which are sent to the remote
+	 * stub. For two-way calls, it then waits for a response message, returning
+	 * the result therein to the caller.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateRemoteI(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		context.put("methodList", new ArrayList<String>());
+		switch (mc) {
+		case BOTH:
+			remote_c_vm.merge(context, pw);
+			break;
+		case SERVER:
+			remote_server_c_vm.merge(context, pw);
+			break;
+		case CLIENT:
+			remote_client_c_vm.merge(context, pw);
+			break;
+		default:
+			break;
+		}
+	}
+
+	/**
+	 * Generate the message to call implementation. This class accepts a message
+	 * and turns it back into a call on the user's implementation. For two-way
+	 * messages, the return value from the user's implementation method is
+	 * turned into the appropriate response message and sent.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateStubH(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("suffix_remote", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		stub_h_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generate the message to call implementation. This class accepts a message
+	 * and turns it back into a call on the user's implementation. For two-way
+	 * messages, the return value from the user's implementation method is
+	 * turned into the appropriate response message and sent.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateStubI(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("suffix_remote", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		stub_c_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generate the transport plumbing helper.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @throws Exception
+	 */
+	void generateHelperH(PrintWriter pw, Service intf, MessageDirection mc)
+			throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		helper_h_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generate the transport plumbing helper.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @throws Exception
+	 */
+	void generateHelperI(PrintWriter pw, Service intf, MessageDirection mc)
+			throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		helper_c_vm.merge(context, pw);
+
+	}
+
+	/**
+	 * Generate the readme.txt.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @throws Exception
+	 */
+	void generateReadme(PrintWriter pw, Service intf, MessageDirection mc)
+			throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+
+		readme_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generate the template main program.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateMainH(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		main_h_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generate the template main program.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateMainI(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		main_c_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generates the base implementation of the interfaces, with each method
+	 * throwing an exception to the tune that it isn't implemented. User's impl
+	 * will extend this base implementation.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateBaseH(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		context.put("methodList", new ArrayList<String>());
+		base_h_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generates the base implementation of the interfaces, with each method
+	 * throwing an exception to the tune that it isn't implemented. User's impl
+	 * will extend this base implementation.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateBaseI(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		context.put("methodList", new ArrayList<String>());
+		base_c_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generate the template user implemention class which extends the base
+	 * implementation generated above. This class will only have the appropriate
+	 * constructor and reference to the appropriate remote, and a comment
+	 * inviting the user to override methods.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateImplH(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		impl_h_vm.merge(context, pw);
+	}
+
+	/**
+	 * Generate the template user implemention class which extends the base
+	 * implementation generated above. This class will only have the appropriate
+	 * constructor and reference to the appropriate remote, and a comment
+	 * inviting the user to override methods.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateImplI(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		impl_c_vm.merge(context, pw);
+	}
+
+	void generateKeywords(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		etch_keywords_vm.merge(context, pw);
+	}
+	
+	/**
+	 * Generate the template user implemention class which extends the base
+	 * implementation generated above. This class will only have the appropriate
+	 * constructor and reference to the appropriate remote, and a comment
+	 * inviting the user to override methods.
+	 * 
+	 * @param pw
+	 * @param intf
+	 * @param mc
+	 * @param hasBaseClass
+	 * @throws Exception
+	 */
+	void generateImplXI(PrintWriter pw, Service intf, MessageDirection mc,
+			boolean hasBaseClass) throws Exception {
+		VelocityContext context = new VelocityContext();
+		context.put("now", new Date());
+		context.put("version", VERSION);
+		context.put("helper", this);
+		context.put("intf", intf);
+		context.put("mc", mc);
+		context.put("suffix", MsgDirHelper.getSuffix(mc).toLowerCase());
+		context.put("hasBaseClass", hasBaseClass);
+		implx_c_vm.merge(context, pw);
+	}
+
+	public String getKeywordForWireshark(String fieldname) {
+		int hash = Hash.hash(fieldname);
+		return String.format("0x%08x", hash) + "," + fieldname;
+		
+	}
+	
+	
+	
+	public MessageDirection getRemoteDirection(MessageDirection mc) {
+		if (mc == MessageDirection.SERVER) {
+			return MessageDirection.CLIENT;
+		}
+		if (mc == MessageDirection.BOTH) {
+			return MessageDirection.BOTH;
+		}
+		return MessageDirection.SERVER;
+	}
+	
+	public String getRemoteDirectionName(MessageDirection mc) {
+
+		return getDirectionName(getRemoteDirection(mc));
+	}
+
+	public boolean hasMessageDirectionBoth(Service intf) {
+		return intf.hasMessageDirection(MessageDirection.BOTH);
+	}
+
+	public boolean isClient(MessageDirection mc) {
+		return mc == MessageDirection.CLIENT || mc == MessageDirection.BOTH;
+	}
+
+	public boolean isServer(MessageDirection mc) {
+		return mc == MessageDirection.SERVER || mc == MessageDirection.BOTH;
+	}
+
+	public String getDirectionName(MessageDirection mc) {
+		return MsgDirHelper.getSuffix(mc).toLowerCase();
+	}
+
+	public MessageDirection getMsgDirServer(){
+		return MessageDirection.SERVER;
+	}
+	
+	public MessageDirection getMsgDirClient(){
+		return MessageDirection.CLIENT;
+	}
+	
+	public String getServiceName(Service intf) {
+		return intf.name().name().toLowerCase();
+	}
+
+	public String getIntfName(Service intf) {
+		return getServiceName(intf);
+	}
+
+	public String getIntfFileNameH(Service intf) {
+		return getIntfName(intf) + "_interface" + fnSuffixH;
+	}
+
+	public String getIntfFileNameI(Service intf) {
+		return getIntfName(intf) + "_interface" + fnSuffixI;
+	}
+
+	public String getBaseName(Service intf, String suffix) {
+		return getServiceName(intf)
+				+ (suffix != null && !suffix.isEmpty() ? "_" + suffix : "");
+	}
+
+	public String getBaseFileNameH(Service intf, String suffix) {
+		return getBaseName(intf, suffix) + fnSuffixH;
+	}
+
+	public String getKeywordFilename(Service intf) {
+		return getServiceName(intf) + "_keywords_wireshark.txt";
+	}
+	
+	public String getBaseFileNameI(Service intf, String suffix) {
+		return getBaseName(intf, suffix) + fnSuffixI;
+	}
+
+	public String getRemoteName(Service intf, String suffix) {
+		return getServiceName(intf) + "_remote"
+				+ (suffix != null && !suffix.isEmpty() ? "_" + suffix : "");
+	}
+
+	public String getRemoteFileNameH(Service intf, String suffix) {
+		return getRemoteName(intf, suffix) + fnSuffixH;
+	}
+
+	public String getRemoteFileNameI(Service intf, String suffix) {
+		return getRemoteName(intf, suffix) + fnSuffixI;
+	}
+
+	public String getStubName(Service intf, String suffix) {
+		return getServiceName(intf)
+				+ (suffix != null && !suffix.isEmpty() ? "_" + suffix : "")
+				+ "_stub";
+	}
+
+	public String getStubFileNameH(Service intf, String suffix) {
+		return getStubName(intf, suffix) + fnSuffixH;
+	}
+
+	public String getStubFileNameI(Service intf, String suffix) {
+		return getStubName(intf, suffix) + fnSuffixI;
+	}
+
+	public String getImplName(Service intf, String suffix) {
+		return getServiceName(intf)
+				+ (suffix != null && !suffix.isEmpty() ? "_" + suffix : "")
+				+ "_impl";
+	}
+
+	public String getImplFileNameH(Service intf, String suffix) {
+		return getImplName(intf, suffix) + fnSuffixH;
+	}
+
+	public String getImplFileNameI(Service intf, String suffix) {
+		return getImplName(intf, suffix) + fnSuffixI;
+	}
+
+	public String getImplXName(Service intf, String suffix) {
+		return getServiceName(intf)
+				+ (suffix != null && !suffix.isEmpty() ? "_" + suffix : "")
+				+ "_implx";
+	}
+
+	public String getImplXFileNameH(Service intf, String suffix) {
+		return getImplXName(intf, suffix) + fnSuffixH;
+	}
+
+	public String getImplXFileNameI(Service intf, String suffix) {
+		return getImplXName(intf, suffix) + fnSuffixI;
+	}
+
+	public String getVfName(Service intf) {
+		return getServiceName(intf) + "_valufact";
+	}
+
+	public String getVfFileNameH(Service intf) {
+		return getVfName(intf) + fnSuffixH;
+	}
+
+	public String getVfFileNameI(Service intf) {
+		return getVfName(intf) + fnSuffixI;
+	}
+
+	public String getMainName(Service intf, MessageDirection mc) {
+		if (mc == MessageDirection.SERVER)
+			return getServiceName(intf) + "_listener_main";
+		return getServiceName(intf) + "_client_main";
+	}
+
+	public String getMainFileNameH(Service intf, MessageDirection mc) {
+		return getMainName(intf, mc) + fnSuffixH;
+	}
+
+	public String getMainFileNameI(Service intf, MessageDirection mc) {
+		return getMainName(intf, mc) + fnSuffixI;
+	}
+
+	public String getHelperName(Service intf) {
+		return getServiceName(intf) + "_helper";
+	}
+
+	public String getHelperFileNameH(Service intf) {
+		return getHelperName(intf) + fnSuffixH;
+	}
+
+	public String getHelperFileNameI(Service intf) {
+		return getHelperName(intf) + fnSuffixI;
+	}
+
+	public void test(TypeRef type) {
+		int i;
+		System.out.println(type);
+		System.out.println("builtin " + type.isBuiltin());
+		type.getNamed(type.intf()).efqname(this);
+
+	}
+
+	public void testMsg(Message msg) {
+		int i;
+		// msg.getResultParam().efqname(this);
+		// msg.type().getNamed(msg.service()).efqname(this)
+		msg.getResultParam().efqname(this);
+	}
+
+	@Override
+	public String asyncReceiverPoolName(Message msg) {
+		return msg.getAsyncReceiver().toString().toLowerCase();
+	}
+
+	@Override
+	public String getTypeValue(TypeRef type, Token value) {
+		Token t = type.type();
+		switch (t.kind) {
+		case EtchGrammarConstants.LONG:
+			return value.image + "LL";
+		case EtchGrammarConstants.FLOAT:
+		case EtchGrammarConstants.DOUBLE:
+			return value.image + (value.image.indexOf('.')>-1 ? "f" : "");
+		case EtchGrammarConstants.STRING:
+			return "L" + protectString(value.image);
+		case EtchGrammarConstants.BOOLEAN:
+			return value.image.toUpperCase();
+		default:
+			return value.image;
+		}
+	}
+
+	private String protectString(String s) {
+		StringBuffer sb = new StringBuffer();
+		sb.append("\"");
+		for (char c : s.toCharArray()) {
+			if (c == '\t') {
+				sb.append("\\t");
+				continue;
+			}
+			if (c == '\r') {
+				sb.append("\\r");
+				continue;
+			}
+			if (c == '\n') {
+				sb.append("\\n");
+				continue;
+			}
+			if (c == '\"') {
+				sb.append("\\\"");
+				continue;
+			}
+			if (c == '\\') {
+				sb.append("\\\\");
+				continue;
+			}
+			if (c >= 32 && c < 127) {
+				sb.append(c);
+				continue;
+			}
+			sb.append(String.format("\\u%04x", (int) c));
+		}
+		sb.append("\"");
+		return sb.toString();
+	}
+
+	@Override
+	public String getTypeName(TypeRef type) {
+		if (type.dim() > 0)
+			return "etch_arraytype*";
+		return getPointerTypeName(type);
+	}
+
+	public String getNativeTypeNameForConstants(TypeRef type) {
+		if (type.type().kind == EtchGrammarConstants.STRING)
+			return "wchar_t*";
+		return getNativeTypeName(type, false);
+	}
+
+	/**
+	 * @param type
+	 *            the etch type
+	 * @return the fundamental native type for c so etch int -> c int, while
+	 *         etch string -> wchar* string.
+	 */
+	@Override
+	public String getNativeTypeName(TypeRef type) {
+		return getNativeTypeName(type, false);
+	}
+
+	public String getNativeTypeName(TypeRef type, boolean addStruct) {
+		return getNativeTypeName(type, false, false);
+	}
+	
+	public String getEtchTypeName(TypeRef type) {
+		return getNativeTypeName(type, false, true);
+	}
+	
+	public String getNativeTypeName(TypeRef type, boolean addStruct, boolean etch_type) {
+		if (type.isArray()) {
+			return (etch_type ? "etch_arraytype" : "etch_arraytype*");
+		}
+		
+		Token t = type.type();
+		switch (t.kind) {
+		case EtchGrammarConstants.VOID:
+			return "void";
+		case EtchGrammarConstants.BOOLEAN:
+			return (etch_type ? "etch_boolean" : "boolean");
+		case EtchGrammarConstants.BYTE:
+			return (etch_type ? "etch_int8" : "byte");
+		case EtchGrammarConstants.SHORT:
+			return (etch_type ? "etch_int16" : "short");
+		case EtchGrammarConstants.INT:
+			return (etch_type ? "etch_int32" : "int");
+		case EtchGrammarConstants.LONG:
+			return (etch_type ? "etch_int64" : "int64");
+		case EtchGrammarConstants.FLOAT:
+			return (etch_type ? "etch_float" : "float");
+		case EtchGrammarConstants.DOUBLE:
+			return (etch_type ? "etch_double" : "double");
+		case EtchGrammarConstants.STRING:
+			return (etch_type ? "etch_string" : "etch_string*");
+		case EtchGrammarConstants.OBJECT:
+			return (etch_type ? "etch_object" : "etch_object*");
+		default: {
+			// we have to use a fully qualified name here.
+			// find the actual type...
+			Named<?> n = type.intf().get(t.image);
+			System.out.println("Token:" + t.image);
+			if (n == null)
+				throw new IllegalArgumentException(String.format(
+						"undefined or ambiguous name at line %d: %s",
+						t.beginLine, t.image));
+
+			
+			if (n.isEnumx()) 
+			{
+				return n.efqname(this) + (etch_type ? "" : "_enum");
+			}
+			else
+			{
+				return (addStruct ? "struct " : "") + n.efqname(this) + (etch_type ? "" : "*");
+			}
+		}
+		}
+	}
+
+	/**
+	 * @param type
+	 *            the etch type
+	 * @return the fundamental native reference type for c. so etch int -> java
+	 *         etch_int32*, while etch string -> etch_string*.
+	 */
+	public String getPointerTypeName(TypeRef type) {
+		if (type.isArray())
+			return "etch_arraytype*";
+		Token t = type.type();
+
+		switch (t.kind) {
+		case EtchGrammarConstants.VOID:
+			return "void*";
+		case EtchGrammarConstants.BOOLEAN:
+			return "etch_boolean*";
+		case EtchGrammarConstants.BYTE:
+			return "etch_byte*";
+		case EtchGrammarConstants.SHORT:
+			return "etch_int16*";
+		case EtchGrammarConstants.INT:
+			return "etch_int32*";
+		case EtchGrammarConstants.LONG:
+			return "etch_int64*";
+		case EtchGrammarConstants.FLOAT:
+			return "etch_float*";
+		case EtchGrammarConstants.DOUBLE:
+			return "etch_double*";
+		case EtchGrammarConstants.STRING:
+			return "etch_string*";
+		case EtchGrammarConstants.OBJECT:
+			return "etch_object*";
+		default: {
+			// we have to use a fully qualified name here.
+			// find the actual type...
+			Named<?> n = type.intf().get(t.image);
+			if (n == null)
+				throw new IllegalArgumentException(String.format(
+						"undefined or ambiguous name at line %d: %s",
+						t.beginLine, t.image));
+			return n.efqname(this) + "*";
+		}
+		}
+	}
+
+	@Override
+	public String mfvname(String vname) {
+		return "_mf_" + vname;
+	}
+
+	@Override
+	public String mtvname(String vname) {
+		return "_mt_" + vname;
+	}
+
+	@Override
+	public String getLang() {
+		return "c";
+	}
+
+	@Override
+	public String enum_efqname(String fqname, String moduleName,
+			String serviceName, String enumName) {
+		// return serviceName.toLowerCase() + "_" + enumName.toLowerCase();
+		return serviceName.toLowerCase() + "_" + enumName;
+	}
+
+	@Override
+	public String except_efqname(String fqname, String moduleName,
+			String serviceName, String exceptName) {
+		// return serviceName.toLowerCase() + "_" + exceptName.toLowerCase();
+		return serviceName.toLowerCase() + "_" + exceptName;
+	}
+
+	@Override
+	public String struct_efqname(String fqname, String moduleName,
+			String serviceName, String structName) {
+		// return serviceName.toLowerCase() + "_" + structName.toLowerCase();
+		return serviceName.toLowerCase() + "_" + structName;
+	}
+
+	@Override
+	public String qualifyParameterName(Token name) {
+		return name.image;
+	}
+
+	@Override
+	public String qualifyConstantName(Service intf, Token name) {
+		return intf.fqname() + '.' + name.image;
+	}
+
+	@Override
+	public String qualifyEnumName(Service intf, Token name) {
+		return intf.fqname() + '.' + name.image;
+	}
+
+	Set<String> history = new HashSet<String>();
+
+	public boolean resetHistory() {
+		history = new HashSet<String>();
+		return true;
+	}
+
+	public boolean addStringToHistory(String s) {
+		history.add(s);
+		return true;
+	}
+
+	public boolean historyContains(String s) {
+		return history.contains(s);
+	}
+
+	// ///////////////////////////////////////////////
+	// /////////////////// WORKSPACE /////////////////
+	// ///////////////////////////////////////////////
+
+	@Override
+	public String formatString(ParamList<Service> n, boolean isExcept)
+			throws ParseException, IOException {
+		ToString ts = (ToString) n.getOpt("ToString");
+		List<FmtItem> list;
+		if (ts != null) {
+			list = ts.getFormat();
+			n.checkFormatList(ts.lineno(), list);
+		} else if (isExcept)
+			list = n.mkFormatList(true, ((Except) n).hasExtends());
+		else
+			list = n.mkFormatList(false, ((Struct) n).hasExtends());
+
+		if (list.size() == 1) {
+			return list.get(0).value();
+		}
+
+		StringBuffer sb = new StringBuffer();
+		sb.append("String.format( ");
+		sb.append("\"");
+		for (FmtItem i : list) {
+			if (i instanceof FieldItem) {
+				sb.append("%s");
+			} else {
+				escape(sb, ((StringItem) i).value());
+			}
+		}
+		sb.append("\"");
+		for (FmtItem i : list) {
+			if (i instanceof FieldItem) {
+				sb.append(", ");
+				sb.append(((FieldItem) i).value());
+			}
+		}
+		sb.append(" )");
+		return sb.toString();
+	}
+
+	private void escape(StringBuffer sb, String s) throws IOException {
+		StringReader rdr = new StringReader(s);
+		int c;
+		while ((c = rdr.read()) >= 0) {
+			if (c == '"')
+				sb.append("\\\"");
+			else if (c == '\\')
+				sb.append("\\\\");
+			else if (c == '\t')
+				sb.append("\\t");
+			else if (c == '\r')
+				sb.append("\\r");
+			else if (c == '\n')
+				sb.append("\\n");
+			else
+				sb.append((char) c);
+		}
+	}
+
+	public String getValidator(Service service, Named<?> named) {
+		
+//		(objmask*) etchvtor_custom_get(ETCHTYPEB_USER, 
+//		 get_dynamic_classid_unique(&CLASSID_TESTER_SIMPLESTRUCT),
+//		 tester_valufact_get_static()->_mt_tester_simpleStruct,
+//        1))
+		
+		if (named instanceof Parameter) {
+			Parameter param = (Parameter) named;
+			TypeRef type = param.type();
+
+			if (type.isBuiltin())
+				return String.format("(etch_object*)etchvtor_%s_get( %d )", getValidatorStringForParam(param),
+						type.dim());
+
+			Named<?> n = type.getNamed(type.intf());
+
+			if (n.isBuiltin()) {
+				Builtin b = (Builtin) n;
+				String cn = b.className();
+
+				int i = cn.indexOf('<');
+				if (i >= 0)
+					cn = cn.substring(0, i);
+				
+				String classid = getClassIDBuiltin(b);
+				String messagetype = getMessageTypeBuiltin(b);
+				return String.format(
+						"(etch_object*)etchvtor_custom_get(%s, CLASSID_%s, builtins._mt_%s,%d)",
+							getEtchTypeForBuiltin(b),classid, messagetype, getDimensionForBuiltin(b));
+			}
+
+
+			if (n.isStruct() || n.isExcept() || n.isEnumx())
+				return String.format(
+						"(etch_object*)etchvtor_custom_get(ETCHTYPEB_USER, get_dynamic_classid_unique(&CLASSID_%s), %s_valufact_get_static()->_mt_%s, %d)", 
+								 n.efqname(this).toUpperCase(), service.name().toString().toLowerCase(), n.efqname(this), type.dim());
+
+			if (n.isExtern())
+			{
+				Assertion.check(false,"extern type not supported for " + n );
+			}
+			else
+			{
+				Assertion.check(false,"unknown type " + n);
+			}
+
+			return "";
+		}
+
+		if (named instanceof Thrown) {
+			Thrown thrown = (Thrown) named;
+			Except e = (Except) thrown.getNamed();
+			return String.format("(etch_object*)etchvtor_custom_get( ETCHTYPEB_USER,get_dynamic_classid_unique(&%s), %s_valufact_get_static()->_mt_%s_%s,0)", 
+						getClassIdVarName(thrown),getExcept(thrown).service().name().toString().toLowerCase(),getExcept(thrown).service().name().toString().toLowerCase(),thrown);
+		}
+
+		if (named instanceof Item)
+			return "(etch_object*)etchvtor_boolean_get( 0 )";
+
+		return "null";
+	}
+
+	private int getDimensionForBuiltin(Builtin b) {
+		if(b.bindingName().equals("etch_date"))
+			return 0;
+		if(b.bindingName().equals("etch_arraylist"))
+			return 1;
+		if(b.bindingName().equals("etch_hashtable"))
+			return 0;
+		if(b.bindingName().equals("etch_set"))
+			return 0;
+
+		return 0;
+	}
+
+	private String getEtchTypeForBuiltin(Builtin b) {
+		if(b.bindingName().equals("etch_date"))
+			return "ETCHTYPEB_PRIMITIVE";
+		if(b.bindingName().equals("etch_arraylist"))
+			return "ETCHTYPEB_ETCHLIST";		
+		if(b.bindingName().equals("etch_hashtable"))
+			return "ETCHTYPEB_ETCHMAP";
+		if(b.bindingName().equals("etch_set"))
+			return "ETCHTYPEB_ETCHSET";
+
+		return "ETCHTYPEB_USER";
+		
+	}
+
+	private String getMessageTypeBuiltin(Builtin b) {
+		if(b.bindingName().equals("etch_date"))
+			return "_etch_datetime";
+		if(b.bindingName().equals("etch_arraylist"))
+			return "_etch_list";		
+		if(b.bindingName().equals("etch_hashtable"))
+			return "_etch_map";
+		if(b.bindingName().equals("etch_set"))
+			return "_etch_set";
+		return "NULL";
+	}
+
+	private String getClassIDBuiltin(Builtin b) {
+		if(b.bindingName().equals("etch_date"))
+			return "DATE";
+		if(b.bindingName().equals("etch_arraylist"))
+			return "ETCH_LIST";		
+		if(b.bindingName().equals("etch_hashtable"))
+			return "ETCH_MAP";
+		if(b.bindingName().equals("etch_set"))
+			return "ETCH_SET";
+
+		return "NULL";
+	}
+
+	/**
+	 * @param name
+	 * @return the appropriate name for a getter method.
+	 */
+	public String getGetterName(Name name) {
+		String s = name.name;
+		return "get" + s.substring(0, 1).toUpperCase() + s.substring(1);
+	}
+
+	/**
+	 * @param name
+	 * @return the appropriate name for a setter method.
+	 */
+	public String getSetterName(Name name) {
+		String s = name.name;
+		return "set" + s.substring(0, 1).toUpperCase() + s.substring(1);
+	}
+
+	@Override
+	public void addDefaults(Service service) throws ParseException {
+		addBuiltin( service, newName( "List" ), "etch_arraylist", true );
+		addBuiltin( service, newName( "Map" ), "etch_hashtable", true );
+		addBuiltin( service, newName( "Set" ), "etch_set", true );
+		addBuiltin(service, newName("Datetime"), "etch_date", false);
+	}
+
+	public String getValidatorStringForParam(Parameter param) {
+		TypeRef type = param.type();
+		return getValidatorStringForParam(type);
+	}
+
+	public String getValidatorStringForParam(TypeRef type) {
+		switch (type.type().kind) {
+		case EtchGrammarConstants.BOOLEAN:
+			return "boolean";
+		case EtchGrammarConstants.BYTE:
+			return "byte";
+		case EtchGrammarConstants.INT:
+			return "int32";
+		case EtchGrammarConstants.SHORT:
+			return "int16";
+		case EtchGrammarConstants.DOUBLE:
+			return "double";
+		case EtchGrammarConstants.FLOAT:
+			return "float";
+		case EtchGrammarConstants.LONG:
+			return "int64";
+		case EtchGrammarConstants.STRING:
+			return "string";
+		}
+		// what should be the default here?
+		return "object";
+	}
+
+	public String getValidatorStringForParam(Message param) {
+		return getValidatorStringForParam(param.type());
+	}
+
+	public boolean isEnumParam(Parameter p) {
+		if (p.type() == null)
+			return false;
+		if (p.type().intf() == null)
+			return false;
+		if (p.type().getNamed(p.type().intf()) == null)
+			return false;
+		return p.type().getNamed(p.type().intf()).isEnumx();
+	}
+
+	public boolean isCustomType(Parameter param) {
+		return isCustomType(param.type());
+	}
+
+	public boolean isRefType(TypeRef param) {
+		if(param == null)
+			return true;
+		switch(param.type().kind) {
+			case EtchGrammarConstants.BOOLEAN:
+			case EtchGrammarConstants.DOUBLE:
+			case EtchGrammarConstants.FLOAT:
+			case EtchGrammarConstants.INT:
+			case EtchGrammarConstants.LONG:
+			case EtchGrammarConstants.ENUM:
+			case EtchGrammarConstants.DECIMAL:
+			case EtchGrammarConstants.SHORT:
+				return false;
+			default:
+				return true;
+		}
+	}
+	
+	public boolean isCustomType(TypeRef param) {
+		switch (param.type().kind) {
+		case EtchGrammarConstants.BOOLEAN:
+		case EtchGrammarConstants.DOUBLE:
+		case EtchGrammarConstants.FLOAT:
+		case EtchGrammarConstants.INTEGER:
+		case EtchGrammarConstants.STRING:
+		case EtchGrammarConstants.LONG:
+			return false;
+		default:
+			return true;
+		}
+	}
+
+	public String getTypeName(Parameter pa) {
+		return pa.type().type().image;
+	}
+
+	public String getTypeName(Message pa) {
+		return pa.type().type().image;
+	}
+
+	public List<String> getUsedServiceNames(Service s) {
+		final List<String> ret = new LinkedList<String>();
+		IncludeTreeWalker walker = new IncludeTreeWalker(ret, s);
+		try {
+			s.treewalk(walker);
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		return walker.getList();
+	}
+
+	public boolean containsStructsOrMessages(Service s) {
+		return s.messages(false).hasNext() || s.structs(false).hasNext();
+	}
+
+	public String getClassIdVarName(Parameter p) {
+		Named<?> n = p.type().getNamed(p.type().intf());
+		return "CLASSID_" + n.efqname(this).toUpperCase();
+	}
+
+	public String getClassIdVarName(Thrown t) {
+		Except p = (Except) t.getNamed();
+		return "CLASSID_" + p.service().name().toString().toUpperCase() + "_"
+				+ p.name().toString().toUpperCase();
+	}
+
+	public Except getExcept(Thrown t) {
+		Except e = (Except) t.getNamed();
+		return e;
+	}
+
+	public String getClassIdVarName(Message n) {
+		Named<?> na = n.type().getNamed(n.type().intf());
+		return "CLASSID_" + na.efqname(this).toUpperCase();
+	}
+
+	public String getDefiningServiceNameOf(TypeRef type) {
+		Named<?> na = type.getNamed(type.intf());
+		return na.parent().name().name.toLowerCase();
+	}
+
+	@Override
+	public String getValidator(Named<?> named) {
+		return getValidator(null, named);
+	}
+
+}
diff --git a/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/CompilerVersion.java b/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/CompilerVersion.java
new file mode 100644
index 0000000..0fd9770
--- /dev/null
+++ b/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/CompilerVersion.java
@@ -0,0 +1,33 @@
+/* $Id$
+ *
+ * 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.etch.bindings.c.compiler;
+
+/**
+ * The version info of this Etch backend (compiler).
+ */
+public interface CompilerVersion
+{
+	// This file is edited by the production build system to replace the value
+	// of VERSION below with whatever it wants the version string to actually be.
+	
+	/** The version of this Etch backend (compiler) */
+	public String VERSION = "c 1.1.0-incubating (LOCAL-0)";
+}
diff --git a/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/CompilerVersion.java.tmpl b/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/CompilerVersion.java.tmpl
new file mode 100644
index 0000000..973d785
--- /dev/null
+++ b/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/CompilerVersion.java.tmpl
@@ -0,0 +1,33 @@
+/* $Id$
+ *
+ * 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.etch.bindings.c.compiler;
+
+/**
+ * The version info of this Etch backend (compiler).
+ */
+public interface CompilerVersion
+{
+	// This file is edited by the production build system to replace the value
+	// of VERSION below with whatever it wants the version string to actually be.
+	
+	/** The version of this Etch backend (compiler) */
+	public String VERSION = "c @EtchLongVersion@ (@EtchBuildTag@)";
+}
diff --git a/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/IncludeTreeWalker.java b/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/IncludeTreeWalker.java
new file mode 100644
index 0000000..219b13e
--- /dev/null
+++ b/binding-c/compiler/src/main/java/org/apache/etch/bindings/c/compiler/IncludeTreeWalker.java
@@ -0,0 +1,184 @@
+package org.apache.etch.bindings.c.compiler;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.util.List;
+
+import org.apache.etch.compiler.ast.Constant;
+import org.apache.etch.compiler.ast.Enumx;
+import org.apache.etch.compiler.ast.Except;
+import org.apache.etch.compiler.ast.Extern;
+import org.apache.etch.compiler.ast.Item;
+import org.apache.etch.compiler.ast.Message;
+import org.apache.etch.compiler.ast.Mixin;
+import org.apache.etch.compiler.ast.Module;
+import org.apache.etch.compiler.ast.Parameter;
+import org.apache.etch.compiler.ast.Service;
+import org.apache.etch.compiler.ast.Struct;
+import org.apache.etch.compiler.ast.Thrown;
+import org.apache.etch.compiler.ast.TreeWalker;
+import org.apache.etch.compiler.ast.TypeRef;
+
+public class IncludeTreeWalker implements TreeWalker {
+
+	private List<String> list;
+	private Service service;
+
+	public IncludeTreeWalker(List<String> list, Service s) {
+		this.list = list;
+		this.service = s;
+	}
+
+	@Override
+	public void doExtern(Extern extern) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void doItem(Item item) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void doMixin(Mixin mixin) {
+		String s = mixin.name().name(); //.intf().name().name();
+		if (!getList().contains(s) && 
+			!s.equals(service.name().name())) {
+			getList().add(s);
+		}
+
+	}
+
+	@Override
+	public void doThrown(Thrown thrown) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void doTypeRef(TypeRef ref) {
+		
+	}
+
+	@Override
+	public void postConstant(Constant constant) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void postEnum(Enumx enumx) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void postExcept(Except except) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void postMessage(Message message) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void postModule(Module module) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void postParameter(Parameter parameter) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void postService(Service service) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void postStruct(Struct struct) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void preConstant(Constant constant) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void preEnum(Enumx enumx) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void preExcept(Except except) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void preMessage(Message message) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void preModule(Module module) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void preParameter(Parameter parameter) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void preService(Service service) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void preStruct(Struct struct) {
+		// TODO Auto-generated method stub
+
+	}
+
+	public List<String> getList() {
+		return list;
+	}
+
+}
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/base_c.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/base_c.vm
new file mode 100644
index 0000000..b765d2c
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/base_c.vm
@@ -0,0 +1,248 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+\#include "$helper.getBaseFileNameH($intf, $suffix)"
+\#include "etch_objecttypes.h"
+\#include "etch_general.h"
+\#include "etch_url.h"  
+
+unsigned short CLASSID_$helper.getBaseName( $intf, $suffix ).toUpperCase()_BASE;
+	
+#foreach($serviceName in $helper.getUsedServiceNames($intf))	
+\#include "${serviceName.toLowerCase()}.h"
+#end
+	
+#if ($helper.isServer($mc))
+int destroy_$helper.getBaseName($intf, $suffix)_via_base(void*);
+#end
+#if ($helper.isClient($mc))
+int destroy_$helper.getBaseName($intf, $suffix)_base(void*);
+#end
+
+#if ($helper.isServer($mc))
+static int $helper.getBaseName( $intf, $suffix )_id_farm;
+#end
+
+/* - - - - - - - - - - - - - -  
+ * constructors
+ * - - - - - - - - - - - - - -  
+ */
+## server base
+#if ($helper.isServer($mc))
+/**
+ * new_$helper.getBaseName( $intf, $suffix )_base()
+ * @param implobj not interpreted
+ * @param psi a $helper.getIntfName( $intf ) service interface. if supplied, caller retains,
+ * otherwise a service interface is instantiated and owned here. 
+ */
+i_$helper.getBaseName( $intf, $suffix )* new_$helper.getBaseName( $intf, $suffix )_base(void* implobj, i_$helper.getIntfName( $intf )* psi)
+{
+    i_$helper.getBaseName( $intf, $suffix )* ips = (i_$helper.getBaseName( $intf, $suffix )*) new_object (sizeof(i_$helper.getBaseName( $intf, $suffix )), 
+        ETCHTYPEB_EXESERVERBASE, get_dynamic_classid_unique(&CLASSID_$helper.getBaseName( $intf, $suffix ).toUpperCase()_BASE));
+
+    /* the server impl is destroyed via this base object. the virtual destructor we assign
+     * here will call the impl object's virtual destructor, which will directly call a 
+     * non-virtual destructor for the base object. 
+     */
+
+    ((etch_object*)ips)->destroy = destroy_$helper.getBaseName( $intf, $suffix )_via_base;
+    
+    ips->thisx   = implobj; /* null passed thru from client main */
+    
+    if (psi)
+        ips->i$helper.getIntfName( $intf ) = psi;
+    else
+    {   ips->i$helper.getIntfName( $intf ) = new_$helper.getIntfName( $intf )_service_interface();
+        ips->is_service_interface_owned = TRUE;
+    }
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+    ips->$n.name() = ips->i$helper.getIntfName( $intf )->$n.name();
+#end
+#end
+#end
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct())
+#if (!$n.isHidden())
+    ips->$n.name().toString() = ips->i$helper.getIntfName($intf)->$n.name().toString();
+#end
+#end
+#end
+
+    ips->iobjsession = new_default_objsession_interface (ips);
+    ips->_session_control = ips->iobjsession->_session_control; 
+    ips->_session_notify  = ips->iobjsession->_session_notify; 
+    ips->_session_query   = ips->iobjsession->_session_query; 
+
+    ips->server_id = ++$helper.getIntfName( $intf )_server_id_farm;
+
+    return ips;
+}
+
+/**
+ * new_$helper.getRemoteName( $intf, $suffix )_base()  
+ * constructor for server base when host is a remote server.
+ * the server base destructor in this case destroys only itself.   
+ * @param psi a $helper.getIntfName( $intf ) service interface, if supplied, caller retains.
+ * may be null.
+ */
+i_$helper.getBaseName( $intf, $suffix )* new_$helper.getRemoteName( $intf, $suffix )_base (void* implobj, i_$helper.getIntfName( $intf )* psi)
+{
+    i_$helper.getBaseName( $intf, $suffix )* ips = new_$helper.getBaseName( $intf, $suffix )_base (implobj, psi);
+    ((etch_object*)ips)->destroy = destroy_$helper.getBaseName( $intf, $suffix )_base;
+    return ips;
+}
+
+/**
+ * destroy_$helper.getBaseName($intf, $suffix)_base()
+ * i_$helper.getBaseName($intf, $suffix) destructor.
+ */
+int destroy_$helper.getBaseName( $intf, $suffix )_base (void* data)
+{
+
+    i_$helper.getBaseName( $intf, $suffix )* ips = (i_$helper.getBaseName( $intf, $suffix )*)data;
+    if (NULL == ips) return -1;
+
+    if (!is_etchobj_static_content(ips))
+    {    
+        if (ips->is_service_interface_owned){
+            //ETCHOBJ_DESTROY(ips->i$helper.getIntfName( $intf ));
+			if(ips->i$helper.getIntfName( $intf )){
+				etch_object_destroy(ips->i$helper.getIntfName( $intf ));
+			}
+			ips->i$helper.getIntfName( $intf ) = NULL;
+			
+		}
+
+        etch_free(ips->iobjsession);
+    }
+            
+    return destroy_objectex((etch_object*)ips);
+}
+
+
+/**
+ * destroy_$helper.getBaseName( $intf, $suffix )_via_base()
+ * destructor for $helper.getBaseName( $intf, $suffix )_impl via i_$helper.getBaseName( $intf, $suffix ).
+ */
+int destroy_$helper.getBaseName( $intf, $suffix )_via_base (void* data)
+{
+    i_$helper.getBaseName( $intf, $suffix )* ips = (i_$helper.getBaseName( $intf, $suffix )*)data;
+    if (NULL == ips) return -1;  
+
+    if (!is_etchobj_static_content(ips))
+    {    
+        /* serverimpl dtor will call base dtor (destroy_$helper.getBaseName( $intf, $suffix )_base) */
+        etch_object* serverimpl = (etch_object*) ips->thisx;
+        ETCH_ASSERT(is_etch_serverimpl(serverimpl));
+        //ETCHOBJ_DESTROY(serverimpl);
+		if(serverimpl){
+			etch_object_destroy(serverimpl);
+		}
+		serverimpl = NULL;
+    }
+
+    return 0;
+}
+
+#end
+## client base
+#if ($helper.isClient($mc))
+/**
+ * new_$helper.getBaseName($intf, $suffix)_base()
+ * @param iservice service interface -- caller retains   
+ */
+i_$helper.getBaseName($intf, $suffix)* new_$helper.getBaseName($intf, $suffix)_base(struct $helper.getImplName($intf, $suffix)* implobj)
+{
+    i_$helper.getBaseName( $intf, $suffix )* ipc = (i_$helper.getBaseName( $intf, $suffix )*) new_object (sizeof(i_$helper.getBaseName( $intf, $suffix )), 
+        ETCHTYPEB_EXECLIENTBASE, get_dynamic_classid_unique(&CLASSID_$helper.getBaseName( $intf, $suffix ).toUpperCase()_BASE));
+
+    ipc->thisx   = implobj;  /* $helper.getImplName( $intf, $suffix ) on client, null on server */
+    ((etch_object*)ipc)->destroy = destroy_$helper.getBaseName( $intf, $suffix )_base;
+
+    ipc->i$helper.getIntfName( $intf ) = new_$helper.getIntfName( $intf )_service_interface();
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+    ipc->$n.name() = ipc->i$helper.getIntfName($intf)->$n.name();
+#end
+#end
+#end
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct())
+#if (!$n.isHidden())
+    ipc->$n.name().toString() = ipc->i$helper.getIntfName($intf)->$n.name().toString();
+#end
+#end
+#end
+ 
+    return ipc;
+}
+
+/**
+ * destroy_$helper.getBaseName( $intf, $suffix )_base()
+ * i_$helper.getBaseName( $intf, $suffix ) destructor.
+ */
+int destroy_$helper.getBaseName( $intf, $suffix )_base (void* data)
+{
+    i_$helper.getBaseName( $intf, $suffix )* ipc = (i_$helper.getBaseName( $intf, $suffix )*)data;
+    if (NULL == ipc) return -1;  
+
+    if (!is_etchobj_static_content(ipc))
+    {    
+        if (ipc->thisx)  /* thisx is null on server (i.e. this is a remote client) */
+        {   /* destroy the $helper.getBaseName( $intf, $suffix )_impl object */
+            ETCH_ASSERT(is_etch_client_impl((etch_object*)ipc->thisx));
+            //ETCHOBJ_DESTROY();
+			if(((etch_object*)ipc->thisx)){
+				etch_object_destroy(((etch_object*)ipc->thisx));
+			}
+			ipc->thisx = NULL;
+        }
+
+        //ETCHOBJ_DESTROY(ipc->i$helper.getIntfName( $intf ));
+		if(ipc->i$helper.getIntfName( $intf )){
+			etch_object_destroy(ipc->i$helper.getIntfName( $intf ));
+		}
+		ipc->i$helper.getIntfName( $intf ) = NULL;
+
+        etch_free(ipc->iobjsession);
+    }
+            
+    return destroy_objectex((etch_object*)ipc);
+}
+
+/* - - - - - - - - - - - - - -  
+ * client base methods
+ * - - - - - - - - - - - - - -  
+ */
+
+/* nothing to do - service defines no client-directed items */
+
+#end
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/base_h.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/base_h.vm
new file mode 100644
index 0000000..9960c76
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/base_h.vm
@@ -0,0 +1,133 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * $helper.getBaseFileNameH( $intf, $suffix )
+ * $helper.getServiceName( $intf ) client interface.
+ * combines java bindings's $intf.name()Server and Base$intf.name()Server
+ */
+
+#ifndef $helper.getBaseName( $intf, $suffix ).toUpperCase()_H
+#define $helper.getBaseName( $intf, $suffix ).toUpperCase()_H
+
+\#include "$helper.getIntfFileNameH( $intf )"
+\#include "etch_sessionint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_$helper.getBaseName( $intf, $suffix ).toUpperCase()_BASE;
+
+//typedef struct $helper.getImplName( $intf, $suffix ) $helper.getImplName( $intf, $suffix );
+
+/**
+ * i_$helper.getBaseName( $intf, $suffix )
+ * $helper.getServiceName( $intf ) $suffix base interface
+ */
+typedef struct i_$helper.getBaseName( $intf, $suffix )
+{
+    etch_object object;
+
+	struct $helper.getImplName( $intf, $suffix )* thisx;
+    i_$helper.getServiceName( $intf )*  i$helper.getServiceName( $intf );
+    
+    
+#if ($helper.isServer($mc))
+    int session_id;
+    unsigned char is_service_interface_owned;
+    unsigned char unused[3];
+#end
+
+    /* - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - -
+     * service virtuals
+     * - - - - - - - - - - -
+     */
+## generate service virtuals
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+    $helper.getServiceName( $intf )_$n.name() $n.name();
+#end
+#end
+#end
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())
+#if (!$n.isHidden())
+    $helper.getServiceName( $intf )_$n.name() async_$n.name();
+#end
+#end
+#end
+#end
+#if (!$intf.hasMessageDirection($mc) && $helper.hasMessageDirectionBoth( $intf ))
+    /* no $mc.toString().toLowerCase()-directed items defined */
+#end
+
+    /* - - - - - - - - - - -
+    * service data
+    * - - - - - - - - - - -
+    */
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct())
+#if (!$n.isHidden())
+    $n.efqname($helper)* $n.name().toString();
+#end
+#end
+#end
+
+     /* - - - - - - - - - - -
+     * private instance data
+     * - - - - - - - - - - -
+     */
+    int server_id;
+
+} i_$helper.getBaseName($intf, $suffix);
+
+#if($helper.isServer($mc))
+i_$helper.getBaseName( $intf, $suffix )* new_$helper.getBaseName( $intf, $suffix )_base (void* implobj, i_$helper.getIntfName( $intf )*);
+i_$helper.getBaseName( $intf, $suffix )* new_$helper.getRemoteName( $intf, $suffix )_base (void* implobj, i_$helper.getIntfName( $intf )*);
+int destroy_$helper.getBaseName( $intf, $suffix )_base (void*);
+#end
+#if($helper.isClient( $mc ))
+//i_$helper.getBaseName($intf, $suffix)* new_$helper.getBaseName($intf, $suffix)_base($helper.getImplName($intf, $suffix)* implobj);
+i_$helper.getBaseName($intf, $suffix)* new_$helper.getBaseName($intf, $suffix)_base();
+#end
+
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* $helper.getBaseName( $intf, $suffix ).toUpperCase()_H */
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/cKeywords.kwd b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/cKeywords.kwd
new file mode 100644
index 0000000..cfc9621
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/cKeywords.kwd
@@ -0,0 +1,35 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+true
+false
+null
+for
+switch
+assert
+default
+goto
+bool
+do
+if
+break
+double
+char
+else
+case
+enum
+return
+catch
+int
+short
+static
+void
+struct
+long
+volatile
+const
+float
+native
+while
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/etch_keywords.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/etch_keywords.vm
new file mode 100644
index 0000000..9287887
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/etch_keywords.vm
@@ -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.
+##
+
+#foreach($n in $intf.iterator())
+#if($n.isMessage())
+#if(!$n.isHidden())
+#set ( $str="$intf.fqname().$n.name()" )
+$helper.getKeywordForWireshark($str)
+#if(! $n.isOneway())
+#set ( $str="$intf.fqname()._result_$n.name()" )
+$helper.getKeywordForWireshark($str)
+#end
+#end
+#end
+#end
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+$helper.getKeywordForWireshark($n.fqname().toString())
+#end
+#end
+#set ($tmp = $helper.resetHistory())
+#foreach($n in $intf.iterator())
+#if(!$n.isHidden())
+#if(!$n.isBuiltin())
+#foreach($p in $n.iterator())
+#if(!$helper.historyContains($p.name().toString()))
+$helper.getKeywordForWireshark($p.name().toString())
+#set ($tmp = $helper.addStringToHistory($p.name().toString()))
+#end
+#end
+#end
+#end
+#end
+$helper.getKeywordForWireshark("_Etch_RuntimeException")
+$helper.getKeywordForWireshark("_Etch_AuthException")
+$helper.getKeywordForWireshark("_exception")
+$helper.getKeywordForWireshark("_Etch_List")
+$helper.getKeywordForWireshark("_Etch_Map")
+$helper.getKeywordForWireshark("_Etch_Set")
+$helper.getKeywordForWireshark("_Etch_Datetime")
+$helper.getKeywordForWireshark("msg")
+$helper.getKeywordForWireshark("_messageId")
+$helper.getKeywordForWireshark("_inReplyTo")
+$helper.getKeywordForWireshark("result")
+$helper.getKeywordForWireshark("keys")
+$helper.getKeywordForWireshark("values")
+$helper.getKeywordForWireshark("dateTime")
+$helper.getKeywordForWireshark("keysAndValues")
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/helper_c.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/helper_c.vm
new file mode 100644
index 0000000..c967a0d
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/helper_c.vm
@@ -0,0 +1,342 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#set($i = $intf.name().name().toLowerCase()) 
+
+/*
+ * ${i}_helper.c 
+ * transport helper for ${i} service
+ */
+\#include "$helper.getIntfFileNameH($intf)"
+
+#if($helper.isServer($mc))
+\#include "${i}_server.h"
+\#include "${i}_server_stub.h"
+\#include "${i}_remote_client.h"
+#end
+#if($helper.isClient($mc))
+\#include "${i}_client_stub.h"
+\#include "${i}_remote_server.h"
+#end
+
+\#include "${i}_helper.h"
+\#include "${i}_valufact.h"
+\#include "etch_svcobj_masks.h"
+\#include "etch_objecttypes.h"
+\#include "etch_url.h" 
+\#include "etch_log.h" 
+
+static const char* LOG_CATEGORY     = "$helper.getServiceName($intf)_helper";
+
+static int ${i}_helper_resources_init(void* data)
+{
+    etch_server_factory* factory = (etch_server_factory*)data;
+    int result = 0;
+    ETCH_ASSERT((factory != NULL) && (factory->in_valufact == NULL));
+    ETCH_ASSERT (factory->in_resx && is_etch_hashtable(factory->in_resx));
+
+    // TODO use new semantic ${i}_valuefactory_create
+    factory->in_valufact = (etch_value_factory*)new_${i}_valufact();
+    ETCH_ASSERT(factory->in_valufact);
+    if(factory->in_valufact == NULL) {
+        return -1;
+    }
+    result = etch_resources_add(factory->in_resx, ETCH_RESXKEY_MSGIZER_VALUFACT, (etch_object*)factory->in_valufact);
+
+    ETCH_ASSERT(0 == result);
+    return result;
+}
+
+#if($helper.isClient($mc))
+etch_status_t ${i}_helper_remote_server_create(${i}_remote_server** remote_server, wchar_t* uri, void* factory_thisx, main_client_create_func client_create)
+{
+    etch_status_t         rv                 = ETCH_SUCCESS;
+    etch_client_factory*  factory            = NULL;
+    ${i}_remote_server* newremote_server   = NULL;
+    i_${i}_client*      client             = NULL;
+    ${i}_client_stub*   client_stub        = NULL;
+    ${i}_valufact*      vf                 = NULL;
+
+    if(remote_server == NULL || client_create == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "creating ${i} client ...\n");
+    factory = new_client_factory (NULL, NULL, client_create);
+    ETCH_ASSERT(factory != NULL);
+	
+	factory->thisx = factory_thisx;
+
+    vf = new_${i}_valufact();
+    ETCH_ASSERT(vf != NULL);
+
+    factory->in_valufact = (etch_value_factory*)vf;
+    factory->in_resx     = etch_transport_resources_init(factory->in_resx);
+    ETCH_ASSERT(factory->in_resx != NULL);
+    etch_resources_add (factory->in_resx, ETCH_RESXKEY_MSGIZER_VALUFACT, (etch_object*)vf);
+
+    // instantiate a delivery service
+    factory->dsvc = new_etch_transport(uri, (etch_factory_params*)factory, NULL);
+    ETCH_ASSERT(is_etch_ideliverysvc(factory->dsvc));
+
+    // instantiate the remote server
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "instantiating remote server ...\n");
+    newremote_server = new_${i}_remote_server(NULL, factory->dsvc, (etch_value_factory*)vf);
+    ETCH_ASSERT(is_etch_remote_server(newremote_server));
+
+    factory->server_id = newremote_server->server_base->server_id;
+    factory->server = newremote_server;
+    newremote_server->client_factory = factory;
+
+    /* here we call back to the client constructor in [main]. the purpose of the 
+     * callback is to isolate the editable xxxx_client_impl constructor from the 
+     * private constructor pieces. the callback instantiates a client implenentation
+     * and returns an interface to it. 
+     */   
+    if(factory->new_client != NULL) {
+        client = factory->new_client(factory, newremote_server);
+        ETCH_ASSERT(is_etch_client_base(client));
+        factory->iclient = client;
+    }
+
+    // get thread pools
+    factory->fpool = (etch_threadpool*)etch_resources_get(factory->in_resx, ETCH_RESXKEY_POOLTYPE_FREE);
+    ETCH_ASSERT(factory->fpool);
+    factory->qpool = (etch_threadpool*)etch_resources_get(factory->in_resx, ETCH_RESXKEY_POOLTYPE_QUEUED);
+    ETCH_ASSERT(factory->qpool);
+
+    // construct client stub
+    client_stub = new_${i}_client_stub(factory);
+    ETCH_ASSERT(is_etch_client_stub(client_stub));
+    factory->stub = client_stub;
+
+    *remote_server = newremote_server;
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG,"remote server instantiated\n");
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "${i} client created\n");
+
+    return rv;
+}
+
+etch_status_t ${i}_helper_remote_server_start_wait(${i}_remote_server* remote_server, const int waitms)
+{
+    etch_status_t   rv           = ETCH_SUCCESS;
+    ${i}_remote*  remote       = NULL;
+    int             result       = 0;
+
+    if(remote_server == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    remote = remote_server->remote_base;
+    ETCH_ASSERT(remote != NULL);
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "starting ${i} client ...\n");
+    result = remote->start_waitup(remote, waitms);
+    if(result != 0) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not start ${i} client\n");
+        rv = ETCH_ERROR;
+    } else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "${i} client started\n");
+        rv = ETCH_SUCCESS;
+    }
+
+    return rv;
+}
+
+etch_status_t ${i}_helper_remote_server_stop_wait(${i}_remote_server* remote_server, const int waitms)
+{
+    etch_status_t   rv         = ETCH_SUCCESS;
+    ${i}_remote*  remote     = NULL;
+    int             result     = 0;
+
+    if(remote_server == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    remote = remote_server->remote_base;
+    ETCH_ASSERT(remote != NULL);
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "stopping ${i} client ...\n");
+    result = remote->stop_waitdown(remote, waitms);
+    if(result != 0) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not stop ${i} client\n");
+        rv = ETCH_ERROR;
+    } else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "${i} client stopped\n");
+        rv = ETCH_SUCCESS;
+    }
+
+    return rv;
+}
+
+etch_status_t ${i}_helper_remote_server_destroy(${i}_remote_server* remote_server)
+{
+    etch_status_t rv     = ETCH_SUCCESS;
+
+    if(remote_server == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "destroying remote server ...\n");
+    etch_object_destroy(remote_server);
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "remote server destroyed\n");
+
+    return rv;
+}
+
+#end
+#if($helper.isServer($mc))
+static void* ${i}_helper_listener_create_func(void* factoryData, void* sessionData)
+{
+    etch_server_factory* factory = (etch_server_factory*)factoryData;
+    etch_session* session = (etch_session*)sessionData;
+    i_${i}_server* iserver;
+    ${i}_server_stub* stub;
+    ${i}_remote_client* client;
+    ETCH_ASSERT(factory && factory->helper_new_listener && factory->main_new_server);
+    ETCH_ASSERT(factory->in_resx && factory->in_valufact);   // TODO assert delivery service
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "instantiating accepted client listener ...\n");
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "creating remote client...\n");
+    client = new_${i}_remote_client(NULL, session, factory->in_valufact);
+    client->session_id = session->session_id;
+    session->client = client;
+
+    /* here we CALL BACK to the constructor in [main], the purpose of the callback
+     * being to isolate the editable constructor from the private constructor. 
+     * the callback instantiates a client's server implementation and returns 
+     * an interface to it. 
+     */ 
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "creating server implementation ...\n");
+    iserver = factory->main_new_server(factory, session);
+    iserver->session_id = session->session_id;
+    session->server = iserver;
+
+    /* note that the main listener will use p->mainpool as a thread manager, not these */
+    factory->qpool = (etch_threadpool*)etch_resources_get(factory->in_resx, ETCH_RESXKEY_POOLTYPE_QUEUED);
+    factory->fpool = (etch_threadpool*)etch_resources_get(factory->in_resx, ETCH_RESXKEY_POOLTYPE_FREE);
+
+    /* eventually new_${i}_server_stub() gets to stub_base constructor, which sets
+     * the delivery service's session to this, the server stub. so, in the java binding,
+     * the server stub is referenced as delivery service.session. we should perhaps also 
+     * store the stub opaquely in both the client and listener objects.
+     */
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "creating server stub ...\n");
+    stub = new_${i}_server_stub(factory, session);
+    stub->session_id = session->session_id;
+    session->server_stub = stub;
+
+    if (iserver && stub)
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "accepted client listener instantiated\n");
+    else
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not instantiate accepted client listener\n");
+
+    return stub;
+}
+
+etch_status_t ${i}_helper_listener_create(i_sessionlistener** listener, wchar_t* uri, void* factory_thisx, main_server_create_func server_create)
+{
+    etch_status_t       rv          = ETCH_SUCCESS;
+    i_sessionlistener*  newlistener = NULL;
+
+    if(listener == NULL || server_create == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "instantiating main listener ...\n");
+
+    newlistener = new_etch_listener(uri, NULL, factory_thisx, ${i}_helper_listener_create_func, server_create, ${i}_helper_resources_init);
+    if(newlistener == NULL) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not instantiate main listener\n");
+        rv = ETCH_ERROR;
+    } else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "main listener instantiated\n");
+        *listener = newlistener;
+        rv = ETCH_SUCCESS;
+    }
+
+    return rv;
+}
+
+etch_status_t ${i}_helper_listener_start_wait(i_sessionlistener* listener, const int waitms)
+{
+    etch_status_t rv     = ETCH_SUCCESS;
+    int result           = 0;
+
+    if(listener == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "starting main listener ...\n");
+
+    result = listener->transport_control(listener->thisx, new_etch_event(CLASSID_CONTROL_START_WAITUP, waitms), NULL);
+    if(result != 0) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not start main listener\n");
+        rv = ETCH_ERROR;
+    } else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "main listener started on thread %d\n", transport_thread_id(listener));
+    }
+
+    return rv;
+}
+
+etch_status_t ${i}_helper_listener_stop_wait(i_sessionlistener* listener, const int waitms)
+{
+    etch_status_t rv     = ETCH_SUCCESS;
+    int result           = 0;
+
+    if(listener == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "stopping main listener ...\n");
+
+    result = listener->transport_control(listener->thisx, new_etch_event(CLASSID_CONTROL_STOP_WAITDOWN, waitms), NULL);
+    if(result != 0) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not stop main listener\n");
+        rv = ETCH_ERROR;
+    } else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "main listener ended\n");
+
+        if (transport_session_count (listener) > 0) {
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "begin client sessions teardown\n");
+            result = transport_teardown_client_sessions(listener);
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "end client sessions teardown\n");
+        }
+    }
+
+    return rv;
+}
+
+etch_status_t ${i}_helper_listener_destroy(i_sessionlistener* listener)
+{
+    etch_status_t rv     = ETCH_SUCCESS;
+
+    etch_object_destroy(listener);
+
+    return rv;
+}
+
+#end //isSERVER
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/helper_h.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/helper_h.vm
new file mode 100644
index 0000000..ffa2dc6
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/helper_h.vm
@@ -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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#set($i = $intf.name().name().toLowerCase()) 
+
+#ifndef $i.toUpperCase()_HELPER_H
+#define $i.toUpperCase()_HELPER_H
+
+\#include "etch.h"
+\#include "etch_errno.h"
+\#include "etch_transport.h"
+#if($helper.isClient($mc))
+\#include "${i}_remote_server.h"
+#end
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if($helper.isClient($mc))
+etch_status_t $helper.getServiceName($intf)_helper_remote_server_create($helper.getServiceName($intf)_remote_server** remote_server, wchar_t* uri, void* factory_thisx, main_client_create_func client_create);
+etch_status_t $helper.getServiceName($intf)_helper_remote_server_start_wait($helper.getServiceName($intf)_remote_server* remote_server, const int waitms);
+etch_status_t $helper.getServiceName($intf)_helper_remote_server_stop_wait($helper.getServiceName($intf)_remote_server* remote_server, const int waitms);
+etch_status_t $helper.getServiceName($intf)_helper_remote_server_destroy($helper.getServiceName($intf)_remote_server* remote_server);
+#end
+
+#if($helper.isServer($mc))
+etch_status_t $helper.getServiceName($intf)_helper_listener_create(i_sessionlistener** listener, wchar_t* uri, void* factory_thisx, main_server_create_func);
+etch_status_t $helper.getServiceName($intf)_helper_listener_start_wait(i_sessionlistener* listener, const int waitms);
+etch_status_t $helper.getServiceName($intf)_helper_listener_stop_wait(i_sessionlistener* listener, const int waitms);
+etch_status_t $helper.getServiceName($intf)_helper_listener_destroy(i_sessionlistener* listener);
+#end
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* $i.toUpperCase()_HELPER_H */
+
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/impl_c.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/impl_c.vm
new file mode 100644
index 0000000..181a992
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/impl_c.vm
@@ -0,0 +1,107 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+\#include "$helper.getImplFileNameH($intf, $suffix)"
+\#include "etch_url.h"
+\#include "etch_arrayval.h"
+\#include "etch_binary_tdo.h"
+\#include "etch_exception.h"
+\#include "etch_general.h"
+\#include "etch_log.h"
+
+\#include <stdio.h>
+
+unsigned short CLASSID_$helper.getImplName($intf, $suffix).toUpperCase();	
+	
+#foreach($serviceName in $helper.getUsedServiceNames($intf))	
+\#include "${serviceName.toLowerCase()}.h"
+#end	
+	
+#if($helper.isServer($mc))
+char* $helper.getServiceName($intf).toUpperCase()_ETCHSIMP = "SIMP";
+#end
+#if($helper.isClient($mc))
+char* $helper.getServiceName($intf).toUpperCase()_ETCHCIMP = "CIMP";
+#end
+
+/* generated signatures */
+int destroy_${helper.getImplName($intf, $suffix)}x(void*);
+$helper.getImplName($intf, $suffix)* init_$helper.getImplName($intf, $suffix)(struct $helper.getRemoteName($intf, $helper.getRemoteDirectionName($mc))*, etch_object_destructor);
+
+## check if any Message goes to $suffix direction
+
+/* - - - - - - - -    
+ * instantiation
+ * - - - - - - - -   
+ */
+
+/**
+ * new_$helper.getImplName($intf, $suffix)()
+ * $helper.getImplName($intf, $suffix) constructor.
+ * add your custom initialization and virtual method overrides here.
+ */
+$helper.getImplName($intf, $suffix)* new_$helper.getImplName($intf, $suffix)(struct $helper.getRemoteName($intf, $helper.getRemoteDirectionName($mc))* $helper.getRemoteDirectionName($mc)) 
+{
+    $helper.getImplName($intf, $suffix)* p$suffix  /* allocate object and assign default virtuals */
+        = init_$helper.getImplName($intf, $suffix)($helper.getRemoteDirectionName($mc), destroy_${helper.getImplName($intf, $suffix)}x);	
+#if($helper.isServer($mc))
+    i_$helper.getBaseName($intf, $suffix)* p${suffix}_base = p${suffix}->$helper.getBaseName($intf, $suffix)_base;
+    
+    ((etch_object*)p${suffix}_base)->class_id = get_dynamic_classid_unique(&CLASSID_$helper.getImplName($intf, $suffix).toUpperCase());
+#end
+    /* add virtual method overrides, if any, here */
+    //p${suffix}->xxx = implementation
+
+    return p$suffix;
+}
+
+
+/**
+ * destroy_${helper.getImplName($intf, $suffix)}x()
+ * destructor for any user allocated memory.
+ * this code is invoked by the private perf_client_impl destructor,
+ * via perf_client.destroyex(). add code here to destroy any memory you  
+ * may have allocated for your custom perf_client implementation.
+ */
+int destroy_${helper.getImplName($intf, $suffix)}x(void* data)
+{
+    /*
+      $helper.getImplName($intf, $suffix)* thisx = ($helper.getImplName($intf, $suffix)*)data;
+     */
+    /* * *  add custom destruction here  * * */
+    /* etch_free(thisx->exampleobj); */
+
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - -
+ * session interface method overrides
+ * - - - - - - - - - - - - - - - - - - -
+ */
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * implementations of $helper.getBaseName($intf, $suffix) messages from server, if any 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+ 
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/impl_h.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/impl_h.vm
new file mode 100644
index 0000000..5b13120
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/impl_h.vm
@@ -0,0 +1,89 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#ifndef $helper.getImplName($intf, $suffix).toUpperCase()_H
+#define $helper.getImplName($intf, $suffix).toUpperCase()_H
+
+\#include "$helper.getBaseFileNameH($intf, $suffix)"
+\#include "etch_transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_$helper.getImplName($intf, $suffix).toUpperCase();
+
+//typedef struct $helper.getRemoteName($intf, $helper.getDirectionName($helper.getRemoteDirection($mc))) $helper.getRemoteName($intf, $helper.getDirectionName($helper.getRemoteDirection($mc)));
+
+/**
+ * $helper.getImplName($intf, $suffix)
+ * your custom implementation of $helper.getBaseName($intf, $suffix). add methods here 
+ * to provide implementations of messages from the client, if any.
+ */
+typedef struct $helper.getImplName($intf, $suffix)
+{
+    etch_object object;  
+
+    i_$helper.getBaseName($intf, $suffix)* $helper.getBaseName($intf, $suffix)_base; /* owned */
+    i_$intf.name().name().toLowerCase()* i$intf.name().name().toLowerCase(); /* not owned */
+    struct $helper.getRemoteName($intf, $helper.getDirectionName($helper.getRemoteDirection($mc)))* $helper.getDirectionName($helper.getRemoteDirection($mc)); /* not owned */
+
+    int (*destroyex) (void*);  /* user memory destructor */
+
+    /* - - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;  /* owned by base */
+    /* note that iobjsession->thisx is set to this $helper.getImplName($intf, $suffix)* */
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - - -
+     * base service virtuals
+     * - - - - - - - - - - - -
+     */
+## generate service virtuals
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+    $helper.getServiceName($intf).toLowerCase()_$n.name() $n.name();
+#end
+#end
+#end
+
+    void* context;
+
+
+} $helper.getImplName($intf, $suffix);
+
+/* constructor */
+$helper.getImplName($intf, $suffix)* new_$helper.getImplName($intf, $suffix) (struct $helper.getRemoteName($intf, $helper.getDirectionName($helper.getRemoteDirection($mc)))*);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* $helper.getImplName($intf, $suffix).toUpperCase()_H */
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/implx_c.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/implx_c.vm
new file mode 100644
index 0000000..b368d5f
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/implx_c.vm
@@ -0,0 +1,128 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * $helper.getImplXFileNameI($intf, $suffix) 
+ * $helper.getImplName functions which would ordinarily not be subject to edit.
+ */
+
+\#include "$helper.getImplFileNameH($intf, $suffix)"
+\#include "$helper.getRemoteFileNameH($intf, $helper.getRemoteDirectionName($mc))"
+\#include "etch_objecttypes.h"
+\#include "etch_general.h"
+\#include "etch_url.h"
+
+int destroy_$helper.getImplName($intf, $suffix)(void*);
+
+/* - - - - - - - - - - - - - - - - - - - - - - - -   
+ *$helper.getImplName($intf, $suffix) private construction / destruction 
+ * - - - - - - - - - - - - - - - - - - - - - - - -    
+ */
+
+/**
+ * init_$helper.getImplName($intf, $suffix)()
+ * called by $helper.getImplName($intf, $suffix) constructor to instantiate server implementation 
+ * object and initialize with default virtuals.
+ * @param client the remote client, not owned.
+ * @param usermem_dtor destructor for any custom memory allocations.
+ */
+$helper.getImplName($intf, $suffix)* init_$helper.getImplName($intf, $suffix)($helper.getRemoteName($intf, $helper.getRemoteDirectionName($mc))* $helper.getRemoteDirectionName($mc), 
+    etch_object_destructor usermem_dtor)
+{
+#if($helper.isServer($mc))
+    $helper.getImplName($intf, $suffix)* p${suffix} = ($helper.getImplName($intf, $suffix)*) new_object (sizeof($helper.getImplName($intf, $suffix)), 
+        ETCHTYPEB_EXESERVERIMPL, get_dynamic_classid_unique(&CLASSID_$helper.getImplName($intf, $suffix).toUpperCase()));  
+#end
+#if ($helper.isClient($mc))
+	$helper.getImplName($intf, $suffix)* p${suffix} = ($helper.getImplName($intf, $suffix)*) new_object (sizeof($helper.getImplName($intf, $suffix)), 
+        ETCHTYPEB_EXECLIENTIMPL, get_dynamic_classid_unique(&CLASSID_$helper.getImplName($intf, $suffix).toUpperCase()));  
+#end
+		
+    p${suffix}->$helper.getRemoteDirectionName($mc)  = $helper.getRemoteDirectionName($mc);  /* not owned */
+    ((etch_object*)p${suffix})->destroy = destroy_$helper.getImplName($intf, $suffix);  /* private destructor */
+    p${suffix}->destroyex = usermem_dtor;  /* user memory destructor */
+
+    /* instantiate base and copy virtuals, if any, to this object */
+#if ($helper.isServer($mc))
+    p${suffix}->$helper.getBaseName($intf, $suffix)_base = new_$helper.getBaseName($intf, $suffix)_base(p${suffix}, NULL); /* owned */
+#end
+#if ($helper.isClient($mc))
+    p${suffix}->$helper.getBaseName($intf, $suffix)_base = new_$helper.getBaseName($intf, $suffix)_base(p${suffix}); /* owned */
+#end
+
+    p${suffix}->i$helper.getIntfName($intf) = p${suffix}->$helper.getBaseName($intf, $suffix)_base->i$helper.getIntfName($intf);
+
+
+#foreach($n in $intf.iterator())	
+#if($n.isMessage())
+#if(!$n.isHidden())
+#if($n.isMsgDir($mc) || $n.isMsgDirBoth())
+    p${suffix}->$n.name() = p${suffix}->$helper.getBaseName($intf, $suffix)_base->$n.name();
+#end
+#end
+#end
+#end
+
+
+#if ($helper.isServer($mc))
+    p${suffix}->iobjsession = p${suffix}->$helper.getBaseName($intf, $suffix)_base->iobjsession;
+#end
+#if ($helper.isClient($mc))
+    p${suffix}->iobjsession = $helper.getRemoteDirectionName($mc)->server_base->iobjsession;
+#end
+    p${suffix}->iobjsession->thisx = p${suffix};  /* set implementor reference */
+    p${suffix}->_session_control = p${suffix}->$helper.getBaseName($intf, $suffix)_base->_session_control;
+    p${suffix}->_session_notify  = p${suffix}->$helper.getBaseName($intf, $suffix)_base->_session_notify;
+    p${suffix}->_session_query   = p${suffix}->$helper.getBaseName($intf, $suffix)_base->_session_query;
+
+    return p${suffix};
+}
+
+/**
+ * destroy_perf_server_impl()
+ * perf_server_impl private destructor.
+ * calls back to user destructor to effect cleanup of any perf_server_impl 
+ * memory which may have been allocated in custom code added by user.
+ */
+int destroy_$helper.getImplName($intf, $suffix) (void* data)
+{
+    $helper.getImplName($intf, $suffix)* thisx = ($helper.getImplName($intf, $suffix)*)data;
+    if (NULL == thisx) return -1;  
+
+    if (!is_etchobj_static_content(thisx))
+    {    
+        if(thisx->destroyex)
+        {   /* call back to user memory destructor */
+            thisx->destroyex(thisx);
+        }
+#if ($helper.isServer($mc))           
+        if(thisx->$helper.getBaseName($intf, $suffix)_base)
+        {
+            destroy_$helper.getBaseName($intf, $suffix)_base(thisx->$helper.getBaseName($intf, $suffix)_base);
+        }
+#end
+    }
+            
+    return destroy_objectex((etch_object*)thisx);
+}
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/intf_c.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/intf_c.vm
new file mode 100644
index 0000000..577c53d
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/intf_c.vm
@@ -0,0 +1,296 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+\#include "$helper.getIntfFileNameH($intf)"
+\#include "etch_url.h"  
+\#include "etch_objecttypes.h"
+\#include "etch_general.h"
+\#include "etch_cache.h"
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isConstant())
+$helper.getNativeTypeNameForConstants( $n.type() ) $n.name() = $helper.getTypeValue( $n.type(), $n.value() );
+#end
+#end
+
+
+## generate CLASSIDs
+unsigned short CLASSID_$helper.getIntfName( $intf ).toUpperCase()_SERVICE_INTERFACE;
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+#if (!$hasBaseClass)
+unsigned short CLASSID_$n.efqname($helper).toUpperCase();
+#if ($n.hasExtends())
+unsigned short CLASSID_$n.efqname($helper).toUpperCase()_VTABLE;
+#end
+#end
+#end
+#end
+	
+	
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getServiceName($intf)_def_$n.name()(void* thisx")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb);")
+$sb
+#end
+#end
+#end
+
+int destroy_$helper.getIntfName( $intf )_service_interface (void*);
+
+
+/*
+ * destructors
+ */
+## generate stucts
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+/**
+ * destroy_$n.efqname($helper)()
+ * $n.name().toString().toLowerCase() object destructor
+ */
+int destroy_$n.efqname($helper)(void* data)
+{
+    $n.efqname($helper)* this = ($n.efqname($helper)*)data;
+#if($n.isExcept())
+	if(!((etch_object*)this)->is_static)
+    	etch_object_destroy(this->message);
+#end    
+#foreach($p in $n.getAllParameters() )
+#if($p.type().isArray())
+    if(!((etch_object*)this)->is_static && this->$p.name())
+        etch_object_destroy(this->$p.name());
+#elseif((!$p.type().isBuiltin() && ! $helper.isEnumParam($p)) || $p.type().isString() || $p.type().isObject())
+    if(!((etch_object*)this)->is_static && this->$p.name())
+        etch_object_destroy(this->$p.name()); 
+#end
+#end
+    destroy_object(this);
+    return 0;
+}
+#end
+#end
+
+/* - - - - - - - - - - - - - -  
+ * constructors
+ * - - - - - - - - - - - - - -  
+ */
+
+## generate stucts
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+#if (!$hasBaseClass)
+/**
+ * new_$n.efqname($helper)()
+ * $n.name().toString().toLowerCase() object constructor.
+ */
+$n.efqname($helper)* new_$n.efqname($helper)() 
+{
+#if($n.hasExtends())
+	etchparentinfo* inheritlist = NULL;
+    vtabmask* vtab  = NULL;
+#end
+#if($n.isExcept())
+
+	$n.efqname( $helper)* $n.name().toString().toLowerCase()  = ($n.efqname($helper)*) new_object(sizeof($n.efqname($helper)), 
+        ETCHTYPEB_EXCEPTION, get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase()));
+    
+    $n.name().toString().toLowerCase()->message = new_stringw(L"user generated exception, no default exception message.");
+    $n.name().toString().toLowerCase()->errorcode = ETCH_ERROR;
+    $n.name().toString().toLowerCase()->excptype = EXCPTYPE_USERDEFINED;
+        
+#else
+    $n.efqname( $helper)* $n.name().toString().toLowerCase() = ($n.efqname($helper)*) new_object(sizeof($n.efqname($helper)), 
+        ETCHTYPEB_USER, get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase()));
+#end
+		
+#if($n.hasExtends())
+    if (NULL == (vtab = etch_cache_find(get_vtable_cachehkey(get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase()_VTABLE)), 0)))  
+    {   
+        vtab = new_vtable(NULL, sizeof(vtabmask), get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase()_VTABLE));
+        etch_cache_insert(((etch_object*)vtab)->get_hashkey(vtab), vtab, FALSE);
+        
+        inheritlist = get_vtab_inheritance_list((etch_object*)$n.name().toString().toLowerCase(),
+            2, 1, get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase()_VTABLE)); /* create inheritance list */ 
+        inheritlist[1].o.obj_type = ETCHTYPEB_USER;
+        inheritlist[1].c.class_id = get_dynamic_classid_unique(&CLASSID_$n.getExtends().efqname($helper).toUpperCase()); 
+    } 
+    ((etch_object*)$n.name().toString().toLowerCase())->vtab = vtab;  
+#end
+	((etch_object*)$n.name().toString().toLowerCase())->destroy = destroy_$n.efqname($helper);
+
+    return $n.name().toString().toLowerCase();
+}
+
+
+#if ($n.isEnumx())
+$n.efqname($helper)* new_$n.efqname($helper)_init($n.efqname($helper)_enum val) {
+	$n.efqname($helper)* theEnum = new_$n.efqname($helper)();
+	theEnum->value = val;
+	return theEnum;
+}
+#end
+
+
+
+/**
+ * clone_$n.efqname($helper)()
+ * $n.name().toString().toLowerCase() object copy constructor.
+ */
+$n.efqname($helper)* clone_$n.efqname($helper)($n.efqname($helper)* other) 
+{
+#if($n.hasExtends())
+	etchparentinfo* inheritlist = NULL;
+    vtabmask* vtab  = NULL;
+#end
+#if($n.isExcept())
+	$n.efqname( $helper)* $n.name().toString().toLowerCase() = ($n.efqname($helper)*) new_object(sizeof($n.efqname($helper)), 
+        ETCHTYPEB_EXCEPTION, get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase()));
+#else
+    $n.efqname( $helper)* $n.name().toString().toLowerCase() = ($n.efqname($helper)*) new_object(sizeof($n.efqname($helper)), 
+        ETCHTYPEB_USER, get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase()));
+#end
+		
+#foreach($p in $n.getAllParameters())
+    $n.name().toString().toLowerCase()->$p.name() = other->$p.name(); 
+#end
+
+#if($n.hasExtends())
+    if (NULL == (vtab = etch_cache_find(get_vtable_cachehkey(get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase()_VTABLE)), 0)))  
+    {   
+        vtab = new_vtable(NULL, sizeof(vtabmask), get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase()_VTABLE));
+        etch_cache_insert(((etch_object*)vtab)->get_hashkey(vtab), vtab, FALSE);
+        
+        inheritlist = get_vtab_inheritance_list((etch_object*)$n.name().toString().toLowerCase(),
+            2, 1, get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase()_VTABLE)); /* create inheritance list */ 
+        inheritlist[1].o.obj_type = ETCHTYPEB_USER;
+        inheritlist[1].c.class_id = get_dynamic_classid_unique(&CLASSID_$n.getExtends().efqname($helper).toUpperCase()); 
+    } 
+    ((etch_object*)$n.name().toString().toLowerCase())->vtab = vtab;  
+#end
+	((etch_object*)$n.name().toString().toLowerCase())->destroy = destroy_$n.efqname($helper);
+
+    return $n.name().toString().toLowerCase();
+}
+
+
+/**
+ * is_$n.efqname( $helper)()
+ */
+int is_$n.efqname( $helper)(void* x) 
+{
+    return x && ((etch_object*)x)->class_id == CLASSID_$n.efqname( $helper).toUpperCase();
+}
+
+#end
+#end
+#end
+
+/**
+ * new_$helper.getServiceName( $intf )_service_interface
+ */
+i_$helper.getServiceName( $intf )* new_$helper.getServiceName( $intf )_service_interface ()
+{
+    i_$helper.getServiceName( $intf )* isvc = (i_$helper.getServiceName( $intf )*) new_object (sizeof(i_$intf.name().name().toLowerCase()), ETCHTYPEB_SVCINTERFACE, 
+        get_dynamic_classid_unique(&CLASSID_$helper.getServiceName( $intf ).toUpperCase()_SERVICE_INTERFACE));
+
+    ((etch_object*)isvc)->destroy = destroy_$helper.getServiceName( $intf )_service_interface;
+
+#foreach($n in $intf.iterator())
+#if ($n.isMessage())
+#if (!$n.isHidden())
+    isvc->$n.name() = $helper.getServiceName( $intf )_def_$n.name();
+#end
+#end
+#end
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct())
+#if (!$n.isHidden())
+    isvc->$n.name().toString() = new_$n.efqname($helper)();
+#end
+#end
+#end
+
+    return isvc;
+}
+
+/**
+ * destroy_$helper.getServiceName( $intf )_service_interface()
+ * i_$helper.getServiceName( $intf ) destructor.
+ */
+int destroy_$helper.getServiceName($intf)_service_interface (void* data)
+{
+    i_$helper.getServiceName( $intf )* isvc = (i_$helper.getServiceName( $intf )*)data;
+    if (NULL == isvc) return -1;  
+
+    if (!is_etchobj_static_content(isvc))
+    {    
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct())
+#if (!$n.isHidden())
+        etch_object_destroy(isvc->$n.name().toString());
+#end
+#end
+#end
+    }
+    
+    return destroy_objectex((etch_object*)isvc);
+}
+
+
+/* - - - - - - - - - - - - - -  
+ * service method stubs
+ * - - - - - - - - - - - - - -  
+ */
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getServiceName( $intf )_def_$n.name()(void* thisx")
+#foreach($p in $n.iterator())
+#set ($sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb)")
+$sb
+{
+#foreach( $p in $n.iterator())
+#if($p.type().isBuiltin())
+	etch_object_destroy($p.name());
+	$p.name() = NULL;
+#else
+    etch_free($p.name());
+#end
+#end
+    return NULL;
+}
+
+#end
+#end
+#end
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/intf_h.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/intf_h.vm
new file mode 100644
index 0000000..d423cce
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/intf_h.vm
@@ -0,0 +1,221 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#ifndef $helper.getIntfName( $intf ).toUpperCase()_H
+#define $helper.getIntfName( $intf ).toUpperCase()_H
+
+\#include "etch_object.h"
+\#include "etch_mailbox.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+## generate CLASSIDs
+extern unsigned short CLASSID_$helper.getIntfName( $intf ).toUpperCase()_SERVICE_INTERFACE;
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+#if (!$hasBaseClass)
+extern unsigned short CLASSID_$n.efqname($helper).toUpperCase();
+#if ($n.hasExtends())
+extern unsigned short CLASSID_$n.efqname($helper).toUpperCase()_VTABLE;
+#end
+#end
+#end
+#end
+
+## generate typedefs
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct())
+#if (!$hasBaseClass)
+//typedef struct $n.efqname($helper) $n.efqname($helper);
+#end
+#end
+#end
+
+#foreach($serviceName in $helper.getUsedServiceNames($intf))	
+\#include "${serviceName.toLowerCase()}.h"
+#end
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isConstant())
+extern $helper.getNativeTypeNameForConstants( $n.type() ) $n.name();
+#end
+#end
+
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isEnumx())
+typedef enum $helper.getIntfName($intf)_$n.name()_enum
+{
+#set( $sep = "" )
+#foreach( $i in $n.iterator() )
+    $sep$n.name()_$i.name()
+#set( $sep = ", " )
+#end
+} $helper.getIntfName( $intf )_$n.name()_enum;
+
+/**
+ * $n.efqname($helper) 
+ * $helper.getServiceName($intf) service value object $n.name().toString().toLowerCase() 
+ */
+typedef struct $n.efqname($helper)
+{
+    etch_object object;
+
+    $helper.getIntfName( $intf )_$n.name()_enum value;
+ 
+ } $n.efqname($helper);
+
+$n.efqname( $helper)* new_$n.efqname($helper)();
+$n.efqname( $helper)* new_$n.efqname($helper)_init($n.efqname( $helper)_enum val);
+$n.efqname($helper)* clone_$n.efqname($helper)($n.efqname($helper)* other);
+int is_$n.efqname($helper)(void* obj); 
+#end
+#end
+
+## generate stucts
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct()  || $n.isExcept())
+#if (!$hasBaseClass)
+/**
+ * $n.efqname($helper) 
+ * $helper.getServiceName($intf) service value object $n.name().toString().toLowerCase() 
+ */
+typedef struct $n.efqname($helper)
+{
+    etch_object object;
+
+#if($n.isExcept())
+    etch_string*    message;
+    uint32          errorcode;
+    excptype_t      excptype;
+#end
+
+#foreach( $p in $n.getAllParameters() )
+    $helper.getNativeTypeName( $p.type(), true ) $p.name();
+#end
+ 
+ } $n.efqname($helper);
+
+$n.efqname( $helper)* new_$n.efqname($helper)();
+$n.efqname($helper)* clone_$n.efqname($helper)($n.efqname($helper)* other); 
+## Generate setter and getter
+int is_$n.efqname($helper)(void* obj); 
+
+#end
+#end
+#end
+
+
+##generate general typdefs
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#set ($sb = "typedef $helper.getPointerTypeName( $n.type() ) (*$helper.getServiceName($intf)_$n.name())(void* thisx")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName( $p.type() ) $p.name()")
+#end
+#set ($sb = "$sb);")
+$sb
+#end
+#end
+#end
+
+## generate mailbox typedef
+//typedef struct i_mailbox i_mailbox;
+
+## generate async begin typedefs
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#set ($sb = "typedef i_mailbox* (*$helper.getServiceName($intf)_async_begin_$n.name())(void* thisx")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb);")
+$sb
+#end
+#end
+#end
+
+## generate async end typedefs
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#set ($sb = "typedef $helper.getPointerTypeName( $n.type() ) (*$helper.getServiceName($intf)_async_end_$n.name())(void* thisx, i_mailbox*);")
+$sb
+#end
+#end
+#end
+
+/**
+ * i_$helper.getIntfName( $intf )
+ * $helper.getIntfName( $intf ) service interface
+ */
+typedef struct i_$helper.getIntfName( $intf )
+{
+    etch_object object;
+
+    /* - - - - - - - - - - -
+     * service virtuals
+     * - - - - - - - - - - -
+     */
+## generate service virtuals
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+    $helper.getServiceName($intf)_$n.name() $n.name();
+#end
+#end
+#end
+     
+    /* - - - - - - - - - - -
+     * service data
+     * - - - - - - - - - - -
+     */
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct()  || $n.isExcept())
+#if (!$n.isHidden())
+    $n.efqname($helper)* $n.name().toString();
+#end
+#end
+#end
+
+} i_$helper.getIntfName($intf);
+
+#if ($intf.hasDescr())
+/**
+#foreach( $s in $intf.descr() )
+ * $s
+#end
+ */
+#end
+i_$helper.getIntfName( $intf )* new_$helper.getIntfName($intf)_service_interface();
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* $helper.getIntfName($intf).toUpperCase()_H */
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/main_c.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/main_c.vm
new file mode 100644
index 0000000..b09253d
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/main_c.vm
@@ -0,0 +1,198 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+#set($i = $intf.name().name().toLowerCase()) 
+/*
+ * $helper.getMainFileNameI($intf, $mc)
+ */
+ 
+\#include "$helper.getMainFileNameH($intf, $mc)"
+\#include "etch_objecttypes.h"
+\#include "etch_runtime.h"
+\#include "etch_arrayval.h"
+\#include "etch_nativearray.h"
+\#include "etch_binary_tdo.h"
+\#include "etch_general.h"
+
+
+#if($helper.isServer($mc))
+/**
+ * new_$helper.getBaseName($intf, $suffix)
+ * create an individual client's $helper.getBaseName($intf, $suffix) implementation.
+ * this is java binding's new$intf.name().name().toLowerCase()Server().
+ * this is called back from helper.new_helper_accepted_server() (java's newServer).
+ * @param p parameter bundle. caller retains. 
+ * @return the i_$helper.getBaseName($intf, $suffix), whose thisx is the $intf.name().name().toLowerCase()_server_impl.
+ */
+static void* ${i}_server_create(void* factoryData, void* sessionData)
+{
+    etch_session* session = (etch_session*)sessionData;
+    $helper.getRemoteName($intf, $helper.getRemoteDirectionName($mc))* client  = ($helper.getRemoteName($intf, $helper.getRemoteDirectionName($mc))*) session->client;
+
+    $helper.getImplName($intf, $suffix)* newserver = new_$helper.getImplName($intf, $suffix)(client);
+
+    return newserver->$helper.getBaseName($intf, $suffix)_base;
+}
+
+etch_status_t ${i}_listener_start(i_sessionlistener** pplistener, wchar_t* uri, int waitupms)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    
+    etch_status = ${i}_helper_listener_create(pplistener, uri, NULL, ${i}_server_create);
+    if(etch_status == ETCH_SUCCESS) 
+    {
+        etch_status = ${i}_helper_listener_start_wait(*pplistener, waitupms);
+    }
+
+    return etch_status;
+}
+
+etch_status_t ${i}_listener_stop(i_sessionlistener* plistener, int waitupms)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    
+    etch_status = ${i}_helper_listener_stop_wait(plistener, waitupms);
+    if(etch_status == ETCH_SUCCESS) 
+    {
+        ${i}_helper_listener_destroy(plistener);
+    }
+
+    return etch_status;
+}
+
+#end
+#if($helper.isClient($mc))
+/**
+ * new_$helper.getBaseName($intf, $suffix)().
+ * callback constructor for client implementation object.
+ * this callback address is passed to start_$helper.getBaseName($intf, $suffix)() in [main].
+ * @param server the remote server. 
+ * @remarks this callback must be supplied, i.e. its functionality cannot be 
+ * defaulted, since the client implementation constructor new_$helper.getImplName($intf, $suffix)()
+ * is not known to start_$helper.getBaseName($intf, $suffix)().
+ */
+static i_$helper.getBaseName($intf, $suffix)* ${i}_client_create(void* factory_thisx, $helper.getRemoteName($intf, $helper.getRemoteDirectionName($mc))* server)
+{
+    $helper.getImplName($intf, $suffix)* client = new_$helper.getImplName($intf, $suffix)(server);
+    return client? client->$helper.getBaseName($intf, $suffix)_base:NULL;
+}
+#end
+
+#if($helper.isServer($mc))
+#ifndef NO_ETCH_SERVER_MAIN
+#end
+
+/**
+ * main()
+ */
+int main(int argc, char* argv[])
+{
+#if($helper.isServer($mc))
+	etch_status_t etch_status = ETCH_SUCCESS;
+    i_sessionlistener* listener = NULL;
+    int waitupms = 4000;
+    
+    wchar_t* uri = L"tcp://0.0.0.0:4001";
+
+    etch_config_t* config = NULL;
+    etch_config_create(&config);
+	
+    etch_status = etch_runtime_initialize(config);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+        return 1;
+    }
+
+    etch_status = ${i}_listener_start(&listener, uri, waitupms);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+
+    // wait for keypress
+    waitkey();
+
+    etch_status = ${i}_listener_stop(listener, waitupms);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+
+    etch_status = etch_runtime_shutdown();
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+        return 1;
+    }
+	etch_config_destroy(config);
+    // wait for keypress
+    waitkey();
+	
+    return 0;
+#end
+#if($helper.isClient($mc))
+    etch_status_t etch_status    = ETCH_SUCCESS;
+    ${i}_remote_server* remote = NULL;
+    int waitupms = 4000;
+    
+    wchar_t* uri = L"tcp://127.0.0.1:4004";	
+	
+       etch_config_t* config = NULL;
+    etch_config_create(&config);
+    // set properties or read file
+
+    etch_status = etch_runtime_initialize(config);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+        return 1;
+    }
+
+    etch_status = ${i}_helper_remote_server_create(&remote, uri, NULL, ${i}_client_create);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+
+    etch_status = ${i}_helper_remote_server_start_wait(remote, waitupms);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+	
+	//add your implementation here
+    
+    // wait until key press
+    waitkey();
+
+    etch_status = ${i}_helper_remote_server_stop_wait(remote, waitupms);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+
+    etch_status = ${i}_helper_remote_server_destroy(remote);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+	etch_config_destroy(config);
+	return 0;
+#end
+}
+
+#if($helper.isServer($mc))
+#endif /* NO_ETCH_SERVER_MAIN */
+#end
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/main_h.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/main_h.vm
new file mode 100644
index 0000000..259b9e3
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/main_h.vm
@@ -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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+#set($i = $intf.name().name().toLowerCase()) 
+/*
+ * $helper.getMainFileNameH($intf, $mc)
+ * $suffix exe main() private header
+ */
+
+#ifndef $helper.getMainFileNameH($intf, $mc).toUpperCase().replace(".","_")
+#define $helper.getMainFileNameH($intf, $mc).toUpperCase().replace(".","_")
+
+\#include "etch_runtime.h"
+\#include "$helper.getHelperFileNameH($intf)"
+\#include "$helper.getImplFileNameH($intf, $suffix)"
+\#include "$helper.getRemoteFileNameH($intf, $helper.getDirectionName($helper.getRemoteDirection($mc)))"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * ${i}_listener_start(pplistener, uri, waitupms)
+ * Start the listener at the given uri, waiting waitupms microseconds for listener startup.
+ * The created listener is saved at address pointed to by pplistener.
+ */
+extern etch_status_t ${i}_listener_start(i_sessionlistener** pplistener, wchar_t* uri, int waitupms);
+
+/*
+ * ${i}_listener_stop(plistener, waitupms)
+ * Stop the listener given by plistener, waiting waitupms microseconds to stop.
+ */
+extern etch_status_t ${i}_listener_stop(i_sessionlistener* plistener, int waitupms);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* $helper.getMainFileNameH($intf, $mc).toUpperCase() */
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/readme.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/readme.vm
new file mode 100644
index 0000000..80a309c
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/readme.vm
@@ -0,0 +1,28 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+Generated C Binding files of Apache Etch.
+
+Add your specific implementations to xxx_client_impl.c/xxx_server_impl.c
+Startup is done via xxx_listener_main.c/xxx_client_main.c
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_c.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_c.vm
new file mode 100644
index 0000000..0525e64
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_c.vm
@@ -0,0 +1,278 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+\#include "$helper.getRemoteFileNameH($intf, '')"
+\#include "etch_url.h"  
+\#include "etch_objecttypes.h"
+\#include "etch_general.h"
+
+unsigned short CLASSID_$helper.getRemoteName($intf, "").toUpperCase();
+
+int destroy_$helper.getRemoteName($intf, '') (void*);
+\#if(0)
+etch_message* etchremote_new_message($helper.getRemoteName($intf, '')*, etch_type*);
+int etchremote_send($helper.getRemoteName($intf, '')*, etch_message*);
+int etchremote_begincall($helper.getRemoteName($intf, '')*, etch_message*, void**);
+int etchremote_endcall  ($helper.getRemoteName($intf, '')*, i_mailbox*, etch_type*, void**);
+int etchremote_transport_control ($helper.getRemoteName($intf, '')*, etch_event*, etch_int32*);
+int etchremote_transport_notify  ($helper.getRemoteName($intf, '')*, etch_event*);
+etch_object* etchremote_transport_query ($helper.getRemoteName($intf, '')*, etch_object*); 
+int etchremote_start_waitup  ($helper.getRemoteName($intf, '')*, const int);
+int etchremote_stop_waitdown ($helper.getRemoteName($intf, '')*, const int);
+#endif
+
+
+/* - - - - - - - - - - - - - -  
+ * constructors
+ * - - - - - - - - - - - - - -  
+ */
+
+/**
+ * new_$helper.getRemoteName($intf, '')
+ * @param ids delivery service -- caller retains
+ * @param vf $intf.name().name().toLowerCase() value factory - caller retains 
+ * @param i$intf.name().name().toLowerCase() optional $intf.name().name().toLowerCase() service interface -- caller retains
+ */
+$helper.getRemoteName($intf, '')* new_$helper.getRemoteName($intf, '') (void* thisx, 
+    i_delivery_service* ids, etch_value_factory* vf, i_$helper.getIntfName($intf)* iservice)
+{
+    $helper.getRemoteName($intf, '')* remote = ($helper.getRemoteName($intf, '')*) new_object (sizeof($helper.getRemoteName($intf, '')), 
+        ETCHTYPEB_REMOTE, get_dynamic_classid_unique(&CLASSID_$helper.getRemoteName($intf, '').toUpperCase()));
+
+    ((etch_object*)remote)->destroy = destroy_$helper.getRemoteName($intf, '');
+
+    /* $intf.name().name().toLowerCase()_remote instance data and methods */
+    remote->dsvc = ids; 
+    remote->vf   = vf;
+    remote->start_waitup  = etchremote_start_waitup;
+    remote->stop_waitdown = etchremote_stop_waitdown;
+
+    /* transport methods */
+    remote->transport_control = etchremote_transport_control;
+    remote->transport_notify  = etchremote_transport_notify;
+    remote->transport_query   = etchremote_transport_query;
+
+    /* remote base */
+    remote->new_message = etchremote_new_message;
+    remote->send        = etchremote_send;
+    remote->sendex      = etchremote_sendex;
+    remote->begin_call  = etchremote_begincall;
+    remote->end_call    = etchremote_endcall;
+
+    /* $helper.getIntfName($intf) service */
+    if (iservice)
+        remote->i$helper.getIntfName($intf) = iservice;
+    else
+    {   remote->i$helper.getIntfName($intf) = new_$intf.name().name().toLowerCase()_service_interface();
+        remote->is_service_interface_owned = TRUE;
+    }
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+    remote->$n.name() = remote->i$helper.getIntfName($intf)->$n.name().toString();
+#end
+#end
+#end
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct())
+#if (!$n.isHidden())
+    remote->$n.name().toString() = remote->i$helper.getIntfName($intf)->$n.name();
+#end
+#end
+#end
+
+    return remote;
+}
+
+
+/**
+ * destroy_$helper.getRemoteName($intf, '')()
+ * $helper.getRemoteName($intf, '') destructor.
+ */
+int destroy_$helper.getRemoteName($intf, '') (void* data)
+{
+    $helper.getRemoteName($intf, '')* thisx = ($helper.getRemoteName($intf, '')*)data;
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx))
+    {
+        if (thisx->is_service_interface_owned && thisx->i$helper.getIntfName($intf))
+            etch_object_destroy(thisx->i$helper.getIntfName($intf));
+    }
+
+    return destroy_objectex((etch_object*)thisx);
+}
+
+
+/* - - - - - - - - - - - - - -  
+ * remote methods
+ * - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchremote_new_message()
+ * instantiates a message to be sent via this.send() or this.begin_call().
+ * @param thisx this remote object.
+ * @param message_type type of message, caller retains.
+ * @return message object, which could wrap an exception.
+ */
+\#if(0)
+etch_message* etchremote_new_message ($helper.getRemoteName($intf, $mc)* thisx, etch_type* message_type)
+{
+    etch_message* msg = new_message(message_type, ETCH_DEFSIZE, thisx->vf);
+    return msg;
+}
+#endif
+
+
+/**
+ * etchremote_send()
+ * sends message to recipient without waiting for a response.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return 0 success, -1 failure.
+ */
+\#if(0)
+int etchremote_send ($helper.getRemoteName($intf, $mc)* thisx, etch_message* msg)
+{
+    const int result = thisx->dsvc->itm->transport_message(thisx->dsvc, NULL, msg);
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_begincall()
+ * sends message beginning a call sequence.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return in out parameter, a mailbox which can be used to retrieve the response.
+ * @return 0 success, -1 failure.
+ */
+
+\#if(0)
+int etchremote_begincall ($helper.getRemoteName($intf, $mc)* thisx, etch_message* msg, i_mailbox** out)
+{
+    const int result = thisx->dsvc->begin_call(thisx->dsvc, msg, out);
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_endcall()
+ * finishes a call sequence by waiting for a response message.
+ * @param thisx this remote object.
+ * @param mbox a mailbox which will be used to read an expected message response.
+ * @param response_type the message type of the expected response.
+ * @return in out parameter, on success, the response.
+ * @return 0 success, -1 failure.
+ */
+\#if(0)
+int etchremote_endcall ($helper.getRemoteName($intf, $mc)* thisx, i_mailbox* mbox, etch_type* response_type, etch_object** out)
+{
+    const int result = thisx->dsvc->end_call(thisx->dsvc, mbox, response_type, out);
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_transport_control()
+ * @param evt caller relinquishes
+ * @param value caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+\#if(0)
+int etchremote_transport_control ($helper.getRemoteName($intf, $mc)* thisx, etch_event* evt, etch_int32* value)
+{
+    const int result = thisx->dsvc->itm->transport_control(thisx->dsvc, evt, value);
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_transport_notify()
+ * @param evt caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+\#if(0)
+int etchremote_transport_notify  ($helper.getRemoteName($intf, $mc)* thisx, etch_event* evt)
+{
+    const int result = thisx->dsvc->itm->transport_notify(thisx->dsvc, evt);
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_transport_query()
+ * @param query caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+\#if(0)
+etch_object* etchremote_transport_query ($helper.getRemoteName($intf, $mc)* thisx, etch_object* query) 
+{
+    etch_object* resultobj = thisx->dsvc->itm->transport_query(thisx->dsvc, query);
+    return resultobj;
+}
+#endif
+
+
+/**
+ * etchremote_start_waitup()
+ * start the transport and wait for it to come up.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+\#if(0)
+int etchremote_start_waitup ($helper.getRemoteName($intf, $mc)* thisx, const int waitms)
+{
+    const int result = thisx->transport_control(thisx, 
+        new_etch_event(CLASSID_CONTROL_START_WAITUP, waitms), NULL);
+
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_stop_waitdown()
+ * stop the transport and wait for it to go down.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+\#if(0)
+int etchremote_stop_waitdown ($helper.getRemoteName($intf, $mc)* thisx, const int waitms)
+{
+    const int result = thisx->transport_control(thisx, 
+        new_etch_event(CLASSID_CONTROL_STOP_WAITDOWN, waitms), NULL);
+
+    return result;
+}
+#endif
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_client_c.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_client_c.vm
new file mode 100644
index 0000000..6a5a7ce
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_client_c.vm
@@ -0,0 +1,480 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * $helper.getRemoteName($intf, $suffix).c
+ */
+
+\#include "$helper.getRemoteFileNameH($intf, $suffix)"
+\#include "$helper.getVfFileNameH($intf)"
+\#include "etch_url.h"
+\#include "etch_log.h"
+\#include "etch_objecttypes.h"
+\#include "etch_general.h"
+
+static const char* LOG_CATEGORY = "$helper.getRemoteName($intf, $suffix)";
+
+unsigned short CLASSID_$helper.getRemoteName($intf, $suffix).toUpperCase();
+	
+char* $helper.getServiceName($intf).toUpperCase()_ETCHREMC = "REMC";
+
+## generate async begin typedefs
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())	
+	
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, '')_client_$n.name() (void*")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb);")
+$sb
+#if (!$n.isOneway())
+#set ($sb = "i_mailbox* $helper.getRemoteName($intf, '')_begin_client_$n.name() (void*")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb);")
+$sb
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, '')_end_client_$n.name()(void*, i_mailbox*);")
+$sb
+#end
+
+#end
+#end
+#end
+#end
+
+
+/* generated signatures */
+int destroy_$helper.getRemoteName($intf, $suffix) (void*);
+
+
+/* - - - - - - - -    
+ * instantiation
+ * - - - - - - - -   
+ */
+
+/**
+ * new_$helper.getServiceName($intf)_remote_client()
+ * $helper.getRemoteName($intf, $suffix) constructor.
+ */
+$helper.getRemoteName($intf, $suffix)* new_$helper.getServiceName($intf)_remote_client (void* thisx, etch_session* session, etch_value_factory* vf)
+{
+    $helper.getRemoteName($intf, "")* remote = NULL;
+    $helper.getRemoteName($intf, $suffix)* rc = NULL;
+
+    rc = ($helper.getRemoteName($intf, $suffix)*) new_object (sizeof($helper.getRemoteName($intf, $suffix)), 
+       ETCHTYPEB_REMOTECLIENT, get_dynamic_classid_unique(&CLASSID_$helper.getRemoteName($intf, $suffix).toUpperCase()));
+
+    ((etch_object*)rc)->destroy = destroy_$helper.getRemoteName($intf, $suffix);
+
+    /* we "implement" the service interface here since it may contain client-directed 
+     * items, in which case those methods and data are exposed in this object.  we do  
+     * not expose the service's server-directed methods in the remote client object.
+     */
+    remote = new_$helper.getRemoteName($intf, "") (thisx, session->ds, vf, NULL);
+    remote->remote_type = ETCH_REMOTETYPE_CLIENT;
+
+    rc->remote_base = remote;
+    rc->client_base = new_$helper.getBaseName($intf, $suffix)_base (thisx);
+    rc->session_id = session->session_id;
+
+	rc->vf = ($helper.getVfName($intf)*) rc->remote_base->vf;
+	
+    /* override client-directed virtuals with implementations here */
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())
+    rc->$n.name() = $helper.getRemoteName($intf, '')_client_$n.name();
+#end
+#end
+#end
+#end
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#if (!$n.isOneway())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())	
+    rc->async_begin_$n.name() = $helper.getRemoteName($intf, '')_begin_client_$n.name();
+    rc->async_end_$n.name() = $helper.getRemoteName($intf, '')_end_client_$n.name();
+#end	
+#end
+#end
+#end
+#end
+    return rc;
+}
+
+
+/**
+ * destroy_$helper.getRemoteName($intf, $suffix)()
+ * $helper.getRemoteName($intf, $suffix) destructor.
+ */
+int destroy_$helper.getRemoteName($intf, $suffix) (void* thisx)
+{
+    $helper.getRemoteName($intf, $suffix)* remote = ($helper.getRemoteName($intf, $suffix)*)thisx;
+    if (NULL == remote) return -1;
+
+    if (!is_etchobj_static_content(remote))
+    {
+		etch_object_destroy(remote->remote_base);
+		remote->remote_base = NULL;
+		etch_object_destroy(remote->client_base);
+		remote->client_base = NULL;
+    }
+    return destroy_objectex((etch_object*)remote);
+}
+
+
+
+
+
+/**
+ * perf_remote_dispose_mailbox()
+ * dispose of mailbox after use.
+ * this is the common means of disposing of a mailbox when we're done with it.
+ * this would intuitively be part of base class code but we don't have one.
+ * @param thisx the remote server this.
+ * @param pibox pointer to pointer to the mailbox interface, passed indirectly
+ * such that this method can null out the caller's mailbox reference.
+ * @return 0 if mailbox was successfullly closed, otherwise -1. 
+ * caller's i_mailbox reference is nulled out regardless of result.
+ */
+int $helper.getRemoteName($intf, "")_${suffix}_dispose_mailbox ($helper.getRemoteName($intf, $suffix)* thisx, i_mailbox** pibox)
+{
+    int result = 0;
+    i_mailbox* ibox = 0;
+    if (!pibox || !*pibox) return -1;
+    ibox = *pibox;
+    *pibox = NULL;  /* null out caller's reference */
+    
+    if (0 != (result = ibox->close_read (ibox)))
+    {  
+        /* we should not need this failsafe unregister if close_read() 
+         * is reliable, since close_read() will do the unregister */
+        i_mailbox_manager* imgr = ibox->manager(ibox);
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not close mailbox %x\n", ibox);
+        if (imgr) result = imgr->unregister(imgr, ibox);
+    }
+ 
+    /* mailbox manager does not destroy the unregistered mailbox since it is    
+     * owned by whoever registered it, that being us, so we destroy it here. 
+     * debug heap issue note: this is/was the spot.
+     */
+    etch_object_destroy(ibox);   
+    return result;
+}
+
+/**
+ * perf_remote_get_stubbase()
+ * convenience to return stub base object from remote server object.
+ */
+etch_stub* $helper.getRemoteName($intf, "")_${suffix}_get_stubbase ($helper.getRemoteName($intf, $suffix)* thisx)
+{
+    etch_stub* stub = NULL;
+    xxxx_either_stub* clistub = (xxxx_either_stub*) thisx->client_factory->stub;
+    stub = clistub? clistub->stub_base: NULL;
+    return stub;
+}
+
+
+/**
+ * $helper.getRemoteName($intf, "")_set_session_notify()
+ * convenience to override remote server's session_notify().
+ * @return the session_notify function that was overridden.
+ */
+etch_session_notify $helper.getRemoteName($intf, "")_${suffix}_set_session_notify($helper.getRemoteName($intf, $suffix)* thisx, etch_session_notify newfunc)
+{
+    etch_session_notify oldfunc = NULL;
+    etch_stub* stub = $helper.getRemoteName($intf, "")_${suffix}_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_notify;
+    stub->impl_callbacks->_session_notify = newfunc;
+    return oldfunc;
+}
+
+
+/**
+ * $helper.getRemoteName($intf, "")_set_session_control()
+ * convenience to override remote server's session_control().
+ * @return the session_control function that was overridden.
+ */
+etch_session_control $helper.getRemoteName($intf, "")_${suffix}_set_session_control($helper.getRemoteName($intf, $suffix)* thisx, etch_session_control newfunc)
+{
+    etch_session_control oldfunc = NULL;
+    etch_stub* stub = $helper.getRemoteName($intf, "")_${suffix}_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_control;
+    stub->impl_callbacks->_session_control = newfunc;
+    return oldfunc;
+}
+
+
+/**
+ * $helper.getRemoteName($intf, "")_set_session_query()
+ * convenience to override remote server's session_query().
+ * @return the session_query function that was overridden.
+ */
+etch_session_query $helper.getRemoteName($intf, "")_${suffix}_set_session_query($helper.getRemoteName($intf, $suffix)* thisx, etch_session_query newfunc)
+{
+    etch_session_query oldfunc = NULL;
+    etch_stub* stub = $helper.getRemoteName($intf, "")_${suffix}_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_query;
+    stub->impl_callbacks->_session_query = newfunc;
+    return oldfunc;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -  
+ * remote procedure call implementations
+ * - - - - - - - - - - - - - - - - - - - - 
+ */
+ 
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())
+
+/* - - - - - - - - - - -  
+ * $helper.getIntfName($intf).$n.name()()
+ * - - - - - - - - - - -  
+ */
+ 
+#if (!$n.isOneway())
+/**
+ * $helper.getRemoteName($intf, '')_begin_$n.name()()
+ * $helper.getIntfName($intf).$n.name() async start 
+ * TODO: doc generation
+ */
+#set ($sb = "i_mailbox* $helper.getRemoteName($intf, '')_begin_client_$n.name()(void* thisx")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb)")
+$sb
+{
+    $helper.getRemoteName($intf, $suffix)* remote = ($helper.getRemoteName($intf, $suffix)*)thisx;
+    int _result = 0;
+    i_mailbox* _mbox = NULL;
+    etch_message* _msg = NULL;
+    etch_type* _msgtype = $helper.getVfName($intf)_get_static()->_mt_$helper.getServiceName($intf)_$n.name();
+
+    do
+    {   
+        _msg = remote->remote_base->new_message (remote->remote_base, _msgtype);
+        if (!_msg) break;
+
+#foreach( $p in $n.iterator() )
+        _result = message_putc (_msg, $helper.getVfName($intf)_get_static()->_mf_$helper.getIntfName($intf)_$p.name(), (void**)&$p.name());
+		if ($p.name() != NULL && 0 != _result) break; 
+#end
+
+        /* fyi msg memory is relinquished here regardless of result */ 
+        _result = remote->remote_base->begin_call(remote->remote_base, _msg, (void**)&_mbox);
+        _msg = NULL;
+
+    } while(0);
+
+    /* destroy any unrelinquished objects */
+#foreach( $p in $n.iterator() )
+    etch_object_destroy($p.name());
+	$p.name() = NULL;
+#end
+    etch_object_destroy(_msg);
+	_msg = NULL;
+    return _mbox;
+}
+
+/**
+ * $helper.getRemoteName($intf, "")_end__$n.name()()
+ * _$n.name() async end (read result from mailbox and return result)
+ * @param thisx this.
+ * @param mbox caller relinquishes
+ * @return etch_int32* result of add, caller owns.
+ */
+$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, "")_end_client_$n.name() (void* thisx, i_mailbox* ibox)
+{
+    $helper.getRemoteName($intf, $suffix)* remote = ($helper.getRemoteName($intf, $suffix)*)thisx;
+    $helper.getPointerTypeName($n.type()) _resobj = NULL;
+    int _result = -1;
+    etch_type* _restype = $helper.getVfName($intf)_get_static()->_mt_$helper.getServiceName($intf)__result_$n.name();
+
+    if(ibox == NULL) {
+        return NULL;
+    }
+
+    remote->remote_base->end_call(remote->remote_base, ibox, _restype, (void**)&_resobj);
+
+    _result = $helper.getRemoteName($intf, '')_${suffix}_dispose_mailbox (thisx, &ibox);
+    if(_result) {
+    	etch_exception* excp = new_etch_exception_from_errorcode(ETCH_ERROR);
+        etch_exception_set_message(excp,new_stringw(L"can not dispose mailbox."));
+        return ($helper.getPointerTypeName($n.type()))excp;
+    }
+
+    return _resobj;
+}
+
+/**
+ * $helper.getRemoteName($intf, "")_$n.name()
+ * $helper.getIntfName($intf).$n.name() remote method call.
+ * instantiates a mailbox, sends perf.add message, waits for result to arrive
+ * in mailbox, disposes mailbox, and returns object containing add() result.
+ * @param thisx this.
+ * @param x etch_int32* caller relinquishes.
+ * @param y etch_int32* caller relinquishes.
+ * @return etch_int32* result of add, caller owns.
+ */
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, '')_client_$n.name()(void* thisx")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb)")
+$sb
+{
+    $helper.getRemoteName($intf, $suffix)* remote = ($helper.getRemoteName($intf, $suffix)*)thisx;
+    $helper.getPointerTypeName($n.type()) _resultobj = NULL;
+
+#set ($sb = "i_mailbox* _mbox = $helper.getRemoteName($intf, '')_begin_client_$n.name()(remote")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $p.name()")
+#end
+#set ($sb = "$sb);")
+    $sb
+    
+    if(_mbox == NULL){
+		etch_exception* excp = new_etch_exception_from_errorcode(ETCH_EIO);
+        etch_exception_set_message(excp,new_stringw(L"can not create mailbox, connection could be down."));
+        return ($helper.getPointerTypeName($n.type()))excp;
+	}
+    
+    _resultobj = $helper.getRemoteName($intf, '')_end_client_$n.name()(remote, _mbox);
+    
+    return _resultobj;
+}
+
+## generate oneway
+#else
+/**
+ * $helper.getRemoteName($intf, '')_begin_$n.name()()
+ * $helper.getIntfName($intf).$n.name() async start 
+ * @param thisx this.
+ * @param x etch_int32* caller relinquishes.
+ * @param y etch_int32* caller relinquishes.
+ * @return mailbox to receive async result. caller owns it. it may be null.
+ * @remarks note that we use the putc version of message.put(), wherein we pass
+ * a *reference* to the value object's pointer, and message.putc() nulls out  
+ * the reference. this permits us to break when a putc() error occurs, without  
+ * leaking the un-put parameters, since prior to exit we can destroy each 
+ * parameter which remains non-null.
+ * @remarks note also that we don't bother to clone the value keys, since they  
+ * are protected objects, and while message_put will appear to destroy them,
+ * this will have no effect.
+ */
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, '')_begin_client_$n.name()(void* thisx")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb)")
+$sb
+{
+    $helper.getRemoteName($intf, $suffix)* remote = ($helper.getRemoteName($intf, $suffix)*)thisx;
+    int _result = 0;
+    etch_message* _msg = NULL;
+    $helper.getPointerTypeName($n.type()) _resultobj = NULL;
+    etch_type* _msgtype = $helper.getVfName($intf)_get_static()->_mt_$helper.getServiceName($intf)_$n.name();
+
+    do
+    {   
+        _msg = remote->remote_base->new_message (remote->remote_base, _msgtype);
+        if (!_msg) break;
+
+#foreach( $p in $n.iterator() )
+        _result = message_putc (_msg, $helper.getVfName($intf)_get_static()->_mf_$helper.getIntfName($intf)_$p.name(), (void**)&$p.name());
+		if ($p.name() != NULL && 0 != _result) break; 
+#end
+
+        /* fyi msg memory is relinquished here regardless of result */ 
+        _resultobj = remote->remote_base->sendex (remote->remote_base, _msg);
+        _msg = NULL;
+
+    } while(0);
+
+    /* destroy any unrelinquished objects */
+#foreach( $p in $n.iterator() )
+    etch_object_destroy($p.name());
+	$p.name() = NULL;
+#end
+    etch_object_destroy(_msg);
+	_msg = NULL;	
+    return _resultobj;
+}
+
+/**
+ * $helper.getRemoteName($intf, '')_end_$n.name()()
+ * async result handler not used since $helper.getIntfName($intf).$n.name() is a one-way send-and-forget method.
+ */
+void* $helper.getRemoteName($intf, '')_end_client_$n.name() ($helper.getRemoteName($intf, $suffix)* thisx, i_mailbox* mbox)
+{
+    return NULL;
+}
+
+/**
+ * $helper.getRemoteName($intf, '')_$n.name()()
+ * $helper.getIntfName($intf).$n.name() remote 1-way method call.
+ * sends $helper.getIntfName($intf).$n.name() message and does not wait for a result. if server implementation
+ * code throws an exception, the exception arrives via session_notify override if any.
+ * @param code an integer object, caller relinquishes.
+ * @param x etch_string caller relinquishes.
+ * @return integer transport result code cast to void*.
+ */
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, '')_client_$n.name()(void* thisx")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb)")
+$sb
+{
+    $helper.getRemoteName($intf, $suffix)* remote = ($helper.getRemoteName($intf, $suffix)*)thisx;
+    /* $helper.getIntfName($intf).$n.name() is a one-way, send-and-forget message so we only do a begin call */
+#set ($sb = "$helper.getPointerTypeName($n.type()) _resultobj = $helper.getRemoteName($intf, '')_begin_client_$n.name()(remote")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $p.name()")
+#end
+#set ($sb = "$sb);")
+    $sb
+
+    return _resultobj;
+}
+
+#end
+#end
+#end
+#end
+#end
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_client_h.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_client_h.vm
new file mode 100644
index 0000000..c54652f
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_client_h.vm
@@ -0,0 +1,109 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * $helper.getRemoteFileNameH($intf, $suffix) 
+ */
+
+#ifndef $helper.getRemoteName($intf, $suffix).toUpperCase()_H
+#define $helper.getRemoteName($intf, $suffix).toUpperCase()_H
+
+\#include "$helper.getRemoteFileNameH($intf, "")"
+\#include "$helper.getBaseFileNameH($intf, $suffix)"
+\#include "etch_transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_$helper.getRemoteName($intf, $suffix).toUpperCase();
+
+/**
+ * $helper.getRemoteName($intf, $suffix)
+ */
+typedef struct $helper.getRemoteName($intf, $suffix)
+{
+    etch_object object;  
+
+    i_$helper.getBaseName($intf, $suffix)* client_base;     /* owned */
+    $helper.getRemoteName($intf, "")* remote_base;     /* owned */
+    etch_client_factory* client_factory; /* owned */
+    default_value_factory* vf;   /* owned by base */
+    int session_id;
+
+    /* toward-client virtuals go here */
+    
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden() && ($n.isMsgDirBoth() || $n.isMsgDirClient()))
+    $helper.getServiceName( $intf )_$n.name() $n.name();
+#end
+#end
+#end
+/*
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct())
+#if (!$n.isHidden())
+    $n.efqname($helper)* $n.name().toString().toLowerCase();
+#end
+#end
+#end
+*/
+
+
+    /* private, generally. since unit tests invoke async begin and end,
+     * we must expose them either as virtuals or as external references.
+     */
+     
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden()&& ($n.isMsgDirBoth() || $n.isMsgDirClient()))
+#if (!$n.isOneway())
+    $helper.getServiceName( $intf )_async_begin_$n.name() async_begin_$n.name();
+#end
+#end
+#end
+#end
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden()&& ($n.isMsgDirBoth() || $n.isMsgDirClient()))
+#if (!$n.isOneway())
+    $helper.getServiceName( $intf )_async_end_$n.name() async_end_$n.name();
+#end
+#end
+#end
+#end
+    
+    
+} $helper.getRemoteName($intf, $suffix);
+
+/* constructor */
+$helper.getRemoteName($intf, $suffix)* new_$helper.getServiceName($intf)_remote_client (void*, etch_session*, etch_value_factory*);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* $helper.getRemoteName($intf, $suffix).toUpperCase()_H */
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_h.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_h.vm
new file mode 100644
index 0000000..df407e0
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_h.vm
@@ -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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * $helper.getRemoteFileNameH($intf, $mc)
+ * $helper.getIntfName($intf) remote.
+ * combines java bindings's RemotePerf, Perf, and RemoteBase.
+ */
+
+#ifndef $helper.getRemoteName($intf, "").toUpperCase()_H
+#define $helper.getRemoteName($intf, "").toUpperCase()_H
+
+\#include "$helper.getIntfFileNameH($intf)"
+\#include "etch_remote.h"
+\#include "etch_transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_$helper.getRemoteName($intf, "").toUpperCase();
+
+/**
+ * $helper.getRemoteName($intf, $suffix)
+ */
+typedef struct $helper.getRemoteName($intf, "")
+{
+    etch_object object;    
+
+    i_$helper.getIntfName($intf)*  i$helper.getIntfName($intf); /* possibly owned */
+    i_delivery_service*  dsvc;  /* not owned */
+    etch_value_factory*  vf;    /* not owned */
+    unsigned char  remote_type; /* client or server */
+    unsigned char  is_service_interface_owned;
+    unsigned short unused;      /* alignment */
+
+    etch_message* (*new_message) (void*, etch_type*);
+    int   (*send)   (void*, etch_message*);
+    void* (*sendex) (void*, etch_message*);
+    etch_delivsvc_begincall begin_call;  /* i_mailbox** out */
+    etch_delvisvc_endcall   end_call;    /* etch_object** out */
+
+    int (*start_waitup)  (void*, const int waitms);
+    int (*stop_waitdown) (void*, const int waitms);
+
+    /* - - - - - - - - - - - - -
+     * transport functionality
+     * - - - - - - - - - - - - -
+     */
+    etch_transport_control transport_control;  
+    etch_transport_notify  transport_notify;   
+    etch_transport_query   transport_query; 
+    etch_transport_get_session get_session;  
+    etch_transport_set_session set_session; 
+
+    /* - - - - - - - - - - -
+     * service virtuals
+     * - - - - - - - - - - -
+     */
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+    $helper.getIntfName( $intf )_$n.name() $n.name();
+#end
+#end
+#end
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct())
+#if (!$n.isHidden())
+    $n.efqname($helper)* $n.name().toString();
+#end
+#end
+#end
+
+    /* - - - - - - - - - - -
+     * private instance data
+     * - - - - - - - - - - -
+     */    
+
+} $helper.getRemoteName($intf, "");
+
+
+$helper.getRemoteName($intf, "")* new_$helper.getRemoteName($intf, "") (void*, i_delivery_service*, etch_value_factory*, i_$helper.getIntfName($intf)*);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+#endif /* $helper.getRemoteName($intf, "").toUpperCase()_H */
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_server_c.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_server_c.vm
new file mode 100644
index 0000000..8c091bb
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_server_c.vm
@@ -0,0 +1,475 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * $helper.getRemoteFileNameI($intf, $suffix)
+ * generated remote procedure calls.
+ */
+
+\#include "$helper.getRemoteFileNameH($intf, $suffix)"
+\#include "etch_plain_mailbox_manager.h"
+\#include "etch_svcobj_masks.h"
+\#include "etch_objecttypes.h"
+\#include "etch_exception.h"
+\#include "etch_url.h" 
+\#include "etch_log.h" 
+\#include "etch_general.h"
+
+unsigned short CLASSID_$helper.getRemoteName($intf, $suffix).toUpperCase();	
+	
+char* $helper.getServiceName($intf).toUpperCase()_ETCHREMS = "REMS";
+
+## generate async begin typedefs
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())	
+	
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, '')_server_$n.name() (void* thisAsVoid")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb);")
+$sb
+#if (!$n.isOneway())
+#set ($sb = "i_mailbox* $helper.getRemoteName($intf, '')_begin_server_$n.name() (void* thisAsVoid")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb);")
+$sb
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, '')_end_server_$n.name()(void*, i_mailbox*);")
+$sb
+#end
+
+#end
+#end
+#end
+#end
+
+int destroy_$helper.getRemoteName($intf, $suffix) (void*);
+
+/* - - - - - - - - - -   
+ * instantiation etc.
+ * - - - - - - - - - -  
+ */
+
+/**
+ * new_$helper.getRemoteName($intf, $suffix)()
+ * $helper.getRemoteName($intf, $suffix) constructor.
+ * @param thisx owner, optional, null in practice.
+ * @param ids delivery service interface, caller retains.
+ * @param vf service specific value factory, caller retains.
+ */
+$helper.getRemoteName($intf, $suffix)* new_$helper.getRemoteName($intf, $suffix) (void* thisx, i_delivery_service* ids, etch_value_factory* vf)
+{
+    $helper.getRemoteName($intf, $suffix)* rs = ($helper.getRemoteName($intf, $suffix)*) new_object (sizeof($helper.getRemoteName($intf, $suffix)), 
+        ETCHTYPEB_REMOTESERVER, get_dynamic_classid_unique(&CLASSID_$helper.getRemoteName($intf, $suffix).toUpperCase()));
+
+    ((etch_object*)rs)->destroy = destroy_$helper.getRemoteName($intf, $suffix);
+
+    rs->remote_base = new_$helper.getRemoteName($intf, "") (thisx, ids, vf, NULL);
+    rs->remote_base->remote_type = ETCH_REMOTETYPE_SERVER;
+
+    /* 2/3/09 now passing perf interface not owned by server_base */
+    rs->server_base = new_$helper.getRemoteName($intf, $suffix)_base (thisx, rs->remote_base->i$helper.getIntfName($intf));  
+
+    rs->vf = ($helper.getVfName($intf)*) rs->remote_base->vf;
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())	
+    rs->$n.name() = $helper.getRemoteName($intf, '')_server_$n.name();
+#end
+#end
+#end
+#end
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#if (!$n.isOneway())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())	
+    rs->async_begin_$n.name() = $helper.getRemoteName($intf, '')_begin_server_$n.name();
+    rs->async_end_$n.name() = $helper.getRemoteName($intf, '')_end_server_$n.name();
+#end	
+#end
+#end
+#end
+#end
+
+    return rs;
+}
+
+/**
+ * destroy_$helper.getBaseName($intf, $suffix)_base()
+ * i_$helper.getBaseName($intf, $suffix) destructor.
+ */
+int destroy_$helper.getRemoteName($intf, $suffix) (void* thisAsVoid)
+{
+    $helper.getRemoteName($intf, $suffix)* thisx = ($helper.getRemoteName($intf, $suffix)*)thisAsVoid;
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx))
+    {
+        etch_object_destroy(thisx->remote_base);
+		thisx->remote_base = NULL;
+		etch_object_destroy(thisx->server_base);
+		thisx->server_base = NULL;
+		etch_object_destroy(thisx->client_factory);
+		thisx->client_factory = NULL;
+    }
+
+    return destroy_objectex((etch_object*)thisx);
+}
+
+
+/**
+ * perf_remote_dispose_mailbox()
+ * dispose of mailbox after use.
+ * this is the common means of disposing of a mailbox when we're done with it.
+ * this would intuitively be part of base class code but we don't have one.
+ * @param thisx the remote server this.
+ * @param pibox pointer to pointer to the mailbox interface, passed indirectly
+ * such that this method can null out the caller's mailbox reference.
+ * @return 0 if mailbox was successfullly closed, otherwise -1. 
+ * caller's i_mailbox reference is nulled out regardless of result.
+ */
+int $helper.getRemoteName($intf, "")_${suffix}_dispose_mailbox ($helper.getRemoteName($intf, $suffix)* thisx, i_mailbox** pibox)
+{
+    int result = 0;
+    i_mailbox* ibox = 0;
+    if (!pibox || !*pibox) return -1;
+    ibox = *pibox;
+    *pibox = NULL;  /* null out caller's reference */
+    
+    if (0 != (result = ibox->close_read (ibox)))
+    {  
+        /* we should not need this failsafe unregister if close_read() 
+         * is reliable, since close_read() will do the unregister */
+        i_mailbox_manager* imgr = ibox->manager(ibox);
+        ETCH_LOG($helper.getServiceName($intf).toUpperCase()_ETCHREMS, ETCH_LOG_ERROR, "could not close mailbox %x\n", ibox);
+        if (imgr) result = imgr->unregister(imgr, ibox);
+    }
+ 
+    /* mailbox manager does not destroy the unregistered mailbox since it is    
+     * owned by whoever registered it, that being us, so we destroy it here. 
+     * debug heap issue note: this is/was the spot.
+     */
+    etch_object_destroy(ibox);   
+    return result;
+}
+
+etch_stub* $helper.getRemoteName($intf, "")_${suffix}_get_stubbase ($helper.getRemoteName($intf, $suffix)* thisx)
+{
+    etch_stub* stub = NULL;
+    xxxx_either_stub* clistub = (xxxx_either_stub*) thisx->client_factory->stub;
+    stub = clistub? clistub->stub_base: NULL;
+    return stub;
+}
+
+
+/**
+ * $helper.getRemoteName($intf, "")_set_session_notify()
+ * convenience to override remote server's session_notify().
+ * @return the session_notify function that was overridden.
+ */
+etch_session_notify $helper.getRemoteName($intf, "")_${suffix}_set_session_notify($helper.getRemoteName($intf, $suffix)* thisx, etch_session_notify newfunc)
+{
+    etch_session_notify oldfunc = NULL;
+    etch_stub* stub = $helper.getRemoteName($intf, "")_${suffix}_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_notify;
+    stub->impl_callbacks->_session_notify = newfunc;
+    return oldfunc;
+}
+
+
+/**
+ * $helper.getRemoteName($intf, "")_set_session_control()
+ * convenience to override remote server's session_control().
+ * @return the session_control function that was overridden.
+ */
+etch_session_control $helper.getRemoteName($intf, "")_${suffix}_set_session_control($helper.getRemoteName($intf, $suffix)* thisx, etch_session_control newfunc)
+{
+    etch_session_control oldfunc = NULL;
+    etch_stub* stub = $helper.getRemoteName($intf, "")_${suffix}_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_control;
+    stub->impl_callbacks->_session_control = newfunc;
+    return oldfunc;
+}
+
+
+/**
+ * $helper.getRemoteName($intf, "")_set_session_query()
+ * convenience to override remote server's session_query().
+ * @return the session_query function that was overridden.
+ */
+etch_session_query $helper.getRemoteName($intf, "")_${suffix}_set_session_query($helper.getRemoteName($intf, $suffix)* thisx, etch_session_query newfunc)
+{
+    etch_session_query oldfunc = NULL;
+    etch_stub* stub = $helper.getRemoteName($intf, "")_${suffix}_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_query;
+    stub->impl_callbacks->_session_query = newfunc;
+    return oldfunc;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -  
+ * remote procedure call implementations
+ * - - - - - - - - - - - - - - - - - - - - 
+ */
+ 
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())
+	
+/* - - - - - - - - - - -  
+ * $helper.getIntfName($intf).$n.name()()
+ * - - - - - - - - - - -  
+ */
+ 
+#if (!$n.isOneway())
+/**
+ * $helper.getRemoteName($intf, '')_begin_$n.name()()
+ * $helper.getIntfName($intf).$n.name() async start 
+ * TODO: doc generation
+ */
+#set ($sb = "i_mailbox* $helper.getRemoteName($intf, '')_begin_server_$n.name()(void* thisAsVoid")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb)")
+$sb
+{
+    $helper.getRemoteName($intf, $suffix)* thisx = ($helper.getRemoteName($intf, $suffix)*)thisAsVoid;
+    int _result = 0;
+    i_mailbox* _mbox = NULL;
+    etch_message* _msg = NULL;
+    etch_type* _msgtype = $helper.getVfName($intf)_get_static()->_mt_$helper.getServiceName($intf)_$n.name();
+
+    do
+    {   
+        _msg = thisx->remote_base->new_message (thisx->remote_base, _msgtype);
+        if (!_msg) break;
+
+#foreach( $p in $n.iterator() )
+        _result = message_putc (_msg, $helper.getVfName($intf)_get_static()->_mf_$helper.getIntfName($intf)_$p.name(), (void**)&$p.name());
+		if ($p.name() != NULL && 0 != _result) break; 
+#end
+
+        /* fyi msg memory is relinquished here regardless of result */ 
+        _result = thisx->remote_base->begin_call(thisx->remote_base, _msg, (void**)&_mbox);
+        _msg = NULL;
+
+    } while(0);
+
+    /* destroy any unrelinquished objects */
+#foreach( $p in $n.iterator() )
+    etch_object_destroy($p.name());
+	$p.name() = NULL;
+#end
+    etch_object_destroy(_msg);
+	_msg = NULL;
+	
+    return _mbox;
+}
+
+/**
+ * $helper.getRemoteName($intf, "")_end__$n.name()()
+ * _$n.name() async end (read result from mailbox and return result)
+ * @param thisx this.
+ * @param mbox caller relinquishes
+ * @return etch_int32* result of add, caller owns.
+ */
+$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, "")_end_server_$n.name() (void* thisAsVoid, i_mailbox* ibox)
+{
+    $helper.getRemoteName($intf, $suffix)* thisx = ($helper.getRemoteName($intf, $suffix)*)thisAsVoid;
+    $helper.getPointerTypeName($n.type()) _resobj = NULL;
+    int _result = -1;
+    etch_type* _restype = $helper.getVfName($intf)_get_static()->_mt_$helper.getServiceName($intf)__result_$n.name();
+    
+    if(ibox == NULL) {
+        return NULL;
+    }
+
+    thisx->remote_base->end_call(thisx->remote_base, ibox, _restype, (void**)&_resobj);
+    
+    _result = $helper.getRemoteName($intf, '')_${suffix}_dispose_mailbox (thisx, &ibox);
+    if(_result) {
+     	etch_exception* excp = new_etch_exception_from_errorcode(ETCH_ERROR);
+        etch_exception_set_message(excp,new_stringw(L"can not dispose mailbox."));
+        return ($helper.getPointerTypeName($n.type()))excp;
+    }
+    
+    return _resobj;
+}
+
+/**
+ * $helper.getRemoteName($intf, "")_$n.name()
+ * $helper.getIntfName($intf).$n.name() remote method call.
+ * instantiates a mailbox, sends perf.add message, waits for result to arrive
+ * in mailbox, disposes mailbox, and returns object containing add() result.
+ * @param thisx this.
+ * @param x etch_int32* caller relinquishes.
+ * @param y etch_int32* caller relinquishes.
+ * @return etch_int32* result of add, caller owns.
+ */
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, '')_server_$n.name()(void* thisAsVoid")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb)")
+$sb
+{
+    $helper.getRemoteName($intf, $suffix)* thisx = ($helper.getRemoteName($intf, $suffix)*)thisAsVoid;
+    $helper.getPointerTypeName($n.type()) _resultobj = NULL;
+
+#set ($sb = "i_mailbox* _mbox = $helper.getRemoteName($intf, '')_begin_server_$n.name()(thisx")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $p.name()")
+#end
+#set ($sb = "$sb);")
+    $sb
+
+	if(_mbox == NULL){
+		etch_exception* excp = new_etch_exception_from_errorcode(ETCH_EIO);
+        etch_exception_set_message(excp,new_stringw(L"can not create mailbox, connection could be down."));
+        return ($helper.getPointerTypeName($n.type()))excp;
+	}
+
+    _resultobj = $helper.getRemoteName($intf, "")_end_server_$n.name() (thisx, _mbox);
+
+    return _resultobj;
+}
+
+## generate oneway
+#else
+/**
+ * $helper.getRemoteName($intf, '')_begin_$n.name()()
+ * $helper.getIntfName($intf).$n.name() async start 
+ * @param thisx this.
+ * @param x etch_int32* caller relinquishes.
+ * @param y etch_int32* caller relinquishes.
+ * @return mailbox to receive async result. caller owns it. it may be null.
+ * @remarks note that we use the putc version of message.put(), wherein we pass
+ * a *reference* to the value object's pointer, and message.putc() nulls out  
+ * the reference. this permits us to break when a putc() error occurs, without  
+ * leaking the un-put parameters, since prior to exit we can destroy each 
+ * parameter which remains non-null.
+ * @remarks note also that we don't bother to clone the value keys, since they  
+ * are protected objects, and while message_put will appear to destroy them,
+ * this will have no effect.
+ */
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, '')_begin_server_$n.name()(void* thisAsVoid")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb)")
+$sb
+{
+    $helper.getRemoteName($intf, $suffix)* thisx = ($helper.getRemoteName($intf, $suffix)*)thisAsVoid;
+#foreach( $p in $n.iterator() )
+#set($result_needed = true)
+#end
+#if($result_needed)
+    int _result = 0;
+#end
+    etch_message* _msg = NULL;
+    $helper.getPointerTypeName($n.type()) _resultobj = NULL;
+    etch_type* _msgtype = $helper.getVfName($intf)_get_static()->_mt_$helper.getServiceName($intf)_$n.name();
+
+    do
+    {   
+        _msg = thisx->remote_base->new_message (thisx->remote_base, _msgtype);
+        if (!_msg) break;
+
+#foreach( $p in $n.iterator() )
+        _result = message_putc (_msg, $helper.getVfName($intf)_get_static()->_mf_$helper.getIntfName($intf)_$p.name(), (void**)&$p.name());
+        if ($p.name() != NULL && 0 != _result) break;
+#end
+
+        /* fyi msg memory is relinquished here regardless of result */ 
+        /* fyi msg memory is relinquished here regardless of result */ 
+        _resultobj = thisx->remote_base->sendex (thisx->remote_base, _msg);
+        _msg = NULL;
+
+    } while(0);
+
+    /* destroy any unrelinquished objects */
+#foreach( $p in $n.iterator() )
+    etch_object_destroy($p.name());
+	$p.name() = NULL;
+#end
+    etch_object_destroy(_msg);
+	_msg = NULL;	
+    return _resultobj;
+}
+
+/**
+ * $helper.getRemoteName($intf, '')_end_$n.name()()
+ * async result handler not used since $helper.getIntfName($intf).$n.name() is a one-way send-and-forget method.
+ */
+void* $helper.getRemoteName($intf, '')_end_server_$n.name() (void* thisAsVoid, i_mailbox* mbox)
+{
+    return NULL;
+}
+
+/**
+ * $helper.getRemoteName($intf, '')_$n.name()()
+ * $helper.getIntfName($intf).$n.name() remote 1-way method call.
+ * sends $helper.getIntfName($intf).$n.name() message and does not wait for a result. if server implementation
+ * code throws an exception, the exception arrives via session_notify override if any.
+ * @param code an integer object, caller relinquishes.
+ * @param x etch_string caller relinquishes.
+ * @return integer transport result code cast to void*.
+ */
+#set ($sb = "$helper.getPointerTypeName($n.type()) $helper.getRemoteName($intf, '')_server_$n.name()(void* thisAsVoid")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $helper.getTypeName($p.type()) $p.name()")
+#end
+#set ($sb = "$sb)")
+$sb
+{
+    $helper.getRemoteName($intf, $suffix)* thisx = ($helper.getRemoteName($intf, $suffix)*)thisAsVoid;
+    /* $helper.getIntfName($intf).$n.name() is a one-way, send-and-forget message so we only do a begin call */
+#set ($sb = "$helper.getPointerTypeName($n.type()) _resultobj = $helper.getRemoteName($intf, '')_begin_server_$n.name()(thisx")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, $p.name()")
+#end
+#set ($sb = "$sb);")
+    $sb
+
+    return _resultobj;
+}
+
+#end
+#end
+#end
+#end
+#end
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_server_h.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_server_h.vm
new file mode 100644
index 0000000..b067ae4
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/remote_server_h.vm
@@ -0,0 +1,117 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * $helper.getRemoteFileNameH($intf, $suffix) 
+ * generated remote procedure calls.
+ */
+
+#ifndef $helper.getRemoteName($intf, $suffix).toUpperCase()_H
+#define $helper.getRemoteName($intf, $suffix).toUpperCase()_H
+
+\#include "$helper.getRemoteFileNameH($intf, "")"
+\#include "$helper.getBaseFileNameH($intf, $suffix)"
+\#include "$helper.getVfFileNameH($intf)"
+\#include "etch_transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_$helper.getRemoteName($intf, $suffix).toUpperCase();
+
+
+/**
+ * $helper.getRemoteName($intf, $suffix)
+ */
+typedef struct $helper.getRemoteName($intf, $suffix)
+{
+    etch_object object;
+    
+    i_$helper.getBaseName($intf, $suffix)* server_base;  /* owned */
+    $helper.getRemoteName($intf, "")*   remote_base;  /* owned */
+    etch_client_factory* client_factory; /* owned */
+    $helper.getVfName($intf)*  vf;     /* owned by base */
+    int server_id;
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden()&& ($n.isMsgDirBoth() || $n.isMsgDirServer()))
+    $helper.getServiceName( $intf )_$n.name() $n.name();
+#end
+#end
+#end
+
+/*
+#foreach( $n in $intf.iterator() )
+#if ($n.isStruct())
+#if (!$n.isHidden())
+    $n.efqname($helper)* $n.name().toString().toLowerCase();
+#end
+#end
+#end
+*/
+
+    /* private, generally. since unit tests invoke async begin and end,
+     * we must expose them either as virtuals or as external references.
+     */
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden()&& ($n.isMsgDirBoth() || $n.isMsgDirServer()))
+#if (!$n.isOneway())
+    $helper.getServiceName( $intf )_async_begin_$n.name() async_begin_$n.name();
+#end
+#end
+#end
+#end
+
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden()&& ($n.isMsgDirBoth() || $n.isMsgDirServer()))
+#if (!$n.isOneway())
+    $helper.getServiceName( $intf )_async_end_$n.name() async_end_$n.name();
+#end
+#end
+#end
+#end
+
+} $helper.getRemoteName($intf, $suffix);
+
+
+/* constructor */
+$helper.getRemoteName($intf, $suffix)* new_$helper.getRemoteName($intf, $suffix)(void*, i_delivery_service*, etch_value_factory*);
+
+int $helper.getRemoteName($intf, "")_dispose_mailbox($helper.getRemoteName($intf, $suffix)*, i_mailbox**);
+
+/* convenience methods to override client's session interface methods */
+etch_stub* $helper.getRemoteName($intf, "")_get_stubbase ($helper.getRemoteName($intf, $suffix)*);
+etch_session_notify $helper.getRemoteName($intf, "")_set_session_notify($helper.getRemoteName($intf, $suffix)*, etch_session_notify);
+etch_session_control $helper.getRemoteName($intf, "")_set_session_control($helper.getRemoteName($intf, $suffix)*, etch_session_control);
+etch_session_query $helper.getRemoteName($intf, "")_set_session_query($helper.getRemoteName($intf, $suffix)*, etch_session_query);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* $helper.getRemoteName($intf, $suffix).toUpperCase()_H */
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/stub_c.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/stub_c.vm
new file mode 100644
index 0000000..59ff496
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/stub_c.vm
@@ -0,0 +1,291 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * $helper.getStubFileNameI($intf, $suffix) 
+ */
+
+\#include "$helper.getBaseFileNameH($intf, $suffix)"
+\#include "$helper.getStubFileNameH($intf, $suffix)"
+\#include "$helper.getVfFileNameH($intf)"
+
+\#include "etch_url.h"
+\#include "etch_objecttypes.h"
+\#include "etch_svcobj_masks.h"
+\#include "etch_general.h"
+
+#if($helper.isServer($mc))
+\#include "etch_exception.h"
+\#include "etch_log.h"
+#end
+
+unsigned short CLASSID_$helper.getStubName($intf, $suffix).toUpperCase();	
+	
+#if($helper.isServer($mc))
+char* $helper.getServiceName($intf).toUpperCase()_$helper.getServiceName($intf).toUpperCase()_ETCHSTBI = "STBI";
+#end
+	
+int destroy_$helper.getStubName($intf, $suffix)(void*);
+
+
+/* - - - - - - - - - - -
+ * stub helper methods 
+ * - - - - - - - - - - -
+ */
+
+## check if any Message goes to $suffix direction
+#if(!$intf.hasMessageDirection($mc) && $helper.hasMessageDirectionBoth($intf))
+/**
+ * $helper.getStubName($intf, $suffix)_run_nothing_
+ */
+int $helper.getStubName($intf, $suffix)_run_nothing_ (etch_stub* stub, i_delivery_service* dsvc, 
+    void* obj, etch_who* whofrom, etch_message* msg)
+{
+    i_$helper.getBaseName($intf, $suffix)* client = (i_$helper.getBaseName($intf, $suffix)*)obj;
+    $helper.getVfName($intf)_impl* pvfi = NULL;
+    $helper.getVfName($intf)* pvf = NULL;
+    struct $helper.getBaseName($intf, $suffix)_impl* impl = NULL;
+
+    /* objects specific to service.nothing_() */
+    etch_field*  key_foo  = NULL;
+    etch_int64*  val_foo  = NULL;
+    etch_field*  key_bar  = NULL;
+    etch_string* val_bar  = NULL;
+    etch_int32* resultobj = NULL;
+
+    etchstub_validate_args (stub, dsvc, msg, client, &pvf, (void**)&pvfi, (void**)&impl);     
+
+    key_foo = NULL;
+    key_bar = NULL;
+    ETCH_ASSERT(key_foo && key_bar);  
+
+    /* nullarg asserts are initial tests only: server impl   
+     * will generate exceptions on nullargs in the real world */
+    val_foo = NULL; /* = (etch_int64*)  message_get (msg, key_foo); */
+    val_bar = NULL; /* = (etch_string*) message_get (msg, key_bar); */
+    ETCH_ASSERT(val_foo && val_bar); 
+
+    /* execute the service method */
+    resultobj = NULL; /* server->nothing_ (impl, val_foo, val_bar); */
+    ETCH_ASSERT(resultobj); 
+
+    /* transmit reply back to sender */
+    return etchstub_send_reply (stub, dsvc, whofrom, msg, (void*) resultobj, TRUE);
+}   
+#end
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())
+#if (!$n.isHidden())
+/**
+ * $helper.getStubName($intf, '')_run_$n.name()
+ */
+int $helper.getStubName($intf, '')_run_$helper.getDirectionName($mc)_$n.name()(etch_stub* stub, i_delivery_service* dsvc, void* obj, etch_who* whofrom, etch_message* msg)
+{
+    i_$helper.getBaseName($intf, $suffix)* $suffix = (i_$helper.getBaseName($intf, $suffix)*)obj;
+	int returnCode = 0;
+    $helper.getVfName($intf)_impl* pvfi = NULL;
+    $helper.getVfName($intf)* pvf = NULL;
+    struct $helper.getBaseName($intf, $suffix)_impl* impl = NULL;
+
+    /* objects specific to $helper.getBaseName($intf, $suffix).$name.name()() */
+#foreach( $p in $n.iterator() )
+    etch_field* key_$p.name() = NULL;
+    $helper.getPointerTypeName($p.type()) val_$p.name() = NULL;
+#end
+#if($n.hasReturn() && !$n.isOneWay())
+    $helper.getPointerTypeName($n.getResultMessage().getResultParam().type()) resultobj = NULL;
+#end
+#if(!$n.hasReturn() && !$n.isOneWay())
+    void* resultobj = NULL;
+#end
+    etchstub_validate_args (stub, dsvc, msg, $suffix, &pvf, (void**)&pvfi, (void**)&impl);
+
+#set($op = '')
+#set($sb = '')
+#foreach($p in $n.iterator())
+#set($sb = "$sb${op}key_$p.name()")
+    key_$p.name() = $helper.getVfName($intf)_get_static()->_mf_$helper.getIntfName($intf)_$p.name();
+#set($op = ' && ')
+#end
+#if($sb != '')
+    ETCH_ASSERT($sb);
+#end
+
+#set($op = '')
+#set($sb = '')
+#foreach($p in $n.iterator())
+##set($sb = "$sb${op}val_$p.name()")
+    val_$p.name() = ($helper.getPointerTypeName($p.type())) message_remove(msg, key_$p.name());
+##set($op = ' && ')
+#end
+##if($sb != '')
+##    ETCH_ASSERT($sb);
+##end
+    
+    /* execute the service method */
+#set($sb = '')
+#if($n.hasReturn() || $n.hasThrown())
+	#set ( $sb = "resultobj = ")
+#end
+#set ($sb = "$sb ${suffix}->$n.name() (impl")
+#foreach( $p in $n.iterator() )
+#set ( $sb = "$sb, val_$p.name()")
+#end
+#set ($sb = "$sb);")
+    $sb
+
+#if(!$n.isOneway() && !$n.hasReturn() && !$n.hasThrown())
+    /* transmit reply back to sender */
+    returnCode = etchstub_send_reply (stub, dsvc, whofrom, msg, (void*) resultobj, FALSE);
+#elseif(!$n.isOneway() && !$n.hasReturn() && $n.hasThrown())
+    returnCode = etchstub_send_reply (stub, dsvc, whofrom, msg, (void*) resultobj, resultobj != NULL);
+#elseif(!$n.isOneway() && $n.hasReturn() && !$helper.isRefType($n.getResultMessage().getResultParam().type()))
+    returnCode = etchstub_send_reply (stub, dsvc, whofrom, msg, (void*) resultobj, TRUE);
+#elseif(!$n.isOneway() && $n.hasReturn() && $helper.isRefType($n.getResultMessage().getResultParam().type()))
+    returnCode = etchstub_send_reply (stub, dsvc, whofrom, msg, (void*) resultobj, resultobj != NULL);
+#elseif($n.isOneway())
+    if(resultobj != NULL) {
+        returnCode = etchstub_send_reply (stub, dsvc, whofrom, msg, (void*) resultobj, TRUE);
+    }
+#end
+	if(!returnCode){
+		etch_object_destroy(msg);
+	}
+    return returnCode;
+}
+#end
+#end
+#end
+#end
+
+/* - - - - - - - - - 
+ * constructors 
+ * - - - - - - - - - 
+ */
+
+#if($helper.isServer($mc))
+/**
+ * new_$helper.getStubName($intf, $suffix)()
+ * @param p serv factory parameter bundle, caller retains. 
+ *
+ * this constructor is called on the server via callback from the listener 
+ * socket accept handler <transportfactory>_session_accepted, via the new_server 
+ * function pointer to perf_helper.new_helper_accepted_server().
+ * java binding passes this constructor the delivery service, however we pass the
+ * etch_server_factory parameter bundle, (i_sessionlistener.server_params),
+ * i_sessionlistener being the set session interface of etch_tcp_server. 
+ */
+$helper.getStubName($intf, $suffix)* new_$helper.getStubName($intf, $suffix)(etch_server_factory* p, etch_session* session)
+{
+    i_delivery_service* ids = session->ds;
+    etch_threadpool *qp = p->qpool, *fp = p->fpool;
+
+    $helper.getStubName($intf, $suffix)* mystub = new_serverstub_init (session->server,  
+        sizeof($helper.getStubName($intf, $suffix)), destroy_$helper.getStubName($intf, $suffix), ids, qp, fp, p);
+
+    ((etch_object*)mystub)->class_id   = get_dynamic_classid_unique(&CLASSID_$helper.getStubName($intf, $suffix).toUpperCase());
+    mystub->session_id = session->session_id;  
+
+    /* initialize service-specific methods and data here. this facility may
+     * likely prove unecessary, as this is generated code, in which case we 
+     * can remove any associated comments from code and headers. */
+    //mystub->my_example_obj = etch_malloc(128, 0); /* example custom alloc */
+
+    /* set stub "helper" methods (run() procedures for each message type) */
+#foreach( $n in $intf.iterator())
+#if ($n.isMessage())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())
+#if (!$n.isHidden())
+    etchtype_set_type_stubhelper($helper.getVfName($intf)_get_static()->_mt_$helper.getServiceName($intf)_$n.name(), $helper.getStubName($intf, '')_run_$helper.getDirectionName($mc)_$n.name());
+#end	
+#end
+#end
+#end
+
+    return mystub;
+}
+#end
+#if($helper.isClient($mc))
+/**
+ * new_$helper.getStubName($intf, $suffix).
+ * called from $helper.getRemoteName($intf, $helper.getRemoteDirection($mc))* perfhelper.new_remote_$helper.getRemoteDirection($mc)().
+ * @param p client parameter bundle
+ */
+$helper.getStubName($intf, $suffix)* new_$helper.getStubName($intf, $suffix) (etch_client_factory* p)   
+{
+    $helper.getStubName($intf, $suffix)* mystub = NULL;
+    i_delivery_service* ids = p->dsvc;
+    etch_threadpool *qp = p->qpool, *fp = p->fpool;
+	
+    i_$helper.getBaseName($intf, $suffix)* client = p->iclient;
+    ETCH_ASSERT(is_etch_ideliverysvc(ids)); 
+    ETCH_ASSERT(is_etch_client_base(client)); 
+
+    mystub = new_clientstub_init (client, sizeof($helper.getStubName($intf, $suffix)), 
+        destroy_$helper.getStubName($intf, $suffix), ids, qp, fp, p);
+
+    ((etch_object*)mystub)->class_id  = get_dynamic_classid_unique(&CLASSID_$helper.getStubName($intf, $suffix).toUpperCase());
+    mystub->server_id = p->server_id;  
+
+    /* initialize custom methods and data here */
+
+    /* set stub helper methods */
+#foreach( $n in $intf.iterator())
+#if ($n.isMessage())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())
+#if (!$n.isHidden())
+    etchtype_set_type_stubhelper($helper.getVfName($intf)_get_static()->_mt_$helper.getServiceName($intf)_$n.name(), $helper.getStubName($intf, '')_run_$helper.getDirectionName($mc)_$n.name());
+#end	
+#end
+#end
+#end 
+
+    return mystub;
+}
+#end
+
+/**
+ * is_$helper.getStubName($intf, $suffix)()
+ */
+int is_$helper.getStubName($intf, $suffix)(void* obj)
+{
+    return obj && ((etch_object*)obj)->class_id == CLASSID_$helper.getStubName($intf, $suffix).toUpperCase();
+}
+
+/**
+ * destroy_def_$helper.getStubName($intf, $suffix)()
+ * $helper.getStubName($intf, $suffix) user-allocated memory destructor.
+ * called back from private object destructor destroy_stub_object().
+ * if you explicitly allocate memory in the client stub object, destroy it here.
+ */
+int destroy_$helper.getStubName($intf, $suffix)(void* data)
+{
+   /*
+     $helper.getStubName($intf, $suffix)* mystub = ($helper.getStubName($intf, $suffix)*)data;
+      free custom memory allocations here */
+    //etch_free(mystub->my_example_obj); /* free example alloc */
+
+    return 0;
+}
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/stub_h.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/stub_h.vm
new file mode 100644
index 0000000..cfd6ece
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/stub_h.vm
@@ -0,0 +1,92 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#ifndef $helper.getStubName($intf, $suffix).toUpperCase()_H
+#define $helper.getStubName($intf, $suffix).toUpperCase()_H
+
+\#include "etch_stub.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_$helper.getStubName($intf, $suffix).toUpperCase();
+
+/**
+ * $helper.getStubName($intf, $suffix)
+ */
+typedef struct $helper.getStubName($intf, $suffix)
+{
+    etch_object object;
+
+    etch_stub* stub_base;
+    
+#if( $helper.getDirectionName($mc).equals("client"))    
+    int  server_id;            
+#end    
+#if(! $helper.getDirectionName($mc).equals("client"))
+    int  session_id;           /* client session to which stub belongs */
+#end    
+    int (*destroyex) (void*);  /* user memory destructor */
+
+    /* - - - - - - - - - - - - - - - - -
+     * $mc.toString().toLowerCase()_directed service virtuals
+     * - - - - - - - - - - - - - - - - -
+     */
+     
+#foreach( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if ($n.isMsgDir($mc) || $n.isMsgDirBoth())
+#if (!$n.isHidden())
+##   add server direction here
+#end
+#end
+#end
+#end
+#if (!$intf.hasMessageDirection($mc) && $helper.hasMessageDirectionBoth( $intf ))
+    /* no $mc.toString().toLowerCase()-directed items defined */
+#end
+
+    /* - - - - - - - - - - - - - - - - -
+     * service-specific allocations
+     * - - - - - - - - - - - - - - - - -
+     */
+    // add here
+
+} $helper.getStubName($intf, $suffix);
+
+#if($helper.isServer($mc))
+$helper.getStubName($intf, $suffix)* new_$helper.getStubName($intf, $suffix) (etch_server_factory*, etch_session*);
+#else
+$helper.getStubName($intf, $suffix)* new_$helper.getStubName($intf, $suffix) (etch_client_factory*);
+#end
+int is_$helper.getStubName($intf, $suffix)(void* obj);
+int destroy_$helper.getStubName($intf, $suffix) (void*);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* PERF_SERVER_STUB_H */
+
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/vf_c.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/vf_c.vm
new file mode 100644
index 0000000..d73b5ff
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/vf_c.vm
@@ -0,0 +1,679 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * $helper.getVfFileNameI($intf) 
+ * $helper.getServiceName($intf) service value factory
+ */
+ 
+\#include "$helper.getVfFileNameH($intf)"
+\#include "$helper.getIntfFileNameH($intf)"
+\#include "etch_serializer.h"
+\#include "etch_exception.h"
+\#include "etch_objecttypes.h"
+\#include "etch_general.h"
+\#include "etch_map.h"
+\#include "etch_runtime.h"
+#foreach($serviceName in $helper.getUsedServiceNames($intf))	
+\#include "${serviceName.toLowerCase()}.h"
+#end	
+#foreach($serviceName in $helper.getUsedServiceNames($intf))	
+\#include "${serviceName.toLowerCase()}_valufact.h"
+#end
+
+unsigned short CLASSID_$helper.getVfName($intf).toUpperCase()_IMPL;
+
+static $helper.getVfName($intf)_statics* _g_$helper.getVfName($intf)_statics = NULL;
+
+/* constructors */
+etch_arraylist* $helper.getVfName($intf)_get_types($helper.getVfName($intf)*);
+
+void $helper.getVfName($intf)_free_statics();
+
+/* initializers */
+static int $helper.getVfName($intf)_init_static_fields();
+static int $helper.getVfName($intf)_init_static_types();
+static int $helper.getVfName($intf)_init_static_parameters();
+static int  $helper.getVfName($intf)_init_static_serializers();
+
+#foreach($n in $intf.iterator())
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+/* $n.name() serializer */
+etch_serializer* new_$n.efqname($helper)_serializer(etch_type*, etch_field*); 
+etch_object* etchserializer_$n.efqname($helper)_export_value(etch_serializer*, etch_object*);
+etch_object* etchserializer_$n.efqname($helper)_import_value(etch_serializer*, etch_object*);
+#end
+#end
+
+#set($valufactname = $helper.getVfName($intf))
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * static constructors/destructors
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_status_t $helper.getServiceName($intf)_etch_runtime_shutdown_hook_func()
+{
+    if(_g_$helper.getServiceName($intf)_valufact_statics) {
+        $helper.getServiceName($intf)_valufact_free_statics();
+    }
+	return ETCH_SUCCESS;
+}
+ 
+${valufactname}_statics* ${valufactname}_get_static(){
+    if(_g_${valufactname}_statics == NULL){
+        _g_${valufactname}_statics  = malloc(sizeof(${valufactname}_statics));
+        memset(_g_${valufactname}_statics ,0 ,sizeof(${valufactname}_statics)); 
+
+        _g_${valufactname}_statics->_etch_${valufactname}_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+        _g_${valufactname}_statics->_etch_${valufactname}_c2tmap = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+
+        defvf_initialize_static(_g_${valufactname}_statics->_etch_${valufactname}_typemap, _g_${valufactname}_statics->_etch_${valufactname}_c2tmap);
+        ${valufactname}_init_static_types();
+        ${valufactname}_init_static_fields();
+        ${valufactname}_init_static_parameters();
+        ${valufactname}_init_static_serializers();
+		etch_runtime_shutdown_hook_add($helper.getServiceName($intf)_etch_runtime_shutdown_hook_func);
+    }
+
+    return _g_${valufactname}_statics;
+}
+
+
+/**
+ * $helper.getVfName($intf)_init_types()
+ * instantiate type objects
+ */
+static int $helper.getVfName($intf)_init_static_types ()
+{
+    int restype = NULL;
+    struct i_hashtable* vtab = NULL; 
+	$helper.getVfName($intf)_statics* p =  $helper.getVfName($intf)_get_static();
+
+    /* instantiate type name strings */
+    
+## generate messages
+#foreach($n in $intf.iterator() )
+#if($n.isMessage())
+#if(!$n.isHidden())
+	p->str_$helper.getServiceName($intf)_$n.name() = new_wchar(L"$intf.fqname().$n.name()");
+#if(! $n.isOneway())
+	p->str_$helper.getServiceName($intf)__result_$n.name() = new_wchar(L"$intf.fqname()._result_$n.name()");
+#end
+#end
+#end
+#end
+
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+    p->str_$n.efqname($helper) = new_wchar(L"$n.fqname()");
+#end
+#end
+
+    /* instantiate type objects */
+#foreach($n in $intf.iterator() )
+#if($n.isMessage())
+#if(!$n.isHidden())
+    p->_mt_$helper.getServiceName($intf)_$n.name() = new_static_type(p->str_$helper.getServiceName($intf)_$n.name());
+    ETCH_ASSERT(p->_mt_$helper.getServiceName($intf)_$n.name());
+#if(! $n.isOneway())
+    p->_mt_$helper.getServiceName($intf)__result_$n.name() = new_static_type(p->str_$helper.getServiceName($intf)__result_$n.name());
+    ETCH_ASSERT(p->_mt_$helper.getServiceName($intf)__result_$n.name());
+#end
+#end
+#end
+#end
+
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+    p->_mt_$n.efqname($helper) = new_static_type(p->str_$n.efqname($helper));
+    ETCH_ASSERT(p->_mt_$n.efqname($helper));
+#end
+#end
+	vtab = (struct i_hashtable*)((etch_object*)p->_etch_$helper.getVfName($intf)_typemap)->vtab;
+    /* add types to vf */
+#foreach($n in $intf.iterator() )
+#if($n.isMessage())
+#if(!$n.isHidden())
+   restype =  vtab->inserth(p->_etch_$helper.getVfName($intf)_typemap->realtable, p->_mt_$helper.getServiceName($intf)_$n.name(), NULL, p->_etch_$helper.getVfName($intf)_typemap, 0); 
+   ETCH_ASSERT(! restype);
+#if(! $n.isOneway())
+   restype =  vtab->inserth(p->_etch_$helper.getVfName($intf)_typemap->realtable, p->_mt_$helper.getServiceName($intf)__result_$n.name(), NULL, p->_etch_$helper.getVfName($intf)_typemap, 0); 
+   ETCH_ASSERT(! restype);
+#end
+#end
+#end
+#end
+
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+	restype =  vtab->inserth(p->_etch_$helper.getVfName($intf)_typemap->realtable, p->_mt_$n.efqname($helper), NULL, p->_etch_$helper.getVfName($intf)_typemap, 0); 
+    ETCH_ASSERT(! restype);
+#end
+#end
+
+    /* set type response fields */
+#foreach($n in $intf.iterator() )
+#if($n.isMessage())
+#if(!$n.isHidden())
+#if(!$n.isOneway())
+    etchtype_set_response_field(p->_mt_$helper.getServiceName($intf)__result_$n.name(),  builtins._mf_result);
+#end
+#end
+#end
+#end
+
+    /* set message result types */
+#foreach($n in $intf.iterator() )
+#if($n.isMessage())
+#if(!$n.isHidden())
+#if(!$n.isOneway())
+    etchtype_set_result_type (p->_mt_$helper.getServiceName($intf)_$n.name(),  p->_mt_$helper.getServiceName($intf)__result_$n.name());
+#end
+#end
+#end
+#end
+
+    /* set timeouts */
+#foreach($n in $intf.iterator() )
+#if($n.isMessage())
+#if(!$n.isHidden())
+#if(!$n.isOneway())
+    etchtype_set_timeout (p->_mt_$helper.getServiceName($intf)__result_$n.name(),  $n.getTimeout());
+#end
+#end
+#end
+#end
+
+	/* set async modes */
+#foreach ( $n in $intf.iterator() )
+#if ($n.isMessage())
+#if (!$n.isHidden())
+#if ($n.isQueuedAsyncReceiver())
+    etchtype_set_async_mode(p->_mt_$helper.getServiceName($intf)_$n.name(), ETCH_ASYNCMODE_QUEUED);
+#elseif ($n.isFreeAsyncReceiver())
+    etchtype_set_async_mode(p->_mt_$helper.getServiceName($intf)_$n.name(), ETCH_ASYNCMODE_FREE);
+#else
+    etchtype_set_async_mode(p->_mt_$helper.getServiceName($intf)_$n.name(), ETCH_ASYNCMODE_NONE);
+#end
+#end
+#end
+#end
+
+	return 0;
+}
+
+
+/**
+ * $helper.getVfName($intf)_init_fields()
+ * instantiate field objects
+ */
+static int $helper.getVfName($intf)_init_static_fields ()
+{
+#set ($tmp = $helper.resetHistory())
+#foreach($n in $intf.iterator())
+#if(!$n.isHidden())
+#if(!$n.isBuiltin())
+#foreach($p in $n.iterator())
+#if(!$helper.historyContains($p.name().toString()))
+    $helper.getVfName($intf)_get_static()->str_$helper.getServiceName($intf)_$p.name() = new_wchar(L"$p.name()");
+#set ($tmp = $helper.addStringToHistory($p.name().toString()))
+#end
+#end
+#end
+#end
+#end
+
+#set ($tmp = $helper.resetHistory())
+#foreach($n in $intf.iterator())
+#if(!$n.isHidden())
+#if(!$n.isBuiltin())
+#foreach($p in $n.iterator())
+#if(!$helper.historyContains($p.name().toString()))
+    $helper.getVfName($intf)_get_static()->_mf_$helper.getServiceName($intf)_$p.name() = new_static_field($helper.getVfName($intf)_get_static()->str_$helper.getServiceName($intf)_$p.name());
+#set ($tmp = $helper.addStringToHistory($p.name().toString()))
+#end
+#end
+#end
+#end
+#end
+	return 0;
+
+}
+
+/**
+ * $helper.getVfName($intf)_init_parameters()
+ * initialize service method parameters
+ */
+static int $helper.getVfName($intf)_init_static_parameters ()
+{
+	$helper.getVfName($intf)_statics* p = $helper.getVfName($intf)_get_static();
+	
+	
+#foreach($n in $intf.iterator())
+#if($n.isEnumx())
+#foreach($p in $n.iterator())	
+	etchtype_put_validator(p->_mt_$helper.getServiceName($intf)_$n.name(), 
+		clone_field(p->_mf_$helper.getServiceName($intf)_$p.name()), (etch_object*)etchvtor_boolean_get(0));
+#end		
+#elseif($n.isStruct() || $n.isExcept())
+//params for $n
+#foreach( $p in $n.getAllParameters() )
+	etchtype_put_validator(p->_mt_$helper.getServiceName($intf)_$n.name(),
+	                       clone_field(p->_mf_$helper.getServiceName($intf)_$p.fqname()), 
+		                   $helper.getValidator($intf, $p));
+#end
+#else
+//params for $n
+#foreach( $p in $n.iterator() )
+#if($n.isHidden())
+	etchtype_put_validator(p->_mt_$helper.getServiceName($intf)_$n.name(),
+	                       builtins._mf_$p.fqname(), 
+						   $helper.getValidator($intf, $p));
+#else
+	etchtype_put_validator(p->_mt_$helper.getServiceName($intf)_$n.name(),
+	                       clone_field(p->_mf_$helper.getServiceName($intf)_$p.fqname()), 
+						   $helper.getValidator($intf, $p));
+#end						
+#end		
+#end
+#if ($n.isMessage())
+    etchtype_put_validator(p->_mt_$helper.getServiceName($intf)_$n.name(), 
+        clone_field(builtins._mf__message_id), (etch_object*) etchvtor_int64_get(0));
+#if ($n.isHidden())
+	etchtype_put_validator(p->_mt_$helper.getServiceName($intf)_$n.name(), 
+        clone_field(builtins._mf_result), (etch_object*) etchvtor_exception_get(0));
+	etchtype_put_validator(p->_mt_$helper.getServiceName($intf)_$n.name(), 
+        clone_field(builtins._mf__in_reply_to), (etch_object*) etchvtor_int64_get(0));
+#set( $param = $n.getResultParam() )
+#set( $reqMsg = $n.getRequestMessage() )
+#foreach( $ex in $reqMsg.thrown().iterator() )
+	etchtype_put_validator(p->_mt_$helper.getServiceName($intf)_$n.name(),
+	                       builtins._mf_result, 
+		                   $helper.getValidator($intf, $ex));
+#end
+	etchtype_put_validator(p->_mt_$helper.getServiceName($intf)_$n.name(),
+	                       builtins._mf_result, 
+		                   $helper.getValidator($intf, $param));
+#end
+#end	
+#end
+	
+
+//OLD
+//structs	
+	return 0;
+}
+
+/**
+ * $helper.getVfName($intf)_init_serializers()
+ */
+static int $helper.getVfName($intf)_init_static_serializers ()
+{
+    int  result = 0;
+#foreach($n in $intf.iterator())
+#if ($n.isExcept())
+#set( $c2map_needed = true )
+#elseif ($n.isStruct()  || $n.isEnumx())
+#set( $c2map_needed = true )
+#end
+#end
+#if ($c2map_needed)
+    $helper.getVfName($intf)_statics* p = $helper.getVfName($intf)_get_static();
+    class_to_type_map* c2tmap = p->_etch_$helper.getVfName($intf)_c2tmap;
+#end
+
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+    const unsigned short classid_$n.efqname($helper) = get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase());
+#end
+#end 
+
+    /* note that etch_serializer_init takes care of the class to type, setting
+     * of component type, instantiation of import export helper and installing
+     * it to the type. 
+     */
+
+#foreach($n in $intf.iterator() )
+#if($n.isExcept())
+	  /* serializer for $n.efqname($helper) */
+    result = etch_serializer_init (p->_mt_$n.efqname($helper), p->str_$n.efqname($helper), 
+        ETCHMAKECLASS(ETCHTYPEB_EXCEPTION, classid_$n.efqname($helper)), 
+            c2tmap, NULL, new_$n.efqname($helper)_serializer);
+
+#elseif ($n.isStruct()  || $n.isEnumx())
+    /* serializer for $n.efqname($helper) */
+    result = etch_serializer_init (p->_mt_$n.efqname($helper), p->str_$n.efqname($helper), 
+        ETCHMAKECLASS(ETCHTYPEB_USER, classid_$n.efqname($helper)), 
+            c2tmap, NULL, new_$n.efqname($helper)_serializer);
+
+#end
+#end
+    return result;
+}
+
+
+
+/**
+ * destroy_$helper.getVfName($intf)_impl()
+ * destructor for the $helper.getServiceName($intf) value factory extension
+ */
+int destroy_$helper.getVfName($intf)_impl(void* data)
+{
+    $helper.getVfName($intf)_impl* impl = ($helper.getVfName($intf)_impl*)data;
+    if (NULL == impl) return -1;
+
+    if (!is_etchobj_static_content(impl))
+    {
+        // add if neccessary
+    }
+
+   return destroy_objectex((etch_object*) impl);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * constructors/destructors
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+ 
+$helper.getVfName($intf)* new_$helper.getVfName($intf)()
+{
+    $helper.getVfName($intf)_impl* impl = NULL;
+	default_value_factory* pvf = new_default_value_factory (
+		$helper.getVfName($intf)_get_static()->_etch_$helper.getVfName($intf)_typemap, 
+		$helper.getVfName($intf)_get_static()->_etch_$helper.getVfName($intf)_c2tmap);
+    ETCH_ASSERT(pvf);
+
+    /* note that the vf destructor is the default value factory destructor,
+     * which in turn invokes the destructor on its impl object 
+     */
+    impl = ($helper.getVfName($intf)_impl*) new_object (sizeof($helper.getVfName($intf)_impl), 
+       ETCHTYPEB_VALUEFACTIMP, get_dynamic_classid_unique(&CLASSID_$helper.getVfName($intf).toUpperCase()_IMPL));
+
+    ((etch_object*)impl)->destroy = destroy_$helper.getVfName($intf)_impl; 
+    pvf->impl = (etch_object*) impl;	
+#foreach ( $n in $intf.iterator() )
+#if ($n.isMixin())
+#set( $m = $n.getModule() )
+#set( $s = $m.iterator().next() )
+		defvf_add_mixin(pvf, new_$s.name().toString().toLowerCase()_valufact());
+#end
+#end
+    return pvf; 
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * vf class methods
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+ 
+void $helper.getVfName($intf)_free_statics ()
+{
+    
+	$helper.getVfName($intf)_statics* data = $helper.getVfName($intf)_get_static();
+    ETCH_ASSERT(data); 
+
+#foreach($n in $intf.iterator() )
+#if($n.isMessage())
+#if(!$n.isHidden())
+    destroy_static_type (data->_mt_$helper.getServiceName($intf)_$n.name());
+#if(! $n.isOneway())	
+    destroy_static_type (data->_mt_$helper.getServiceName($intf)__result_$n.name());
+#end	
+#end
+#end
+#end
+	
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isExcept()  || $n.isEnumx())
+    destroy_static_type (data->_mt_$n.efqname($helper));
+#end
+#end
+
+#set ($tmp = $helper.resetHistory())
+#foreach($n in $intf.iterator())
+#if (!$n.isHidden())
+#foreach($p in $n.iterator())
+#if(!$helper.historyContains($p.name().toString()))
+    destroy_static_field(data->_mf_$helper.getServiceName($intf)_$p.name());
+#set ($tmp = $helper.addStringToHistory($p.name().toString()))
+#end
+#end
+##
+#end
+#end
+
+#set ($tmp = $helper.resetHistory())
+#foreach($n in $intf.iterator())
+#if (!$n.isHidden())
+#foreach($p in $n.iterator())
+#if(!$helper.historyContains($p.name().toString()))
+    etch_free (data->str_$helper.getServiceName($intf)_$p.name());
+#set ($tmp = $helper.addStringToHistory($p.name().toString()))
+#end
+#end
+##
+#end
+#end
+
+#foreach($n in $intf.iterator())
+#if($n.isMessage())
+#if(!$n.isHidden())
+    etch_free (data->str_$helper.getServiceName($intf)_$n.name());
+#if(! $n.isOneway())  	
+    etch_free (data->str_$helper.getServiceName($intf)__result_$n.name());
+#end
+##
+#end
+#end
+#end
+
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isExcept() || $n.isEnumx())
+    etch_free (data->str_$n.efqname($helper));
+#end
+#end
+
+
+    //set_etchobj_static_content(data->_etch_$helper.getServiceName($intf)_valufact_typemap);
+    //set_etchobj_static_content(data->_etch_$helper.getServiceName($intf)_valufact_c2tmap);
+	
+	data->_etch_$helper.getServiceName($intf)_valufact_typemap->is_readonly_keys = 0;
+    data->_etch_$helper.getServiceName($intf)_valufact_c2tmap->is_readonly_keys = 0;
+    etch_object_destroy(data->_etch_$helper.getServiceName($intf)_valufact_typemap);
+    etch_object_destroy(data->_etch_$helper.getServiceName($intf)_valufact_c2tmap);
+
+	etch_free(data);
+	_g_$helper.getServiceName($intf)_valufact_statics = NULL;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * serializers
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+ 
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+/**
+ * etchserializer_$n.efqname($helper)_export_value() 
+ * export valueof a $n.efqname($helper)
+ * @param objval a $n.efqname($helper), caller owns it and presumably will
+ * destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+etch_object* etchserializer_$n.efqname($helper)_export_value(etch_serializer* thisx, etch_object* objval)
+{
+    const int THISINITSIZE = 2;
+    etch_structvalue* expstruct = NULL;
+    const unsigned short classid_$n.efqname($helper) = get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase());
+#if($n.isExcept())
+	if (!is_etch_objparams(objval, ETCHTYPEB_EXCEPTION, classid_$n.efqname($helper))) return NULL;
+#else
+	if (!is_etch_objparams(objval, ETCHTYPEB_USER, classid_$n.efqname($helper))) return NULL;
+#end
+
+    expstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+
+#if($n.isEnumx())	
+	switch((($n.efqname($helper)*)objval)->value)
+	{
+#foreach($enumType in $n.iterator())
+       case $n.name()_$enumType: structvalue_put(expstruct, clone_field(_g_$helper.getVfName($intf)_statics->_mf_$helper.getServiceName($intf)_$enumType), (etch_object*) new_boolean(TRUE)); break;
+#end
+    }
+#end
+
+#foreach($p in $n.getAllParameters())
+#if($p.type().isArray())
+	structvalue_put(expstruct, _g_$helper.getVfName($intf)_statics->_mf_$helper.getServiceName($intf)_$p.name(), 
+       etch_object_clone_func((void*)(($n.efqname($helper)*)objval)->${p.fqname()}));
+#elseif($helper.isEnumParam($p))
+	structvalue_put(expstruct, _g_$helper.getVfName($intf)_statics->_mf_$helper.getServiceName($intf)_$p.name(), 
+       (etch_object*)new_$helper.getIntfName( $intf )_$p.type()_init((($n.efqname($helper)*)objval)->${p.fqname()}));
+#elseif($helper.getValidatorStringForParam($p) == 'object'
+		|| $helper.getValidatorStringForParam($p) == 'string')
+	if((($n.efqname($helper)*)objval)->${p.fqname()}) {
+		structvalue_put(expstruct, _g_$helper.getVfName($intf)_statics->_mf_$helper.getServiceName($intf)_$p.name(), 
+			etch_object_clone_func((void*)(($n.efqname($helper)*)objval)->${p.fqname()}));
+	}
+#else
+    structvalue_put(expstruct, _g_$helper.getVfName($intf)_statics->_mf_$helper.getServiceName($intf)_$p.name(),
+	   (etch_object*) new_$helper.getValidatorStringForParam($p)((($n.efqname($helper)*)objval)->$p.fqname()));
+#end	      
+#end
+    return (etch_object*) expstruct; /* caller owns this structvalue */
+}
+
+/**
+ * etchserializer_$n.efqname($helper)_import_value() 
+ * import value for a $n.efqname($helper).
+ * @param objval an etch_structvalue of appropriate type for the $n.efqname($helper).
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported $n.efqname($helper). 
+ * caller owns and must destroy the returned object.  
+ */
+etch_object* etchserializer_$n.efqname($helper)_import_value (etch_serializer* thisx, etch_object* objval) 
+{
+    $n.efqname($helper)* outobj = NULL;
+	
+#foreach($p in $n.getAllParameters())
+    $helper.getEtchTypeName($p.type())* valobj_$p.name() = NULL;
+#end	   
+
+#if($n.isEnumx())
+	$helper.getIntfName( $intf )_$n.name()_enum enumValue = NULL;
+	etch_boolean* enumFlagValue;
+#end
+
+    etch_structvalue* instruct = NULL;
+    if (!is_etch_struct(objval)) return NULL;
+
+    instruct = (etch_structvalue*) objval;
+    if (!structvalue_is_type(instruct, thisx->type)) return NULL;
+
+#if($n.isEnumx())
+
+#foreach($enumType in $n.iterator())
+    enumFlagValue = (etch_boolean*) structvalue_get(instruct, _g_$helper.getVfName($intf)_statics->_mf_$helper.getServiceName($intf)_$enumType);
+    if(enumFlagValue && enumFlagValue->value)
+    {
+        enumValue = $n.name()_$enumType;
+    }
+#end	
+
+#end
+
+#foreach($p in $n.getAllParameters())
+    /* fetch the $p.name() value wrapper out of the struct. struct owns it */
+#if($helper.isEnumParam($p))
+	valobj_$p.name() = ($helper.getEtchTypeName($p.type())*) structvalue_get(instruct, _g_$helper.getVfName($intf)_statics->_mf_$helper.getServiceName($intf)_$p.name());
+#elseif($p.type().isArray())
+    valobj_$p.name() = (etch_arraytype*) structvalue_remove(instruct, _g_$helper.getVfName($intf)_statics->_mf_$helper.getServiceName($intf)_$p.name());	
+#elseif($helper.getValidatorStringForParam($p) == 'object')
+    valobj_$p.name() = ($helper.getEtchTypeName($p.type())*) structvalue_get(instruct, _g_$helper.getVfName($intf)_statics->_mf_$helper.getServiceName($intf)_$p.name());
+#else
+    valobj_$p.name() = ($helper.getEtchTypeName($p.type())*) structvalue_get(instruct, _g_$helper.getVfName($intf)_statics->_mf_$helper.getServiceName($intf)_$p.name());
+#end	
+#if($p.type().isArray())
+    if (valobj_$p.name() && !is_etch_arraytype(valobj_$p.name())) return NULL;
+#elseif($p.type().isObject())
+	//nothing to check, is object
+#else
+    if (valobj_$p.name() && !is_$helper.getEtchTypeName($p.type())(valobj_$p.name())) return NULL;
+#end
+#end
+
+    outobj = new_$n.efqname($helper)();
+	
+#if($n.isEnumx())
+    outobj->value = enumValue;
+#end
+	
+#foreach($p in $n.getAllParameters())
+#if($p.type().isArray())
+    if(valobj_$p.name())
+    outobj->$p.name() = valobj_$p.name(); 
+    //outobj->$p.name() = (etch_arraytype*) etch_object_clone_func((void*)valobj_$p.name());	
+#elseif($helper.getValidatorStringForParam($p) == 'string')	
+    if(valobj_$p.name())
+        outobj->$p.name() = (etch_string*) etch_object_clone_func((void*)valobj_$p.name());
+#elseif($helper.isEnumParam($p))
+    if(valobj_$p.name())
+        outobj->$p.name() = valobj_$p.name()->value;
+#elseif($helper.getValidatorStringForParam($p) == 'object')
+    if(valobj_$p.name())
+        outobj->$p.name() = ($helper.getEtchTypeName($p.type())*) etch_object_clone_func((void*)valobj_$p.name());
+#else
+    if(valobj_$p.name())
+        outobj->$p.name() = valobj_$p.name()->value;
+#end
+#end
+    return (etch_object*) outobj;  /* caller owns this object */
+}
+
+/**
+ * new_$n.efqname($helper)_serializer() 
+ * etch_serializer_excp constructor - conforms to typedef etch_serializer_ctor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_$n.efqname($helper)_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    ((etch_object*)newobj)->class_id = get_dynamic_classid_unique(&CLASSID_$n.efqname($helper).toUpperCase()_SERIALIZER);
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_$n.efqname($helper)_export_value;
+    newobj->import_value = etchserializer_$n.efqname($helper)_import_value;
+
+    return newobj;
+}
+
+#end
+#end
diff --git a/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/vf_h.vm b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/vf_h.vm
new file mode 100644
index 0000000..91c6820
--- /dev/null
+++ b/binding-c/compiler/src/main/resources/org/apache/etch/bindings/c/compiler/vf_h.vm
@@ -0,0 +1,143 @@
+##
+## 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.
+##
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+ 
+/*
+ * $helper.getVfFileNameH($intf)
+ * $helper.getIntfName($intf) implementation of value factory
+ */
+
+#ifndef $helper.getVfName($intf).toUpperCase()_H
+#define $helper.getVfName($intf).toUpperCase()_H
+
+\#include "etch_default_value_factory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef default_value_factory $helper.getVfName($intf).toLowerCase();
+
+extern unsigned short CLASSID_$helper.getVfName($intf).toUpperCase()_IMPL;
+
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+unsigned short CLASSID_$helper.getServiceName($intf).toUpperCase()_$n.name().name().toUpperCase()_SERIALIZER;
+#end
+#end
+
+
+/**
+ * $helper.getVfName($intf)_statics
+ */
+typedef struct $helper.getVfName($intf)_statics
+{
+    class_to_type_map*  _etch_$helper.getVfName($intf)_c2tmap;
+    vf_idname_map*      _etch_$helper.getVfName($intf)_typemap;
+
+## generate messages
+#foreach($n in $intf.iterator() )
+#if($n.isMessage())
+#if(!$n.isHidden())
+    etch_type* _mt_$helper.getServiceName($intf)_$n.name();
+#if(! $n.isOneway())
+    etch_type* _mt_$helper.getServiceName($intf)__result_$n.name();
+#end
+#end
+#end
+#end
+
+## generate stucts
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+    etch_type* _mt_$helper.getServiceName($intf)_$n.name();
+#end
+#end
+
+	
+#set ($tmp = $helper.resetHistory())
+#foreach($n in $intf.iterator())
+#if (!$n.isHidden())
+#foreach($p in $n.iterator())
+#if(!$helper.historyContains($p.name().toString()))
+    etch_field* _mf_$helper.getServiceName($intf)_$p.name();
+#set ($tmp = $helper.addStringToHistory($p.name().toString()))
+#end
+#end
+##
+#end
+#end
+
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+    struct etch_serializer* serializer_$n.name();
+#end
+#end   
+
+#set ($tmp = $helper.resetHistory())
+#foreach($n in $intf.iterator())
+#if (!$n.isHidden())
+#foreach($p in $n.iterator())
+#if(!$helper.historyContains($p.name().toString()))
+    wchar_t* str_$helper.getServiceName($intf)_$p.name();
+#set ($tmp = $helper.addStringToHistory($p.name().toString()))
+#end
+#end
+##
+#end
+#end
+
+#foreach($n in $intf.iterator() )
+#if($n.isMessage())
+    wchar_t* str_$helper.getServiceName($intf)_$n.name();
+#end
+#end
+##generate struct names
+#foreach($n in $intf.iterator() )
+#if ($n.isStruct() || $n.isEnumx() || $n.isExcept())
+    wchar_t* str_$helper.getIntfName($intf)_$n.name();
+#end
+#end
+
+} $helper.getVfName($intf)_statics;
+
+/**
+ * $helper.getVfName($intf)_impl
+ * $helper.getIntfName($intf) extension of default value factory
+ */
+typedef struct $helper.getVfName($intf)_impl
+{
+    etch_object object;    
+    	
+} $helper.getVfName($intf)_impl;
+
+$helper.getVfName($intf)* new_$helper.getVfName($intf)();
+$helper.getVfName($intf)_statics* $helper.getVfName($intf)_get_static();
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif 
+
diff --git a/binding-c/runtime/c/README.win32 b/binding-c/runtime/c/README.win32
new file mode 100644
index 0000000..55c3d6f
--- /dev/null
+++ b/binding-c/runtime/c/README.win32
@@ -0,0 +1,75 @@
+How to build the etch c binding:
+*******************************
+
+You need the following:
+***********************
+Build for Win32
+- Apache APR Source Version 1.3 for Win32, e.g. available under 
+  http://ftp-stud.hs-esslingen.de/pub/Mirrors/ftp.apache.org/dist/apr/apr-1.3.9-win32-src.zip or
+  http://archive.apache.org/dist/apr/apr-1.3.9-win32-src.zip
+
+- Apache APR Iconv Source Version 1.2 for Win32, e.g. available under
+  http://ftp-stud.hs-esslingen.de/pub/Mirrors/ftp.apache.org/dist/apr/apr-iconv-1.2.1-win32-src-r2.zip or
+  http://archive.apache.org/dist/apr/apr-iconv-1.2.1-win32-src-r2.zip
+
+- Apache APR Util Version 1.3 for Win32, e.g. available under
+  ftp://ftp-stud.hs-esslingen.de/pub/Mirrors/ftp.apache.org/dist/apr/apr-util-1.3.9-win32-src.zip or
+  http://archive.apache.org/dist/apr/apr-util-1.3.9-win32-src.zip
+
+- CUnit Sources from Version CUnit-2.1-0-src.zip
+  http://cunit.sourceforge.net/
+  download from http://sourceforge.net/projects/cunit/
+
+---------------------------------------------------------------------------------------------------------
+
+The following instructions were tested using MS Visual Studio 2005 SP1 on Windows 7. 
+It should work with newer Visual Studio versions too, but was not tested. 
+
+(Linux build will be available soon.)
+
+Prerequisites:
+**************
+
+- you should have the following folder structure inside your etch sources
+  - [somefolder]/etch/src/extern/apr
+  - [somefolder]/etch/src/extern/apr/apr
+  - [somefolder]/etch/src/extern/apr/apr-iconv
+  - [somefolder]/etch/src/extern/apr/apr-util
+  - [somefolder]/etch/src/extern/cunit
+
+- unpack all apr zips (apr-1.3.9-win32-src.zip, apr-iconv-1.2.1-win32-src-r2.zip, apr-util-1.3.9-win32-src.zip)
+  to [somefolder]/etch/src/extern/apr and remove all version numbers from the unpacked folders
+-- [somefolder]/etch/src/extern/apr/apr-1.3.9 to [somefolder]/etch/src/extern/apr/apr
+-- [somefolder]/etch/src/extern/apr/apr-iconv-1.2.1 to [somefolder]/etch/src/extern/apr/apr-iconv
+-- [somefolder]/etch/src/extern/apr/apr-util-1.3.9 to [somefolder]/etch/src/extern/apr/apr-util
+- unpack the CUnit-2.1-0-src.zip into the cunit folder and remove all version numbers from the unpacked folder
+-- [somefolder]/etch/src/extern/CUnit-2.1-0 to [somefolder]/etch/src/extern/apr/cunit
+
+To build, do the following:
+***************************
+
+1.) open the APR-util VS solution ([somefolder]/apr/apr-util/apr-util.dsw) 
+    (convert to 2005 is ok, yes to all)
+    -> build the apr project
+    -> build the apriconv project
+    -> build the libapr project
+    -> build the libapriconv project
+    -> build the libapriconv_ccs_modules project
+    -> build the libapriconv_ces_modules project
+    the rest of the projects in the apr solution should not be needed
+2.) set the environment variable 
+    APR_ICONV_PATH to [somefolder]\etch\src\extern\apr\apr-iconv\Debug\iconv
+3.) open the CUNIT solution in VS ([somefolder]/etch/src/extern/cunit/VS8/CUnit.sln)
+    -> build the libcunit project
+    the rest of the projects in the CUnit solution should not be needed
+4.) open the etch C binding solution ([somefolder]/etch/binding-c/runtime/c/etch-c.sln)
+    -> build the solution
+5.) copy 
+	 apr\Debug\libapr-1.dll 
+    to	
+	 [somefolder]/etch/binding-c/runtime/src/test/target/win32/Debug
+5.) copy 
+	 apr-iconv\Debug\libapriconv-1.dll 
+    to	
+	 [somefolder]/etch/binding-c/runtime/src/test/target/win32/Debug
+6.) run the project etch-c-test to verify your build
diff --git a/binding-c/runtime/c/etch-c.sln b/binding-c/runtime/c/etch-c.sln
new file mode 100644
index 0000000..c726809
--- /dev/null
+++ b/binding-c/runtime/c/etch-c.sln
@@ -0,0 +1,64 @@
+

+Microsoft Visual Studio Solution File, Format Version 9.00

+# Visual Studio 2005

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "etch-c", "src\main\etch-c.vcproj", "{C49054D6-0122-4F20-A0A2-06197D08567B}"

+	ProjectSection(WebsiteProperties) = preProject

+		Debug.AspNetCompiler.Debug = "True"

+		Release.AspNetCompiler.Debug = "False"

+	EndProjectSection

+	ProjectSection(ProjectDependencies) = postProject

+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66} = {CC75FED8-5D1B-4323-B73A-36C41FD1CC66}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "etch-c-test", "src\test\etch-c-test.vcproj", "{64A36C3F-2BE4-4471-A291-C65BD8A9E6FE}"

+	ProjectSection(WebsiteProperties) = preProject

+		Debug.AspNetCompiler.Debug = "True"

+		Release.AspNetCompiler.Debug = "False"

+	EndProjectSection

+	ProjectSection(ProjectDependencies) = postProject

+		{C49054D6-0122-4F20-A0A2-06197D08567B} = {C49054D6-0122-4F20-A0A2-06197D08567B}

+	EndProjectSection

+EndProject

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jenkhash", "src\extern\jenkhash\jenkhash.vcproj", "{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}"

+	ProjectSection(WebsiteProperties) = preProject

+		Debug.AspNetCompiler.Debug = "True"

+		Release.AspNetCompiler.Debug = "False"

+	EndProjectSection

+EndProject

+Global

+	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+		Debug|Win32 = Debug|Win32

+		Debug Static|Win32 = Debug Static|Win32

+		Release Static|Win32 = Release Static|Win32

+		Release|Win32 = Release|Win32

+	EndGlobalSection

+	GlobalSection(ProjectConfigurationPlatforms) = postSolution

+		{C49054D6-0122-4F20-A0A2-06197D08567B}.Debug Static|Win32.ActiveCfg = Debug Static|Win32

+		{C49054D6-0122-4F20-A0A2-06197D08567B}.Debug Static|Win32.Build.0 = Debug Static|Win32

+		{C49054D6-0122-4F20-A0A2-06197D08567B}.Debug|Win32.ActiveCfg = Debug|Win32

+		{C49054D6-0122-4F20-A0A2-06197D08567B}.Debug|Win32.Build.0 = Debug|Win32

+		{C49054D6-0122-4F20-A0A2-06197D08567B}.Release Static|Win32.ActiveCfg = Release Static|Win32

+		{C49054D6-0122-4F20-A0A2-06197D08567B}.Release Static|Win32.Build.0 = Release Static|Win32

+		{C49054D6-0122-4F20-A0A2-06197D08567B}.Release|Win32.ActiveCfg = Release|Win32

+		{C49054D6-0122-4F20-A0A2-06197D08567B}.Release|Win32.Build.0 = Release|Win32

+		{64A36C3F-2BE4-4471-A291-C65BD8A9E6FE}.Debug Static|Win32.ActiveCfg = Debug Static|Win32

+		{64A36C3F-2BE4-4471-A291-C65BD8A9E6FE}.Debug Static|Win32.Build.0 = Debug Static|Win32

+		{64A36C3F-2BE4-4471-A291-C65BD8A9E6FE}.Debug|Win32.ActiveCfg = Debug|Win32

+		{64A36C3F-2BE4-4471-A291-C65BD8A9E6FE}.Debug|Win32.Build.0 = Debug|Win32

+		{64A36C3F-2BE4-4471-A291-C65BD8A9E6FE}.Release Static|Win32.ActiveCfg = Release Static|Win32

+		{64A36C3F-2BE4-4471-A291-C65BD8A9E6FE}.Release Static|Win32.Build.0 = Release Static|Win32

+		{64A36C3F-2BE4-4471-A291-C65BD8A9E6FE}.Release|Win32.ActiveCfg = Release|Win32

+		{64A36C3F-2BE4-4471-A291-C65BD8A9E6FE}.Release|Win32.Build.0 = Release|Win32

+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Debug Static|Win32.ActiveCfg = Debug Static|Win32

+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Debug Static|Win32.Build.0 = Debug Static|Win32

+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Debug|Win32.ActiveCfg = Debug|Win32

+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Debug|Win32.Build.0 = Debug|Win32

+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Release Static|Win32.ActiveCfg = Release Static|Win32

+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Release Static|Win32.Build.0 = Release Static|Win32

+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Release|Win32.ActiveCfg = Release|Win32

+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Release|Win32.Build.0 = Release|Win32

+	EndGlobalSection

+	GlobalSection(SolutionProperties) = preSolution

+		HideSolutionNode = FALSE

+	EndGlobalSection

+EndGlobal

diff --git a/binding-c/runtime/c/include/etch.h b/binding-c/runtime/c/include/etch.h
new file mode 100644
index 0000000..facc18f
--- /dev/null
+++ b/binding-c/runtime/c/include/etch.h
@@ -0,0 +1,123 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+#ifndef _ETCH_H_
+#define _ETCH_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <apr_pools.h>
+#include <apr_atomic.h>
+#include <apr_errno.h>
+#include <apr_general.h>
+#include <apr_thread_mutex.h>
+#include <apr_thread_cond.h>
+#include <apr_portable.h>
+#include <apr_strings.h>
+#include <apr_time.h>
+
+/**
+ * macros
+ */
+#define ETCH_ASSERT(condition) assert(condition)
+#define ETCH_ASSERT_EXIT(condition) assert(condition)
+
+//TODO: check which component use this defines, change functions
+// to use etch_status_t
+#define ETCH_DEFSIZE     0
+#define ETCH_INFWAIT     0
+#define ETCH_NOWAIT    (-1)
+#define ETCH_TIMEOUT     1
+#define ETCH_INTERRUPTED 0
+
+//TODO: check this stuff, check etch_nativearray encoding (QNX, Windows)
+#define ETCH_ENCODING_ASCII 0
+#define ETCH_ENCODING_UTF8  1
+#define ETCH_ENCODING_UTF16 2
+#define ETCH_ENCODING_UTF32 3
+#define ETCH_ENCODING_UCS2  4
+#define ETCH_ENCODING_UCS4  5
+#define ETCH_ENCODING_UNICODE 6
+
+#define ETCH_ENCODING_DEFAULT ETCH_ENCODING_UTF8
+#define IS_ETCH_ENCODING_8BIT(n) (n == ETCH_ENCODING_UTF8 || n == ETCH_ENCODING_ASCII)
+
+//TODO: check this sutff, etch_thread
+#define ETCH_THREADPOOLTYPE_FREE   0
+#define ETCH_THREADPOOLTYPE_QUEUED 1
+
+// TODO: check this stuff
+#define ETCHMAKECLASS(t,c) ((t << 16) | c)
+#define ETCHGETCLASS(n,t,c) do{ c=(short)(n & 0xffff); t=(short)(n>>16); }while(0);
+
+//TODO: check this stuff,etch_stub
+#define ETCH_ASYNCMODE_NONE   0  /* implies operation is synchronous */
+#define ETCH_ASYNCMODE_QUEUED 1  /* operation is queued to a thread pool */
+#define ETCH_ASYNCMODE_FREE   2  /* operation is executed in a new thread */
+
+//TODO: check, etch_tcpconxn
+#define ETCH_SHUTDOWNSIGNAL "$ETCHQUIT"
+
+/**
+ * common defines
+ */
+#undef  NULL
+#define NULL  0
+
+#undef  FALSE
+#define FALSE 0
+
+#undef  TRUE
+#define TRUE  1
+
+/**
+ * typedefs of basic datatypes
+ */
+typedef char                int8;
+typedef unsigned char       uint8;
+typedef short int           int16;
+typedef unsigned short int  uint16;
+typedef int                 int32;
+typedef unsigned int        uint32;
+typedef long long           int64;
+typedef unsigned long long  uint64;
+typedef unsigned char       byte;
+typedef unsigned char       boolean;
+
+uint32 etchhash(const void* key, const int keylen, const unsigned priorhash);
+
+typedef int (*etch_comparator) (void* myobj, void* otherobj);
+
+#define IS_ETCH_TRANSPORT_LITTLEENDIAN FALSE
+#define ETCHCONFIGDEF_EXAMPLE_STRING_MAXLEN 15 
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_H */
diff --git a/binding-c/runtime/c/include/etch_arraylist.h b/binding-c/runtime/c/include/etch_arraylist.h
new file mode 100644
index 0000000..0f029a0
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_arraylist.h
@@ -0,0 +1,115 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_arrarylist.h 
+ * arraylist implementation.
+ */
+
+#ifndef ETCHARRAYLIST_H
+#define ETCHARRAYLIST_H
+
+#include "etch.h"
+#include "etch_mutex.h"
+#include "etch_collection.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCHARRAYLIST_DEFSIZE 128
+#define ETCHARRAYLIST_CONTENT_SIMPLE 0  /* content memory freed as a unit */
+#define ETCHARRAYLIST_CONTENT_OBJECT 1  /* content is etchobject */
+#define ETCHARRAYLIST_SYNCHRONIZED TRUE
+
+//TODO: Check´, why this is needed
+typedef int (*arraycallback) (int, void*); /* arraylist callback signature */
+
+
+/** 
+ *  etch_arraylist: data structure encapsulating the arraylist
+ *  if is_readonly is set, content is read only and therefore is_free_content  
+ *  will have no effect -- list items may still be inserted and removed. This
+ *  guards against accidentally freeing memory during arraylist destruction 
+ *  for arrays of references which are still intended to remain in use. 
+ */
+typedef struct etch_arraylist
+{
+    etch_object object;
+
+    void** base;
+    unsigned short content_obj_type;  /* etch obj_type of a native value */
+    unsigned short content_class_id;  /* etch class_id of a native value */
+    unsigned int count;
+
+    /* this object may be masked by etch_collection_mask to determine content
+     * type and class, so do not add any fields above this comment */
+
+    unsigned int delta;
+    unsigned int size;
+    i_iterable iterable;
+
+    byte is_readonly;  
+    byte content_type;
+
+    arraycallback freehook; /* hook for free list content */
+
+} etch_arraylist;
+
+
+etch_arraylist* new_etch_arraylist(const unsigned int initialsize, const unsigned int deltasize);
+etch_arraylist* new_etch_arraylist_from(etch_arraylist*);
+etch_arraylist* new_etch_arraylist_synchronized(const unsigned int initialsize, const unsigned int deltasize);
+etch_arraylist* new_etch_arraylist_synchronized_from(etch_arraylist*);
+
+int   etch_arraylist_add      (etch_arraylist*, void* content);
+int   etch_arraylist_add_from (etch_arraylist*, etch_arraylist* newitems, etch_comparator); 
+int   etch_arraylist_containsp(etch_arraylist*, void* content, const unsigned startat); /* pointer compare */
+int   etch_arraylist_contains (etch_arraylist*, void* content, const unsigned startat, etch_comparator);
+int   etch_arraylist_count(etch_arraylist* list);
+int   etch_arraylist_indexofp (etch_arraylist*, void* content, const unsigned startat); /* pointer compare */
+int   etch_arraylist_indexof  (etch_arraylist*, void* content, const unsigned startat, etch_comparator);
+int   etch_arraylist_remove_content(etch_arraylist*, void* content, const unsigned startat, etch_comparator);
+int   etch_arraylist_insert   (etch_arraylist*, const unsigned i, void* content);
+int   etch_arraylist_remove   (etch_arraylist*, const unsigned i, const int is_free_content);
+int   etch_arraylist_set      (etch_arraylist*, const unsigned i, void* content);
+void* etch_arraylist_get      (etch_arraylist*, const unsigned i);
+void  etch_arraylist_clear    (etch_arraylist*, const int is_free_content);
+void  etch_arraylist_destroy  (etch_arraylist*, const int is_free_content);
+void  etch_arraylist_copyattrs(etch_arraylist* to, etch_arraylist* from);
+
+/* 
+ * explicit synchronization locking methods.
+ * these should be used only for locking a list during list iteration.   
+ * for synchronization of list operations, the presence of list.synchook  
+ * and list.synclock is sufficient. 
+ */
+int   etch_arraylist_getlock  (etch_arraylist*);
+int   etch_arraylist_trylock  (etch_arraylist*);
+int   etch_arraylist_rellock  (etch_arraylist*);
+
+/* i_iterable function overrides */
+int   etch_arraylist_iterable_first   (etch_iterator*);
+int   etch_arraylist_iterable_next    (etch_iterator*);
+int   etch_arraylist_iterable_has_next(etch_iterator*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHARRAYLIST_H */
diff --git a/binding-c/runtime/c/include/etch_arrayval.h b/binding-c/runtime/c/include/etch_arrayval.h
new file mode 100644
index 0000000..4cfbdc4
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_arrayval.h
@@ -0,0 +1,100 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_arrayval.h 
+ */
+
+#ifndef ETCHARRAYVAL_H
+#define ETCHARRAYVAL_H
+
+#include "etch_msgutl.h"
+#include "etch_arraylist.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define ETCHARRAYVAL_READONLY TRUE
+#define ETCHARRAYVAL_NOTREADONLY FALSE
+
+/**
+ * etch_arrayvalue
+ * an array of values, where each value is a pointer to an etch object.
+ */
+typedef struct etch_arrayvalue
+{
+    etch_object object;
+ 
+    etch_arraylist* list;
+    unsigned short content_obj_type;  /* etch obj_type of a native value */
+    unsigned short content_class_id;  /* etch class_id of a native value */
+    int  dim;
+
+    /* this object may be masked by etch_collection_mask to determine content
+     * type and class, so do not add any fields above this comment */
+
+    unsigned short content_item_size; /* byte count of a native value */ 
+    unsigned char  is_array_owned;    /* arrayvalue owns natarray? */ 
+    signed   char  type_code;         /* external content type */
+
+    etch_type* custom_struct_type;     /* not owned */
+    struct etch_nativearray* natarray; /* see is_array_owned */
+} etch_arrayvalue;
+
+/**
+ * new_arrayvalue_arraylist()
+ * allocates and returns an arraylist configured appropriately for use as arrayvalue backing store
+ */
+etch_arraylist* new_arrayvalue_arraylist(const int initsize, const int deltsize, 
+    const int is_readonly, const int is_synchronized);
+
+/* public methods on etch_arrayvalue */
+etch_arrayvalue* new_arrayvalue(const byte type_code, etch_type* custom_struct_type, 
+    const int dim, const int initsize, const int deltsize, 
+    const int is_readonly, const int is_synchronized);
+
+etch_arrayvalue* new_arrayvalue_from(struct etch_nativearray* natarray, 
+    const signed char type_code, etch_type* custom_struct_type, 
+    const int initsize, const int deltsize, 
+    const int is_readonly);
+
+etch_arrayvalue* new_arrayvalue_default();
+
+ETCH_ARRAY_ELEMENT* new_array_element(const int objtype);
+
+int   arrayvalue_add (etch_arrayvalue* thisp, ETCH_ARRAY_ELEMENT* content);
+
+int   arrayvalue_count(etch_arrayvalue*);
+void* arrayvalue_get(etch_arrayvalue*, const int index);
+
+int   arrayvalue_set_iterator(etch_arrayvalue*, etch_iterator*);
+void  arrayvalue_set_static_content(etch_arrayvalue*, const int is_set);
+
+int   arrayvalue_to_nativearray(etch_arrayvalue*);
+
+signed char arrayvalue_get_external_typecode (unsigned short, unsigned short);
+signed char etch_classid_to_arraytype (const unsigned short class_id);
+unsigned short etch_arraytype_to_classid (const signed char typecode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHARRAYVAL_H */
diff --git a/binding-c/runtime/c/include/etch_binary_tdi.h b/binding-c/runtime/c/include/etch_binary_tdi.h
new file mode 100644
index 0000000..09c30cc
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_binary_tdi.h
@@ -0,0 +1,138 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_binary_tdi.h
+ * binary tagged data input
+ */
+
+#ifndef ETCH_BINARY_TDI_H
+#define ETCH_BINARY_TDI_H
+
+#include "etch_tagged_data.h"
+#include "etch_tagdata_inp.h"
+#include "etch_flexbuffer.h"
+#include "etch_value_factory.h"
+
+#if(0)
+
+ BINARY_TAGGED_DATA_INPUT
+ value_factory vf;
+ ctor(valuefactory);
+
+     BINARY_TAGGED_DATA
+     bool  (*check_value)(object value, validator v);
+     byte  (*adjust_small_value)(byte type, object value);   
+     byte  (*check_value)(object value);
+     byte  (*get_native_type_code)(class*);
+     byte  (*get_custom_struct_type)(class*);
+     class*(*get_native_type)(byte type);
+     byte  (*check_byte)  (byte  v, byte is1, byte dt);
+     byte  (*check_short) (short v, byte is2, byte dt);
+     byte  (*check_int)   (int   v, byte is4, byte dt);
+     byte  (*check_long)  (long  v, byte is8, byte dt);
+
+        TAGGED_DATA
+        array_value* (*to_array_value) (object value);
+        object* (*from_array_value) (object value);
+        object* (*alloc_array_value)(byte type, Type custtructtype, int dim, int len);
+        class*  (*get_component_type)(byte type, Type custtructtype, int dim);
+        byte    (*check_value) (object value);
+        byte    (*get_native_typecode) (class* c);
+        byte    (*get_custom_struct_type)(class*);
+        class*  (*get_native_type)(byte type);
+
+    TAGGED_DATA_INPUT
+    etch_message* (*start_message) (tagged_data_input*);  
+    etch_message* (*end_message) (tagged_data_input*, etch_message*);
+    etch_structvalue* (*start_struct) (tagged_data_input*);
+    int (*read_struct_element) (tagged_data_input*, struct etch_struct_element*);
+    int (*end_struct) (tagged_data_input*, etch_structvalue*);
+    etch_arrayvalue* (*start_array) (tagged_data_input*);
+    int (*read_array_element) (tagged_data_input*, ETCH_ARRAY_ELEMENT**);
+    int (*end_array) (tagged_data_input*, etch_arrayvalue*);
+
+#endif
+
+
+/** 
+ *  i_binary_tdi: vtable for binary tagged data input interface
+ */
+struct i_binary_tdi
+{
+    etch_object object;
+
+    etchparentinfo* inherits_from;
+
+    /* i_tagdata_input */
+	etchtdi_start_message         start_message;
+    etchtdi_read_message          read_message;
+	etchtdi_end_message           end_message;
+	etchtdi_start_struct          start_struct;
+    etchtdi_read_struct           read_struct;
+    etchtdi_end_struct            end_struct;
+    etchtdi_start_array           start_array;
+    etchtdi_read_array            read_array;
+    etchtdi_end_array             end_array;
+
+    tagdata_get_native_type_code  get_native_type_code;
+    tagdata_get_native_type       get_native_type;
+    tagdata_get_custom_structtype get_custom_structtype;
+    tagdata_check_value check_value;	
+};
+
+typedef struct i_binary_tdi i_binary_tdi;
+
+
+/**
+ * binary_tagged_data_input
+ * binary tagged data input implementation
+ */
+typedef struct binary_tagged_data_input
+{
+    etch_object object;
+
+    etch_object* impl;  /* must appear first to mask tagged_data_input */
+
+    etch_value_factory*  vf;     /* not owned */
+    etch_flexbuffer* flexbuf;    /* not owned */
+    etch_validator*  vtor_int;   /* not owned */
+    etch_object* static_nullobj;         /* owned */
+    etch_object* static_eodmarker;       /* owned */
+    etch_string* static_emptystring; /* owned */
+
+} binary_tagged_data_input;
+
+
+ binary_tagged_data_input* new_binary_tagdata_input(etch_value_factory*);
+ tagged_data_input*        new_binary_tdi(etch_value_factory*);
+
+struct etch_message* bintdi_read_message(tagged_data_input* tdix, 
+    etch_flexbuffer* fbuf);
+
+struct etch_message* bintdi_read_message_fromf(etch_value_factory* vf, 
+    etch_flexbuffer* fbuf);
+
+struct etch_message* bintdi_read_message_from(etch_value_factory* vf, byte* buf, 
+    const int bufsize);
+
+struct etch_message* bintdi_read_message_fromo(etch_value_factory* vf, byte* buf, 
+    const int bufsize, const int msglen, const int offset);
+
+
+#endif /* #ifndef ETCH_BINARY_TDI_H */
diff --git a/binding-c/runtime/c/include/etch_binary_tdo.h b/binding-c/runtime/c/include/etch_binary_tdo.h
new file mode 100644
index 0000000..4425b88
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_binary_tdo.h
@@ -0,0 +1,98 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_binary_tdo.h
+ * binary tagged data output
+ */
+
+#ifndef ETCH_BINARY_TDO_H
+#define ETCH_BINARY_TDO_H
+
+#include "etch_tagdata_out.h"
+#include "etch_flexbuffer.h"
+#include "etch_message.h"
+#include "etch_value_factory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct etch_arrayvalue;
+
+/** 
+ *  i_binary_tdo: vtable for binary tagged data output interface
+ */
+typedef struct i_binary_tdo
+{
+    etch_object object;
+
+    etchparentinfo* inherits_from; 
+
+    /* i_tagdata_output */
+	etchtdo_start_message         start_message;
+    etchtdo_write_message         write_message;
+	etchtdo_end_message           end_message;
+	etchtdo_start_struct          start_struct;
+    etchtdo_write_struct          write_struct;
+    etchtdo_end_struct            end_struct;
+    etchtdo_start_array           start_array;
+    etchtdo_write_array           write_array;
+    etchtdo_end_array             end_array;
+
+    tagdata_get_native_type_code  get_native_type_code;
+    tagdata_get_native_type       get_native_type;
+    tagdata_get_custom_structtype get_custom_structtype;
+    tagdata_check_value check_value;	
+} i_binary_tdo;
+
+/**
+ * binary_tagged_data_output
+ * binary tagged data input implementation
+ */
+typedef struct binary_tagged_data_output
+{
+    etch_object object;
+
+    etch_object* impl;  /* must appear first to mask tagged_data_output */
+
+    etch_value_factory*  vf;      /* not owned */
+    etch_flexbuffer* flexbuf; /* usually owned */
+    unsigned char is_flexbuf_owned;
+
+    etch_validator*  vtor_int;    /* not owned */
+    etch_validator*  vtor_eod;    /* not owned */
+    etch_object* static_nullobj;          /* owned */
+    etch_object* static_eodmarker;        /* owned */
+    etch_string* static_emptystring;  /* owned */
+
+} binary_tagged_data_output;
+
+binary_tagged_data_output* new_binary_tagdata_output(etch_value_factory*, etch_flexbuffer*); 
+tagged_data_output*        new_binary_tdo(etch_value_factory*);
+
+int bintdo_get_bytes (etch_message*, etch_value_factory*, byte** out);
+int bintdo_write_value (binary_tagged_data_output*, etch_validator*, etch_object*);
+struct etch_arrayvalue* bintdo_to_arrayvalue (binary_tagged_data_output* tdo, struct etch_nativearray*);
+struct etch_arrayvalue* normalize_etch_array(void* a, const int maxdim);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* #ifndef ETCH_BINARY_TDO_H */
diff --git a/binding-c/runtime/c/include/etch_cache.h b/binding-c/runtime/c/include/etch_cache.h
new file mode 100644
index 0000000..c477b21
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_cache.h
@@ -0,0 +1,91 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_cache.h -- etch caching
+ */
+
+#ifndef _ETCH_CACHE_H_
+#define _ETCH_CACHE_H_
+
+#include "etch.h"
+#include "etch_runtime.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*etch_cache_freehook_func)(void*, void*);
+
+// etch_cache type
+typedef struct etch_hashtable etch_cache_t;
+
+/**
+ * create a new cache instance.
+ */
+etch_status_t etch_cache_create();
+
+/**
+ * set freehook for cache values.
+ */
+etch_status_t etch_cache_set_freehook(etch_cache_freehook_func freehook);
+
+/**
+ * locate cached object with specified key, returning it or NULL
+ * @param typ specified key
+ * @param out   TODO: doc
+ * @return      TODO: doc
+ */
+void* etch_cache_find(const unsigned int typ, void** out);
+
+/**
+ * Remove specified object from cache given integer key.
+ * @param typ specified key
+ * @return pointer to cached object, which is not freed here.
+ */
+void* etch_cache_del(const unsigned int typ);
+
+/**
+ * Add specified object to cache given integer key.
+ * @param typ specified key
+ * @return return 0 or -1.
+ */
+int etch_cache_add(const unsigned int typ, void* data);
+
+/**
+ * Add specified object to cache with existence test optional.
+ * @param typ   TODO: doc
+ * @param data      TODO: doc
+ * @param is_check  TODO: doc
+ * @return inserted item hash, or zero.
+ */
+int etch_cache_insert(const unsigned int typ, void* data, const int is_check);
+
+
+/**
+ * clear the cache and destroy the cache object
+ * @return      TODO: doc
+ */
+int etch_cache_destroy();
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ETCH_CACHE_H_ */
diff --git a/binding-c/runtime/c/include/etch_collection.h b/binding-c/runtime/c/include/etch_collection.h
new file mode 100644
index 0000000..dd3a252
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_collection.h
@@ -0,0 +1,122 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_collection.h 
+ * definitions common to collections
+ */
+
+#ifndef ETCHCOLLECTION_H
+#define ETCHCOLLECTION_H
+
+#include "etch.h"
+#include "etch_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_SYNC_SET 1
+#define ETCH_SYNC_TRY 2
+#define ETCH_SYNC_REL 3
+#define ETCH_SYNC_DEL 4
+
+#define ETCH_SYNC_SET_ ((void*) ETCH_SYNC_SET)
+#define ETCH_SYNC_TRY_ ((void*) ETCH_SYNC_TRY)
+#define ETCH_SYNC_REL_ ((void*) ETCH_SYNC_REL)
+#define ETCH_SYNC_DEL_ ((void*) ETCH_SYNC_DEL)
+
+struct i_iterable;
+struct etch_iterator;
+
+/** 
+ *  method signatures for i_iterable interface.
+ *  each accepts an iterator object as first parameter. the iterator constructor
+ *  should call first(), thus establishing a current position. next() should operate 
+ *  as first() if there is no current position.
+ */
+typedef int (*iterable_first)    (struct etch_iterator*); 
+typedef int (*iterable_next)     (struct etch_iterator*); 
+typedef int (*iterable_has_next) (struct etch_iterator*); 
+
+/** 
+ *  etch_iterator: iterator object for any i_iterable.
+ */
+typedef struct etch_iterator
+{
+    etch_object object;
+
+    iterable_first    first;
+    iterable_next     next;
+    iterable_has_next has_next;
+
+    int   ordinal;       /* 1-based position index */
+    void* collection;    /* underlying collection */
+    void* current_value; /* data at current posn */
+    void* current_key;   /* key at current posn */
+    unsigned char   is_own_collection;
+} etch_iterator;
+
+
+
+/** 
+ *  i_iterable: vtable for iterable interface
+ */
+struct i_iterable
+{
+    etch_object object;
+
+    etchparentinfo* inherits_from; 
+
+    iterable_first    first;    /* set current position at first entry  */
+    iterable_next     next;     /* set current position at next entry  */ 
+    iterable_has_next has_next; /* return TRUE if next will succeed */
+};
+
+typedef struct i_iterable i_iterable;
+
+
+/** 
+ *  new_iterable
+ *  constructor for i_iterable interface
+ */
+i_iterable* new_iterable(i_iterable* thisp, i_iterable* parent, 
+    iterable_first, iterable_next, iterable_has_next);
+
+/** 
+ *  new_iterator(), set_iterator(), destroy_iterator
+ *  constructors and destructors for etch_iterator
+ */
+etch_iterator* new_iterator(void* collection, i_iterable* iterable);
+
+int set_iterator(etch_iterator* thisp, void* collection, i_iterable* iterable);
+
+/* should be static! call via vtable */
+int destroy_iterator(void*);
+
+etch_iterator* new_empty_iterator();
+
+
+int etch_comparator_noteq(void* a, void* b);
+int etch_comparator_equal(void* a, void* b);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHCOLLECTION_H */
diff --git a/binding-c/runtime/c/include/etch_config.h b/binding-c/runtime/c/include/etch_config.h
new file mode 100644
index 0000000..dd13855
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_config.h
@@ -0,0 +1,124 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */
+
+/* 
+ * etch_config.h -- configuration items and file
+ */
+ 
+#ifndef _ETCH_CONFIG_H_
+#define _ETCH_CONFIG_H_
+
+#include "etch_errno.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct etch_config_t etch_config_t;
+
+/**
+ * create a new configuration.
+ * default config properties:
+ * TODO: document default properties
+ * @param config that will be created.
+ */
+etch_status_t etch_config_create(etch_config_t** config);
+
+/**
+ * reads the given config file.
+ * @config handle.
+ * @param config configuration handle.
+ * @param filepath to the file which holds the configuration.
+ */
+etch_status_t etch_config_open(etch_config_t* config, const char* filepath);
+
+/**
+ * sets a new property value
+ * @config handle.
+ * @name of the property.
+ * @value of the property.
+ */
+etch_status_t etch_config_set_property(etch_config_t* config, const char* name, const char* value);
+
+/**
+ * check if property with name existis.
+ * @config handle.
+ * @param name of the property.
+ * @return true if exists, else false.
+ */
+int etch_config_has_property(etch_config_t* config, const char* name);
+
+/**
+ * get the string property by name.
+ * @config handle.
+ * @name of the property.
+ * @value char** where the value will be written
+ * @return etch_status ETCH_SUCCESS or ETCH_EINVAL
+ */
+etch_status_t etch_config_get_property_string(etch_config_t* config, const char* name, char** value);
+
+/**
+ * get the int32 property by name.
+ * @config handle.
+ * @name of the property.
+ * @value where the value will be written
+ * @return etch_status ETCH_SUCCESS or ETCH_EINVAL
+ */
+etch_status_t etch_config_get_property_int(etch_config_t* config, const char* name, int32* value);
+
+/**
+ * gets the property by index.
+ * @config handle.
+ * @name of the property.
+ * @value char** where the value will be written; the value has to be freed with etch_free after use.
+ * @return etch_status ETCH_SUCCESS or ETCH_EINVAL
+ */
+etch_status_t etch_config_get_property_by_index(etch_config_t* config, uint16 index, char** value);
+
+/**
+ * clear the property list.
+ * @config handle.
+ * @return etch_status_t
+ */
+etch_status_t etch_config_clear(etch_config_t* config);
+
+/**
+ * gets the length of the property list.
+ * @config handle.
+ * @return length
+ */
+uint16 etch_config_get_length(etch_config_t* config);
+
+/**
+ * gets the size of the property list.
+ * @config handle.
+ * @return length
+ */
+uint16 etch_config_get_size(etch_config_t* config);
+
+/**
+ * destroy the configure instance.
+ * @config handle.
+ */
+etch_status_t etch_config_destroy(etch_config_t* config);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ETCH_CONFIG_H_ */
diff --git a/binding-c/runtime/c/include/etch_connection.h b/binding-c/runtime/c/include/etch_connection.h
new file mode 100644
index 0000000..4e1a9ff
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_connection.h
@@ -0,0 +1,172 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_connection.h
+ * connection client and server classes - tcp, udp
+ */
+
+#ifndef ETCHCONNECTION_H
+#define ETCHCONNECTION_H
+
+#include "apr_thread_proc.h"
+#include <apr_network_io.h>
+#include <apr_thread_mutex.h>
+#include <apr_thread_cond.h>
+#include "etch_transport_data.h"
+#include "etch_transportint.h"
+#include "etch_sessionint.h"
+#include "etch_thread.h"
+#include "etch_mutex.h"
+#include "etch_wait.h"
+#include "etch_url.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef apr_socket_t etch_rawsocket;
+ 
+typedef int (*etch_set_socket_options) (void* conxn);
+typedef int (*etch_connection_event_handler) (void* conxn, const int, int, void*);
+
+int  etch_defconx_on_event(void* conxn, const int, int, void*);
+int  etch_defconx_on_data (void* conxn, const int, int, void*);
+
+#define IS_ETCH_SOCKET_TIMEOUT(n) (APR_TIMEUP == n || 730060 == n)
+#define ETCH_CONX_DEFAULT_BUFSIZE (1024 * 32)
+#define ETCH_CONX_NO_LINGER  FALSE
+#define ETCH_CONX_USE_LINGER TRUE
+#define ETCH_CONX_NOT_RECONNECTING FALSE
+#define ETCH_CONX_IS_RECONNECTING  TRUE
+#define ETCH_THIS_END_CLOSED   (-2)
+#define ETCH_OTHER_END_CLOSED  (-3)
+#define ETCH_SHUTDOWN_NOTIFIED (-4)
+#define APR_THIS_END_CLOSED  730053
+#define APR_OTHER_END_CLOSED 730054
+
+
+/*
+ * etch_connection  
+ * abstract base class, never instantiated so not an object
+ */
+typedef struct etch_connection
+{
+    unsigned        sig;
+    unsigned        conxid;
+    void*           owner;
+    apr_socket_t*   socket;
+    apr_sockaddr_t* sockdata;
+    apr_pool_t*     aprpool;  
+    etch_mutex*      mutex;
+    unsigned        bufsize;
+    etch_object*    listener;
+    etch_thread*    thread;
+    unsigned char   is_ownpool;
+    unsigned char   is_started;
+    unsigned char   is_closing;
+    unsigned char   unused;
+
+    etch_wait_t* wait_up;      /* wait object - owned */
+    etch_wait_t* wait_down;    /* wait object - owned */
+    etch_object*  session;   /* session data - not owned */
+    char*     hostname;  /* ansi string - owned */
+    int64     waitcond;  /* up/down wait condition */
+    int       port;
+    int       delay;
+ 
+    etch_connection_event_handler  on_data;
+    etch_connection_event_handler  on_event;
+    etch_set_socket_options  set_socket_options;
+
+} etch_connection;
+
+
+
+#define ETCH_DEFAULT_SOCKET_FAMILY  APR_INET
+extern unsigned connection_id_farm;
+
+#define ETCH_CONNECTION_DEFLINGERTIME 30
+#define ETCH_CONNECTION_DEFNODELAY  TRUE
+#define ETCH_CONNECTION_DEFRETRYATTEMPTS 0
+#define ETCH_CONNECTION_DEFRETRYDELAYMS  1000
+
+extern const wchar_t* ETCH_CONNECTION_RECONDELAY;
+extern const wchar_t* ETCH_CONNECTION_AUTOFLUSH;
+extern const wchar_t* ETCH_CONNECTION_KEEPALIVE;
+extern const wchar_t* ETCH_CONNECTION_LINGERTIME;
+extern const wchar_t* ETCH_CONNECTION_NODELAY;
+extern const wchar_t* ETCH_CONNECTION_TRAFCLASS;
+extern const wchar_t* ETCH_CONNECTION_BUFSIZE;
+extern const wchar_t* ETCH_TCPLISTENER_BACKLOG;
+
+#define ETCH_CONXEVT_CREATED            0x1
+#define ETCH_CONXEVT_CREATERR           0x2
+#define ETCH_CONXEVT_SHUTDOWN           0x3
+#define ETCH_CONXEVT_DATA               0x4
+#define ETCH_CONXEVT_RECEIVING          0x5
+#define ETCH_CONXEVT_RECEIVETIMEOUT     0x6
+#define ETCH_CONXEVT_RECEIVERR          0x7
+#define ETCH_CONXEVT_RECEIVED           0x8
+#define ETCH_CONXEVT_RECEIVEND          0x9
+#define ETCH_CONXEVT_SENDING            0xa
+#define ETCH_CONXEVT_SENDTIMEOUT        0xb
+#define ETCH_CONXEVT_SENDERR            0xc
+#define ETCH_CONXEVT_SENT               0xd
+#define ETCH_CONXEVT_SENDEND            0xe
+#define ETCH_CONXEVT_CONXCLOSED         0xf
+#define ETCH_CONXEVT_PEERCLOSED         0x10
+#define ETCH_CONXEVT_OPENING            0x11
+#define ETCH_CONXEVT_OPENERR            0x12
+#define ETCH_CONXEVT_OPENED             0x13
+#define ETCH_CONXEVT_STARTING           0x14
+#define ETCH_CONXEVT_STARTERR           0x15
+#define ETCH_CONXEVT_STARTED            0x16 
+#define ETCH_CONXEVT_ACCEPTPUMPEXIT     0x1e    
+#define ETCH_CONXEVT_ACCEPTPUMPEXITERR  0x1f  
+#define ETCH_CONXEVT_RCVPUMP_START      0x20
+#define ETCH_CONXEVT_RCVPUMP_RECEIVING  0x21
+#define ETCH_CONXEVT_RCVPUMP_ERR        0x22
+#define ETCH_CONXEVT_RCVPUMP_STOP       0x23
+#define ETCH_CONXEVT_ACCEPTING          0x25 
+#define ETCH_CONXEVT_ACCEPTERR          0x26 
+#define ETCH_CONXEVT_ACCEPTED           0x27 
+#define ETCH_CONXEVT_LISTENED           0x28 
+#define ETCH_CONXEVT_UP                 0x2a 
+#define ETCH_CONXEVT_DOWN               0x2b
+#define ETCH_CONXEVT_SOCKOPTERR         0x2f
+#define ETCH_CONXEVT_STOPPING           0x30
+#define ETCH_CONXEVT_STOPERR            0x31
+#define ETCH_CONXEVT_STOPPED            0x32
+#define ETCH_CONXEVT_CLOSING            0x33
+#define ETCH_CONXEVT_CLOSERR            0x34
+#define ETCH_CONXEVT_CLOSED             0x35 
+#define ETCH_CONXEVT_DESTRUCTOR         0x3a 
+#define ETCH_CONXEVT_DESTROYING         0x3b 
+#define ETCH_CONXEVT_DESTROYED          0x3c
+
+int etch_init_connection(etch_connection*, etch_rawsocket*, void* owner);
+int etch_destroy_connection(etch_connection*);
+int etchconx_wait_up  (etch_connection*, int timeoutms);
+int etchconx_wait_down(etch_connection*, int timeoutms);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* ETCHCONNECTION_H */
diff --git a/binding-c/runtime/c/include/etch_default_value_factory.h b/binding-c/runtime/c/include/etch_default_value_factory.h
new file mode 100644
index 0000000..aa5cc9a
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_default_value_factory.h
@@ -0,0 +1,142 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_defvalufact.h
+ * default implementation of value factory
+ */
+
+#ifndef ETCH_DEFVALUFACT_H
+#define ETCH_DEFVALUFACT_H
+
+#include "etch_message.h"
+#include "etch_exception.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_DEFVF_IDNMAP_DEFINITSIZE 64
+#define ETCH_DEVVF_C2TMAP_DEFINITSIZE 16
+#define ETCH_DEVVF_MIXINS_DEFINITSIZE 4
+
+typedef etch_hashtable vf_idname_map;
+typedef etch_hashtable class_to_type_map;
+
+
+/**
+ * default_value_factory
+ * value factory base implementation.
+ */
+typedef struct default_value_factory
+{
+    etch_object object;
+
+    etch_object* impl;
+
+    class_to_type_map* class_to_type;
+    vf_idname_map*  types;
+    etch_arraylist* mixins;
+  
+    unsigned char is_own_types;
+    unsigned char is_own_class_to_type;
+	
+} default_value_factory;
+
+
+default_value_factory* new_default_value_factory(vf_idname_map* typemap, class_to_type_map* c2tmap);
+default_value_factory* new_default_value_factory_ex(const int objsize, vf_idname_map* typemap, class_to_type_map* c2tmap);
+
+/**
+ * defvf_statics
+ */
+typedef struct defvf_statics
+{
+    etch_type* _mt__etch_runtime_exception;
+	etch_type* _mt__etch_auth_exception; 
+	etch_type* _mt__exception;
+	etch_type* _mt__etch_list;
+	etch_type* _mt__etch_map;
+	etch_type* _mt__etch_set;
+	etch_type* _mt__etch_datetime;
+	
+	etch_field* _mf_msg;
+	etch_field* _mf__message_id;
+	etch_field* _mf__in_reply_to;
+	etch_field* _mf_result;
+
+} defvf_statics;
+
+
+/* 
+ * built-in (etch-global, quasi-static) objects.
+ * these singleton objects are global to all vfs, instantiated with the 
+ * initial vf, and destroyed at etch teardown.
+ */
+extern defvf_statics  builtins;
+extern unsigned char  is_builtins_instantiated;
+
+extern const wchar_t* str_etch_runtime_exception;
+extern const wchar_t* str_etch_auth_exception;        
+extern const wchar_t* str_exception; 
+extern const wchar_t* str_etch_list; 
+extern const wchar_t* str_etch_map;
+extern const wchar_t* str_etch_set;
+extern const wchar_t* str_etch_datetime; 
+
+extern const wchar_t* str_msg;
+extern const wchar_t* str_message_id; 
+extern const wchar_t* str_in_reply_to; 
+extern const wchar_t* str_result; 
+
+extern const wchar_t* str_utf8; 
+extern const wchar_t* str_keys; 
+extern const wchar_t* str_values;  
+extern const wchar_t* str_date_time;
+extern const wchar_t* str_keys_values;
+
+extern const wchar_t* str_msgizervf;
+extern const wchar_t* str_msgizerfmt;
+
+/* 
+ * etchvf_free_builtins()
+ * frees memory for etch-global quasi-static builtin objects,
+ * and for the validators cache and its validator content.
+ * it should be invoked at etch teardown, after last vf is destroyed.
+ * unit tests will show memory leaks unless they invoke this after test.
+ */
+void etchvf_free_builtins();
+
+int destroy_default_value_factory(void* data);
+int defvf_initialize_static(vf_idname_map* typemap, class_to_type_map*  c2tmap);
+etch_type* etchtypemap_get_by_name(etch_hashtable*, const wchar_t* name);
+int defvf_add_mixin(default_value_factory*, etch_value_factory* mixedin_vf);
+int get_etch_string_encoding(etch_value_factory*);
+int etchtypelist_comparator(void* a, void* b);
+unsigned message_get_id32 (etch_message*);
+class_to_type_map* new_class_to_type_map(const int initialsize);
+etch_set* new_vf_types_collection(const int initialsize);
+vf_idname_map* new_vf_idname_map(const int initialsize);
+int class_to_type_map_put(class_to_type_map*, const unsigned, etch_type*); 
+etch_type* class_to_type_map_get(class_to_type_map*, const unsigned);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_DEFVALUFACT_H */
diff --git a/binding-c/runtime/c/include/etch_encoding.h b/binding-c/runtime/c/include/etch_encoding.h
new file mode 100644
index 0000000..2a5eb16
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_encoding.h
@@ -0,0 +1,56 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_encoding.h -- character encoding
+ */
+
+#ifndef _ETCH_ENCODING_H_
+#define _ETCH_ENCODING_H_
+
+#include "etch.h"
+#include "etch_mem.h"
+#include "etch_errno.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+etch_status_t etch_encoding_initialize();    
+
+etch_status_t etch_encoding_shutdown();
+
+/**
+ * transcode a bytestream from encoding inEncoding to outEncoding
+ * @param out must be freed by the caller via etch_free
+ */
+int etch_encoding_transcode(char** out, unsigned char outEncoding, const char* in, unsigned char inEncoding, unsigned int inByteCount, int* outByteCount, etch_pool_t* pool);
+
+int etch_encoding_transcode_wchar(char** out, unsigned char outEncoding, const wchar_t* in, etch_pool_t* pool);
+
+int etch_encoding_transcode_to_wchar(wchar_t** out, const void* in, unsigned char inEncoding, unsigned int inByteCount, etch_pool_t* pool);
+
+unsigned char etch_encoding_for_wchar();
+
+unsigned int etch_encoding_get_sizeof_terminator(unsigned char encoding);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_ENCODING_H */
diff --git a/binding-c/runtime/c/include/etch_errno.h b/binding-c/runtime/c/include/etch_errno.h
new file mode 100644
index 0000000..1d6ada5
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_errno.h
@@ -0,0 +1,64 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_errno.h -- error number file
+ */
+
+#include "etch.h"
+
+#ifndef _ETCH_ERRNO_H_
+#define _ETCH_ERRNO_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Type for specifying an error or status code.
+ */
+typedef int etch_status_t;
+
+/* no error */
+#define ETCH_SUCCESS        0
+/* error */
+#define ETCH_ERROR          1
+/* invalid argument error */
+#define ETCH_EINVAL         2
+/* function not implemented */
+#define ETCH_ENOTIMPL       3
+/* not memory */
+#define ETCH_ENOMEM         4
+/* invalid state */
+#define ETCH_EINVALSTATE    5
+/* invalid state */
+#define ETCH_EFILENOTFOUND  6
+/* busy state */
+#define ETCH_EBUSY          7
+/* timeout */
+#define ETCH_ETIMEOUT       8
+/* index out of bound */
+#define ETCH_EOUTOFBOUNDS   9
+/* IO Error */
+#define ETCH_EIO             10
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* _ETCH_GENERAL_H_ */
diff --git a/binding-c/runtime/c/include/etch_exception.h b/binding-c/runtime/c/include/etch_exception.h
new file mode 100644
index 0000000..2c99b0a
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_exception.h
@@ -0,0 +1,72 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_exception.h -- etch exception
+ */
+
+#ifndef ETCHEXCP_H
+#define ETCHEXCP_H
+
+#include "etch_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * create a new etch exception
+ */
+etch_exception* new_etch_exception(const excptype_t type);
+
+
+/**
+ * create a new builtin etch exception with errorcode
+ */
+etch_exception* new_etch_exception_from_errorcode(int errorcode);
+
+/**
+ * set message of the exception
+ */
+void etch_exception_set_message(etch_exception* ex, etch_string* mess);
+
+/**
+ * get message of the exception
+ */
+etch_string* etch_exception_get_message(etch_exception* ex);
+
+/**
+ * get exception type
+ */
+etch_status_t etch_exception_get_type(etch_exception* exception, excptype_t* type);
+
+/**
+ * error code of this exception
+ */
+uint32 etch_exception_get_errorcode(etch_exception* ex);
+
+/**
+ * destroy exception
+ */
+int destroy_etch_exception(void* excp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHEXCP_H */
diff --git a/binding-c/runtime/c/include/etch_field.h b/binding-c/runtime/c/include/etch_field.h
new file mode 100644
index 0000000..5d0c5e5
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_field.h
@@ -0,0 +1,56 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_field.h -- defines the etch_field object.
+ * An etch_field is an etch_id_name representing a field of a struct or message 
+ * (i.e. a key for a value).
+ */
+
+#ifndef ETCHFIELD_H
+#define ETCHFIELD_H
+
+#include "etch_id_name.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** 
+ * etch_field
+ * We're simply typef'ing this for now, but we've left it open to later define
+ * an etch_field struct having an etch_id_name as a member.
+ */
+typedef etch_id_name etch_field;
+
+etch_field* new_field(const wchar_t* name);
+etch_field* new_static_field(const wchar_t* name);
+int destroy_static_field(etch_field*);
+
+#define clone_field      clone_id_name
+#define destroy_field    destroy_id_name
+#define is_good_field    is_good_id_name
+#define is_equal_fields  is_equal_id_names
+#define compute_field_id compute_id_name_id
+#define compute_field_id_from_widename compute_id_name_id_from_widename
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHFIELD_H */ 
diff --git a/binding-c/runtime/c/include/etch_flexbuffer.h b/binding-c/runtime/c/include/etch_flexbuffer.h
new file mode 100644
index 0000000..1e9ccf4
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_flexbuffer.h
@@ -0,0 +1,97 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * a flex_buffer wraps a byte array and manages the active region of
+ * it (0..length). it supports dynamically extending the buffer.
+ * 
+ * a flexbuffer has an index (read or write cursor). the various get
+ * and put operations always occur at the current index, with the index
+ * adjusted appropriately afterward. get() will not move the index past
+ * length. if put needs to move index past length, length is also
+ * adjusted. this may cause the byte array to be re-allocated.
+ */
+
+#ifndef ETCH_FLEX_BUFFER_H
+#define ETCH_FLEX_BUFFER_H
+
+#include "etch_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_FLEXBUF_PUT_ALL (-1)
+
+
+typedef struct etch_flexbuffer
+{
+    etch_object object;
+
+    unsigned char *buf;
+    size_t bufsize; /* buffer size */
+    size_t datalen; /* data length */
+    size_t index;   /* current position */
+    unsigned char   is_littleendian; 
+
+} etch_flexbuffer;
+
+etch_flexbuffer *new_flexbuffer(size_t);
+etch_flexbuffer *new_flexwriter_from   (void *buf, size_t, size_t);
+etch_flexbuffer *new_flexbuffer_from   (void *buf, size_t, size_t, size_t);
+etch_flexbuffer *etch_flexbuf_create_b (void *buf, size_t, size_t);
+etch_flexbuffer *etch_flexbuf_create_bi(void *buf, size_t, size_t, size_t);
+etch_flexbuffer *etch_flexbuf_skip     (etch_flexbuffer*,  size_t, int);
+
+byte*   etch_flexbuf_get_buffer(etch_flexbuffer*);
+int     destroy_etch_flexbuffer(void*);
+int     etch_flexbuf_set_length(etch_flexbuffer*, size_t);
+int     etch_flexbuf_set_index (etch_flexbuffer*, size_t);
+void    etch_flexbuf_clear     (etch_flexbuffer*);
+size_t  etch_flexbuf_avail     (etch_flexbuffer*);
+int     etch_flexbuffer_reset_to     (etch_flexbuffer*, size_t);
+etch_flexbuffer *etch_flexbuf_compact(etch_flexbuffer*);
+etch_flexbuffer *etch_flexbuf_reset  (etch_flexbuffer*);
+
+size_t etch_flexbuf_get (etch_flexbuffer*, byte*, size_t, size_t);
+
+int    etch_flexbuf_get_byte  (etch_flexbuffer*, byte* out);
+int    etch_flexbuf_get_short (etch_flexbuffer*, short* out);
+int    etch_flexbuf_get_int   (etch_flexbuffer*, int* out);
+int    etch_flexbuf_get_long  (etch_flexbuffer*, int64* out);
+int    etch_flexbuf_get_float (etch_flexbuffer*, float* out);
+int    etch_flexbuf_get_double(etch_flexbuffer*, double* out);
+
+size_t etch_flexbuf_get_fully  (etch_flexbuffer*, byte*, size_t);
+byte*  etch_flexbuf_get_all    (etch_flexbuffer*, size_t* out_count);
+byte*  etch_flexbuf_get_allfrom(etch_flexbuffer*, size_t, size_t* out_count);
+
+size_t etch_flexbuf_put        (etch_flexbuffer*, byte*, size_t, size_t);
+size_t etch_flexbuf_put_from   (etch_flexbuffer*, etch_flexbuffer*, size_t);
+size_t etch_flexbuf_put_byte   (etch_flexbuffer*, byte   value);
+size_t etch_flexbuf_put_short  (etch_flexbuffer*, short  value);
+size_t etch_flexbuf_put_int    (etch_flexbuffer*, int    value);
+size_t etch_flexbuf_put_long   (etch_flexbuffer*, int64  value);
+size_t etch_flexbuf_put_float  (etch_flexbuffer*, float  value);
+size_t etch_flexbuf_put_double (etch_flexbuffer*, double value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCH_FLEX_BUFFER_H */
diff --git a/binding-c/runtime/c/include/etch_general.h b/binding-c/runtime/c/include/etch_general.h
new file mode 100644
index 0000000..b457025
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_general.h
@@ -0,0 +1,72 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_general.h -- general file
+ */
+
+#ifndef _ETCH_GENERAL_H_
+#define _ETCH_GENERAL_H_
+
+#include "etch.h"
+#include "etch_mem.h"
+#include "etch_errno.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * get_dynamic_classid()
+ * get a class ID for objects not known to the binding,
+ * class ID sequence for generated classes.
+ */
+unsigned short get_dynamic_classid(); 
+
+/**
+ * get_dynamic_classid_unique()
+ * if specified ID already assigned, return it; otherwise generate and return. 
+ * assignment is currently non-atomic.
+ */
+unsigned short get_dynamic_classid_unique(unsigned short* globalid); 
+
+/**
+ * remove spaces and tabs on left and right side
+ * from given string.
+ * @param str to trim
+ * @return trimed string.
+ */
+char* strtrim(char* str);
+
+/**
+ * waitkey()
+ * method to wait for a keypress.
+ */
+void waitkey();
+
+int etch_snwprintf(wchar_t *buffer, size_t count, const wchar_t *format, ...);
+
+//todo: refactor this stuff
+int hexchar_to_int (const unsigned char hexchar);
+int hexwchar_to_int(const wchar_t hexwchar);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* _ETCH_GENERAL_H_ */
diff --git a/binding-c/runtime/c/include/etch_hash.h b/binding-c/runtime/c/include/etch_hash.h
new file mode 100644
index 0000000..10192c6
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_hash.h
@@ -0,0 +1,206 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_hash.h 
+ * etch hashtable 
+ */
+
+#ifndef ETCHHASH_H
+#define ETCHHASH_H
+
+#include "etch.h"
+#include "etch_mutex.h"
+#include "etch_collection.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_INITIAL_HASHTABLE_SIZE          32768
+#define MIN_INITIAL_HASHTABLE_SIZE          4
+#define ETCH_DEFAULT_HASHTABLE_SIZE         16
+#define ETCHHASHTABLE_CONTENT_OPAQUE        0
+#define ETCHHASHTABLE_CONTENT_OBJECT        1   /* opaque key */
+#define ETCHHASHTABLE_CONTENT_INT_OBJECT    2   
+#define ETCHHASHTABLE_CONTENT_LONG_OBJECT   3
+#define ETCHHASHTABLE_CONTENT_STRING_OBJECT 4
+#define ETCHHASHTABLE_CONTENT_OBJECT_OBJECT 5   /* etch_map */
+#define ETCHHASHTABLE_CONTENT_OBJECT_NONE   6   /* etch_set */
+
+#define HASHTABLE_DEFAULT_READONLY_KEYS     TRUE
+#define HASHTABLE_DEFAULT_READONLY_VALUES   TRUE
+#define HASHTABLE_DEFAULT_TRACKED_MEMORY    TRUE
+#define HASHTABLE_DEFAULT_CONTENT_TYPE      0
+
+//TODO: clean up BEGIN
+typedef int (*mapcallback) (void*, void*); /* hashtable callback signature */
+int string_to_object_clear_handler (void*, void*);
+int object_to_object_clear_handler (void*, void*);
+int etch_noop_clear_handler (void* key, void* value);
+//TODO: clean up END 
+
+/** 
+ *  etch_hashitem  
+ *  an entry in a hashtable. 
+ */
+typedef struct etch_hashitem
+{
+    char* key;
+    void* value;
+    unsigned hash;
+
+} etch_hashitem;
+
+/** 
+ * the etch C hashtable interface.
+ * all methods of this interface should have implementations (i.e. not be null).
+ */
+typedef struct i_hashtable
+{
+    etch_object object;
+
+    etchparentinfo* inherits_from; 
+
+    int (*create)  (const int size,  void* in, void** out);
+    int (*hdestroy)(void* realtable, void* in, void** out);
+    int (*insert)  (void* realtable, void* key, const int keylen, void* data, const int datalen, void* in, void** out);
+    int (*inserth) (void* realtable, void* key, void* data, void* in, void** out);
+    int (*find)    (void* realtable, void* key, const int keylen, void* in, void** out);
+    int (*findh)   (void* realtable, const unsigned key, void* in, void** out);
+    int (*first)   (void* realtable, void* in, void** out);
+    int (*next)    (void* realtable, void* in, void** out);
+    int (*current) (void* realtable, void* in, void** out);
+    int (*remove)  (void* realtable, void* key, const int keylen, void* in, void** out);
+    int (*removeh) (void* realtable, const unsigned key, void* in, void** out);
+    int (*clear)   (void* realtable, const int freekey, const int freeval, void* in, void** out);
+    int (*count)   (void* realtable, void* in, void** out);
+    int (*size)    (void* realtable, void* in, void** out);
+    int (*stats)   (void* realtable, void* in, void** out);
+    int (*hash)    (void* realtable, void* key, const int keylen, const int priorhash, void* in, void** out); 
+
+} i_etch_hashtable;
+
+/**
+ * etch_hashtable
+ * hashtable object
+ */
+typedef struct etch_hashtable
+{
+    etch_object object;
+
+    void* realtable; /* implementation's hashtable object */
+    unsigned short content_obj_type; /* todo: populate */
+    unsigned short content_class_id; /* todo: populate */
+    
+    unsigned char is_readonly_keys;
+    unsigned char is_readonly_values;
+    unsigned char is_tracked_memory;
+    unsigned char content_type;
+      
+    /* this object may be masked by etch_collection_mask to determine content
+     * type and class, so do not add any fields above this comment */
+
+    i_iterable  iterable;   /* iterable interface */
+
+    mapcallback freehook;   /* clear() callback if any */
+
+} etch_hashtable;
+
+/**
+ * create a new instance of etch_hashtable.
+ */
+etch_hashtable* new_hashtable(const unsigned int initialsize);
+
+/**
+ * create a new instance of etch_hashtable
+ * that is synchronized.
+ */
+etch_hashtable* new_hashtable_synchronized(const unsigned int initialsize);
+
+/**
+ * create a new instancec of etch_map.
+ */
+etch_hashtable* new_etch_map(const unsigned int initialsize);
+
+/**
+ * create a new instance of etch_set.
+ */
+etch_hashtable* new_etch_set(const unsigned int initialsize);
+
+/**
+ * destory the instance of etch_hashtable.
+ */
+int destroy_hashtable(etch_hashtable* hashtable, const int is_free_k, const int is_free_v);
+
+/* 
+ * explicit synchronization locking methods.
+ * these should be used only for locking a map during map iteration.   
+ * for synchronization of map operations, the presence of map.synchook  
+ * and map.synclock is sufficient. 
+ */
+int   hashtable_getlock (etch_hashtable*);
+int   hashtable_trylock (etch_hashtable*);
+int   hashtable_rellock (etch_hashtable*);
+
+//int   hashtable_defsynchook(void* action, void* mutex);
+
+/* i_iterable function overrides */
+int   hashtable_iterable_first   (etch_iterator*);
+int   hashtable_iterable_next    (etch_iterator*);
+int   hashtable_iterable_has_next(etch_iterator*);
+
+//TODO: cleanup
+
+typedef etch_hashtable etch_set;
+etch_set* new_set(const int initialsize);
+
+#define is_etch_set(x) (x && (((etch_object*)x)->obj_type == ETCHTYPEB_HASHTABLE) \
+ && (((etch_hashtable*)x)->content_type == ETCHHASHTABLE_CONTENT_OBJECT_NONE))
+
+int jenkins_insert (void* realtable, void* key, const int keylen, void* data, const int datalen, void* in, void** out);
+int jenkins_inserth(void* realtable, void* key, void* data, void* in, void** out);
+int jenkins_find   (void* realtable, void* key, const int keylen, void* in, void** out);
+int jenkins_findh  (void* realtable, const unsigned int hashed, void* in, void** out);
+int jenkins_first  (void* realtable, void* in, void** out);
+int jenkins_next   (void* realtable, void* in, void** out);
+int jenkins_current(void* realtable, void* in, void** out);
+int jenkins_remove (void* realtable, void* key, const int keylen, void* in, void** out);
+int jenkins_clear  (void* realtable, const int freekey, const int freeval, void* in, void** out);
+int jenkins_count  (void* realtable, void* in, void** out);
+int jenkins_size   (void* realtable, void* in, void** out); 
+int jenkins_stats  (void* realtable, void* in, void** out);
+int jenkins_hash   (void* realtable, char* key, const int keylen, const int priorhash, void* in, void** out);
+int jenkins_hashx  (char* key, const int keylen, const int priorhash);  
+int jenkins_destroy(void* realtable, void* in, void** out); 
+int jenkins_create (const int initialsize_items, void* in, void** out);
+etch_hashtable* ctor_jenkins_hashtable(const int initialsize_bits);
+etch_hashtable* new_systemhashtable   (const int initialsize_items);
+void delete_systemhashtable(etch_hashtable*);
+
+
+struct etch_hashtable;
+
+struct etch_arraylist* get_map_keys(struct etch_hashtable*);
+struct etch_arraylist* get_map_values(struct etch_hashtable*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHHASH_H */
diff --git a/binding-c/runtime/c/include/etch_id_name.h b/binding-c/runtime/c/include/etch_id_name.h
new file mode 100644
index 0000000..f3a0d71
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_id_name.h
@@ -0,0 +1,68 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_id_name.h 
+ * etch_id_name is base class for etch_field and etch_type. it binds
+ * together a type or field name with its associated id. The id is used
+ * for certain operations, such as the key in a map, comparisons, and
+ * binary encoding on the wire.  
+*/
+
+#ifndef ETCHIDNAME_H
+#define ETCHIDNAME_H
+
+#include "etch.h"
+#include "etch_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * etch_id_name
+ */
+struct etch_id_name
+{
+    etch_object object;
+
+    etch_object*    impl; /* extension of id_name, if any */      
+
+	unsigned id;          /* wire ID, not a hashmap key */
+    size_t   namebytelen; /* byte length including terminator */
+    wchar_t* name;        /* owned */
+    char*    aname;       /* owned - 8-bit name 1st step in id_name conversion */
+};
+
+typedef struct etch_id_name etch_id_name;  
+
+etch_id_name* new_id_name(const wchar_t* name);
+void* clone_id_name(void*);
+int destroy_id_name(void*);
+
+int is_good_id_name(etch_id_name* thisp);
+int is_equal_id_names(etch_id_name*, etch_id_name*);
+int compute_id_name_id(const char*);
+int compute_id_name_id_from_widename(const wchar_t*);
+uint32 id_name_get_hashkey(void*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHIDNAME_H */ 
diff --git a/binding-c/runtime/c/include/etch_id_name_map.h b/binding-c/runtime/c/include/etch_id_name_map.h
new file mode 100644
index 0000000..3f68422
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_id_name_map.h
@@ -0,0 +1,75 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_id_name.h 
+ * etch_id_name is base class for etch_field and etch_type. it binds
+ * together a type or field name with its associated id. The id is used
+ * for certain operations, such as the key in a map, comparisons, and
+ * binary encoding on the wire.  
+*/
+
+#ifndef _ETCH_ID_NAME_MAP_H_
+#define _ETCH_ID_NAME_MAP_H_
+
+#include "etch.h"
+#include "etch_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct etch_id_name_map etch_id_name_map;
+
+/**
+ * creates a new instance of etch_id_name_map
+ */
+etch_status_t etch_id_name_map_create(etch_id_name_map** map);
+
+/**
+ * gets the IdName data which corresponds to the specified id.
+ */
+etch_status_t etch_id_name_map_get_by_id(etch_id_name_map* map, int32 id, void** data);
+
+/**
+ * gets the IdName data which corresponds to the specified id.
+ */
+etch_status_t etch_id_name_map_get_by_name(etch_id_name_map* map, const wchar_t* name, void** data);
+
+/**
+ * adds the id name data to the map.
+ */
+etch_status_t etch_id_name_map_add(etch_id_name_map* map, int32 id, const wchar_t* name, void* data);
+
+/**
+ * get count of the map.
+ */
+uint32 etch_id_name_map_count(etch_id_name_map* map);
+
+// get values function
+
+/**
+ * destroy the etch_id_name_map instance
+ */
+etch_status_t etch_id_name_map_destroy(etch_id_name_map* map);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef _ETCH_ID_NAME_MAP_H_ */
diff --git a/binding-c/runtime/c/include/etch_linked_list.h b/binding-c/runtime/c/include/etch_linked_list.h
new file mode 100644
index 0000000..a7fedd2
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_linked_list.h
@@ -0,0 +1,97 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_linklist.h 
+ * linked list implementation.
+ */
+
+#ifndef _ETCH_LINKED_LIST_H_
+#define _ETCH_LINKED_LIST_H_
+
+#include "etch_collection.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_LINKED_LIST_SYNCHRONIZED 1
+#define ETCH_LINKED_LIST_DATA_FREE    2
+
+typedef struct etch_linked_list_t etch_linked_list_t;
+
+/**
+ * create a new linked list instance.
+ */
+etch_status_t etch_linked_list_create(etch_linked_list_t** list, uint8 flags);
+
+/**
+ * add a new element to the list.
+ */
+etch_status_t etch_linked_list_add(etch_linked_list_t* list, void* data);
+
+/**
+ * get element at index.
+ */
+etch_status_t etch_linked_list_get(etch_linked_list_t* list, int32 index, void** data);
+
+/**
+ * get element at index.
+ */
+int32 etch_linked_list_index_of(etch_linked_list_t* list, const void* data);
+
+/**
+ * check the list if the element is inside.
+ */
+uint8 etch_linked_list_contains(etch_linked_list_t* list, const void* data);
+
+/**
+ * insert a new element at the given index to the list.
+ */
+etch_status_t etch_linked_list_insert(etch_linked_list_t* list, int32 index, void* data);
+
+/**
+ * remove an element from the list.
+ */
+etch_status_t etch_linked_list_remove_at(etch_linked_list_t* list, const int32 index);
+
+/**
+ * remove an element from the list.
+ */
+etch_status_t etch_linked_list_remove(etch_linked_list_t* list, void* data);
+
+/**
+ * clear the list.
+ */
+etch_status_t etch_linked_list_clear(etch_linked_list_t* list);
+
+/**
+ * get count of the list.
+ */
+uint32 etch_linked_list_count(etch_linked_list_t* list);
+
+/**
+ * destroy a linked list instance
+ */
+etch_status_t etch_linked_list_destroy(etch_linked_list_t* list);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef _ETCH_LINKED_LIST_H_ */
diff --git a/binding-c/runtime/c/include/etch_log.h b/binding-c/runtime/c/include/etch_log.h
new file mode 100644
index 0000000..b568ed9
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_log.h
@@ -0,0 +1,169 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_log.h 
+ * logger for the c binding
+ */
+#ifndef _ETCH_LOG_H_
+#define _ETCH_LOG_H_
+
+#include "etch.h"
+#include "etch_config.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * etch_log macros
+ */
+#define ETCH_LOG(category, level, fmt, ...) etch_log_log(NULL, category, level, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
+#define ETCH_LOGW(category, level, fmt, ...) etch_log_logw(NULL, category, level, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
+
+/**
+ * etch_log_t
+ */
+typedef struct etch_log_t etch_log_t;
+
+/**
+ * etch_log_levels
+ */
+typedef enum etch_log_level
+{
+    /**
+     * extended debug for low-level
+     * or voluminous detail
+     */
+    ETCH_LOG_XDEBUG = 0,
+
+    /**
+     * traces of connection open
+     * close send receive etc
+     */
+    ETCH_LOG_DEBUG,
+
+    /**
+     * display server and client
+     * open and close etc
+     */
+    ETCH_LOG_INFO,
+
+    /**
+     * messages that should be
+     * noted regardless
+     */
+    ETCH_LOG_WARN,
+
+    /**
+     * failures
+     */
+    ETCH_LOG_ERROR
+
+} etch_log_level;
+
+/**
+ * etch_log_message_t
+ */
+typedef struct etch_log_message_t
+{
+    const char*     category;
+    time_t          timestamp;
+    etch_log_level  level;
+    uint32          threadid;
+    const char*     file;
+    uint32          line;
+    char*           message;
+} etch_log_message_t;
+
+/*
+ * log appender definitions.
+ */
+typedef etch_status_t etch_log_appender_create(void** appender, etch_config_t* config);
+typedef etch_status_t etch_log_appender_open(void* appender);
+typedef etch_status_t etch_log_appender_log(void* appender, etch_log_message_t* message);
+typedef etch_status_t etch_log_appender_close(void* appender);
+typedef etch_status_t etch_log_appender_destroy(void* appender);
+
+typedef struct etch_log_appender_desc {
+    etch_log_appender_create*   create;
+    etch_log_appender_open*     open;
+    etch_log_appender_log*      log;
+    etch_log_appender_close*    close;
+    etch_log_appender_destroy*  destroy;
+} etch_log_appender_desc;
+
+typedef struct etch_log_appender {
+    struct etch_log_appender_desc* desc;
+    void*                          data;
+} etch_log_appender;
+
+/**
+ * register a new log appender.
+ * @param name of the appender
+ * @param desc of log appender.
+ * @return status.
+ */
+etch_status_t etch_log_register_appender(const char* name, etch_log_appender_desc* desc);
+
+/**
+ * create a new logger.
+ * @param logger that will be created.
+ * @return status.
+ */
+etch_status_t etch_log_create(etch_log_t** logger, etch_config_t* config);
+
+/**
+ * etch_log_log()
+ * write a log message to console/file/system log depending on configuration.
+ * @param logger logger instance
+ * @param category the category name for this message.
+ * @param level logging level of the message.
+ * @param file filename where the log function is called.
+ * @param line line number where the log function is called.
+ * @param fmt the format string ala printf.
+ * @...   a variable length argument list ala printf.
+ * @return void
+ */
+etch_status_t etch_log_log(etch_log_t* logger, const char* category, etch_log_level level, const char* file, int line, const char* fmt, ...);
+
+/**
+ * etch_log_logw()
+ * write a log message to console/file/system log depending on configuration.
+ * @param logger logger instance
+ * @param category the category name for this message.
+ * @param level logging level of the message.
+ * @param file filename where the log function is called.
+ * @param line line number where the log function is called.
+ * @param fmt the format wide string ala wprintf.
+ * @...   a variable length argument list ala wprintf.
+ * @return void
+ */
+etch_status_t etch_log_logw(etch_log_t* logger, const char* category, etch_log_level level, const char* file, int line, const wchar_t* fmt, ...);
+
+/**
+ * destroy the logger instance.
+ * @config handle.
+ */
+etch_status_t etch_log_destroy(etch_log_t* logger);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCH_LOG_H */
diff --git a/binding-c/runtime/c/include/etch_mailbox.h b/binding-c/runtime/c/include/etch_mailbox.h
new file mode 100644
index 0000000..0895c20
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_mailbox.h
@@ -0,0 +1,304 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_mailboxint.h
+ * mailbox interface
+ */
+#ifndef ETCHIMAILBOX_H
+#define ETCHIMAILBOX_H
+
+#include "etch_object.h"
+#include "etch_message.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_MAILBOX_TIMEOUT   (-2)
+#define ETCH_MAILBOX_DUPLICATE (-3)
+
+struct i_mailbox;
+struct i_mailbox_manager;
+
+/**
+ * etch_mailbox_notify()
+ * notify interface callback to receive notification of mailbox status changes.
+ * @remarks accomodation is made for a single status listener only.
+ * @param thisx caller
+ * @param mb the mailbox whose status has changed.
+ * @param state the state object specified during callback registration.
+ * @param closed true if the mailbox timeout has expired and the mailbox is now closed to delivery, 
+ * false if a message has arrived.
+ */
+typedef int (*etch_mailbox_notify) (void* thisx, struct i_mailbox* mb, void* state, const int is_closed);
+
+
+/**
+ * etch_mailbox_element
+ * this is for now an etch object, in case it needs to own the message
+ */
+typedef struct etch_mailbox_element
+{
+    unsigned int    hashkey;
+    unsigned short  obj_type;
+    unsigned short  class_id;
+    struct etch_object* vtab;
+    etch_object_destructor destroy;
+    etch_object_clone clone;
+    obj_gethashkey  get_hashkey;
+    struct etch_object* parent;
+    etchresult*     result;
+    unsigned int    refcount;
+    unsigned int    length;
+    unsigned char   is_null;
+    unsigned char   is_copy;
+    unsigned char   is_static;
+    unsigned char   reserved;
+    etch_mutex_hookproc  synchook;
+    etch_mutex_t*  synclock;
+
+    etch_message*   msg;
+    etch_who*       whofrom;
+
+} etch_mailbox_element;
+
+
+/* - - - - - - - - - - - - - - - - - 
+ * signatures of i_mailbox virtuals
+ * - - - - - - - - - - - - - - - - - 
+ */
+
+/** 
+ * etch_mailbox_message()
+ * queues the specified message to this mailbox.
+ * @param thisx caller
+ * @param msg the message to be received, caller relinquishes on success, retains on failure.
+ * @param whofrom sender, caller retains
+ * @return 0 success, -1 failure. 
+ */
+typedef int (*etch_mailbox_message)(void* thisx, etch_who* whofrom, etch_message* msg);
+
+/** 
+ * etch_mailbox_read()
+ * reads the next message from the mailbox, waiting indefinitely for a message to be delivered.
+ * @param thisx caller
+ * @param out location to receive the etch_mailbox_element* result.
+ * @return 0 success, -1 failure. on success, out location is populated with the requested message.
+ * if mailbox is empty and closed, result will be zero and *out will contain null.
+ * -1 this indicates an exception condition, not an empty condition.
+ */
+typedef int (*etch_mailbox_read) (void* thisx, etch_mailbox_element** out);
+
+/** 
+ * etch_mailbox_read_withwait()
+ * reads the next message from the mailbox, waiting the specified time for a message to be delivered.
+ * @param thisx caller
+ * @param maxdelay the maximum amount of time in milliseconds to wait for a message when the
+ * mailbox is empty. zero indicates wait indefinitely, -1 indicates do not wait.
+ * @param out location to receive the etch_mailbox_element* result.
+ * @return 0 success, -1 failure. on success, out location is populated with the requested message.
+ * if mailbox is empty and closed, result will be zero and *out will contain null.
+ * -1 this indicates an exception condition, not an empty condition.
+ */
+typedef int (*etch_mailbox_read_withwait) (void* thisx, const int maxdelay, etch_mailbox_element** out);
+
+/** 
+ * etch_mailbox_close_delivery()
+ * closes the mailbox such that no more messages can be delivered to it.
+ * any messages currently queued will continue to be processed.
+ * @param thisx caller
+ * @return 0 if mailbox was closed successfuly, -1 if mailbox was already closed or could not be closed.
+ */
+typedef int (*etch_mailbox_close_delivery) (void* thisx);
+
+/** 
+ * etch_mailbox_close_read()
+ * closes the mailbox such that no more messages can be delivered to it or read from it.
+ * any messages currently queued will be delivered to a default handler.
+ * @param thisx caller
+ * @return 0 if mailbox was closed successfuly, -1 if mailbox was already closed or could not be closed.
+ */
+typedef int (*etch_mailbox_close_read) (void* thisx);
+
+/** 
+ * etch_mailbox_register_notify()
+ * register a etch_mailbox_notify callback to receive notification of mailbox status changes.
+ * @param thisx caller
+ * @param notify pointer to a function conforming to the etch_mailbox_notify signature.
+ * @param state a value to pass through via the supplied notify callback.
+ * @param maxdelay the maximum amount of time in milliseconds to wait for delivery of the notification.
+ * zero indicates wait indefinitely, -1 indicates do not wait.  
+ * @return 0 on success, -1 if a callback is already registered, or on exception condition.
+ */
+typedef int (*etch_mailbox_register_notify) (void* thisx, etch_mailbox_notify, etch_object* state, const int maxdelay);
+
+/** 
+ * etch_mailbox_unregister_notify()
+ * remove the specified etch_mailbox_notify callback. cancels any current timeout.
+ * @param thisx caller
+ * @param notify pointer to a function conforming to the etch_mailbox_notify signature.
+ * @return 0 if specified callback was unregistered or -1 is specified calback is not currently
+ * registered, or on exception condition.
+ */
+typedef int (*etch_mailbox_unregister_notify) (void* thisx, etch_mailbox_notify);
+
+/** 
+ * etch_mailbox_is_empty()
+ * @return boolean value indicating if specified mailbox is empty
+ */
+typedef int (*etch_mailbox_is_empty)  (void* thisx);
+
+/** 
+ * etch_mailbox_is_closed()
+ * @return boolean value indicating if specified mailbox is closed
+ */
+typedef int (*etch_mailbox_is_closed) (void* thisx);
+
+/** 
+ * etch_mailbox_is_full()
+ * @return boolean value indicating if specified mailbox is full
+ */
+typedef int (*etch_mailbox_is_full)   (void* thisx);
+
+
+/** @return the message id of this mailbox  */
+typedef int64 (*etch_mailbox_get_message_id) (void* thiz);
+
+
+/** @return the concrete etch_mailbox object for this mailbox */
+typedef struct etch_plainmailbox etch_mailbox;
+typedef etch_mailbox* (*etch_mailbox_get_implobj) (struct i_mailbox*);
+
+
+/** @return the manager for this mailbox */
+typedef struct i_mailbox_manager* (*etch_mailbox_get_manager) (struct i_mailbox*);
+
+
+
+/* - - - - - - - - - - - - - - - - - 
+ * i_mailbox 
+ * - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * i_mailbox
+ * mailbox interface
+ */
+typedef struct i_mailbox
+{
+    unsigned int    hashkey;
+    unsigned short  obj_type;
+    unsigned short  class_id;
+    struct etch_object* vtab;
+    etch_object_destructor destroy;
+    etch_object_clone clone;
+    obj_gethashkey  get_hashkey;
+    struct etch_object* parent;
+    etchresult*     result;
+    unsigned int    refcount;
+    unsigned int    length;
+    unsigned char   is_null;
+    unsigned char   is_copy;
+    unsigned char   is_static;
+    unsigned char   reserved;
+    etch_mutex_hookproc  synchook;
+    etch_mutex_t*   synclock;
+
+    void* thisx;  /* instantiating object */
+    etch_mailbox_get_implobj mailbox;
+    etch_mailbox_get_manager manager;
+
+    etch_mailbox_message message;
+    etch_mailbox_read    read;
+    etch_mailbox_read_withwait     read_withwait;
+    etch_mailbox_close_delivery    close_delivery;
+    etch_mailbox_close_read        close_read;
+    etch_mailbox_register_notify   register_notify;
+    etch_mailbox_unregister_notify unregister_notify;
+    etch_mailbox_is_empty  is_empty;
+    etch_mailbox_is_closed is_closed;
+    etch_mailbox_is_full   is_full;
+    etch_mailbox_get_message_id get_message_id;
+
+} i_mailbox;
+
+
+
+/* - - - - - - - - - - - - - - - - - 
+ * public methods 
+ * - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * new_mailbox_element()
+ * etch_mailbox_element constructor
+ * @param msg todo document ownership
+ * @param whofrom todo document ownership
+ */
+etch_mailbox_element* new_mailbox_element(etch_message* msg, etch_who* whofrom);
+
+
+/**
+ * new_default_mailbox_interface()
+ * i_mailbox constructor
+ * populates all virtuals with stub methods.
+ * @param thisx instantiator object
+ */
+i_mailbox* new_default_mailbox_interface(void* thisx);
+
+
+/**
+ * etch_mailbox_get_implobj()
+ * verify and return the concrete mailbox implementation
+ */
+etch_mailbox* etchmbox_get_implobj(i_mailbox*);
+
+
+/**
+ * etch_mailbox_get_manager()
+ * verify and return the mailbox's mailbox manager
+ */
+struct i_mailbox_manager* etchmbox_get_manager(i_mailbox*);
+
+
+/**
+ * new_mailbox_interface()
+ * i_mailbox constructor
+ * populates virtuals with specified methods.
+ * @param thisx instantiator object.
+ * @param balance of parameters are pointers to virtual method implementations.
+ */
+i_mailbox* new_mailbox_interface(void* thisx,
+    etch_mailbox_message,
+    etch_mailbox_read,
+    etch_mailbox_read_withwait,
+    etch_mailbox_close_delivery,
+    etch_mailbox_close_read,
+    etch_mailbox_register_notify,
+    etch_mailbox_unregister_notify,
+    etch_mailbox_is_empty,
+    etch_mailbox_is_closed,
+    etch_mailbox_is_full,
+    etch_mailbox_get_message_id); 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHIMAILBOX_H */
diff --git a/binding-c/runtime/c/include/etch_mailbox_manager.h b/binding-c/runtime/c/include/etch_mailbox_manager.h
new file mode 100644
index 0000000..8ad9722
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_mailbox_manager.h
@@ -0,0 +1,132 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_mailboxmgr.h
+ * i_mailboxmgr interface
+ */
+#ifndef ETCHIMAILBOXMGR_H
+#define ETCHIMAILBOXMGR_H
+
+#if(0)
+
+ MAILBOXMANAGER
+ |  transportCall(Who to, message)  
+ |  redeliver(Who from, message)
+ |  unregister(mailbox)
+ |- SESSIONMESSAGE<SessionData>
+ |  |  sessionMessage(Who from, message)  
+ |   - SESSION
+ |       sessionQuery(); sessionControl(); sessionNotify();
+  - TRANSPORTMESSAGE  
+    |  transportMessage(to, Message);
+     - TRANSPORT
+          transportQuery(); transportControl(); transportNotify();
+          getSession(); setSession();
+#endif
+
+#include "etch_mailbox.h"
+#include "etch_session_message.h"
+#include "etch_transport_message.h"
+#include "etch_mutex.h"
+#include "etch_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*etch_mbm_transport_call) (struct i_mailbox_manager* thisx, etch_who* whoto, etch_message* msg, i_mailbox** out);
+
+typedef int (*etch_mbm_redeliver)  (void* thisx, etch_who* whofrom, etch_message* msg);
+typedef int (*etch_mbm_unregister) (void* thisx, i_mailbox* mailbox);
+
+/**
+ * i_mailbox_manager
+ * mailbox manager interface
+ */
+typedef struct i_mailbox_manager
+{
+    etch_object object;
+
+    void* thisx; /* object which is the interface implementor */
+
+    /**
+     * transport_call()
+     * sends a message which begins a call after allocating a mailbox 
+     * to receive responses.
+     * @param whoto recipient. caller retains.
+     * @param message the message which begins the call.
+     * caller relinquishes on success, retains on other than success.  
+     * @param out pointer to location to return the i_mailbox which will 
+     * receive responses to the call.
+     * @return 0 success, -1 error
+     */
+    etch_mbm_transport_call transport_call;
+
+    /**
+     * redeliver()
+     * redelivers messages extant from a closed mailbox.
+     * @param whofrom sender. caller retains.
+     * @param message. caller relinquishes on success, retains on other than success.  
+     * @return 0 success, -1 error
+     */
+    etch_mbm_redeliver      redeliver;
+
+    /**
+     * unregister()
+     * removes specified mailbox from the set of mailboxes receiving responses to messages.
+     * @param mailbox the mailbox to remove. caller does not own it.
+     * @return 0 success, -1 error
+     */
+    etch_mbm_unregister     unregister;
+
+    /* implements session message interface */
+    i_sessionmessage*    ism;
+    etch_session_message session_message;
+    etch_session_control session_control;
+    etch_session_notify  session_notify;
+    etch_session_query   session_query;
+
+    /* implements transport message interface */
+    i_transportmessage*    itm;  
+    etch_transport_message transport_message;
+    etch_transport_control transport_control;  
+    etch_transport_notify  transport_notify;   
+    etch_transport_query   transport_query;   
+    etch_transport_get_session  get_session;   
+    etch_transport_set_session  set_session;
+
+    etch_mutex* rwlock;  /* not owned */
+
+} i_mailbox_manager;
+
+
+/**
+ * new_mailboxmgr_interface()
+ * i_mailbox_manager constructor.
+ * @param thisx the mailbox manager object.
+ * @param itm transportmesssage interface, caller retains, can be null.
+ * @param ism sessionmessage interface, caller retains, can be null.
+ */
+i_mailbox_manager* new_mailboxmgr_interface(void* thisx, i_transportmessage*, i_sessionmessage*);  
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHIMAILBOXMGR_H */
diff --git a/binding-c/runtime/c/include/etch_map.h b/binding-c/runtime/c/include/etch_map.h
new file mode 100644
index 0000000..bcc306a
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_map.h
@@ -0,0 +1,71 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etchmap.h -- generic string to object map
+ */
+
+#ifndef ETCHMAP_H
+#define ETCHMAP_H
+
+#include "etch.h"
+#include "etch_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCHMAP_MAX_IKEYSIZE 31
+
+void* etchmap_find         (etch_hashtable*, const unsigned int key, void** out);
+void* etchmap_findx        (etch_hashtable*, char* key, void** out);
+void* etchmap_findxw       (etch_hashtable*, wchar_t* key, void** out);
+void* etchmap_findxl       (etch_hashtable*, char* key, unsigned keylen, void** out);
+void* etchmap_find_by_hash (etch_hashtable*, const unsigned hash, void** out);
+
+void* etchmap_del          (etch_hashtable*, const unsigned int key);
+void* etchmap_delx         (etch_hashtable*, char* key);
+void* etchmap_delxw        (etch_hashtable*, wchar_t* key);
+void* etchmap_delxl        (etch_hashtable*, char* ckey, const unsigned keylen);
+
+int etchmap_add            (etch_hashtable*, const unsigned int key, void* data);
+int etchmap_addx           (etch_hashtable*, char* key, void* data);
+int etchmap_addxw          (etch_hashtable*, wchar_t* key, void* data);
+int etchmap_insert         (etch_hashtable*, const unsigned, void*, const int is_check);
+int etchmap_insertx        (etch_hashtable*, char* key, void* data, const int is_check);
+int etchmap_insertxw       (etch_hashtable*, wchar_t* key, void* data, const int is_check);
+int etchmap_insertxl       (etch_hashtable*, char*, const unsigned, void*, const int); 
+int etchmap_insertxlw      (etch_hashtable*, wchar_t*, const unsigned, void*, const int); 
+
+int etchmap_count(etch_hashtable*);
+
+etch_hashitem* etchmap_current(etch_hashtable*);
+
+int etchmap_map_add (etch_hashtable* map, etch_object* key, etch_object* value); 
+int etchmap_map_find(etch_hashtable* map, etch_object* key, etch_hashitem** out);
+int etchmap_set_add (etch_hashtable* set, etch_object* key); 
+int etchmap_is_object_key(etch_hashtable*);
+
+int string_to_etchobject_clear_handler    (char* key, etch_object* value);  
+int string_to_genericobject_clear_handler (char* key, void* value);  
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHMAP_H*/ 
diff --git a/binding-c/runtime/c/include/etch_mem.h b/binding-c/runtime/c/include/etch_mem.h
new file mode 100644
index 0000000..65dcd9a
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_mem.h
@@ -0,0 +1,59 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etchmem.h -- heap memory allocate and free.
+ * The c binding wraps the heap allocator in order to track allocations. we supply 
+ * the etch_malloc macro which, when ETCH_DEBUGALLOC is defined,  will accept module 
+ * name and code line number, along with object type and allocation size, in order  
+ * to track heap allocations and frees, and to subsequently report memory leaks. 
+ */
+
+#ifndef ETCHMEM_H
+#define ETCHMEM_H
+
+#include "etch.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef apr_pool_t etch_pool_t;
+
+#define etch_malloc(n,o) _etch_malloc(n, __FILE__, __LINE__)
+#define etch_realloc(p,n,o) _etch_realloc(p,n,__FILE__, __LINE__)
+#define etch_free(n) _etch_free(n, __FILE__, __LINE__)
+#define etch_showmem(f,c)
+#define etch_dumpmem()
+
+void* _etch_malloc(size_t size, char* file, int line);
+void* _etch_realloc(void*, size_t size, char* file, int line);
+void _etch_free(void* mem, char* file, int line);
+
+/* For own malloc/free hook */
+typedef void*(*mallocFunc)(size_t);
+typedef void(*freeFunc)(void*);
+typedef void*(*reallocFunc)(void*,size_t);
+
+void etch_set_mallocator(mallocFunc myMallocFunc, freeFunc myFreeFunc, reallocFunc myReallocFunc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHMEM_H*/ 
diff --git a/binding-c/runtime/c/include/etch_message.h b/binding-c/runtime/c/include/etch_message.h
new file mode 100644
index 0000000..1c22de1
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_message.h
@@ -0,0 +1,85 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_message.h 
+ * a message is modeled as a command and some arguments. command is an arbitrary
+ * integer value, and the arguments are key / value pairs, where the key is an
+ * arbitrary integer value and the value is any one of the standard java objects
+ * an array value, a struct value, or any type serializable by value factory.
+ */
+
+#ifndef ETCHMESSAGE_H
+#define ETCHMESSAGE_H
+
+#include "etch_structval.h"
+#include "etch_value_factory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* 
+ * etch_message  
+ * this class is "final" 
+ */
+typedef struct etch_message
+{
+    etch_object object;
+
+    etch_structvalue* sv;   /* owned */
+    etch_value_factory* vf; /* not owned */
+     
+} etch_message;
+
+  
+/*
+ * etch_unwanted_message
+ */
+typedef struct etch_unwanted_message
+{
+    etch_object object;
+
+    etch_message* message;   /* owned */
+    etch_who*     whofrom;   /* not owned */
+
+} etch_unwanted_message;
+
+etch_unwanted_message* new_unwanted_message(etch_who* whofrom, etch_message* msg);
+
+
+etch_message* new_message (etch_type*, const int, etch_value_factory*);  
+
+etch_object*  message_get   (etch_message*, etch_field* key);
+etch_object*  message_remove(etch_message*, etch_field* key); 
+int           message_put   (etch_message*, etch_field* key, etch_object* value);
+int           message_putc  (etch_message*, etch_field* key, void** valref);
+etch_message* message_reply (etch_message*, etch_type* type);
+etch_type*    message_type  (etch_message*);
+char*         message_aname (etch_message*);
+etch_int64*   message_get_id(etch_message*);
+etch_int64*   message_get_in_reply_to(etch_message*);
+int           message_set_in_reply_to(etch_message*, etch_int64* id);
+int           message_set_id(etch_message*, etch_int64* id);
+int           message_size  (etch_message*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHMESSAGE_H*/ 
diff --git a/binding-c/runtime/c/include/etch_messagizer.h b/binding-c/runtime/c/include/etch_messagizer.h
new file mode 100644
index 0000000..80caa82
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_messagizer.h
@@ -0,0 +1,133 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_msgizer.h
+ * messagizer accepts packets and translates them to messages,
+ * and it accepts messages and translates them to packets.
+ */
+
+#ifndef ETCHMSGIZER_H
+#define ETCHMSGIZER_H
+
+#include "apr_thread_proc.h"
+#include "etch_session_message.h"
+#include "etch_session_packet.h"
+#include "etch_transport_message.h"
+#include "etch_transport_packet.h"
+
+#include "etch_tagdata_inp.h"
+#include "etch_tagdata_out.h"
+
+#include "etch_flexbuffer.h"
+#include "etch_resources.h"  
+#include "etch_mutex.h"
+#include "etch_url.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if(0)
+
+ MESSAGIZER(TRANSPORTPACKET)
+ |  tagdata_input*  tdi;
+ |  tagdata_output* tdo;
+ |  transportPacket* transport;
+ |  sessionPacket(from, buf);      // override  i_sessionpacket
+ |  transportMessage(to, Message); // implement i_transportmsg
+  - SESSIONPACKET
+ |  |  int (*etch_session_packet) (void* thisx, void* whofrom, void* buffer);
+ |   - SESSION
+ |        sessionQuery(); sessionControl(); sessionNotify();
+  - TRANSPORTMESSAGE  
+    |  int transportMessage(to, Message);
+     - TRANSPORT
+          transportQuery(); transportControl(); transportNotify();
+#endif
+
+
+/*
+ * etch_messagizer
+ */
+typedef struct etch_messagizer
+{
+    etch_object object;
+
+    /* i_transportpacket of next lower layer (packetizer) */
+    i_transportpacket*   transport; /* not owned */
+
+    /* i_sessionmessage of next higher layer (mailbox manager) */
+    i_sessionmessage*    session;   /* not owned */
+
+    etch_flexbuffer*     msgbuf;        /* owned */
+    tagged_data_input*   tdi;           /* owned */
+    tagged_data_output*  tdo;           /* owned */
+
+    /* - - - - - - - - - - - - - - -
+     * i_transportmessage
+     * - - - - - - - - - - - - - - -
+     */
+
+    /**
+     * i_transportmessage::transport_message()
+     * delivers message to transport from session
+     * @param to recipient
+     * @return 0 success, -1 error
+     */
+    etch_transport_message transport_message;
+    i_transportmessage*    transportmsg;      /* owned */
+    etch_transport_control transport_control; /* i_transportmessage::itransport */
+    etch_transport_notify  transport_notify;  /* i_transportmessage::itransport */
+    etch_transport_query   transport_query;   /* i_transportmessage::itransport */
+    etch_transport_get_session  get_session;  /* i_transportmessage::itransport */
+    etch_transport_set_session  set_session;  /* i_transportmessage::itransport */
+
+    /* - - - - - - - - - - - - - - -
+     * i_sessionpacket
+     * - - - - - - - - - - - - - - -
+     */
+
+    /**
+     * i_sessionpacket::session_packet()
+     * delivers data to the session from the transport
+     * @param from from who sent the packet
+     * @param buffer the packet from the packet source 
+     * @return 0 success, -1 error
+     */    
+    etch_session_packet  session_packet;
+    i_sessionpacket*     sessionpkt;       /* owned */
+    etch_session_control session_control;  /* i_sessionpacket::isession */
+    etch_session_notify  session_notify;   /* i_sessionpacket::isession */
+    etch_session_query   session_query;    /* i_sessionpacket::isession */
+
+    etch_mutex* msglock;
+
+} etch_messagizer;
+
+
+etch_messagizer* new_messagizer  (i_transportpacket*, wchar_t* uri, etch_resources* resxmap);
+etch_messagizer* new_messagizer_a(i_transportpacket*, etch_url*, etch_resources*);
+i_session* etch_msgizer_get_session(void*); 
+void etch_msgizer_set_session(void*, void*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* ETCHMSGIZER_H */
diff --git a/binding-c/runtime/c/include/etch_msgutl.h b/binding-c/runtime/c/include/etch_msgutl.h
new file mode 100644
index 0000000..d85fd7e
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_msgutl.h
@@ -0,0 +1,70 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etchmsgutl.h -- includes common to the etch message components
+ */
+
+#ifndef ETCHMSGUTL_H
+#define ETCHMSGUTL_H
+
+#include "etch_object.h"
+#include "etch_type.h"
+#include "etch_field.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_ARRAYVALUE_DEFAULT_INITSIZE 32
+#define ETCH_ARRAYVALUE_DEFAULT_DELTSIZE 0
+#define ETCH_ARRAYVALUE_DEFAULT_READONLY TRUE
+#define ETCH_ARRAYVALUE_DEFAULT_SYNCHRONIZED FALSE
+#define ETCH_ARRAYVALUE_DEFAULT_CONTENT_TYPE ETCHARRAYLIST_CONTENT_OBJECT
+
+#define ETCH_STRUCT_CONTENT_TYPE_OBJ 1
+#define ETCH_STRUCT_DEFAULT_INITSIZE 64
+#define ETCH_STRUCT_DEFAULT_READONLY_KEY TRUE
+#define ETCH_STRUCT_DEFAULT_READONLY_VAL TRUE
+#define ETCH_STRUCT_DEFAULT_TRACKED_MEM  TRUE
+#define ETCH_STRUCT_DEFAULT_CONTENT_TYPE ETCH_STRUCT_CONTENT_TYPE_OBJ
+
+/**
+ * equate java array element to an object.
+ * we do so to facilitate porting of the java code.
+ */
+typedef etch_object ETCH_ARRAY_ELEMENT;
+
+
+/**
+ * etch_struct_element
+ */
+typedef struct etch_struct_element
+{
+  etch_field* key;
+  etch_object*    value;
+} etch_struct_element;
+
+
+etch_struct_element* new_struct_element(etch_field*, etch_object*, etch_struct_element*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHMSGUTL_H */
diff --git a/binding-c/runtime/c/include/etch_mutex.h b/binding-c/runtime/c/include/etch_mutex.h
new file mode 100644
index 0000000..ccecf41
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_mutex.h
@@ -0,0 +1,85 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_mutex.h -- thread mutex implementation
+ * currently wraps APR mutex. 
+ */
+
+#ifndef _ETCH_MUTEX_H_
+#define _ETCH_MUTEX_H_
+
+#include "etch_errno.h"
+#include "etch_mem.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_MUTEX_NESTED   0x1
+#define ETCH_MUTEX_UNNESTED 0x2
+
+/**
+ * etch mutex type
+ */
+typedef struct etch_mutex_t etch_mutex_t;
+
+typedef etch_mutex_t etch_mutex;
+typedef int (*etch_mutex_hookproc)(int action, etch_mutex* mutex);
+
+/**
+ * create a new etch mutex instance.
+ * @param address where the new created mutex will be stored.
+ * @param flags mutex type ETCH_MUTEX_NESTED or ETCH_MUTEX_UNNESTED.
+ * @param pool memory pool where the memory will be allocated from.
+ * @return status
+ */
+etch_status_t etch_mutex_create(etch_mutex_t** mutex, unsigned int flags, etch_pool_t* pool);
+
+/**
+ * acquire the lock for the given mutex.
+ * @param mutex
+ * @return status
+ */
+etch_status_t etch_mutex_lock(etch_mutex_t* mutex);
+
+/**
+ * try to acquire the lock for the given mutex.
+ * @param mutex
+ * @return status
+ */
+etch_status_t etch_mutex_trylock(etch_mutex_t* mutex);
+
+/**
+ * release the lock for the given mutex.
+ * @param mutex
+ * @return status
+ */
+etch_status_t etch_mutex_unlock(etch_mutex_t* mutex);
+
+/**
+ * destroy the given mutex.
+ * @param mutex
+ */
+etch_status_t etch_mutex_destroy(etch_mutex_t* mutex);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_MUTEX_H */
diff --git a/binding-c/runtime/c/include/etch_nativearray.h b/binding-c/runtime/c/include/etch_nativearray.h
new file mode 100644
index 0000000..cb6a36c
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_nativearray.h
@@ -0,0 +1,101 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_nativearray.h -- etch_nativarray implementation.
+ */
+#ifndef ETCH_NATIVEARRAY_H
+#define ETCH_NATIVEARRAY_H
+
+/**
+ * etch_nativearray  
+ * object wrapper and methods for an n-dimensioned array of any type
+ * represented in memory as a single byte vector.
+ */
+
+#include "etch_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// etch_nativearray defines
+#define ETCH_MAX_NATIVE_DIM 3 /* arbitrary limit on native array dimensions */
+
+/**
+ * etch_nativearray
+ */
+typedef struct etch_nativearray
+{
+    etch_object object;
+    
+    unsigned char   is_content_owned;
+    
+    void*  values;  /* flattened array content */
+    unsigned short content_obj_type;  /* ETCHTYPEB_INT32 means content is int */
+    unsigned short content_class_id;  /* CLASSID_NONE means content not wrapped */
+    int  numdims;   /* number of dimensions, e.g., 2 for x[3][4]  */
+
+    /* this object may be masked by etch_collection_mask to determine content
+     * type and class, so do not add any fields above this comment */
+
+    size_t itemsize;  /* size in bytes of an item, e.g. sizeof(int) */
+    size_t bytecount; /* length in bytes of array content (values)  */
+    size_t dimension[ETCH_MAX_NATIVE_DIM]; /* for int x[2][3] [0] is 3, [1] is 2  */
+    size_t dimsize  [ETCH_MAX_NATIVE_DIM]; /* for int x[2][3] [0] is 4, [1] is 12 */
+    size_t counts   [ETCH_MAX_NATIVE_DIM]; /* optional actual population counts */
+
+    // dim size example
+    // int[2][3] array 2 * 3
+    //
+    // int[0][0] 4
+    // int[0][1] 8
+    // int[0][2] 12
+    // int[1][0] 16
+    // int[1][1] 20
+    // int[1][2] 24
+    // | dim size 0 = 4                          | dim size 1 = 12 = 3 * sizeof(int)
+    // | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 |
+
+    int (*put1) (struct etch_nativearray*, void* v, int i); 
+    int (*put2) (struct etch_nativearray*, void* v, int i, int j); 
+    int (*put3) (struct etch_nativearray*, void* v, int i, int j, int k);
+    int (*get1) (struct etch_nativearray*, void* v, int i); 
+    int (*get2) (struct etch_nativearray*, void* v, int i, int j); 
+    int (*get3) (struct etch_nativearray*, void* v, int i, int j, int k); 
+} etch_nativearray;
+
+etch_nativearray* new_etch_nativearray (unsigned short class_id, const size_t itemsize, const int numdims, const int dim0, const int dim1, const int dim2);
+etch_nativearray* new_etch_nativearray_from (void* values, unsigned short class_id, const size_t itemsize, const int numdims, const int dim0, const int dim1, const int dim2);
+etch_nativearray* new_etch_nativearray_of(unsigned short content_obj_type, unsigned short content_class_id, const int numdims, const int dim0, const int dim1, const int dim2);
+etch_nativearray* new_subarray(etch_nativearray* a, const int i); etch_nativearray* etch_nativearray_assign_to(etch_nativearray*, etch_nativearray*);
+etch_object* etch_nativearray_get_element(etch_nativearray*, const int i);
+int etch_nativearray_get_component_type(etch_object* classobj, etch_component_type_params*);
+int etch_nativearray_get_wrapped_component(etch_nativearray*, const int i, etch_object** out);
+int destroy_etch_nativearray_content(etch_nativearray*);
+int destroy_etch_nativearray(void*);
+size_t etch_nativearray_off1 (etch_nativearray* a, int i);
+size_t etch_nativearray_off2 (etch_nativearray* a, int i, int j);
+size_t etch_nativearray_off3 (etch_nativearray* a, int i, int j, int k);
+void* etch_nativearray_clone(void* other);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_MUTEX_H */
diff --git a/binding-c/runtime/c/include/etch_object.h b/binding-c/runtime/c/include/etch_object.h
new file mode 100644
index 0000000..bb2db0a
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_object.h
@@ -0,0 +1,583 @@
+
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etchobj.h 
+ * etch object definitions
+ */
+
+#ifndef ETCHOBJ_H
+#define ETCHOBJ_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include "etch.h"
+#include "etch_mutex.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct etch_object;
+struct vtabmask;
+struct etchexception; /* declared in etchexcp.h which we can't include here */
+
+/**
+ * function signatures for object virtuals
+ */
+typedef int   (*etch_object_destructor)(void*); /* should tak etch_object or etch_object */
+typedef void* (*etch_object_clone)(void*); /* should take and return etch_object or etch_object */
+typedef uint32   (*obj_gethashkey)(void*); /* should take etch_object or etch_object */
+
+typedef struct etchresult
+{
+    int resultcode;   
+    int reasoncode;
+    struct etchexception* exception;
+} etchresult;
+
+/**
+ * etch_object
+ * mask over all etch objects
+ */
+typedef struct etch_object
+{
+    unsigned int hashkey;     /* unique key used by a hash map */
+    unsigned short   obj_type;    /* type of this object */
+    unsigned short   class_id;    /* class identifier */
+    struct vtabmask* vtab;        /* virtual function table */
+    etch_object_destructor          destroy;
+    etch_object_clone         clone;
+    obj_gethashkey   get_hashkey; /* hash key calculation override */
+    struct etch_object*  parent;      /* class from which this derives */
+    etchresult*      result;      /* embedded result and exception */
+    unsigned int     refcount;    /* non-zero implies ref counted  */
+    unsigned int     length;      /* byte count of the flat object */
+    unsigned char    is_null;     /* does object wrap a null value */
+    unsigned char    is_copy;     /* is object content not owned   */
+    unsigned char    is_static;   /* should destructor free object */
+    unsigned char    reserved;	  /* reserved for individual use   */
+    etch_mutex_hookproc  synchook; /* hook for synchronization      */
+    etch_mutex_t*   synclock; /* synchronization mutex         */
+} etch_object;
+
+typedef struct etch_byte    etch_byte;
+typedef struct etch_boolean etch_boolean;
+typedef struct etch_int8    etch_int8;
+typedef struct etch_int16   etch_int16;
+typedef struct etch_int32   etch_int32;
+typedef struct etch_int64   etch_int64;
+typedef struct etch_float   etch_float;
+typedef struct etch_double  etch_double;
+typedef struct etch_string  etch_string;
+typedef struct etch_date    etch_date;
+typedef struct etch_exception etch_exception;
+
+/**
+ * etchparentinfo
+ * object inheritance list entry
+ */
+typedef struct etchparentinfo
+{
+   union {
+     unsigned short  obj_type;
+     unsigned short  list_size;  /* entry[0] in any inheritance list */
+   } o;
+   union {
+     unsigned short  class_id;
+     unsigned short  list_count; /* entry[0] in any inheritance list */
+   } c;
+} etchparentinfo;
+
+/**
+ * vtabmask
+ * mask over any vtable 
+ */
+typedef struct vtabmask
+{
+    etch_object object;
+
+    // inheritance list
+    etchparentinfo*  inherits_from;   // 4 byte
+    unsigned char unused[4];          // 4 byte
+    
+    /* function pointers start here */
+} vtabmask;
+
+
+/**
+ * etch_byte - wrapped byte 
+ * note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
+ * by code which generalizes such objects, to have the object's value as the first
+ * non-header item in the object.
+ */
+struct etch_byte
+{
+    etch_object object;
+    signed char value;          // 1 byte
+};
+
+/**
+ * etch_boolean - wrapped boolean 
+ * note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
+ * by code which generalizes such objects, to have the object's value as the first
+ * non-header item in the object.
+ */
+struct etch_boolean
+{
+    etch_object object;
+    unsigned char value;        // 1 byte
+};
+
+/**
+ * etch_int8 - wrapped 8-bit integer 
+ * note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
+ * by code which generalizes such objects, to have the object's value as the first
+ * non-header item in the object.
+ */
+struct etch_int8
+{
+    etch_object object;
+    signed char value;          // 1 byte
+};
+
+/**
+ * etch_int16 - wrapped 16-bit integer 
+ * note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
+ * by code which generalizes such objects, to have the object's value as the first
+ * non-header item in the object.
+ */
+struct etch_int16
+{
+    etch_object object;
+    signed short    value;      // 2 byte
+};
+
+/**
+ * etch_int32 - wrapped 32-bit integer 
+ * note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
+ * by code which generalizes such objects, to have the object's value as the first
+ * non-header item in the object.
+ */
+struct etch_int32
+{
+    etch_object object;
+    signed int value;           // 4 byte
+};
+
+/**
+ * etch_int64 - wrapped 64-bit integer 
+ * note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
+ * by code which generalizes such objects, to have the object's value as the first
+ * non-header item in the object.
+ */
+struct etch_int64
+{
+    etch_object object;
+    int64 value;    // 8 byte
+};
+
+/**
+ * etch_float - wrapped 32-bit float 
+ * note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
+ * by code which generalizes such objects, to have the object's value as the first
+ * non-header item in the object.
+ */
+struct etch_float
+{
+    etch_object object;
+    float value;                // 4 byte
+};
+
+/**
+ * etch_double - wrapped 64-bit float 
+ * note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
+ * by code which generalizes such objects, to have the object's value as the first
+ * non-header item in the object.
+ */
+struct etch_double
+{
+    etch_object object;
+    double value;       // 8 byte
+};
+
+
+typedef union etch_charptr
+{
+  void*    value;
+  wchar_t* valw;
+  char*    valc;
+} etch_charptr;
+
+
+/**
+ * etch_string - wrapped pointer to unicode string  
+ * note that this and all CLASSID_PRIMITIVE_XXXX wrapped primitives are expected
+ * by code which generalizes such objects, to have the object's value as the first
+ * non-header item in the object.
+ */
+struct etch_string
+{
+    etch_object object;
+    union etch_charptr v;     /* pointer to string value */
+    unsigned int char_count;  /* number of characters */
+    unsigned int byte_count;  /* including terminator */
+    unsigned char   encoding; 
+};
+
+/**
+ * etch_date - date object 
+ */
+struct etch_date
+{
+    etch_object object;
+
+    time_t  value;
+    clock_t ticks;
+};
+
+typedef enum excptype
+{ 
+  EXCPTYPE_NONE          = 0x0,
+  EXCPTYPE_BUILTIN       = 0x1,
+  EXCPTYPE_USERDEFINED   = 0x2
+} excptype_t; 
+
+/**
+ * etch_collection_mask  
+ * masks etch object collections such as etch_nativearray, etch_arraylist, 
+ * and etch_hashtable. not instantiated.
+ */
+typedef struct etch_collection_mask
+{
+    etch_object object;
+
+    void* p;
+    unsigned short content_obj_type;
+    unsigned short content_class_id;
+    unsigned int n;
+
+} etch_collection_mask; 
+
+
+/**
+ * etch_arraytype is used as a mask over etch_nativearray and etch_arrayvalue.
+ * a function using an etch_arraytype* parameter will test for one or the other
+ * and possibly convert the passed array to the other type.
+ */  
+typedef struct etch_collection_mask etch_arraytype;
+
+/**
+ * etch_objclass
+ * parameter structure identifying an etch object type
+ */
+typedef struct etch_objclass
+{
+    unsigned short  obj_type;
+    unsigned short  class_id;
+    unsigned short  content_obj_type;
+    unsigned short  content_class_id;
+    unsigned short  vtable_class_id;
+    unsigned int    numdims;
+    etchparentinfo* inherits_from; 
+    etch_object* parent;
+
+} etch_objclass;
+
+
+/**
+ * etch_component_type_params
+ * parameter and result structure for get_component_type() etc.
+ */
+typedef struct etch_component_type_params
+{
+    unsigned int   dimensions;
+    unsigned short origl_class_id;
+    unsigned short origl_obj_type;
+    unsigned short final_obj_type;
+    unsigned short final_class_id;
+    struct etch_nativearray* origl_array;
+    struct etch_nativearray* final_array;
+
+} etch_component_type_params;
+
+
+typedef struct etch_array_id_params
+{
+    unsigned short array_obj_type;
+    unsigned short array_class_id;
+    unsigned short content_obj_type;
+    unsigned short content_class_id;
+   
+} etch_array_id_params;
+
+
+/* 
+ * default base object virtual method implementations
+ */
+int  destroy_object(void*);
+int  destroy_objectex(etch_object*);
+int  destroy_string(void*);
+void*  clone_object (void*);
+void*  clone_string (void*);
+void*  clone_null(void*);
+etch_object*  new_object(const int objsize, 
+    const unsigned short obj_type, const unsigned short class_id);
+
+/* 
+ * wide char string clone
+ */
+wchar_t* new_wchar(const wchar_t* s);
+
+/* 
+ * narrow char string clone
+ */
+char* new_char(const char* s);
+
+typedef struct etch_who {
+    etch_object object;
+    void* value;
+} etch_who; 
+
+
+typedef etch_int32  etch_event;
+typedef etch_int32  etch_query;
+typedef etch_int32  etch_control;
+etch_who* new_who(void* whoobj); 
+etch_object*  new_nullobj();
+
+int destroy_etch_object_value(etch_object*);
+etch_object* etchobj_assign_to(etch_object*, etch_object*);
+
+
+/* 
+ * etch primitive constructors
+ */
+etch_byte*      new_byte(const signed char);
+etch_boolean*   new_boolean(boolean);
+etch_int8*      new_int8(signed char);
+etch_int16*     new_int16(short);
+etch_int32*     new_int32(int);
+etch_int64*     new_int64(int64);
+etch_float*     new_float(float);
+etch_double*    new_double(double);
+etch_string*    new_string(const void*, const unsigned char encoding);
+etch_string*    new_stringw(const void*); 
+etch_string*    new_stringa(const void*); 
+etch_string*    new_string_from(const void*, const unsigned char encoding);
+etch_date*      new_date(); 
+etch_object*    new_primitive(const unsigned, const unsigned short);
+
+etchresult* new_etchresult(const int result, const int reason);
+
+int32 etch_number_as_int32(const void* object);
+
+/* these are wrapped integers for now. if we need more data, we can define dedicated objects */
+etch_event*   new_etch_event  (const unsigned short class_id, const int value);
+etch_query*   new_etch_query  (const unsigned short class_id, const int value);
+etch_control* new_etch_control(const unsigned short class_id, const int value);
+
+etch_status_t etch_object_destroy(void* object);
+etch_object* etch_object_clone_func(void* pobject);
+
+#define ETCH_NOREFCOUNT_MARKER 0xffffffff
+#define is_etchobj_refcount_decremented(x) (x->get_hashkey(x) == ETCH_NOREFCOUNT_MARKER)
+
+#define ETCHOBJCLASS(x) ETCHMAKECLASS(((etch_object*)x)->obj_type, ((etch_object*)x)->class_id)
+#define ETCH_CONX_SIG 0xe5d4c3b2
+
+typedef union
+{
+  char   vbyte;  unsigned char vubyte; short vint16; int vint32; int64 vint64; double vdouble; 
+  float  vfloat; void* vaddr;  etch_string* vstring; 
+  struct etch_object* vetch_object; 
+  struct etch_nativearray* vnatarray; struct etch_structvalue* vsv; 
+  struct etch_arrayvalue*  varrayval; struct etch_arraylist* varraylist;
+  int64  all;
+} union_alltypes;
+
+
+#define is_etch_byte(x)         (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_BYTE)
+#define is_etch_boolean(x)      (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_BOOL)
+#define is_etch_int8(x)         (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_INT8)
+#define is_etch_int16(x)        (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_INT16)
+#define is_etch_int32(x)        (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_INT32)
+#define is_etch_int64(x)        (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_INT64)
+#define is_etch_float(x)        (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_FLOAT)
+#define is_etch_double(x)       (x && ((etch_object*)x)->class_id == CLASSID_PRIMITIVE_DOUBLE)
+#define is_etch_primitive(x)    (x && ((etch_object*)x)->obj_type == ETCHTYPEB_PRIMITIVE)
+#define is_etch_struct(x)       (x && ((etch_object*)x)->obj_type == ETCHTYPEB_STRUCTVAL)
+#define is_etch_validator(x)    (x && ((etch_object*)x)->obj_type == ETCHTYPEB_VALIDATOR)
+#define is_etch_arraylist(x)    (x && ((etch_object*)x)->obj_type == ETCHTYPEB_ARRAYLIST)
+#define is_etch_arrayvalue(x)   (x && ((etch_object*)x)->obj_type == ETCHTYPEB_ARRAYVAL)
+#define is_etch_valuefact(x)    (x && ((etch_object*)x)->obj_type == ETCHTYPEB_VALUEFACTORY)
+#define is_etch_valuefactimpl(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_VALUEFACTIMP)
+#define is_etch_exception(x)    (x && ((etch_object*)x)->obj_type == ETCHTYPEB_EXCEPTION)
+#define is_etch_queue(x)        (x && ((etch_object*)x)->obj_type == ETCHTYPEB_ETCHQUEUE)
+#define is_etch_wait(x)         (x && ((etch_object*)x)->obj_type == ETCHTYPEB_WAIT)
+#define is_etch_mailbox(x)      (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MAILBOX)
+#define is_etch_imailbox(x)     (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MAILBOXINT)
+#define is_etch_mailboxmgr(x)   (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MBOXMGR_IMPL)
+#define is_etch_imailboxmgr(x)  (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MBOX_MANAGER)
+#define is_etch_sessionmsg(x)   (x && ((etch_object*)x)->obj_type == ETCHTYPEB_SESSIONMSG)
+#define is_etch_transportmsg(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_TRANSPORTMSG)
+#define is_etch_hashtable(x)    (x && ((etch_object*)x)->obj_type == ETCHTYPEB_HASHTABLE) 
+#define is_etch_nativearray(x)  (x && ((etch_object*)x)->obj_type == ETCHTYPEB_NATIVEARRAY)
+#define is_etch_deliverysvc(x)  (x && ((etch_object*)x)->obj_type == ETCHTYPEB_DELIVERYSVC_IMPL)
+#define is_etch_ideliverysvc(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_DELIVERYSVCINT)
+#define is_etch_tcpserver(x)    (x && ((etch_object*)x)->obj_type == ETCHTYPEB_TCPSERVER)
+#define is_etch_sessionlxr(x)   (x && ((etch_object*)x)->obj_type == ETCHTYPEB_SESSIONLXR)
+#define is_etch_sessionpacket(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_SESSIONPKT) 
+#define is_etch_transportpkt(x) (x && ((etch_object*)x)->obj_type == ETCHTYPEB_TRANSPORTPKT) 
+#define is_etch_sessiondata(x)  (x && ((etch_object*)x)->obj_type == ETCHTYPEB_SESSIONDATA) 
+#define is_etch_transportdata(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_TRANSPORTDATA) 
+#define is_etch_packetizer(x)   (x && ((etch_object*)x)->obj_type == ETCHTYPEB_PACKETIZER) 
+#define is_etch_messagizer(x)   (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MESSAGIZER) 
+#define is_etch_serverimpl(x)   (x && ((etch_object*)x)->obj_type == ETCHTYPEB_EXESERVERIMPL) 
+#define is_etch_serverbase(x)   (x && ((etch_object*)x)->obj_type == ETCHTYPEB_EXESERVERBASE) 
+#define is_etch_factoryparams(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_FACTORYPARAMS) 
+#define is_etch_clientsession(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_CLIENT_SESSION) 
+#define is_etch_remote_server(x)(x && ((etch_object*)x)->obj_type == ETCHTYPEB_REMOTESERVER) 
+#define is_etch_client_impl(x)  (x && ((etch_object*)x)->obj_type == ETCHTYPEB_EXECLIENTIMPL) 
+#define is_etch_client_stub(x)  (x && ((etch_object*)x)->obj_type == ETCHTYPEB_CLIENTSTUB) 
+#define is_etch_server_stub(x)  (x && ((etch_object*)x)->obj_type == ETCHTYPEB_SERVERSTUB) 
+#define is_etch_client_base(x)  (x && ((etch_object*)x)->obj_type == ETCHTYPEB_EXECLIENTBASE) 
+#define is_etch_threadpool(x)   (x && ((etch_object*)x)->obj_type == ETCHTYPEB_THREADPOOL)
+#define is_etch_flexbuffer(x)   (x && ((etch_object*)x)->obj_type == ETCHTYPEB_FLEXBUF) 
+#define is_etch_message(x)      (x && ((etch_object*)x)->obj_type == ETCHTYPEB_MESSAGE) 
+#define is_etch_thread(x)       (x && ((etch_object*)x)->obj_type == ETCHTYPEB_THREAD) 
+
+#define is_etch_string(x)      (x && ((etch_object*)x)->class_id == CLASSID_STRING \
+ && ((etch_object*)x)->obj_type == ETCHTYPEB_PRIMITIVE)  
+
+#define is_etch_date(x) (x && ((etch_object*)x)->class_id == CLASSID_DATE \
+ && ((etch_object*)x)->obj_type == ETCHTYPEB_PRIMITIVE) 
+
+#define is_etch_object(x)     (x && ((etch_object*)x)->obj_type == ETCHTYPEB_ETCHOBJECT) 
+#define is_etch_object_type(a,b)(a == ETCHTYPEB_ETCHOBJECT || b == CLASSID_OBJECT ) 
+#define is_etch_nativearray_type(t,c) (t == ETCHTYPEB_NATIVEARRAY)
+#define is_etch_arraylist_type(t,c)   (t == ETCHTYPEB_ARRAYLIST)
+#define is_etch_objarray_type(t,c)    (c == CLASSID_ARRAY_OBJECT)
+
+#define is_etch_tcpconnection(x) (x \
+ && ((etch_object*)x)->obj_type == ETCHTYPEB_CONNECTION \
+ && ((etch_object*)x)->class_id == CLASSID_TCP_CONNECTION) 
+
+#define is_etch_serverparams(x) (x \
+ && ((etch_object*)x)->obj_type == ETCHTYPEB_FACTORYPARAMS \
+ && ((etch_object*)x)->class_id == CLASSID_SERVERFACTORY) 
+
+#define is_etch_clientparams(x) (x \
+ && ((etch_object*)x)->obj_type == ETCHTYPEB_FACTORYPARAMS \
+ && ((etch_object*)x)->class_id == CLASSID_CLIENTFACTORY) 
+
+#define is_etch_combo_validator(x) (x \
+ && ((etch_object*)x)->obj_type == ETCHTYPEB_VALIDATOR \
+ && ((etch_object*)x)->class_id == CLASSID_COMBO_VALIDATOR) 
+
+#define is_etch_primitive_number(x) (x \
+ && ((etch_object*)x)->class_id >= CLASSID_PRIMITIVE_BYTE \
+ && ((etch_object*)x)->class_id <= CLASSID_PRIMITIVE_DOUBLE)
+
+#define is_etch_arraytype(x) (x \
+ && (((etch_object*)x)->obj_type >= ETCHTYPEB_NATIVEARRAY \
+  || ((etch_object*)x)->obj_type <= ETCHTYPEB_ARRAYVAL))
+
+#define is_etch_unwantedmsg(x) (x \
+ && ((etch_object*)x)->obj_type == ETCHTYPEB_EVENT \
+ && ((etch_object*)x)->class_id == CLASSID_EVENT_UNWANTMSG) 
+
+
+#define is_etch_objparams(x,a,b) (x && ((etch_object*)x)->obj_type == a && ((etch_object*)x)->class_id == b)  
+
+#define is_etch_connection(cx) (cx && (*(unsigned*)cx) == ETCH_CONX_SIG)
+
+/**
+ * macros to interpret state of the object byteflag is_static 
+ */
+#define ETCHOBJ_IMMUTABLE_SHELL   1   /* object shell not to be freed */
+#define ETCHOBJ_IMMUTABLE_CONTENT 2   /* object content not to be freed */
+#define ETCHOBJ_IMMUTABLE_ALL     3   /* entire object not to be freed */
+#define ETCHOBJ_STATIC_RESOURCE   4   /* object will not be destroyed by resources mgr */
+#define is_etchobj_static_shell(x)   (  ( ((etch_object*)x)->is_static  &  ETCHOBJ_IMMUTABLE_SHELL ) != 0 )
+#define is_etchobj_static_shellonly(x)  ( ((etch_object*)x)->is_static ==  ETCHOBJ_IMMUTABLE_SHELL )
+#define is_etchobj_static_content(x)    ( ((etch_object*)x)->is_static >=  ETCHOBJ_IMMUTABLE_CONTENT ) 
+#define is_etchobj_static_contonly(x)   ( ((etch_object*)x)->is_static ==  ETCHOBJ_IMMUTABLE_CONTENT )
+#define is_etchobj_static_all(x)        ( ((etch_object*)x)->is_static ==  ETCHOBJ_IMMUTABLE_ALL )
+#define is_etchobj_static_resource(x) ( ( ((etch_object*)x)->is_static  &  ETCHOBJ_STATIC_RESOURCE) != 0 )
+#define set_etchobj_static_all(x)       ( ((etch_object*)x)->is_static |=  ETCHOBJ_IMMUTABLE_ALL )
+#define set_etchobj_static_shell(x)     ( ((etch_object*)x)->is_static |=  ETCHOBJ_IMMUTABLE_SHELL )
+#define set_etchobj_static_content(x)   ( ((etch_object*)x)->is_static |=  ETCHOBJ_IMMUTABLE_CONTENT )
+#define set_etchobj_static_resource(x)  ( ((etch_object*)x)->is_static |=  ETCHOBJ_STATIC_RESOURCE )
+#define clear_etchobj_static_shell(x)   ( ((etch_object*)x)->is_static &= ~ETCHOBJ_IMMUTABLE_SHELL )
+#define clear_etchobj_static_content(x) ( ((etch_object*)x)->is_static &= ~ETCHOBJ_IMMUTABLE_CONTENT )
+#define clear_etchobj_static_all(x)     ( ((etch_object*)x)->is_static &= ~ETCHOBJ_IMMUTABLE_ALL )
+#define clear_etchobj_static_resource(x)( ((etch_object*)x)->is_static &= ~ETCHOBJ_STATIC_RESOURCE )
+
+
+/**
+ * macros to get size/count from etch object inheritance list
+ */        
+#define has_parents(obj) {obj && ((vtabmask*)((etch_object*)obj)->vtab)->inherits_from \
+     && ((vtabmask*)((etch_object*)obj)->vtab)->inherits_from[0].list_count > 0))     
+#define get_etchobj_parent_count(obj) \
+  (obj && ((etch_object*)obj)->vtab && ((vtabmask*)obj->vtab)->inherits_from? \
+  ((vtabmask*)((etch_object*)obj)->vtab)->inherits_from[0].list_count: 0)
+#define get_etchobj_parent_listsize(obj) \
+  (obj && ((etch_object*)obj)->vtab && ((vtabmask*)obj->vtab)->inherits_from? \
+  ((vtabmask*)((etch_object*)obj)->vtab)->inherits_from[0].list_size: 0) 
+
+/**
+ * methods to access and/or instantiate object's inheritance hierarchy
+ */ 
+etchparentinfo* get_vtab_inheritance_list(etch_object*, 
+   const short size, const short count, const short vtabclass);
+etchparentinfo* new_etch_inheritance_list(const short size, const short count, 
+   etchparentinfo* oldlist);
+etchparentinfo* get_next_etch_parent(etch_object*, int current_index);
+etchparentinfo* get_next_etch_parentex(const unsigned short class_id, 
+   etchparentinfo* inhertlist, int current_index);
+
+int  etchobj_is_assignable_from(etch_objclass* target, etch_objclass* source);
+int  etchobj_is_assignable_fromobj(etch_object* targetobj, etch_object* sourceobj);
+void set_etch_assignable_arg_from(etch_objclass*, etch_object*);
+
+unsigned etch_get_char_hashkey (const char*);
+unsigned etch_get_wchar_hashkey(const wchar_t*);
+
+int      is_derives_from_object(etch_object*);
+int      is_derives_from_object_class(const unsigned short class_id);
+int      verify_object(etch_object*, const unsigned short, const unsigned short, void** out);
+void*    new_vtable(const void* parentvtab, const size_t size, const short classid);
+short    short_type(unsigned i, unsigned j); 
+void*    get_base_vtable(etch_object*); 
+unsigned etch_addref(etch_object*);
+unsigned etch_release(etch_object*);
+unsigned etch_release_wrapper(etch_object*);
+uint32 defgethashkey(void*);
+uint32 etch_number_get_hashkey(void*);
+unsigned get_vtable_cachehkey(unsigned short class_id);
+unsigned get_class_cachekey(unsigned short obj_type, unsigned short class_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHOBJ_H */
diff --git a/binding-c/runtime/c/include/etch_objecttypes.h b/binding-c/runtime/c/include/etch_objecttypes.h
new file mode 100644
index 0000000..e276f94
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_objecttypes.h
@@ -0,0 +1,361 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_objecttypes.h -- constants for internal object types.
+ */
+
+#ifndef ETCHOBJTYPES_H
+#define ETCHOBJTYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** 
+ * identifies a class object's data type or content type
+ */
+typedef enum objtype_b
+{  
+    ETCHTYPEB_UNDEFINED       = 0x0,
+    ETCHTYPEB_NONE            = 0x0,
+    ETCHTYPEB_BYTE            = 0x1,
+    ETCHTYPEB_BOOL            = 0x2,
+    ETCHTYPEB_INT8            = 0x3,
+    ETCHTYPEB_INT16           = 0x4,
+    ETCHTYPEB_INT32           = 0x5,
+    ETCHTYPEB_INT64           = 0x6,
+    ETCHTYPEB_IEEE32          = 0x7,
+    ETCHTYPEB_IEEE64          = 0x8,
+    ETCHTYPEB_STRING          = 0x9,
+    ETCHTYPEB_CLASS           = 0xa,
+    ETCHTYPEB_RAWOBJECT       = 0xb,
+    ETCHTYPEB_CUSTOM          = 0xc,
+    ETCHTYPEB_EXTERN          = 0xd,
+    ETCHTYPEB_ETCHOBJECT      = 0xe,
+    ETCHTYPEB_HASHTABLE       = 0xf,
+    ETCHTYPEB_VTABLE          = 0x10,
+    ETCHTYPEB_EXCEPTION       = 0x11,
+    ETCHTYPEB_CACHEREC        = 0x12,
+    ETCHTYPEB_BYTES           = 0x13,
+    ETCHTYPEB_ID_NAME         = 0x14,
+    ETCHTYPEB_FIELD           = 0x15,
+    ETCHTYPEB_TYPE            = 0x16,
+    ETCHTYPEB_STRUCTVAL       = 0x17,
+    ETCHTYPEB_ARRAYVAL        = 0x18,
+    ETCHTYPEB_VALUEFACTORY    = 0x19,
+    ETCHTYPEB_VALUEFACTOBJ    = 0x1a,
+    ETCHTYPEB_VALUEFACTIMP    = 0x1b,
+    ETCHTYPEB_MESSAGE         = 0x1c,
+    ETCHTYPEB_TAGDATA         = 0x1d,
+    ETCHTYPEB_TAGDATAINP      = 0x1e,
+    ETCHTYPEB_TAGDATAOUT      = 0x1f,
+    ETCHTYPEB_TDIOBJ          = 0x20,
+    ETCHTYPEB_TDOOBJ          = 0x21,
+    ETCHTYPEB_ARRAYELEMENT    = 0x22,
+    ETCHTYPEB_STRUCTELEMENT   = 0x23,
+    ETCHTYPEB_INSTANCEDATA    = 0x24,
+    ETCHTYPEB_COLLECTION      = 0x25,
+    ETCHTYPEB_LINKLIST        = 0x26,
+    ETCHTYPEB_ITERATOR        = 0x27,
+    ETCHTYPEB_RESULT          = 0x28,
+    ETCHTYPEB_PRIMITIVE       = 0x29,
+    ETCHTYPEB_DATE            = 0x2a,
+    ETCHTYPEB_URL             = 0x2b,
+    ETCHTYPEB_XPORTFACT       = 0x2c,
+    ETCHTYPEB_CONNECTION      = 0x2d,
+    ETCHTYPEB_TCPSERVER       = 0x2e,
+    ETCHTYPEB_TCPCLIENT       = 0x2f,
+    ETCHTYPEB_SOCKET          = 0x30,
+    ETCHTYPEB_FLEXBUF         = 0x31,
+    ETCHTYPEB_WHO             = 0x32,
+    ETCHTYPEB_ARRAYLIST       = 0x33, 
+    ETCHTYPEB_BINARYTDI       = 0x34,
+    ETCHTYPEB_BINARYTDO       = 0x35,
+    ETCHTYPEB_IDNAMEIMPL      = 0x36,
+    ETCHTYPEB_SERIALIZER      = 0x37,
+    ETCHTYPEB_FORMATFACT      = 0x38,
+    ETCHTYPEB_VALIDATOR       = 0x39,
+    ETCHTYPEB_NATIVEARRAY     = 0x3a, 
+    ETCHTYPEB_SESSIONMSG      = 0x3b,
+    ETCHTYPEB_TRANSPORTMSG    = 0x3c,
+    ETCHTYPEB_SESSIONDATA     = 0x3d,
+    ETCHTYPEB_SESSIONPKT      = 0x3e,
+    ETCHTYPEB_SESSIONLXR      = 0x3f,
+    ETCHTYPEB_DEFAULT_VF      = 0x40,
+    ETCHTYPEB_DEFAULT_VFOBJ   = 0x41,
+    ETCHTYPEB_DEFAULT_VFIMP   = 0x42,
+    ETCHTYPEB_THREAD          = 0x43,
+    ETCHTYPEB_THREADPOOL      = 0x44,
+    ETCHTYPEB_MUTEX           = 0x45,
+    ETCHTYPEB_THREADPARAMS    = 0x46,
+    ETCHTYPEB_WAIT            = 0x47, 
+    ETCHTYPEB_OBJSESSION      = 0x48,
+    ETCHTYPEB_MSGHANDLER      = 0x49,
+    ETCHTYPEB_SOURCE          = 0x4a,
+    ETCHTYPEB_SOURCEHDLR      = 0x4b,
+    ETCHTYPEB_MSGSOURCE       = 0x4c,
+    ETCHTYPEB_PACKETIZER      = 0x4d,
+    ETCHTYPEB_MESSAGIZER      = 0x4e,
+    ETCHTYPEB_PACKETHANDLER   = 0x4f,
+    ETCHTYPEB_ETCHLIST        = ETCHTYPEB_ARRAYLIST,
+    ETCHTYPEB_ETCHMAP         = ETCHTYPEB_HASHTABLE,
+    ETCHTYPEB_ETCHSET         = 0x50,
+    ETCHTYPEB_ETCHQUEUE       = 0x51,
+    ETCHTYPEB_UNUSED1         = 0x52,
+    ETCHTYPEB_SERVERIMPL      = 0x53,
+    ETCHTYPEB_EVENT           = 0x54,
+    ETCHTYPEB_MAILBOX         = 0x55,
+    ETCHTYPEB_MBOX_ELEMENT    = 0x56,
+    ETCHTYPEB_MBOX_MANAGER    = 0x57,
+    ETCHTYPEB_MBOXMGR_IMPL    = 0x58,
+    ETCHTYPEB_MAILBOXINT      = 0x59,
+    ETCHTYPEB_TRANSPORTDATA   = 0x5b,
+    ETCHTYPEB_TRANSPORTPKT    = 0x5c,
+    ETCHTYPEB_DELIVERYSVC     = 0x5d,
+    ETCHTYPEB_DELIVERYSVCINT  = 0x5e,
+    ETCHTYPEB_DELIVERYSVC_IMPL= 0x5f,
+    ETCHTYPEB_SERVERFACT      = 0x60,
+    ETCHTYPEB_CLIENTFACT      = 0x61,
+    ETCHTYPEB_SERVERFACT_IMPL = 0x62,
+    ETCHTYPEB_CLIENTFACT_IMPL = 0x63,
+    ETCHTYPEB_SVCINTERFACE    = 0x64,
+    ETCHTYPEB_EXESERVERBASE   = 0x66,
+    ETCHTYPEB_EXESERVERIMPL   = 0x67,
+    ETCHTYPEB_EXECLIENTBASE   = 0x68,
+    ETCHTYPEB_EXECLIENTIMPL   = 0x69,
+    ETCHTYPEB_REMOTE          = 0x6a,
+    ETCHTYPEB_REMOTECLIENT    = 0x6b,
+    ETCHTYPEB_REMOTESERVER    = 0x6c,
+    ETCHTYPEB_CLIENT_SESSION  = 0x74,
+    ETCHTYPEB_STUB            = 0x70,
+    ETCHTYPEB_CLIENTSTUB      = 0x71,
+    ETCHTYPEB_SERVERSTUB      = 0x72,
+    ETCHTYPEB_FACTORYPARAMS   = 0x73,
+
+    ETCHTYPEB_EODMARK         = 0x7f,
+
+    ETCHTYPEB_DYNAMIC         = 0x80,
+
+    ETCHTYPEB_USER            = 0xa0,
+
+}  objtype_b;
+
+const char* etch_object_type_get_name(objtype_b type);
+
+/** 
+ * class IDs
+ */
+typedef enum etch_classid
+{   
+    CLASSID_NONE               = 0x0, 
+    CLASSID_ANY                = 0x0, 
+    CLASSID_UNWRAPPED          = 0x0, 
+    CLASSID_PRIMITIVE_BYTE     = 0x1, /* primitive class IDs must start at 1 */
+    CLASSID_PRIMITIVE_BOOL     = 0x2,  
+    CLASSID_PRIMITIVE_INT8     = 0x3,
+    CLASSID_PRIMITIVE_INT16    = 0x4,
+    CLASSID_PRIMITIVE_INT32    = 0x5,
+    CLASSID_PRIMITIVE_INT64    = 0x6,
+    CLASSID_PRIMITIVE_FLOAT    = 0x7,
+    CLASSID_PRIMITIVE_DOUBLE   = 0x8,
+    CLASSID_STRING             = 0x9,
+    CLASSID_DATE               = 0xa,
+    CLASSID_OBJECT             = 0xf,
+    CLASSID_DEF_VF             = 0x10,  
+    CLASSID_DEF_VF_OBJ         = 0x11,  
+    CLASSID_DEF_VF_IMPL        = 0x12,  
+    CLASSID_DEF_VF_VTAB        = 0x13, 
+    CLASSID_BINARYTDI_VTAB     = 0x14,
+    CLASSID_BINARYTDO_VTAB     = 0x15,
+    CLASSID_TAGDATA            = 0x16,
+    CLASSID_BINARYTDI          = 0x17,
+    CLASSID_BINARYTDO          = 0x18,
+    CLASSID_ETCHMESSAGE        = 0x1a,
+    CLASSID_HASHTABLE          = 0x1b,
+    CLASSID_ETCH_MAP           = CLASSID_HASHTABLE,
+    CLASSID_HASHTABLE_VTAB     = 0x20, 
+    CLASSID_ITERABLE_VTAB      = 0x21, 
+    CLASSID_ITERATOR           = 0x22, 
+    CLASSID_ID_NAME            = 0x23, 
+    CLASSID_ID_FIELD           = 0x24, 
+    CLASSID_ID_TYPE            = 0x25, 
+    CLASSID_TDI_VTAB           = 0x26,
+    CLASSID_TDO_VTAB           = 0x27,
+    CLASSID_BINTDI_VTAB        = 0x28,
+    CLASSID_BINTDO_VTAB        = 0x29,
+    CLASSID_AVAILABLE_VTAB     = 0x2a,
+    CLASSID_TYPEIMPL           = 0x2b,
+    CLASSID_VTAB_FIELD         = 0x2c,
+    CLASSID_VTAB_TYPE          = 0x2d,
+    CLASSID_ETCH_ARRAYLIST     = 0x2e,
+    CLASSID_ETCH_LIST          = CLASSID_ETCH_ARRAYLIST,
+    CLASSID_ETCH_SET           = 0x2f,
+    CLASSID_STRUCTVALUE        = 0x30,
+    CLASSID_ARRAYVALUE         = 0x31,
+    CLASSID_ARRAYELEMENT       = 0x32,
+    CLASSID_VALUEFACTORY       = 0x33,
+    CLASSID_TAGDATAINP         = 0x34,
+    CLASSID_TAGDATAOUT         = 0x35,
+    CLASSID_EXCEPTION          = 0x36,
+    CLASSID_THREAD             = 0x39,
+    CLASSID_THREADPOOL         = 0x3a,
+    CLASSID_MUTEX              = 0x3b,
+    CLASSID_WAIT               = 0x3c,
+    CLASSID_STUB               = 0x3d,
+    CLASSID_SERVERIMPL         = 0x3e,
+    CLASSID_MSGSOURCE          = 0x3f,
+    CLASSID_MESSAGIZER         = 0x40,
+    CLASSID_MSGHANDLER         = 0x41,
+    CLASSID_SOURCE             = 0x42,
+    CLASSID_SOURCEHDLR         = 0x43,
+    CLASSID_URL                = 0x49,
+    CLASSID_PACKETIZER         = 0x4a,
+    CLASSID_PACKETHANDLER      = 0x4b,
+    CLASSID_FLEXBUF            = 0x4e,
+    CLASSID_WHO                = 0x4f,
+    CLASSID_ARRAY_OBJECT       = 0x50,
+    CLASSID_ARRAY_BYTE         = 0x51,
+    CLASSID_ARRAY_BOOL         = 0x52,
+    CLASSID_ARRAY_INT8         = 0x53,
+    CLASSID_ARRAY_INT16        = 0x54,
+    CLASSID_ARRAY_INT32        = 0x55,
+    CLASSID_ARRAY_INT64        = 0x56,
+    CLASSID_ARRAY_FLOAT        = 0x57,
+    CLASSID_ARRAY_DOUBLE       = 0x58,
+    CLASSID_ARRAY_STRING       = 0x59,
+    CLASSID_ARRAY_STRUCT       = 0x5a,
+    CLASSID_ETCHQUEUE          = 0x5b,
+    CLASSID_ETCHSOCKET         = 0x5c,
+    CLASSID_CLIENT_SESSION     = 0x5d,
+    CLASSID_UNUSED_1           = 0x5e,
+    CLASSID_XPORTFACT          = 0x5f,
+    CLASSID_FORMATFACT         = 0x60,
+    CLASSID_FORMATFACT_BINARY  = 0x61,
+    CLASSID_FORMATFACT_XML     = 0x62,
+    CLASSID_TCP_CONNECTION     = 0x63,  
+    CLASSID_TCP_LISTENER       = 0x64, 
+    CLASSID_TCP_CLIENT         = 0x65, 
+    CLASSID_SOCKET             = 0x66,
+    CLASSID_UNUSED_2           = 0x67,
+    CLASSID_UNUSED_3           = 0x68,
+    CLASSID_SESSIONMSG         = 0x69,
+    CLASSID_TRANSPORTMSG       = 0x6a,
+    CLASSID_TRANSPORTPKT       = 0x6b,
+    CLASSID_SESSIONDATA        = 0x6c,
+    CLASSID_TRANSPORTDATA      = 0x6d,
+    CLASSID_SESSIONPKT         = 0x6e,
+    CLASSID_SESSIONLXR         = 0x6f,
+    CLASSID_VALIDATOR          = 0x70,
+    CLASSID_COMBO_VALIDATOR    = 0x71,
+    CLASSID_VALIDATOR_BOOL     = 0x72, 
+    CLASSID_VALIDATOR_BYTE     = 0x73, 
+    CLASSID_VALIDATOR_INT8     = 0x74, 
+    CLASSID_VALIDATOR_INT16    = 0x75, 
+    CLASSID_VALIDATOR_INT32    = 0x76, 
+    CLASSID_VALIDATOR_INT64    = 0x77, 
+    CLASSID_VALIDATOR_FLOAT    = 0x78, 
+    CLASSID_VALIDATOR_DOUBLE   = 0x79, 
+    CLASSID_VALIDATOR_STRING   = 0x7a,
+    CLASSID_VALIDATOR_OBJECT   = 0x7b,
+    CLASSID_VALIDATOR_EXCEPTION= 0x7c,
+    CLASSID_VALIDATOR_STRUCT   = 0x7d,
+    CLASSID_VALIDATOR_EOD      = 0x7e,
+    CLASSID_VALIDATOR_CUSTOM   = 0x7f,
+
+    CLASSID_RUNTIME_EXCEPTION  = 0x80, 
+    CLASSID_AUTH_EXCEPTION     = 0x81,
+    CLASSID_SERIALIZER_EXCP    = 0x82, 
+    CLASSID_SERIALIZER_RTXCP   = 0x83,
+    CLASSID_SERIALIZER_AUTHXCP = 0x84,
+    CLASSID_SERIALIZER_LIST    = 0x85,
+    CLASSID_SERIALIZER_MAP     = 0x86,
+    CLASSID_SERIALIZER_SET     = 0x87,
+    CLASSID_SERIALIZER_DATE    = 0x88,
+
+    CLASSID_EVENT_UNWANTMSG    = 0x90,
+    CLASSID_MAILBOX            = 0x91,
+    CLASSID_MAILBOXINT         = 0x92,
+    CLASSID_MBOX_ELEMENT       = 0x93,
+    CLASSID_PLAIN_MAILBOX      = 0x94,
+    CLASSID_MBOX_MANAGER       = 0x95,
+    CLASSID_PLAIN_MBOXMGR      = 0x96,
+    CLASSID_DELIVERYSVC        = 0x97,
+    CLASSID_TCP_DELIVERYSVC    = 0x98,
+    CLASSID_CLIENTSTUB         = 0x99,
+    CLASSID_SERVERSTUB         = 0x9a,
+    CLASSID_SERVERFACTORY      = 0x9b,
+    CLASSID_CLIENTFACTORY      = 0x9c,
+
+    CLASSID_TCP_XPORTFACT      = 0xb0,
+    CLASSID_SERVERFACT         = 0xb1,
+    CLASSID_CLIENTFACT         = 0xb2,
+    CLASSID_EXECLIENT_IMPL     = 0xb3,
+    CLASSID_EXECLIENTBASE_IMPL = 0xb4,
+    CLASSID_EXESERVER_IMPL     = 0xb5,
+    CLASSID_EXESERVERBASE_IMPL = 0xb6,
+
+    CLASSID_CONTROL_START         = 0x101, 
+    CLASSID_CONTROL_START_WAITUP  = 0x102, 
+    CLASSID_CONTROL_STOP          = 0x103, 
+    CLASSID_CONTROL_STOP_WAITDOWN = 0x104, 
+    CLASSID_WAITUP                = 0x105,
+    CLASSID_WAITDOWN              = 0x106, 
+ 
+    CLASSID_QUERY_IS_UP           = 0x110, 
+    CLASSID_QUERY_LOCALADDR       = 0x111, 
+    CLASSID_QUERY_REMOTEADDR      = 0x112, 
+    CLASSID_QUERY_WAITUP          = 0x113, 
+    CLASSID_QUERY_WAITDOWN        = 0x114, 
+
+    CLASSID_DYNAMIC_START         = 0x400, 
+
+} etch_classid;
+
+/*
+ * ranges of numeric types 
+ */
+#define ETCHTYPE_MIN_TINY   ((signed char)(0xc0))      /* -64 */
+#define ETCHTYPE_MAX_TINY   ((signed char)(0x7f))      /* 127 */
+#define ETCHTYPE_MIN_BYTE   ((signed char)(0x80))      /* -128 (-(2^7))  */
+#define ETCHTYPE_MAX_BYTE   ((signed char)(0x7f))      /* 127  ((2^7)-1) */
+#define ETCHTYPE_MIN_INT16  ((signed short)(0x8000))   /* -65536 (-(2^15))  */
+#define ETCHTYPE_MAX_INT16  ((signed short)(0x7fff))   /* 65535  ((2^15)-1) */
+#define ETCHTYPE_MIN_INT32  ((signed int)(0x80000000)) /* (-(2^31))  */
+#define ETCHTYPE_MAX_INT32  ((signed int)(0x7fffffff)) /* ((2^31)-1) */
+#define ETCHTYPE_MIN_INT64  ((signed long long)(0x8000000000000000LL))  /* (-(2^63))  */ 
+#define ETCHTYPE_MAX_INT64  ((signed long long)(0x7fffffffffffffffLL))  /* ((2^63)-1) */ 
+#define ETCHTYPE_MIN_FLOAT  (1.4e-45f) 
+#define ETCHTYPE_MAX_FLOAT  (3.40282346e+38f)  
+#define ETCHTYPE_MIN_DOUBLE (4.9e-324) 
+#define ETCHTYPE_MAX_DOUBLE (1.7976931348623157e+308) 
+
+#define is_inrange_bool(n) (n == 0 || n == 1)
+#define is_inrange_tiny(n) (n >= ETCHTYPE_MIN_TINY  && n <= ETCHTYPE_MAX_TINY)
+#define is_inrange_tiny_for_signed_chars(n) (n >= ETCHTYPE_MIN_TINY)
+#define is_inrange_byte(n) (n >= ETCHTYPE_MIN_BYTE  && n <= ETCHTYPE_MAX_BYTE)
+#define is_inrange_int8(n) (n >= ETCHTYPE_MIN_BYTE  && n <= ETCHTYPE_MAX_BYTE)
+#define is_inrange_int16(n)(n >= ETCHTYPE_MIN_INT16 && n <= ETCHTYPE_MAX_INT16)
+#define is_inrange_int32(n)(n >= ETCHTYPE_MIN_INT32 && n <= ETCHTYPE_MAX_INT32)
+#define is_inrange_int64(n)(n >= ETCHTYPE_MIN_INT64 && n <= ETCHTYPE_MAX_INT64)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* ETCHOBJTYPES_H */ 
diff --git a/binding-c/runtime/c/include/etch_packetizer.h b/binding-c/runtime/c/include/etch_packetizer.h
new file mode 100644
index 0000000..f7fa2b7
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_packetizer.h
@@ -0,0 +1,147 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_packetizer.h
+ * packetizes a stream data source. Reads a packet header: 32-bit flag 
+ * and 32-bit length, both big-endian, verifies the flag, using length from
+ * header, reads packet data and forwards it to the packet handler.
+ * as a packet source, accepts a packet and prepends a packet header to it 
+ * prior to delivering it to a data source.
+ */
+
+#ifndef ETCHPACKETIZER_H
+#define ETCHPACKETIZER_H
+
+#include "apr_thread_proc.h"
+#include "etch_session_data.h"
+#include "etch_transport_packet.h"
+#include "etch_transport_data.h"
+#include "etch_session_packet.h"
+#include "etch_arraylist.h"
+#include "etch_resources.h"
+#include "etch_flexbuffer.h"
+#include "etch_thread.h"
+#include "etch_mutex.h"
+#include "etch_url.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCHPZR_HAS_MUTEX FALSE
+
+#if(0)
+
+ PACKETIZER(TRANSPORTDATA)
+ |  transportData* transport;
+ |  sessionData(from, buf);      // override  i_sessiondata
+ |  transportPacket(to, buf);    // implement i_transportpacket
+  - SESSIONDATA
+ |  |  int sessionData (whofrom, buffer);
+ |   - SESSION
+ |        sessionQuery(); sessionControl(); sessionNotify();
+  - TRANSPORTPACKET  
+    |  int transportPacket(to, buffer);
+    |  int headerSize;
+     - TRANSPORT
+          transportQuery(); transportControl(); transportNotify();
+#endif
+
+const wchar_t* ETCH_PKTIZER_MAX_PKT_SIZE_TERM;
+const int ETCH_PKTIZER_DEFMAXPKTSIZE;
+const int ETCH_PKTIZER_HEADERSIZE;
+const int ETCH_PKTIZER_SIG;
+
+struct etch_packetizer;
+
+/*
+ * etch_packetizer
+ */
+typedef struct etch_packetizer
+{
+    etch_object object;
+
+    /* transport of next lower layer of the stack (connection) */
+    i_transportdata*   transport;   /* not owned */
+
+   /* session of next higher layer of the stack (messagizer) */
+    i_sessionpacket*   session;     /* not owned */
+
+    /* - - - - - - - - - - - - - - -
+     * i_transportpacket
+     * - - - - - - - - - - - - - - -
+     */
+
+    /**
+     * i_transportpacket::transport_packet()
+     * delivers packet to the transport after adding packet header.
+     * @param to recipient
+     * @param buf flexbuffer positioned on the packet and including space for header.
+     * @return 0 success, -1 error
+     */
+    etch_transport_packet  transport_packet;  /* transport_packet() */
+    i_transportpacket* transportpkt;          /* owned */
+    etch_transport_control transport_control; /* i_transportmessage::itransport */
+    etch_transport_notify  transport_notify;  /* i_transportmessage::itransport */
+    etch_transport_query   transport_query;   /* i_transportmessage::itransport */
+    etch_transport_get_session  get_session;  /* i_transportmessage::itransport */
+    etch_transport_set_session  set_session;  /* i_transportmessage::itransport */
+
+    /* - - - - - - - - - - - - - - -
+     * i_sessiondata
+     * - - - - - - - - - - - - - - -
+     */
+
+    /**
+     * i_sessiondata::session_data()
+     * delivers data to the session from the transport
+     * @param from from who sent the packet data
+     * @param buffer the packet from the packet source positioned at the data
+     * @return 0 success, -1 error
+     */ 
+    etch_session_data    session_data;     /* session_data() */  
+    i_sessiondata*       sessiondata;      /* owned */ 
+    etch_session_control session_control;  /* i_sessionpacket::isession */
+    etch_session_notify  session_notify;   /* i_sessionpacket::isession */
+    etch_session_query   session_query;    /* i_sessionpacket::isession */
+
+    int (*process_header) (struct etch_packetizer*, etch_flexbuffer*, const int is_reset);
+
+    etch_mutex_t* datalock;
+
+    etch_flexbuffer* savebuf;  /* owned */
+
+    size_t headersize;
+    size_t bodylength;
+    size_t maxpacketsize;
+    unsigned char is_wantheader; /* logic state flag: set true in ctor */
+
+} etch_packetizer;
+
+etch_packetizer* new_packetizer  (i_transportdata*, wchar_t* uri, etch_resources*);
+etch_packetizer* new_packetizer_a(i_transportdata*, etch_url*, etch_resources*);
+
+i_session*  etch_pktizer_get_session(void*); 
+int  etch_pktizer_process_header (etch_packetizer*, etch_flexbuffer*, const int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* ETCHPACKETIZER_H */
diff --git a/binding-c/runtime/c/include/etch_plain_mailbox.h b/binding-c/runtime/c/include/etch_plain_mailbox.h
new file mode 100644
index 0000000..be48833
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_plain_mailbox.h
@@ -0,0 +1,158 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_plainmailbox.h
+ * standard mailbox using a fixed size queue
+ */
+
+#ifndef ETCHPLAINMBOX_H
+#define ETCHPLAINMBOX_H
+
+#include "etch_mailbox.h"
+#include "etch_mailbox_manager.h"
+#include "etch_simpletimer.h"
+#include "etch_thread.h"
+#include "etch_queue.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MBOX_LIFETIME_UNTIL_CLOSE 0
+#define MBOX_DEFMAXMESSAGES 8
+#define ETCH_MAILBOX_RESULT_ALREADY_CLOSED 1
+
+#define ETCH_MAILBOX_STATE_INITIAL         0
+#define ETCH_MAILBOX_STATE_OPEN            2
+#define ETCH_MAILBOX_STATE_CLOSED_DELIVERY 4
+#define ETCH_MAILBOX_STATE_CLOSED_READ     6
+#define ETCH_MAILBOX_STATE_SHUTDOWN        8
+
+typedef etch_timer_callback etch_alarm_wakeup;
+
+#if(0)
+
+ PLAINMAILBOX(MAILBOXMANAGER) 
+ |- ALARMLISTENER
+ |  etch_alarm_wakeup()
+  - MAILBOX
+    | etch_mailbox_message() 
+    | etch_mailbox_read() 
+    | etch_mailbox_read_withwait()
+    | etch_mailbox_close_delivery()
+    | etch_mailbox_close_read()
+    | etch_mailbox_register_notify()
+    | etch_mailbox_unregister_notify()
+    | etch_mailbox_is_empty()
+    | etch_mailbox_is_closed()
+    | etch_mailbox_is_full()
+    | etch_mailbox_get_message_id()
+     -
+#endif
+
+struct i_mailbox_manager;
+
+/*
+ * etch_plainmailbox
+ * this object is instantiated, and is also a mask over any other mailbox
+ * class object which may be defined. etch_plainmailbox is therefore
+ * typedef'ed below as etch_mailbox.
+ */
+typedef struct etch_plainmailbox
+{
+    etch_object object;
+
+    void* impl;
+    struct i_mailbox_manager* manager;
+
+    /* - - - - - - - - - - - - - - -
+     * notify interface
+     * - - - - - - - - - - - - - - -
+     */
+    etch_mailbox_notify notify;  
+
+    /* - - - - - - - - - - - - - - -
+     * alarm listener interface
+     * - - - - - - - - - - - - - - -
+     */
+    etch_alarm_wakeup wakeup;
+
+    /* - - - - - - - - - - - - - - -
+     * i_mailbox interface
+     * - - - - - - - - - - - - - - -
+     */
+    i_mailbox* imailbox;
+
+    etch_mailbox_message           message;
+    etch_mailbox_read              read;
+    etch_mailbox_read_withwait     read_withwait;
+    etch_mailbox_close_delivery    close_delivery;
+    etch_mailbox_close_read        close_read;
+    etch_mailbox_register_notify   register_notify;
+    etch_mailbox_unregister_notify unregister_notify;
+    etch_mailbox_is_empty          is_empty;
+    etch_mailbox_is_closed         is_closed;
+    etch_mailbox_is_full           is_full;
+    etch_mailbox_get_message_id    get_message_id; 
+
+    /* - - - - - - - - - - - - - - -
+     * etch_mailbox instance data
+     * - - - - - - - - - - - - - - -
+     */
+    int   lifetime;
+    int   max_messages;
+    int   max_message_delay;
+    int64 message_id;
+    etch_queue* queue;  
+    etch_timer* lifetimer;
+    etch_mutex*  rwlock;    /* global read write lock - not owned */
+    etch_mutex*  readlock;  /* unused - lose it */
+    etch_object* notify_state;
+
+    unsigned char is_alarm_set;
+    unsigned char mailbox_state;
+    unsigned char unused_a;
+    unsigned char unused_b;
+
+    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     * derivations must include all the above and define data following
+     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     */
+
+} etch_plainmailbox;
+
+etch_mailbox* new_mailbox
+ (  struct i_mailbox_manager*, 
+    const int64 message_id, 
+    const int max_msgdelay, 
+    const int lifetime, 
+    const int max_messages
+ );
+
+int etchmbox_contains_message(etch_mailbox*, etch_message*);
+int etchmbox_get_readlock (etch_plainmailbox*, const char*);
+int etchmbox_release_readlock (etch_plainmailbox*, const char*);
+int etchmbox_get_readlockex (etch_mutex*, const char*);
+int etchmbox_release_readlockex (etch_mutex*, const char*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* ETCHPLAINMBOX_H */
diff --git a/binding-c/runtime/c/include/etch_plain_mailbox_manager.h b/binding-c/runtime/c/include/etch_plain_mailbox_manager.h
new file mode 100644
index 0000000..6fad8ed
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_plain_mailbox_manager.h
@@ -0,0 +1,134 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */
+
+/*
+ * etch_plainmailboxmgr.h
+ * mailbox manager accepts packets for potential delivery to a mailbox or to an
+ * alternate message handler if an appropriate mailbox is not available. 
+ * a mailbox can be created on request keyed by the a message's ID.
+ */
+
+#ifndef ETCHPLAINMBOXMGR_H
+#define ETCHPLAINMBOXMGR_H
+
+#include "etch_mailbox_manager.h"
+#include "etch_resources.h"
+#include "etch_mutex.h"
+#include "etch_url.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCHMBMGR_DEFNUMMAILBOXES 8
+
+#if(0)
+
+ PLAINMAILBOXMGR 
+ |  register(mailbox)
+ |  unregister(mailbox)
+ |  unregisterAll();
+ |  getMailbox(messageID);
+  - MAILBOXMANAGER
+    |  transportCall(Who to, message)  
+    |  redeliver(Who from, message)
+    |  unregister(mailbox)
+    |- SESSIONMESSAGE<SessionData>
+    |  |  sessionMessage(Who from, message)  
+    |   - SESSION
+    |       sessionQuery(); sessionControl(); sessionNotify();
+     - TRANSPORTMESSAGE  
+       |  transportMessage(to, Message);
+        - TRANSPORT
+             transportQuery(); transportControl(); transportNotify();
+             getSession(); setSession();
+#endif
+
+/*
+ * etch_plainmailboxmgr
+ */
+typedef struct etch_plainmailboxmgr
+{
+    etch_object object;
+
+    int  max_delay;
+    etch_mutex* xlock;  /* owned - unused */
+    etch_mutex* rwlock; /* not owned */
+    etch_hashtable* mailboxes; /* owned */
+    unsigned char is_connection_up;
+
+    /* - - - - - - - - - - - - - - -
+     * i_mailbox_manager interface
+     * - - - - - - - - - - - - - - -
+     */
+    i_mailbox_manager*      imanager; /* owned */
+    etch_mbm_transport_call transport_call;
+    etch_mbm_redeliver      redeliver;
+    etch_mbm_unregister     unregister;
+
+    /* i_transportmessage of next lower layer (messagizer) */
+    i_transportmessage*     transport;  /* not owned */
+
+    /* i_sessionmessage of next higher layer (delivery service) */
+    i_sessionmessage*       session;    /* not owned */
+
+    /* - - - - - - - - - - - - - - -
+     * i_sessionmessage interface
+     * - - - - - - - - - - - - - - -
+     */
+    i_sessionmessage*    isessionmsg;  /* owned */
+    etch_session_message session_message;  
+    etch_session_control session_control;
+    etch_session_notify  session_notify;
+    etch_session_query   session_query;
+
+    /* - - - - - - - - - - - - - - -
+     * i_transportmessage interface
+     * - - - - - - - - - - - - - - -
+     */
+    i_transportmessage*    transportmsg;  /* owned */
+    etch_transport_message transport_message;
+    etch_transport_control transport_control;  
+    etch_transport_notify  transport_notify;   
+    etch_transport_query   transport_query;   
+    etch_transport_get_session  get_session;   
+    etch_transport_set_session  set_session;
+
+} etch_plainmailboxmgr;
+
+/**
+ * new_plain_mailbox_manager()
+ * etch_plainmailboxmgr constructor
+ * @param itm i_transportmessage interface object, caller retains ownership.
+ * @param uri url string, caller relinquishes ownership.
+ * @param resxmap caller retains ownership.
+ */
+etch_plainmailboxmgr* new_plain_mailbox_manager(i_transportmessage*, wchar_t* uri, etch_resources*, etch_mutex*); 
+
+i_mailbox* pmboxmgr_get_mailbox(etch_plainmailboxmgr*, etch_int64* msgid);
+
+int pmboxmgr_register_mailbox(etch_plainmailboxmgr*, i_mailbox*);
+int pmboxmgr_unregister_all(etch_plainmailboxmgr*); 
+etch_hashtable* new_pmboxmgr_mailboxmap();  
+int pmboxmgr_size(etch_plainmailboxmgr*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* ETCHPLAINMBOXMGR_H */
diff --git a/binding-c/runtime/c/include/etch_queue.h b/binding-c/runtime/c/include/etch_queue.h
new file mode 100644
index 0000000..fb8be61
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_queue.h
@@ -0,0 +1,93 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_queue.h
+ * synchronized FIFO queue 
+ */
+#ifndef ETCHQUEUE_H
+#define ETCHQUEUE_H
+
+#include "etch_object.h"
+#include "etch_thread.h"
+#include "etch_queue_apr.h"
+#include "etch_collection.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_DEFQSIZE 32
+
+#define ETCHQUEUE_CONTENT_SIMPLE 0  /* content memory freed as a unit */
+#define ETCHQUEUE_CONTENT_OBJECT 1  /* content is etchobject */
+
+#define ETCH_QUEUE_OPERATION_TIMEOUT  1
+#define ETCH_QUEUE_OPERATION_CANCELED 2
+#define ETCH_QUEUE_EOF                3
+
+#define ETCHQUEUE_NEEDLOCK TRUE   
+#define ETCHQUEUE_NOLOCK   FALSE
+
+typedef int (*queuecallback) (int, void*); /* queue callback signature */
+
+/** 
+ *  etch_queue
+ */
+typedef struct etch_queue   
+{
+    etch_object object;
+
+    etch_apr_queue_t* aprq;
+    unsigned short content_obj_type;  /* etch obj_type of a native value */
+    unsigned short content_class_id;  /* etch class_id of a native value */
+    unsigned int   qcapacity;
+
+    /* this object may be masked by etch_collection_mask to determine content
+     * type and class, so do not add any fields above this comment */
+
+    i_iterable    iterable;
+    apr_pool_t*   subpool;
+    queuecallback freehook;  
+    unsigned char is_readonly;  
+    unsigned char content_type;
+
+} etch_queue;
+
+
+etch_queue*   new_queue(const int initialsize);
+int etchqueue_put(etch_queue*, void* item);
+int etchqueue_try_put(etch_queue*, void* item);
+int etchqueue_put_withwait(etch_queue*, const int waitms, void* item);
+int etchqueue_get(etch_queue*, void** itemout);
+int etchqueue_try_get(etch_queue*, void** itemout);
+int etchqueue_get_withwait(etch_queue*, const int waitms, void** itemout);
+int etchqueue_notify_all(etch_queue*);
+int etchqueue_lock(etch_queue*);
+int etchqueue_unlock(etch_queue*);
+int etchqueue_trylock(etch_queue*);
+int etchqueue_size(etch_queue*);
+int etchqueue_is_closed(etch_queue*);
+int etchqueue_is_full(etch_queue*);
+int etchqueue_close(etch_queue*, const int is_needlock);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHQUEUE_H */
diff --git a/binding-c/runtime/c/include/etch_queue_apr.h b/binding-c/runtime/c/include/etch_queue_apr.h
new file mode 100644
index 0000000..f523feb
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_queue_apr.h
@@ -0,0 +1,89 @@
+/* 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.
+ */
+
+/*
+ * etch_queue_apr.h
+ * based on apr_queue, with timeouts added on push and pop waits.
+ */
+
+#ifndef ETCHQUEUEAPR_H
+#define ETCHQUEUEAPR_H
+
+#define ETCHQUEUE_CLEARING_CLOSED_QUEUE (-2)
+
+#include "etch_object.h"
+#include "apr_thread_cond.h"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** 
+ * etch_apr_queue_t
+ * same as the private apr_queue_t 
+ */
+typedef struct etch_apr_queue_t 
+{
+    void              **data;
+    unsigned int        nelts; /**< # elements */
+    unsigned int        in;    /**< next empty location */
+    unsigned int        out;   /**< next filled location */
+    unsigned int        bounds;/**< max size of queue */
+    unsigned int        full_waiters;
+    unsigned int        empty_waiters;
+    apr_thread_mutex_t *one_big_mutex;
+    apr_thread_cond_t  *not_empty;
+    apr_thread_cond_t  *not_full;
+    int                 terminated;
+
+} etch_apr_queue_t;
+
+
+apr_status_t etch_apr_queue_create(etch_apr_queue_t **queue, 
+    unsigned int queue_capacity, apr_pool_t *a);
+
+apr_status_t etch_apr_queue_push(etch_apr_queue_t *queue, 
+    apr_interval_time_t timeout, void *data);
+
+apr_status_t etch_apr_queue_pop(etch_apr_queue_t *queue, 
+    apr_interval_time_t timeout, void **data);
+
+apr_status_t etch_apr_queue_trypush(etch_apr_queue_t *queue, void *data);
+
+apr_status_t etch_apr_queue_trypop(etch_apr_queue_t *queue, void **data);
+
+unsigned int etch_apr_queue_size(etch_apr_queue_t*);
+
+apr_status_t etch_apr_queue_interrupt_all(etch_apr_queue_t*);
+
+apr_status_t etch_apr_queue_unsafe_interrupt_all(etch_apr_queue_t*);
+
+apr_status_t etch_apr_queue_term(etch_apr_queue_t *queue);
+
+apr_status_t etch_apr_queue_unsafeclose(etch_apr_queue_t*);
+
+apr_status_t etch_apr_queue_trylock(etch_apr_queue_t*);
+
+apr_status_t etch_apr_queue_lock(etch_apr_queue_t*);
+
+apr_status_t etch_apr_queue_unlock(etch_apr_queue_t*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHQUEUEAPR_H */
diff --git a/binding-c/runtime/c/include/etch_remote.h b/binding-c/runtime/c/include/etch_remote.h
new file mode 100644
index 0000000..8a917fc
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_remote.h
@@ -0,0 +1,64 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_remote.h
+ * remote base
+ */
+
+#ifndef ETCH_REMOTE_H
+#define ETCH_REMOTE_H
+
+#include "etch_object.h"
+#include "etch_thread.h"
+#include "etch_transport.h"
+#include "etch_session_message.h"
+#include "etch_svcobj_masks.h"
+#include "etch_message.h"
+#include "etch_default_value_factory.h"
+
+#define ETCH_REMOTETYPE_NONE   0
+#define ETCH_REMOTETYPE_CLIENT 1
+#define ETCH_REMOTETYPE_SERVER 2
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+xxxx_remote* new_etch_remote_base (void* thisx, const int objsize, 
+    const unsigned short class_id, i_delivery_service*, 
+    etch_value_factory*, etch_object*);
+
+int etchremote_start_waitup (void* data, const int waitms);
+int etchremote_stop_waitdown (void* data, const int waitms);
+int etchremote_transport_control (void* data, etch_event* evt, etch_object* value); /* value could be an etch_int32 */
+int etchremote_transport_notify  (void* data, etch_event* evt);
+etch_object* etchremote_transport_query (void* data, etch_query* query);
+etch_message* etchremote_new_message (void* data, etch_type* message_type);
+int etchremote_send (void* data, etch_message* msg);
+void* etchremote_sendex (void* data, etch_message* msg);
+int etchremote_begincall (void* data, etch_message* msg, void** out);
+int etchremote_endcall (void* data, i_mailbox* mbox, etch_type* response_type, void** out);
+
+int is_etch_remote(void* x);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_REMOTE_H */
diff --git a/binding-c/runtime/c/include/etch_resources.h b/binding-c/runtime/c/include/etch_resources.h
new file mode 100644
index 0000000..86e6632
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_resources.h
@@ -0,0 +1,64 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_resources.h
+ * resource map
+ * a string-to-etch-object-based hashtable
+ */
+
+#ifndef ETCHRESOURCES_H
+#define ETCHRESOURCES_H
+
+#include "etch_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define ETCH_RESOURCES_DEFSIZE 16
+
+extern const wchar_t* ETCH_RESXKEY_SOCKET;
+extern const wchar_t* ETCH_RESXKEY_ACCEPTED_CONX;
+extern const wchar_t* ETCH_RESXKEY_POOLTYPE_FREE;
+extern const wchar_t* ETCH_RESXKEY_POOLTYPE_QUEUED;
+extern const wchar_t* ETCH_RESXKEY_MSGIZER_FORMAT;
+extern const wchar_t* ETCH_RESXKEY_MSGIZER_VALUFACT;
+extern const wchar_t* ETCH_RESXVAL_XPORTFMT_BINARY;
+extern const wchar_t* ETCH_RESXVAL_XPORTFMT_XML;
+extern const wchar_t* ETCH_XFACTKEY_TCP;
+extern const wchar_t* ETCH_XPORTKEY_START;
+extern const wchar_t* ETCH_XPORTKEY_START_AND_WAIT_UP;
+extern const wchar_t* ETCH_XPORTKEY_IS_UP;
+extern const wchar_t* ETCH_XPORTKEY_STOP;
+extern const wchar_t* ETCH_XPORTKEY_STOP_AND_WAIT_DOWN;
+
+
+typedef etch_hashtable etch_resources;
+etch_resources* new_etch_resources (const int initialsize);
+etch_object* etch_resources_get (etch_resources*, const wchar_t* key);
+int etch_resources_add (etch_resources*, const wchar_t* key, etch_object* value);
+int etch_resources_replace (etch_resources*, const wchar_t* key, etch_object* value);
+int etch_resources_clear (etch_resources*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHRESOURCES_H */
diff --git a/binding-c/runtime/c/include/etch_runtime.h b/binding-c/runtime/c/include/etch_runtime.h
new file mode 100644
index 0000000..8aa8a0b
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_runtime.h
@@ -0,0 +1,92 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_runtime.h -- runtime methods.
+ */
+
+#ifndef _ETCH_RUNTIME_H_
+#define _ETCH_RUNTIME_H_
+
+#include "etch.h"
+#include "etch_config.h"
+#include "etch_log.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * malloc'ed global constants 
+ */
+typedef struct etch_global_constants
+{
+    wchar_t* etch_charsetname_us_ascii;
+    wchar_t* etch_charsetname_utf8;
+    wchar_t* etch_charsetname_utf16;
+
+    char* pctd; /* for "%d" sprintf mask */
+
+} etch_global_constants;
+
+
+// shutdown hook function
+typedef etch_status_t (*etch_runtime_shutdown_hook_func)();
+
+/**
+ * etch runtime mem abort function
+ */
+int etch_runtime_mem_abort(int retcode);
+
+/**
+ * initialize the etch runtime components.
+ */
+etch_status_t etch_runtime_initialize(etch_config_t* config);
+
+/**
+ * gets the runtime version.
+ */
+etch_status_t etch_runtime_get_version(uint16* major, uint16* minor, uint16* revision);
+
+/**
+ * gets the runtime configuration.
+ */
+etch_status_t etch_runtime_get_config(etch_config_t** config);
+
+/**
+ * gets the runtime logger.
+ */
+etch_status_t etch_runtime_get_logger(etch_log_t** logger);
+
+/**
+ * register callback function, witch will be called when
+ * the runtime shutdown.
+ */
+etch_status_t etch_runtime_shutdown_hook_add(etch_runtime_shutdown_hook_func);
+
+/**
+ * shutdown the etch runtime components
+ */
+etch_status_t etch_runtime_shutdown();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_RUNTIME_H */
diff --git a/binding-c/runtime/c/include/etch_serializer.h b/binding-c/runtime/c/include/etch_serializer.h
new file mode 100644
index 0000000..ce9ad25
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_serializer.h
@@ -0,0 +1,82 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_serializer.h 
+ * builtin custom type serializers
+ */
+
+#ifndef ETCH_SERIALIZER_H
+#define ETCH_SERIALIZER_H
+
+#include "etch_object.h"
+#include "etch_id_name.h"
+#include "etch_type.h"
+#include "etch_field.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* we restate typedefs stated elsewhere, here, 
+ * since we can't include those headers in this one.
+ */
+struct etch_hashtable;
+struct etch_validator;
+struct etch_serializer;
+typedef struct etch_serializer* (*etch_serializer_ctor) (etch_type*, etch_field*);
+
+
+/**
+ * etch_serializer
+ * import/export helper
+ */
+typedef struct etch_serializer
+{
+    etch_object object;
+
+    etch_object* impl;
+
+    etch_object* (*export_value) (struct etch_serializer* thisx, etch_object* objval); 
+  
+    etch_object* (*import_value) (struct etch_serializer* thisx, etch_object* structval); 
+
+    etch_id_name*  type;  /* not owned */
+    etch_id_name* field;  /* not owned */
+
+} etch_serializer;
+
+etch_serializer* new_etch_serializer(const int objsize);
+
+int etch_serializer_init(etch_type*, const wchar_t*, const unsigned, 
+    struct etch_hashtable*, struct etch_validator*, etch_serializer_ctor);
+
+int etch_serializer_exception_init(etch_type*, struct etch_hashtable* c2tmap);
+int etch_serializer_rtxcp_init    (etch_type*, struct etch_hashtable* c2tmap);
+int etch_serializer_authxcp_init  (etch_type*, struct etch_hashtable* c2tmap);
+int etch_serializer_list_init     (etch_type*, struct etch_hashtable* c2tmap);
+int etch_serializer_map_init      (etch_type*, struct etch_hashtable* c2tmap);
+int etch_serializer_set_init      (etch_type*, struct etch_hashtable* c2tmap);
+int etch_serializer_date_init     (etch_type*, struct etch_hashtable* c2tmap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_SERIALIZER_H */
diff --git a/binding-c/runtime/c/include/etch_session_data.h b/binding-c/runtime/c/include/etch_session_data.h
new file mode 100644
index 0000000..0c30528
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_session_data.h
@@ -0,0 +1,83 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sessiondata.h
+ * i_sessiondata interface
+ * interface used to deliver packets to the session from the transport
+ */
+#ifndef ETCHISESSIONDATA_H
+#define ETCHISESSIONDATA_H
+
+#if(0)
+
+ SESSIONDATA
+ |  int sessionData(Who from, buffer)  
+  - SESSION
+       sessionQuery(); sessionControl(); sessionNotify();
+ 
+#endif
+
+
+#include "etch_sessionint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*etch_session_data) (void* thisx, void* whofrom, void* buffer);
+
+
+/**
+ * i_sessiondata
+ * sessiondata interface
+ * a message handler delivers messages from a message source
+ */
+typedef struct i_sessiondata
+{
+    etch_object object;
+
+    void* thisx; /* object which is the interface implementor */
+
+    /* session interface */
+    i_session* isession;
+    etch_session_control session_control;
+    etch_session_notify  session_notify;
+    etch_session_query   session_query;
+
+    /**
+     * session_data()
+     * delivers packets to the session from the transport
+     * @param from whofrom who sent the message.
+     * caller relinquishes this object on success, retains on failure.
+     * @param buf the packet buffer from the packet source. 
+     * caller relinquishes this object on success, retains on failure.
+     * @return 0 success, -1 error
+     */
+    etch_session_data session_data;
+
+} i_sessiondata;
+
+
+i_sessiondata* new_sessiondata_interface(void* thisx, etch_session_data, i_session*); 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHISESSIONDATA_H */
diff --git a/binding-c/runtime/c/include/etch_session_listener.h b/binding-c/runtime/c/include/etch_session_listener.h
new file mode 100644
index 0000000..87948d2
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_session_listener.h
@@ -0,0 +1,132 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sessionmsg.h
+ * i_sessionmessage interface
+ * interface used to deliver messages to the session from the transport
+ */
+#ifndef ETCHISESSIONLISTEN_H
+#define ETCHISESSIONLISTEN_H
+
+#if(0)
+
+ SESSIONLISTENER
+ |  int sessionAccepted(socket)  
+  - SESSION
+       sessionQuery(); sessionControl(); sessionNotify();
+ 
+#endif
+
+#include "etch_sessionint.h"
+#include "etch_transportint.h"
+#include "etch_resources.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* session accepted interface */                          // 11/16
+typedef int (*etch_session_accepted) (void* thisx, void* acceptedconx);
+
+/* this is the signature that must be called from accept */ 
+/* this function is defined in servermain */
+typedef void* (*funcptr_new_impl_server) (void* thisx, void* remote_client);
+struct i_sessionlistener;
+
+typedef int (*etchlistener_waitexit) (struct i_sessionlistener*);
+
+/**
+ * i_server_factory
+ * server factory interface
+ */
+typedef struct i_server_factory
+{
+    etch_object object;
+
+    void* thisx;  /* object which is the interface implementor */
+    funcptr_new_impl_server new_server;  /* server constructor */
+
+    etch_object*   session;  /* not owned */  
+    i_session* isession; /* not owned */
+    etch_session_control session_control;
+    etch_session_notify  session_notify;
+    etch_session_query   session_query;
+
+} i_server_factory;
+
+
+/**
+ * i_sessionlistener
+ * sessionlistener interface
+ */
+typedef struct i_sessionlistener
+{
+    etch_object object;
+
+    void* thisx; /* object which is the interface implementor */
+
+    /* session interface */
+    void* session;           /* not owned */
+    i_session* isession;     /* may be owned or not */
+    etch_session_control   session_control;
+    etch_session_notify    session_notify;
+    etch_session_query     session_query;
+
+   /**
+     * session_accepted()
+     * delivers a socket to the session from the listener
+     * @param socket caller retains
+     * @return 0 success, -1 failure
+     */
+    etch_session_accepted session_accepted;
+
+    /* transport interface */
+    void* transport;             /* not owned */
+    i_transport* itransport;     /* may be owned or not */
+    /* these virtuals are proxied up to this level since [main] 
+     * does not see the specific transport header e.g. tcpserver */
+    etch_transport_control transport_control;
+    etch_transport_notify  transport_notify;
+    etch_transport_query   transport_query;
+    etch_transport_set_session set_session; 
+    etch_transport_get_session get_session; 
+
+    void* url;                  /* owned */
+    void* server_params;        /* owned */ 
+    etch_resources* resources;  /* owned */  
+    etchlistener_waitexit wait_exit;  /* listener thread exit wait */
+
+    unsigned char is_session_owned;
+    unsigned char is_transport_owned;
+    unsigned char is_resources_owned;
+    unsigned char unused;
+
+} i_sessionlistener;
+
+
+i_sessionlistener* new_sessionlistener_interface (void* thisx, etch_session_accepted, i_session*); 
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHISESSIONLISTEN_H */
diff --git a/binding-c/runtime/c/include/etch_session_message.h b/binding-c/runtime/c/include/etch_session_message.h
new file mode 100644
index 0000000..b8e6f56
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_session_message.h
@@ -0,0 +1,84 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sessionmsg.h
+ * i_sessionmessage interface
+ * interface used to deliver messages to the session from the transport
+ */
+#ifndef ETCHISESSIONMSG_H
+#define ETCHISESSIONMSG_H
+
+#if(0)
+
+ SESSIONMESSAGE
+ |  int sessionMessage(Who from, message)  
+  - SESSION
+       sessionQuery(); sessionControl(); sessionNotify();
+ 
+#endif
+
+
+#include "etch_sessionint.h"
+#include "etch_object.h"
+#include "etch_message.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*etch_session_message) (void* , etch_who* , etch_message* );
+
+
+/**
+ * i_sessionmessage
+ * sessionmessage interface
+ * a message handler delivers messages from a message source
+ */
+typedef struct i_sessionmessage
+{
+    etch_object object;
+
+    void* thisx; /* object which is the interface implementor */
+
+    /* session interface */
+    i_session* isession;
+    etch_session_control session_control;
+    etch_session_notify  session_notify;
+    etch_session_query   session_query;
+
+   /**
+     * session_message()
+     * delivers data to the session from the transport
+     * @param from whofrom who sent the message.
+     * caller relinquishes this object on success, retains on failure.
+     * @param message the message from the message source. 
+     * caller relinquishes this object on success, retains on failure.
+     * @return 0 success, -1 error
+     */
+    etch_session_message session_message;
+
+} i_sessionmessage;
+
+i_sessionmessage* new_sessionmsg_interface(void* thisx, etch_session_message sm, i_session* session); 
+ 
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHISESSIONMSG_H */
diff --git a/binding-c/runtime/c/include/etch_session_packet.h b/binding-c/runtime/c/include/etch_session_packet.h
new file mode 100644
index 0000000..8b3bb77
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_session_packet.h
@@ -0,0 +1,81 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sessionpkt.h
+ * i_sessionpacket interface
+ * interface used to deliver packets to the session from the transport
+ */
+#ifndef ETCHISESSIONPACKET_H
+#define ETCHISESSIONPACKET_H
+
+#if(0)
+
+ SESSIONPACKET
+ |  int sessionPacket(Who from, packet)  
+  - SESSION
+       sessionQuery(); sessionControl(); sessionNotify();
+ 
+#endif
+
+
+#include "etch_sessionint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*etch_session_packet) (void* thisx, void* whofrom, void* buffer);
+
+
+/**
+ * i_sessionpacket
+ * sessionpacket interface
+ */
+typedef struct i_sessionpacket
+{
+    etch_object object;
+
+    void* thisx; /* object which is the interface implementor */
+
+   /* session interface */
+    i_session* isession;
+    etch_session_control session_control;
+    etch_session_notify  session_notify;
+    etch_session_query   session_query;
+
+    /**
+     * session_packet()
+     * delivers data to the session from the transport.
+     * @param from whofrom who sent the packet
+     * @param packet the packet from the packet source 
+     * @return 0 OK, -1 buffer contents invalid.
+     */
+    etch_session_packet  session_packet;
+
+
+} i_sessionpacket;
+
+
+i_sessionpacket* new_sessionpkt_interface(void* thisx, etch_session_packet, i_session*); 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHISESSIONPACKET_H */
diff --git a/binding-c/runtime/c/include/etch_sessionint.h b/binding-c/runtime/c/include/etch_sessionint.h
new file mode 100644
index 0000000..311f7b7
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_sessionint.h
@@ -0,0 +1,129 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sessionint.h
+ * session interface
+ */
+#ifndef ETCHISESSION_H
+#define ETCHISESSION_H
+
+#include "etch_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char*   ETCHDSIF;
+#define ETCHEVT_SESSION_UP   0x80
+#define ETCHEVT_SESSION_DOWN 0x81
+
+/*
+ * the memory ownership contracts for control, notify, and query, are:
+ * caller relinquishes all arguments except of course the this pointer,
+ * regardless of outcome. it follows that only simple and temporal
+ * objects are passed as parameters.
+ */
+typedef int   (*etch_session_control)(void* thisx, etch_event* evt, etch_object* value);
+typedef int   (*etch_session_notify) (void* thisx, etch_event* evt);
+typedef etch_object* (*etch_session_query)  (void* thisx, etch_query* query);
+
+/**
+ * i_session
+ * session interface
+ * not an etch object, ergo no ->desroy(), no ->clone()
+ */
+typedef struct i_session
+{
+    etch_session_control session_control;
+    etch_session_notify  session_notify;
+    etch_session_query   session_query;
+
+    void* thisx;
+
+} i_session;
+
+/**
+ * i_session_mask
+ * mask over any implemented session interface
+ */
+typedef struct i_session_mask
+{
+    etch_object object;
+
+    void* thisx; /* object which is the interface implementor */
+
+    /* session interface */
+    i_session* isession;
+    etch_session_control session_control;
+    etch_session_notify  session_notify;
+    etch_session_query   session_query;
+
+    void* main_session_method;
+
+} i_session_mask;
+
+i_session* new_default_session_interface(void* thisx);
+i_session* new_session_interface(void* thisx, etch_session_control sc, etch_session_notify sn, etch_session_query sq);
+i_session* clone_session(void* thisx, const i_session*);
+
+/**
+ * i_objsession
+ * obj_session interface
+ * same interface, names changed to avoid collisions.
+ * not determined whether this is necessary in the c binding.
+ * not an etch object, ergo no ->destroy(), no ->clone()
+ */
+typedef struct i_objsession
+{
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    void* thisx;
+
+} i_objsession;
+
+/**
+ * etch_objsession_objinfo
+ * session methods parameter info struct
+ */
+typedef struct etch_objsession_objinfo
+{
+  etch_object*  obj;
+  etch_object*  resobj;
+  etch_object*  msg;
+  etch_who* whofrom;
+  char*     msg_aname;
+  etch_exception*     exception;
+  unsigned short obj_type;
+  unsigned short class_id;
+  unsigned char  is_message;
+  unsigned char  is_exception;
+
+} etch_objsession_objinfo;
+
+i_objsession* new_default_objsession_interface(void* thisx);
+i_objsession* new_objsession_interface(void* thisx, etch_session_control sc, etch_session_notify sn, etch_session_query sq);
+void etchsession_get_objinfo(etch_objsession_objinfo* objinfo, void* evt);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHISESSION_H */
diff --git a/binding-c/runtime/c/include/etch_simpletimer.h b/binding-c/runtime/c/include/etch_simpletimer.h
new file mode 100644
index 0000000..6dd627a
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_simpletimer.h
@@ -0,0 +1,84 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_simpletimer.h  
+ * thread-per-use one-shot relative timer
+ * this should be replaced with a timer pool implementation when development resources permit 
+ */
+
+#ifndef ETCH_SIMPLETIMER_H
+#define ETCH_SIMPLETIMER_H
+
+#include "apr_thread_proc.h"  /* must be included first */
+#include "etch_thread.h"       /* must be included second */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_TIMER_REASON_TIMEOUT     ETCH_TIMEOUT
+#define ETCH_TIMER_REASON_INTERRUPTED ETCH_INTERRUPTED
+#define ETCH_TIMER_REASON_ERROR       (-1)
+
+
+typedef etch_thread etch_timer;
+
+
+/**
+ * etch_timer_callback 
+ * signature of timer expiration callback.
+ * @param passthrudata user object passed to timer constructor.
+ * @param reason expiration reason 1 timeout, 0 signaled, -1 error.
+ */
+typedef void (*etch_timer_callback) (void* passthrudata, const int reason); 
+
+
+/**
+ * new_timer() 
+ * etch_timer constructor
+ * @param durationms timer duration in milliseconds.
+ * @param passthrudata user data to be returned in expiration callback.
+ * caller retains ownership of this memory.
+ * @param callback expiration callback void (*callback) (void*, int);
+ * in which creator's passthrudata is passed as the first parameter, and the timeout
+ * reason passed in parameter 2 (reason value 0 is signaled, 1 is timeout, -1 error).
+ * @return the timer object. caller owns this object but must not destroy it until 
+ * after the expiration callback has completed and returned.
+ */
+etch_timer* new_timer(const int durationms, void* passthrudata, etch_timer_callback);
+
+
+/**
+ * etch_timer_start() 
+ * start the specified timer. a timer must always be explicitly started.
+ */
+int etch_timer_start(etch_timer*);
+
+
+/**
+ * etch_timer_stop()
+ * signal specified timer to stop waiting and exit its thread. 
+ */
+int etch_timer_stop (etch_timer*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_SIMPLETIMER_H */
diff --git a/binding-c/runtime/c/include/etch_sourceint.h b/binding-c/runtime/c/include/etch_sourceint.h
new file mode 100644
index 0000000..2b0f2ea
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_sourceint.h
@@ -0,0 +1,75 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sourceint.h
+ * source interface
+ */
+#ifndef ETCHISOURCE_H
+#define ETCHISOURCE_H
+
+#include "etch_transportint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* (*etch_source_get_handler) (void* thisx);
+typedef void  (*etch_source_set_handler) (void* thisx, void* handler);
+
+
+/**
+ * i_source
+ * source interface
+ * common interface to sources of data, packets, or messages.
+ * models the various handlers' view of a communication channel
+ */
+typedef struct i_source
+{
+    etch_object object;
+
+    void* thisx; /* object which is the i_source */
+
+    /**
+     * get_handler(this) returns an object implementing i_sourcehandler
+     */
+    etch_source_get_handler get_handler;
+
+    /**
+     * set_handler(this, handler) expects an object implementing i_sourcehandler
+     */
+    etch_source_set_handler set_handler;
+
+    /**
+     * transport interface (query, control, notify), not an etch object
+     */
+    i_transport* itransport;
+
+} i_source;
+
+
+i_source* new_default_source_interface();
+
+i_source* new_source_interface(void* thisx,
+    etch_source_get_handler gh, etch_source_set_handler sh, i_transport* xp); 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHISOURCE_H */
diff --git a/binding-c/runtime/c/include/etch_structval.h b/binding-c/runtime/c/include/etch_structval.h
new file mode 100644
index 0000000..9d54de6
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_structval.h
@@ -0,0 +1,64 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_structval.h -- defines the etch_structvalue object.
+ * etch_structvalue is a typed map of key/value pairs, where type is an etch_type,
+ * a key is an etch_field, and value is an etch object. all values are the same 
+ * class, corresponding to the struct type.
+ */
+
+#ifndef ETCHSTRUCTVAL_H
+#define ETCHSTRUCTVAL_H
+
+#include "etch_msgutl.h"
+#include "etch_tagdata_inp.h"
+#include "etch_tagdata_out.h"
+#include "etch_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * etch_structvalue
+ */
+typedef struct etch_structvalue
+{
+    etch_object object;
+
+    etch_hashtable* items;       /* owned */
+    etch_type*      struct_type; /* not owned */
+
+} etch_structvalue;
+
+
+etch_structvalue* new_structvalue(etch_type*, const int initialsize);
+int structvalue_put     (etch_structvalue*, etch_field* key, etch_object* value);
+int structvalue_is_type (etch_structvalue*, etch_type*);
+etch_object* structvalue_get(etch_structvalue*, etch_field* key);
+etch_object* structvalue_remove(etch_structvalue*, etch_field* key); 
+etch_hashtable* new_structvalue_hashtable();
+int structvalue_count(etch_structvalue*);
+int destroy_structvalue(void* data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHSTRUCTVAL_H */ 
diff --git a/binding-c/runtime/c/include/etch_stub.h b/binding-c/runtime/c/include/etch_stub.h
new file mode 100644
index 0000000..5315b89
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_stub.h
@@ -0,0 +1,130 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_stub.h
+ * a translation of the java binding StubBase
+ */
+
+#ifndef ETCH_STUB_H
+#define ETCH_STUB_H
+
+#include "etch_object.h"
+#include "etch_thread.h"
+#include "etch_transport.h"
+#include "etch_session_message.h"
+#include "etch_message.h"
+#include "etch_default_value_factory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_STUBTYPE_NONE   0
+#define ETCH_STUBTYPE_CLIENT 1
+#define ETCH_STUBTYPE_SERVER 2
+
+/*
+ * etch_stub
+ * stub base quasi interface
+ */
+typedef struct etch_stub
+{
+    etch_object object;
+  
+    etch_object* obj;         /* concrete client or server object, not owned */
+    etch_object* stubobj;     /* stub xxxx_either_stub* container, not owned */
+    i_objsession* impl_callbacks; /* impl's session callbacks, not owned */
+    i_delivery_service* delivery_service;     /* not owned */
+
+    /* - - - - - - - - - -
+     * i_sessionmessage
+     * - - - - - - - - - - 
+     */
+    i_session*           isession;         /* owned by isessionmsg */
+    i_sessionmessage*    isessionmsg;      /* owned */
+    etch_session_message session_message; 
+    etch_session_control session_control;
+    etch_session_notify  session_notify;
+    etch_session_query   session_query;
+
+    /* TODO lose threadpools and delivery params, they are here */
+    etch_server_factory* params;           /* not owned */
+
+    unsigned char stub_type;
+    unsigned char is_implobj_owned;
+
+    /* session interface notes:
+     * the stub base itself implements i_sessionmessage and its associated
+     * i_session. the client or server implementor implements, or not, the 
+     * objession interface methods, which are the callbacks to which the 
+     * i_session calls will be forwarded, if present, to the implementation. 
+     * when we construct a stub, we copy the implementor's objsession* to 
+     * the stub's impl_callbacks member for convenience. so, the presence 
+     * of objession callbacks indicates the desire to have exceptions, etc.
+     * forwarded to the implementation.
+     */
+} etch_stub;
+
+
+/*
+ * etchstub_runparams
+ * parameters to a stub helper thread.
+ */
+typedef struct etchstub_runparams
+{
+    unsigned int        sig;    /* signature */
+    etch_stub*          stub;   /* stub's this pointer */
+    opaque_stubhelper   run;    /* stub helper function */
+    void*               server; /* i_xxx_server impl mask */
+    i_delivery_service* ds;
+    etch_who*           who;
+    etch_message*       msg;
+
+} etchstub_runparams;
+
+#define ETCH_STUBPARAMS_SIGNATURE 0xe1d2c3b4
+
+
+etch_stub* new_stub (void* thisx, unsigned char stubtype, 
+   i_delivery_service*, etch_threadpool* qp, etch_threadpool* fp);
+
+void* new_clientstub_init (void* implobj, const int bytelen, etch_object_destructor userdtor, 
+    i_delivery_service*, etch_threadpool* qp, etch_threadpool* fp, void*);  
+
+void* new_serverstub_init (void* implobj, const int bytelen, etch_object_destructor userdtor, 
+    i_delivery_service*, etch_threadpool* qp, etch_threadpool* fp, void*);  
+
+void* new_stubimpl_init (void* implobj, const int objsize, 
+      const unsigned char stubtype, etch_object_destructor userdtor,
+      i_delivery_service* ids, etch_threadpool* qp, etch_threadpool* fp, 
+      void* params);  
+
+int etchstub_validate_args (etch_stub*, i_delivery_service*, etch_message*, 
+    void* iclient, default_value_factory**, void** vfimpl, void** clientimpl);
+
+int etchstub_send_reply (etch_stub*, i_delivery_service*, 
+    etch_who*, etch_message*, etch_object*, boolean );
+
+int is_etch_stub(void*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_STUB_H */
diff --git a/binding-c/runtime/c/include/etch_svcobj_masks.h b/binding-c/runtime/c/include/etch_svcobj_masks.h
new file mode 100644
index 0000000..a4e10f3
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_svcobj_masks.h
@@ -0,0 +1,339 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_svcobj_masks.h
+ * masks over generated objects
+ */
+
+#ifndef ETCHSVCetch_objectS_H
+#define ETCHSVCetch_objectS_H
+
+#include "etch_transport.h"
+#include "etch_stub.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * i_xxx_server
+ * server base interface
+ * not instantiated, mask over a server base.
+ */
+typedef struct i_xxxx_server
+{
+    etch_object object;
+
+    etch_object* thisx;  /* xxxx_server_impl* */
+    etch_object* ixxxx;  /* service interface */
+    int session_id;
+    unsigned char is_service_interface_owned;
+    unsigned char unused[3];
+
+    /* - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     * methods and data specific to the service follow in the implementation
+     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     */
+
+} i_xxxx_server;
+
+
+
+/**
+ * i_xxxx_client
+ * xxxx client base interface
+ * this object is not instantiated, it is merely a mask over any
+ * i_xxxx_client object, where xxxx is the etch service
+ */
+typedef struct i_xxxx_client
+{
+    etch_object object;
+
+    etch_object* thisx;  /* xxxx_client_impl* */
+    etch_object* ixxxx;  /* service interface */ 
+    int server_id; 
+
+    /* - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     * methods and data specific to the service follow in the implementation
+     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     */
+
+} i_xxxx_client;
+
+
+
+/**
+ * i_xxxx_either
+ * mask over xxxx client base or xxxx_server_base
+ */
+typedef struct i_xxxx_either
+{
+    etch_object object;
+
+    etch_object* thisx;  /* xxxx_yyyy_impl* */
+    etch_object* ixxxx;  /* service interface */
+    int owner_id;
+
+    /* - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+} i_xxxx_either;
+
+
+/**
+ * xxxx_remote
+ * not instantiated, mask over any xxxx_remote object,
+ * where xxxx is the service name
+ */
+typedef struct xxxx_remote
+{
+    etch_object object;
+
+    etch_object*  ixxxx;           /* possibly owned */
+    i_delivery_service*  dsvc; /* not owned */
+    etch_value_factory*  vf;   /* not owned */
+    unsigned char  remote_type; /* client or server */
+    unsigned char  is_service_interface_owned;
+    unsigned short unused;      /* alignment */
+
+    etch_message* (*new_message) (void*, etch_type*);
+    int   (*send)   (void*, etch_message*);
+    void* (*sendex) (void*, etch_message*);
+    etch_delivsvc_begincall begin_call;  /* i_mailbox** out */
+    etch_delvisvc_endcall   end_call;    /* etch_object** out */
+
+    int (*start_waitup)  (void*, const int waitms);
+    int (*stop_waitdown) (void*, const int waitms);
+
+    /* - - - - - - - - - - - - -
+     * transport functionality
+     * - - - - - - - - - - - - -
+     */
+    etch_transport_control transport_control;  
+    etch_transport_notify  transport_notify;   
+    etch_transport_query   transport_query;   
+    etch_transport_get_session get_session;  
+    etch_transport_set_session set_session;  
+
+    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     * methods and data specific to the service follow in the implementation
+     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     */
+
+} xxxx_remote;
+
+typedef xxxx_remote etch_remote;
+
+
+
+/**
+ * xxxx_remote_client
+ * this object is not instantiated, it is merely a mask over any
+ * xxxx_remote_client object, where xxxx is the etch service
+ */
+typedef struct xxxx_remote_client
+{
+    etch_object object;
+
+    i_xxxx_client* xxxx_client_base;  /* owned */
+    xxxx_remote*   xxxx_remote_base;  /* owned */
+    etch_server_factory* server_factory; /* owned */
+    default_value_factory*  vf;       /* owned by base */
+    int session_id;
+
+    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     * methods and data specific to the service follow in the implementation
+     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     */
+
+} xxxx_remote_client;
+
+
+
+/**
+ * xxxx_remote_server
+ */
+typedef struct xxxx_remote_server
+{
+    etch_object object;
+
+    i_xxxx_server* server_base;  /* owned */
+    xxxx_remote*   remote_base;  /* owned */
+    etch_client_factory* client_factory; /* owned */
+    default_value_factory*  vf;  /* owned by base */
+    int server_id;
+ 
+    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     * methods and data specific to the service follow in the implementation
+     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     */
+
+} xxxx_remote_server;
+
+
+/**
+ * xxxx_remote_either
+ */
+typedef struct xxxx_remote_either
+{
+    etch_object object;
+
+    i_xxxx_either* either_base;    /* owned */
+    xxxx_remote*   remote_base;    /* owned */
+    void*          either_factory; /* owned */
+    default_value_factory*  vf;    /* owned by base */
+    int owner_id;
+
+} xxxx_remote_either;
+
+
+/**
+ * xxxx_either_stub
+ * mask over xxxx_client_stub or xxxx_server_stub
+ */
+typedef struct xxxx_either_stub
+{
+    etch_object object;
+
+    etch_stub*      stub_base;
+    int             owner_id;  /* e.g. session_id */   
+
+    int (*destroyex)(void*);   /* user memory destructor */
+
+} xxxx_either_stub;
+
+/**
+ * xxxx_server_impl
+ * this object is not instantiated, it is merely a mask over any
+ * xxxx_server_impl object, where xxxx is the etch service
+ */
+typedef struct xxxx_server_impl
+{
+    etch_object object;
+    i_xxxx_server*      server_base; /* owned */
+    etch_object*            ixxxx;       /* not owned */
+    xxxx_remote_client* client;      /* not owned */
+
+    int (*destroyex) (void*);  /* user memory destructor */
+
+    /* - - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;  /* owned by base */
+    /* note that iobjsession->thisx is set to this xxxx_server_impl* */
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     * methods and data specific to the service follow in the implementation
+     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     */
+
+} xxxx_server_impl;
+
+/**
+ * xxxx_client_impl
+ * this object is not instantiated, it is merely a mask over any
+ * xxxx_client_impl object, where xxxx is the etch service
+ */
+typedef struct xxxx_client_impl
+{
+    etch_object object;
+
+    i_xxxx_client*      client_base;  /* owned */
+    etch_object*            ixxxx;        /* not owned */
+    xxxx_remote_server* server;       /* not owned */
+
+    int (*destroyex) (void*);  /* user memory destructor */
+
+    /* - - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;  /* owned by base */
+    /* note that iobjsession->thisx is set to this perf_client_impl* */
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     * methods and data specific to the service follow in the implementation
+     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     */
+
+} xxxx_client_impl;
+
+
+/**
+ * xxxx_either_impl
+ * mask over any xxxx_client_impl or xxxx_server_impl
+ */
+typedef struct xxxx_either_impl
+{
+    etch_object object;
+
+    i_xxxx_either*  either_base;  /* owned */
+    etch_object*        ixxxx;        /* not owned */
+    xxxx_remote_either* either;   /* not owned */
+
+    int (*destroyex) (void*);  /* user memory destructor */
+
+    /* - - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;  /* owned by base */
+    /* note that iobjsession->thisx is set to this perf_client_impl* */
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+} xxxx_either_impl;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHSVCetch_objectS_H */
diff --git a/binding-c/runtime/c/include/etch_tagdata_inp.h b/binding-c/runtime/c/include/etch_tagdata_inp.h
new file mode 100644
index 0000000..945d7f0
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_tagdata_inp.h
@@ -0,0 +1,104 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_tagdata_inp.h
+ * tagged data input base class
+ */
+
+#ifndef ETCH_TAGDATA_INP_H
+#define ETCH_TAGDATA_INP_H
+
+#include "etch_msgutl.h"
+#include "etch_tagged_data.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct etch_message; 
+struct etch_structvalue;
+struct etch_arrayvalue;
+struct etch_flexbuffer;
+
+/**
+ * tagged_data_input
+ * tagged data input implementation
+ */
+typedef struct tagged_data_input
+{
+    etch_object object;
+
+    etch_object* impl;
+
+} tagged_data_input;
+
+
+/**
+ * i_tagged_data_input virtual function signatures
+ */
+typedef struct etch_message* (*etchtdi_start_message)(tagged_data_input*);  
+typedef struct etch_message* (*etchtdi_read_message) (tagged_data_input*, struct etch_flexbuffer*);  
+typedef int (*etchtdi_end_message) (tagged_data_input*, struct etch_message*); 
+ 
+typedef struct etch_structvalue*(*etchtdi_start_struct) (tagged_data_input*); 
+typedef struct etch_structvalue*(*etchtdi_read_struct)  (tagged_data_input*); 
+typedef int (*etchtdi_read_struct_element)       (tagged_data_input*, struct etch_struct_element*);  
+typedef int (*etchtdi_end_struct) (tagged_data_input*, struct etch_structvalue*); 
+
+typedef struct etch_arrayvalue* (*etchtdi_start_array)(tagged_data_input*);
+typedef struct etch_arrayvalue* (*etchtdi_read_array) (tagged_data_input*, struct etch_validator*);
+typedef int (*etchtdi_read_array_element)      (tagged_data_input*, ETCH_ARRAY_ELEMENT**);
+typedef int (*etchtdi_end_array)(tagged_data_input*, struct etch_arrayvalue*);
+
+
+/**
+ * i_tagged_data_input
+ * virtual function table for tagged data input
+ */
+struct i_tagged_data_input
+{
+    etch_object object;
+
+    etchparentinfo* inherits_from; 
+
+	etchtdi_start_message start_message;
+    etchtdi_read_message  read_message;
+	etchtdi_end_message   end_message;
+	etchtdi_start_struct  start_struct;
+    etchtdi_read_struct   read_struct;
+	etchtdi_end_struct    end_struct;
+	etchtdi_start_array   start_array;
+    etchtdi_read_array    read_array;
+	etchtdi_end_array     end_array;
+
+    tagdata_get_native_type_code  get_native_type_code;
+    tagdata_get_custom_structtype get_custom_structtype;
+    tagdata_check_value check_value;
+};
+
+typedef struct i_tagged_data_input i_tagged_data_input;
+
+
+tagged_data_input* new_tagged_data_input();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_TAGDATA_INP_H */
diff --git a/binding-c/runtime/c/include/etch_tagdata_out.h b/binding-c/runtime/c/include/etch_tagdata_out.h
new file mode 100644
index 0000000..d0b8035
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_tagdata_out.h
@@ -0,0 +1,94 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_tagdata_out.h
+ * tagged data output
+ */
+
+#ifndef ETCH_TAGDATA_OUT_H
+#define ETCH_TAGDATA_OUT_H
+
+#include "etch_msgutl.h"
+#include "etch_tagged_data.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct etch_message;
+struct etch_structvalue;
+struct etch_arrayvalue;
+struct etch_flexbuffer;
+
+/**
+ * tagged_data_output
+ * tagged data output implementation
+ */
+typedef struct tagged_data_output
+{
+    etch_object object;
+
+    etch_object* impl;
+} tagged_data_output;
+
+/**
+ * i_tagged_data_output virtual function signatures
+ */
+typedef int (*etchtdo_start_message)(tagged_data_output*, struct etch_message*);  
+typedef int (*etchtdo_write_message)(tagged_data_output*, struct etch_message*, struct etch_flexbuffer*);  
+typedef int (*etchtdo_end_message)  (tagged_data_output*, struct etch_message*); 
+ 
+typedef int (*etchtdo_start_struct) (tagged_data_output*, struct etch_structvalue*);  
+typedef int (*etchtdo_write_struct) (tagged_data_output*, struct etch_structvalue*); 
+typedef int (*etchtdo_end_struct)   (tagged_data_output*, struct etch_structvalue*); 
+
+typedef int (*etchtdo_start_array)  (tagged_data_output*, struct etch_arrayvalue*);
+typedef int (*etchtdo_write_array)  (tagged_data_output*, struct etch_arrayvalue*, struct etch_validator*); 
+typedef int (*etchtdo_end_array)    (tagged_data_output*, struct etch_arrayvalue*);
+
+
+/**
+ * i_tagged_data_output
+ */
+struct i_tagged_data_output
+{
+    etch_object object;
+
+    etchparentinfo* inherits_from; 
+
+    etchtdo_start_message   start_message;
+    etchtdo_write_message   write_message;
+    etchtdo_end_message     end_message;
+    etchtdo_start_struct    start_struct;
+    etchtdo_write_struct    write_struct;
+    etchtdo_end_struct      end_struct;
+    etchtdo_start_array     start_array;
+    etchtdo_write_array     write_array;
+    etchtdo_end_array       end_array;
+};
+
+typedef struct i_tagged_data_output i_tagged_data_output;
+
+tagged_data_output* new_tagged_data_output();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_TAGDATA_OUT_H */
diff --git a/binding-c/runtime/c/include/etch_tagged_data.h b/binding-c/runtime/c/include/etch_tagged_data.h
new file mode 100644
index 0000000..66045b4
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_tagged_data.h
@@ -0,0 +1,201 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_tagdata.h
+ * tagged data
+ */
+
+#ifndef ETCH_TAGDATA_H
+#define ETCH_TAGDATA_H
+
+#include "etch_object.h"
+#include "etch_type.h"
+#include "etch_validator.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct etch_arrayvalue;
+
+#define ETCH_BINTAGDATA_CURRENT_VERSION 3
+
+/** 
+ *  i_tagdata virtual function signatures
+ */
+typedef signed char (*tagdata_check_value) (etch_object* value);
+typedef signed char (*tagdata_get_native_type_code) (const unsigned short obj_type, const unsigned short class_id);
+typedef int  (*tagdata_get_native_type)(const signed char, etch_array_id_params*);
+typedef etch_type* (*tagdata_get_custom_structtype) (etch_object* thisx, const unsigned short obj_type, const unsigned short class_id);
+
+/** 
+ *  tagged data static function signatures
+ */
+struct etch_arrayvalue* etchtagdata_to_arrayvalue(etch_object* thisx, struct etch_nativearray* value, tagdata_get_native_type_code get_native_type_code);
+
+int  etchtagdata_adjust_small_value (const byte in, etch_object* value, signed char* out); 
+int  etchtagdata_validate_value(etch_object* valobj, struct etch_validator*, signed char* out);
+int  etchtagdata_get_number(etch_object* valobj, const double fminval, const double fmaxval,  int64* out);
+int  etchtagdata_get_double_number(etch_object* valobj, const double fmin, const double fmax, double* outd);
+int  etchtagdata_get_float_number(etch_object* valobj, const double fmin, const double fmax, float* outf);
+int  etchtagdata_bool_value  (etch_object* valobj, boolean* out);
+int  etchtagdata_byte_value  (etch_object* valobj, byte* out);
+int  etchtagdata_int16_value (etch_object* valobj, short* out);
+int  etchtagdata_int32_value (etch_object* valobj, int* out);
+int  etchtagdata_int64_value (etch_object* valobj, int64* out);
+int  etchtagdata_float_value (etch_object* valobj, float* out);
+int  etchtagdata_double_value(etch_object* valobj, double* out);
+int  etchtagdata_is_eod (etch_object*);
+int  etchtagdata_is_null(etch_object*);
+etch_object* etchtagdata_new_eodmarker(const int is_static);
+etch_object* etchtagdata_new_nullobj  (const int is_static);
+etch_string* etchtagdata_new_emptystring(const int is_static);
+signed char etchtagdata_check_value   (etch_object*);
+signed char etchtagdata_check_byte    (const signed char);  
+signed char etchtagdata_check_short   (const short); 
+signed char etchtagdata_check_integer (const int); 
+signed char etchtagdata_check_long    (const int64); 
+
+
+/**
+ * etch_typecode
+ * enumeration of values denoting type of an encoded value
+ * rage 1: -128 to -65  defined types
+ * range 2: -64 to 127  tiny integer values
+ */
+typedef enum etch_typecode
+{
+	/**
+	 * denotes a null value.
+	 */
+	ETCH_XTRNL_TYPECODE_NULL = -128,
+	/**
+	 * denotes no value, which is different than null. for example, an array is a
+	 * sequence of values (some of which may be null) terminated by a NONE.
+	 */
+	ETCH_XTRNL_TYPECODE_NONE = -127,
+    ETCH_XTRNL_TYPECODE_ENDDATA = ETCH_XTRNL_TYPECODE_NONE,
+
+    /* - - - - - - - - - - - - - - - - - - 
+     * scalars (also see tiny int below)
+     * - - - - - - - - - - - - - - - - - - 
+     */
+
+	/**
+	 * denotes a false boolean value.
+	 */
+	ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE = -126,
+	/**
+	 * denotes a true boolean value.
+	 */
+	ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE = -125,
+    ETCH_XTRNL_TYPECODE_BOOLEAN_CONTENT = ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE,
+
+	/**
+	 * signed byte.
+	 */
+	ETCH_XTRNL_TYPECODE_BYTE = -124,
+	/**
+	 * two byte signed short, msb first
+	 */
+	ETCH_XTRNL_TYPECODE_SHORT = -123,
+	/**
+	 * four byte signed integer, msb first.
+	 */
+	ETCH_XTRNL_TYPECODE_INT = -122,    
+	/**
+	 * eight byte byte signed long, msb first 
+	 */
+	ETCH_XTRNL_TYPECODE_LONG = -121, 
+	/**
+	 * four byte ieee floating format number 
+	 */
+	ETCH_XTRNL_TYPECODE_FLOAT = -120,
+	/**
+	 * eight byte ieee floating format number.
+	 */
+	ETCH_XTRNL_TYPECODE_DOUBLE = -119,
+
+    /* - - - - - - - - - - - - - - - - - - 
+     * arrays  
+     * - - - - - - - - - - - - - - - - - - 
+     */
+
+	/**
+	 * an array of bytes.
+	 */
+	ETCH_XTRNL_TYPECODE_BYTES = -117,
+	/**
+	 * a sequence of values.
+	 */
+	ETCH_XTRNL_TYPECODE_ARRAY = -111,  
+
+    /* - - - - - - - - - - - - - - - - - - 
+     * strings  
+     * - - - - - - - - - - - - - - - - - - 
+     */
+
+	/**
+	 * denotes an empty string.
+	 */
+	ETCH_XTRNL_TYPECODE_EMPTY_STRING = -110,
+	/**
+	 * utf-8 encoded string
+	 */
+	ETCH_XTRNL_TYPECODE_STRING = -109,
+
+    /* - - - - - - - - - - - - - - - - - - 
+     * structures  
+     * - - - - - - - - - - - - - - - - - - 
+     */
+
+	/**
+	 * a sequence of key / value pairs.
+	 */
+	ETCH_XTRNL_TYPECODE_STRUCT = -108,
+
+	/**
+	 * a custom value from a value factory (struct, exception, enum, extern).
+     * an associated value identifies the specific type. the wire format of
+     * STRUCT and CUSTOM are the same, i.e. can use CUSTOM in place of STRUCT
+     * and accept STRUCT as if CUSTOM.
+	 */
+	ETCH_XTRNL_TYPECODE_CUSTOM = -107,
+	/**
+	 * denotes that any value is ok (as long as we know how to serialize it).
+	 * dynamic methods should be applied to determine type.
+	 * this type never appears on the wire.
+	 */
+	ETCH_XTRNL_TYPECODE_ANY = -106,
+
+    /* - - - - - - - - - - - - - - - - - - 
+     * tiny integers (no value follows)
+     * - - - - - - - - - - - - - - - - - - 
+     */
+
+	ETCH_XTRNL_TYPECODE_MIN_TINY_INT = -64,
+	ETCH_XTRNL_TYPECODE_MAX_TINY_INT = 127,
+
+} etch_typecode;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_TAGDATA_H */
diff --git a/binding-c/runtime/c/include/etch_tcp_connection.h b/binding-c/runtime/c/include/etch_tcp_connection.h
new file mode 100644
index 0000000..5ad127d
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_tcp_connection.h
@@ -0,0 +1,119 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_connection.h
+ * connection client and server classes - tcp, udp
+ */
+
+#ifndef _ETCH_TCP_CONNECTION_H_
+#define _ETCH_TCP_CONNECTION_H_
+
+#include "apr_thread_proc.h"
+#include "etch_connection.h"
+#include "etch_transport_data.h"
+#include "etch_transportint.h"
+#include "etch_session_data.h"
+#include "etch_url.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct etch_tcp_client;
+
+/*
+ * tcp specific connection type
+ */
+typedef struct etch_tcp_connection
+{
+    etch_object object;
+
+    etch_connection  cx;
+    struct etch_tcp_client* rcvlxr;  /* owned */
+
+    i_transportdata* itd;     /* owned */
+
+    i_sessiondata*   session; /* not owned */
+
+    int linger;
+    int traffic_class;
+
+    unsigned char is_nodelay;
+    unsigned char is_keepalive;
+    unsigned char is_autoflush;
+    unsigned char is_session_owned;
+
+} etch_tcp_connection;
+
+
+/*
+ * udp connection
+ * placeholder - this will go in etch_udpconxn.h when we implement udp transport
+ */
+typedef struct etch_udp_connection
+{
+    etch_object object;
+ 
+    etch_connection cx;
+
+    apr_sockaddr_t *last_from;
+
+} etch_udp_connection;
+
+
+/**
+ * etch_tcp_client 
+ * tcp client listener class
+ */
+typedef struct etch_tcp_client
+{
+    etch_object object;
+ 
+    etch_tcp_connection* cxlisten; /* not owned */
+    etch_thread* thread;
+    unsigned char is_started;
+
+} etch_tcp_client;
+
+
+extern unsigned connection_id_farm;
+
+etch_tcp_connection* new_tcp_connection(etch_url*, void* resources, etch_rawsocket*);
+int  init_etch_tcpconx_interfaces (etch_tcp_connection*);
+int  new_tcpsocket (apr_socket_t**, apr_pool_t*);
+int  destroy_etch_tcp_connection(void* thisx);
+int  etch_tcpconx_start(etch_tcp_connection*);
+int  etch_tcpclient_start_listener (etch_tcp_connection*);
+int  etch_tcpconx_open (etch_tcp_connection*, const int is_reconnect);
+int  etch_tcpconx_close(etch_tcp_connection*, const int is_linger);
+int  etch_tcpconx_wait_until(etch_tcp_connection*, const int64 waitval, const int timeoutms);
+int  etch_tcpconx_on_event(void*, const int e, int p1, void* p2);
+int  etch_tcpclient_send(etch_tcp_connection *conx, unsigned char* buf, const size_t totallen, int* rc);
+int  etch_tcpclient_sendex (etch_tcp_connection *conx, unsigned char* buf, const size_t totallen, const int timeout_ms, int* rc);
+int  etch_tcpclient_receive (etch_tcp_connection*, unsigned char*, const size_t, int*);
+int  etch_tcpclient_receivex(etch_tcp_connection*, unsigned char*, const size_t, const int, int*);
+int  etch_tcpclient_stop(etch_tcp_connection*);
+int  etch_tcpclient_stop_listener (etch_tcp_connection*);
+int  is_good_tcp_params(etch_url*, void* resources, etch_rawsocket*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* ETCHTCPCONXN_H */
diff --git a/binding-c/runtime/c/include/etch_tcp_server.h b/binding-c/runtime/c/include/etch_tcp_server.h
new file mode 100644
index 0000000..15dd2d0
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_tcp_server.h
@@ -0,0 +1,120 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_connection.h
+ * connection client and server classes - tcp, udp
+ */
+
+#ifndef ETCHTCPSERVER_H
+#define ETCHTCPSERVER_H
+
+#include "apr_thread_proc.h"
+#include "etch_tcp_connection.h"
+#include "etch_resources.h"
+#include "etch_session_listener.h"
+#include "etch_mutex.h"
+#include "etch_linked_list.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct etch_tcp_server;
+typedef int (*etch_listener_event_handler) (struct etch_tcp_server*, struct etch_tcp_connection*, const int, int, void*);
+
+#define ETCH_TCPSERVER_STATE_CLOSED   0
+#define ETCH_TCPSERVER_STATE_CLOSING  1
+#define ETCH_TCPSERVER_STATE_STOPPED  2
+#define ETCH_TCPSERVER_STATE_STOPPING 3
+#define ETCH_TCPSERVER_STATE_STARTING 4
+#define ETCH_TCPSERVER_STATE_STARTED  5
+
+
+/**
+ * etch_tcp_server 
+ * tcp listener class
+ */
+typedef struct etch_tcp_server
+{
+    etch_object object;
+
+    etch_tcp_connection* cxlisten; /* owned */
+    etch_threadpool* threadpool;   /* not owned */
+    etch_threadpool* subpool;      /* not owned */
+    etch_listener_event_handler   on_event;
+    etch_connection_event_handler on_data;
+    
+    /* - - - - - - - - - - - - - - - - - -
+     * i_sessionlistener - set externally
+     * - - - - - - - - - - - - - - - - - -
+     */
+    i_session*            isession;  /* not owned */
+    i_sessionlistener*    session;   /* owned or not */
+    etch_session_control  session_control;
+    etch_session_notify   session_notify;
+    etch_session_query    session_query; 
+    etch_session_accepted on_session_accepted;
+
+    /* - - - - - - - - - - - - - - - - - -
+     * i_transport
+     * - - - - - - - - - - - - - - - - - -
+     */
+    i_transport* itransport;  /* owned */
+    etch_transport_control transport_control;
+    etch_transport_notify  transport_notify;
+    etch_transport_query   transport_query;
+    etch_transport_get_session get_session;
+    etch_transport_set_session set_session;
+
+    /* - - - - - - - - - - - - - - - - - 
+     * instance data 
+     * - - - - - - - - - - - - - - - - - 
+     */
+    unsigned listener_id;
+    int  backlog;
+    int  connections;
+    etch_url* url;
+    etch_wait_t* waiter;     /* not owned */
+    etch_resources* resxmap; /* not owned */
+
+    unsigned char state;
+    unsigned char is_started;
+    unsigned char is_session_owned;
+    unsigned char is_threadpool_owned;
+
+    etch_linked_list_t* client_connections;
+    etch_mutex*         client_connections_mutex;
+    etch_thread*        thread;
+
+} etch_tcp_server;
+
+unsigned tcpserver_id_farm;
+
+etch_tcp_server* new_tcp_server(etch_url*, etch_threadpool*, etch_threadpool*, etch_resources*, i_sessionlistener*);
+int  etch_tcpsvr_open (etch_tcp_server*, const int is_reconnect);
+int  etch_tcpsvr_start(etch_tcp_server*);
+int  etch_tcpsvr_stop (etch_tcp_server*);
+int  etch_tcpsvr_close(etch_tcp_server*);
+int  etch_deftcplistener_on_event(etch_tcp_server*, etch_tcp_connection*, const int e, int p1, void* p2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* ETCHTCPSERVER_H */
diff --git a/binding-c/runtime/c/include/etch_tdformat.h b/binding-c/runtime/c/include/etch_tdformat.h
new file mode 100644
index 0000000..c2f70bf
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_tdformat.h
@@ -0,0 +1,69 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_tdformat.h
+ * a factory used to construct tagged data processors for messagizer
+ */
+
+#ifndef ETCHTDFORMAT_H
+#define ETCHTDFORMAT_H
+
+#include "etch_tagdata_inp.h"
+#include "etch_tagdata_out.h"
+#include "etch_binary_tdi.h"
+#include "etch_binary_tdo.h"
+#include "etch_value_factory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** 
+ *  tagdata_format_factory
+ */
+typedef struct tagdata_format_factory
+{
+    etch_object object;
+
+    tagged_data_input*  (*new_tagdata_input)  (etch_value_factory*);
+    tagged_data_output* (*new_tagdata_output) (etch_value_factory*);
+
+} tagdata_format_factory;
+
+typedef enum etchtdf  /* tagged data format IDs */
+{   ETCH_TAGDATA_FORMAT_BINARY, 
+    ETCH_TAGDATA_FORMAT_XML,
+    ETCH_TAGDATA_FORMAT_COUNT  /* must be last in list */
+} etchtdf;
+
+const wchar_t* tdformat_names[ETCH_TAGDATA_FORMAT_COUNT];
+
+const wchar_t* tdfname_binary;
+const wchar_t* tdfname_xml;
+
+int is_tdf_initialized;
+
+tagdata_format_factory* get_format_factory(wchar_t* format_name);
+int  etchtdf_name_to_id(wchar_t* format_name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* ETCHTDFORMAT_H */
diff --git a/binding-c/runtime/c/include/etch_thread.h b/binding-c/runtime/c/include/etch_thread.h
new file mode 100644
index 0000000..46ab71b
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_thread.h
@@ -0,0 +1,206 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etchpool.h -- threads and thread pool 
+ */
+
+#ifndef ETCHPOOL_H
+#define ETCHPOOL_H
+
+#include "apr_thread_proc.h"
+#include "apr_atomic.h"
+
+#include "etch_object.h"
+#include "etch_mutex.h"
+#include "etch_wait.h"
+#include "etch_arraylist.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_THREADSTATE_INITIAL    0
+#define ETCH_THREADSTATE_STARTED    4
+#define ETCH_THREADSTATE_STOPPING   7
+#define ETCH_THREADSTATE_STOPPED    8
+#define ETCH_THREADSTATE_DEFUNCT    9
+
+#define ETCH_DEFAULT_POOLTHREADS    4
+#define ETCH_THREAD_PARAMS_SIGNATURE 0xcafef00d
+
+//TODO: check global + do doc
+// move to c file
+// synchronize thread_id_farm var
+extern unsigned thread_id_farm;
+
+
+extern etch_mutex* loglock;
+
+
+unsigned next_etch_threadid();
+int etch_apr_init();
+struct etch_threadpool;
+struct etch_thread;
+int etch_init_static_mutex(etch_mutex*, const int is_nestable);
+
+struct etch_threadpool;
+
+/** signature of a thread procedure */
+typedef void (*etch_threadproc) (void*); 
+
+/** signature of a thread procedure callback */
+typedef int (*etch_thread_callback) (void*); 
+
+/** interface to run a pool thread */
+typedef struct etch_thread* (*etch_run) (struct etch_threadpool*, etch_threadproc, void*); 
+
+/**
+ * etch_apr_threaddata
+ * thread parameters specific to the apache portable runtime. 
+ * this object memory is always managed by the caller, regardless of
+ * thread params is_xxxx configuration.
+ */
+typedef struct etch_apr_threaddata
+{
+    apr_pool_t*       mempool;
+    apr_thread_t*     thread;
+    apr_threadattr_t* threadattr;  
+    unsigned char     threadstate;
+    unsigned char     is_dedicated_mempool;
+
+} etch_apr_threaddata;
+
+
+/**
+ * etch_thread_params
+ * parameters to any thread start. 
+ * an internal threadproc invokes the user threadproc, 
+ * so we supply this object to the internal threadproc as data.
+ */
+typedef struct etch_thread_params
+{
+    unsigned int signature;           /* thread params sig */
+    int etch_thread_id;               /* our sequential ID */
+    etch_threadproc threadproc;       /* user thread proc */ 
+    etch_thread_callback on_start;    /* thread start hook */ 
+    etch_thread_callback on_exit;     /* thread exit hook */ 
+    etch_apr_threaddata* libdata;     /* thread library data*/
+    struct etch_threadpool* etchpool; /* thread pool if any */
+    struct etch_thread* etchobj;      /* etch_thread object */ 
+    etch_wait_t* waitobj;             /* post-start waiter */  
+    void*  data;                      /* actual thread data */
+    unsigned char is_own_data;        /* does thread own data */
+    unsigned char is_data_etchobject; /* is destroy() in play */
+    unsigned char threadstate;        /* current start state */
+    unsigned char unused;
+    etch_mutex_hookproc  synchook;
+    etch_mutex_t*   synclock;
+
+} etch_thread_params;
+
+
+/** 
+ *  etch_thread: thread object
+ */
+typedef struct etch_thread
+{
+    etch_object object;
+    
+    unsigned char   is_joined;
+
+    int (*start) (void*);
+    int (*stop)  (void*);
+
+    etch_thread_params   params;
+    etch_apr_threaddata  aprdata;
+    etch_wait_t*         waiter;
+    int64                startCond;
+    etch_mutex_t*   objlock;
+
+} etch_thread;
+
+
+/** 
+ *  etch_threadpool: thread pool object
+ */
+typedef struct etch_threadpool
+{
+    etch_object object;
+
+    etch_run run;
+
+    etch_mutex* pool_lock;
+
+    /* to do: embed underlying queued threadpool here, such as APR pool */
+
+    etch_arraylist* threadlist;
+    etch_mutex* threadlist_lock; 
+    unsigned int    threadpool_id;  
+    int (*count) (); /* implementation should return threadlist.count */
+
+    unsigned char   pooltype;      /* queued or free */
+    unsigned char   is_defunct;    /* is pool forcibly destroying threads */
+    unsigned char   is_iterating;  /* is pool currently being iterated */
+    unsigned char   is_free_data;  /* will thread free its data memory */
+    unsigned char   is_free_threads;     /* is poolthread memory freed */
+    unsigned char   is_data_etchobject;  /* can thread call destroy() on data */
+    unsigned char   is_manual_start;     /* is explicit thread.start() required */
+    unsigned char   unused;      
+    
+} etch_threadpool;
+
+
+/* 
+ * global free thread pool
+ */
+extern etch_threadpool* global_free_threadpool;  
+etch_threadpool* etch_glopool();
+int etch_glopool_exit();
+
+extern unsigned short etch_threadpool_id_farm;
+
+#define ETCH_HAS_QUEUED_THREADPOOL (0)
+
+
+etch_threadpool* new_threadpool(const unsigned pooltype, const int initsize);
+etch_thread* new_thread (etch_threadproc, void*);
+etch_thread* threadpool_remove_entry (etch_threadpool*, const int thread_id);
+etch_thread* threadpool_thread (etch_threadpool*, const int i);
+int    threadpool_waitfor_all(etch_threadpool*, const int is_cancel);
+int    threadpool_remove (etch_threadpool*, const int id);
+int    destroy_threadpool(void*);
+
+void   etch_init_threadparams (etch_thread_params*);
+int    etch_createthread (etch_thread_params*);
+int    etch_thread_join  (etch_thread_params*);
+int    etch_thread_cancel(etch_thread*);
+int    etch_thread_current_id();
+int    etch_join(etch_thread*);
+void   etch_thread_yield ();
+int    etch_on_threadstart(void*);
+int    etch_on_threadexit (void*);
+size_t etch_get_threadid  (void* threadstruct);
+void   etch_sleep(const int ms);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHPOOL_H */
diff --git a/binding-c/runtime/c/include/etch_thread2.h b/binding-c/runtime/c/include/etch_thread2.h
new file mode 100644
index 0000000..50f23df
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_thread2.h
@@ -0,0 +1,108 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_thread.h -- thread implementation 
+ */
+
+#ifndef _ETCH_THREAD_H_
+#define _ETCH_THREAD_H
+
+#include "etch_errno.h"
+#include "etch_mem.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_THREAD_CREATE_JOINABLE 0
+#define ETCH_THREAD_CREATE_DETACHED 1
+
+typedef struct etch_thread_attr_t etch_thread_attr_t;
+typedef struct etch_thread_t etch_thread_t;
+
+typedef void (*etch_thread_func)(etch_thread_t* thread, void* data);
+
+/**
+ * create a new thread attr instance.
+ * @param attr
+ * @return status
+ */
+etch_status_t etch_thread_attr_create(etch_thread_attr_t** attr);
+
+/**
+ * set thread detach state.
+ * @param attr
+ * @param state ETCH_THREAD_CREATE_JOINABLE or ETCH_THREAD_CREATE_DETACHED
+ * @return status
+ */
+etch_status_t etch_thread_attr_set_detachstate(etch_thread_attr_t* attr, int state);
+
+/**
+ * get thread detach state.
+ * @param attr
+ * @param state ETCH_THREAD_CREATE_JOINABLE or ETCH_THREAD_CREATE_DETACHED
+ * @return status
+ */
+etch_status_t etch_thread_attr_get_detachstate(etch_thread_attr_t* attr, int* state);
+
+/**
+ * destroy thread attr instance.
+ * @param attr
+ * @return status
+ */
+etch_status_t etch_thread_attr_destroy(etch_thread_attr_t* attr);
+
+
+/**
+ * create a new thread.
+ * @param thread
+ * @param attr
+ * @param thread_proc
+ * @param data
+ * @return status
+ */
+etch_status_t etch_thread_create(etch_thread_t** thread, const etch_thread_attr_t* attr, etch_thread_func thread_proc, void* data);
+
+/**
+ * wait thread proc has finished. 
+ * @param thread
+ * @param status return code of thread exit
+ * @return status
+ */
+etch_status_t etch_thread_join(etch_thread_t* thread, etch_status_t* status);
+
+/**
+ * yield current thread.
+ * @param status
+ */
+etch_status_t etch_thread_yield();
+
+/**
+ * thread exit, return status
+ * @param thread
+ * @param status thread exit status
+ * @return status
+ */
+etch_status_t etch_thread_exit(etch_thread_t* thread, etch_status_t status);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef _ETCH_THREAD_H */
diff --git a/binding-c/runtime/c/include/etch_threadpool.h b/binding-c/runtime/c/include/etch_threadpool.h
new file mode 100644
index 0000000..2328159
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_threadpool.h
@@ -0,0 +1,46 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_threadpool.h -- etch thread pool 
+ */
+
+#ifndef _ETCH_THREAD_POOL_H_
+#define _ETCH_THREAD_POOL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "etch_errno.h"
+
+#define ETCH_THREADPOOL_TYPE_FREE 0x01
+#define ETCH_THREADPOOL_TYPE_QUEUED 0x02
+
+typedef struct etch_threadpool_t etch_threadpool_t;
+
+etch_status_t etch_threadpool_create(etch_threadpool_t** threadpool, uint8 type, const uint16 init_size);
+etch_status_t etch_threadpool_remove(etch_threadpool_t* threadpool, const uint16 thread_id);
+etch_status_t etch_threadpool_join(etch_threadpool_t* threadpool);
+etch_status_t etch_threadpool_destroy(etch_threadpool_t* threadpool);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef _ETCH_THREAD_POOL_H_ */
\ No newline at end of file
diff --git a/binding-c/runtime/c/include/etch_threadpool_apr.h b/binding-c/runtime/c/include/etch_threadpool_apr.h
new file mode 100644
index 0000000..f698091
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_threadpool_apr.h
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ */
+
+#ifndef APU_THREAD_POOL_H
+#define APU_THREAD_POOL_H
+
+#include "apr_thread_proc.h"
+
+/**
+ * @file apr_thread_pool.h
+ * @brief APR Thread Pool Library
+
+ * @remarks This library implements a thread pool using apr_thread_t. A thread
+ * pool is a set of threads that can be created in advance or on demand until a
+ * maximum number. When a task is scheduled, the thread pool will find an idle
+ * thread to handle the task. In case all existing threads are busy and the
+ * number of tasks in the queue is higher than the adjustable threshold, the
+ * pool will try to create a new thread to serve the task if the maximum number
+ * has not been reached. Otherwise, the task will be put into a queue based on
+ * priority, which can be valued from 0 to 255, with higher values being served
+ * first. If there are tasks with the same priority, the new task might be put at
+ * the top or at the bottom - it depends on which function is used to put the task.
+ *
+ * @remarks There may be the case where the thread pool can use up to the maximum
+ * number of threads at peak load, but having those threads idle afterwards. A
+ * maximum number of idle threads can be set so that the extra idling threads will
+ * be terminated to save system resources.
+ */
+#if APR_HAS_THREADS
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @defgroup APR_Util_TP Thread Pool routines
+ * @ingroup APR_Util
+ * @{
+ */
+
+/** Opaque Thread Pool structure. */
+typedef struct apr_thread_pool apr_thread_pool_t;
+
+#define APR_THREAD_TASK_PRIORITY_LOWEST 0
+#define APR_THREAD_TASK_PRIORITY_LOW 63
+#define APR_THREAD_TASK_PRIORITY_NORMAL 127
+#define APR_THREAD_TASK_PRIORITY_HIGH 191
+#define APR_THREAD_TASK_PRIORITY_HIGHEST 255
+
+/**
+ * Create a thread pool
+ * @param me The pointer in which to return the newly created apr_thread_pool
+ * object, or NULL if thread pool creation fails.
+ * @param init_threads The number of threads to be created initially, this number
+ * will also be used as the initial value for the maximum number of idle threads.
+ * @param max_threads The maximum number of threads that can be created
+ * @param pool The pool to use
+ * @return APR_SUCCESS if the thread pool was created successfully. Otherwise,
+ * the error code.
+ */
+apr_status_t etch_apr_thread_pool_create(apr_thread_pool_t **me,
+                                                 apr_size_t init_threads,
+                                                 apr_size_t max_threads,
+                                                 apr_pool_t *pool);
+
+/**
+ * Destroy the thread pool and stop all the threads
+ * @return APR_SUCCESS if all threads are stopped.
+ */
+apr_status_t etch_apr_thread_pool_destroy(apr_thread_pool_t *me);
+
+/**
+ * Schedule a task to the bottom of the tasks of same priority.
+ * @param me The thread pool
+ * @param func The task function
+ * @param param The parameter for the task function
+ * @param priority The priority of the task.
+ * @param owner Owner of this task.
+ * @return APR_SUCCESS if the task had been scheduled successfully
+ */
+apr_status_t etch_apr_thread_pool_push(apr_thread_pool_t *me,
+                                               apr_thread_start_t func,
+                                               void *param,
+                                               apr_byte_t priority,
+                                               void *owner);
+/**
+ * Schedule a task to be run after a delay
+ * @param me The thread pool
+ * @param func The task function
+ * @param param The parameter for the task function
+ * @param time Time in microseconds
+ * @param owner Owner of this task.
+ * @return APR_SUCCESS if the task had been scheduled successfully
+ */
+apr_status_t etch_apr_thread_pool_schedule(apr_thread_pool_t *me,
+                                                   apr_thread_start_t func,
+                                                   void *param,
+                                                   apr_interval_time_t time,
+                                                   void *owner);
+
+/**
+ * Schedule a task to the top of the tasks of same priority.
+ * @param me The thread pool
+ * @param func The task function
+ * @param param The parameter for the task function
+ * @param priority The priority of the task.
+ * @param owner Owner of this task.
+ * @return APR_SUCCESS if the task had been scheduled successfully
+ */
+apr_status_t etch_apr_thread_pool_top(apr_thread_pool_t *me,
+                                              apr_thread_start_t func,
+                                              void *param,
+                                              apr_byte_t priority,
+                                              void *owner);
+
+/**
+ * Cancel tasks submitted by the owner. If there is any task from the owner that
+ * is currently running, the function will spin until the task finished.
+ * @param me The thread pool
+ * @param owner Owner of the task
+ * @return APR_SUCCESS if the task has been cancelled successfully
+ * @note The task function should not be calling cancel, otherwise the function
+ * may get stuck forever. The function assert if it detect such a case.
+ */
+apr_status_t etch_apr_thread_pool_tasks_cancel(apr_thread_pool_t *me,
+                                                       void *owner);
+
+/**
+ * Get the current number of tasks waiting in the queue
+ * @param me The thread pool
+ * @return Number of tasks in the queue
+ */
+apr_size_t etch_apr_thread_pool_tasks_count(apr_thread_pool_t *me);
+
+/**
+ * Get the current number of scheduled tasks waiting in the queue
+ * @param me The thread pool
+ * @return Number of scheduled tasks in the queue
+ */
+apr_size_t etch_apr_thread_pool_scheduled_tasks_count(apr_thread_pool_t *me);
+
+/**
+ * Get the current number of threads
+ * @param me The thread pool
+ * @return Total number of threads
+ */
+apr_size_t etch_apr_thread_pool_threads_count(apr_thread_pool_t *me);
+
+/**
+ * Get the current number of busy threads
+ * @param me The thread pool
+ * @return Number of busy threads
+ */
+apr_size_t etch_apr_thread_pool_busy_count(apr_thread_pool_t *me);
+
+/**
+ * Get the current number of idle threads
+ * @param me The thread pool
+ * @return Number of idle threads
+ */
+apr_size_t etch_apr_thread_pool_idle_count(apr_thread_pool_t *me);
+
+/**
+ * Access function for the maximum number of idle threads. Number of current
+ * idle threads will be reduced to the new limit.
+ * @param me The thread pool
+ * @param cnt The number
+ * @return The number of threads that were stopped.
+ */
+apr_size_t etch_apr_thread_pool_idle_max_set(apr_thread_pool_t *me,
+                                                     apr_size_t cnt);
+
+/**
+ * Get number of tasks that have run
+ * @param me The thread pool
+ * @return Number of tasks that have run
+ */
+apr_size_t
+    etch_apr_thread_pool_tasks_run_count(apr_thread_pool_t * me);
+
+/**
+ * Get high water mark of the number of tasks waiting to run
+ * @param me The thread pool
+ * @return High water mark of tasks waiting to run
+ */
+apr_size_t
+    etch_apr_thread_pool_tasks_high_count(apr_thread_pool_t * me);
+
+/**
+ * Get high water mark of the number of threads
+ * @param me The thread pool
+ * @return High water mark of threads in thread pool
+ */
+apr_size_t
+    etch_apr_thread_pool_threads_high_count(apr_thread_pool_t * me);
+
+/**
+ * Get the number of idle threads that were destroyed after timing out
+ * @param me The thread pool
+ * @return Number of idle threads that timed out
+ */
+apr_size_t
+    etch_apr_thread_pool_threads_idle_timeout_count(apr_thread_pool_t * me);
+
+/**
+ * Access function for the maximum number of idle threads
+ * @param me The thread pool
+ * @return The current maximum number
+ */
+apr_size_t etch_apr_thread_pool_idle_max_get(apr_thread_pool_t *me);
+
+/**
+ * Access function for the maximum number of threads.
+ * @param me The thread pool
+ * @param cnt Number of threads
+ * @return The original maximum number of threads
+ */
+apr_size_t etch_apr_thread_pool_thread_max_set(apr_thread_pool_t *me,
+                                                       apr_size_t cnt);
+
+/**
+ * Access function for the maximum wait time (in microseconds) of an
+ * idling thread that exceeds the maximum number of idling threads.
+ * A non-zero value allows for the reaping of idling threads to shrink
+ * over time.  Which helps reduce thrashing.
+ * @param me The thread pool
+ * @param timeout The number of microseconds an idle thread should wait
+ * till it reaps itself
+ * @return The original maximum wait time
+ */
+apr_interval_time_t
+    etch_apr_thread_pool_idle_wait_set(apr_thread_pool_t * me,
+                                  apr_interval_time_t timeout);
+
+/**
+ * Access function for the maximum wait time (in microseconds) of an
+ * idling thread that exceeds the maximum number of idling threads
+ * @param me The thread pool
+ * @return The current maximum wait time
+ */
+apr_interval_time_t
+    etch_apr_thread_pool_idle_wait_get(apr_thread_pool_t * me);
+
+/**
+ * Access function for the maximum number of threads
+ * @param me The thread pool
+ * @return The current maximum number
+ */
+apr_size_t etch_apr_thread_pool_thread_max_get(apr_thread_pool_t *me);
+
+/**
+ * Access function for the threshold of tasks in queue to trigger a new thread.
+ * @param me The thread pool
+ * @param cnt The new threshold
+ * @return The original threshold
+ */
+apr_size_t etch_apr_thread_pool_threshold_set(apr_thread_pool_t *me,
+                                                      apr_size_t val);
+
+/**
+ * Access function for the threshold of tasks in queue to trigger a new thread.
+ * @param me The thread pool
+ * @return The current threshold
+ */
+apr_size_t etch_apr_thread_pool_threshold_get(apr_thread_pool_t * me);
+
+/**
+ * Get owner of the task currently been executed by the thread.
+ * @param thd The thread is executing a task
+ * @param owner Pointer to receive owner of the task.
+ * @return APR_SUCCESS if the owner is retrieved successfully
+ */
+apr_status_t etch_apr_thread_pool_task_owner_get(apr_thread_t *thd,
+                                                         void **owner);
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* APR_HAS_THREADS */
+#endif /* !APR_THREAD_POOL_H */
diff --git a/binding-c/runtime/c/include/etch_transport.h b/binding-c/runtime/c/include/etch_transport.h
new file mode 100644
index 0000000..b5d98e7
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_transport.h
@@ -0,0 +1,282 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_transport.h -- common transport code
+ */
+
+#ifndef ETCHTRANSPORT_H
+#define ETCHTRANSPORT_H
+
+#include "etch_message.h"
+#include "etch_tcp_connection.h"
+#include "etch_resources.h"
+#include "etch_arraylist.h"
+#include "etch_mailbox_manager.h"
+#include "etch_session_listener.h"
+#include "etch_wait.h"
+#include "etch_url.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*etch_delivsvc_begincall)(void* thisx, etch_message*, void** out);  /* i_mailbox** out */
+typedef int (*etch_delvisvc_endcall)  (void* thisx, i_mailbox*, etch_type* response_type, void** out); /* etch_object** out */
+
+typedef void* (*new_client_impl_funcptr)(void* argstruct);  /* not used */
+typedef void* (*main_client_create_func)(void* factory_thisx, void* server);
+
+typedef void* (*helper_listener_create_func)(void* serverargs, void* sessionargs);
+typedef int   (*helper_resources_init_func)(void* argstruct);
+typedef void* (*main_server_create_func)(void* factory_thisx, void* client);
+
+/*
+ * i_delivery_service
+ * the implementor of delivery service will implement i_sessionmessage and
+ * i_session, and copy pointers to the implementations to this interface.
+ */
+typedef struct i_delivery_service
+{
+    etch_object object;
+
+    etch_delivsvc_begincall begin_call;
+    etch_delvisvc_endcall   end_call;
+    
+    i_sessionmessage*   session;   /* not owned */
+    i_transportmessage* transport; /* not owned */
+    i_sessionmessage*   ism;       /* not owned */
+    i_transportmessage* itm;       /* not owned */
+
+    void* thisx;
+    etch_mutex* rwlock; /* not owned */
+    unsigned char is_session_owned;
+    unsigned char is_transport_owned;
+
+} i_delivery_service;
+
+
+/*
+ * etch_tcp_delivery_service
+ * java binding does not have one of these, it constructs and returns a  
+ * DeliveryService in TcpTransportFactory.newTransport(). we will instead 
+ * invoke new_etch_transport(uri, resources), returning an i_delivery_service. 
+ */
+typedef struct etch_tcp_delivery_service  
+{
+    etch_object object;
+
+    // ***** TODO lose i_deliveryservice instantiation and instead mask 
+    // ***** all delivery service with i_deliveryservice. *************
+    i_delivery_service*     ids;
+    etch_delivsvc_begincall begin_call;
+    etch_delvisvc_endcall   end_call;
+
+    /* i_transportmessage - owns the tcp delivery service */
+    i_transportmessage*     transport;   /* owned by transportx */ 
+    i_mailbox_manager*      transportx;  /* owned */ 
+
+    /* external implementation of i_session_message */
+    i_sessionmessage*       session;     /* not owned */
+
+    /* delivery service implementation of i_session_message */
+    i_sessionmessage*       sessionmsg;  /* owned */
+    etch_session_message    session_message;
+    etch_session_control    session_control;
+    etch_session_notify     session_notify;
+    etch_session_query      session_query;
+
+    /* delivery service implementation of i_transport_message */
+    /* owns the tcp delivery service */
+    i_transportmessage*     transportmsg;   /* owned */ 
+    etch_transport_message  transport_message;
+    etch_transport_control  transport_control;  
+    etch_transport_notify   transport_notify;   
+    etch_transport_query    transport_query;   
+    etch_transport_get_session  get_session;   
+    etch_transport_set_session  set_session;  
+
+    /* private component implementations */
+    etch_resources* resources;    /* not owned */
+    etch_tcp_connection* tcpconx; /* not owned on server - destroyed on listener exit */
+    etch_mutex* rwlock; /* not owned */
+    etch_wait_t* wait_up;   /* owned by tcpconx */
+    etch_wait_t* wait_down; /* owned by tcpconx */
+    void* packetizer;  /* owned */
+    void* messagizer;  /* owned */
+    void* mailboxmgr;  /* owned */
+
+    unsigned char is_tcpconx_owned;
+    unsigned char unused[3];
+
+} etch_tcp_delivery_service;
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * factory parameter bundle
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etch_session
+ * server's per-client parameters.
+ * this object wraps all of a server's per-session instance data.
+ */
+typedef struct etch_session
+{
+    etch_object object;
+
+    void* thisx;             /* host etch_factory_params* */
+
+    unsigned   session_id;   /* session key: same as cx.conxid */
+    /* fyi a session's receive thread is available at cx.thread */
+    etch_connection* cx;     /* session client accepted connection */ 
+    i_delivery_service* ds;  /* session delivery service */
+    void*      client;       /* xxxx_remote_client* */
+    void*      server;       /* i_xxxx_server */
+    void*      server_stub;  /* xxxx_server_stub* */
+    etch_object*   conximpl;     /* accepted conx impl obj e.g. tcp_connection* */
+
+    /* note that mainlistener.thisx is the server object e.g. etch_tcp_server 
+     * and that serverobject.session is this i_sessionlistener */
+    i_sessionlistener* mainlistener; /* accept listener */ 
+
+} etch_session;
+
+
+/**
+ * etch_factory_params
+ * mask over server or client factory parameter bundle
+ */
+typedef struct etch_factory_params
+{
+    etch_object object;
+
+    void* thisx;        /* params owner TODO populate this */
+
+    wchar_t*            in_uri;
+    etch_resources*     in_resx;
+    etch_value_factory* in_valufact;
+    etch_threadpool*    mainpool;
+    etch_threadpool*    subpool;
+    etch_threadpool*    qpool;
+    etch_threadpool*    fpool;
+    etch_mutex*          mblock;
+    etch_object*            session;  
+    i_session*          isession;  
+    etch_arraylist*     per_connection_params;    
+
+    /* factory constructors */
+    void* helper_new_xxxx;
+    void* main_new_xxxx;
+
+} etch_factory_params;
+
+
+/**
+ * etch_server_factory
+ * virtual server constructors and associated parameters.
+ * masked by etch_factory_params
+ */
+typedef struct etch_server_factory
+{
+    etch_object object;
+
+    void* thisx;        /* params owner TODO populate this */
+
+    wchar_t*            in_uri;
+    etch_resources*     in_resx;
+    etch_value_factory* in_valufact;
+    etch_threadpool*    mainpool;   /* main listener thread manager*/
+    etch_threadpool*    subpool;
+    etch_threadpool*    qpool;      /* session thread manager */
+    etch_threadpool*    fpool;      /* session thread manager */
+    etch_mutex*          mblock;     /* utility lock */
+    etch_object*            session;    /* i_session_listener* */ 
+    i_session*          isession;   /* listener's i_session */  
+    etch_arraylist*     clientlist; /* create session in new_helper_accepted_server() */  
+
+    /* pointer to xxxx_helper_listener_create() in xxxx_helper */
+    helper_listener_create_func helper_new_listener;
+
+    /* pointer to new_xxxx_server() in [main] */
+    main_server_create_func main_new_server; 
+
+} etch_server_factory;
+
+
+/**
+ * etch_client_factory
+ * masked by etch_factory_params
+ */
+typedef struct etch_client_factory
+{
+    etch_object object;
+
+    void* thisx;        /* params owner todo populate this */
+
+    wchar_t*            in_uri;
+    etch_resources*     in_resx;
+    etch_value_factory* in_valufact;
+    etch_threadpool*    mainpool;
+    etch_threadpool*    subpool;
+    etch_threadpool*    qpool;
+    etch_threadpool*    fpool;
+    etch_mutex*          rwlock;  /* mailbox read/write lock */
+    etch_object*   session; /* unused? */ 
+    i_session* isession;/* unused? */  
+    etch_arraylist*     per_server;  /* unused? */
+
+    main_client_create_func new_client;
+    new_client_impl_funcptr new_client_impl;  /* unused */
+
+    int   server_id;
+    void* server;   /* xxxx_remote_server* use: is_etch_remote_server(x) */
+    void* iclient;  /* i_xxxx_client use: is_etch_client_base(x) */
+    void* stub;     /* xxxx_client_stub* */
+    i_delivery_service* dsvc; /* use: is_etch_ideliverysvc(x) */
+
+} etch_client_factory;
+
+
+etch_tcp_delivery_service* new_tcp_delivery_service (etch_url*, etch_factory_params*, etch_tcp_connection*);
+etch_tcp_delivery_service* get_etch_ds_impl (i_delivery_service*); 
+
+etch_resources* etch_transport_resources_init(etch_resources*); 
+
+etch_resources* get_etch_transport_resources(etch_resources*);
+
+etch_client_factory* new_client_factory (etch_object* session, i_session* isession, main_client_create_func client_create_func);
+etch_server_factory* new_server_factory (etch_object* session, i_session* isession, helper_listener_create_func helper_listener_create, main_server_create_func main_server_create);
+
+i_delivery_service* new_delivery_service_interface(i_sessionmessage*, i_transportmessage*);  
+i_delivery_service* new_etch_transport  (wchar_t*  uri, etch_factory_params*, void* conximpl);
+i_delivery_service* new_etch_transport_a(etch_url* url, etch_factory_params*, void* conximpl);
+
+etch_session* remove_etch_session (etch_server_factory*, const int session_id);
+int  get_etch_session (etch_server_factory*, const int session_id, etch_session** out);
+int  transport_teardown_client_sessions (i_sessionlistener*);
+int  transport_session_count (i_sessionlistener*);
+int  transport_thread_id (i_sessionlistener*);
+
+i_sessionlistener* new_etch_listener (wchar_t* uri, etch_resources* resources, void* factory_thisx, helper_listener_create_func, main_server_create_func, helper_resources_init_func);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHTRANSPORT_H */
diff --git a/binding-c/runtime/c/include/etch_transport_data.h b/binding-c/runtime/c/include/etch_transport_data.h
new file mode 100644
index 0000000..12f9694
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_transport_data.h
@@ -0,0 +1,83 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_transportdata.h
+ * i_transportdata interface
+ * interface used to deliver messages to the transport from the transport
+ */
+#ifndef ETCHITRANSPORTDATA_H
+#define ETCHITRANSPORTDATA_H
+
+#if(0)
+
+ TRANSPORTDATA
+ |  void transportData(Who to, buffer)  
+  - TRANSPORT<SessionData>
+      transportQuery(); transportl(); transport();
+      getSession(); setSession();
+ 
+#endif
+
+#include "etch_transportint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*etch_transport_data) (void* thisx, void* whofrom, void* buffer);
+
+
+/**
+ * i_transportdata
+ * transportdata interface
+ * a message handler delivers messages from a message source
+ */
+typedef struct i_transportdata
+{
+    etch_object object;
+
+    void* thisx; /* object which is the interface implementor */
+
+    /* transport interface */
+    i_transport* itransport;  /* owned */
+    etch_transport_control transport_control;  
+    etch_transport_notify  transport_notify;   
+    etch_transport_query   transport_query;   
+    etch_transport_get_session  get_session;   
+    etch_transport_set_session  set_session;  
+
+   /**
+     * transport_data()
+     * delivers data to transport from ...
+     * @param to recipient
+     * @param message the message  
+     * @return 0 success, -1 error
+     */
+    etch_transport_data transport_data;
+
+} i_transportdata;
+
+
+i_transportdata* new_transportdata_interface(void* thisx, etch_transport_data, i_transport*); 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHITRANSPORTDATA_H */
diff --git a/binding-c/runtime/c/include/etch_transport_message.h b/binding-c/runtime/c/include/etch_transport_message.h
new file mode 100644
index 0000000..f995d20
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_transport_message.h
@@ -0,0 +1,84 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_transportmsg.h
+ * i_transportmessage interface
+ * interface used to deliver messages to the transport from the transport
+ */
+
+#ifndef ETCHITRANSPORTMSG_H
+#define ETCHITRANSPORTMSG_H
+
+#if(0)
+
+ TRANSPORTMESSAGE
+ |  void transportMessage(Who to, message)  
+  - TRANSPORT<SessionMessage>
+      transportQuery(); transportl(); transport();
+      getSession(); setSession();
+ 
+#endif
+
+#include "etch_transportint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*etch_transport_message) (void* thisx, void* whofrom, void* message);
+
+
+/**
+ * i_transportmessage
+ * transportmessage interface
+ * a message handler delivers messages from a message source
+ */
+typedef struct i_transportmessage
+{
+    etch_object object;
+
+    void* thisx; /* object which is the interface implementor */
+
+    /* transport interface */
+    i_transport* itransport;
+    etch_transport_control transport_control;  
+    etch_transport_notify  transport_notify;   
+    etch_transport_query   transport_query;   
+    etch_transport_get_session  get_session;   
+    etch_transport_set_session  set_session;  
+
+   /**
+     * transport_message()
+     * delivers data to transport from ...
+     * @param to recipient
+     * @param message the message  
+     * @return 0 success, -1 error
+     */
+    etch_transport_message transport_message;
+
+} i_transportmessage;
+
+
+i_transportmessage* new_transportmsg_interface(void* thisx, etch_transport_message, i_transport*); 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHITRANSPORTMSG_H */
diff --git a/binding-c/runtime/c/include/etch_transport_packet.h b/binding-c/runtime/c/include/etch_transport_packet.h
new file mode 100644
index 0000000..c029b4d
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_transport_packet.h
@@ -0,0 +1,93 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_transportpkt.h
+ * i_transportpacket interface
+ * interface used to deliver packets to transport from session
+ */
+
+#ifndef ETCHITRANSPORTPACKET_H
+#define ETCHITRANSPORTPACKET_H
+
+
+#if(0)
+
+ TRANSPORTPACKET
+ |  int transportPacket(Who from, packetbuffer)  
+  - TRANSPORT
+       transportQuery(); transportControl(); transportNotify();
+ 
+#endif
+
+
+#include "etch_transportint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int (*etch_transport_packet) (void* thisx, void* whoto, void* buffer);
+typedef int (*etch_transport_packet_headersize) (void* thisx);
+
+
+/**
+ * i_transportpacket
+ * transportpacket interface
+ */
+typedef struct i_transportpacket
+{
+    etch_object object;
+
+    void* thisx; /* object which is the interface implementor */
+
+    /* transport interface */
+    i_transport* itransport;
+    etch_transport_control transport_control;  
+    etch_transport_notify  transport_notify;   
+    etch_transport_query   transport_query;   
+    etch_transport_get_session  get_session;   
+    etch_transport_set_session  set_session; 
+
+    /**
+     * transport_packet()
+     * delivers packet to transport after adding packet header.
+     * @param to recipient
+     * @param buffer buffer positioned at the packet data, with space for header
+     * @return 0 success, -1 error
+     */
+    etch_transport_packet  transport_packet; 
+
+    /**
+     * etch_transport_packet_headersize()
+     * @return size of packet header in bytes
+     */
+    etch_transport_packet_headersize  get_headersize;
+
+    int   header_size;
+
+} i_transportpacket;
+
+
+i_transportpacket* new_transportpkt_interface(void* thisx, etch_transport_packet, i_transport*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHITRANSPORTPACKET_H */
diff --git a/binding-c/runtime/c/include/etch_transportint.h b/binding-c/runtime/c/include/etch_transportint.h
new file mode 100644
index 0000000..5b9e72c
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_transportint.h
@@ -0,0 +1,102 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_transportint.h
+ * transport interface
+ */
+#ifndef ETCHITRANSPORT_H
+#define ETCHITRANSPORT_H
+
+#include "etch_object.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * the memory ownership contracts for control, notify, and query, are:
+ * caller relinquishes all arguments except of course the this pointer,
+ * regardless of outcome. it follows that only simple and temporal
+ * objects are passed as parameters.
+ */
+typedef int   (*etch_transport_control) (void* thisx, etch_event* eventx, etch_object*);
+typedef int   (*etch_transport_notify)  (void* thisx, etch_event* eventx);
+typedef etch_object* (*etch_transport_query)   (void* thisx, etch_query*);
+
+struct i_sessionmessage;
+typedef struct i_session* (*etch_transport_get_session) (void* thisx);
+typedef void  (*etch_transport_set_session) (void* thisx, void*);
+
+
+/**
+ * i_transport
+ * transport interface
+ * not an etch object, ergo no destructor
+ */
+typedef struct i_transport
+{
+    etch_transport_control transport_control;
+    etch_transport_notify  transport_notify;
+    etch_transport_query   transport_query;
+
+    etch_transport_get_session  get_session;
+    etch_transport_set_session  set_session;
+
+    void* thisx;
+
+} i_transport;
+
+
+
+/**
+ * i_transport_mask
+ * mask over any implemented transport interface
+ */
+typedef struct i_transport_mask
+{
+    etch_object object;
+
+    void* thisx; /* object which is the interface implementor */
+
+    /* transport interface */
+    i_transport* itransport;
+    etch_transport_control transport_control;
+    etch_transport_notify  transport_notify;
+    etch_transport_query   transport_query;
+    etch_transport_get_session  get_session;
+    etch_transport_set_session  set_session;
+
+    void* main_transport_method;
+
+} i_transport_mask;
+
+
+i_transport* new_default_transport_interface();
+
+i_transport* new_transport_interface(void* thisx, etch_transport_control, etch_transport_notify, etch_transport_query);
+
+i_transport* new_transport_interface_ex(void* thisx, etch_transport_control, etch_transport_notify, etch_transport_query, etch_transport_get_session, etch_transport_set_session);
+
+i_transport* clone_transport(void* thisx, const i_transport*) ;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ETCHITRANSPORT_H */
diff --git a/binding-c/runtime/c/include/etch_type.h b/binding-c/runtime/c/include/etch_type.h
new file mode 100644
index 0000000..f8aa3d1
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_type.h
@@ -0,0 +1,134 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_type.h  
+ * an etch_type is an etch_id_name representing a type of a struct or message 
+ */
+
+#ifndef ETCHTYPE_H
+#define ETCHTYPE_H
+
+#include "etch_id_name.h"
+#include "etch_hash.h"
+#include "etch_field.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct etch_serializer;
+
+#define ETCHTYPE_DEFSIZE_VTORMAP  4
+#define ETCHTYPE_DEFSIZE_FIELDMAP 8
+
+/** 
+ * etch_type (see etch_id_name.h)
+ */
+typedef etch_id_name etch_type;
+
+struct etch_stub;
+struct i_delivery_service;
+struct etch_who;
+struct etch_message;
+
+/** 
+ * nonspecific stub helper callback signature.
+ * the parameter types are in reality (StubBase, DeliveryService, T obj, Who, Message)
+ * however we can't include those headers here.
+ */
+typedef int (*opaque_stubhelper) (struct etch_stub* stub, struct i_delivery_service* delsvc, void* obj, struct etch_who* sender, struct etch_message* msg);
+
+/** 
+ * etch_type_impl
+ * etch_type instance data extending etch_id_name 
+ */
+typedef struct etch_type_impl
+{
+    etch_object object;
+
+    etch_hashtable* fieldmap;          /* map owned, content not owned */
+    etch_hashtable* vtormap;           /* map & keys owned, values maybe */
+    /* if validators order is significant we can use etch_arraylist */
+  
+    etch_type*  result_type;           /* not owned */
+    etch_type*  super_type;            /* not owned */
+    etch_field* response_field;        /* not owned */
+
+    opaque_stubhelper stubhelper;      /* stub helper method */
+    struct etch_serializer*  impexphelper;    /* owned */
+
+    unsigned int   timeout;            /* ms to wait for response */
+    unsigned int   component_class;    /* type/class of content, not owned */
+    unsigned char  is_run_validators;
+    unsigned char  async_mode;
+
+} etch_type_impl;
+
+
+etch_type* new_type(const wchar_t* name);
+etch_type* new_static_type(const wchar_t* name);
+int destroy_static_type(etch_type*);
+
+etch_field*   etchtype_add_field        (etch_type*, etch_field* field);
+etch_field*   etchtype_get_field_by_id  (etch_type*, const unsigned id);
+etch_field*   etchtype_get_field_by_name(etch_type*, const wchar_t* name);
+etch_id_name* etchtype_get_key_by_id    (etch_hashtable*, const unsigned id);
+etch_id_name* etchtype_get_key_by_name  (etch_hashtable*, const wchar_t*);
+int etchtype_set_fields_iterator(etch_type*, etch_iterator*);
+void* etchtype_get_fields  (etch_type*);
+int   etchtype_fields_count(etch_type*);
+
+int etchtype_put_validator (etch_type*, etch_field*, etch_object*); 
+etch_object* etchtype_get_validator_by_id  (etch_type*, const unsigned id);
+etch_object* etchtype_get_validator_by_name(etch_type*, const wchar_t* name);
+int etchtype_set_validators_iterator(etch_type*, etch_iterator*);
+int etchtype_clear_validator (etch_type*, etch_field*);
+int etchtype_clear_validators(etch_type*);
+int etchtype_validators_count(etch_type*);
+
+unsigned int  etchtype_get_timeout(etch_type*);
+unsigned int  etchtype_set_timeout(etch_type*, unsigned int ms);
+etch_field*   etchtype_get_response_field(etch_type*);
+etch_field*   etchtype_set_response_field(etch_type*, etch_field*);
+unsigned int  etchtype_get_component_type(etch_type*);
+unsigned int  etchtype_set_component_type(etch_type*, unsigned int typeclass);
+etch_type*    etchtype_set_result_type(etch_type*, etch_type* rtype);
+etch_type*    etchtype_get_result_type(etch_type*);
+etch_type*    etchtype_set_super_type(etch_type*, etch_type* stype);
+etch_type*    etchtype_get_super_type(etch_type*);
+unsigned char etchtype_set_run_validators(etch_type*, unsigned char val);
+unsigned char etchtype_get_run_validators(etch_type*);
+unsigned char etchtype_set_async_mode (etch_type*, unsigned char);
+unsigned char etchtype_get_async_mode (etch_type*);
+opaque_stubhelper etchtype_set_type_stubhelper(etch_type*, opaque_stubhelper);
+opaque_stubhelper etchtype_get_type_stubhelper(etch_type*);
+struct etch_serializer*  etchtype_set_impexphelper(etch_type*, struct etch_serializer*);
+struct etch_serializer*  etchtype_get_impexphelper(etch_type*);
+int etchtype_is_assignable_from(etch_type* type, etch_type* othertype);
+
+#define is_good_type    is_good_id_name
+#define is_equal_types  is_equal_id_names
+#define compute_type_id compute_id_name_id
+#define compute_type_id_from_widename compute_field_id_from_widename
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHTYPE_H*/ 
diff --git a/binding-c/runtime/c/include/etch_url.h b/binding-c/runtime/c/include/etch_url.h
new file mode 100644
index 0000000..ae4a861
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_url.h
@@ -0,0 +1,83 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etchurl.h -- URL class
+ * modeled after java binding URL class
+ */
+
+#ifndef ETCHURL_H
+#define ETCHURL_H
+
+#include "etch_collection.h"
+#include "etch_arraylist.h"
+#include "etch_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCH_URL_DEFAULT_SCHEME L"http"
+#define ETCH_URL_DEFNUMPARMS 4
+#define ETCH_URL_DEFNUMTERMS 4
+#define ETCH_URL_DEFSUBTERMS 4
+
+
+typedef struct etch_url
+{
+    etch_object object;
+
+    unsigned port;
+
+    wchar_t* raw;
+    wchar_t* scheme;  
+    wchar_t* user;  
+    wchar_t* password; 
+    wchar_t* fragment; 
+    wchar_t* host;  
+    wchar_t* uri;  
+
+    etch_arraylist* params;
+    etch_hashtable* terms;  
+
+    size_t charcount;
+    size_t bytecount;
+
+} etch_url;
+
+
+etch_url* new_url(wchar_t* urlstring);
+etch_object* etchurl_get_term (etch_url*, const wchar_t* termname);
+boolean etchurl_get_boolean_term(etch_url*, const wchar_t* termname, boolean* retval);
+etch_iterator* etchurl_get_params(etch_url*);
+etch_object* etchurl_remove_term(etch_url*, wchar_t* key);
+int etchurl_get_integer_term(etch_url*, const wchar_t* termname, int* retval);
+int etchurl_add_term(etch_url*, wchar_t* termname, wchar_t* termval);
+int etchurl_add_double_term( etch_url*, wchar_t* termname, const double termval);
+int etchurl_add_integer_term(etch_url*, wchar_t* termname, const int termval);
+int etchurl_paramcount(etch_url*);
+int etchurl_termcount (etch_url*);
+
+int is_url_scheme_http (etch_url*); 
+int is_url_scheme_udp  (etch_url*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCHURL_H */
diff --git a/binding-c/runtime/c/include/etch_validator.h b/binding-c/runtime/c/include/etch_validator.h
new file mode 100644
index 0000000..2f55072
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_validator.h
@@ -0,0 +1,265 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_validator.h
+ */
+
+#ifndef ETCH_VALIDATOR_H
+#define ETCH_VALIDATOR_H
+
+#include "etch_object.h"
+#include "etch_type.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ETCHVTOR_MAX_NDIMS  3  /* max array dimensions */
+#define ETCHVTOR_MAX_CACHED 4  /* max cached vtors per type */
+
+struct etch_validator;
+typedef int (*etchvtor_validate)  (struct etch_validator*, etch_object*);
+typedef int (*etchvtor_checkvalue)(struct etch_validator*, etch_object*, byte* out);
+typedef etch_object* (*etchvtor_validate_value)(struct etch_validator*, etch_object*);
+typedef struct etch_validator* (*etchvtor_element_validator)(struct etch_validator*);
+
+
+/** 
+ *  etch_validator
+ *  vet message values 
+ */
+typedef struct etch_validator
+{
+    etch_object object;
+
+    /**
+     * etch_validator virtuals
+     */
+    etchvtor_validate   validate;
+    etchvtor_checkvalue check_value;
+    etchvtor_validate_value    validate_value;
+    etchvtor_element_validator element_validator;
+
+    /** 
+     * etch_type_validator instance data
+     */
+    unsigned short  expected_obj_type;
+    unsigned short  expected_class_id;
+    int             numdimensions;
+    char*           description;   /* owned */
+    etch_type*      struct_type;   /* not owned */
+    etchparentinfo* inherits_from; /* owned or not, see flag */
+    unsigned char   is_cached;
+    unsigned char   is_subclassable;
+    unsigned char   is_owned_inherits_from;  
+    unsigned char   unused;
+
+    /* etch_combo_validator instance data
+     */
+    struct etch_validator* vtor_a; /* not owned */
+    struct etch_validator* vtor_b; /* not owned */
+
+} etch_validator;
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * validator constructors and public methods
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+etch_validator* new_validator();
+
+etch_validator* new_validator_from(etchvtor_validate, etchvtor_checkvalue, etchvtor_element_validator, etchvtor_validate_value);
+
+etch_validator* new_type_validator_1
+   (const unsigned short vtor_classid,
+    const unsigned short scalar_obj_type,
+    const unsigned short scalar_classid, 
+    const unsigned short scalar_vtabkey,
+    const unsigned short array_classid, 
+    const int ndims, char* descr);
+
+etch_validator* new_type_validator_2
+   (const unsigned short vtor_classid,
+    const unsigned short scalar_obj_type,
+    const unsigned short scalar_classid, 
+    const unsigned short array_classid, 
+    etchparentinfo* inheritlist,
+    const int ndims, char* descr);
+
+int etchvtor_check_dimensions(const int);
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * validator cache
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/* the validator cache is a single memory array, subdivided into caches for
+ * each validator type, which caches instantiated validators. validators are 
+ * cached to a max number of dimensions. end of service processing should 
+ * iterate the static cache and free memory for validators cached therein,
+ * in order for memory allocation tests to pass. validators have an is_cached
+ * flag, regarded by the etch_validator dtor, so validator user can destroy()
+ * validator regardless of its cache state, the dtor will check the flag and
+ * refuse to destroy if cached. the final cleanup must therefore clear the
+ * is_cached marker on each cached validator prior to calling destroy(). 
+ */
+#define ETCHVTOR_CACHED_TYPE_COUNT 12 /* count of cached validator types */
+#define ETCHVTOR_BYTES_PER_CACHE (sizeof(void*) * ETCHVTOR_MAX_CACHED) 
+
+// the validator cache
+extern etch_validator* etchvtor_cache[ETCHVTOR_CACHED_TYPE_COUNT * ETCHVTOR_MAX_CACHED];
+
+void etchvtor_clear_cache();
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * boolean validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_BOOLEAN  0   /* boolean validator cache slot index */
+extern etch_validator** etchvtor_cache_boolean; /* boolean validator cache address */
+etch_validator*  etchvtor_boolean_get(const int dimensions);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * byte validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_BYTE     1   /* byte validator cache slot index */
+extern etch_validator** etchvtor_cache_byte;    /* byte validator cache address */
+etch_validator*  etchvtor_byte_get(const int dimensions);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * int8 validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_INT8     2   /* int8 validator cache slot index */
+extern etch_validator** etchvtor_cache_int8;    /* int8 validator cache address */
+etch_validator*  etchvtor_int8_get(const int dimensions);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * int16 validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_INT16    3   /* int16 validator cache slot index */
+extern etch_validator** etchvtor_cache_int16;   /* int16 validator cache address */
+etch_validator*  etchvtor_int16_get(const int dimensions);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * int32 validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_INT32    4   /* int32 validator cache slot index */
+extern etch_validator** etchvtor_cache_int32;   /* int32 validator cache address */
+etch_validator*  etchvtor_int32_get(const int dimensions);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * int64 validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_INT64    5    /* int64 validator cache slot index */
+extern etch_validator** etchvtor_cache_int64;    /* int64 validator cache address */
+etch_validator*  etchvtor_int64_get(const int dimensions);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * float validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_FLOAT    6   /* float validator cache slot index */
+extern etch_validator** etchvtor_cache_float;   /* float validator cache address */
+etch_validator*  etchvtor_float_get (const int dimensions);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * double validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_DOUBLE    7   /* double validator cache slot index */
+extern etch_validator** etchvtor_cache_double;   /* double validator cache address */
+etch_validator*  etchvtor_double_get (const int dimensions);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * string validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_STRING    8   /* string validator cache slot index */
+extern etch_validator** etchvtor_cache_string;   /* string validator cache address */
+etch_validator*  etchvtor_string_get (const int dimensions);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * object validator (etch_object* anonymous wrapper)
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_OBJECT    9   /* object validator cache slot index */
+extern etch_validator** etchvtor_cache_object;   /* object validator cache address */
+etch_validator*  etchvtor_object_get (const int dimensions);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * exception validator 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_EXCEPTION 10   /* excp validator cache slot index */
+extern etch_validator** etchvtor_cache_exception; /* excp validator cache address */
+etch_validator*  etchvtor_exception_get(); 
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * eod_validator (end-of-data maker "none")
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+#define ETCHVTOR_CACHE_SLOT_EOD    11  /* eod validator cache slot index */
+extern etch_validator** etchvtor_cache_eod;   /* eod validator cache address */
+etch_validator*  etchvtor_eod_get();
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * struct validator (not cached since unique per type)
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+etch_validator*  new_validator_struct();
+etch_validator*  etchvtor_struct_get(etch_type*, const int numdims);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * combo validator (not cached)
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+etch_validator* new_combo_validator(etch_validator* vtor_a, etch_validator* vtor_b);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * custom validator (cached in a custom cache)
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+etch_validator* new_validator_custom(const unsigned short obj_type, const unsigned short class_id, etch_type*, const int numdims);
+etch_validator* etchvtor_custom_get(const unsigned short obj_type, const unsigned short class_id, etch_type*, const int numdims);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_VALIDATOR_H */
diff --git a/binding-c/runtime/c/include/etch_value_factory.h b/binding-c/runtime/c/include/etch_value_factory.h
new file mode 100644
index 0000000..20b833e
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_value_factory.h
@@ -0,0 +1,199 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_valufact.h
+ * value factory is an interface defining the value factory which helps the
+ * idl compiler serialize and deserialize messages, convert values, etc.
+ */
+
+#ifndef ETCH_VALUFACT_H
+#define ETCH_VALUFACT_H
+
+#include "etch_msgutl.h"
+#include "etch_arraylist.h"
+#include "etch_structval.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct i_value_factory;
+struct etch_message;
+
+/**
+ * value_factory
+ * value factory implementation
+ */
+typedef struct etch_value_factory
+{
+    etch_object object;
+
+    etch_object* impl;
+
+} etch_value_factory;
+ 
+
+/**
+ * i_value_factory
+ * virtual function table for value factory
+ */
+struct i_value_factory
+{
+    etch_object object;
+
+    etchparentinfo* inherits_from;
+
+    /* - - - - - - - - - - - -
+     * type
+     * - - - - - - - - - - - -
+     */
+
+	/**
+	 * adds a type to the set of types.
+	 * @return the argument. If there is a collision with
+	 * an id and name, both associated with the same type,
+	 * then that type is returned instead of the argument.
+	 * @throws IllegalArgumentException (returns NULL) if
+	 * bad arg, or if collision in the id or name or both,
+	 * when not associated with the same type.
+	 */
+	etch_type* (*add_type) (void* vf, etch_type*);
+
+	/**
+	 * translates a type id into the associated etch_type object.
+	 */
+	etch_type* (*get_type_by_id) (void* vf, const unsigned id);
+
+	/**
+	 * translates a name into the associated etch_type object.
+	 */
+	etch_type* (*get_type_by_name) (void* vf, const wchar_t* name);
+
+	/**
+	 * @return a collection of all the types 
+	 */
+	etch_arraylist* (*get_types) (void* vf);
+
+
+    /* - - - - - - - - - - - -
+     * encoding
+     * - - - - - - - - - - - -
+     */
+
+	/**
+	 * @return the encoding to use for strings.
+	 */
+	wchar_t* (*get_string_encoding) (void* vf);
+
+
+    /* - - - - - - - - - - - -
+     * message id
+     * - - - - - - - - - - - -
+     */
+
+	/**
+	 * @param msg the message whose well-known id field is to be returned.
+	 * @return the value of the well-known message-id field. This is a
+	 * unique identifier for this message on a particular transport
+	 * during a particular session. If there is no well-known message-id
+	 * field defined, or if the message-id field has not been set, then
+	 * return null. TODO: determine WHY we can't return an int64 with value
+     * zero equating to null?
+	 */
+	etch_int64* (*get_message_id) (void* vf, struct etch_message*);
+
+	/**
+	 * sets the value of the well-known message-id field. this is a unique
+	 * identifier for this message on a particular transport during a
+	 * particular session. if there is no well-known message-id field
+	 * defined then no action is taken. if msgid is null, the field
+	 * is cleared. 
+     * regardless, the msgid object memory is owned by this method, to be 
+     * assigned to the value factory; therefore if the action fails, this
+     * method must destroy the object.
+	 */
+	int (*set_message_id) (void* vf, struct etch_message*, etch_int64* msgid);
+
+
+    /* - - - - - - - - - - - -
+     * reply to
+     * - - - - - - - - - - - -
+     */
+
+	/**
+	 * @return the value of the in-reply-to field, or null if there is
+	 * none or if there is no such field defined.
+	 */
+	etch_int64* (*get_in_reply_to) (void* vf, struct etch_message*);
+
+	/**
+	 * if no well-known in-reply-to field defined then no action is taken.
+	 * if msgid is null, the field is cleared.
+	 */
+	 int (*set_in_reply_to) (void* vf, struct etch_message*, etch_int64* msgid);
+
+
+    /* - - - - - - - - - - - -
+     * value conversion
+     * - - - - - - - - - - - -
+     */
+
+	/**
+	 * Converts a value to a struct value representation to be exported
+	 * to a tagged data output.
+	 * @param value a custom type defined by a service, or a well-known
+	 * standard type (e.g., date).
+	 * @return a struct value representing the value.
+	 */
+	etch_structvalue* (*export_custom_value) (void* vf, etch_object* value);
+
+	/**
+	 * Converts a struct value imported from a tagged data input to
+	 * a normal type.
+	 * @param sv a struct value representation of a custom type, or a
+	 * well known standard type.
+	 * @return a custom type, or a well known standard type.
+	 */
+	etch_object* (*import_custom_value) (void* vf, etch_structvalue* sv);
+
+	/**
+	 * @param class_id the class of a custom value.
+	 * @return the struct type of a custom value class.
+	 */
+	etch_type* (*get_custom_struct_type) (void* vf, const unsigned etchclass);
+
+	/**
+	 * get well-known message type for exception thrown by oneway message
+	 */
+    etch_type* (*get_mt_exception) (void* vf);
+};
+
+typedef struct i_value_factory i_value_factory;
+
+/**
+ * constructors/destructors
+ */
+etch_value_factory* new_value_factory(const int objlen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_VALUFACT_H */
diff --git a/binding-c/runtime/c/include/etch_wait.h b/binding-c/runtime/c/include/etch_wait.h
new file mode 100644
index 0000000..45a0683
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_wait.h
@@ -0,0 +1,111 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_wait.h -- wait implementation
+ */
+
+#ifndef _ETCH_WAIT_H_
+#define _ETCH_WAIT_H_
+
+#include "etch_errno.h"
+#include "etch_mem.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct etch_wait_t etch_wait_t;
+
+/**
+ * create a new etch wait instance. 
+ * @param waiter address where the new created mutex will be stored.
+ * @param pool memory pool, if pool is null the global pool will be used
+ * @return status
+ */
+etch_status_t etch_wait_create(etch_wait_t** waiter, etch_pool_t* pool);
+
+/**
+ * set autoreset mode
+ * @param waiter instance.
+ * @param autorest mode 0 = autoreset off, 1 = autoreset on. If autoreset is
+ *        on, the signal state will automaticly reset after a signal was send to
+ *        the sleeping threads.
+ * @return status
+ */
+
+
+/**
+ * wait until signaled.
+ * @param waiter instance
+ * @return status
+ */
+etch_status_t etch_wait_wait(etch_wait_t* waiter, int64 cond_value);
+
+/**
+ * wait until signaled and new value.
+ * @param waiter instance
+ * @param timeout in ms
+ * @return status
+ */
+etch_status_t etch_wait_wait_and_set(etch_wait_t* waiter, int64 cond_value, int64 new_cond_value);
+
+/**
+ * wait timed until signaled.
+ * @param waiter instance
+ * @param timeout in ms
+ * @return status
+ */
+etch_status_t etch_wait_timedwait(etch_wait_t* waiter, int64 cond_value, uint32 timeout);
+
+/**
+ * wait timed until signaled and new value.
+ * @param waiter instance
+ * @param timeout in ms
+ * @return status
+ */
+etch_status_t etch_wait_timedwait_and_set(etch_wait_t* waiter, int64 cond_value, uint32 timeout, int64 new_cond_value);
+
+
+/**
+ * set etch_wait in signaled state, all waiting thread will
+ * be signaled
+ * @param waiter instance
+ * @return status
+ */
+etch_status_t etch_wait_set(etch_wait_t* waiter, int64 cond_value);
+
+/**
+ * set condition variable without signaling waiting threads
+ * be signaled
+ * @param waiter instance
+ * @return status
+ */
+etch_status_t etch_wait_reset(etch_wait_t* waiter, int64 cond_value);
+
+/**
+ * destroy the given mutex.
+ * @param mutex
+ */
+etch_status_t etch_wait_destroy(etch_wait_t* waiter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ETCH_WAIT_H_ */
diff --git a/binding-c/runtime/c/include/etch_warn.h b/binding-c/runtime/c/include/etch_warn.h
new file mode 100644
index 0000000..23d1a89
--- /dev/null
+++ b/binding-c/runtime/c/include/etch_warn.h
@@ -0,0 +1,43 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */
+
+/*
+ * etch_warn.h -- warn
+ */
+
+#ifndef ETCH_WARN_H
+#define ETCH_WARN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifndef _UNICODE
+#pragma message("WARNING: _UNICODE not defined")
+#endif
+
+#ifndef UNICODE
+#pragma message("WARNING: UNICODE not defined")
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* #ifndef ETCH_WARN_H */
diff --git a/binding-c/runtime/c/include/etchinternal_single_linked_list.h b/binding-c/runtime/c/include/etchinternal_single_linked_list.h
new file mode 100644
index 0000000..4c060f6
--- /dev/null
+++ b/binding-c/runtime/c/include/etchinternal_single_linked_list.h
@@ -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.
+ *
+ */
+
+#ifndef etch_thread_help_h_included
+#define etch_thread_help_h_included
+
+#include <stdlib.h>
+
+
+typedef struct etchinternal_single_linked_list_node {
+  void* data;
+  struct etchinternal_single_linked_list_node* next;
+} etchinternal_single_linked_list_node;
+
+typedef struct etchinternal_single_linked_list {
+  etchinternal_single_linked_list_node* head;
+} etchinternal_single_linked_list;
+
+etchinternal_single_linked_list_node* etchinternal_single_linked_list_node_create(void* data, etchinternal_single_linked_list_node* next);
+etchinternal_single_linked_list* etchinternal_single_linked_list_create();
+void etchinternal_single_linked_list_destroy(etchinternal_single_linked_list* list);
+void etchinternal_single_linked_list_add(etchinternal_single_linked_list* list, void* data, size_t size);
+
+typedef int (*etchinternal_find_func)(void*, void*);
+void* etchinternal_single_linked_list_find(etchinternal_single_linked_list* list, etchinternal_find_func find, void* find_data);
+
+#endif
diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenkfasthash.c b/binding-c/runtime/c/src/extern/jenkhash/jenkfasthash.c
new file mode 100644
index 0000000..a74389e
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenkfasthash.c
@@ -0,0 +1,1008 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+-------------------------------------------------------------------------------
+lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+From website: "Update: I'm leaving the old hash ..., but I've got a new hash at 
+http://burtleburtle.net/bob/c/lookup3.c (this code -- JLD) that is roughly twice 
+as fast and more thorough than the one (used in lookup.c -- JLD). It's designed 
+along the same lines as the hash below, 12 byte blocks, switch statements, etc. 
+The biggest theoretical distinction is it has different mixing functions for the 
+last block than for all but the last block, at 21 and 24 instructions, instead of 
+the 36 instruction mix below that serves for both. It also has separate code paths 
+for aligned and unaligned strings, to take advantage of 2-byte and 4-byte reads 
+when it can. "
+
+These are functions for producing 32-bit hashes for hash table lookup.
+hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() 
+are externally useful functions.  Routines to test the hash are included 
+if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+the public domain.  It has no warranty.
+
+You probably want to use hashlittle().  hashlittle() and hashbig()
+hash byte arrays.  hashlittle() is is faster than hashbig() on
+little-endian machines.  Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+hashlittle() except it returns two 32-bit hashes for the price of one.  
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+  a = i1;  b = i2;  c = i3;
+  mix(a,b,c);
+  a += i4; b += i5; c += i6;
+  mix(a,b,c);
+  a += i7;
+  final(a,b,c);
+then use c as the hash value.  If you have a variable length array of
+4-byte integers to hash, use hashword().  If you have a byte array (like
+a character string), use hashlittle().  If you have several byte arrays, or
+a mix of things, see the comments above hashlittle().  
+
+Why is this so big?  I read 12 bytes at a time into 3 4-byte integers, 
+then mix those integers.  This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+-------------------------------------------------------------------------------
+*/
+#define SELF_TEST 1
+
+#include <stdio.h>      /* defines printf for tests */
+#include <time.h>       /* defines time_t for timings in the test */
+#include <stdint.h>     /* defines uint32_t etc */
+#include <sys/param.h>  /* attempt to define endianness */
+#ifdef linux
+# include <endian.h>    /* attempt to define endianness */
+#endif
+
+/*
+ * My best guess at if you are big-endian or little-endian.  This may
+ * need adjustment.
+ */
+#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
+     __BYTE_ORDER == __LITTLE_ENDIAN) || \
+    (defined(i386) || defined(__i386__) || defined(__i486__) || \
+     defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
+       __BYTE_ORDER == __BIG_ENDIAN) || \
+      (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#else
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 0
+#endif
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+  of top bits of (a,b,c), or in any combination of bottom bits of
+  (a,b,c).
+* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+  is commonly produced by subtraction) look like a single 1-bit
+  difference.
+* the base values were pseudorandom, all zero but one bit set, or 
+  all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+    4  6  8 16 19  4
+    9 15  3 18 27 15
+   14  9  3  7 17  3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta.  I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose 
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche.  There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a.  The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism.  Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism.  I did what I could.  Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+  a -= c;  a ^= rot(c, 4);  c += b; \
+  b -= a;  b ^= rot(a, 6);  a += c; \
+  c -= b;  c ^= rot(b, 8);  b += a; \
+  a -= c;  a ^= rot(c,16);  c += b; \
+  b -= a;  b ^= rot(a,19);  a += c; \
+  c -= b;  c ^= rot(b, 4);  b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different.  This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+  of top bits of (a,b,c), or in any combination of bottom bits of
+  (a,b,c).
+* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+  is commonly produced by subtraction) look like a single 1-bit
+  difference.
+* the base values were pseudorandom, all zero but one bit set, or 
+  all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+  4  8 15 26 3 22 24
+ 10  8 15 26 3 22 24
+ 11  8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+{ \
+  c ^= b; c -= rot(b,14); \
+  a ^= c; a -= rot(c,11); \
+  b ^= a; b -= rot(a,25); \
+  c ^= b; c -= rot(b,16); \
+  a ^= c; a -= rot(c,4);  \
+  b ^= a; b -= rot(a,14); \
+  c ^= b; c -= rot(b,24); \
+}
+
+/*
+--------------------------------------------------------------------
+ This works on all machines.  To be useful, it requires
+ -- that the key be an array of uint32_t's, and
+ -- that the length be the number of uint32_t's in the key
+
+ The function hashword() is identical to hashlittle() on little-endian
+ machines, and identical to hashbig() on big-endian machines,
+ except that the length has to be measured in uint32_ts rather than in
+ bytes.  hashlittle() is more complicated than hashword() only because
+ hashlittle() has to dance around fitting the key bytes into registers.
+--------------------------------------------------------------------
+*/
+uint32_t hashword(
+const uint32_t *k,                   /* the key, an array of uint32_t values */
+size_t          length,               /* the length of the key, in uint32_ts */
+uint32_t        initval)         /* the previous hash, or an arbitrary value */
+{
+  uint32_t a,b,c;
+
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval;
+
+  /*------------------------------------------------- handle most of the key */
+  while (length > 3)
+  {
+    a += k[0];
+    b += k[1];
+    c += k[2];
+    mix(a,b,c);
+    length -= 3;
+    k += 3;
+  }
+
+  /*------------------------------------------- handle the last 3 uint32_t's */
+  switch(length)                     /* all the case statements fall through */
+  { 
+  case 3 : c+=k[2];
+  case 2 : b+=k[1];
+  case 1 : a+=k[0];
+    final(a,b,c);
+  case 0:     /* case 0: nothing left to add */
+    break;
+  }
+  /*------------------------------------------------------ report the result */
+  return c;
+}
+
+
+/*
+--------------------------------------------------------------------
+hashword2() -- same as hashword(), but take two seeds and return two
+32-bit values.  pc and pb must both be nonnull, and *pc and *pb must
+both be initialized with seeds.  If you pass in (*pb)==0, the output 
+(*pc) will be the same as the return value from hashword().
+--------------------------------------------------------------------
+*/
+void hashword2 (
+const uint32_t *k,                   /* the key, an array of uint32_t values */
+size_t          length,               /* the length of the key, in uint32_ts */
+uint32_t       *pc,                      /* IN: seed OUT: primary hash value */
+uint32_t       *pb)               /* IN: more seed OUT: secondary hash value */
+{
+  uint32_t a,b,c;
+
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + ((uint32_t)(length<<2)) + *pc;
+  c += *pb;
+
+  /*------------------------------------------------- handle most of the key */
+  while (length > 3)
+  {
+    a += k[0];
+    b += k[1];
+    c += k[2];
+    mix(a,b,c);
+    length -= 3;
+    k += 3;
+  }
+
+  /*------------------------------------------- handle the last 3 uint32_t's */
+  switch(length)                     /* all the case statements fall through */
+  { 
+  case 3 : c+=k[2];
+  case 2 : b+=k[1];
+  case 1 : a+=k[0];
+    final(a,b,c);
+  case 0:     /* case 0: nothing left to add */
+    break;
+  }
+  /*------------------------------------------------------ report the result */
+  *pc=c; *pb=b;
+}
+
+
+/*
+-------------------------------------------------------------------------------
+hashlittle() -- hash a variable-length key into a 32-bit value
+  k       : the key (the unaligned variable-length array of bytes)
+  length  : the length of the key, counting by bytes
+  initval : can be any 4-byte value
+Returns a 32-bit value.  Every bit of the key affects every bit of
+the return value.  Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2.  There is no need to do
+mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+use a bitmask.  For example, if you need only 10 bits, do
+  h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+  for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this
+code any way you wish, private, educational, or commercial.  It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable.  Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
+{
+  uint32_t a,b,c;                                          /* internal state */
+  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */
+
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+  u.ptr = key;
+  if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
+    const uint8_t  *k8;
+
+    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      b += k[1];
+      c += k[2];
+      mix(a,b,c);
+      length -= 12;
+      k += 3;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    /* 
+     * "k[2]&0xffffff" actually reads beyond the end of the string, but
+     * then masks off the part it's not allowed to read.  Because the
+     * string is aligned, the masked-off tail is in the same word as the
+     * rest of the string.  Every machine with memory protection I've seen
+     * does it on word boundaries, so is OK with this.  But VALGRIND will
+     * still catch it and complain.  The masking trick does make the hash
+     * noticably faster for short strings (like English words).
+     */
+#ifndef VALGRIND
+
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+    case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+    case 5 : b+=k[1]&0xff; a+=k[0]; break;
+    case 4 : a+=k[0]; break;
+    case 3 : a+=k[0]&0xffffff; break;
+    case 2 : a+=k[0]&0xffff; break;
+    case 1 : a+=k[0]&0xff; break;
+    case 0 : return c;              /* zero length strings require no mixing */
+    }
+
+#else /* make valgrind happy */
+
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */
+    case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */
+    case 9 : c+=k8[8];                   /* fall through */
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */
+    case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */
+    case 5 : b+=k8[4];                   /* fall through */
+    case 4 : a+=k[0]; break;
+    case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */
+    case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */
+    case 1 : a+=k8[0]; break;
+    case 0 : return c;
+    }
+
+#endif /* !valgrind */
+
+  } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
+    const uint8_t  *k8;
+
+    /*--------------- all but last block: aligned reads and different mixing */
+    while (length > 12)
+    {
+      a += k[0] + (((uint32_t)k[1])<<16);
+      b += k[2] + (((uint32_t)k[3])<<16);
+      c += k[4] + (((uint32_t)k[5])<<16);
+      mix(a,b,c);
+      length -= 12;
+      k += 6;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */
+    case 10: c+=k[4];
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 9 : c+=k8[8];                      /* fall through */
+    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */
+    case 6 : b+=k[2];
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 5 : b+=k8[4];                      /* fall through */
+    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */
+    case 2 : a+=k[0];
+             break;
+    case 1 : a+=k8[0];
+             break;
+    case 0 : return c;                     /* zero length requires no mixing */
+    }
+
+  } else {                        /* need to read the key one byte at a time */
+    const uint8_t *k = (const uint8_t *)key;
+
+    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      a += ((uint32_t)k[1])<<8;
+      a += ((uint32_t)k[2])<<16;
+      a += ((uint32_t)k[3])<<24;
+      b += k[4];
+      b += ((uint32_t)k[5])<<8;
+      b += ((uint32_t)k[6])<<16;
+      b += ((uint32_t)k[7])<<24;
+      c += k[8];
+      c += ((uint32_t)k[9])<<8;
+      c += ((uint32_t)k[10])<<16;
+      c += ((uint32_t)k[11])<<24;
+      mix(a,b,c);
+      length -= 12;
+      k += 12;
+    }
+
+    /*-------------------------------- last block: affect all 32 bits of (c) */
+    switch(length)                   /* all the case statements fall through */
+    {
+    case 12: c+=((uint32_t)k[11])<<24;
+    case 11: c+=((uint32_t)k[10])<<16;
+    case 10: c+=((uint32_t)k[9])<<8;
+    case 9 : c+=k[8];
+    case 8 : b+=((uint32_t)k[7])<<24;
+    case 7 : b+=((uint32_t)k[6])<<16;
+    case 6 : b+=((uint32_t)k[5])<<8;
+    case 5 : b+=k[4];
+    case 4 : a+=((uint32_t)k[3])<<24;
+    case 3 : a+=((uint32_t)k[2])<<16;
+    case 2 : a+=((uint32_t)k[1])<<8;
+    case 1 : a+=k[0];
+             break;
+    case 0 : return c;
+    }
+  }
+
+  final(a,b,c);
+  return c;
+}
+
+
+/*
+ * hashlittle2: return 2 32-bit hash values
+ *
+ * This is identical to hashlittle(), except it returns two 32-bit hash
+ * values instead of just one.  This is good enough for hash table
+ * lookup with 2^^64 buckets, or if you want a second hash if you're not
+ * happy with the first, or if you want a probably-unique 64-bit ID for
+ * the key.  *pc is better mixed than *pb, so use *pc first.  If you want
+ * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
+ */
+void hashlittle2( 
+  const void *key,       /* the key to hash */
+  size_t      length,    /* length of the key */
+  uint32_t   *pc,        /* IN: primary initval, OUT: primary hash */
+  uint32_t   *pb)        /* IN: secondary initval, OUT: secondary hash */
+{
+  uint32_t a,b,c;                                          /* internal state */
+  union { const void *ptr; size_t i; } u;     /* needed for Mac Powerbook G4 */
+
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + ((uint32_t)length) + *pc;
+  c += *pb;
+
+  u.ptr = key;
+  if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
+    const uint8_t  *k8;
+
+    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      b += k[1];
+      c += k[2];
+      mix(a,b,c);
+      length -= 12;
+      k += 3;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    /* 
+     * "k[2]&0xffffff" actually reads beyond the end of the string, but
+     * then masks off the part it's not allowed to read.  Because the
+     * string is aligned, the masked-off tail is in the same word as the
+     * rest of the string.  Every machine with memory protection I've seen
+     * does it on word boundaries, so is OK with this.  But VALGRIND will
+     * still catch it and complain.  The masking trick does make the hash
+     * noticably faster for short strings (like English words).
+     */
+#ifndef VALGRIND
+
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+    case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+    case 5 : b+=k[1]&0xff; a+=k[0]; break;
+    case 4 : a+=k[0]; break;
+    case 3 : a+=k[0]&0xffffff; break;
+    case 2 : a+=k[0]&0xffff; break;
+    case 1 : a+=k[0]&0xff; break;
+    case 0 : *pc=c; *pb=b; return;  /* zero length strings require no mixing */
+    }
+
+#else /* make valgrind happy */
+
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */
+    case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */
+    case 9 : c+=k8[8];                   /* fall through */
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */
+    case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */
+    case 5 : b+=k8[4];                   /* fall through */
+    case 4 : a+=k[0]; break;
+    case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */
+    case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */
+    case 1 : a+=k8[0]; break;
+    case 0 : *pc=c; *pb=b; return;  /* zero length strings require no mixing */
+    }
+
+#endif /* !valgrind */
+
+  } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
+    const uint8_t  *k8;
+
+    /*--------------- all but last block: aligned reads and different mixing */
+    while (length > 12)
+    {
+      a += k[0] + (((uint32_t)k[1])<<16);
+      b += k[2] + (((uint32_t)k[3])<<16);
+      c += k[4] + (((uint32_t)k[5])<<16);
+      mix(a,b,c);
+      length -= 12;
+      k += 6;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */
+    case 10: c+=k[4];
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 9 : c+=k8[8];                      /* fall through */
+    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */
+    case 6 : b+=k[2];
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 5 : b+=k8[4];                      /* fall through */
+    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */
+    case 2 : a+=k[0];
+             break;
+    case 1 : a+=k8[0];
+             break;
+    case 0 : *pc=c; *pb=b; return;  /* zero length strings require no mixing */
+    }
+
+  } else {                        /* need to read the key one byte at a time */
+    const uint8_t *k = (const uint8_t *)key;
+
+    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      a += ((uint32_t)k[1])<<8;
+      a += ((uint32_t)k[2])<<16;
+      a += ((uint32_t)k[3])<<24;
+      b += k[4];
+      b += ((uint32_t)k[5])<<8;
+      b += ((uint32_t)k[6])<<16;
+      b += ((uint32_t)k[7])<<24;
+      c += k[8];
+      c += ((uint32_t)k[9])<<8;
+      c += ((uint32_t)k[10])<<16;
+      c += ((uint32_t)k[11])<<24;
+      mix(a,b,c);
+      length -= 12;
+      k += 12;
+    }
+
+    /*-------------------------------- last block: affect all 32 bits of (c) */
+    switch(length)                   /* all the case statements fall through */
+    {
+    case 12: c+=((uint32_t)k[11])<<24;
+    case 11: c+=((uint32_t)k[10])<<16;
+    case 10: c+=((uint32_t)k[9])<<8;
+    case 9 : c+=k[8];
+    case 8 : b+=((uint32_t)k[7])<<24;
+    case 7 : b+=((uint32_t)k[6])<<16;
+    case 6 : b+=((uint32_t)k[5])<<8;
+    case 5 : b+=k[4];
+    case 4 : a+=((uint32_t)k[3])<<24;
+    case 3 : a+=((uint32_t)k[2])<<16;
+    case 2 : a+=((uint32_t)k[1])<<8;
+    case 1 : a+=k[0];
+             break;
+    case 0 : *pc=c; *pb=b; return;  /* zero length strings require no mixing */
+    }
+  }
+
+  final(a,b,c);
+  *pc=c; *pb=b;
+}
+
+
+
+/*
+ * hashbig():
+ * This is the same as hashword() on big-endian machines.  It is different
+ * from hashlittle() on all machines.  hashbig() takes advantage of
+ * big-endian byte ordering. 
+ */
+uint32_t hashbig( const void *key, size_t length, uint32_t initval)
+{
+  uint32_t a,b,c;
+  union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */
+
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+  u.ptr = key;
+  if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {
+    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
+    const uint8_t  *k8;
+
+    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      b += k[1];
+      c += k[2];
+      mix(a,b,c);
+      length -= 12;
+      k += 3;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    /* 
+     * "k[2]<<8" actually reads beyond the end of the string, but
+     * then shifts out the part it's not allowed to read.  Because the
+     * string is aligned, the illegal read is in the same word as the
+     * rest of the string.  Every machine with memory protection I've seen
+     * does it on word boundaries, so is OK with this.  But VALGRIND will
+     * still catch it and complain.  The masking trick does make the hash
+     * noticably faster for short strings (like English words).
+     */
+#ifndef VALGRIND
+
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
+    case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
+    case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;
+    case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;
+    case 5 : b+=k[1]&0xff000000; a+=k[0]; break;
+    case 4 : a+=k[0]; break;
+    case 3 : a+=k[0]&0xffffff00; break;
+    case 2 : a+=k[0]&0xffff0000; break;
+    case 1 : a+=k[0]&0xff000000; break;
+    case 0 : return c;              /* zero length strings require no mixing */
+    }
+
+#else  /* make valgrind happy */
+
+    k8 = (const uint8_t *)k;
+    switch(length)                   /* all the case statements fall through */
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=((uint32_t)k8[10])<<8;  /* fall through */
+    case 10: c+=((uint32_t)k8[9])<<16;  /* fall through */
+    case 9 : c+=((uint32_t)k8[8])<<24;  /* fall through */
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=((uint32_t)k8[6])<<8;   /* fall through */
+    case 6 : b+=((uint32_t)k8[5])<<16;  /* fall through */
+    case 5 : b+=((uint32_t)k8[4])<<24;  /* fall through */
+    case 4 : a+=k[0]; break;
+    case 3 : a+=((uint32_t)k8[2])<<8;   /* fall through */
+    case 2 : a+=((uint32_t)k8[1])<<16;  /* fall through */
+    case 1 : a+=((uint32_t)k8[0])<<24; break;
+    case 0 : return c;
+    }
+
+#endif /* !VALGRIND */
+
+  } else {                        /* need to read the key one byte at a time */
+    const uint8_t *k = (const uint8_t *)key;
+
+    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += ((uint32_t)k[0])<<24;
+      a += ((uint32_t)k[1])<<16;
+      a += ((uint32_t)k[2])<<8;
+      a += ((uint32_t)k[3]);
+      b += ((uint32_t)k[4])<<24;
+      b += ((uint32_t)k[5])<<16;
+      b += ((uint32_t)k[6])<<8;
+      b += ((uint32_t)k[7]);
+      c += ((uint32_t)k[8])<<24;
+      c += ((uint32_t)k[9])<<16;
+      c += ((uint32_t)k[10])<<8;
+      c += ((uint32_t)k[11]);
+      mix(a,b,c);
+      length -= 12;
+      k += 12;
+    }
+
+    /*-------------------------------- last block: affect all 32 bits of (c) */
+    switch(length)                   /* all the case statements fall through */
+    {
+    case 12: c+=k[11];
+    case 11: c+=((uint32_t)k[10])<<8;
+    case 10: c+=((uint32_t)k[9])<<16;
+    case 9 : c+=((uint32_t)k[8])<<24;
+    case 8 : b+=k[7];
+    case 7 : b+=((uint32_t)k[6])<<8;
+    case 6 : b+=((uint32_t)k[5])<<16;
+    case 5 : b+=((uint32_t)k[4])<<24;
+    case 4 : a+=k[3];
+    case 3 : a+=((uint32_t)k[2])<<8;
+    case 2 : a+=((uint32_t)k[1])<<16;
+    case 1 : a+=((uint32_t)k[0])<<24;
+             break;
+    case 0 : return c;
+    }
+  }
+
+  final(a,b,c);
+  return c;
+}
+
+
+#ifdef SELF_TEST
+
+/* used for timings */
+void driver1()
+{
+  uint8_t buf[256];
+  uint32_t i;
+  uint32_t h=0;
+  time_t a,z;
+
+  time(&a);
+  for (i=0; i<256; ++i) buf[i] = 'x';
+  for (i=0; i<1; ++i) 
+  {
+    h = hashlittle(&buf[0],1,h);
+  }
+  time(&z);
+  if (z-a > 0) printf("time %d %.8x\n", z-a, h);
+}
+
+/* check that every input bit changes every output bit half the time */
+#define HASHSTATE 1
+#define HASHLEN   1
+#define MAXPAIR 60
+#define MAXLEN  70
+void driver2()
+{
+  uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1];
+  uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z;
+  uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];
+  uint32_t x[HASHSTATE],y[HASHSTATE];
+  uint32_t hlen;
+
+  printf("No more than %d trials should ever be needed \n",MAXPAIR/2);
+  for (hlen=0; hlen < MAXLEN; ++hlen)
+  {
+    z=0;
+    for (i=0; i<hlen; ++i)  /*----------------------- for each input byte, */
+    {
+      for (j=0; j<8; ++j)   /*------------------------ for each input bit, */
+      {
+	for (m=1; m<8; ++m) /*------------ for serveral possible initvals, */
+	{
+	  for (l=0; l<HASHSTATE; ++l)
+	    e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);
+
+      	  /*---- check that every output bit is affected by that input bit */
+	  for (k=0; k<MAXPAIR; k+=2)
+	  { 
+	    uint32_t finished=1;
+	    /* keys have one bit different */
+	    for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}
+	    /* have a and b be two keys differing in only one bit */
+	    a[i] ^= (k<<j);
+	    a[i] ^= (k>>(8-j));
+	     c[0] = hashlittle(a, hlen, m);
+	    b[i] ^= ((k+1)<<j);
+	    b[i] ^= ((k+1)>>(8-j));
+	     d[0] = hashlittle(b, hlen, m);
+	    /* check every bit is 1, 0, set, and not set at least once */
+	    for (l=0; l<HASHSTATE; ++l)
+	    {
+	      e[l] &= (c[l]^d[l]);
+	      f[l] &= ~(c[l]^d[l]);
+	      g[l] &= c[l];
+	      h[l] &= ~c[l];
+	      x[l] &= d[l];
+	      y[l] &= ~d[l];
+	      if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;
+	    }
+	    if (finished) break;
+	  }
+	  if (k>z) z=k;
+	  if (k==MAXPAIR) 
+	  {
+	     printf("Some bit didn't change: ");
+	     printf("%.8x %.8x %.8x %.8x %.8x %.8x  ",
+	            e[0],f[0],g[0],h[0],x[0],y[0]);
+	     printf("i %d j %d m %d len %d\n", i, j, m, hlen);
+	  }
+	  if (z==MAXPAIR) goto done;
+	}
+      }
+    }
+   done:
+    if (z < MAXPAIR)
+    {
+      printf("Mix success  %2d bytes  %2d initvals  ",i,m);
+      printf("required  %d  trials\n", z/2);
+    }
+  }
+  printf("\n");
+}
+
+/* Check for reading beyond the end of the buffer and alignment problems */
+void driver3()
+{
+  uint8_t buf[MAXLEN+20], *b;
+  uint32_t len;
+  uint8_t q[] = "This is the time for all good men to come to the aid of their country...";
+  uint32_t h;
+  uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country...";
+  uint32_t i;
+  uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country...";
+  uint32_t j;
+  uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country...";
+  uint32_t ref,x,y;
+  uint8_t *p;
+
+  printf("Endianness.  These lines should all be the same (for values filled in):\n");
+  printf("%.8x                            %.8x                            %.8x\n",
+         hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13),
+         hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13),
+         hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13));
+  p = q;
+  printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+         hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+         hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+         hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+         hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+         hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+         hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+  p = &qq[1];
+  printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+         hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+         hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+         hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+         hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+         hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+         hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+  p = &qqq[2];
+  printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+         hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+         hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+         hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+         hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+         hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+         hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+  p = &qqqq[3];
+  printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+         hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+         hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+         hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+         hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+         hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+         hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+  printf("\n");
+
+  /* check that hashlittle2 and hashlittle produce the same results */
+  i=47; j=0;
+  hashlittle2(q, sizeof(q), &i, &j);
+  if (hashlittle(q, sizeof(q), 47) != i)
+    printf("hashlittle2 and hashlittle mismatch\n");
+
+  /* check that hashword2 and hashword produce the same results */
+  len = 0xdeadbeef;
+  i=47, j=0;
+  hashword2(&len, 1, &i, &j);
+  if (hashword(&len, 1, 47) != i)
+    printf("hashword2 and hashword mismatch %x %x\n", 
+	   i, hashword(&len, 1, 47));
+
+  /* check hashlittle doesn't read before or after the ends of the string */
+  for (h=0, b=buf+1; h<8; ++h, ++b)
+  {
+    for (i=0; i<MAXLEN; ++i)
+    {
+      len = i;
+      for (j=0; j<i; ++j) *(b+j)=0;
+
+      /* these should all be equal */
+      ref = hashlittle(b, len, (uint32_t)1);
+      *(b+i)=(uint8_t)~0;
+      *(b-1)=(uint8_t)~0;
+      x = hashlittle(b, len, (uint32_t)1);
+      y = hashlittle(b, len, (uint32_t)1);
+      if ((ref != x) || (ref != y)) 
+      {
+	printf("alignment error: %.8x %.8x %.8x %d %d\n",ref,x,y,
+               h, i);
+      }
+    }
+  }
+}
+
+/* check for problems with nulls */
+ void driver4()
+{
+  uint8_t buf[1];
+  uint32_t h,i,state[HASHSTATE];
+
+
+  buf[0] = ~0;
+  for (i=0; i<HASHSTATE; ++i) state[i] = 1;
+  printf("These should all be different\n");
+  for (i=0, h=0; i<8; ++i)
+  {
+    h = hashlittle(buf, 0, h);
+    printf("%2ld  0-byte strings, hash is  %.8x\n", i, h);
+  }
+}
+
+
+int main()
+{
+  driver1();   /* test that the key is hashed: used for timings */
+  driver2();   /* test that whole key is hashed thoroughly */
+  driver3();   /* test that nothing but the key is hashed */
+  driver4();   /* test hashing multiple buffers (all buffers are null) */
+  return 1;
+}
+
+#endif  /* SELF_TEST */
+
diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenkhash.sln b/binding-c/runtime/c/src/extern/jenkhash/jenkhash.sln
new file mode 100644
index 0000000..006f569
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenkhash.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jenkhash", "jenkhash.vcproj", "{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Debug|Win32.ActiveCfg = Debug|Win32
+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Debug|Win32.Build.0 = Debug|Win32
+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Release|Win32.ActiveCfg = Release|Win32
+		{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenkhash.vcproj b/binding-c/runtime/c/src/extern/jenkhash/jenkhash.vcproj
new file mode 100644
index 0000000..f3b4205
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenkhash.vcproj
@@ -0,0 +1,469 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8,00"

+	Name="jenkhash"

+	ProjectGUID="{CC75FED8-5D1B-4323-B73A-36C41FD1CC66}"

+	RootNamespace="jenkhash"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+		<Platform

+			Name="Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(ProjectDir)target\win32\$(ConfigurationName)"

+			IntermediateDirectory="$(ProjectDir)target\win32\$(ConfigurationName)"

+			ConfigurationType="4"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB"

+				MinimalRebuild="false"

+				ExceptionHandling="0"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="3"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+				CompileAs="1"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+				AdditionalOptions="/NODEFAULTLIB:LIBCMT"

+				OutputFile="$(OutDir)\$(ProjectName).lib"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+				CommandLine=""

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			CharacterSet="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"

+				RuntimeLibrary="2"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug Static|Win32"

+			OutputDirectory="$(ProjectDir)target\win32\$(ConfigurationName)"

+			IntermediateDirectory="$(ProjectDir)target\win32\$(ConfigurationName)"

+			ConfigurationType="4"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release Static|Win32"

+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			CharacterSet="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"

+				RuntimeLibrary="2"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

+			OutputDirectory="$(SolutionDir)Windows Mobile 5.0 Pocket PC SDK (ARMV4I)\$(ConfigurationName)"

+			IntermediateDirectory="Windows Mobile 5.0 Pocket PC SDK (ARMV4I)\$(ConfigurationName)"

+			ConfigurationType="4"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				TargetEnvironment="1"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				Optimization="0"

+				PreprocessorDefinitions="WIN32;_DEBUG;DEBUG;_LIB;APR_DECLARE_STATIC;API_DECLARE_STATIC;_CRT_SECURE_NO_WARNINGS;_WIN32_WCE=$(CEVER);UNDER_CE;WINCE;$(ARCHFAM);$(_ARCHFAM_)"

+				MinimalRebuild="false"

+				ExceptionHandling="0"

+				RuntimeLibrary="3"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				DebugInformationFormat="1"

+				CompileAs="1"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+				AdditionalOptions="/NODEFAULTLIB:LIBCMT"

+				OutputFile="..\lib\$(ProjectName).lib"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+				CommandLine=".\postbuild.bat"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Windows Mobile 5.0 Pocket PC SDK (ARMV4I)"

+			OutputDirectory="$(SolutionDir)Windows Mobile 5.0 Pocket PC SDK (ARMV4I)\$(ConfigurationName)"

+			IntermediateDirectory="Windows Mobile 5.0 Pocket PC SDK (ARMV4I)\$(ConfigurationName)"

+			ConfigurationType="4"

+			CharacterSet="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+				TargetEnvironment="1"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				ExecutionBucket="7"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"

+				RuntimeLibrary="2"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCCodeSignTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+			<DeploymentTool

+				ForceDirty="-1"

+				RemoteDirectory=""

+				RegisterOutput="0"

+				AdditionalFiles=""

+			/>

+			<DebuggerTool

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\jenkhtab.c"

+				>

+			</File>

+			<File

+				RelativePath=".\jenklook.c"

+				>

+			</File>

+			<File

+				RelativePath=".\jenkrecy.c"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath=".\jenkhtab.h"

+				>

+			</File>

+			<File

+				RelativePath=".\jenklook.h"

+				>

+			</File>

+			<File

+				RelativePath=".\jenkrecy.h"

+				>

+			</File>

+			<File

+				RelativePath=".\jenkstd.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Resource Files"

+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"

+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"

+			>

+		</Filter>

+		<File

+			RelativePath=".\jenkmake.txt"

+			>

+		</File>

+		<File

+			RelativePath=".\jenkread.txt"

+			>

+		</File>

+		<File

+			RelativePath=".\jenktest.txt"

+			>

+		</File>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenkhtab.c b/binding-c/runtime/c/src/extern/jenkhash/jenkhtab.c
new file mode 100644
index 0000000..753d5e4
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenkhtab.c
@@ -0,0 +1,463 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+--------------------------------------------------------------------
+By Bob Jenkins.  hashtab.c.  Public Domain.
+
+This implements a hash table.
+* Keys are unique.  Adding an item fails if the key is already there.
+* Keys and items are pointed at, not copied.  If you change the value
+  of the key after it is inserted then hfind will not be able to find it.
+* The hash table maintains a position that can be set and queried.
+* The table length doubles dynamically and never shrinks.  The insert
+  that causes table doubling may take a long time.
+* The table length splits when the table length equals the number of items
+  Comparisons usually take 7 instructions.
+  Computing a hash value takes 35+6n instructions for an n-byte key.
+
+  hcreate  - create a hash table
+  hdestroy - destroy a hash table
+   hcount  - The number of items in the hash table
+   hkey    - key at the current position
+   hkeyl   - key length at the current position
+   hstuff  - stuff at the current position
+  hfind    - find an item in the table
+   hadd    - insert an item into the table
+   hdel    - delete an item from the table
+  hstat    - print statistics about the table
+   hfirst  - position at the first item in the table
+   hnext   - move the position to the next item in the table
+--------------------------------------------------------------------
+*/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "jenkstd.h"
+#include "jenklook.h"
+#include "jenkhtab.h"
+#include "jenkrecy.h"
+
+#define HSANITY 1
+
+/* sanity check -- make sure ipos, apos, and count make sense */
+static void hsanity(htab *t)
+{
+  ub4 i, end, counter;
+  hitem *h;
+
+  /* test that apos makes sense */
+  end = (ub4) 1 << (t->logsize);
+  if (end < t->apos)
+      printf("error:  end %ld  apos %ld\n", end, t->apos);
+
+  /* test that ipos is in bucket apos */
+  if (t->ipos)
+  {
+    for (h=t->table[t->apos];  h && h != t->ipos;  h = h->next)
+      ;
+    if (h != t->ipos)
+        printf("error:ipos not in apos, apos is %ld\n", t->apos);
+  }
+
+  /* test that t->count is the number of elements in the table */
+  counter=0;
+  for (counter=0, i=0;  i<end;  ++i)
+       for (h=t->table[i];  h;  h = h->next) ++counter;
+
+  if (counter != t->count)
+      printf("error: counter %ld  t->count %ld\n", counter, t->count);
+}
+
+
+/*
+ * hgrow - Double the size of a hash table.
+ * Allocate a new, 2x bigger array,
+ * move everything from the old array to the new array, then free the old array.
+ */
+static void hgrow(htab *t)
+{
+  register ub4 newsize = (ub4)1<<(++t->logsize);
+  register ub4 newmask = newsize-1;
+  register ub4 i;
+  register hitem **oldtab = t->table;
+  register hitem **newtab = (hitem **) malloc(newsize*sizeof(hitem *));
+
+  /* make sure newtab is cleared */
+  for (i=0; i<newsize; ++i) newtab[i] = (hitem *)0;
+  t->table = newtab;
+  t->mask = newmask;
+
+  /* Walk through old table putting entries in new table */
+  for (i=newsize>>1; i--;)
+  {
+    register hitem *pthis, *pthat, **newplace;
+    for (pthis = oldtab[i]; pthis;)
+    {
+      pthat = pthis;
+      pthis = pthis->next;
+      newplace = &newtab[(pthat->hval & newmask)];
+      pthat->next = *newplace;
+      *newplace = pthat;
+    }
+  }
+
+  /* position the hash table on some existing item */
+  hfirst(t);
+
+  /* free the old array */
+  free((char*)oldtab);
+}
+
+
+/* hcreate - create a hash table initially of size power(2,logsize) */
+htab *hcreate(intx logsize)/* = log base 2 of the size of the hash table */   
+{
+  ub4  i, len;
+  htab *t = (htab*) malloc(sizeof(htab));
+
+  len = ((ub4) 1 << logsize);
+  t->table = (hitem **) malloc(sizeof(hitem *)*(ub4)len);
+  for (i=0; i < len; ++i) t->table[i] = (hitem *)0;
+  t->logsize = logsize;
+  t->mask = len-1;
+  t->count = 0;
+  t->apos = (ub4)0;
+  t->ipos = (hitem *)0;
+  t->space = remkroot(sizeof(hitem));
+  t->bcount = 0;
+  return t;
+}
+
+
+/* hdestroy - destroy the hash table and free all its memory */
+void hdestroy(htab* t)
+{
+  /* hitem *h; // unreferenced local var wng */
+  refree(t->space);
+  free((char *)t->table);
+  free((char *)t);
+}
+
+
+/* hcount() is a macro, see hashtab.h */
+/* hkey()   is a macro, see hashtab.h */
+/* hkeyl()  is a macro, see hashtab.h */
+/* hstuff() is a macro, see hashtab.h */
+
+
+/**
+ * hfind - find an item with a given key in a hash table.
+ * if found, point at the item and return TRUE, otherwise FALSE. 
+ */
+intx hfind(htab* t, ub1* key, ub4 keylen)
+{
+  hitem *h;
+  ub4    x = lookup(key,keylen,0); /* hash */
+  ub4    y;
+
+  for (h = t->table[y=(x&t->mask)]; h; h = h->next)
+  {
+    if ((x == h->hval) && (keylen == h->keyl) && !memcmp(key, h->key, keylen))
+    {
+      t->apos = y;
+      t->ipos = h;
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+
+/**
+ * hfindx - find an item with a given hashed key in a hash table.
+ * this function was added by JLD, Cisco CUAE.
+ * keylen is byte length of original key, not of the hash.
+ * if found, point at the item and return TRUE, otherwise FALSE. 
+ */
+intx hfindx(htab* t, const ub4 hashval)
+{
+  intx result = FALSE;
+  ub4    i = hashval & t->mask;
+  hitem *h = t->table[i];
+
+  for (; h; h = h->next)   
+    if (hashval == h->hval)
+    { t->apos = i;
+      t->ipos = h;
+      result  = TRUE;
+      break;
+    }
+   
+  return result;
+}
+
+
+
+/**
+ * hadd - add an item to a hash table.
+ * return FALSE if key is already in the table, otherwise TRUE.
+ */
+intx hadd(htab *t, ub1 *key, ub4 keylen, void* stuff)
+{
+  register hitem *h, **hp;
+  register ub4 y;
+  register ub4 x = lookup(key,keylen,0);
+
+  /* make sure the key is not already there */
+  for (h = t->table[(y = (x & t->mask))]; h; h = h->next)
+  {
+    if ((x == h->hval) && (keylen == h->keyl) && !memcmp(key, h->key, keylen))
+    {
+      t->apos = y;
+      t->ipos = h;
+      return FALSE;
+    }
+  }
+
+  /* find space for a new item */
+  /* JLD pointer assumed same size as int -- ouch! */
+  h = (hitem*) renew (t->space);   
+
+  /* make the hash table bigger if it is getting full */
+  if (++t->count > (ub4) 1 << (t->logsize))
+  {
+    hgrow(t);
+    y = (x&t->mask);
+  }
+
+  /* add the new key to the table */
+  h->key   = key;
+  h->keyl  = keylen;
+  h->stuff = stuff;
+  h->hval  = x;      /* hash */
+  hp = &t->table[y];
+  h->next = *hp;
+  *hp = h;
+  t->ipos = h;
+  t->apos = y;
+
+  #ifdef HSANITY
+  hsanity(t);
+  #endif  /* HSANITY */
+
+  return TRUE;
+}
+
+
+/**
+ * haddx - add an item to a hash table.
+ * this is a version of hadd which expects a pre-calculated hashed key 
+ * in the initial 4 bytes of the key object. 
+ * return FALSE if key is already in the table, otherwise TRUE.
+ * this function was added by JLD, Cisco CUAE
+ */
+intx haddx(htab *t, void* keyobj, void* valobj)
+{
+  register hitem *h, **hp;
+  register ub4 y;              
+  register ub4 hashval = *((ub4*) keyobj);  
+  const ub4 KEYLEN = sizeof(void*);
+  if (0 == hashval) return FALSE;
+
+  for (h = t->table[(y = (hashval & t->mask))]; h; h = h->next)
+  {
+    if ((hashval == h->hval) && (KEYLEN == h->keyl) && !memcmp(keyobj, h->key, KEYLEN))
+    {
+      t->apos = y;
+      t->ipos = h;
+      return FALSE;
+    }
+  }
+
+  /* find space for a new item */
+  h = (hitem*) renew (t->space);   
+
+  /* make the hashval table bigger if it is getting full */
+  if (++t->count > (ub4) 1 << (t->logsize))
+  {
+    hgrow(t);
+    y = (hashval&t->mask);
+  }
+
+  /* add the new key and value to the table */
+  h->key   = keyobj;
+  h->keyl  = KEYLEN;
+  h->stuff = valobj;
+  h->hval  = hashval;      
+  hp = &t->table[y];
+  h->next = *hp;
+  *hp = h;
+  t->ipos = h;
+  t->apos = y;
+
+  #ifdef HSANITY
+  hsanity(t);
+  #endif  /* HSANITY */
+
+  return TRUE;
+}
+
+
+/* hdel - delete the item at the current position */
+intx hdel(htab* t)
+{
+  hitem  *h;    /* item being deleted */
+  hitem **ip;   /* a counter */
+
+  /* check for item not existing */
+  if (!(h = t->ipos)) return FALSE;
+
+  /* remove item from its list */
+  for (ip = &t->table[t->apos]; *ip != h; ip = &(*ip)->next)
+    ;
+  *ip = (*ip)->next;
+  --(t->count);
+
+  /* adjust position to something that exists */
+  if (!(t->ipos = h->next)) hnbucket(t);
+
+  /* recycle the deleted hitem node */
+  redel(t->space, h);
+
+  #ifdef HSANITY
+  hsanity(t);
+  #endif  /* HSANITY */
+
+  return TRUE;
+}
+
+
+/* hfirst - position on the first element in the table */
+intx hfirst(htab *t)
+{
+  t->apos = (ub4) t->mask;
+  (void)hnbucket(t);
+  return (t->ipos != (hitem *)0);
+}
+
+
+/* hnext() is a macro, see hashtab.h */
+
+
+
+/*
+ * hnbucket - Move position to the first item in the next bucket.
+ * Return TRUE if we did not wrap around to the beginning of the table
+ */
+intx hnbucket(htab *t)
+{
+  ub4  oldapos = t->apos;
+  ub4  end = (ub4) 1 << (t->logsize);
+  ub4  i;
+
+  /* see if the element can be found without wrapping around */
+  for (i=oldapos+1; i<end; ++i)
+  {
+    if (t->table[i&t->mask])
+    {
+      t->apos = i;
+      t->ipos = t->table[i];
+      return TRUE;
+    }
+  }
+
+  /* must have to wrap around to find the last element */
+  for (i=0; i <= oldapos; ++i)
+  {
+    if (t->table[i])
+    {
+      t->apos = i;
+      t->ipos = t->table[i];
+      return FALSE;
+    }
+  }
+
+  return FALSE;
+}
+
+
+/**
+     hstat: report table statistics
+*/
+void hstat(htab *t)
+{
+  ub4     i,j;
+  double  total = 0.0;
+  hitem  *h;
+  hitem  *walk, *walk2, *stat = (hitem *)0;
+
+  /* in stat, keyl will store length of list, hval the number of buckets */
+  for (i=0; i <= t->mask; ++i)
+  {
+    for (h=t->table[i], j=0; h; ++j, h=h->next)
+      ;
+    for (walk=stat; walk && (walk->keyl != j); walk=walk->next)
+      ;
+    if (walk)
+    {
+      ++(walk->hval);
+    }
+    else
+    {
+      walk = (hitem *)renew(t->space);
+      walk->keyl = j;
+      walk->hval = 1;
+      if (!stat || stat->keyl > j) {walk->next=stat; stat=walk;}
+      else
+      {
+        for (walk2=stat;
+             walk2->next && (walk2->next->keyl<j);
+             walk2=walk2->next)
+          ;
+        walk->next = walk2->next;
+        walk2->next = walk;
+      }
+    }
+  }
+
+  /* figure out average list length for existing elements */
+  for (walk=stat; walk; walk=walk->next)
+  {
+    total += (double)walk->hval * (double)walk->keyl * (double)walk->keyl;
+  }
+
+  if  (t->count) 
+       total /= (double)t->count;
+  else total = 0.0;
+
+  /* print statistics */
+  printf("** hashtable stats follow\n");
+  for (walk=stat; walk; walk=walk->next)
+       printf("** items %ld: %ld buckets\n", walk->keyl, walk->hval);   
+  printf("** buckets: %ld items: %ld existing: %g\n\n",
+         ((ub4)1<<t->logsize), t->count, total);
+
+  /* clean up */
+  while (stat)
+  {
+    walk = stat->next;
+    redel(t->space, stat);
+    stat = walk;
+  }
+}
+
+
diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenkhtab.h b/binding-c/runtime/c/src/extern/jenkhash/jenkhtab.h
new file mode 100644
index 0000000..1db1075
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenkhtab.h
@@ -0,0 +1,233 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+--------------------------------------------------------------------
+By Bob Jenkins, 1996.  hash.h.  Public Domain.
+
+This implements a hash table.
+* Keys are unique.  Adding an item fails if the key is already there.
+* Keys and items are pointed at, not copied.  If you change the value
+  of the key after it is inserted then hfind will not be able to find it.
+* The hash table maintains a position that can be set and queried.
+* The table length doubles dynamically and never shrinks.  The insert
+  that causes table doubling may take a long time.
+* The table length splits when the table length equals the number of items
+  Comparisons usually take 7 instructions.
+  Computing a hash value takes 35+6n instructions for an n-byte key.
+
+  hcreate  - create a hash table
+  hdestroy - destroy a hash table
+   hcount  - The number of items in the hash table
+   hkey    - key at the current position
+   hkeyl   - key length at the current position
+   hstuff  - stuff at the current position
+  hfind    - find an item in the table
+   hadd    - insert an item into the table
+   hdel    - delete an item from the table
+  hstat    - print statistics about the table
+   hfirst  - position at the first item in the table
+   hnext   - move the position to the next item in the table
+--------------------------------------------------------------------
+*/
+
+#ifndef HASHTAB
+#define HASHTAB
+#include "jenkstd.h"
+
+#define HASHTAB_DEBUG /* #define HASHTAB_DEBUG to display debug info */
+
+/* PRIVATE TYPES AND DEFINITIONS */
+
+struct hitem
+{
+  ub1          *key;      /* key that is hashed */
+  ub4           keyl;     /* length of key */
+  void         *stuff;    /* stuff stored in this hitem */
+  ub4           hval;     /* hash value */
+  struct hitem *next;     /* next hitem in list */
+};
+typedef struct hitem  hitem;
+
+
+struct htab
+{
+  struct hitem **table;   /* hash table, array of size 2^logsize */
+  intx           logsize; /* log of size of table */
+  size_t         mask;    /* (hashval & mask) is position in table */
+  ub4            count;   /* how many items in this hash table so far? */
+  ub4            apos;    /* position in the array */
+  struct hitem  *ipos;    /* current item in the array */
+  struct reroot *space;   /* space for the hitems */
+  ub4            bcount;  /* # hitems useable in current block */
+};
+typedef struct htab  htab;
+
+
+/* PUBLIC FUNCTIONS */
+
+/* hcreate - create a hash table
+   ARGUMENTS:
+     logsize - 1<<logsize will be the initial table length
+   RETURNS:
+     the new table
+ */
+htab *hcreate(intx logsize);
+
+
+/* hdestroy - destroy a hash table
+   ARGUMENTS:
+     t - the hash table to be destroyed.  Note that the items and keys
+         will not be freed, the user created them and must destroy
+         them himself.
+   RETURNS:
+     nothing
+ */
+void  hdestroy(htab *t);
+
+
+/* hcount, hkey, hkeyl, hstuff
+     ARGUMENTS:
+     t - the hash table
+   RETURNS:
+     hcount - (ub4)    The number of items in the hash table
+     hkey   - (ub1 *)  key for the current item
+     hkeyl  - (ub4)    key length for the current item
+     hstuff - (void *) stuff for the current item
+   NOTE:
+     The current position always has an item as long as there
+       are items in the table, so hexist can be used to test if the
+       table is empty.
+     hkey, hkeyl, and hstuff will crash if hcount returns 0
+ */
+#define hcount(t) ((t)->count)
+#define hkey(t)   ((t)->ipos->key)
+#define hkeyl(t)  ((t)->ipos->keyl)
+#define hstuff(t) ((t)->ipos->stuff)
+
+
+
+/* hfind - move the current position to a given key
+   ARGUMENTS:
+     t    - the hash table
+     key  - the key to look for
+     keyl - length of the key
+   RETURNS:
+     TRUE if the item exists, FALSE if it does not.
+     If the item exists, moves the current position to that item.
+ */
+intx hfind(htab *t, ub1 *key, ub4 keyl);
+
+intx hfindx(htab* t, const ub4 hashed);
+
+
+/* hadd - add a new item to the hash table
+          change the position to point at the item with the key
+   ARGUMENTS:
+     t     - the hash table
+     key   - the key to look for
+     keyl  - length of the key
+     stuff - other stuff to be stored in this item
+   RETURNS:
+     FALSE if the operation fails (because that key is already there).
+ */
+intx hadd (htab *t, ub1 *key, ub4 keyl, void *stuff);
+
+intx haddx(htab *t, void *keyobj, void *stuff); 
+
+
+/* hdel - delete the item at the current position
+          change the position to the following item
+  ARGUMENTS:
+    t    - the hash table
+  RETURNS:
+    FALSE if there is no current item (meaning the table is empty)
+  NOTE:
+    This frees the item, but not the key or stuff stored in the item.
+    If you want these then deal with them first.  For example:
+      if (hfind(tab, key, keyl))
+      {
+        free(hkey(tab));
+        free(hstuff(tab));
+        hdel(tab);
+      }
+ */
+intx hdel(htab *t);
+
+
+/* hfirst - move position to the first item in the table
+  ARGUMENTS:
+    t    - the hash table
+  RETURNS:
+    FALSE if there is no current item (meaning the table is empty)
+  NOTE:
+ */
+intx hfirst(htab *t);
+
+
+/* hnext - move position to the next item in the table
+  ARGUMENTS:
+    t    - the hash table
+  RETURNS:
+    FALSE if the position wraps around to the beginning of the table
+  NOTE:
+    To see every item in the table, do
+      if (hfirst(t)) do
+      {
+        key   = hkey(t);
+        stuff = hstuff(t);
+      }
+      while (hnext(t));
+ */
+
+/* intx hnext(htab *t); */
+
+#define hnext(t) \
+  ((!(t)->ipos) ? FALSE :  \
+    ((t)->ipos=(t)->ipos->next) ? TRUE : hnbucket(t))
+
+/* hnbucket - PRIVATE - move to first item in the next nonempty bucket
+  ARGUMENTS:
+    t    - the hash table
+  RETURNS:
+    FALSE if the position wraps around to the beginning of the table
+  NOTE:
+    This is private to hashtab; do not use it externally.
+ */
+intx hnbucket(htab *t);
+
+
+/* hstat - print statistics about the hash table
+  ARGUMENTS:
+    t    - the hash table
+  NOTE:
+    items <0>:  <#buckets with zero items> buckets
+    items <1>:  <#buckets with 1 item> buckets
+    ...
+    buckets: #buckets  items: #items  existing: x
+    ( x is the average length of the list when you look for an
+      item that exists.  When the item does not exists, the average
+      length is #items/#buckets. )
+
+    If you put n items into n buckets, expect 1/(n!)e buckets to
+    have n items.  That is, .3678 0, .3678 1, .1839 2, ...
+    Also expect "existing" to be about 2.
+ */
+void hstat(htab *t);
+
+#endif   /* HASHTAB */
diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenklook.c b/binding-c/runtime/c/src/extern/jenkhash/jenklook.c
new file mode 100644
index 0000000..878f266
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenklook.c
@@ -0,0 +1,262 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+
+/*
+--------------------------------------------------------------------
+lookupa.c, by Bob Jenkins, December 1996.  Same as lookup2.c
+Use this code however you wish.  Public Domain.  No warranty.
+Source is http://burtleburtle.net/bob/c/lookupa.c
+--------------------------------------------------------------------
+*/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jenkstd.h"
+#include "jenklook.h"
+
+
+/*
+--------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+For every delta with one or two bit set, and the deltas of all three
+  high bits or all three low bits, whether the original value of a,b,c
+  is almost all zero or is uniformly distributed,
+* If mix() is run forward or backward, at least 32 bits in a,b,c
+  have at least 1/4 probability of changing.
+* If mix() is run forward, every bit of c will change between 1/3 and
+  2/3 of the time.  (Well, 22/100 and 78/100 for some 2-bit deltas.)
+mix() was built out of 36 single-cycle latency instructions in a 
+  structure that could supported 2x parallelism, like so:
+      a -= b; 
+      a -= c; x = (c>>13);
+      b -= c; a ^= x;
+      b -= a; x = (a<<8);
+      c -= a; b ^= x;
+      c -= b; x = (b>>13);
+      ...
+  Unfortunately, superscalar Pentiums and Sparcs can't take advantage 
+  of that parallelism.  They've also turned some of those single-cycle
+  latency instructions into multi-cycle latency instructions.  Still,
+  this is the fastest good hash I could find.  There were about 2^^68
+  to choose from.  I only looked at a billion or so.
+--------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+  a -= b; a -= c; a ^= (c>>13); \
+  b -= c; b -= a; b ^= (a<<8); \
+  c -= a; c -= b; c ^= (b>>13); \
+  a -= b; a -= c; a ^= (c>>12);  \
+  b -= c; b -= a; b ^= (a<<16); \
+  c -= a; c -= b; c ^= (b>>5); \
+  a -= b; a -= c; a ^= (c>>3);  \
+  b -= c; b -= a; b ^= (a<<10); \
+  c -= a; c -= b; c ^= (b>>15); \
+}
+
+/*
+--------------------------------------------------------------------
+lookup() -- hash a variable-length key into a 32-bit value
+  k     : the key (the unaligned variable-length array of bytes)
+  len   : the length of the key, counting by bytes
+  level : the previous hash, or an arbitrary 4-byte value
+Returns a 32-bit value.  Every bit of the key affects every bit of
+the return value.  Every 1-bit and 2-bit delta achieves avalanche.
+About 6len+35 instructions.
+
+The best hash table sizes are powers of 2.  There is no need to do
+mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+use a bitmask.  For example, if you need only 10 bits, do
+  h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (ub1 **)k, do it like this:
+  for (i=0, h=0; i<n; ++i) h = lookup( k[i], len[i], h);
+
+By Bob Jenkins, 1996.  bob_jenkins@burtleburtle.net.  You may use this
+code any way you wish, private, educational, or commercial.
+
+See http://burtleburtle.net/bob/hash/evahash.html
+Use for hash table lookup, or anything where one collision in 2^32 is
+acceptable.  Do NOT use for cryptographic purposes.
+--------------------------------------------------------------------
+*/
+
+ub4 lookup(register ub1 *k, register ub4 length, register ub4 level)
+{
+   register ub4 a,b,c,len;
+
+   /* Set up the internal state */
+   len = length;
+   a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
+   c = level;           /* the previous hash value */
+
+   /*---------------------------------------- handle most of the key */
+   while (len >= 12)
+   {
+      a += (k[0] +((ub4)k[1]<<8) +((ub4)k[2]<<16) +((ub4)k[3]<<24));
+      b += (k[4] +((ub4)k[5]<<8) +((ub4)k[6]<<16) +((ub4)k[7]<<24));
+      c += (k[8] +((ub4)k[9]<<8) +((ub4)k[10]<<16)+((ub4)k[11]<<24));
+      mix(a,b,c);
+      k += 12; len -= 12;
+   }
+
+   /*------------------------------------- handle the last 11 bytes */
+   c += length;
+   switch(len)              /* all the case statements fall through */
+   {
+   case 11: c+=((ub4)k[10]<<24);
+   case 10: c+=((ub4)k[9]<<16);
+   case 9 : c+=((ub4)k[8]<<8);
+      /* the first byte of c is reserved for the length */
+   case 8 : b+=((ub4)k[7]<<24);
+   case 7 : b+=((ub4)k[6]<<16);
+   case 6 : b+=((ub4)k[5]<<8);
+   case 5 : b+=k[4];
+   case 4 : a+=((ub4)k[3]<<24);
+   case 3 : a+=((ub4)k[2]<<16);
+   case 2 : a+=((ub4)k[1]<<8);
+   case 1 : a+=k[0];
+     /* case 0: nothing left to add */
+   }
+   mix(a,b,c);
+   /*-------------------------------------------- report the result */
+   return c;
+}
+
+
+/*
+--------------------------------------------------------------------
+mixc -- mixc 8 4-bit values as quickly and thoroughly as possible.
+Repeating mix() three times achieves avalanche.
+Repeating mix() four times eliminates all funnels and all
+  characteristics stronger than 2^{-11}.
+--------------------------------------------------------------------
+*/
+#define mixc(a,b,c,d,e,f,g,h) \
+{ \
+   a^=b<<11; d+=a; b+=c; \
+   b^=c>>2;  e+=b; c+=d; \
+   c^=d<<8;  f+=c; d+=e; \
+   d^=e>>16; g+=d; e+=f; \
+   e^=f<<10; h+=e; f+=g; \
+   f^=g>>4;  a+=f; g+=h; \
+   g^=h<<8;  b+=g; h+=a; \
+   h^=a>>9;  c+=h; a+=b; \
+}
+
+/*
+--------------------------------------------------------------------
+checksum() -- hash a variable-length key into a 256-bit value
+  k     : the key (the unaligned variable-length array of bytes)
+  len   : the length of the key, counting by bytes
+  state : an array of CHECKSTATE 4-byte values (256 bits)
+The state is the checksum.  Every bit of the key affects every bit of
+the state.  There are no funnels.  About 112+6.875len instructions.
+
+If you are hashing n strings (ub1 **)k, do it like this:
+  for (i=0; i<8; ++i) state[i] = 0x9e3779b9;
+  for (i=0, h=0; i<n; ++i) checksum( k[i], len[i], state);
+
+(c) Bob Jenkins, 1996.  bob_jenkins@burtleburtle.net.  You may use this
+code any way you wish, private, educational, or commercial, as long
+as this whole comment accompanies it.
+
+See http://burtleburtle.net/bob/hash/evahash.html
+Use to detect changes between revisions of documents, assuming nobody
+is trying to cause collisions.  Do NOT use for cryptography.
+--------------------------------------------------------------------
+*/
+void  checksum( k, len, state)
+register ub1 *k;
+register ub4  len;
+register ub4 *state;
+{
+   register ub4 a,b,c,d,e,f,g,h,length;
+
+   /* Use the length and level; add in the golden ratio. */
+   length = len;
+   a=state[0]; b=state[1]; c=state[2]; d=state[3];
+   e=state[4]; f=state[5]; g=state[6]; h=state[7];
+
+   /*---------------------------------------- handle most of the key */
+   while (len >= 32)
+   {
+      a += (k[0] +(k[1]<<8) +(k[2]<<16) +(k[3]<<24));
+      b += (k[4] +(k[5]<<8) +(k[6]<<16) +(k[7]<<24));
+      c += (k[8] +(k[9]<<8) +(k[10]<<16)+(k[11]<<24));
+      d += (k[12]+(k[13]<<8)+(k[14]<<16)+(k[15]<<24));
+      e += (k[16]+(k[17]<<8)+(k[18]<<16)+(k[19]<<24));
+      f += (k[20]+(k[21]<<8)+(k[22]<<16)+(k[23]<<24));
+      g += (k[24]+(k[25]<<8)+(k[26]<<16)+(k[27]<<24));
+      h += (k[28]+(k[29]<<8)+(k[30]<<16)+(k[31]<<24));
+      mixc(a,b,c,d,e,f,g,h);
+      mixc(a,b,c,d,e,f,g,h);
+      mixc(a,b,c,d,e,f,g,h);
+      mixc(a,b,c,d,e,f,g,h);
+      k += 32; len -= 32;
+   }
+
+   /*------------------------------------- handle the last 31 bytes */
+   h += length;
+   switch(len)
+   {
+   case 31: h+=(k[30]<<24);
+   case 30: h+=(k[29]<<16);
+   case 29: h+=(k[28]<<8);
+   case 28: g+=(k[27]<<24);
+   case 27: g+=(k[26]<<16);
+   case 26: g+=(k[25]<<8);
+   case 25: g+=k[24];
+   case 24: f+=(k[23]<<24);
+   case 23: f+=(k[22]<<16);
+   case 22: f+=(k[21]<<8);
+   case 21: f+=k[20];
+   case 20: e+=(k[19]<<24);
+   case 19: e+=(k[18]<<16);
+   case 18: e+=(k[17]<<8);
+   case 17: e+=k[16];
+   case 16: d+=(k[15]<<24);
+   case 15: d+=(k[14]<<16);
+   case 14: d+=(k[13]<<8);
+   case 13: d+=k[12];
+   case 12: c+=(k[11]<<24);
+   case 11: c+=(k[10]<<16);
+   case 10: c+=(k[9]<<8);
+   case 9 : c+=k[8];
+   case 8 : b+=(k[7]<<24);
+   case 7 : b+=(k[6]<<16);
+   case 6 : b+=(k[5]<<8);
+   case 5 : b+=k[4];
+   case 4 : a+=(k[3]<<24);
+   case 3 : a+=(k[2]<<16);
+   case 2 : a+=(k[1]<<8);
+   case 1 : a+=k[0];
+   }
+   mixc(a,b,c,d,e,f,g,h);
+   mixc(a,b,c,d,e,f,g,h);
+   mixc(a,b,c,d,e,f,g,h);
+   mixc(a,b,c,d,e,f,g,h);
+
+   /*-------------------------------------------- report the result */
+   state[0]=a; state[1]=b; state[2]=c; state[3]=d;
+   state[4]=e; state[5]=f; state[6]=g; state[7]=h;
+}
diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenklook.h b/binding-c/runtime/c/src/extern/jenkhash/jenklook.h
new file mode 100644
index 0000000..b363815
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenklook.h
@@ -0,0 +1,42 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+------------------------------------------------------------------------------
+By Bob Jenkins, September 1996.
+lookupa.h, a hash function for table lookup, same function as lookup.c.
+Use this code in any way you wish.  Public Domain.  It has no warranty.
+Source is http://burtleburtle.net/bob/c/lookupa.h
+------------------------------------------------------------------------------
+*/
+
+#ifndef LOOKUPA
+#define LOOKUPA
+
+#ifndef STANDARD
+#include "jenkstd.h"
+#endif
+
+#define CHECKSTATE 8
+#define hashsize(n) ((ub4)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+
+ub4  lookup(ub1 *k, ub4 length, ub4 level);
+void checksum(ub1 *k, ub4 length, ub4 *state);
+
+#endif /* LOOKUPA */
diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenkmake.txt b/binding-c/runtime/c/src/extern/jenkhash/jenkmake.txt
new file mode 100644
index 0000000..c23f5e4
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenkmake.txt
@@ -0,0 +1,19 @@
+CFLAGS = -O
+
+.cc.o:
+	gcc $(CFLAGS) -c $<
+
+O = recycle.o lookupa.o hashtab.o unique.o
+
+unique : $(O)
+	gcc -o unique $(O) -lm
+
+# DEPENDENCIES
+
+recycle.o : recycle.c standard.h recycle.h
+
+lookupa.o : lookupa.c standard.h lookupa.h
+
+hashtab.o : hashtab.c standard.h recycle.h lookupa.h hashtab.h
+
+unique.o  : unique.c standard.h hashtab.h
diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenkrecy.c b/binding-c/runtime/c/src/extern/jenkhash/jenkrecy.c
new file mode 100644
index 0000000..bb4dcb8
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenkrecy.c
@@ -0,0 +1,105 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+--------------------------------------------------------------------
+By Bob Jenkins, September 1996.  recycle.c
+You may use this code in any way you wish, and it is free.  No warranty.
+
+This manages memory for commonly-allocated structures.
+It allocates RESTART to REMAX items at a time.
+Timings have shown that, if malloc is used for every new structure,
+malloc will consume about 90% of the time in a program.  
+This module cuts down the number of mallocs by an order of magnitude.
+This also decreases memory fragmentation, and freeing structures
+only requires freeing the root.
+--------------------------------------------------------------------
+*/
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "jenkstd.h"
+#include "jenkrecy.h"
+
+
+reroot *remkroot(size_t size)
+{
+   reroot *r = (reroot*) remalloc(sizeof(reroot), "recycle.c, root");
+   r->list  = (recycle*)0;
+   r->trash = (recycle*)0;
+   r->size  = align(size);
+   r->logsize = RESTART;
+   r->numleft = 0;
+   return r;
+}
+
+
+
+void refree(struct reroot *r)
+{
+   recycle *temp;
+   if (temp = r->list) while (r->list)
+   {
+      temp = r->list->next;
+      free((char *)r->list);
+      r->list = temp;
+   }
+   free((char *)r);
+   return;
+}
+
+
+
+/* to be called from the macro renew only */
+char *renewx(struct reroot *r)
+{
+   recycle *temp;
+   if (r->trash)
+   {  /* pull a node off the trash heap */
+      temp = r->trash;
+      r->trash = temp->next;
+      (void)memset((void *)temp, 0, r->size);
+   }
+   else
+   {  /* allocate a new block of nodes */
+      r->numleft = (int) r->size*((ub4)1<<r->logsize);
+      if (r->numleft < REMAX) ++r->logsize;
+      temp = (recycle *)remalloc(sizeof(recycle) + r->numleft, 
+				 "recycle.c, data");
+      temp->next = r->list;
+      r->list = temp;
+      r->numleft -= (int) r->size;
+      temp = (recycle *)((char *)(r->list+1)+r->numleft);
+   }
+   return (char *)temp;
+}
+
+
+char *remalloc(size_t len, char* purpose)
+{
+  char *x = (char*) malloc(len);
+  if (!x)
+  {
+    fprintf(stderr, "malloc %lu failed for %s\n", (unsigned long)len, purpose);
+    exit(SUCCESS);
+  }
+  return x;
+}
+
diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenkrecy.h b/binding-c/runtime/c/src/extern/jenkhash/jenkrecy.h
new file mode 100644
index 0000000..1099f1c
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenkrecy.h
@@ -0,0 +1,82 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+--------------------------------------------------------------------
+By Bob Jenkins, September 1996.  recycle.h
+You may use this code in any way you wish, and it is free.  No warranty.
+
+This manages memory for commonly-allocated structures.
+It allocates RESTART to REMAX items at a time.
+Timings have shown that, if malloc is used for every new structure,
+  malloc will consume about 90% of the time in a program.  This
+  module cuts down the number of mallocs by an order of magnitude.
+This also decreases memory fragmentation, and freeing all structures
+  only requires freeing the root.
+--------------------------------------------------------------------
+*/
+
+#include "jenkstd.h"
+
+#ifndef RECYCLE
+#define RECYCLE
+
+#define RESTART    0
+#define REMAX      32000
+
+struct recycle
+{
+   struct recycle *next;
+};
+typedef struct recycle recycle;
+
+struct reroot
+{
+   struct recycle *list;     /* list of malloced blocks */
+   struct recycle *trash;    /* list of deleted items */
+   size_t          size;     /* size of an item */
+   size_t          logsize;  /* log_2 of number of items in a block */
+   intx            numleft;  /* number of bytes left in this block */
+};
+typedef  struct reroot  reroot;
+
+/* make a new recycling root */
+reroot *remkroot(size_t mysize);
+
+/* free a recycling root and all the items it has made */
+void refree(struct reroot *r);
+
+/* get a new (cleared) item from the root */
+#define renew(r) ((r)->numleft ? \
+   (((char *)((r)->list+1))+((r)->numleft-=(int)(r)->size)) : renewx(r))
+
+char *renewx(struct reroot *r);
+
+
+/* delete an item; let the root recycle it */
+/* void redel(/o_ struct reroot *r, struct recycle *item _o/); */
+#define redel(root,item) { \
+   ((recycle *)item)->next=(root)->trash; \
+   (root)->trash=(recycle *)(item); \
+}
+
+/* malloc, but complain to stderr and exit program if no joy */
+/* use plain free() to free memory allocated by remalloc() */
+char *remalloc(size_t len, char *purpose);
+
+#endif  /* RECYCLE */
diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenkstd.h b/binding-c/runtime/c/src/extern/jenkhash/jenkstd.h
new file mode 100644
index 0000000..e032385
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenkstd.h
@@ -0,0 +1,110 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+------------------------------------------------------------------------------
+Standard definitions and types, Bob Jenkins
+------------------------------------------------------------------------------
+*/
+#ifndef STANDARD
+#define STANDARD
+
+/*
+   JLD cisco systems: ensure VS 2005 wide character support is turned on.
+   These definitions are enabled in the VS project, however for Linux and etc.
+   they may serve as a reminder that an etch binding should be unicode enabled.
+*/
+#ifndef _UNICODE    /* defined by default in VS2005 */
+#define _UNICODE
+#endif
+
+#if defined(WIN32) && !defined(_WIN32_WCE)
+#include <tchar.h>  /* wide char support, wmain() vs main() */
+#else
+#include <wchar.h>
+#endif
+
+#ifndef UNICODE     /* defined by default in VS2005 */
+#define UNICODE
+#endif
+/*
+   end VS 2005 wide character support -- JLD
+*/
+ 
+#include <stdio.h>
+#include <stddef.h>
+
+typedef  unsigned long long  ub8;
+#define UB8MAXVAL 0xffffffffffffffffLL
+#define UB8BITS 64
+typedef    signed long long  sb8;
+#define SB8MAXVAL 0x7fffffffffffffffLL
+typedef  unsigned long  int  ub4;   /* unsigned 4-byte quantities */
+#define UB4MAXVAL 0xffffffff
+typedef    signed long  int  sb4;
+#define UB4BITS 32
+#define SB4MAXVAL 0x7fffffff
+typedef  unsigned short int  ub2;
+#define UB2MAXVAL 0xffff
+#define UB2BITS 16
+typedef    signed short int  sb2;
+#define SB2MAXVAL 0x7fff
+typedef  unsigned       char ub1;
+#define UB1MAXVAL 0xff
+#define UB1BITS 8
+typedef    signed       char sb1;   /* signed 1-byte quantities */
+#define SB1MAXVAL 0x7f
+
+/* JLD replaced Jenkins' 'word' typdef with 'intx'. 'word' is too 
+   likely to be confused by the reader with a Windows 16-bit integer.
+   intx is brief, and is more readable as 'the register size on the
+   host OS". It remains unclear whether simply changing this typedef to 
+   a 64-bit integer, on a 64-bit OS, is sufficient for the hashtable
+   to work as advertised in 64 bits. See macro renew() for example,
+   where it appears as if sizeof(char*) is assumed same as sizeof(int).   
+*/
+typedef int intx; 
+/* typedef int  word fastest type available */
+
+#define bis(target,mask)  ((target) |=  (mask))
+#define bic(target,mask)  ((target) &= ~(mask))
+#define bit(target,mask)  ((target) &   (mask))
+
+/* JLD commented this stuff out
+#ifndef min
+#define min(a,b) (((a)<(b)) ? (a) : (b))
+#endif  
+
+#ifndef max
+#define max(a,b) (((a)<(b)) ? (b) : (a))
+#endif  
+*/
+
+#ifndef align
+#define align(a) (((ub4)a+(sizeof(void *)-1))&(~(sizeof(void *)-1)))
+#endif  
+
+#ifndef abs
+#define abs(a)   (((a)>0) ? (a) : -(a))
+#endif
+
+#define TRUE    1
+#define FALSE   0
+#define SUCCESS 0  /* 1 on VAX */
+
+#endif /* STANDARD */
diff --git a/binding-c/runtime/c/src/extern/jenkhash/jenktest.txt b/binding-c/runtime/c/src/extern/jenkhash/jenktest.txt
new file mode 100644
index 0000000..1183597
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/jenktest.txt
@@ -0,0 +1,58 @@
+apple
+banana
+banter
+baseball
+blueberry
+brown
+browser
+camera
+can
+cantaloupe
+cherry
+cinnamon
+clear
+dash
+date
+distance
+ever
+ewe
+eye
+fig
+grape
+her
+lake
+leaf
+leave
+lemon
+lever
+lime
+mellon
+mango
+math
+music
+netscape
+never
+orange
+pear
+pepper
+politics
+psychedelic
+psychology
+salt
+science
+sift
+signals
+softball
+spice
+stupid
+swear
+syntax
+strawberry
+tangerine
+towel
+turn
+washcloth
+watermelon
+will
+words
+yellow
diff --git a/binding-c/runtime/c/src/extern/jenkhash/readme-jenk.txt b/binding-c/runtime/c/src/extern/jenkhash/readme-jenk.txt
new file mode 100644
index 0000000..b782a65
--- /dev/null
+++ b/binding-c/runtime/c/src/extern/jenkhash/readme-jenk.txt
@@ -0,0 +1,90 @@
+
+This is Bob Jenkins' hash table code from burtleburtle.net/bob/hash/hashtab.html.
+The author, Bob Jenkins, has placed this code in the public domain, 
+He states as such in comments in the code itself. Regarding inclusion of the
+code in an Apache project, he states:
+   I do prefer that you keep a pointer back to me as the source, so I can 
+   answer questions if any come up.  I would object if someone claimed 
+   they'd written it themselves. But other than that, there's no restrictions, 
+   you can remove or rewrite any of the comments or code, 
+   including the disclaimers.
+
+   James DeCocq (jadecocq) wrote:
+   > Hi Bob,
+   > Last year I used your excellent hash table C code in a project which 
+   > is now to become an Apache open source project. What is the usual  
+   > attribution and licensing disclaimer procedures when folks use your  
+   > code in open source projects? 
+
+CUSTOMIZED FOR ETCH
+The original code has been customized for use by etch. Changes are as follows:
+- renamed files belonging to this subproject to begin with "jenk".
+- changed name of unique.c to jenktest.c; changed this to read from file not stdin
+- added includes to .c files such that they compile individually
+
+BEGIN JENKINS COMMENTS ON THE CODE
+hashtab.h and hashtab.c form the hash table module. 
+The files before those are the support files that I always use. 
+The file after it (unique.c) is an example of how to use the hash table. 
+(The program UNIQUE takes a file in STDIN and dumps the unique lines 
+(duplicates removed) to STDOUT. 
+It also shuffles the unique lines pseudorandomly. 
+The sample input provided doesn't have any duplicate lines, 
+so the output should be the same size as the input, but the lines will be shuffled.) 
+
+The hash table has a fixed hash function, and its size is a power of two. 
+It doubles in size when it needs to, and when it doubles, it doubles all at once. 
+It never shrinks. Input keys and data are pointed to, not copied. 
+Keys are unique. 
+Collisions are handled by chaining. 
+
+Functions are: 
+hcreate  - create a hash table 
+hdestroy - destroy a hash table 
+hcount   - how many items are in the hash table? 
+hkey     - the key at the current position 
+hkeyl    - the length of the key at the current position 
+hstuff   - the other data at the current position 
+hfind    - position the hash table at some key 
+hadd     - add a new <key,stuff> pair to the table 
+hdel     - delete the item at the current position 
+hfirst   - position at the first item in the table 
+hnext    - move to the next item in the table 
+hstat    - print statistics about this table 
+
+The most unusual thing about this module is that it maintains a current position. 
+This means you can't have a dangling pointer into it. 
+If you position on something, and then delete it, the position moves to another item. 
+On the other hand, it also means it's hard to do nested loops over all the items in the table, 
+since there can be only one position at a time. 
+END JENKINS COMMENTS ON THE CODE
+
+
+JENKINS EMAIL RE 64-BIT COMPATIBILITY
+I don't have any.  However, Thomas Wang came up with this one:
+
+public long hash64shift(long key)
+{
+  key = (~key) + (key << 21); // key = (key << 21) - key - 1;
+  key = key ^ (key >>> 24);
+  key = (key + (key << 3)) + (key << 8); // key * 265
+  key = key ^ (key >>> 14);
+  key = (key + (key << 2)) + (key << 4); // key * 21
+  key = key ^ (key >>> 28);
+  key = key + (key << 31);
+  return key;
+}
+
+I haven't tested it, but the functions of his that I have tested aren't bad, and the operations look about like what I'd expect is needed.  My preliminary stabs at a 64-bit functions said 8 or 9 shifts are needed, he's got 10, but many are done in parallel, so it does look like a promising function.
+
+James DeCocq (jadecocq) wrote:
+> Hi Bob,
+>
+> Have you tried the code in 64 bits? I don't currently have the ability 
+> to do so, but a glance at some of the code, specifically the renew() 
+> macro, seems as if it might assume that a pointer is the same size as 
+> an int. If it is the case that it makes assumptions as to 32 bits, are 
+> there specific tweaks you may have made for 64 bits that you can share?
+END JENKINS EMAIL RE 64-BIT COMPATIBILITY
+
+
diff --git a/binding-c/runtime/c/src/main/apr/etch_threadpool_apr.c b/binding-c/runtime/c/src/main/apr/etch_threadpool_apr.c
new file mode 100644
index 0000000..75dc753
--- /dev/null
+++ b/binding-c/runtime/c/src/main/apr/etch_threadpool_apr.c
@@ -0,0 +1,1025 @@
+/*
+ * 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.
+ */
+
+/*
+ * etch_threadpool_apr.c
+ * apache portable runtime threadpool code
+ */
+
+#include "etch.h"
+#include "etch_threadpool_apr.h"
+#include "apr_ring.h"
+#include "apr_thread_cond.h"
+
+#define TASK_PRIORITY_SEGS 4
+#define TASK_PRIORITY_SEG(x) (((x)->dispatch.priority & 0xFF) / 64)
+
+
+typedef struct apr_thread_pool_task
+{
+    APR_RING_ENTRY(apr_thread_pool_task) link;
+    apr_thread_start_t func;
+    void *param;
+    void *owner;
+    union
+    {
+        apr_byte_t priority;
+        apr_time_t time;
+    } dispatch;
+} apr_thread_pool_task_t;
+
+
+APR_RING_HEAD(apr_thread_pool_tasks, apr_thread_pool_task);
+
+
+struct apr_thread_list_elt
+{
+    APR_RING_ENTRY(apr_thread_list_elt) link;
+    apr_thread_t *thd;
+    volatile void *current_owner;
+    volatile enum { TH_RUN, TH_STOP, TH_PROBATION } state;
+};
+
+
+APR_RING_HEAD(apr_thread_list, apr_thread_list_elt);
+
+
+struct apr_thread_pool
+{
+    apr_pool_t *pool;
+    volatile apr_size_t thd_max;
+    volatile apr_size_t idle_max;
+    volatile apr_interval_time_t idle_wait;
+    volatile apr_size_t thd_cnt;
+    volatile apr_size_t idle_cnt;
+    volatile apr_size_t task_cnt;
+    volatile apr_size_t scheduled_task_cnt;
+    volatile apr_size_t threshold;
+    volatile apr_size_t tasks_run;
+    volatile apr_size_t tasks_high;
+    volatile apr_size_t thd_high;
+    volatile apr_size_t thd_timed_out;
+    struct apr_thread_pool_tasks *tasks;
+    struct apr_thread_pool_tasks *scheduled_tasks;
+    struct apr_thread_list *busy_thds;
+    struct apr_thread_list *idle_thds;
+    apr_thread_mutex_t *lock;
+    apr_thread_mutex_t *cond_lock;
+    apr_thread_cond_t *cond;
+    volatile int terminated;
+    struct apr_thread_pool_tasks *recycled_tasks;
+    struct apr_thread_list *recycled_thds;
+    apr_thread_pool_task_t *task_idx[TASK_PRIORITY_SEGS];
+};
+
+
+
+static apr_status_t thread_pool_construct(apr_thread_pool_t * me,
+                                          apr_size_t init_threads,
+                                          apr_size_t max_threads)
+{
+    apr_status_t rv;
+    int i;
+
+    me->thd_max = max_threads;
+    me->idle_max = init_threads;
+    me->threshold = init_threads / 2;
+    rv = apr_thread_mutex_create(&me->lock, APR_THREAD_MUTEX_NESTED,
+                                 me->pool);
+    if (APR_SUCCESS != rv) {
+        return rv;
+    }
+    rv = apr_thread_mutex_create(&me->cond_lock, APR_THREAD_MUTEX_UNNESTED,
+                                 me->pool);
+    if (APR_SUCCESS != rv) {
+        apr_thread_mutex_destroy(me->lock);
+        return rv;
+    }
+    rv = apr_thread_cond_create(&me->cond, me->pool);
+    if (APR_SUCCESS != rv) {
+        apr_thread_mutex_destroy(me->lock);
+        apr_thread_mutex_destroy(me->cond_lock);
+        return rv;
+    }
+    me->tasks = apr_palloc(me->pool, sizeof(*me->tasks));
+    if (!me->tasks) {
+        goto CATCH_ENOMEM;
+    }
+    APR_RING_INIT(me->tasks, apr_thread_pool_task, link);
+    me->scheduled_tasks = apr_palloc(me->pool, sizeof(*me->scheduled_tasks));
+    if (!me->scheduled_tasks) {
+        goto CATCH_ENOMEM;
+    }
+    APR_RING_INIT(me->scheduled_tasks, apr_thread_pool_task, link);
+    me->recycled_tasks = apr_palloc(me->pool, sizeof(*me->recycled_tasks));
+    if (!me->recycled_tasks) {
+        goto CATCH_ENOMEM;
+    }
+    APR_RING_INIT(me->recycled_tasks, apr_thread_pool_task, link);
+    me->busy_thds = apr_palloc(me->pool, sizeof(*me->busy_thds));
+    if (!me->busy_thds) {
+        goto CATCH_ENOMEM;
+    }
+    APR_RING_INIT(me->busy_thds, apr_thread_list_elt, link);
+    me->idle_thds = apr_palloc(me->pool, sizeof(*me->idle_thds));
+    if (!me->idle_thds) {
+        goto CATCH_ENOMEM;
+    }
+    APR_RING_INIT(me->idle_thds, apr_thread_list_elt, link);
+    me->recycled_thds = apr_palloc(me->pool, sizeof(*me->recycled_thds));
+    if (!me->recycled_thds) {
+        goto CATCH_ENOMEM;
+    }
+    APR_RING_INIT(me->recycled_thds, apr_thread_list_elt, link);
+    me->thd_cnt = me->idle_cnt = me->task_cnt = me->scheduled_task_cnt = 0;
+    me->tasks_run = me->tasks_high = me->thd_high = me->thd_timed_out = 0;
+    me->idle_wait = 0;
+    me->terminated = 0;
+    for (i = 0; i < TASK_PRIORITY_SEGS; i++) {
+        me->task_idx[i] = NULL;
+    }
+    goto FINAL_EXIT;
+  CATCH_ENOMEM:
+    rv = APR_ENOMEM;
+    apr_thread_mutex_destroy(me->lock);
+    apr_thread_mutex_destroy(me->cond_lock);
+    apr_thread_cond_destroy(me->cond);
+  FINAL_EXIT:
+    return rv;
+}
+
+/*
+ * NOTE: This function is not thread safe by itself. Caller should hold the lock
+ */
+static apr_thread_pool_task_t *pop_task(apr_thread_pool_t * me)
+{
+    apr_thread_pool_task_t *task = NULL;
+    int seg;
+
+    /* check for scheduled tasks */
+    if (me->scheduled_task_cnt > 0) {
+        task = APR_RING_FIRST(me->scheduled_tasks);
+        ETCH_ASSERT(task != NULL);
+        ETCH_ASSERT(task != APR_RING_SENTINEL(me->scheduled_tasks, apr_thread_pool_task, link));
+        /* if it's time */
+        if (task->dispatch.time <= apr_time_now()) {
+            --me->scheduled_task_cnt;
+            APR_RING_REMOVE(task, link);
+            return task;
+        }
+    }
+    /* check for normal tasks if we're not returning a scheduled task */
+    if (me->task_cnt == 0) {
+        return NULL;
+    }
+
+    task = APR_RING_FIRST(me->tasks);
+    assert(task != NULL);
+    assert(task != APR_RING_SENTINEL(me->tasks, apr_thread_pool_task, link));
+    --me->task_cnt;
+    seg = TASK_PRIORITY_SEG(task);
+    if (task == me->task_idx[seg]) {
+        me->task_idx[seg] = APR_RING_NEXT(task, link);
+        if (me->task_idx[seg] == APR_RING_SENTINEL(me->tasks,
+                                                   apr_thread_pool_task, link)
+            || TASK_PRIORITY_SEG(me->task_idx[seg]) != seg) {
+            me->task_idx[seg] = NULL;
+        }
+    }
+    APR_RING_REMOVE(task, link);
+    return task;
+}
+
+
+static apr_interval_time_t waiting_time(apr_thread_pool_t * me)
+{
+    apr_thread_pool_task_t *task = NULL;
+
+    task = APR_RING_FIRST(me->scheduled_tasks);
+    assert(task != NULL);
+    assert(task !=
+           APR_RING_SENTINEL(me->scheduled_tasks, apr_thread_pool_task,
+                             link));
+    return task->dispatch.time - apr_time_now();
+}
+
+
+
+/*
+ * NOTE: This function is not thread safe by itself. Caller should hold the lock
+ */
+static struct apr_thread_list_elt *elt_new(apr_thread_pool_t * me,
+                                           apr_thread_t * t)
+{
+    struct apr_thread_list_elt *elt;
+
+    if (APR_RING_EMPTY(me->recycled_thds, apr_thread_list_elt, link)) {
+        elt = apr_pcalloc(me->pool, sizeof(*elt));
+        if (NULL == elt) {
+            return NULL;
+        }
+    }
+    else {
+        elt = APR_RING_FIRST(me->recycled_thds);
+        APR_RING_REMOVE(elt, link);
+    }
+
+    APR_RING_ELEM_INIT(elt, link);
+    elt->thd = t;
+    elt->current_owner = NULL;
+    elt->state = TH_RUN;
+    return elt;
+}
+
+
+
+/*
+ * The worker thread function. Take a task from the queue and perform it if
+ * there is any. Otherwise, put itself into the idle thread list and waiting
+ * for signal to wake up.
+ * The thread terminate directly by detach and exit when it is asked to stop
+ * after finishing a task. Otherwise, the thread should be in idle thread list
+ * and should be joined.
+ */
+static void *APR_THREAD_FUNC thread_pool_func(apr_thread_t * t, void *param)
+{
+    apr_status_t rv = APR_SUCCESS;
+    apr_thread_pool_t *me = param;
+    apr_thread_pool_task_t *task = NULL;
+    apr_interval_time_t wait;
+    struct apr_thread_list_elt *elt;
+
+    apr_thread_mutex_lock(me->lock);
+    elt = elt_new(me, t);
+    if (!elt) {
+        apr_thread_mutex_unlock(me->lock);
+        apr_thread_exit(t, APR_ENOMEM);
+    }
+
+    while (!me->terminated && elt->state != TH_STOP) {
+        /* Test if not new element, it is awakened from idle */
+        if (APR_RING_NEXT(elt, link) != elt) {
+            --me->idle_cnt;
+            APR_RING_REMOVE(elt, link);
+        }
+
+        APR_RING_INSERT_TAIL(me->busy_thds, elt, apr_thread_list_elt, link);
+        task = pop_task(me);
+        while (NULL != task && !me->terminated) {
+            ++me->tasks_run;
+            elt->current_owner = task->owner;
+            apr_thread_mutex_unlock(me->lock);
+            apr_thread_data_set(task, "apr_thread_pool_task", NULL, t);
+            task->func(t, task->param);
+            apr_thread_mutex_lock(me->lock);
+            APR_RING_INSERT_TAIL(me->recycled_tasks, task,
+                                 apr_thread_pool_task, link);
+            elt->current_owner = NULL;
+            if (TH_STOP == elt->state) {
+                break;
+            }
+            task = pop_task(me);
+        }
+        assert(NULL == elt->current_owner);
+        if (TH_STOP != elt->state)
+            APR_RING_REMOVE(elt, link);
+
+        /* Test if a busy thread been asked to stop, which is not joinable */
+        if ((me->idle_cnt >= me->idle_max
+             && !(me->scheduled_task_cnt && 0 >= me->idle_max)
+             && !me->idle_wait)
+            || me->terminated || elt->state != TH_RUN) {
+            --me->thd_cnt;
+            if ((TH_PROBATION == elt->state) && me->idle_wait)
+                ++me->thd_timed_out;
+            APR_RING_INSERT_TAIL(me->recycled_thds, elt,
+                                 apr_thread_list_elt, link);
+            apr_thread_mutex_unlock(me->lock);
+            apr_thread_detach(t);
+            apr_thread_exit(t, APR_SUCCESS);
+            return NULL;        /* should not be here, safe net */
+        }
+
+        /* busy thread become idle */
+        ++me->idle_cnt;
+        APR_RING_INSERT_TAIL(me->idle_thds, elt, apr_thread_list_elt, link);
+
+        /* 
+         * If there is a scheduled task, always scheduled to perform that task.
+         * Since there is no guarantee that current idle threads are scheduled
+         * for next scheduled task.
+         */
+        if (me->scheduled_task_cnt)
+            wait = waiting_time(me);
+        else if (me->idle_cnt > me->idle_max) {
+            wait = me->idle_wait;
+            elt->state = TH_PROBATION;
+        }
+        else
+            wait = -1;
+
+        apr_thread_mutex_unlock(me->lock);
+        apr_thread_mutex_lock(me->cond_lock);
+        if (wait >= 0) {
+            rv = apr_thread_cond_timedwait(me->cond, me->cond_lock, wait);
+        }
+        else {
+            rv = apr_thread_cond_wait(me->cond, me->cond_lock);
+        }
+        apr_thread_mutex_unlock(me->cond_lock);
+        apr_thread_mutex_lock(me->lock);
+    }
+
+    /* idle thread been asked to stop, will be joined */
+    --me->thd_cnt;
+    apr_thread_mutex_unlock(me->lock);
+    apr_thread_exit(t, APR_SUCCESS);
+    return NULL;                /* should not be here, safe net */
+}
+
+static apr_status_t thread_pool_cleanup(void *me)
+{
+    apr_thread_pool_t *_self = me;
+
+    _self->terminated = 1;
+    etch_apr_thread_pool_idle_max_set(_self, 0);
+    while (_self->thd_cnt) {
+        apr_sleep(20 * 1000);   /* spin lock with 20 ms */
+    }
+    apr_thread_mutex_destroy(_self->lock);
+    apr_thread_mutex_destroy(_self->cond_lock);
+    apr_thread_cond_destroy(_self->cond);
+    return APR_SUCCESS;
+}
+
+
+
+apr_status_t etch_apr_thread_pool_create(apr_thread_pool_t ** me,
+                                                 apr_size_t init_threads,
+                                                 apr_size_t max_threads,
+                                                 apr_pool_t * pool)
+{
+    apr_thread_t *t;
+    apr_status_t rv = APR_SUCCESS;
+
+    *me = apr_pcalloc(pool, sizeof(**me));
+    if (!*me) {
+        return APR_ENOMEM;
+    }
+
+    (*me)->pool = pool;
+
+    rv = thread_pool_construct(*me, init_threads, max_threads);
+    if (APR_SUCCESS != rv) {
+        *me = NULL;
+        return rv;
+    }
+    apr_pool_cleanup_register(pool, *me, thread_pool_cleanup,
+                              apr_pool_cleanup_null);
+
+    while (init_threads) {
+        rv = apr_thread_create(&t, NULL, thread_pool_func, *me, (*me)->pool);
+        if (APR_SUCCESS != rv) {
+            break;
+        }
+        ++(*me)->thd_cnt;
+        if ((*me)->thd_cnt > (*me)->thd_high)
+            (*me)->thd_high = (*me)->thd_cnt;
+        --init_threads;
+    }
+
+    return rv;
+}
+
+
+
+apr_status_t etch_apr_thread_pool_destroy(apr_thread_pool_t * me)
+{
+    return apr_pool_cleanup_run(me->pool, me, thread_pool_cleanup);
+}
+
+
+
+/*
+ * NOTE: This function is not thread safe by itself. Caller should hold the lock
+ */
+static apr_thread_pool_task_t *task_new(apr_thread_pool_t * me,
+                                        apr_thread_start_t func,
+                                        void *param, apr_byte_t priority,
+                                        void *owner, apr_time_t time)
+{
+    apr_thread_pool_task_t *t;
+
+    if (APR_RING_EMPTY(me->recycled_tasks, apr_thread_pool_task, link)) {
+        t = apr_pcalloc(me->pool, sizeof(*t));
+        if (NULL == t) {
+            return NULL;
+        }
+    }
+    else {
+        t = APR_RING_FIRST(me->recycled_tasks);
+        APR_RING_REMOVE(t, link);
+    }
+
+    APR_RING_ELEM_INIT(t, link);
+    t->func = func;
+    t->param = param;
+    t->owner = owner;
+    if (time > 0) {
+        t->dispatch.time = apr_time_now() + time;
+    }
+    else {
+        t->dispatch.priority = priority;
+    }
+    return t;
+}
+
+
+
+/*
+ * Test it the task is the only one within the priority segment. 
+ * If it is not, return the first element with same or lower priority. 
+ * Otherwise, add the task into the queue and return NULL.
+ *
+ * NOTE: This function is not thread safe by itself. Caller should hold the lock
+ */
+static apr_thread_pool_task_t *add_if_empty(apr_thread_pool_t * me,
+                                            apr_thread_pool_task_t * const t)
+{
+    int seg;
+    int next;
+    apr_thread_pool_task_t *t_next;
+
+    seg = TASK_PRIORITY_SEG(t);
+    if (me->task_idx[seg]) {
+        assert(APR_RING_SENTINEL(me->tasks, apr_thread_pool_task, link) !=
+               me->task_idx[seg]);
+        t_next = me->task_idx[seg];
+        while (t_next->dispatch.priority > t->dispatch.priority) {
+            t_next = APR_RING_NEXT(t_next, link);
+            if (APR_RING_SENTINEL(me->tasks, apr_thread_pool_task, link) ==
+                t_next) {
+                return t_next;
+            }
+        }
+        return t_next;
+    }
+
+    for (next = seg - 1; next >= 0; next--) {
+        if (me->task_idx[next]) {
+            APR_RING_INSERT_BEFORE(me->task_idx[next], t, link);
+            break;
+        }
+    }
+    if (0 > next) {
+        APR_RING_INSERT_TAIL(me->tasks, t, apr_thread_pool_task, link);
+    }
+    me->task_idx[seg] = t;
+    return NULL;
+}
+
+
+/*
+ *   schedule a task to run in "time" microseconds. Find the spot in the ring where
+ *   the time fits. Adjust the short_time so the thread wakes up when the time is reached.
+ */
+static apr_status_t schedule_task(apr_thread_pool_t *me,
+                                  apr_thread_start_t func, void *param,
+                                  void *owner, apr_interval_time_t time)
+{
+    apr_thread_pool_task_t *t;
+    apr_thread_pool_task_t *t_loc;
+    apr_thread_t *thd;
+    apr_status_t rv = APR_SUCCESS;
+    apr_thread_mutex_lock(me->lock);
+
+    t = task_new(me, func, param, 0, owner, time);
+    if (NULL == t) {
+        apr_thread_mutex_unlock(me->lock);
+        return APR_ENOMEM;
+    }
+    t_loc = APR_RING_FIRST(me->scheduled_tasks);
+    while (NULL != t_loc) {
+        /* if the time is less than the entry insert ahead of it */
+        if (t->dispatch.time < t_loc->dispatch.time) {
+            ++me->scheduled_task_cnt;
+            APR_RING_INSERT_BEFORE(t_loc, t, link);
+            break;
+        }
+        else {
+            t_loc = APR_RING_NEXT(t_loc, link);
+            if (t_loc ==
+                APR_RING_SENTINEL(me->scheduled_tasks, apr_thread_pool_task,
+                                  link)) {
+                ++me->scheduled_task_cnt;
+                APR_RING_INSERT_TAIL(me->scheduled_tasks, t,
+                                     apr_thread_pool_task, link);
+                break;
+            }
+        }
+    }
+    /* there should be at least one thread for scheduled tasks */
+    if (0 == me->thd_cnt) {
+        rv = apr_thread_create(&thd, NULL, thread_pool_func, me, me->pool);
+        if (APR_SUCCESS == rv) {
+            ++me->thd_cnt;
+            if (me->thd_cnt > me->thd_high)
+                me->thd_high = me->thd_cnt;
+        }
+    }
+    apr_thread_mutex_unlock(me->lock);
+    apr_thread_mutex_lock(me->cond_lock);
+    apr_thread_cond_signal(me->cond);
+    apr_thread_mutex_unlock(me->cond_lock);
+    return rv;
+}
+
+
+
+static apr_status_t add_task(apr_thread_pool_t *me, apr_thread_start_t func,
+                             void *param, apr_byte_t priority, int push,
+                             void *owner)
+{
+    apr_thread_pool_task_t *t;
+    apr_thread_pool_task_t *t_loc;
+    apr_thread_t *thd;
+    apr_status_t rv = APR_SUCCESS;
+
+    apr_thread_mutex_lock(me->lock);
+
+    t = task_new(me, func, param, priority, owner, 0);
+    if (NULL == t) {
+        apr_thread_mutex_unlock(me->lock);
+        return APR_ENOMEM;
+    }
+
+    t_loc = add_if_empty(me, t);
+    if (NULL == t_loc) {
+        goto FINAL_EXIT;
+    }
+
+    if (push) {
+        while (APR_RING_SENTINEL(me->tasks, apr_thread_pool_task, link) !=
+               t_loc && t_loc->dispatch.priority >= t->dispatch.priority) {
+            t_loc = APR_RING_NEXT(t_loc, link);
+        }
+    }
+    APR_RING_INSERT_BEFORE(t_loc, t, link);
+    if (!push) {
+        if (t_loc == me->task_idx[TASK_PRIORITY_SEG(t)]) {
+            me->task_idx[TASK_PRIORITY_SEG(t)] = t;
+        }
+    }
+
+  FINAL_EXIT:
+    me->task_cnt++;
+    if (me->task_cnt > me->tasks_high)
+        me->tasks_high = me->task_cnt;
+    if (0 == me->thd_cnt || (0 == me->idle_cnt && me->thd_cnt < me->thd_max &&
+                             me->task_cnt > me->threshold)) {
+        rv = apr_thread_create(&thd, NULL, thread_pool_func, me, me->pool);
+        if (APR_SUCCESS == rv) {
+            ++me->thd_cnt;
+            if (me->thd_cnt > me->thd_high)
+                me->thd_high = me->thd_cnt;
+        }
+    }
+    apr_thread_mutex_unlock(me->lock);
+
+    apr_thread_mutex_lock(me->cond_lock);
+    apr_thread_cond_signal(me->cond);
+    apr_thread_mutex_unlock(me->cond_lock);
+
+    return rv;
+}
+
+
+
+apr_status_t etch_apr_thread_pool_push(apr_thread_pool_t *me,
+                                               apr_thread_start_t func,
+                                               void *param,
+                                               apr_byte_t priority,
+                                               void *owner)
+{
+    return add_task(me, func, param, priority, 1, owner);
+}
+
+
+
+apr_status_t etch_apr_thread_pool_schedule(apr_thread_pool_t *me,
+                                                   apr_thread_start_t func,
+                                                   void *param,
+                                                   apr_interval_time_t time,
+                                                   void *owner)
+{
+    return schedule_task(me, func, param, owner, time);
+}
+
+
+
+apr_status_t etch_apr_thread_pool_top(apr_thread_pool_t *me,
+                                              apr_thread_start_t func,
+                                              void *param,
+                                              apr_byte_t priority,
+                                              void *owner)
+{
+    return add_task(me, func, param, priority, 0, owner);
+}
+
+
+
+static apr_status_t remove_scheduled_tasks(apr_thread_pool_t *me,
+                                           void *owner)
+{
+    apr_thread_pool_task_t *t_loc;
+    apr_thread_pool_task_t *next;
+
+    t_loc = APR_RING_FIRST(me->scheduled_tasks);
+    while (t_loc !=
+           APR_RING_SENTINEL(me->scheduled_tasks, apr_thread_pool_task,
+                             link)) {
+        next = APR_RING_NEXT(t_loc, link);
+        /* if this is the owner remove it */
+        if (t_loc->owner == owner) {
+            --me->scheduled_task_cnt;
+            APR_RING_REMOVE(t_loc, link);
+        }
+        t_loc = next;
+    }
+    return APR_SUCCESS;
+}
+
+
+
+static apr_status_t remove_tasks(apr_thread_pool_t *me, void *owner)
+{
+    apr_thread_pool_task_t *t_loc;
+    apr_thread_pool_task_t *next;
+    int seg;
+
+    t_loc = APR_RING_FIRST(me->tasks);
+    while (t_loc != APR_RING_SENTINEL(me->tasks, apr_thread_pool_task, link)) {
+        next = APR_RING_NEXT(t_loc, link);
+        if (t_loc->owner == owner) {
+            --me->task_cnt;
+            seg = TASK_PRIORITY_SEG(t_loc);
+            if (t_loc == me->task_idx[seg]) {
+                me->task_idx[seg] = APR_RING_NEXT(t_loc, link);
+                if (me->task_idx[seg] == APR_RING_SENTINEL(me->tasks,
+                                                           apr_thread_pool_task,
+                                                           link)
+                    || TASK_PRIORITY_SEG(me->task_idx[seg]) != seg) {
+                    me->task_idx[seg] = NULL;
+                }
+            }
+            APR_RING_REMOVE(t_loc, link);
+        }
+        t_loc = next;
+    }
+    return APR_SUCCESS;
+}
+
+
+
+static void wait_on_busy_threads(apr_thread_pool_t *me, void *owner)
+{
+#ifndef NDEBUG
+    apr_os_thread_t *os_thread;
+#endif
+    struct apr_thread_list_elt *elt;
+    apr_thread_mutex_lock(me->lock);
+    elt = APR_RING_FIRST(me->busy_thds);
+    while (elt != APR_RING_SENTINEL(me->busy_thds, apr_thread_list_elt, link)) {
+        if (elt->current_owner != owner) {
+            elt = APR_RING_NEXT(elt, link);
+            continue;
+        }
+#ifndef NDEBUG
+        /* make sure the thread is not the one calling tasks_cancel */
+        apr_os_thread_get(&os_thread, elt->thd);
+#ifdef WIN32
+        /* hack for apr win32 bug */
+        assert(!apr_os_thread_equal(apr_os_thread_current(), os_thread));
+#else
+        assert(!apr_os_thread_equal(apr_os_thread_current(), *os_thread));
+#endif
+#endif
+        while (elt->current_owner == owner) {
+            apr_thread_mutex_unlock(me->lock);
+            apr_sleep(200 * 1000);
+            apr_thread_mutex_lock(me->lock);
+        }
+        elt = APR_RING_FIRST(me->busy_thds);
+    }
+    apr_thread_mutex_unlock(me->lock);
+    return;
+}
+
+
+
+apr_status_t etch_apr_thread_pool_tasks_cancel(apr_thread_pool_t *me,
+                                                       void *owner)
+{
+    apr_status_t rv = APR_SUCCESS;
+
+    apr_thread_mutex_lock(me->lock);
+    if (me->task_cnt > 0) {
+        rv = remove_tasks(me, owner);
+    }
+    if (me->scheduled_task_cnt > 0) {
+        rv = remove_scheduled_tasks(me, owner);
+    }
+    apr_thread_mutex_unlock(me->lock);
+    wait_on_busy_threads(me, owner);
+
+    return rv;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_tasks_count(apr_thread_pool_t *me)
+{
+    return me->task_cnt;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_scheduled_tasks_count(apr_thread_pool_t *me)
+{
+    return me->scheduled_task_cnt;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_threads_count(apr_thread_pool_t *me)
+{
+    return me->thd_cnt;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_busy_count(apr_thread_pool_t *me)
+{
+    return me->thd_cnt - me->idle_cnt;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_idle_count(apr_thread_pool_t *me)
+{
+    return me->idle_cnt;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_tasks_run_count(apr_thread_pool_t * me)
+{
+    return me->tasks_run;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_tasks_high_count(apr_thread_pool_t * me)
+{
+    return me->tasks_high;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_threads_high_count(apr_thread_pool_t * me)
+{
+    return me->thd_high;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_threads_idle_timeout_count(apr_thread_pool_t * me)
+{
+    return me->thd_timed_out;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_idle_max_get(apr_thread_pool_t *me)
+{
+    return me->idle_max;
+}
+
+
+apr_interval_time_t etch_apr_thread_pool_idle_wait_get(apr_thread_pool_t * me)
+{
+    return me->idle_wait;
+}
+
+
+
+/*
+ * This function stop extra idle threads to the cnt.
+ * @return the number of threads stopped
+ * NOTE: There could be busy threads become idle during this function
+ */
+static struct apr_thread_list_elt *trim_threads(apr_thread_pool_t *me,
+                                                apr_size_t *cnt, int idle)
+{
+    struct apr_thread_list *thds;
+    apr_size_t n, n_dbg, i;
+    struct apr_thread_list_elt *head, *tail, *elt;
+
+    apr_thread_mutex_lock(me->lock);
+    if (idle) {
+        thds = me->idle_thds;
+        n = me->idle_cnt;
+    }
+    else {
+        thds = me->busy_thds;
+        n = me->thd_cnt - me->idle_cnt;
+    }
+    if (n <= *cnt) {
+        apr_thread_mutex_unlock(me->lock);
+        *cnt = 0;
+        return NULL;
+    }
+    n -= *cnt;
+
+    head = APR_RING_FIRST(thds);
+    for (i = 0; i < *cnt; i++) {
+        head = APR_RING_NEXT(head, link);
+    }
+    tail = APR_RING_LAST(thds);
+    if (idle) {
+        APR_RING_UNSPLICE(head, tail, link);
+        me->idle_cnt = *cnt;
+    }
+
+    n_dbg = 0;
+    for (elt = head; elt != tail; elt = APR_RING_NEXT(elt, link)) {
+        elt->state = TH_STOP;
+        n_dbg++;
+    }
+    elt->state = TH_STOP;
+    n_dbg++;
+    assert(n == n_dbg);
+    *cnt = n;
+
+    apr_thread_mutex_unlock(me->lock);
+
+    APR_RING_PREV(head, link) = NULL;
+    APR_RING_NEXT(tail, link) = NULL;
+    return head;
+}
+
+
+
+static apr_size_t trim_idle_threads(apr_thread_pool_t *me, apr_size_t cnt)
+{
+    apr_size_t n_dbg;
+    struct apr_thread_list_elt *elt, *head, *tail;
+    apr_status_t rv;
+
+    elt = trim_threads(me, &cnt, 1);
+
+    apr_thread_mutex_lock(me->cond_lock);
+    apr_thread_cond_broadcast(me->cond);
+    apr_thread_mutex_unlock(me->cond_lock);
+
+    n_dbg = 0;
+    if (NULL != (head = elt)) {
+        while (elt) {
+            tail = elt;
+            apr_thread_join(&rv, elt->thd);
+            elt = APR_RING_NEXT(elt, link);
+            ++n_dbg;
+        }
+        apr_thread_mutex_lock(me->lock);
+        APR_RING_SPLICE_TAIL(me->recycled_thds, head, tail,
+                             apr_thread_list_elt, link);
+        apr_thread_mutex_unlock(me->lock);
+    }
+    assert(cnt == n_dbg);
+
+    return cnt;
+}
+
+
+/* don't join on busy threads for performance reasons, who knows how long will
+ * the task takes to perform
+ */
+static apr_size_t trim_busy_threads(apr_thread_pool_t *me, apr_size_t cnt)
+{
+    trim_threads(me, &cnt, 0);
+    return cnt;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_idle_max_set(apr_thread_pool_t *me,
+                                                     apr_size_t cnt)
+{
+    me->idle_max = cnt;
+    cnt = trim_idle_threads(me, cnt);
+    return cnt;
+}
+
+
+
+apr_interval_time_t etch_apr_thread_pool_idle_wait_set(apr_thread_pool_t * me,
+                                  apr_interval_time_t timeout)
+{
+    apr_interval_time_t oldtime;
+
+    oldtime = me->idle_wait;
+    me->idle_wait = timeout;
+
+    return oldtime;
+}
+
+
+
+apr_size_t etch_apr_thread_pool_thread_max_get(apr_thread_pool_t *me)
+{
+    return me->thd_max;
+}
+
+
+/*
+ * This function stop extra working threads to the new limit.
+ * NOTE: There could be busy threads become idle during this function
+ */
+apr_size_t etch_apr_thread_pool_thread_max_set(apr_thread_pool_t *me,
+                                                       apr_size_t cnt)
+{
+    unsigned int n;
+
+    me->thd_max = cnt;
+    if (0 == cnt || me->thd_cnt <= cnt) {
+        return 0;
+    }
+
+    n = (unsigned) me->thd_cnt - cnt;
+    if (n >= me->idle_cnt) {
+        trim_busy_threads(me, n - me->idle_cnt);
+        trim_idle_threads(me, 0);
+    }
+    else {
+        trim_idle_threads(me, me->idle_cnt - n);
+    }
+    return n;
+}
+
+
+apr_size_t etch_apr_thread_pool_threshold_get(apr_thread_pool_t *me)
+{
+    return me->threshold;
+}
+
+
+apr_size_t etch_apr_thread_pool_threshold_set(apr_thread_pool_t *me,
+                                                      apr_size_t val)
+{
+    apr_size_t ov;
+
+    ov = me->threshold;
+    me->threshold = val;
+    return ov;
+}
+
+
+apr_status_t etch_apr_thread_pool_task_owner_get(apr_thread_t *thd,
+                                                         void **owner)
+{
+    apr_status_t rv;
+    apr_thread_pool_task_t *task;
+    void *data;
+
+    rv = apr_thread_data_get(&data, "apr_thread_pool_task", thd);
+    if (rv != APR_SUCCESS) {
+        return rv;
+    }
+
+    task = data;
+    if (!task) {
+        *owner = NULL;
+        return APR_BADARG;
+    }
+
+    *owner = task->owner;
+    return APR_SUCCESS;
+}
+
+
+/* vim: set ts=4 sw=4 et cin tw=80: */
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_arrayval.c b/binding-c/runtime/c/src/main/bindings/msg/etch_arrayval.c
new file mode 100644
index 0000000..b381b42
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_arrayval.c
@@ -0,0 +1,678 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*  
+ * etch_arrayval.c -- etch_arrayvalue implementation.
+ *
+ * todo: modify this class to permit using an etch_nativearray as the arrayvalue
+ * backing store. this could be very useful for large arrays of small values,
+ * where not all values are accessed individually. the key to this conversion  
+ * is always returning a non-disposable object from get(), and we ensure this
+ * by always returnings item[i] from the arraylist. when a get(i) is requested,
+ * we check the arraylist first, lazy-allocating it if necessary. if arraylist[i]
+ * is null, we populate arraylist[i] from natarray[i]. we then return arraylist[i]
+ * which is always non-disposable.
+ */
+
+#include "etch_arrayval.h"
+#include "etch_tagged_data.h"
+#include "etch_nativearray.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+
+etch_arrayvalue* new_arrayvalue_init(const int, const int, const int, const int);
+etch_arrayvalue* populate_arrayvalue_from(etch_arrayvalue*);
+unsigned short etch_itemtype_to_arrayclass(unsigned short item_obj_type);
+int  array_value_add(etch_arrayvalue* thisp, ETCH_ARRAY_ELEMENT* content);
+
+typedef struct etch_arrayvalue_content_wrapper {
+    etch_object object;
+    void* value;
+} etch_arrayvalue_content_wrapper;
+
+
+/**
+ * new_arrayvalue()
+ * primary constructor for etch_arrayvalue
+ * @param type_code wire ID of the array content class.
+ * @param custom_struct_type non-disposable type of custom struct, 
+   caller retains ownership as with all types.
+ */
+etch_arrayvalue* new_arrayvalue (const byte type_code, etch_type* custom_struct_type, 
+    const int dim, const int initsize, const int deltsize, 
+    const int is_readonly, const int is_synchronized)
+{
+    etch_arrayvalue* newobj = new_arrayvalue_init(initsize, deltsize, is_readonly, is_synchronized);
+
+    newobj->dim = dim;
+    newobj->type_code = type_code;
+    ((etch_object*)newobj)->class_id  = etch_arraytype_to_classid(type_code);
+
+    newobj->custom_struct_type = custom_struct_type; /* not owned */
+
+    return newobj;
+}
+
+
+/**
+ * new_arrayvalue_from()
+ * etch_arrayvalue constructor - builds arryavalue from an etch_nativearray.
+ * when native array is multi-dimensioned, this constructor is invoked recursively.
+ * todo: convert this to use the subarray call, which this code duplicates.
+ * todo: add a parameter to permit the arrayvalue to remain unpopulated; i.e.,
+ * the nativearray is present but the object array is not yet populated.
+ */
+etch_arrayvalue* new_arrayvalue_from(etch_nativearray* natarray, 
+    const signed char type_code, etch_type* custom_struct_type, 
+    const int initsize, const int deltsize, const int is_readonly)
+{
+    const int    SUBARRAY_NUMDIMS = natarray->numdims - 1;
+    const size_t SUBARRAY_COUNT   = natarray->dimension[SUBARRAY_NUMDIMS];
+    const size_t SUBARRAY_BYTELEN = natarray->dimsize  [SUBARRAY_NUMDIMS];
+
+    int i = 0;
+    etch_arrayvalue* newav = NULL;  /* nativearray currently max 3 dims*/
+    if (((etch_object*)natarray)->is_null) return NULL;
+    if (SUBARRAY_NUMDIMS < 0 || SUBARRAY_NUMDIMS > 2) return NULL;
+
+    newav = new_arrayvalue_init(initsize, deltsize, is_readonly, FALSE);
+    newav->is_array_owned  = !is_readonly;   /* does av own nativearray */
+    newav->type_code = type_code;       /* external array content type */
+    ((etch_object*)newav)->class_id  = etch_arraytype_to_classid (type_code);
+    newav->natarray  = natarray;
+    newav->dim       = natarray->numdims;
+    ((etch_object*)newav)->class_id  = ((etch_object*)natarray)->class_id;  /* validator expects class match */
+
+    newav->custom_struct_type = custom_struct_type;  /* not owned */
+
+    if  (SUBARRAY_NUMDIMS == 0) /* if single dimension, populate values */
+    {
+        
+        if(natarray->content_class_id == CLASSID_UNWRAPPED){
+            arrayvalue_set_static_content(newav, FALSE);
+        }
+        else{
+            arrayvalue_set_static_content(newav, TRUE);
+        }
+        newav = populate_arrayvalue_from(newav);
+    }
+    else 
+    {   newav->content_obj_type  = ETCHTYPEB_ARRAYVAL;
+        newav->content_item_size = sizeof(void*);
+        arrayvalue_set_static_content(newav, FALSE);
+
+        for(; i < (const int) SUBARRAY_COUNT; i++)      
+        {
+            /* the native array was multi-dimensioned. we therefore add values    
+             * to this arrayvalue, which are arrayalues of one dimension less than
+             * that of the parent arrayvalue. the sub-arrayvalues are created from 
+             * etch_nativearrays created from offset pointers into the parent
+             * native array byte vector. sub-arrays therefore do not own content.
+             */
+            const int itemcount = (int) natarray->dimension[SUBARRAY_NUMDIMS-1];
+            const size_t vector_offset = i * SUBARRAY_BYTELEN;
+            byte* subvector = (byte*) natarray->values + vector_offset;
+            etch_arrayvalue* subav = NULL;
+
+            /* create a sub-array. note we pass a possibly unused dimension   
+             * value in order to avoid the extra logic to not do so */
+            etch_nativearray* newarray = new_etch_nativearray_from(subvector, ((etch_object*)natarray)->class_id, 
+                natarray->itemsize, SUBARRAY_NUMDIMS,  
+                (int) natarray->dimension[0], (int) natarray->dimension[1], 0);
+
+            newarray->content_class_id  = natarray->content_class_id;
+            newarray->content_obj_type  = natarray->content_obj_type;
+            newarray->is_content_owned  = FALSE; /* pointer into parent vector */
+            newarray->counts[0] = newarray->counts[0];  /* move counts in case */
+            newarray->counts[1] = newarray->counts[1]; /* caller is using them */
+            newarray->counts[2] = 0;
+           
+            subav = new_arrayvalue_from  /* recursively create a sub-arrayvalue */
+                (newarray, type_code, custom_struct_type, itemcount, 0, is_readonly);
+            subav->is_array_owned = TRUE;
+            arrayvalue_add(newav, (ETCH_ARRAY_ELEMENT*) subav); 
+        }
+    }
+
+    return newav;
+}
+
+
+/**
+ * new_arrayvalue_default()
+ * default constructor for etch_arrayvalue
+ */
+etch_arrayvalue* new_arrayvalue_default ()
+{
+    etch_arrayvalue* newobj = new_arrayvalue_init
+        (ETCH_ARRAYVALUE_DEFAULT_INITSIZE, 
+         ETCH_ARRAYVALUE_DEFAULT_DELTSIZE, 
+         ETCH_ARRAYVALUE_DEFAULT_READONLY,
+         ETCH_ARRAYVALUE_DEFAULT_SYNCHRONIZED);
+
+    return newobj;
+}
+
+/**
+ * destroy_array_value()
+ * destructor for an etch_arrayvalue object
+ */
+int destroy_arrayvalue (void* data)
+{
+    etch_arrayvalue* thisp = (etch_arrayvalue*)data;
+
+    if (!is_etchobj_static_content(thisp))
+    {
+        if (thisp->natarray && thisp->is_array_owned) 
+            etch_object_destroy(thisp->natarray);
+
+        etch_object_destroy(thisp->list);
+    }
+
+    destroy_objectex((etch_object*)thisp);
+    return 0;
+}
+
+
+void* clone_etch_arrayvalue(void* data)
+{
+  etch_arrayvalue* other = (etch_arrayvalue*)data;
+    etch_arrayvalue* newarray = NULL;
+    if(other == NULL) 
+        return NULL;
+
+    newarray = new_arrayvalue(other->type_code,other->custom_struct_type,other->dim,2,2,TRUE,FALSE);
+    
+    etch_object_destroy(newarray->list);
+
+
+    newarray->list = new_etch_arraylist_from(other->list);
+    newarray->list->is_readonly = 1;
+
+    return newarray;
+}
+
+
+/**
+ * new_arrayvalue_init() 
+ * common initialization on etch_arrayvalue construction.
+ */
+etch_arrayvalue* new_arrayvalue_init (const int initsize, const int deltsize, 
+    const int is_readonly, const int is_synchronized)
+{
+    etch_arrayvalue* newobj = (etch_arrayvalue*) new_object(sizeof(etch_arrayvalue), 
+         ETCHTYPEB_ARRAYVAL, CLASSID_ARRAYVALUE);
+
+    ((etch_object*)newobj)->destroy = destroy_arrayvalue;
+    ((etch_object*)newobj)->clone   = clone_etch_arrayvalue;
+
+    /* the underlying arraylist is marked as content type object, meaning we can
+     * interpret content as etchobject and call methods on the object accordingly,
+     * most notably destroy(). when is_readonly is true, the underlying list will
+     * not free memory for its content when the list is destroyed.
+     */
+    newobj->list = new_arrayvalue_arraylist(initsize, deltsize, is_readonly, is_synchronized);  
+
+    return newobj;
+}
+
+
+
+/** 
+ * populate_arrayvalue_from()
+ * populate the specified arrayvalue from its attached single-dimensioned native array
+ */
+etch_arrayvalue* populate_arrayvalue_from (etch_arrayvalue* av)  
+{
+    etch_nativearray* nat = av->natarray;
+    const int numentries  = (int) nat->dimension[0];
+    etch_object* wrapped_value = NULL;
+    int i = 0, result = 0;
+    if (nat->numdims != 1) return NULL;
+
+    /* TODO: check itemsize if this is always the size of the real element size */
+    av->content_obj_type  = nat->content_obj_type;
+    av->content_item_size = (short) nat->itemsize;
+
+    for(; i < numentries; i++) {
+        result = etch_nativearray_get_wrapped_component(nat, i, &wrapped_value);
+        arrayvalue_add(av, (ETCH_ARRAY_ELEMENT*) wrapped_value); 
+    }
+
+    return av;
+}
+
+
+/**
+ * arrayvalue3_to_nativearray()
+ * convert an arrayvalue of dimension 3 to a native array. assumes that an
+ * appropriately sized and configured etch_nativearray object is resident in
+ * the arrayvalue object.
+ */
+int arrayvalue3_to_nativearray(etch_arrayvalue* av2)
+{
+    const int item2count = arrayvalue_count(av2);
+    int item1count = 0, item0count = 0;
+    etch_nativearray* natv = av2->natarray;
+    etch_arrayvalue_content_wrapper* wrapper = NULL;
+    etch_arrayvalue *av1 = NULL, *av0 = NULL;
+    int i, j, k, items=0; 
+
+    for(i=0; i < item2count; i++)
+    {    
+        av1 = arrayvalue_get(av2, i);
+        if (!is_etch_arrayvalue(av1)) return -1; 
+        item1count = arrayvalue_count(av1);
+
+        for(j=0; j < (const int) item1count; j++)
+        {   
+            av0 = arrayvalue_get(av1, j);
+            if (!is_etch_arrayvalue(av0)) return -1; 
+            item0count = arrayvalue_count(av0);
+
+            for(k=0; k < (const int) item0count; k++)
+            {  /* insert native values into nativearray byte vector. we mask the
+                * wrapped primitive with an etch_object. we can do so because the
+                * etch primitive object is guaranteed to offset its value the
+                * same as that of an etch_object, right after the object header. 
+                */ 
+                if (NULL == (wrapper = arrayvalue_get(av0, k))) return -1;
+                if (0 == natv->put3(natv, &wrapper->value, i, j, k))
+                    items++;
+                else return -1;
+            }   
+        }    
+    }    
+
+    return items;
+}
+
+
+/**
+ * arrayvalue2_to_nativearray()
+ * convert an arrayvalue of dimension 2 to a native array. assumes that an
+ * appropriately sized and configured etch_nativearray object is resident in
+ * the arrayvalue object.
+ */
+int arrayvalue2_to_nativearray(etch_arrayvalue* av1)
+{
+    const int item1count = arrayvalue_count(av1);
+    int item0count = 0;
+    etch_nativearray* natv = av1->natarray;
+    etch_arrayvalue_content_wrapper* wrapper = NULL;
+    etch_arrayvalue *av0 = NULL;
+    int i, j, items=0; 
+
+    for(i = 0; i < item1count; i++)
+    {    
+        av0 = arrayvalue_get(av1, i);
+        if (!is_etch_arrayvalue(av0)) return -1; 
+        item0count = arrayvalue_count(av0);
+
+        for(j = 0; j < (const int) item0count; j++)
+        {   /* insert native values into nativearray byte vector. we mask the
+             * wrapped primitive with an etch_object. we can do so because the
+             * etch primitive object is guaranteed to offset its value the
+             * same as that of an etch_object, right after the object header. 
+             */ 
+            if (NULL == (wrapper = arrayvalue_get(av0, j))) return -1;
+            if (0 == natv->put2(natv, &wrapper->value, i, j))
+                items++;
+            else return -1;        
+        }   
+    }    
+
+    return items;
+}
+
+
+/**
+ * arrayvalue1_to_nativearray()
+ * convert an arrayvalue of dimension 1 to a native array. assumes that an
+ * appropriately sized and configured etch_nativearray object is resident in
+ * the arrayvalue object.
+ */
+int arrayvalue1_to_nativearray(etch_arrayvalue* av)
+{
+    const int itemcount = arrayvalue_count(av);
+    etch_nativearray* natv = av->natarray;
+    etch_arrayvalue_content_wrapper* wrapper = NULL;
+    int i=0, items = 0;  
+   
+    for(; i < itemcount; i++)
+    {   /* insert native values into nativearray byte vector. we mask the
+         * wrapped primitive with an etch_object. we can do so because the
+         * etch primitive object is guaranteed to offset its value the
+         * same as that of an etch_object, right after the object header. 
+         */ 
+        if (NULL == (wrapper = arrayvalue_get(av, i))) return -1;
+        if (0 == natv->put1(natv, &wrapper->value, i))
+            items++;
+        else return -1;    
+    }
+
+    return items;
+}
+
+
+/**
+ * arrayvalue_to_nativearray()
+ * convert an arrayvalue to a native array
+ * if the arrayvalue is created from a native array, the source native array is
+ * still resident, however this method assumes we want to create the native array
+ * regardless of whether one is resident. is also assumes that if we have created
+ * the arrayvalue from scratch, we have done so properly, i.e., a multi-dimensioned
+ * arrayvalue is and arrayvalue of arrayvalues. It additionally assumes that the
+ * arrayvalue is populated with at least one value; if this were not the case we  
+ * would need to switch on the byte type_code to determine the item size.
+ */
+int arrayvalue_to_nativearray (etch_arrayvalue* av)
+{
+    int dim0count=0, dim1count=0, dim2count=0, itemsize=0;
+    etch_arrayvalue *av2 = NULL, *av1 = NULL, *av0 = NULL;
+    unsigned short array_class_id = 0;
+    etch_nativearray* newna = NULL;
+    const int dimensions = av->dim;
+
+    switch(dimensions)  /* determine native array size */
+    {   case 1:
+            av0 = av;
+            break;
+
+        case 2:
+            dim1count = arrayvalue_count(av);
+            av1 = (etch_arrayvalue*) arrayvalue_get(av, 0);
+            if (is_etch_arrayvalue(av1)) 
+                av0 = av1;
+            break;
+
+        case 3:
+            dim2count = arrayvalue_count(av);
+            av2 = (etch_arrayvalue*) arrayvalue_get(av, 0);
+            if (!is_etch_arrayvalue(av2)) break;
+
+            dim1count = arrayvalue_count(av2);
+            av1 = (etch_arrayvalue*) arrayvalue_get(av2, 0);
+            if (is_etch_arrayvalue(av1)) 
+                av0 = av1;
+    }
+
+    if (av0) /* if arrayvalue was populated ... */
+    {   itemsize  = av0->content_item_size;
+        dim0count = arrayvalue_count(av0);
+        if(av0->content_class_id == CLASSID_UNWRAPPED){
+           array_class_id = CLASSID_UNWRAPPED;
+        }else{
+           array_class_id = etch_itemtype_to_arrayclass(av0->content_obj_type);
+        }
+    }
+
+    if (dim0count == 0 || itemsize == 0) 
+        return NULL;  /* bad arrayvalue */
+
+    newna = new_etch_nativearray  /* allocate appropriately sized native array */
+       (array_class_id, itemsize, dimensions, dim0count, dim1count, dim2count);
+    if (NULL == newna) return NULL;
+
+    /* if previous native array was attached to the arrayvalue, free it */
+    etch_object_destroy(av->natarray);
+
+    av->natarray = newna;  /* attach new native array to its arrayvalue */
+
+    switch(dimensions)    /* populate new native array from array value */
+    {   case 1: return arrayvalue1_to_nativearray(av);
+        case 2: return arrayvalue2_to_nativearray(av);  
+        case 3: return arrayvalue3_to_nativearray(av);  
+    }
+
+    return NULL;
+}
+
+
+/**
+ * arrayvalue_add()
+ * returns 0 or -1
+ */
+int arrayvalue_add (etch_arrayvalue* av, ETCH_ARRAY_ELEMENT* content)
+{
+    const int result = etch_arraylist_add(av->list, content);
+    return result;
+}
+
+
+/**
+ * array_value_add()
+ * returns 0 or -1
+ */
+int array_value_add (etch_arrayvalue* av, ETCH_ARRAY_ELEMENT* content)
+{
+    const int result = etch_arraylist_add(av->list, content);
+    return result;
+}
+
+
+/**
+ * arrayvalue_get()
+ * return item at specified index
+ * returns array item, always an address, or NULL.
+ */
+void* arrayvalue_get (etch_arrayvalue* thisp, const int i) 
+{
+    return etch_arraylist_get(thisp->list, i);
+}
+
+
+/**
+ * arrayvalue_count()
+ * return item count
+ */
+int arrayvalue_count (etch_arrayvalue* thisp)
+{
+    return thisp? thisp->list? thisp->list->count: 0: 0;
+}
+
+
+/**
+ * new_arrayvalue_arraylist()
+ * allocates and returns an arraylist configured appropriately for use as arrayvalue backing store
+ */
+etch_arraylist* new_arrayvalue_arraylist (const int initsize, const int deltsize, 
+    const int is_readonly, const int is_synchronized)
+{
+    etch_arraylist* list = is_synchronized? 
+        new_etch_arraylist_synchronized(initsize, deltsize):
+        new_etch_arraylist(initsize, deltsize);
+
+    list->is_readonly = is_readonly != 0;  
+    list->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
+    return list;
+}
+
+
+static const signed char etch_primitive_typecodes[11] 
+ = {ETCH_XTRNL_TYPECODE_CUSTOM,       /* CLASSID_ARRAY_OBJECT */
+    ETCH_XTRNL_TYPECODE_BYTE,         /* CLASSID_ARRAY_BYTE   */
+    ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE, /* CLASSID_ARRAY_BOOL   */
+    ETCH_XTRNL_TYPECODE_BYTE,         /* CLASSID_ARRAY_BYTE   */
+    ETCH_XTRNL_TYPECODE_SHORT,        /* CLASSID_ARRAY_INT16  */
+    ETCH_XTRNL_TYPECODE_INT,          /* CLASSID_ARRAY_INT32  */
+    ETCH_XTRNL_TYPECODE_LONG,         /* CLASSID_ARRAY_INT64  */
+    ETCH_XTRNL_TYPECODE_FLOAT,        /* CLASSID_ARRAY_FLOAT  */
+    ETCH_XTRNL_TYPECODE_DOUBLE,       /* CLASSID_ARRAY_DOUBLE */
+    ETCH_XTRNL_TYPECODE_STRING,       /* CLASSID_ARRAY_STRING */
+    0,        
+   };
+
+static const unsigned short etch_arrayval_classids[11] 
+ = {CLASSID_ARRAY_OBJECT,       /* ETCH_XTRNL_TYPECODE_CUSTOM */
+    CLASSID_ARRAY_BYTE,         /* ETCH_XTRNL_TYPECODE_BYTE   */
+    CLASSID_ARRAY_BOOL,         /* ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE */
+    CLASSID_ARRAY_BYTE,         /* ETCH_XTRNL_TYPECODE_BYTE   */
+    CLASSID_ARRAY_INT16,        /* ETCH_XTRNL_TYPECODE_SHORT  */
+    CLASSID_ARRAY_INT32,        /* ETCH_XTRNL_TYPECODE_INT    */
+    CLASSID_ARRAY_INT64,        /* ETCH_XTRNL_TYPECODE_LONG   */
+    CLASSID_ARRAY_FLOAT,        /* ETCH_XTRNL_TYPECODE_FLOAT  */
+    CLASSID_ARRAY_DOUBLE,       /* ETCH_XTRNL_TYPECODE_DOUBLE */
+    CLASSID_ARRAY_STRING,       /* ETCH_XTRNL_TYPECODE_STRING */
+    0,
+   };
+
+
+/**
+ * etch_arraytype_to_classid()
+ * returns array class ID corresponding to serialization byte code.
+ */
+unsigned short etch_arraytype_to_classid (const signed char typecode)
+{
+    int i = 0;
+    unsigned short idout = 0;
+    signed char* p = (signed char*) etch_primitive_typecodes;
+
+    for(; *p; i++, p++)
+        if (*p == typecode)
+        {   idout = etch_arrayval_classids[i];
+            break;
+        }
+
+    return idout;
+}
+
+
+/**
+ * etch_classid_to_arraytype()
+ * returns serialization bytecode corresponding to array class ID
+ */
+signed char etch_classid_to_arraytype (const unsigned short class_id)
+{
+    int i = 0;
+    signed char typecodeout = 0;
+    unsigned short* p = (unsigned short*) etch_arrayval_classids;
+
+    for(; *p; i++, p++)
+        if (*p == class_id)
+        {   typecodeout = etch_primitive_typecodes[i];
+            break;
+        }
+
+    return typecodeout;
+}
+
+
+/**
+ * etch_itemtype_to_arrayclass()
+ * returns array object type corresponding to item object type 
+ */
+unsigned short etch_itemtype_to_arrayclass(unsigned short item_obj_type)
+{ 
+    if  (item_obj_type > 0 && item_obj_type <= ETCHTYPEB_STRING) 
+         return etch_arrayval_classids[item_obj_type]; 
+    else return CLASSID_ARRAY_OBJECT;
+}
+
+
+/**
+ * arrayvalue_get_external_typecode() 
+ * returns an array type bytecode for the specified array content type.
+ */
+signed char arrayvalue_get_external_typecode (unsigned short obj_type, unsigned short class_id)
+{
+    signed char xtype = 0;
+
+    #if(0) /* uncompiled arrays are here for documentation purposes */
+
+    unsigned short primitive_class_ids[] =
+    {   CLASSID_ANY,             /* 0x0 */              
+        CLASSID_PRIMITIVE_BYTE,  /* 0x1 */
+        CLASSID_PRIMITIVE_BOOL,  /* 0x2 */
+        CLASSID_PRIMITIVE_INT8,  /* 0x3 */
+        CLASSID_PRIMITIVE_INT16, /* 0x4 */
+        CLASSID_PRIMITIVE_INT32, /* 0x5 */
+        CLASSID_PRIMITIVE_INT64, /* 0x6 */
+        CLASSID_PRIMITIVE_FLOAT, /* 0x7 */
+        CLASSID_PRIMITIVE_DOUBLE,/* 0x8 */
+        CLASSID_STRING,          /* 0x9 */
+    };
+
+    unsigned short primitive_obj_types[] =
+    {   ETCHTYPEB_UNDEFINED, /* 0x0 */   
+        ETCHTYPEB_BYTE,      /* 0x1 */
+        ETCHTYPEB_BOOL,      /* 0x2 */  
+        ETCHTYPEB_INT8,      /* 0x3 */    
+        ETCHTYPEB_INT16,     /* 0x4 */     
+        ETCHTYPEB_INT32,     /* 0x5 */  
+        ETCHTYPEB_INT64,     /* 0x6 */   
+        ETCHTYPEB_IEEE32,    /* 0x7 */  
+        ETCHTYPEB_IEEE64,    /* 0x8 */      
+        ETCHTYPEB_STRING,    /* 0x9 */     
+    };
+
+    #endif
+
+    if (obj_type == ETCHTYPEB_PRIMITIVE)
+    {   if (class_id < 1 || class_id > 9)
+            class_id = 0;
+
+        xtype = etch_primitive_typecodes [class_id];
+    }    
+    else /* primitive obj_type? */
+    if (obj_type > 0 && obj_type <= 9)
+        xtype = etch_primitive_typecodes [obj_type];
+
+    else switch(obj_type)
+    {   case ETCHTYPEB_STRUCTVAL:   xtype = ETCH_XTRNL_TYPECODE_CUSTOM; break; 
+        case ETCHTYPEB_ARRAYVAL:    xtype = ETCH_XTRNL_TYPECODE_ARRAY;  break;
+        case ETCHTYPEB_NATIVEARRAY: xtype = ETCH_XTRNL_TYPECODE_ARRAY;  break;
+        default: xtype = ETCH_XTRNL_TYPECODE_CUSTOM;   
+    }
+    
+    return xtype;
+}
+
+
+/* 
+ * arrayvalue_set_static_content()
+ * configure arraylist of object wrappers such that objects are not freed by the arraylist
+ * destructor. presumably this would be used during recursive access to arrayvalue, where
+ * lowest level objects are seen and destroyed prior to higher level objects such as the
+ * array wrappers. 
+ */
+void arrayvalue_set_static_content (etch_arrayvalue* av, const int is_set)
+{
+    etch_arraylist* list = av? av->list: NULL;
+    if (list) list->is_readonly = is_set? TRUE: FALSE;
+}
+
+
+/* 
+ * arrayvalue_set_iterator()
+ * set an iterator on the arrayvalue, which becomes an iterator on its list
+ */
+int arrayvalue_set_iterator (etch_arrayvalue* av, etch_iterator* iterator)
+{
+    int rv = 0;
+    if(av == NULL || iterator == NULL) {
+        return -1;
+    }
+    if(av->list == NULL) {
+        return -1;
+    }
+
+    rv = set_iterator (iterator, av->list, &av->list->iterable);
+    return rv;
+}
+
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_binary_tdi.c b/binding-c/runtime/c/src/main/bindings/msg/etch_binary_tdi.c
new file mode 100644
index 0000000..6a22c72
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_binary_tdi.c
@@ -0,0 +1,1205 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*  
+ * etch_binary_tdi.c -- binary tagged data input implementation.
+ */
+
+#include "etch_binary_tdi.h"
+#include "etch_cache.h"
+#include "etch_structval.h"
+#include "etch_arrayval.h"
+#include "etch_tagged_data.h"
+#include "etch_default_value_factory.h"
+#include "etch_encoding.h"
+#include "etch_exception.h"
+#include "etch_nativearray.h"
+#include "etch_log.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+
+static const char* LOG_CATEGORY =  "etch_binary_tdi";
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * private method signatures
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+i_binary_tdi* new_binarytdi_vtable();
+
+etch_message* bintdi_start_message (tagged_data_input*);
+int bintdi_end_message (tagged_data_input*, etch_message*);
+etch_message* bintdi_read_message(tagged_data_input*, etch_flexbuffer*);
+
+etch_structvalue* bintdi_start_struct(tagged_data_input*);
+etch_structvalue* bintdi_read_struct (tagged_data_input*);
+int bintdi_end_struct  (tagged_data_input*, etch_structvalue*);
+
+etch_arrayvalue*  bintdi_start_array(tagged_data_input*);
+etch_arrayvalue*  bintdi_read_array (tagged_data_input*, etch_validator*);    
+int bintdi_end_array(tagged_data_input*, etch_arrayvalue*);
+
+etch_arrayvalue*  bintdi_alloc_array(tagged_data_input*, const byte array_content_type,
+     etch_type* custom_type, const int ndims, const int nelements);
+
+int  bintdi_read_keys_values(binary_tagged_data_input*, etch_structvalue*);
+int  bintdi_read_values(binary_tagged_data_input*, etch_arrayvalue*, etch_validator*);
+etch_object* bintdi_read_value (binary_tagged_data_input*, etch_validator*);
+etch_object* bintdi_read_valuex(binary_tagged_data_input*, etch_validator*, boolean);
+etch_type*   bintdi_get_custom_structtype(etch_object*, 
+     const unsigned short, const unsigned short);
+etch_type*   bintdi_read_type(binary_tagged_data_input*);
+etch_int32*  bintdi_read_intvalue(binary_tagged_data_input*);
+int  bintdi_read_value_rawint(binary_tagged_data_input* tdi, int* out);
+
+etch_validator* bintdi_get_validator_for(binary_tagged_data_input* tdi, etch_field* field);
+etch_object* bintdi_validate_value(binary_tagged_data_input*, 
+    etch_validator*, boolean is_none_ok, etch_object*);
+etch_object* bintdi_validate_valuex(binary_tagged_data_input*, 
+    etch_validator*, boolean is_none_ok, etch_object*);
+
+int  bintdi_get_native_type(const signed char external_typecode, etch_array_id_params* out); 
+int  bintdi_get_component_type(tagged_data_input*, const byte array_content_type,
+     etch_type* custom_type, const int dims, etch_array_id_params* out);
+signed char bintagdata_get_native_typecode(const unsigned short, const unsigned short);
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * constructors/destructors
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+
+/**
+ * destroy_binary_tagged_data_input()
+ */
+int destroy_binary_tagged_data_input(void* data)
+{
+    binary_tagged_data_input* tdi = (binary_tagged_data_input*)data;
+
+    if (!is_etchobj_static_content(tdi))
+        etch_object_destroy(tdi->impl);
+
+    /* destroy private instance data */
+    etch_free(tdi->static_nullobj);
+    etch_free(tdi->static_eodmarker);
+    clear_etchobj_static_all(tdi->static_emptystring);
+    etch_object_destroy(tdi->static_emptystring);
+     
+    return destroy_objectex((etch_object*)tdi);
+}
+
+
+/**
+ * clone_tagged_data_input()
+ * tdi copy constructor. if the tdi object implements a separate instance data
+ * object, that object is cloned as well. 
+ */
+void* clone_binary_tagged_data_input(void* data)
+{
+  binary_tagged_data_input* tdi = (binary_tagged_data_input*)data;
+    binary_tagged_data_input* newtdi = (binary_tagged_data_input*) clone_object((etch_object*) tdi);
+    newtdi->impl = tdi->impl?  tdi->impl->clone(tdi->impl): NULL;
+    return newtdi;
+}
+
+
+/**
+ * new_binary_tagdata_input()
+ * binary_tagged_data_input constructor 
+ */
+binary_tagged_data_input* new_binary_tagdata_input(etch_value_factory* vf)
+{
+    i_binary_tdi* vtab = NULL;
+
+    binary_tagged_data_input* tdi = (binary_tagged_data_input*) new_object
+       (sizeof(binary_tagged_data_input), ETCHTYPEB_BINARYTDI, CLASSID_BINARYTDI);
+
+    ((etch_object*)tdi)->destroy = destroy_binary_tagged_data_input;
+    ((etch_object*)tdi)->clone   = clone_binary_tagged_data_input;
+    tdi->vf = vf;
+
+    vtab = etch_cache_find(get_vtable_cachehkey(CLASSID_BINARYTDI_VTAB), 0);
+
+    if(!vtab)  
+    {   vtab = new_binarytdi_vtable();
+        etch_cache_insert(((etch_object*)vtab)->get_hashkey(vtab), vtab, FALSE);
+    } 
+ 
+    ((etch_object*)tdi)->vtab = (vtabmask*)vtab;  
+    tdi->vtor_int = etchvtor_int32_get(0); 
+    tdi->static_nullobj     = etchtagdata_new_nullobj(TRUE);
+    tdi->static_eodmarker   = etchtagdata_new_eodmarker(TRUE);
+    tdi->static_emptystring = etchtagdata_new_emptystring(TRUE);
+    return tdi; 
+}
+
+
+/**
+ * new_binary_tdi()
+ * casts result to generic tdi for use by interfaces
+ */
+tagged_data_input* new_binary_tdi(etch_value_factory* vf)
+{
+    return (tagged_data_input*) new_binary_tagdata_input(vf);
+}
+
+
+
+
+/**
+ * new_new_binarytdi_vtable()
+ * constructor for binary tdi virtual function table
+ */
+i_binary_tdi* new_binarytdi_vtable()
+{
+    etchparentinfo* inheritlist = new_etch_inheritance_list(3, 2, NULL); 
+   
+    i_binary_tdi* vtab 
+        = new_vtable(NULL, sizeof(i_binary_tdi), CLASSID_BINARYTDI_VTAB);
+
+    /* i_tagged_data_input */
+    vtab->start_message = bintdi_start_message;
+    vtab->read_message  = bintdi_read_message;
+    vtab->end_message   = bintdi_end_message;
+    vtab->start_struct  = bintdi_start_struct;
+    vtab->read_struct   = bintdi_read_struct;
+    vtab->end_struct    = bintdi_end_struct;
+    vtab->start_array   = bintdi_start_array;
+    vtab->read_array    = bintdi_read_array;
+    vtab->end_array     = bintdi_end_array;
+
+    /* i_tagdata */
+    vtab->check_value = etchtagdata_check_value;
+    vtab->get_native_type = bintdi_get_native_type;
+    vtab->get_native_type_code  = bintagdata_get_native_typecode;
+    vtab->get_custom_structtype = bintdi_get_custom_structtype;
+
+    /* inheritance */
+    inheritlist[1].o.obj_type = ETCHTYPEB_TAGDATAINP;
+    inheritlist[1].c.class_id = CLASSID_TAGDATAINP;
+    inheritlist[2].o.obj_type = ETCHTYPEB_TAGDATA;
+    inheritlist[2].c.class_id = CLASSID_TAGDATA;
+
+    vtab->inherits_from = inheritlist;
+
+    return vtab;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * read message
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * bintdi_start_message()
+ * starts reading a message from the stream.
+ * returns NULL if the wire data was insufficient to construct a  
+ * message object, otherwise returns the new message object,
+ * of the type read off the wire herein.
+ */
+etch_message* bintdi_start_message(tagged_data_input* tdix)
+{
+    binary_tagged_data_input* tdi = (binary_tagged_data_input*) tdix;
+    etch_type*  typeobj   = NULL; /* not owned here */
+    etch_message* newmsg  = NULL; /* disposable, returned */
+    int message_itemcount = 0, result = 0;
+    byte wire_version = 0;
+
+    do 
+    {   result = etch_flexbuf_get_byte (tdi->flexbuf, &wire_version);
+
+        if (wire_version != ETCH_BINTAGDATA_CURRENT_VERSION) 
+        {   
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR,"message version expected %d found %d", ETCH_BINTAGDATA_CURRENT_VERSION, wire_version);
+            break;
+        }
+
+        /* bintdi_read_type returns us a non-disposable reference to a global type,     
+         * which we then give to the new message, which does not own its type. 
+         */
+        if (NULL == (typeobj = bintdi_read_type (tdi))) break;
+
+        if (-1 != bintdi_read_value_rawint (tdi, &message_itemcount))
+            newmsg = new_message(typeobj, message_itemcount, tdi->vf);
+
+    } while(0);
+
+    if(newmsg) {
+         ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "message receive starts\n"); 
+    }
+    else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "error starting message receive\n"); 
+    }
+    return newmsg;
+}
+
+
+/**
+ * bintdi_end_message()
+ * end message deserialization
+ */
+int bintdi_end_message(tagged_data_input* tdi, etch_message* msg)
+{
+    int result = 0;
+    /* if the newly-deserialized message is not a reply message, 
+     * there is nothing to do here, since bintdi_read_keys_values() 
+     * already read the eod marker. if it is a reply message, and
+     * if the message contains an exception, we will ensure that the 
+     * message result object both exists and reflects that exception.
+     */
+
+    if (message_get_in_reply_to (msg))  
+    {
+        etch_field* xkey = builtins._mf_msg;
+        /* look for an exception in the newly-deserialized message */
+        etch_exception* excpobj = (etch_exception*) message_get (msg, xkey);
+
+        if (is_etch_exception(excpobj))
+        {   /* look for a result object in the message */
+            etch_field* resobj_key = builtins._mf_result;
+            etch_object* resobj = message_get (msg, resobj_key);
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "exception found in message\n"); 
+            //replace result with exception object
+            //TODO memory leak here? (resobj not destroyed, should we?)
+            resobj = ((etch_object*)excpobj)->clone(excpobj);
+            result = message_put (msg, resobj_key, resobj); 
+        }
+    }
+
+    return result; 
+}
+
+
+/**
+ * bintdi_read_message() 
+ * "non-static" read message version, accepts a tdi
+ */
+etch_message* bintdi_read_message (tagged_data_input* tdix, etch_flexbuffer* fbuf)
+{
+    etch_message* newmsg = NULL;
+    binary_tagged_data_input* tdi = (binary_tagged_data_input*) tdix;
+    tdi->flexbuf = fbuf;
+
+    if (NULL == (newmsg = bintdi_start_message(tdix)))
+        return NULL;
+
+    /* todo verify that this deserialization failure is eventually session_notify'ed */ 
+    if (-1 == bintdi_read_keys_values (tdi, newmsg->sv)) {   
+        etch_object_destroy(newmsg);
+        return NULL; 
+    }
+
+    bintdi_end_message(tdix, newmsg);
+    return newmsg;
+} 
+
+
+/**
+ * bintdi_read_message_fromf() 
+ * reads a message from the supplied flex buffer           
+ */
+etch_message* bintdi_read_message_fromf (etch_value_factory* vf, etch_flexbuffer* fbuf)
+{
+    binary_tagged_data_input* tdi = new_binary_tagdata_input(vf);
+
+    return bintdi_read_message((tagged_data_input*) tdi, fbuf);
+} 
+
+
+/**
+ * bintdi_read_message_from() 
+ * reads a message from the supplied data buffer           
+ */
+etch_message* bintdi_read_message_from (etch_value_factory* vf, byte* buf, 
+    const int bufsize)
+{
+    etch_flexbuffer* fbuf = new_flexbuffer_from(buf, bufsize, bufsize, 0);
+
+    return bintdi_read_message_fromf(vf, fbuf);
+} 
+
+
+/**
+ * bintdi_read_message_fromo() 
+ * reads a message from the supplied data buffer, at the specified offset           
+ */
+etch_message* bintdi_read_message_fromo (etch_value_factory* vf, byte* buf, 
+    const int bufsize, const int msglen, const int offset)
+{
+    etch_flexbuffer* fbuf = new_flexbuffer_from(buf, bufsize, msglen, offset);
+
+    return bintdi_read_message_fromf(vf, fbuf);
+} 
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * read struct
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * bintdi_start_struct()
+ * starts reading a struct from the stream.
+ */
+etch_structvalue* bintdi_start_struct(tagged_data_input* tdix)
+{
+    binary_tagged_data_input* tdi = (binary_tagged_data_input*) tdix; 
+    etch_structvalue* newsv = NULL;
+    etch_type* thistype = NULL;
+    int struct_itemcount = 0;
+
+    /* bintdi_read_type returns us a non-disposable reference to a global type, 
+     * which we then give to the new structvalue, which does not own its type. 
+     */
+    if (NULL == (thistype = bintdi_read_type(tdi))) {
+        return NULL;
+    }
+
+    if (-1 != bintdi_read_value_rawint(tdi, &struct_itemcount))
+        newsv = new_structvalue(thistype, struct_itemcount);
+
+    return newsv;
+}
+
+
+/**                              
+ * bintdi_end_struct()
+ * does nothing since read_keys_values read to end of stream 
+ */
+int bintdi_end_struct(tagged_data_input* tdi, etch_structvalue* sv)
+{
+    return 0;  
+}
+
+
+/**
+ * bintdi_read_struct()
+ * read a struct out of the buffer, create and return a new struct value 
+ */
+etch_structvalue* bintdi_read_struct(tagged_data_input* tdix)
+{
+    binary_tagged_data_input* tdi = (binary_tagged_data_input*) tdix;
+    etch_structvalue* newsv = NULL;
+
+    newsv = ((struct i_binary_tdi*)((etch_object*)tdi)->vtab)->start_struct((tagged_data_input*) tdi);
+    if(newsv){
+        if (-1 == bintdi_read_keys_values(tdi, newsv)) {   
+            etch_object_destroy(newsv);
+            newsv = NULL;
+        }else  
+        {
+            bintdi_end_struct(tdix, newsv);
+        }
+    }
+    return newsv;
+} 
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * read array
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * bintdi_start_array()
+ */
+etch_arrayvalue* bintdi_start_array(tagged_data_input* tdix)
+{
+    etch_type*  custom_type = NULL;    /* not owned here */
+    etch_arrayvalue* arrayval = NULL;  /* owned by caller */
+    binary_tagged_data_input* tdi = (binary_tagged_data_input*) tdix;
+    int numdimensions = 0, numelements = 0, result = 0;
+    byte array_content_type = 0;
+
+    result = etch_flexbuf_get_byte(tdi->flexbuf, &array_content_type);
+
+    switch((signed char)array_content_type)
+    { case ETCH_XTRNL_TYPECODE_CUSTOM:
+      case ETCH_XTRNL_TYPECODE_STRUCT:
+           /* bintdi_read_type returns a non-disposable type reference */
+           custom_type = bintdi_read_type(tdi);   
+           if (NULL == custom_type) return NULL;
+    }
+   
+    bintdi_read_value_rawint(tdi, &numdimensions);
+    bintdi_read_value_rawint(tdi, &numelements);
+
+    if(numdimensions <= 0 || numelements < 0){
+        return NULL;
+    }
+
+    /* create the arrayvalue. we pass no memory ownership here */
+    arrayval = bintdi_alloc_array(tdix, array_content_type, custom_type, numdimensions, numelements);
+    return arrayval;
+}
+
+
+/**
+ * bintdi_end_array()
+ * ends array in progress
+ */
+int bintdi_end_array(tagged_data_input* tdi, etch_arrayvalue* x)
+{
+    return 0;
+}
+
+
+/**
+ * bintdi_read_array()
+ * read an array out of the buffer, create and return a new array object 
+ *
+ * todo (eventually). arrays are not optimal. following the java binding model,
+ * an array on the wire is read into an array_value. in c, this means an array
+ * of objects, one object per array element. this can make for very large data
+ * structures, 60 bytes of overhead per array element. we would like to instead
+ * use the etch_nativearray format, where an array is a blob of bytes, with
+ * attributes and methods describing how to index into the array. however
+ * it was not known if doing so would paint the c binding into a corner at 
+ * some point, so for now, we create the arrayvalue just as the java binding, 
+ * and export that structure to an etch_nativearray when and if we need it.
+ */
+etch_arrayvalue* bintdi_read_array(tagged_data_input* tdix, etch_validator* vtor)
+{
+    binary_tagged_data_input* tdi = (binary_tagged_data_input*) tdix;
+
+    etch_arrayvalue* newarray = bintdi_start_array((tagged_data_input*) tdi);
+    if (NULL == newarray) return NULL;
+                                     
+    if (-1 == bintdi_read_values(tdi, newarray, vtor)) {   
+        etch_object_destroy(newarray);
+        return NULL;
+    }
+
+    bintdi_end_array((tagged_data_input*)tdi, newarray);
+
+    return newarray;
+} 
+
+
+/**
+ * bintdi_alloc_array()
+ * allocate an arrayvalue in which to read data for the pending array.
+ * java binding allocates a native array here. we can't do that yet since we
+ * don't have the attributes of each dimension until we get the entire array
+ * out of the stream buffer, and we want to avoid lookahead if possible.
+ * @return new array object, or NULL indicating exception condition
+ */
+etch_arrayvalue* bintdi_alloc_array(tagged_data_input* tdi, const byte array_content_type,
+   etch_type* custom_type, const int ndims, const int nelements)
+{
+    etch_array_id_params arraytype;
+    etch_arrayvalue* arrayval = NULL;
+
+    if (-1 == bintdi_get_component_type(tdi, array_content_type, 
+        custom_type, ndims, &arraytype))
+        return NULL; 
+
+    /* remarks regarding ownership of content for these arrayvalue objects. 
+     * first, recall that their content is etch objects wrapping data read from  
+     * the data buffer, and that the data so wrapped is owned by the wrapper. 
+     * ownership of memory for those base data objects is assigned up the line
+     * until some object assumes responsibility. content for these arrayvalues
+     * is either those wrapper objects, at dimension[0], or arrayvalue objects
+     * at the higher dimensions. in all cases, the arryavalue owns its content,  
+     * and therefore its content will be destroyed with the arrayvalue. since  
+     * the destruction is recursive, destroying the top object destroys it all.
+     */
+    arrayval = new_arrayvalue(array_content_type, custom_type, ndims, nelements, 0, FALSE, 0);
+    if (NULL == arrayval) {
+        return NULL;
+    }
+
+    /* validator will validate array based on this class */
+    ((etch_object*)arrayval)->class_id = arraytype.array_class_id;
+
+    /* content type will be used later when we need to create a nativearray */
+    arrayval->content_obj_type = arraytype.content_obj_type;
+    arrayval->content_class_id = arraytype.content_class_id;
+    return arrayval;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - -
+ * read from stream and reconstruct objects
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * bintdi_read_intvalue()
+ * convenience method used when an encoded integer is expected next in
+ * the buffer, to read that value from the buffer and return it as an 
+ * etch_int32 object, ownership of which belongs to the caller.
+ */
+etch_int32* bintdi_read_intvalue(binary_tagged_data_input* tdi)
+{
+    return (etch_int32*) bintdi_read_value(tdi, tdi->vtor_int);
+}
+
+/**
+ * bintdi_read_bytes()
+ * read all bytes from the buffer, returning those bytes
+ * @param extra pad bytes e.g. when we are reading a string and need a null term
+ */
+byte* bintdi_read_bytes(binary_tagged_data_input* tdi, const int extra, int* psize)
+{
+    byte* buf = NULL;
+    int bytecount = 0, newbufsize = 0;
+
+    if (-1 == bintdi_read_value_rawint(tdi, &bytecount)) return NULL; 
+
+    if(bytecount >= 0 && (size_t) bytecount <= etch_flexbuf_avail(tdi->flexbuf)) {
+        newbufsize = bytecount + extra;
+        buf = etch_malloc(newbufsize, ETCHTYPEB_BYTES);
+        memset(buf, 0, newbufsize);
+        etch_flexbuf_get_fully(tdi->flexbuf, buf, bytecount);
+        if (psize) *psize = newbufsize;
+    }
+
+    return buf;
+} 
+
+
+/**
+ * bintdi_read_type()
+ * read a type ID from the buffer, map to and return the associated static type
+ */
+etch_type* bintdi_read_type(binary_tagged_data_input* tdi)
+{
+    etch_type* type = NULL;
+    int  type_id = 0;
+
+    if (0 == bintdi_read_value_rawint(tdi, &type_id))
+        type = ((struct i_value_factory*)((etch_object*)tdi->vf)->vtab)->get_type_by_id(tdi->vf, type_id);               
+
+    /* note that the type object returned by valuefactory.get_type_by_id 
+     * is not disposable, it is a reference into the global types map. 
+     * and we are returning that nondisposable reference here */
+
+    return type;
+}
+
+
+/**
+ * bintdi_read_bytearray()
+ * read all bytes from the buffer, return a native array wrapping the resultant byte array
+ * todo: is this OK to return nativearray in one case, and arrayvalue in another?
+ * can we handle the nativearray format across the board? we can at least use nativearray
+ * for byte blobs. even if we use arravalue format we should at least use nativearray
+ * as the base of the arrayvalue, since if we need to be able to access elements, we can't
+ * simply reflect to an array as does java, we need the subscripting of the nativearray.
+ */
+etch_nativearray* bintdi_read_bytearray(binary_tagged_data_input* tdi)
+{
+    int  size = 0;
+    etch_nativearray* newarray = NULL;
+    byte* buf = bintdi_read_bytes(tdi, 0, &size); /* buf is disposable, newarray will own it */
+    newarray  = new_etch_nativearray_from(buf, CLASSID_ARRAY_BYTE, sizeof(byte), 1, size, 0, 0); 
+    newarray->is_content_owned = TRUE;
+    return newarray;
+} 
+
+
+/**
+ * bintdi_read_string()
+ * read all bytes from the buffer and translate to unicode C string
+ * @return the wrapped string
+ */	
+etch_string* bintdi_read_string(binary_tagged_data_input* tdi)
+{
+    int result = 0, size = 0;
+    wchar_t* widestring = NULL;
+    etch_string* newstr = NULL;
+    byte* buf = NULL;
+
+    const int configured_encoding = tdi->vf? get_etch_string_encoding(tdi->vf): ETCH_ENCODING_DEFAULT;
+    
+    const int nulltermsize = etch_encoding_get_sizeof_terminator(configured_encoding);
+
+    buf = bintdi_read_bytes(tdi, nulltermsize, &size); /* we own this memory */
+    if(buf) {
+        // TODO: pool
+        result = etch_encoding_transcode_to_wchar(&widestring, buf, configured_encoding, size, NULL);
+        etch_free(buf);
+        /* construct string object, relinquishing ownership of string buffer */
+        newstr = new_string_from(widestring, etch_encoding_for_wchar());
+    }
+    return newstr;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * read structured content
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * bintdi_read_keys_values()
+ * deserializes a message from a buffer.
+ * read all key/value pairs from buffer, populating the specified struct.
+ * @param tdi caller retains.
+ * @param sv caller retains.
+ * @return 0 success, -1 deserialization failed, caller should throw exception.
+ */
+int bintdi_read_keys_values (binary_tagged_data_input* tdi, etch_structvalue* sv)
+{
+	etch_type* svtype = sv->struct_type;
+    etch_validator* thisvtor = NULL;  /* non-disposable ref to type vtor */
+    etch_object* thisobj     = NULL;  /* disposable return from read_value */
+    etch_object* thisvalue   = NULL;  /* disposable return from read_value */
+    etch_field*  key_field   = NULL;  /* non-disposable ref to static field */
+    etch_field*  key_clone   = NULL;  /* disposable copy of structvalue key */
+    etch_int32*  this_idobj  = NULL;  /* non-disposable copy of thisobj */
+    int result = 0;
+
+    while(result == 0)
+    {    
+        thisobj = bintdi_read_valuex(tdi, tdi->vtor_int, TRUE); /* disposable */ 
+        
+        //could not read next key field
+        if(!thisobj) {
+            break;
+        }
+
+        if (etchtagdata_is_eod (thisobj)) break;    /* data end marker found */
+
+        key_clone = NULL; 
+        thisvalue = NULL; 
+        result = -1;
+
+        this_idobj = (etch_int32*) thisobj; 
+        key_field  = etchtype_get_field_by_id (svtype, this_idobj->value);  
+ 
+        if (NULL == key_field) 
+        {
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR,"field lookup failed, trying to skip that value\n"); 
+            //skip the value of unknown keys...
+            thisvalue = bintdi_read_value(tdi, etchvtor_object_get(0));  /* returns a disposable ref */ 
+            //if this fails, we cannot know where we are, so stop
+            if(thisvalue == NULL) {
+                ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR,"cant skip value, error in deserialization\n"); 
+                result = -1;
+                break;
+            } else  {//else we can continue
+                ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR,"skipped the value for the unknown key\n"); 
+                result = 0;
+                continue;
+            }
+        }
+
+        thisvtor  = (etch_validator*) etchtype_get_validator_by_name(svtype, key_field->name);  /* returns us a non-disposable ref */ 
+       
+        thisvalue = bintdi_read_value(tdi, thisvtor);  /* returns a disposable ref */ 
+        if (NULL == thisvalue){
+            break; /* validation or other deserialization error */
+        }
+
+        key_clone = (etch_field*)etch_object_clone_func(key_field);
+
+        /* structvalue_put() expects disposable key and value objects, i.e. it will
+         * call destructors on the objects when the struct is destroyed. however if
+         * the put() fails, we still own the objects, which are accounted for below.
+         * note also that this contract differs from the etch_message interface to  
+         * a struct, which eats its put parameters regardless of outcome.
+         */
+        result = structvalue_put(sv, key_clone, (etch_object*) thisvalue);
+
+        //printf("read_keys_values: got field %s, value: %p\n",key_clone->aname,thisvalue);
+
+        /* if put was OK we have relinquished ownership of valuobj */
+        /* key_field was relinquished regardless. */
+
+        etch_object_destroy(thisobj); 
+		thisobj = NULL;
+    }
+
+    if (-1 == result) 
+    {   /* some error, usually failed validation */ 
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR,"message deserialization failed\n"); 
+	    etch_object_destroy(key_clone);
+	    key_clone = NULL;
+
+        etch_object_destroy(thisvalue);
+	    thisvalue = NULL;
+    }
+
+    etch_object_destroy(thisobj);
+    thisobj = NULL;
+
+    return result; 
+}
+
+
+/**
+ * bintdi_read_values()
+ * read values from buffer, populating the specified array with the values so read
+ */
+int bintdi_read_values (binary_tagged_data_input* tdi, 
+    etch_arrayvalue* av, etch_validator* vtor)
+{
+    int counter = 0;
+    etch_validator* ev = vtor? vtor->element_validator(vtor): NULL;
+    etch_object* thisobj = 0;
+    int result = 0;
+    if (!av || !vtor) return -1;
+
+    while(result == 0)
+    {    
+
+        thisobj = bintdi_read_valuex(tdi, ev, TRUE);
+
+        if (NULL == thisobj) return -1;
+        if (etchtagdata_is_eod(thisobj)) break;  
+
+        /* relinquish ownership of thisobj to the arrayvalue */
+        result = arrayvalue_add(av, thisobj);
+        if (0 == result) thisobj = NULL;
+        counter++;
+    }
+
+    etch_object_destroy(ev);
+    etch_object_destroy(thisobj); 
+    return result; 
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * read tokens
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * bintdi_read_value()
+ */
+etch_object* bintdi_read_value(binary_tagged_data_input* tdi, etch_validator* vtor)
+{
+    return bintdi_read_valuex(tdi, vtor, FALSE);
+}
+
+
+/**
+ * bintdi_read_valuex()
+ * reads a tag byte from the buffer, and based on the tag, reads zero or more
+ * bytes from the buffer, appropriate to the data type indicated by the tag.
+ * @return a *disposable* object which appropriately wraps the bytes or object
+ * read from input buffer. however if the data tag indicated a null object, a
+ * nullobj is returned, or if the tag indicated end of data, an eod object is
+ * returned. if validation fails on the object, NULL is returned, otherwise an
+ * object is always returned on which the caller is expected to call destroy().
+ */
+etch_object* bintdi_read_valuex (binary_tagged_data_input* tdi, etch_validator* v, boolean is_none_ok)
+{
+    /* if this method returns NULL it must first destroy any object created 
+     * herein. normally this is accomplished in bintdi_validate_value.
+     */
+    union_alltypes u;
+    signed char objtype = 0;
+    
+    if (-1 == etch_flexbuf_get_byte (tdi->flexbuf, (byte*)&objtype))
+        return NULL;
+
+    switch((signed char)objtype)
+    {
+        case ETCH_XTRNL_TYPECODE_NULL: 
+             /* returns the instance null object. it is considered disposable because
+              * caller can and will call destroy() on it. however the destructor will
+              * have no effect, the null object is destroyed in the tdi destructor.*/
+             return (etch_object*) bintdi_validate_valuex (tdi, v, FALSE, 
+                (etch_object*) tdi->static_nullobj);
+
+	    case ETCH_XTRNL_TYPECODE_NONE:  
+             /* returns the instance eod object. it is considered disposable because
+              * caller can and will call destroy() on it. however the destructor will
+              * have no effect, the eod object is destroyed in the tdi destructor. */
+             return bintdi_validate_value(tdi, v, is_none_ok, 
+                (etch_object*) tdi->static_eodmarker);                                                 	                                            
+    	 
+	    case ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE:                                          
+             return bintdi_validate_value (tdi, v, FALSE, (void*) new_boolean(FALSE));                                                
+    	
+	    case ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE:                                           
+             return bintdi_validate_value (tdi, v, FALSE, (void*) new_boolean(TRUE));                                               
+    	
+	    case ETCH_XTRNL_TYPECODE_BYTE: 
+	      if (-1 == etch_flexbuf_get_byte(tdi->flexbuf, (byte*)(&u.vbyte))) break;
+             return bintdi_validate_valuex (tdi, v, FALSE, (void*) new_byte(u.vbyte));                                               
+    	
+	    case ETCH_XTRNL_TYPECODE_SHORT: 
+             if (-1 == etch_flexbuf_get_short(tdi->flexbuf, &u.vint16)) break;                                                                                                
+             return bintdi_validate_valuex (tdi, v, FALSE, (void*) new_int16(u.vint16));                                                                                                 
+    	
+	    case ETCH_XTRNL_TYPECODE_INT:  
+             if (-1 == etch_flexbuf_get_int(tdi->flexbuf, &u.vint32)) break;
+             return bintdi_validate_valuex (tdi, v, FALSE, (void*) new_int32(u.vint32));
+ 
+	    case ETCH_XTRNL_TYPECODE_LONG: 
+             if (-1 == etch_flexbuf_get_long(tdi->flexbuf, &u.vint64)) break;                                                                             
+             return bintdi_validate_value (tdi, v, FALSE, (void*) new_int64(u.vint64));                                               
+    	
+	    case ETCH_XTRNL_TYPECODE_FLOAT:
+             if (-1 == etch_flexbuf_get_float(tdi->flexbuf, &u.vfloat)) break;                                                                                                                     
+             return bintdi_validate_value (tdi, v, FALSE, (void*) new_float(u.vfloat));                                               
+    	
+	    case ETCH_XTRNL_TYPECODE_DOUBLE:                                       
+             if (-1 == etch_flexbuf_get_double(tdi->flexbuf, &u.vdouble)) break;                                                                                                                     
+             return bintdi_validate_value(tdi, v, FALSE, (void*) new_double(u.vdouble));                                               
+    	
+	    case ETCH_XTRNL_TYPECODE_BYTES: 
+             /* must return arrayvalue for symmetry with tdo */
+             /* todo modify arrayvalue to not populate objects when so requested */
+             u.vnatarray = bintdi_read_bytearray(tdi);  
+             return bintdi_validate_value (tdi, v, FALSE, (void*) u.vnatarray);                                   
+             /*
+             u.varrayval = new_arrayvalue_from(u.vnatarray, ETCH_XTRNL_TYPECODE_BYTES, 
+                 NULL, (int) u.vnatarray->bytecount, 0, FALSE);
+             return bintdi_validate_value (tdi, v, FALSE, (void*) u.varrayval);                                   
+    	    */
+
+             //return (etch_object*)u.vnatarray;
+	    case ETCH_XTRNL_TYPECODE_EMPTY_STRING:                 
+             return bintdi_validate_value (tdi, v, FALSE, (void*) tdi->static_emptystring);                              
+    	
+	    case ETCH_XTRNL_TYPECODE_STRING:   
+             u.vstring = bintdi_read_string(tdi);                                      
+             return bintdi_validate_value (tdi, v, FALSE, (void*) u.vstring);   
+    	
+	    case ETCH_XTRNL_TYPECODE_STRUCT:   
+             u.vsv = bintdi_read_struct((void*) tdi);                                    
+             return bintdi_validate_value (tdi, v, FALSE, (void*) u.vsv);                                               
+    	
+	    case ETCH_XTRNL_TYPECODE_ARRAY: 
+             u.varrayval = bintdi_read_array((tagged_data_input*) tdi, v);
+             return bintdi_validate_value (tdi, v, FALSE, (void*) u.varrayval);   
+    	
+	    case ETCH_XTRNL_TYPECODE_CUSTOM:  
+        {    
+             etch_object* reconstituted_object = NULL;
+             /* acquire struct */
+             etch_structvalue* keys_values = bintdi_read_struct((tagged_data_input*) tdi);
+
+             //deserialization failed
+             if(! keys_values) {
+                return NULL;
+             }
+             /* relinquish struct */
+             reconstituted_object = ((struct i_value_factory*)((etch_object*)tdi->vf)->vtab)->import_custom_value(tdi->vf, keys_values); 
+
+             return bintdi_validate_value (tdi, v, FALSE, (void*) reconstituted_object);   
+        }                                            
+    	
+	    default:                                          
+	      if (is_inrange_tiny_for_signed_chars(objtype))
+                 return bintdi_validate_valuex (tdi, v, FALSE, (void*) new_byte(objtype));
+    }
+    
+    return NULL;
+}
+
+
+/**
+ * bintdi_read_value_rawint()
+ * read an integer value from the buffer, returning the 32-bit primitive
+ * in the out parameter.
+ * @param out a pointer to an int to receive the value read from the buffer.
+ * @return 0 success, -1 if an integer could not be read from the buffer
+ */
+int bintdi_read_value_rawint(binary_tagged_data_input* tdi, int* out)
+{
+    int thisint = 0, result = 0; 
+    signed char objtype = 0;
+    union_alltypes u; 
+
+    if (0 != etch_flexbuf_get_byte(tdi->flexbuf, (byte*)&objtype))
+        result = -1;
+    else
+    if (is_inrange_tiny_for_signed_chars(objtype))
+        thisint = objtype;
+    else switch(objtype)
+    {
+        case ETCH_XTRNL_TYPECODE_INT:  
+             if (0 == (result = etch_flexbuf_get_int(tdi->flexbuf, &u.vint32)))
+                 thisint = u.vint32;
+             break;
+        case ETCH_XTRNL_TYPECODE_SHORT: 
+            if (0 == (result = etch_flexbuf_get_short(tdi->flexbuf, &u.vint16)))
+                thisint = u.vint16;
+            break;
+        case ETCH_XTRNL_TYPECODE_BYTE: 
+	  if (0 == (result = etch_flexbuf_get_byte(tdi->flexbuf, (byte*)&u.vbyte)))
+                thisint = u.vbyte;
+            break;
+        default:
+            result = -1;
+    }
+
+    *out = thisint;
+    return result;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * utility methods  
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * bintdi_get_component_type()
+ *  
+ * @return etch c obj_type and class_id of an array of specified external type,
+ * and its content, or -1 indicating exception condition.
+ */
+int bintdi_get_component_type(tagged_data_input* tdi, const byte array_content_type,
+    etch_type* custom_type, const int dims, etch_array_id_params* out)
+{
+    if (NULL == out) return -1;
+    memset(out, 0, sizeof(etch_array_id_params));
+    
+    return bintdi_get_native_type(array_content_type, out);
+}
+
+
+/*
+ * bintdi_get_native_type()
+ * returns the internal object types and class ids corresponding to the 
+ * external byte typecode indicating content type of an array on the wire.
+ * class_id may or may not be significant, depending on particular obj_type.
+ */
+int bintdi_get_native_type(const signed char external_typecode, etch_array_id_params* out) 
+{
+    int result = 0;
+    memset(out, 0, sizeof(etch_array_id_params));
+    out->content_obj_type = ETCHTYPEB_PRIMITIVE;
+    out->array_obj_type   = ETCHTYPEB_NATIVEARRAY;
+    
+
+    switch(external_typecode) 
+    {
+        case ETCH_XTRNL_TYPECODE_INT:
+             out->content_class_id = CLASSID_PRIMITIVE_INT32;
+             out->array_class_id   = CLASSID_ARRAY_INT32;
+             break;
+
+        case ETCH_XTRNL_TYPECODE_STRING:
+        case ETCH_XTRNL_TYPECODE_EMPTY_STRING:
+             out->content_class_id = CLASSID_STRING;
+             out->array_class_id   = CLASSID_ARRAY_STRING;
+             break;
+
+        case ETCH_XTRNL_TYPECODE_BYTE:
+             out->content_class_id = CLASSID_PRIMITIVE_BYTE;
+             out->array_class_id   = CLASSID_ARRAY_BYTE;
+             break;
+
+        case ETCH_XTRNL_TYPECODE_LONG:
+             out->content_class_id = CLASSID_PRIMITIVE_INT64;
+             out->array_class_id   = CLASSID_ARRAY_INT64;
+             break;
+
+        case ETCH_XTRNL_TYPECODE_SHORT:
+             out->content_class_id = CLASSID_PRIMITIVE_INT16;
+             out->array_class_id   = CLASSID_ARRAY_INT16;
+             break;
+
+        case ETCH_XTRNL_TYPECODE_DOUBLE:
+             out->content_class_id = CLASSID_PRIMITIVE_DOUBLE;
+             out->array_class_id   = CLASSID_ARRAY_DOUBLE;
+             break;
+
+        case ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE:
+        case ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE:
+             out->content_class_id = CLASSID_PRIMITIVE_BOOL;
+             out->array_class_id   = CLASSID_ARRAY_BOOL;
+             break;
+
+        case ETCH_XTRNL_TYPECODE_FLOAT:
+             out->content_class_id = CLASSID_PRIMITIVE_FLOAT;
+             out->array_class_id   = CLASSID_ARRAY_FLOAT;
+             break;
+
+        case ETCH_XTRNL_TYPECODE_ANY:
+        case ETCH_XTRNL_TYPECODE_ARRAY:
+        case ETCH_XTRNL_TYPECODE_STRUCT:
+        case ETCH_XTRNL_TYPECODE_CUSTOM:
+        case ETCH_XTRNL_TYPECODE_NULL:
+             out->content_obj_type = ETCHTYPEB_ETCHOBJECT;
+             out->content_class_id = CLASSID_OBJECT;
+             out->array_class_id   = CLASSID_ARRAY_OBJECT;
+             break;
+
+        case ETCH_XTRNL_TYPECODE_BYTES:
+             out->content_obj_type = ETCHTYPEB_ARRAYVAL;
+             out->content_class_id = CLASSID_ARRAY_BYTE;
+             out->array_class_id   = CLASSID_ARRAY_BYTE;
+             break;
+
+        default:
+             if (is_inrange_tiny_for_signed_chars(external_typecode))
+             {
+                 out->content_class_id = CLASSID_PRIMITIVE_INT8;
+                 out->array_class_id   = CLASSID_ARRAY_INT8;
+             }
+             else
+             {   out->content_obj_type = ETCHTYPEB_NONE;
+                 out->content_class_id = CLASSID_NONE;
+                 result = -1;
+             }
+    }
+
+    return result; 
+}
+
+
+/*
+ * bintagdata_get_native_typecode()
+ * returns the external type code corresponding to internal type.
+ * etchtagdata_get_native_typecode() override
+ */
+signed char bintagdata_get_native_typecode
+   (const unsigned short obj_type, const unsigned short class_id)
+{
+    byte xtype = 0;
+
+    static const byte primitives[10] 
+     = {ETCH_XTRNL_TYPECODE_CUSTOM,       /* CLASSID_NONE             = 0x0 */
+        ETCH_XTRNL_TYPECODE_BYTE,         /* CLASSID_PRIMITIVE_BYTE   = 0x1 */
+        ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE, /* CLASSID_PRIMITIVE_BOOL   = 0x2 */
+        ETCH_XTRNL_TYPECODE_BYTE,         /* CLASSID_PRIMITIVE_INT8   = 0x3 */
+        ETCH_XTRNL_TYPECODE_SHORT,        /* CLASSID_PRIMITIVE_INT16  = 0x4 */
+        ETCH_XTRNL_TYPECODE_INT,          /* CLASSID_PRIMITIVE_INT32  = 0x5 */
+        ETCH_XTRNL_TYPECODE_LONG,         /* CLASSID_PRIMITIVE_INT64  = 0x6 */
+        ETCH_XTRNL_TYPECODE_FLOAT,        /* CLASSID_PRIMITIVE_FLOAT  = 0x7 */
+        ETCH_XTRNL_TYPECODE_DOUBLE,       /* CLASSID_PRIMITIVE_DOUBLE = 0x8 */
+        ETCH_XTRNL_TYPECODE_STRING        /* CLASSID_STRING           = 0x9 */
+       };
+     
+    switch(obj_type)
+    { 
+        case ETCHTYPEB_PRIMITIVE:
+             if  (class_id <= CLASSID_STRING)
+                  xtype = primitives[class_id];
+             else xtype = ETCH_XTRNL_TYPECODE_CUSTOM;   
+             break;
+
+        case ETCHTYPEB_ETCHOBJECT:
+             xtype = ETCH_XTRNL_TYPECODE_ANY;
+             break;
+
+        default:
+             xtype = ETCH_XTRNL_TYPECODE_CUSTOM;             
+    }
+
+    return xtype;
+}
+
+
+/*
+ * bintdi_get_custom_structtype()
+ * override of etchtagdata_get_custom_structtype. 
+ * defers to value factory to return a non-disposable struct type 
+ * for the specified class.
+ */
+etch_type* bintdi_get_custom_structtype(etch_object* thisx,
+    const unsigned short obj_type, const unsigned short class_id)
+{
+    etch_type *static_type = NULL; 
+    binary_tagged_data_input *tdi = (binary_tagged_data_input*) thisx;
+    etch_value_factory  *vf = tdi->vf;
+    if(vf) static_type = ((struct i_value_factory*)((etch_object*)vf)->vtab)->get_custom_struct_type(vf, class_id);
+    return static_type;    
+}
+
+
+/**
+ * bintdi_validate_value()
+ * not an override.
+ * &return an object *of the type being validated*, or null. this may be the same
+ * object as the passed value, or may be different. for example if we are working
+ * with an array of int, and a zero value was serialized, it will have been
+ * deserialized into an etch_byte, and the int validator validate_value will  
+ * create and return an etch_int32 in its stead.
+ * null return indicates a validation error. null object return indicates value
+ * read was logically null. eod object return indicates end of data. if validation
+ * fails on a object, that object's destructor is invoked here.
+ */
+etch_object* bintdi_validate_value (binary_tagged_data_input* tdi, 
+    etch_validator* vtor, boolean is_none_ok, etch_object* value)
+{
+    etch_object* resultobj = NULL;
+
+    if(! value)
+        return NULL;
+
+    if  (NULL == vtor) {
+        resultobj = NULL;
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "no validator for type %x class %x\n", ((etch_object*)value)->obj_type, ((etch_object*)value)->class_id);  
+        etch_object_destroy(value);
+        value = NULL;
+        return NULL;
+    }
+    else if  (NULL == value) {
+         return NULL;
+    }
+    else if  (etchtagdata_is_eod(value)  && is_none_ok) {
+         resultobj = value;
+    }
+    else if  (etchtagdata_is_null(value) && is_none_ok) {
+         resultobj = value;
+    }
+    else if  (NULL == (resultobj = vtor->validate_value (vtor, value)))
+    {    
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "validation failed for type %x class %x\n", ((etch_object*)value)->obj_type, ((etch_object*)value)->class_id);
+        etch_object_destroy(value);
+        value = NULL;
+
+         /* todo it would be nice to get an exception back across the wire here
+          * rather than kibosh the session, but not sure what the path would be
+          * to get it there, since we don't have a message yet at this point.
+          */
+    }
+ 
+
+    /* resultobj may be the same object as value, or may be different.
+     * if value was not an object of the type being validated, i.e. the validator
+     * is the int validator but the value object is an etch_byte representing zero,
+     * resultobj will be an etch_int32. if validation failed resultobj is null.
+     */
+    return resultobj;
+}
+
+
+/**
+ * bintdi_validate_valuex()
+ * invokes bintdi_validate_value on a value object, and if the validated object
+ * to be returned is not the same object as the passed value object, that value
+ * object's destructor is invoked. within the tdi, this will not necessarily
+ * destroy the value object, as the tdi can pass protected static objects, 
+ * such as an object representing null, for validation. 
+ * @return a validated object of the same class as that of the supplied validator,
+ * which may or may not be the same object as the passed value object.
+ */
+etch_object* bintdi_validate_valuex(binary_tagged_data_input* tdi, 
+    etch_validator* vtor, boolean is_none_ok, etch_object* valueobj)
+{
+    etch_object* resultobj = bintdi_validate_value(tdi, vtor, is_none_ok, valueobj);
+
+    if  (resultobj && valueobj && (resultobj != valueobj))
+         etch_object_destroy(valueobj);
+      
+    return resultobj;
+}
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_binary_tdo.c b/binding-c/runtime/c/src/main/bindings/msg/etch_binary_tdo.c
new file mode 100644
index 0000000..f3ca824
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_binary_tdo.c
@@ -0,0 +1,807 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*  
+ * etch_binary_tdo.c -- binary tagged data output implementation.
+ */
+
+#include "etch_runtime.h"
+#include "etch_binary_tdo.h"
+#include "etch_default_value_factory.h"
+#include "etch_cache.h"
+#include "etch_arrayval.h"
+#include "etch_encoding.h"
+#include "etch_nativearray.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+static const char* LOG_CATEGORY = "etch_binary_tdo";
+
+
+byte bintagdata_get_native_typecode(const unsigned short, const unsigned short);
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * private signatures
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+i_binary_tdo* new_binarytdo_vtable();
+int bintdo_start_message(tagged_data_output*, etch_message*);
+int bintdo_write_message(tagged_data_output*, etch_message*, etch_flexbuffer*);
+int bintdo_end_message  (tagged_data_output*, etch_message*);
+
+int bintdo_start_struct (tagged_data_output*, etch_structvalue*);
+int bintdo_write_struct (tagged_data_output*, etch_structvalue*);
+int bintdo_end_struct   (tagged_data_output*, etch_structvalue*);
+
+int bintdo_start_array  (tagged_data_output*, etch_arrayvalue*);
+int bintdo_write_array  (tagged_data_output*, etch_arrayvalue*, etch_validator*);             
+int bintdo_end_array    (tagged_data_output*, etch_arrayvalue*);
+
+int bintdo_write_type  (binary_tagged_data_output*, etch_type*);
+int bintdo_write_values(binary_tagged_data_output*, etch_arrayvalue*, etch_validator*);
+int bintdo_write_keys_values(binary_tagged_data_output*, etch_structvalue*);
+int bintdo_write_bytes_from  (binary_tagged_data_output*, etch_nativearray*);
+int bintdo_write_value_rawint(binary_tagged_data_output*, const int);
+int bintdo_write_intvalue (binary_tagged_data_output*, const int);
+int bintdo_write_nonevalue(binary_tagged_data_output*);
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * constructors/destructors
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+
+/**
+ * destroy_binary_tagged_data_output()
+ */
+int destroy_binary_tagged_data_output(void* data)
+{
+    binary_tagged_data_output* tdo = (binary_tagged_data_output*)data;
+    if (!is_etchobj_static_content(tdo))
+    {
+        etch_object_destroy(tdo->impl);
+
+        if (tdo->flexbuf && tdo->is_flexbuf_owned)
+            etch_object_destroy(tdo->flexbuf);
+    }
+
+    /* destroy private instance data */
+    etch_free(tdo->static_nullobj);
+    etch_free(tdo->static_eodmarker);
+    clear_etchobj_static_all(tdo->static_emptystring);
+    etch_object_destroy(tdo->static_emptystring);
+     
+    return destroy_objectex((etch_object*)tdo);
+}
+
+/**
+ * clone_tagged_data_output()
+ * tdo copy constructor. if the tdo object implements a separate instance data
+ * object, that object is cloned as well. 
+ */
+void* clone_binary_tagged_data_output(void* data)
+{
+    binary_tagged_data_output* tdo = (binary_tagged_data_output*)data;
+    binary_tagged_data_output* newtdo = (binary_tagged_data_output*) clone_object((etch_object*) tdo);
+    newtdo->impl = tdo->impl?  tdo->impl->clone(tdo->impl): NULL;
+    return newtdo;
+}
+
+/**
+ * new_binary_tdo()
+ * binary_tagged_data_output constructor
+ * @param vf a value factory. can be null. caller retains ownership.
+ * @param fbuf the buffer to write to. can be null. caller retains ownership.
+ */
+binary_tagged_data_output* new_binary_tagdata_output(etch_value_factory* vf, etch_flexbuffer* fbuf) 
+{
+    i_binary_tdo* vtab = NULL;
+
+    binary_tagged_data_output* tdo  = (binary_tagged_data_output*) new_object
+        (sizeof(binary_tagged_data_output), ETCHTYPEB_TAGDATAOUT, CLASSID_TAGDATAOUT);
+
+    ((etch_object*)tdo)->destroy = destroy_binary_tagged_data_output;
+    ((etch_object*)tdo)->clone   = clone_binary_tagged_data_output;
+    tdo->flexbuf = fbuf;  /* if caller passes buffer, caller owns it */ 
+    if (fbuf) tdo->is_flexbuf_owned = FALSE;
+    tdo->vf = vf;
+
+    vtab = etch_cache_find(get_vtable_cachehkey(CLASSID_BINARYTDO_VTAB), 0);
+
+    if(!vtab)  
+    {   vtab = new_binarytdo_vtable();
+        etch_cache_insert(((etch_object*)vtab)->get_hashkey(vtab), vtab, FALSE);
+    } 
+
+    ((etch_object*)tdo)->vtab = (vtabmask*)vtab; 
+    tdo->vtor_eod = etchvtor_eod_get();  
+    tdo->vtor_int = etchvtor_int32_get(0); 
+    tdo->static_nullobj     = etchtagdata_new_nullobj(TRUE);
+    tdo->static_eodmarker   = etchtagdata_new_eodmarker(TRUE);
+    tdo->static_emptystring = etchtagdata_new_emptystring(TRUE);
+    return tdo; 
+}
+
+
+/**
+ * new_binary_tdo()
+ * casts result to generic tdo for use by interfaces
+ */
+tagged_data_output* new_binary_tdo(etch_value_factory* vf)
+{
+    return (tagged_data_output*) new_binary_tagdata_output(vf, NULL);
+}
+
+
+
+
+
+
+/**
+ * new_new_binarytdo_vtable()
+ * constructor for binary tdo virtual function table
+ */
+i_binary_tdo* new_binarytdo_vtable()
+{
+    etchparentinfo* inheritlist = new_etch_inheritance_list(3, 2, NULL); 
+   
+    i_binary_tdo* vtab 
+        = new_vtable(NULL, sizeof(i_binary_tdo), CLASSID_BINARYTDO_VTAB);
+
+    /* i_tagged_data_input */
+    vtab->start_message = bintdo_start_message;
+    vtab->write_message = bintdo_write_message;
+    vtab->end_message   = bintdo_end_message;
+    vtab->start_struct  = bintdo_start_struct;
+    vtab->write_struct  = bintdo_write_struct;
+    vtab->end_struct    = bintdo_end_struct;
+    vtab->start_array   = bintdo_start_array;
+    vtab->write_array   = bintdo_write_array;
+    vtab->end_array     = bintdo_end_array;
+
+    /* i_tagdata */
+    #if(0)
+    vtab->check_value = etchtagdata_check_value;
+    vtab->get_native_type = bintdo_get_native_type;
+    vtab->get_native_type_code  = bintdo_get_native_typecode;
+    vtab->get_custom_structtype = bintdo_get_custom_structtype;
+    #endif
+
+    /* inheritance */
+    inheritlist[1].o.obj_type = ETCHTYPEB_TAGDATAOUT;
+    inheritlist[1].c.class_id = CLASSID_TAGDATAOUT;
+    inheritlist[2].o.obj_type = ETCHTYPEB_TAGDATA;
+    inheritlist[2].c.class_id = CLASSID_TAGDATA;
+
+    vtab->inherits_from = inheritlist;
+
+    return vtab;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * write message
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * bintdo_start_message()
+ * message is unique among serialized objects in that since message is at the
+ * top level, no type byte is written to mark the start of a message. a version
+ * number is written to identify the btd implementation version used to write
+ * the message.
+ */
+int bintdo_start_message(tagged_data_output* tdox, etch_message* msg)   
+{
+    binary_tagged_data_output* tdo = (binary_tagged_data_output*) tdox;
+    ETCH_ASSERT(tdo && msg);
+    etch_flexbuf_put_byte(tdo->flexbuf, ETCH_BINTAGDATA_CURRENT_VERSION);
+    return bintdo_start_struct(tdox, msg->sv);
+}
+
+
+ /**
+ * bintdo_write_message()
+ * message is unique among serialized objects in that since message is at the
+ * top level, no type byte is written to mark the start of a message. a version
+ * number is written to identify the btd implementation version used to write
+ * the message.
+ */
+int bintdo_write_message(tagged_data_output* tdox, etch_message* msg, etch_flexbuffer* fbuf)
+{
+    binary_tagged_data_output* tdo = (binary_tagged_data_output*) tdox;
+    ETCH_ASSERT(tdo && msg && fbuf);
+    tdo->flexbuf = fbuf;
+
+    if (-1 == bintdo_start_message(tdox, msg)) return -1; 
+
+    if (-1 == bintdo_write_keys_values(tdo, msg->sv)) return -1;
+
+    return bintdo_end_message(tdox, msg);
+}
+
+
+/**
+ * tdo_end_message()
+ * marks the end of the message in process.
+ */
+int bintdo_end_message(tagged_data_output* tdox, etch_message* msg)   
+{
+    return bintdo_end_struct(tdox, msg->sv);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * write struct
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * bintdo_start_struct()
+ * write the beginning of struct data. 
+ */
+int bintdo_start_struct(tagged_data_output* tdox, etch_structvalue* sv)   
+{
+    binary_tagged_data_output* tdo = (binary_tagged_data_output*) tdox;
+    ETCH_ASSERT(tdo && sv);
+    /* caller has already written a bytecode to the buffer indicating struct follows */
+
+    if (-1 == bintdo_write_type(tdo, sv->struct_type)) return -1;
+
+    return bintdo_write_value_rawint(tdo, structvalue_count(sv));  
+}
+
+
+/**
+ * bintdo_write_struct()
+ */
+int bintdo_write_struct(tagged_data_output* tdox, etch_structvalue* sv)  
+{
+    ETCH_ASSERT(tdox && sv);
+
+    if (-1 == bintdo_start_struct(tdox, sv)) return -1;
+
+    if (-1 == bintdo_write_keys_values((binary_tagged_data_output*)tdox, sv)) return -1;
+
+    return bintdo_end_struct(tdox, sv);
+}
+
+
+/**
+ * bintdo_end_struct()
+ * mark end of specified struct
+ */
+int bintdo_end_struct(tagged_data_output* tdox, etch_structvalue* sv)   
+{
+    return bintdo_write_nonevalue((binary_tagged_data_output*) tdox);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * write array
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * bintdo_start_array()
+ * starts writing of an array 
+ */
+int bintdo_start_array (tagged_data_output* tdox, etch_arrayvalue* av)   
+{
+    int errs = 0;
+    binary_tagged_data_output* tdo = (binary_tagged_data_output*) tdox;
+    ETCH_ASSERT(tdo && av);
+
+    etch_flexbuf_put_byte (tdo->flexbuf, av->type_code);
+
+    if (ETCH_XTRNL_TYPECODE_CUSTOM == av->type_code)
+        errs += bintdo_write_type (tdo, av->custom_struct_type);
+
+    errs += bintdo_write_value_rawint (tdo, av->dim); 
+    errs += bintdo_write_value_rawint (tdo, arrayvalue_count(av));   
+    return errs? -1: 0;
+}
+
+
+/**
+ * bintdo_write_array()
+ */
+int bintdo_write_array (tagged_data_output* tdox, etch_arrayvalue* av, etch_validator* vtor)
+{
+    ETCH_ASSERT(tdox && vtor);
+
+    if (!is_etch_arrayvalue(av)) return -1;
+
+    if (-1 == bintdo_start_array (tdox, av)) return -1;
+
+    if (-1 == bintdo_write_values ((binary_tagged_data_output*) tdox, av, vtor)) 
+        return -1;
+
+    return bintdo_end_array(tdox, av);
+}
+
+
+/**
+ * bintdo_end_array()
+ * writes end of the array being read.
+ */
+int bintdo_end_array (tagged_data_output* tdo, etch_arrayvalue* av)  
+{
+    return bintdo_write_nonevalue ((binary_tagged_data_output*) tdo);
+}
+
+
+/**
+ * bintdo_to_arrayvalue()
+ * convert supplied native array to an etch_arrayvalue.
+ * @param na the native array. caller retains.
+ * @return an etch_arrayvalue. caller owns it.
+ */
+etch_arrayvalue* bintdo_to_arrayvalue (binary_tagged_data_output* tdo, etch_nativearray* na)
+{
+    etch_type* NULLTYPE = NULL;
+
+    signed char content_typecode = arrayvalue_get_external_typecode(na->content_obj_type, na->content_class_id);
+
+    /* todo we should calculate array size from native array 
+     * metadata rather than creating it using a default size */
+    etch_arrayvalue* av = NULL;
+	if(((etch_object*)na)->class_id != CLASSID_ARRAY_OBJECT && content_typecode == ETCH_XTRNL_TYPECODE_CUSTOM) {
+		etch_type* theType = NULL;
+		//theType = class_to_type_map_get(tdo->vf)->class_to_type, na->content_class_id);
+		theType = ((struct i_value_factory*)((etch_object*)tdo->vf)->vtab)->get_custom_struct_type(tdo->vf, ETCHMAKECLASS(na->content_obj_type, na->content_class_id));
+		av = new_arrayvalue_from (na, content_typecode, theType, ETCH_DEFSIZE, ETCH_DEFSIZE, TRUE);
+		av->content_class_id = na->content_class_id;
+		av->custom_struct_type = theType;
+    }
+    else
+    if(((etch_object*)na)->class_id == CLASSID_ARRAY_OBJECT && content_typecode == ETCH_XTRNL_TYPECODE_CUSTOM) {
+        av = new_arrayvalue_from (na, ETCH_XTRNL_TYPECODE_ANY, NULLTYPE, ETCH_DEFSIZE, ETCH_DEFSIZE, TRUE);
+        av->content_class_id = na->content_class_id;
+    }
+    else {
+        av = new_arrayvalue_from (na, content_typecode, NULLTYPE, ETCH_DEFSIZE, ETCH_DEFSIZE, TRUE);
+        av->content_class_id = na->content_class_id;
+    }
+
+    if(NULL == av) {
+         ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "nativearray conversion failed"); 
+    }
+  
+
+
+
+    return av;
+}
+
+
+///**
+// * normalize_etch_array()
+// * validate parameter as an array type with dimension <= that specified,
+// * and convert to arrayvalue if necessary.
+// * @param a an arrayvalue or nativearray. caller retains.
+// * @param maxdim maximum number of dimensions, zero means don't validate dimensions.
+// * @return the passed array expressed as an to arrayvalue, or NULL if error. 
+// */
+//etch_arrayvalue* normalize_etch_array(void* a, const int maxdim)
+//{
+//    etch_arrayvalue* av = NULL;  
+//   
+//    if (is_etch_nativearray(a))
+//    {   etch_nativearray* na = (etch_nativearray*) a;
+//        if (0 == maxdim || na->numdims <= maxdim)
+//            av = bintdo_to_arrayvalue(na);
+//    }
+//    else
+//    if (is_etch_arrayvalue(a))
+//    {   etch_arrayvalue* xav = (etch_arrayvalue*) a;
+//        if (0 == maxdim || xav->dim <= maxdim)
+//            av = xav;
+//    }
+//
+//    return av;
+//}
+
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * disassemble objects and write bytes 
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * bintdo_write_nonevalue()
+ * convenience method to write eod marker 
+ */
+int bintdo_write_nonevalue(binary_tagged_data_output* tdo)
+{
+    return bintdo_write_value(tdo, tdo->vtor_eod, tdo->static_eodmarker);
+}
+
+
+/**
+ * bintdo_write_intvalue()
+ * convenience method used when an encoded integer is expected next in  
+ * the buffer, to write such a value to the buffer. 
+ *
+ * this method is no longer used, we now use bintdo_write_value_rawint()
+ */
+int bintdo_write_intvalue(binary_tagged_data_output* tdo, const int value)
+{
+    etch_int32* intobj = new_int32(value);
+    int result = bintdo_write_value(tdo, tdo->vtor_int, (etch_object*) intobj);
+    etch_object_destroy(intobj);
+    return result;
+}
+
+
+/**
+ * bintdo_write_value_rawint()
+ * write specified 32-bit integer value to the buffer
+ */
+int bintdo_write_value_rawint(binary_tagged_data_output* tdo, const int value)
+{
+    size_t nout = 0;
+
+    if  (is_inrange_tiny(value))
+         nout = etch_flexbuf_put_byte(tdo->flexbuf, (signed char) value);
+    else
+    if  (is_inrange_byte(value))
+         if  (sizeof(byte) == etch_flexbuf_put_byte(tdo->flexbuf, ETCH_XTRNL_TYPECODE_BYTE)) 
+              nout = etch_flexbuf_put_byte(tdo->flexbuf, (signed char) value); 
+         else;
+    else
+    if  (is_inrange_int16(value))
+         if  (sizeof(byte) == etch_flexbuf_put_byte(tdo->flexbuf, ETCH_XTRNL_TYPECODE_SHORT)) 
+              nout = etch_flexbuf_put_short(tdo->flexbuf, (short) value); 
+         else;
+    else 
+    if  (sizeof(byte) == etch_flexbuf_put_byte(tdo->flexbuf, ETCH_XTRNL_TYPECODE_INT))
+         nout = etch_flexbuf_put_int(tdo->flexbuf, value); 
+            
+    return nout? 0: -1;   
+}
+
+
+/**
+ * bintdo_write_type()
+ * convenience method used when an etch_type is to be written to the buffer, 
+ * to write such a value to the buffer. caller owns the supplied type. 
+ * only the type's id is written.
+ */
+int bintdo_write_type(binary_tagged_data_output* tdo, etch_type* type)
+{
+    return type? bintdo_write_value_rawint(tdo, type->id): -1;
+}
+
+
+/**
+ * bintdo_get_bytes()
+ * gets serialized bytes of the specified message. caller owns returned byte vector.
+ * not sure what this is used for.
+ * "static" method, no tdo is passed. 
+ * @return count of bytes 
+ */
+int bintdo_get_bytes(etch_message* msg, etch_value_factory* vf, byte** out)
+{
+    size_t bytecount = 0;
+    etch_flexbuffer* fbuf = new_flexbuffer(0); /* tdo will own this */
+    binary_tagged_data_output* tdo = new_binary_tagdata_output(vf, fbuf);
+    bintdo_write_message((tagged_data_output*)tdo, msg, fbuf);
+
+    *out = etch_flexbuf_get_all(fbuf, &bytecount); /* new allocation */
+
+    etch_object_destroy(tdo);
+    return (int) bytecount;
+}
+
+
+/**
+ * bintdo_write_bytes()
+ * writes a byte vector to the buffer. 
+ */
+int bintdo_write_bytes(binary_tagged_data_output* tdo, char* bytes, const int bytecount)
+{
+    size_t nout = 0;
+    /* TODO handle return value */
+    bintdo_write_value_rawint(tdo, (int) bytecount); 
+
+    nout = etch_flexbuf_put(tdo->flexbuf, (unsigned char*)bytes, 0, bytecount);
+
+    return nout == bytecount? 0: -1;   
+}
+
+ 
+/**
+ * bintdo_write_bytes_from()
+ * writes a byte vector from a native array to the buffer. 
+ * @param bytearray an etch_nativearray of single dimension and of content type byte. 
+ */
+int bintdo_write_bytes_from(binary_tagged_data_output* tdo, etch_nativearray* bytearray)
+{
+     /* we're assuming we always get a nativearray object and not a char*,
+      * however i'm not sure yet exactly where the tdo input is created, 
+      * so i'm not positive this is the way is should be. update: perhaps this
+      * method should be passed an arrayvalue, keep an eye on this.
+      */
+    size_t bytecount = 0, nout = 0;
+    int result = 0;
+
+    //if ((is_etch_nativearray(bytearray)) 
+    //&& (((etch_object*)bytearray)->class_id = CLASSID_ARRAY_BYTE)
+    //&& (bytearray->numdims == 1));
+    //else return -1;
+
+    bytecount = bytearray->bytecount; /* or bytearray->dimsize[0], same thing */
+
+    result = bintdo_write_value_rawint(tdo, (int) bytecount); 
+
+    nout = etch_flexbuf_put(tdo->flexbuf, bytearray->values, 0, bytecount);
+
+    return nout == bytecount? 0: -1;   
+}
+
+
+/**
+ * bintdo_write_string()
+ * writes a string value to the buffer. 
+ */
+int bintdo_write_string(binary_tagged_data_output* tdo, etch_string* s)
+{
+    int result = 0, wire_encoding = 0, this_encoding = 0, is_new_memory = 0;
+    int bytes_to_write = 0, bytes_written = 0;
+    unsigned char* bytevector = NULL;
+    unsigned int terminator = 0;
+    if (NULL == s) return -1;
+
+    wire_encoding = get_etch_string_encoding(tdo->vf);
+    this_encoding = s->encoding;
+
+    if (wire_encoding == this_encoding) {
+      bytevector = s->v.value;
+      bytes_to_write = s->byte_count;
+    } else {
+        // TODO: pool
+      result = etch_encoding_transcode((char**)&bytevector, wire_encoding, s->v.value, this_encoding, s->byte_count, &bytes_to_write, NULL);
+        ETCH_ASSERT(result != -1);
+        is_new_memory = TRUE;
+    }
+    terminator = etch_encoding_get_sizeof_terminator(wire_encoding);
+    if ((unsigned int)bytes_to_write > terminator) {
+      bytes_to_write -= terminator;
+    }
+
+    if (NULL == bytevector) return -1;
+
+    result = bintdo_write_value_rawint(tdo, bytes_to_write);
+
+    bytes_written = (int) etch_flexbuf_put(tdo->flexbuf, bytevector, 0, bytes_to_write);
+    result = bytes_written == bytes_to_write? 0: -1;
+
+    if (is_new_memory)
+        etch_free(bytevector);
+
+    return result;
+}
+
+
+/**
+ * bintdo_write_values()
+ * write all values from the specified array
+ */
+int bintdo_write_values(binary_tagged_data_output* tdo, etch_arrayvalue* av, 
+    etch_validator* vtor)
+{
+    int  errs = 0;
+    etch_validator* ev = vtor? vtor->element_validator(vtor): NULL;
+    etch_iterator iterator;
+    set_iterator(&iterator, av->list, &av->list->iterable);
+
+    while(iterator.has_next(&iterator))
+    {
+        errs += (0 != bintdo_write_value(tdo, ev, iterator.current_value));
+        iterator.next(&iterator);
+    } 
+
+    etch_object_destroy(ev);
+
+    return errs? -1: 0;
+}
+
+
+/**
+ * bintdo_write_keys_values()
+ * write key/value pairs from the struct to the buffer
+ */
+int bintdo_write_keys_values (binary_tagged_data_output* tdo, etch_structvalue* sv)
+{
+    etch_type* struct_type = sv->struct_type;
+    etch_validator* thisvtor = NULL;
+    etch_field* thiskey = NULL;
+    etch_object* thisval = NULL;
+    int result = 0;
+
+    etch_iterator iterator;
+    set_iterator(&iterator, sv->items, &sv->items->iterable);
+
+    while(iterator.has_next(&iterator))
+    {
+        thiskey  = (etch_field*) iterator.current_key;
+        thisval  = (etch_object*)    iterator.current_value;
+        ETCH_ASSERT(thiskey);
+
+        thisvtor = (etch_validator*) 
+            etchtype_get_validator_by_name (struct_type, thiskey->name);
+
+        if (NULL == thisvtor)
+        {
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "type '%s' missing validator '%s'\n", struct_type->aname, thiskey->aname);
+            result = -1;
+            break;
+        }
+                         
+        result = bintdo_write_value_rawint (tdo, thiskey->id);
+        result = bintdo_write_value (tdo, thisvtor, thisval);
+        if (-1 == result) break;
+
+        iterator.next(&iterator);
+    }
+   
+    return result;
+}
+
+
+/**
+ * bintdo_write_value()
+ * write specified value to the buffer
+ * @param vtor validator for specified value, or null if none
+ * @param value the value to be encoded and written, as a *non-disposable* object,
+ * i.e. caller owns memory for the value object.
+ */
+int bintdo_write_value (binary_tagged_data_output* tdo, etch_validator* vtor, etch_object* value)
+{
+    etch_config_t*  config    = NULL;
+    int32           propvalue = 0;
+    int             result    = 0;
+    size_t          nout      = 0;
+    union_alltypes  u; 
+    signed char     external_typecode;
+
+    etch_runtime_get_config(&config);
+    ETCH_ASSERT(config);
+
+    etch_config_get_property_int(config, "etch.validate.write", &propvalue);
+    if (propvalue == 1)
+    {   /* we should disable validate on write in production */
+        if (NULL == value); /* don't recall why null value is not validated */
+        else
+        if (!vtor || -1 == vtor->validate (vtor, (etch_object*) value))
+        {   
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "validation failed for type %x class %x\n", ((etch_object*)value)->obj_type, ((etch_object*)value)->class_id);  
+            return -1;
+        }
+    }
+
+    /* determine tag (fyi signed only because using the java byte constants) */
+    external_typecode = etchtagdata_check_value((etch_object*) value);
+
+    /* write tag */
+    if (sizeof(byte) != etch_flexbuf_put_byte(tdo->flexbuf, external_typecode))
+        return -1;
+
+    switch(external_typecode)
+    {	    
+        case ETCH_XTRNL_TYPECODE_NULL:             
+	    case ETCH_XTRNL_TYPECODE_NONE: 
+        case ETCH_XTRNL_TYPECODE_EMPTY_STRING: 
+	    case ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE:                                          
+	    case ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE:  
+             return 0; /* nothing to do, tag says it all */
+
+	    case ETCH_XTRNL_TYPECODE_BYTE:  
+	      if (0 == etchtagdata_byte_value((etch_object*) value, (byte*)&u.vbyte))
+                 nout = etch_flexbuf_put_byte(tdo->flexbuf, u.vbyte); 
+             break;   
+
+	    case ETCH_XTRNL_TYPECODE_INT:  
+             if (0 == etchtagdata_int32_value((etch_object*) value, &u.vint32))
+                 nout = etch_flexbuf_put_int(tdo->flexbuf, u.vint32); 
+             break;  
+
+	    case ETCH_XTRNL_TYPECODE_LONG:  
+             if (0 == etchtagdata_int64_value((etch_object*) value, &u.vint64))
+                 nout = etch_flexbuf_put_long(tdo->flexbuf, u.vint64); 
+             break; 
+
+	    case ETCH_XTRNL_TYPECODE_SHORT:  
+             if (0 == etchtagdata_int16_value((etch_object*) value, &u.vint16))
+                 nout = etch_flexbuf_put_short(tdo->flexbuf, u.vint16); 
+             break;  
+
+	    case ETCH_XTRNL_TYPECODE_DOUBLE:  
+             if (0 == etchtagdata_double_value((etch_object*) value, &u.vdouble))
+                 nout = etch_flexbuf_put_double(tdo->flexbuf, u.vdouble); 
+             break;   
+
+	    case ETCH_XTRNL_TYPECODE_FLOAT:  
+             if (0 == etchtagdata_float_value((etch_object*) value, &u.vfloat))
+                 nout = etch_flexbuf_put_float(tdo->flexbuf, u.vfloat); 
+             break;  
+
+	    case ETCH_XTRNL_TYPECODE_BYTES:  
+             /* we get an arrayvalue here. to do differently would be problematic 
+              * without rewriting higher levels to not work with arrayvalue. 
+              * perhaps we should simply pass arrayvalue to bintdo_write_bytes_from().
+              * TODO either accept a native array here, or change
+              * bintdo_write_bytes_from() to accept an arrayvalue, or both.
+              */
+			if(is_etch_nativearray(value)){
+				u.vnatarray = (etch_nativearray*)value;
+				result = bintdo_write_bytes_from(tdo,u.vnatarray);
+				return result;
+			}
+			else{
+				u.vnatarray = ((etch_arrayvalue*)value)->natarray;
+				result = bintdo_write_bytes_from(tdo, u.vnatarray);
+				return result;
+			}
+
+	    case ETCH_XTRNL_TYPECODE_ARRAY: 
+             /* if arriving here from client app we may get an etch_nativearray,
+              * which we must convert to an arrayvalue now.  
+              * TODO write a version of bintdo_write_array which accepts a    
+              * nativearray, so we can avoid this to_arrayvalue() conversion.
+              */ 
+            if (is_etch_nativearray(value)) {
+                u.varrayval = bintdo_to_arrayvalue(tdo, (etch_nativearray*) value);
+                result = bintdo_write_array((tagged_data_output*)tdo, u.varrayval, vtor);
+                etch_object_destroy(u.varrayval);
+            }
+            else {
+                u.varrayval = (etch_arrayvalue*) value;
+                result = bintdo_write_array((tagged_data_output*)tdo, u.varrayval, vtor);
+            }
+            return result;
+
+ 	    case ETCH_XTRNL_TYPECODE_STRING:  
+        {    etch_string* s = (etch_string*) value; 
+             result = bintdo_write_string(tdo, s);
+             return result;
+        }
+
+        case ETCH_XTRNL_TYPECODE_CUSTOM:
+        {
+             etch_structvalue* sv = ((struct i_value_factory*)((etch_object*)tdo->vf)->vtab)->export_custom_value(tdo->vf, value);
+             if (NULL == sv) return -1;
+             
+             result = bintdo_write_struct((tagged_data_output*) tdo, sv);
+             
+             etch_object_destroy(sv);
+             return result;
+        }
+
+        default:
+             return is_inrange_tiny_for_signed_chars(external_typecode)? 0: -1;
+    }
+
+    return nout? 0: -1;   
+}
+
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_default_value_factory.c b/binding-c/runtime/c/src/main/bindings/msg/etch_default_value_factory.c
new file mode 100644
index 0000000..958172e
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_default_value_factory.c
@@ -0,0 +1,896 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_defvalufact.c 
+ * default value factory from which all others inherit
+ */
+
+#include "etch_default_value_factory.h"
+#include "etch_serializer.h"
+#include "etch_map.h"
+#include "etch_log.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include <wchar.h>
+
+char* ETCHVALF = "VALF";
+
+void etchvf_instantiate_builtins();
+
+etch_type*    defvf_add_type (void*, etch_type*);
+etch_id_name* get_idname_by_id (etch_hashtable* map, const unsigned id); 
+etch_type*    defvf_get_type_by_id (void*,  const unsigned id);
+etch_type*    defvf_get_type_by_name(void*, const wchar_t* name); 
+etch_type*    defvf_get_type_by_name(void*, const wchar_t* name); 
+wchar_t*      defvf_get_string_encoding (void*);
+etch_type*    defvf_get_custom_struct_type (void*, const unsigned);
+etch_int64*   defvf_get_message_id  (void*, etch_message*);
+int           defvf_set_message_id  (void*, etch_message*, etch_int64* id);
+etch_int64*   defvf_get_in_reply_to (void*, etch_message*);
+int           defvf_set_in_reply_to (void*, etch_message*, etch_int64* id);
+etch_type*    defvf_get_mt_exception(void*);
+etch_type*    defvf_get_mt_rutime_exception(void*);
+etch_type*    defvf_get_mt_auth_exception(void*);
+etch_object*      defvf_import_custom_value (void*, etch_structvalue*);
+etch_structvalue* defvf_export_custom_value (void*, etch_object* value);
+etch_arraylist* new_vf_mixin_collection(void*);
+etch_arraylist* defvf_get_types (void*);
+
+
+/* 
+ * built-in (etch-global, quasi-static) objects.
+ * these singleton objects are global to all vfs, instantiated with the 
+ * initial vf, and destroyed at etch teardown.
+ */
+defvf_statics  builtins;
+unsigned char  is_builtins_instantiated;
+
+const wchar_t* str_etch_runtime_exception;
+const wchar_t* str_etch_auth_exception;        
+const wchar_t* str_exception; 
+const wchar_t* str_etch_list; 
+const wchar_t* str_etch_map;
+const wchar_t* str_etch_set;
+const wchar_t* str_etch_datetime; 
+
+const wchar_t* str_msg;
+const wchar_t* str_message_id; 
+const wchar_t* str_in_reply_to; 
+const wchar_t* str_result; 
+
+const wchar_t* str_utf8; 
+const wchar_t* str_keys; 
+const wchar_t* str_values;  
+const wchar_t* str_date_time;
+const wchar_t* str_keys_values;
+
+const wchar_t* str_msgizervf;
+const wchar_t* str_msgizerfmt;
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * constructors/destructors
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * new_default_value_factory()
+ * constructor for default_value_factory
+ * @param typemap the types map. if caller supplies this object, caller
+ * retains ownership, unless vf.is_own_types flag is subsequently set false.
+ * @param c2tmap the class to type map. if caller supplies this object, caller
+ * retains ownership, unless vf.is_own_class_to_type flag is subsequently set false.
+ */
+default_value_factory* new_default_value_factory(vf_idname_map* typemap, class_to_type_map* c2tmap)
+{
+    return new_default_value_factory_ex(sizeof(default_value_factory), typemap, c2tmap);
+}
+
+/**
+ * destroy_default_value_factory()
+ * destructor for default_value_factory
+ */
+int destroy_default_value_factory(void* data)  
+{   
+    default_value_factory* vf = (default_value_factory*)data;
+
+    if (!is_etchobj_static_content(vf))
+    {   
+        etch_object_destroy(vf->mixins);
+        etch_object_destroy(vf->impl);
+    }
+
+   return destroy_objectex((etch_object*) vf);
+}
+
+/**
+ * new_default_value_factory_ex()
+ * constructor for default_value_factory
+ * @param objsize the size of the value factory
+ * @param typemap the types map. if caller supplies this object, caller
+ * retains ownership, unless vf.is_own_types flag is subsequently set false.
+ * @param c2tmap the class to type map. if caller supplies this object, caller
+ * retains ownership, unless vf.is_own_class_to_type flag is subsequently set false.
+ */
+default_value_factory* new_default_value_factory_ex(const int objsize, vf_idname_map* typemap, class_to_type_map* c2tmap)
+{
+    i_value_factory*        vtab    = NULL;
+    default_value_factory*  newvf   = NULL;
+
+    ETCH_ASSERT("typemap==NULL" && typemap);
+    ETCH_ASSERT("c2tmap==NULL" && c2tmap);
+    
+    newvf = (default_value_factory*) new_value_factory(objsize);
+    ((etch_object*)newvf)->destroy = destroy_default_value_factory;
+
+    vtab = (i_value_factory*)((etch_object*)newvf)->vtab;
+    vtab->add_type              = defvf_add_type;
+    vtab->export_custom_value   = defvf_export_custom_value;
+    vtab->get_custom_struct_type= defvf_get_custom_struct_type;
+    vtab->get_in_reply_to       = defvf_get_in_reply_to;
+    vtab->get_message_id        = defvf_get_message_id;
+    vtab->get_string_encoding   = defvf_get_string_encoding;
+    vtab->get_type_by_id        = defvf_get_type_by_id;
+    vtab->get_type_by_name      = defvf_get_type_by_name;
+    vtab->get_types             = defvf_get_types;
+    vtab->import_custom_value   = defvf_import_custom_value;
+    vtab->set_in_reply_to       = defvf_set_in_reply_to;
+    vtab->set_message_id        = defvf_set_message_id;
+
+    newvf->mixins = new_vf_mixin_collection(newvf);
+    newvf->types = typemap;
+    newvf->class_to_type = c2tmap;
+    return newvf;
+}
+
+
+
+int
+defvf_initialize_static(vf_idname_map* typemap, class_to_type_map* c2tmap){
+    int result = 0;
+    
+    struct i_hashtable* vtab =((struct i_hashtable*)((etch_object*)typemap)->vtab);
+
+    etchvf_instantiate_builtins();
+    
+    vtab->inserth
+        (typemap->realtable, builtins._mt__etch_runtime_exception, NULL,typemap, 0); 
+    vtab->inserth
+        (typemap->realtable, builtins._mt__etch_auth_exception, NULL,typemap, 0); 
+    vtab->inserth
+        (typemap->realtable, builtins._mt__exception, NULL,typemap, 0); 
+    vtab->inserth
+        (typemap->realtable, builtins._mt__etch_list, NULL,typemap, 0);
+    vtab->inserth
+        (typemap->realtable, builtins._mt__etch_map, NULL,typemap, 0);
+    vtab->inserth
+        (typemap->realtable, builtins._mt__etch_set, NULL,typemap, 0);
+    vtab->inserth
+        (typemap->realtable, builtins._mt__etch_datetime, NULL,typemap, 0);
+
+    etch_serializer_exception_init(builtins._mt__exception, c2tmap);
+    etch_serializer_authxcp_init  (builtins._mt__etch_auth_exception, c2tmap);
+    etch_serializer_rtxcp_init    (builtins._mt__etch_runtime_exception, c2tmap);
+    etch_serializer_list_init     (builtins._mt__etch_list,c2tmap);
+    etch_serializer_map_init      (builtins._mt__etch_map, c2tmap);
+    etch_serializer_set_init      (builtins._mt__etch_set, c2tmap);
+    etch_serializer_date_init     (builtins._mt__etch_datetime, c2tmap);
+    return result;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * vf class methods
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * defvf_add_type()
+ * adds a type to set of types
+ * @param type a non-disposable etch_type object
+ * @return the effective type. if there was a name collision, the existing type
+ * is returned in place of the supplied type, AND the supplied type is destroyed.
+ * this simplifies logic up the line, and is consistent with caller expecting to
+ * relinquish memory management of the type passed.
+ */
+etch_type* defvf_add_type (void* data, etch_type* type) 
+{
+  default_value_factory* vf = (default_value_factory*)data;
+    etch_type *effective_type = type;
+
+    const int result = ((struct i_hashtable*)((etch_object*)vf->types)->vtab)->inserth
+        (vf->types->realtable, type, NULL, vf->types, 0); 
+
+    if (-1 == result)
+        effective_type = defvf_get_type_by_name(vf, type->name);
+
+    if (effective_type != type && NULL != effective_type)
+        destroy_static_type(type);
+
+    if(effective_type == NULL)
+    {
+        ETCH_LOG("etch_default_value_factory", ETCH_LOG_ERROR, "error adding type '%s'\n", type->aname);
+    }
+    return effective_type;   
+}
+
+
+/**
+ * get_idname_by_id()
+ * given a id_name map and a numeric id, return the id_name for that key. 
+ * @return a non-disposable *reference*, not a copy, or null if not found.
+ */
+etch_id_name* get_idname_by_id (etch_hashtable* map, const unsigned id)
+{
+    etch_iterator iterator;
+
+	hashtable_getlock(map);
+    set_iterator(&iterator, map, &map->iterable);
+
+    while(iterator.has_next(&iterator))
+    {
+        etch_id_name* this_idname = (etch_id_name*) iterator.current_key;
+		if (this_idname->id == id) {
+			hashtable_rellock(map);
+			return this_idname;
+		}
+        iterator.next(&iterator);
+    }
+	hashtable_rellock(map);
+    return NULL;
+}
+
+
+/**
+ * defvf_get_type_by_id()
+ * @return a non-disposable reference to the type matching the supplied id,
+ * or null if no match. all mixed-in vfs are recursed for a match.
+ */
+etch_type* defvf_get_type_by_id (void* data, const unsigned id)
+{
+  default_value_factory* vf = (default_value_factory*)data;
+    etch_type* type = get_idname_by_id(vf->types, id);
+    if (type) return type;
+
+    if (vf->mixins->count) 
+    {
+        etch_iterator iterator; 
+        set_iterator(&iterator, vf->mixins, &vf->mixins->iterable);
+ 
+        while(iterator.has_next(&iterator))
+        {
+            default_value_factory* mvf 
+                = (default_value_factory*) iterator.current_value;
+
+            if (is_etch_valuefact(mvf) && (mvf != vf))
+            {
+                type = defvf_get_type_by_id(mvf, id);
+                if (type) return type; 
+            }
+
+            iterator.next(&iterator);
+        }
+    }
+
+    return NULL;
+}
+
+
+/**
+ * get_idname_by_name()
+ * given a id_name map and a name string, return the id_name for that name. 
+ * @return a non-disposable *reference*, not a copy, or null if not found.
+ * recall that etch_type and etch_field each are typedefs of etch_id_name. 
+ */
+etch_id_name* get_idname_by_name(etch_hashtable* map, const wchar_t* name)
+{
+    etch_hashitem  hashbucket, *thisitem = &hashbucket; 
+    const unsigned hash = etch_get_wchar_hashkey(name);
+  
+    const int result = ((struct i_hashtable*)((etch_object*)map)->vtab)->findh(map->realtable, hash, map, (void**)&thisitem); 
+ 
+    return result == 0? (etch_id_name*) thisitem->key: NULL;
+}
+
+
+/**
+ * etchtypemap_get_by_name()
+ * given a type map and a name, looks up the type matching that name, 
+ * adding a new type to the map if no match was found.
+ * @return a non-disposable reference to the type matching the supplied  
+ * name, or null if no match.  
+ */
+etch_type* etchtypemap_get_by_name(etch_hashtable* map, const wchar_t* name)
+{
+    etch_type* thistype = get_idname_by_name(map, name);
+
+    if (NULL == thistype) 
+    {
+        /* TODO handle return value */
+        ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth(map->realtable, thistype = new_type(name), NULL, map, 0);
+    }
+       
+    return thistype;
+}
+
+
+/**
+ * defvf_get_type_by_name()
+ * searches vf and all mixed-in vfs for type matching specified name.
+ * @return a non-disposable reference to the type corresponding to 
+ * specified name, or null if no match.
+ */
+etch_type* defvf_get_type_by_name (void* data, const wchar_t* name) 
+{
+  default_value_factory* vf = (default_value_factory*)data;
+    etch_type* type = get_idname_by_name(vf->types, name);
+    if (type) return type;
+
+    if (vf->mixins->count) 
+    {
+        etch_iterator iterator; 
+        set_iterator(&iterator, vf->mixins, &vf->mixins->iterable);
+ 
+        while(iterator.has_next(&iterator))
+        {
+            default_value_factory* mvf 
+                = (default_value_factory*) iterator.current_value;
+
+            if (is_etch_valuefact(mvf) && (mvf != vf)) 
+            {
+                type = defvf_get_type_by_name(mvf, name);
+                if (type) return type; 
+            }
+
+            iterator.next(&iterator);
+        }
+    }
+
+    return NULL;
+}
+
+	
+/**
+ * defvf_get_types()
+ * @return a disposable arraylist of non-disposable references to all types 
+ * resident in this vf, and in all its mixed-in vfs. caller should invoke 
+ * the returned list's destructor, which will destroy the list shell.
+ */
+etch_arraylist* defvf_get_types (void* data)
+{    
+  default_value_factory* vf = (default_value_factory*)data;
+    etch_arraylist* typeslist = get_map_keys(vf->types);
+
+    if (vf->mixins->count) 
+    {
+        int  newmixintypes = 0;
+        etch_iterator iterator; 
+        set_iterator(&iterator, vf->mixins, &vf->mixins->iterable);
+ 
+        while(iterator.has_next(&iterator))
+        {
+            etch_arraylist* mvflist;
+ 
+            default_value_factory* mvf 
+                = (default_value_factory*) iterator.current_value;
+
+            if (is_etch_valuefact(mvf) && (mvf != vf)) 
+            {
+                mvflist = get_map_keys(mvf->types);
+
+                newmixintypes += etch_arraylist_add_from(typeslist, mvflist, etchtypelist_comparator); 
+
+                etch_object_destroy(mvflist);
+            }
+
+            iterator.next(&iterator);
+        }
+    }
+
+    return typeslist; /* caller must dispose */
+}
+
+
+/**
+ * defvf_get_string_encoding()
+ * @returns a non-disposable reference to the encoding type
+ */
+wchar_t* defvf_get_string_encoding (void* data)
+{
+    return (wchar_t*) str_utf8;
+}
+
+
+/**
+ * get_etch_string_encoding()
+ * return etch code indicating current string encoding
+ */
+int get_etch_string_encoding(etch_value_factory* vf)
+{
+    wchar_t* encoding = ((struct i_value_factory*)((etch_object*)vf)->vtab)->get_string_encoding(vf);
+    if (0 == wcscmp(encoding, L"utf-8"))  return ETCH_ENCODING_UTF8; 
+    if (0 == wcscmp(encoding, L"utf-16")) return ETCH_ENCODING_UTF16;
+    return ETCH_ENCODING_ASCII;
+}
+
+
+/**
+ * defvf_get_custom_struct_type()
+ * @return a non-disposable reference to the etch type type corresponding   
+ * to the specified class. invoked recursively via mixed in vfs. 
+ */
+etch_type* defvf_get_custom_struct_type(void* data, const unsigned etchclass)
+{
+  default_value_factory* vf = (default_value_factory*)data;
+    etch_type* type = (etch_type*) etchmap_find(vf->class_to_type, etchclass, 0);
+    if (type) return type;
+
+    if (vf->mixins->count) 
+    {
+        etch_iterator iterator; 
+        set_iterator(&iterator, vf->mixins, &vf->mixins->iterable);
+ 
+        while(iterator.has_next(&iterator))
+        {
+            default_value_factory* mvf 
+                = (default_value_factory*) iterator.current_value;
+                  
+            if (is_etch_valuefact(mvf) && (mvf != vf)) /* ensure no cycle */
+            {
+                type = ((struct i_value_factory*)((etch_object*)mvf)->vtab)->get_custom_struct_type(mvf, etchclass);
+                if (type) break;
+            }
+
+            iterator.next(&iterator);
+        }
+    }
+
+    return type;
+}
+	
+
+/**
+ * defvf_import_custom_value()
+ * get helper method from the struct's type to import the custom value associated
+ * with the type. if found, invoke the method to create the custom object.
+ * @param sv the *disposable* raw key-value pairs read in by tdi,
+ * from which to reconstruct the expected custom value object.
+ * caller relinquishes ownership of this object regardless of outcome.
+ * @return the *disposable* custom object, which must be cast by caller, or null.
+ */
+etch_object* defvf_import_custom_value (void* data, etch_structvalue* sv)
+{  
+    etch_object* custom_value = NULL;
+
+    etch_serializer* impxhelper = etchtype_get_impexphelper(sv->struct_type);
+
+    if (impxhelper)
+        custom_value = impxhelper->import_value(impxhelper, (etch_object*) sv);
+     
+    etch_object_destroy(sv);
+
+    return custom_value;
+}
+
+
+/**
+ * defvf_export_custom_value()
+ * establishes the etch type of the custom struct to be exported to, gets the
+ * export helper method from the type, and invokes that method to do the export.
+ * @param value the custom value object to be exported to a struct for tdo.
+ * caller retains ownership of this object.
+ * @return the exported struct, or null. caller owns the returned struct.
+ */
+etch_structvalue* defvf_export_custom_value(void* data, etch_object* value)
+{
+  default_value_factory* vf = (default_value_factory*)data;
+    etch_type* custom_type = NULL;
+    etch_serializer*  impxhelper = NULL; 
+    etch_structvalue* exported_value = NULL;
+    if (NULL == value) return NULL;
+
+    custom_type = defvf_get_custom_struct_type(vf, ETCHOBJCLASS(value));
+
+    if (NULL == custom_type)
+    {
+        switch(((etch_object*)value)->obj_type)
+        { 
+          case ETCHTYPEB_STRUCTVAL:
+               custom_type = ((etch_structvalue*)value)->struct_type;
+               break;
+          case ETCHTYPEB_EXCEPTION:
+               custom_type = builtins._mt__etch_runtime_exception;
+               break;
+          case ETCHTYPEB_ETCHLIST:
+               custom_type = builtins._mt__etch_list;
+               break;
+          case ETCHTYPEB_ETCHMAP:
+               custom_type = builtins._mt__etch_map;
+               break;
+          case ETCHTYPEB_ETCHSET:
+               custom_type = builtins._mt__etch_set;
+               break;
+        }
+    }
+
+    /* fetch non-disposable helper object from custom type */
+    impxhelper = etchtype_get_impexphelper(custom_type);
+
+    if (impxhelper && value)
+    {   /* export value object to struct */
+        exported_value = (etch_structvalue*) 
+            impxhelper->export_value(impxhelper, value);
+
+        /* changed to not destroy value 6/23, since the tdo itself does not own 
+         * the value, and the export custom value is invoked from tdo write_value. */
+        /* value->destroy(value); */
+    }
+
+    return exported_value;
+}
+
+
+/**
+ * defvf_add_mixin()
+ * add a mixed in value factory to this value factory.
+ * @return 0 or -1.
+ */
+int defvf_add_mixin(default_value_factory* vf, etch_value_factory* mixedin_vf)
+{
+    return etch_arraylist_add(vf->mixins, mixedin_vf);
+}
+
+
+/**
+ * defvf_get_message_id()
+ * valuefactory.get_message_id() implementation.
+ * @return a non-disposable reference to the etch_int64 id object, or null. 
+ */
+etch_int64* defvf_get_message_id (void* data, etch_message* msg)
+{
+    return (etch_int64*) message_get(msg, builtins._mf__message_id);
+}
+
+
+/**
+ * message_get_id32()
+ * get and return message id in 32 bits. used for debugging, logging, etc.
+ */
+unsigned message_get_id32 (etch_message* msg)
+{
+    etch_int64* id64 = (etch_int64*) message_get (msg, builtins._mf__message_id);
+    const int id32 = id64? (unsigned) id64->value: 0;
+    return id32;
+}
+
+
+/**
+ * defvf_set_message_id()
+ * valuefactory.set_message_id() implementation.
+ * @param id a *disposable* etch_int64* wrapping the message id. 
+ * regardless of outcome, caller relinquishes ownership of this object.
+ * @return 0 or -1.
+ */
+int defvf_set_message_id (void* data, etch_message* msg, etch_int64* id)
+{
+    return message_put(msg, clone_field(builtins._mf__message_id), (etch_object*) id); 
+}
+
+
+/**
+ * defvf_get_in_reply_to() 
+ * gets the id of the message to which this message is a reply.
+ * returns a non-disposable reference to an etch_int64*, not a copy, or null.
+ */
+etch_int64* defvf_get_in_reply_to (void* data, etch_message* msg)
+{
+    return (etch_int64*) message_get(msg, builtins._mf__in_reply_to);
+}
+
+
+/**
+ * defvf_set_in_reply_to() 
+ * sets the id of the message to which this message is a reply.
+ * @param id a *disposable* etch_int64* wrapping the message id.  
+ * regardless of outcome, caller relinquishes ownership of this object.
+ * @return 0 or -1.
+ */
+int defvf_set_in_reply_to (void* data, etch_message* msg, etch_int64* id)
+{
+    return message_put (msg, clone_field(builtins._mf__in_reply_to), (etch_object*) id); 
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * vf types collection
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/* 
+ * defvf_typescollection_clear_handler()
+ * callback set to handle freeing of key memory during a clear() of the vf
+ * types collection. such a map owns its content, which consists of both builtin
+ * types, which are marked static, and of user types, which are generally not
+ * marked static. the type's destructor is invoked here; however the destructor
+ * will take no action on the static types (these being freed later when the 
+ * builtins are destroyed. those types which are added as a result of a runtime
+ * get() call, e.g., etchtypemap_get_by_name(vf->types, L"my_newtype"),
+ * are not marked static and so will be destroyed with this map.
+ */
+int defvf_typescollection_clear_handler (void* data1, void* data2)
+{
+    #if(0)
+    etch_type* type = (etch_type*) key;
+    if  (is_etchobj_static_shell(type))     
+         wprintf(L"vf types map NOT destroying %s\n", type->name);
+    else wprintf(L"vf types map destroying %s\n", type->name);
+    fflush(stdout);  
+    #endif
+
+    //key->destroy(key); /* see comments above re static and nonstatic types */
+    return TRUE; 
+}
+ 
+
+/**
+ * new_vf_types_collection()
+ * return a hashtable configured as expected for a set of types 
+ */
+etch_set* new_vf_types_collection(const int initialsize)
+{
+    etch_set* map = new_set(initialsize);  
+    map->content_obj_type = ETCHTYPEB_TYPE;
+    map->content_class_id = CLASSID_ID_TYPE;  
+    map->freehook = defvf_typescollection_clear_handler;
+    return map;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * vf_idname_map
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/* 
+ * defvf_idnmap_clear_handler()
+ * callback set to handle freeing of key memory during a clear() of a vf
+ * id_name map. map keys are etch_field owned by the map. however the map does
+ * not know how to destroy such a key so we handle that here. values in this
+ * map are etch_type owned elsewhere (presumably quasi-static built-in types).
+ */
+int defvf_idnmap_clear_handler (void* data1, void* data2)
+{
+  etch_object* key = (etch_object*)data1;
+    #ifdef ETCH_DEBUG_VF
+    etch_id_name* idn = (etch_id_name*) key;
+    wprintf(L"destroy idn %08x '%s'\n", (size_t) (void*) key, idn->name);
+    #endif
+ 
+    etch_object_destroy(key);
+    return TRUE; 
+}
+ 
+
+/**
+ * new_vf_idname_map()
+ * return a hashtable configured as expected for a vf 
+ * todo lose this method and the clear handler we don't use it 
+ */
+etch_hashtable* new_vf_idname_map(const int initialsize)
+{
+    etch_hashtable* map = new_hashtable(initialsize);  
+    map->is_tracked_memory  = TRUE; 
+    map->is_readonly_keys   = FALSE; /* keys are etch_field* owned by the map */ 
+    map->is_readonly_values = FALSE; /* values are etch_type* owned elsewhere */ 
+    map->content_type       = ETCHHASHTABLE_CONTENT_OBJECT;
+    map->content_obj_type   = ETCHTYPEB_TYPE;
+    map->content_class_id   = CLASSID_ID_TYPE;  
+    map->freehook = defvf_idnmap_clear_handler; /* key memory free hook */
+    return map;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * class_to_type_map
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * class_to_type_map_put()
+ * put the specified type to the supplied map, keyed by specified class.
+ * the map does not own the specified type object.
+ * @return 0 or -1;
+ */
+int class_to_type_map_put(class_to_type_map* map, const unsigned thisclass, 
+    etch_type* type)
+{
+    int hashvalue = etchmap_insert (map, thisclass, type, TRUE);
+    return hashvalue? 0: -1;
+}
+
+
+/**
+ * class_to_type_map_get()
+ * get the type associated with the specified class from the supplied map.
+ * @return a non-disposable reference to the matching type, or null.
+ */
+etch_type* class_to_type_map_get(class_to_type_map* map, const unsigned thisclass) 
+{
+    etch_type* foundobj = (etch_type*) etchmap_find (map, thisclass, NULL);
+    return foundobj;
+}
+
+
+/**
+ * new_class_to_type_map()
+ * class_to_type_map constructor.
+ * such a map associates a "class", which in this context is a 32-bit unsigned
+ * integer whose high 16 bits is the etch object obj_type, and the low 16 bits
+ * the etch object class_id, to an etch_type. 
+ */
+class_to_type_map* new_class_to_type_map(const int initialsize)
+{
+    /* this map calls no etch destructors when destroyed. the key strings are 
+     * freed automatically by the etch_hashtable, and the values are pointers
+     * to etch_type objects owned elsewhere. it obviously follows that this 
+     * map should be destroyed prior to any such referenced type object. 
+     */
+    class_to_type_map* map  = new_hashtable(initialsize);  
+    map->is_tracked_memory  = TRUE; 
+    map->is_readonly_keys   = TRUE; /* keys are strings owned by the hashtable */ 
+    map->is_readonly_values = TRUE; /* values are non-disposable etch_type* */ 
+    map->content_type       = ETCHHASHTABLE_CONTENT_OBJECT;
+    map->content_obj_type   = ETCHTYPEB_TYPE;
+    map->content_class_id   = CLASSID_ID_TYPE;  
+    return map;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - -
+ * built-in (etch-global, quasi-static) objects
+ * - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/* these objects are global to all vfs.
+ * for each such object, a corresponding entry should exist both in 
+ * etchvf_instantiate_builtins(), and in etchvf_free_builtins()
+ */
+const wchar_t* str_etch_runtime_exception = L"_Etch_RuntimeException";   
+const wchar_t* str_etch_auth_exception    = L"_Etch_AuthException";         
+const wchar_t* str_exception     = L"_exception"; 
+const wchar_t* str_etch_list     = L"_Etch_List"; 
+const wchar_t* str_etch_map      = L"_Etch_Map";
+const wchar_t* str_etch_set      = L"_Etch_Set";
+const wchar_t* str_etch_datetime = L"_Etch_Datetime";
+ 
+const wchar_t* str_msg           = L"msg";   
+const wchar_t* str_message_id    = L"_messageId";  
+const wchar_t* str_in_reply_to   = L"_inReplyTo";  
+const wchar_t* str_result        = L"result";
+   
+const wchar_t* str_utf8          = L"utf-8"; 
+const wchar_t* str_keys          = L"keys";    
+const wchar_t* str_values        = L"values";  
+const wchar_t* str_date_time     = L"dateTime";
+const wchar_t* str_keys_values   = L"keysAndValues"; 
+
+const wchar_t* str_msgizervf     = L"Messagizer.valueFactory";
+const wchar_t* str_msgizerfmt    = L"Messagizer.format";
+
+
+/* 
+ * etchvf_free_builtins()
+ * frees memory for etch-global quasi-static builtin objects,
+ * and for the validators cache and its validator content.
+ * it should be invoked at etch teardown, after last vf is destroyed.
+ * unit tests will show memory leaks unless they invoke this post-test.
+ */
+
+void etchvf_free_builtins()
+{
+    if (is_builtins_instantiated)  
+    {
+        destroy_static_type(builtins._mt__etch_runtime_exception);
+        destroy_static_type(builtins._mt__etch_auth_exception);
+        destroy_static_type(builtins._mt__exception);
+        destroy_static_type(builtins._mt__etch_list); 
+        destroy_static_type(builtins._mt__etch_map); 
+        destroy_static_type(builtins._mt__etch_set); 
+        destroy_static_type(builtins._mt__etch_datetime); 
+
+        destroy_static_field(builtins._mf_msg);
+        destroy_static_field(builtins._mf_result);
+        destroy_static_field(builtins._mf__message_id);
+        destroy_static_field(builtins._mf__in_reply_to);
+    }
+
+    etchvtor_clear_cache();  /* destroy cached validators */
+
+    is_builtins_instantiated = FALSE;
+}
+
+
+/**
+ * etchvf_instantiate_builtins()
+ * instantiate built-in objects such as default types and fields.
+ * these singleton objects are destroyed explicitly by invoking  
+ * etchvf_free_builtins().
+ * todo: mark these objects immutable and unmark in destructor.
+ * todo: determine how we handle case of multiple vfs.
+ */
+void etchvf_instantiate_builtins()
+{  
+    if (is_builtins_instantiated) return;
+
+    builtins._mt__etch_runtime_exception = new_static_type(str_etch_runtime_exception);
+    builtins._mt__etch_auth_exception = new_static_type(str_etch_auth_exception);
+    builtins._mt__exception = new_static_type(str_exception);
+    builtins._mt__etch_list = new_static_type(str_etch_list); 
+    builtins._mt__etch_map  = new_static_type(str_etch_map); 
+    builtins._mt__etch_set  = new_static_type(str_etch_set); 
+    builtins._mt__etch_datetime = new_static_type(str_etch_datetime); 
+
+    builtins._mf_msg = new_static_field(str_msg); 
+    builtins._mf_result = new_static_field(str_result); 
+    builtins._mf__message_id  = new_static_field(str_message_id); 
+    builtins._mf__in_reply_to = new_static_field(str_in_reply_to); 
+
+    etchtype_put_validator(builtins._mt__exception, 
+        clone_field(builtins._mf_result), (etch_object*) etchvtor_exception_get());
+    etchtype_put_validator(builtins._mt__exception, 
+        clone_field(builtins._mf__message_id), (etch_object*) etchvtor_int64_get(0));
+    etchtype_put_validator(builtins._mt__exception, 
+        clone_field(builtins._mf__in_reply_to),(etch_object*) etchvtor_int64_get(0));
+
+    is_builtins_instantiated = TRUE;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * other methods
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+	
+/**
+ * etchtypelist_comparator()
+ * etch_comparator comparing two etch_types
+ * hook for arraylist_add_from to determine if a type from list b
+ * already exists in list a.
+ */
+int etchtypelist_comparator(void* a, void* b)
+{
+    return a && b && (((etch_type*)a)->id == ((etch_type*)b)->id);
+}
+
+
+/**
+ * new_vf_mixin_collection()
+ * instantiate and return a collection configured appropriately for the
+ * storage of value factory objects of mixed-in classes.
+ */
+etch_arraylist* new_vf_mixin_collection(void* data)
+{
+  default_value_factory* vf = (default_value_factory*)data;
+    //TODO: eheck if arraylist have to be synchronized
+    etch_arraylist* list = new_etch_arraylist(ETCH_DEVVF_MIXINS_DEFINITSIZE, 0);
+    list->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
+    list->is_readonly  = TRUE; /* list dtor will not destroy list content */
+    list->content_obj_type = ((etch_object*)vf)->obj_type;
+    list->content_class_id = ((etch_object*)vf)->class_id;
+    return list;
+}
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_field.c b/binding-c/runtime/c/src/main/bindings/msg/etch_field.c
new file mode 100644
index 0000000..962e69b
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_field.c
@@ -0,0 +1,74 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * field.c -- methods on the etch_field object.
+ * an etch_field is an etch_id_name representing a field of a struct or message 
+ * (i.e. a key for a value).
+ */
+#include "etch_field.h"
+#include "etch_objecttypes.h"
+
+/** 
+ * an etch_field is for now simply a typedef of etch_id_name.
+ * all its methods except ctor are #defined as those of etch_id_name.
+ */
+
+etch_field* new_field(const wchar_t* name)
+{
+    etchparentinfo* inheritlist = NULL;
+
+    etch_field* newobj = (etch_field*) new_id_name(name);
+    if (NULL == newobj) return NULL;
+    ((etch_object*)newobj)->obj_type = ETCHTYPEB_FIELD;
+    ((etch_object*)newobj)->class_id = CLASSID_ID_FIELD;
+
+    /* fetch cached inheritance list, or create if initial instantiation, 
+     * and ensure id_name parent keys exist in the (one-based) list */
+    inheritlist = get_vtab_inheritance_list((etch_object*)newobj, 2, 1, CLASSID_VTAB_FIELD);
+    ETCH_ASSERT(((etch_object*)newobj)->vtab && ((etch_object*)newobj)->vtab->inherits_from);
+    inheritlist[1].o.obj_type = ((etch_object*)newobj)->obj_type;
+    inheritlist[1].c.class_id = CLASSID_ID_NAME;
+
+    return newobj;
+}
+
+
+/**
+ * new__static_field() 
+ * create a field object whose destructor will have no effect.
+ */
+etch_field* new_static_field(const wchar_t* name)
+{
+    etch_field* newfield = new_field(name);
+    set_etchobj_static_all(newfield);
+    return newfield;
+} 
+
+ 
+/** 
+ * destroy_static_field()
+ * etch_field destructor.
+ * this should not be set as the virtual dtor for a field, since the field
+ * would then not be quasi-static as desired. it should be invoked explicitly
+ */
+int destroy_static_field(etch_field* field)
+{
+    clear_etchobj_static_all(field);
+    return destroy_field(field); 
+} 
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_id_name.c b/binding-c/runtime/c/src/main/bindings/msg/etch_id_name.c
new file mode 100644
index 0000000..e813e32
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_id_name.c
@@ -0,0 +1,234 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * id_name.c
+ * an id_name is a base class for etch_field and etch_type, used to bind
+ * a type or field name to an associated and unique id. the id is used for
+ * certain operations, such as the key in a map, comparisons, wire encoding.
+ * it owns memory for its name, but not necessarily that for its impl.
+ * since the character name is only used internally, not on the wire, 
+ * we are gradually converting this object to use an 8-bit character 
+ * name, primarily to enable type-related logging.
+ */
+
+#include "etch_id_name.h"
+#include "etch_encoding.h"
+#include "etch_map.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+#include <wchar.h>
+
+/**
+ * new_id_name() 
+ * constructor accepting name. id is generated from a hash of the name.
+ * allocates, initializes and returns an etch_id_name*. the specified
+ * name is cloned, thus the etch_id_name owns all its memory (note that
+ * this may not be the case for derived classes such as etch_type).
+ */
+etch_id_name* new_id_name(const wchar_t* name) 
+{
+    etch_id_name* idn = NULL;
+    wchar_t* namecopy = NULL;
+    size_t   bytelen  = 0;
+    int result = 0;
+    if (NULL == name) return NULL;
+
+    idn = (etch_id_name*) new_object
+        (sizeof(etch_id_name), ETCHTYPEB_ID_NAME, CLASSID_ID_NAME);
+
+    ((etch_object*)idn)->destroy = destroy_id_name;
+    ((etch_object*)idn)->clone   = clone_id_name;
+
+    bytelen  = ( wcslen(name) + 1 ) * sizeof(wchar_t);
+    namecopy = etch_malloc(bytelen, ETCHTYPEB_BYTES); 
+    /* wcscpy_s(namecopy, bytelen, name) causes a release build to hang at
+     * shutdown when the string is length 4 or more. let's not use wcscpy_s 
+     * until we can determine the cause. */
+#ifdef WIN32
+    #pragma warning(disable:4996) /* disable nonsecure function warning */
+#endif
+    wcscpy(namecopy, name);
+
+    /* carrying both name versions is first step in the 8-bit conversion */
+    /* etch_unicode_to_utf8() returns us an etch_malloc'ed buffer which we own */
+    // TODO: pool
+    result = etch_encoding_transcode_wchar(&idn->aname, ETCH_ENCODING_UTF8, name, NULL);
+    ETCH_ASSERT(result != -1);
+
+    idn->name = namecopy; /* use wide name to compute hash etc. for now */
+    idn->id = compute_id_name_id_from_widename((wchar_t*)name); 
+    idn->namebytelen = bytelen;
+    ((etch_object*)idn)->get_hashkey = id_name_get_hashkey;
+    ((etch_object*)idn)->get_hashkey((etch_object*)idn);
+
+    return idn;
+}
+
+
+/**
+ * new_id_name_from_8bitname() 
+ * constructor accepting narrow character name. 
+ * name is maintained internally as unicode.  
+ * see comments at new_id_name()
+ * note that this ctor will not be needed after 8-bit conversion.
+ */
+etch_id_name* new_id_name_from_8bitname(char* name)
+{
+    etch_id_name* idn = NULL;
+    int result;
+
+    if (name)
+    {
+        wchar_t* out;
+        // TODO: pool
+        result = etch_encoding_transcode_to_wchar(&out, name, ETCH_ENCODING_UTF8, (unsigned int)strlen(name), NULL);
+        if (result == -1) {
+            return 0;
+        }
+        idn = new_id_name(out);
+        etch_free(out);
+    }
+
+    return idn;
+}
+
+
+/**
+ * clone_id_name() 
+ * copy constructor 
+ */
+void* clone_id_name(void* data) 
+{
+  const etch_id_name* thatidn = (const etch_id_name*)data;
+    etch_id_name* newidn = thatidn? new_id_name (thatidn->name): NULL;
+
+    if (newidn)
+    {   
+        ((etch_object*)newidn)->obj_type = ((etch_object*)thatidn)->obj_type;
+        ((etch_object*)newidn)->class_id = ((etch_object*)thatidn)->class_id;
+    }
+
+    return newidn;
+}
+
+
+/**
+ * destroy_id_name()
+ * destructor for an etch_id_name object.
+ * deallocates all memory allocated for the object and its contents.
+ */
+int destroy_id_name(void* data)
+{
+    etch_id_name* thisp = (etch_id_name*)data;
+    
+    
+    if (!is_etchobj_static_content(thisp))  
+    {
+        etch_object_destroy(thisp->impl); 
+
+        etch_free (thisp->name); 
+        etch_free( thisp->aname);
+    }
+
+    if (!is_etchobj_static_shell(thisp))    
+        etch_free(thisp);
+ 
+    return 0;
+}
+
+
+/**
+ * compute_id_name_id() 
+ * this algorithm and its result must be identical to that of the java binding.  
+ */
+int compute_id_name_id (const char* name)
+{
+    char c, *p = (char*) name;
+    int  h6, i = 0, hash = 5381;
+    const int numchars = (const int) strlen(name);
+
+    for (; i < numchars; i++, p++)
+    {
+    	c  = *p;
+    	h6 = hash << 6;
+    	hash = (h6 << 10) + h6 - hash + c;
+    }
+
+    return hash;
+}
+
+
+/**
+ * compute_id_name_id_from_widename()
+ * see comments at compute_id_name_id()
+ */
+int compute_id_name_id_from_widename (const wchar_t* name)
+{
+    char *cbuf = NULL;
+    int   idname_id = 0;
+    int result;
+
+    // TODO: pool
+    result = etch_encoding_transcode_wchar(&cbuf, ETCH_ENCODING_UTF8, name, NULL);
+    if (-1 == result) return -1;
+    idname_id = compute_id_name_id(cbuf);
+
+    etch_free(cbuf);
+    return idname_id;
+}
+
+
+/**
+ * is_equal_id_names()
+ */
+int is_equal_id_names (etch_id_name* thisx, etch_id_name* thatx)
+{
+    const int result = thisx && thatx 
+      && (((etch_object*)thisx)->class_id == ((etch_object*)thatx)->class_id) && (thisx->id == thatx->id);  
+    return result; 
+}
+
+
+/**
+ * is_good_id_name()
+ * verify that the id_name is complete
+ */
+int is_good_id_name (etch_id_name* p)
+{
+    const int result = p && p->name && p->id && p->namebytelen && ((etch_object*)p)->get_hashkey(p);
+    return result; 
+}
+
+
+/**
+ * id_name_get_hashkey
+ * hashkey computation for an id_name object.
+ * hash key is computed using the name string as hash source.
+ */
+uint32 id_name_get_hashkey (void* data)
+{
+  etch_object* idn = (etch_object*)data;
+    etch_id_name* thisx = (etch_id_name*) idn;
+
+    /* continue to use wide name to compute hash until it is eliminated */
+    idn->hashkey = etch_get_wchar_hashkey(thisx->name);
+
+    return idn->hashkey;
+}
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_id_name_map.c b/binding-c/runtime/c/src/main/bindings/msg/etch_id_name_map.c
new file mode 100644
index 0000000..01653b9
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_id_name_map.c
@@ -0,0 +1,57 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+#include "etch_id_name_map.h"
+#include "etch_hash.h"
+
+struct etch_id_name_map
+{
+    etch_hashtable* ids;
+    etch_hashtable* names;
+};
+
+etch_status_t etch_id_name_map_create(etch_id_name_map** map)
+{
+    return ETCH_ENOTIMPL;
+}
+
+etch_status_t etch_id_name_map_get_by_id(etch_id_name_map* map, int32 id, void** data)
+{
+    return ETCH_ENOTIMPL;
+}
+
+etch_status_t etch_id_name_map_get_by_name(etch_id_name_map* map, const wchar_t* name, void** data)
+{
+    return ETCH_ENOTIMPL;
+}
+
+etch_status_t etch_id_name_map_add(etch_id_name_map* map, int32 id, const wchar_t* name, void* data)
+{
+        return ETCH_ENOTIMPL;
+}
+
+uint32 etch_id_name_map_count(etch_id_name_map* map)
+{
+        return ETCH_ENOTIMPL;
+}
+
+etch_status_t etch_id_name_map_destroy(etch_id_name_map* map)
+{
+        return ETCH_ENOTIMPL;
+}
+
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_message.c b/binding-c/runtime/c/src/main/bindings/msg/etch_message.c
new file mode 100644
index 0000000..93cc84a
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_message.c
@@ -0,0 +1,382 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_message.c
+ * message object
+ */
+
+#include "etch_message.h"
+#include "etch_log.h"
+#include "etch_objecttypes.h"
+
+static const char* LOG_CATEGORY = "etch_message";
+
+
+etch_message* new_message_init(etch_type*, const int);
+
+/**
+ * new_message()  
+ * constructor for etch_message
+ * the value factory is a reference, the type is a copy to be passed through
+ * to the underlying struct, which will then own the type memory.
+ */
+etch_message* new_message (etch_type* type, const int size, etch_value_factory* vf) 
+{
+    etch_message* newmsg = NULL;
+    if (!type || !vf) return NULL;
+
+    newmsg = new_message_init(type, size);
+    if (newmsg == NULL) return NULL;
+
+    newmsg->vf = vf; 
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "creating message %x\n", newmsg);
+    return newmsg;
+}
+
+
+/**
+ * destroy_message()
+ * destructor for etch_message
+ */ 
+int destroy_message (void* data) 
+{
+    etch_message* msg = (etch_message*)data;
+    int result = 0;
+
+    if (!is_etchobj_static_content(msg))
+    {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "destroying message %x\n", msg);
+        result = destroy_structvalue(msg->sv);
+    }
+
+    destroy_objectex((etch_object*)msg);
+    return result;    
+}
+
+/**
+ * new_message_init() 
+ * common initialization on etch_message construction.
+ */
+etch_message* new_message_init(etch_type* type, const int initialsize)
+{
+    etch_message* newmsg = NULL;
+    if (NULL == type) return NULL;
+
+    newmsg = (etch_message*) new_object(sizeof(etch_message), 
+        ETCHTYPEB_MESSAGE, CLASSID_ETCHMESSAGE);
+    
+    ((etch_object*)newmsg)->destroy = destroy_message;
+    newmsg->sv = new_structvalue(type, initialsize);
+
+    return newmsg;
+}
+
+
+
+
+/**
+ * message_remove()
+ * removes an element from the message struct, returning the element.
+ * if the element is found, its key is destroyed, and the object is returned.
+ * caller owns returned object.
+ */ 
+etch_object* message_remove(etch_message* msg, etch_field* key)
+{
+    return structvalue_remove(msg->sv, key);
+}
+
+
+/**
+ * message_put()
+ * insert key/value pair
+ *
+ * @param key an etch_field whose destructor will be invoked when the struct is
+ * destroyed. 
+ *
+ * @param value a *disposable* object which is the value of the key/val pair.
+ * if passed as null, specified key is removed from the message, per java binding.
+ * otherwise this object's destructor will be invoked when its struct is destroyed.
+ *
+ * @return 0 or -1. 
+ * on failure, destructors are invoked here on both key and value.
+ *
+ * remarks: to simplify caller logic under normal circumstances, caller
+ * relinquishes ownership of parameters (other than this of course), regardless
+ * of outcome. should caller wish to retain ownership on failure, the parameter
+ * object could be marked such that the destructor invoked here becomes benign.
+ */ 
+int message_put(etch_message* msg, etch_field* key, etch_object* value) 
+{ 
+    /* on success, struct owns key and value */
+    if (0 == structvalue_put(msg->sv, key, value))
+        return 0;
+
+    etch_object_destroy(value);
+    value = NULL;
+
+    destroy_field(key); /* note we are often passed protected vf keys */
+    return -1; 
+}
+
+
+/**
+ * message_putc()
+ * insert key/value pair and clear value reference
+ *
+ * @param key an etch_field whose destructor will be invoked when the struct is
+ * destroyed. 
+ *
+ * @param value an indirect reference to a *disposable* object which is the value 
+ * of the key/val pair.
+ * caller's reference is nulled out once this object is relinquished; thus caller
+ * can safely test for null and then destroy the object.
+ *
+ * @return 0 or -1. 
+ * on failure, destructors are invoked here on both key and value.
+ *
+ * remarks: to simplify caller logic under normal circumstances, caller
+ * relinquishes ownership of parameters (other than this of course), regardless
+ * of outcome. should caller wish to retain ownership on failure, the parameter
+ * object could be marked such that the destructor invoked here becomes benign.
+ */ 
+int message_putc(etch_message* msg, etch_field* key, void** valref) 
+{ 
+    etch_object* value = NULL;
+
+    if (valref)
+    {   value = (etch_object*) *valref;
+        *valref = NULL;  /* clear caller's reference as we now own value */
+    }
+    
+	if (value){ /* on success, struct owns key and value */
+        if (0 == structvalue_put (msg->sv, key, value)){
+            return 0;
+		}
+	}	
+
+    /* a struct put was not successful so destroy parameter objects */
+    etch_object_destroy(value);
+    value = NULL;
+
+    destroy_field(key);  /* note we are often passed protected vf keys */
+    return -1; 
+}
+
+
+/**
+ * message_get()
+ * fetch value for key.
+ * @return a non-disposable reference to the value, not a copy, or null.
+ */
+etch_object* message_get(etch_message* msg, etch_field* key)
+{
+    etch_object* retobj = NULL;
+
+    if (msg && key && msg->sv)
+        retobj = structvalue_get(msg->sv, key); 
+
+    #if(0)
+    if (NULL == msg || NULL == key || NULL == msg->sv) 
+        return throw_from(EXCPTYPE_ILLEGALARG, ETCHTYPEB_UNDEFINED, 0, 0); 
+    retobj = structvalue_get(msg->sv, key); 
+    #endif
+     
+    return retobj; 
+}
+
+
+/**
+ * message_type()
+ * return etch type of specified message
+ */
+etch_type* message_type(etch_message* msg)
+{
+    return msg && msg->sv? msg->sv->struct_type: NULL;
+}
+
+
+/**
+ * message_aname()
+ * return name of specified message in 8-bit encoding.
+ * @return a reference to the message name, caller does not own it.
+ */
+char* message_aname (etch_message* msg)
+{
+    etch_type* msgtype = message_type(msg);
+    char*  msgname = msgtype && msgtype->aname? msgtype->aname: "";
+    return msgname;
+}
+
+
+/**
+ * message_reply()
+ * creates a message which is a reply to the current message.
+ * the current message's value factory is copied to the new message. 
+ * message id of the current message (if any) is copied into the 
+ * in-reply-to field of the new message.
+ * @param newtype the type of the reply. caller retains ownership.
+ * @return a reply message, which will contain exception if error.
+ */ 
+etch_message* message_reply (etch_message* msg, etch_type* newtype)  
+{
+    int result = -1;
+    etch_int64*   msgid  = NULL;
+    etch_message* newmsg = NULL;
+
+    if (NULL == msg) return NULL;
+
+    if (NULL == newtype) /* use message type's result type */
+        newtype = etchtype_get_result_type (msg->sv->struct_type);
+
+    if (NULL == newtype) return NULL;
+
+    /* construct message. caller retains ownership of type */
+    newmsg = new_message (newtype, 0, msg->vf);  
+
+    msgid  = message_get_id (msg); /* get back a ref to ID or null */
+
+    if (msgid)  
+        result = message_set_in_reply_to (newmsg, ((etch_object*)msgid)->clone(msgid));
+    
+    if (0 != result)
+    {      
+        etch_object_destroy(newmsg);
+        newmsg = NULL;
+    }     
+
+    return newmsg;
+}
+
+
+/**
+ * message_set_id()
+ * sets the message-id field of this message.
+ * @param id a *disposable* long object wrapping the connection specific 
+ * unique identifier of this message, or NULL if the message has not yet
+ * been sent. NOTE that the send process overwrites any value which might 
+ * otherwise be set here.
+ */ 
+int message_set_id(etch_message* msg, etch_int64* id)
+{
+    int  result = 0;
+    if (!id) return -1;       
+
+    /* id object ownership is relinquished here even if the call fails */
+    result = ((struct i_value_factory*)((etch_object*)msg->vf)->vtab)->set_message_id(msg->vf, msg, id);
+    return result;
+}
+
+
+/**
+ * message_get_id()
+ * @return a non-disposable reference to the connection specific unique  
+ * identifier of this message, or null if there was no such identifier. 
+ */ 
+etch_int64* message_get_id(etch_message* msg)
+{
+    etch_int64* id = ((struct i_value_factory*)((etch_object*)msg->vf)->vtab)->get_message_id(msg->vf, msg);
+    return id;
+}
+
+
+/**
+ * message_get_in_reply_to()
+ * @return a non-disposable reference to the message-id of the message that 
+ * this message is a response to, or null if this is an original message 
+ * or if the original message did not have a message-id. 
+ * caller does not own the returned object.
+ */ 
+etch_int64* message_get_in_reply_to(etch_message* msg)
+{
+    /* vf returns to us a reference to its value */
+    etch_int64* id = ((struct i_value_factory*)((etch_object*)msg->vf)->vtab)->get_in_reply_to(msg->vf, msg);
+    return id;
+}
+
+
+/**
+ * message_set_in_reply_to()
+ * sets the in-reply-to field of this message.
+ * @param msgid a *disposable* long object wrapping the message-id of the 
+ * message that this message is a response to. note that caller must clone 
+ * or otherwise supply a disposable object as this parameter.  
+ */ 
+int message_set_in_reply_to(etch_message* msg, etch_int64* msgid)
+{
+    int result = 0;
+    if (!msgid) return -1;       
+
+    /* msgid ownership is relinquished here even if the call fails */
+    result = ((struct i_value_factory*)((etch_object*)msg->vf)->vtab)->set_in_reply_to(msg->vf, msg, msgid);
+    return result;
+}
+
+
+/**
+ * message_size()
+ */ 
+
+int message_size (etch_message* msg) 
+{
+    return msg? structvalue_count(msg->sv): 0;
+}
+
+
+/* - - - - - - - - - - -
+ * etch_unwanted_message
+ * - - - - - - - - - - -
+ */
+  
+/**
+ * destroy_unwanted_message()
+ * etch_unwanted_message destructor
+ */
+int destroy_unwanted_message(void* data)
+{
+    etch_unwanted_message* msg = (etch_unwanted_message*)data;
+    
+    if (msg->message != NULL && !is_etchobj_static_content(msg))
+    {   
+        msg->message->sv->items->is_readonly_keys = 0;
+        msg->message->sv->items->is_readonly_values = 0;
+        etch_object_destroy(msg->message);
+    }
+
+   return destroy_objectex((etch_object*) msg);
+}
+
+
+/**
+ * new_unwanted_message()
+ * etch_unwanted_message constructor
+ * @param whofrom caller retains
+ * @param msg caller relinquishes
+ */
+etch_unwanted_message* new_unwanted_message(etch_who* whofrom, etch_message* msg)
+{
+   etch_unwanted_message* newmsg = (etch_unwanted_message*) new_object
+     (sizeof(etch_unwanted_message), ETCHTYPEB_EVENT, CLASSID_EVENT_UNWANTMSG);
+
+    ((etch_object*)newmsg)->destroy = destroy_unwanted_message;
+    ((etch_object*)newmsg)->clone   = clone_null;
+
+    newmsg->message = msg;
+    newmsg->whofrom = whofrom;
+    return newmsg;
+}
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_structval.c b/binding-c/runtime/c/src/main/bindings/msg/etch_structval.c
new file mode 100644
index 0000000..ca0790c
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_structval.c
@@ -0,0 +1,256 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*  
+ * etch_structval.c -- etch_structvalue implementation.
+ */
+
+#include "etch_runtime.h"
+#include "etch_structval.h"
+#include "etch_validator.h"
+#include "etch_encoding.h"
+#include "etch_exception.h"
+#include "etch_map.h"
+#include "etch_log.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+
+char* ETCHSVAL = "SVAL";
+
+etch_structvalue* new_structvalue_init();
+
+/* 
+ * structvalue_clear_handler()
+ * this callback is set to handle freeing of key and value memory during a clear()
+ * of the structvalue map. structs own all their memory, so if there is a problem
+ * here, it should be resolved at the source, not by modifying this code.
+ */
+int structvalue_clear_handler (void* data1, void* data2)
+{
+    etch_field* key = (etch_field*)data1;
+    etch_object* value = (etch_object*)data2;
+    etch_object_destroy(value);
+	destroy_field(key);
+    return TRUE;
+}
+
+
+
+/**
+ * new_structvalue()  
+ * primary constructor for etch_structvalue. 
+ * @param etch_type object, caller retains ownership of the type as usual
+ */
+etch_structvalue* new_structvalue(etch_type* type, const int initialsize)
+{
+    etch_structvalue* newobj = new_structvalue_init(initialsize);
+
+    newobj->struct_type = type;
+
+    return newobj;
+}
+
+
+/**
+ * destroy_structvalue()
+ * destructor for an etch_structvalue object
+ *
+ * a structvalue owns all its memory *except* its type object, which is global  
+ * to the vf. this means that (a) the etch_type supplied on construction must be   
+ * a reference to a type owned by the service vf (or the unit test); and (b) all 
+ * struct keys must be etch_field* allocated on the heap and not referenced again 
+ * outside of that structvalue scope; and (c) all struct values must be etch object
+ * references allocated on the heap and not referenced again outside of the 
+ * structvalue scope.
+ */
+int destroy_structvalue(void* data) 
+{
+    etch_structvalue* thisp = (etch_structvalue*)data;
+    if (NULL == thisp) return 0;
+    
+        
+    if (!is_etchobj_static_content(thisp)){
+        etch_object_destroy(thisp->items);
+		thisp->items = NULL;
+	}
+
+    /* see comments above as to why we don't destroy type */
+
+    destroy_objectex((etch_object*)thisp);   
+    return 0;
+}
+
+
+/**
+ * new_structvalue_init() (private)
+ * common initialization on etch_structvalue construction.
+ */
+etch_structvalue* new_structvalue_init(const int initialsize)
+{
+    etch_structvalue* newobj = etch_malloc(sizeof(etch_structvalue), ETCHTYPEB_STRUCTVAL);
+    memset(newobj, 0, sizeof(etch_structvalue));
+    ((etch_object*)newobj)->obj_type = ETCHTYPEB_STRUCTVAL;
+    ((etch_object*)newobj)->class_id = CLASSID_STRUCTVALUE; /* for now anyway */
+
+    ((etch_object*)newobj)->destroy = destroy_structvalue;
+    ((etch_object*)newobj)->clone   = clone_null;
+
+    newobj->items = new_structvalue_hashtable(initialsize);
+    /* mark map such that it knows its keys and values are etch objects */
+    newobj->items->content_type = ETCHHASHTABLE_CONTENT_OBJECT_OBJECT;
+
+    return newobj;
+}
+
+
+
+
+
+/*  
+ * new_structvalue_hashtable
+ * create the backing store for a struct value
+ */
+etch_hashtable* new_structvalue_hashtable(const int initialsize) 
+{    
+    etch_hashtable* ht = new_hashtable(initialsize);  
+    if (ht == NULL) return NULL;
+    ht->content_type       = ETCH_STRUCT_DEFAULT_CONTENT_TYPE;
+    ht->is_tracked_memory  = ETCH_STRUCT_DEFAULT_TRACKED_MEM;
+    ht->is_readonly_keys   = ETCH_STRUCT_DEFAULT_READONLY_KEY;
+    ht->is_readonly_values = ETCH_STRUCT_DEFAULT_READONLY_VAL;
+    ht->freehook = structvalue_clear_handler;
+    return ht;
+}
+
+
+/**
+ * structvalue_put()
+ * inserts (or removes) specified key/value pair to/from struct store.
+ * @param key an etch_field whose destructor will be invoked when the struct is
+ * destroyed. presumably this etch_field is disposable; if not, the object must
+ * be marked as immutable using set_etchobj_static_all.
+ * @param value a *disposable* object which is the value of the key/val pair.
+ * this object's destructor will be invoked when the struct is destroyed.
+ * presumably this object and its content are disposable; if not, the object must
+ * be marked accordingly using set_etchobj_static_all or set_etchobj_static_content.
+ * returns 0 or -1.
+ */
+int structvalue_put(etch_structvalue* thisp, etch_field* key, etch_object* value) 
+{   
+    etch_config_t*  config    = NULL;
+    int32           propvalue = 0;
+    etch_hashtable* map       = NULL;
+
+    etch_runtime_get_config(&config);
+    ETCH_ASSERT(config);
+
+    map = thisp->items;
+    if (NULL == key) return -1;
+
+    if (NULL == value)  /* per contract, no value implies removal desired */
+        return ((struct i_hashtable*)((etch_object*)map)->vtab)->removeh (map->realtable, ((etch_object*)key)->get_hashkey(key), key, 0);
+
+    etch_config_get_property_int(config, "etch.validate.write", &propvalue);
+    if(propvalue == 1) {
+        etch_type* thistype = thisp->struct_type;
+        char *errmsg = NULL;
+
+        etch_validator* vtor = (etch_validator*)
+            etchtype_get_validator_by_name(thistype, key->name);
+
+        if (NULL == vtor)
+            errmsg = "validator missing";
+        else
+        if (0 != vtor->validate (vtor, (etch_object*) value))
+            errmsg = "validation failed";
+
+        if (errmsg)
+        {   ETCH_LOG(ETCHSVAL, ETCH_LOG_ERROR, "%s for type '%s' field '%s'\n", errmsg, thistype->aname, key->aname);
+            return -1;
+        }
+    }
+    return ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth (map->realtable, key, value, map, 0);    
+}
+
+
+/**
+ * structvalue_get()
+ * access an element from the struct.
+ * returns a reference not a copy.
+ */
+etch_object* structvalue_get (etch_structvalue* thisp, etch_field* key) 
+{
+    int  result = 0;
+    etch_hashitem   hashbucket;
+    etch_hashitem*  thisitem = &hashbucket; 
+    etch_hashtable* map = thisp? thisp->items: NULL;
+    if (NULL == map) return NULL;
+
+    result = ((struct i_hashtable*)((etch_object*)map)->vtab)->findh(map->realtable, ((etch_object*)key)->get_hashkey(key), map, (void**)&thisitem);
+    
+    return result == 0? thisitem->value: NULL;
+}
+
+
+/**
+ * structvalue_remove
+ * removes an element from the struct, returning the element.
+ * if the element is found, its key is destroyed, and the object is returned.
+ * caller owns returned object.
+ */
+etch_object* structvalue_remove(etch_structvalue* thisp, etch_field* key) 
+{
+    int  result = 0;
+    etch_hashitem   hashbucket;
+    etch_hashitem*  thisitem = &hashbucket; 
+    etch_hashtable* map = thisp? thisp->items: NULL;
+    memset(thisitem,0,sizeof(etch_hashitem));
+    if (NULL == map) return NULL;
+
+    /* remove specified item from hashtable without destroying content */
+    result = ((struct i_hashtable*)((etch_object*)map)->vtab)->removeh(map->realtable, ((etch_object*)key)->get_hashkey(key), map, (void**)&thisitem);
+    if (-1 == result) return NULL;
+
+    /* free entry key */
+    if (thisitem->key) 
+        if  (etchmap_is_object_key(map))
+            ((etch_object*)thisitem->key)->destroy(thisitem->key);
+        else etch_free(thisitem->key);
+    
+    return (etch_object*) thisitem->value;
+}
+
+
+/**
+ * structvalue_is_type()
+ * indicates if type of this struct is the same as the specified type
+ */
+int structvalue_is_type(etch_structvalue* thisp, etch_type* type)
+{
+    return is_equal_types(thisp->struct_type, type);
+}
+
+
+/**
+ * structvalue_count()
+ * returns number of pairs in the struct
+ */
+int structvalue_count(etch_structvalue* sv)
+{
+    return etchmap_count(sv->items);
+}
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_tagdata.c b/binding-c/runtime/c/src/main/bindings/msg/etch_tagdata.c
new file mode 100644
index 0000000..5029300
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_tagdata.c
@@ -0,0 +1,604 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*  
+ * etch_tagdata.c -- tagged data implementation.
+ */
+
+#include "etch_tagged_data.h"
+#include "etch_type.h"
+#include "etch_arrayval.h"
+#include "etch_nativearray.h"
+#include "etch_objecttypes.h"
+
+
+/* the only instance data in the java version is the value factory 
+ * for C, inheritors can implement that, in order that we don't need
+ * any instance data here and can just implement methods. 
+ */
+
+/*
+ * etchtagdata_get_number()
+ * java.Lang.Number emulation support.
+ * given an anonymous wrapped primitive, return its value represented as
+ * a 64-bit integer.
+ */
+int etchtagdata_get_number(etch_object* valobj, 
+    const double fmin, const double fmax, int64* out)
+{
+    int64 longval = 0;
+    double dval;
+    if (!is_etch_primitive_number(valobj)) return -1; 
+
+    switch(((etch_object*)valobj)->class_id)
+    { 
+        case CLASSID_PRIMITIVE_INT32:
+             longval = ((etch_int32*)valobj)->value;
+             break; 
+
+        case CLASSID_PRIMITIVE_INT64:
+             longval = ((etch_int64*)valobj)->value;
+             break;
+
+        case CLASSID_PRIMITIVE_BYTE:
+        case CLASSID_PRIMITIVE_BOOL: 
+        case CLASSID_PRIMITIVE_INT8: 
+             longval = ((etch_byte*)valobj)->value;
+             break;
+
+        case CLASSID_PRIMITIVE_INT16:
+             longval = ((etch_int16*)valobj)->value;
+             break;
+         
+        case CLASSID_PRIMITIVE_DOUBLE: 
+        case CLASSID_PRIMITIVE_FLOAT:  
+        {   
+            switch(((etch_object*)valobj)->class_id)
+            { case CLASSID_PRIMITIVE_DOUBLE:
+                   dval = ((etch_double*)valobj)->value;
+                   break;
+              case CLASSID_PRIMITIVE_FLOAT:
+                   dval = (double) ((etch_float*)valobj)->value;
+                   break;
+            }
+
+            /* round ieee value if necessary */
+            if (dval >= 0.0 && dval <= fmax) 
+                dval += 0.5;
+            else
+            if (dval  < 0.0 && dval >= fmin)
+                dval -= 0.5;
+
+            longval = (int64) dval;   
+            break;
+        }
+    }
+
+    *out = longval;
+    return 0;
+}
+
+
+/*
+ * etchtagdata_get_fnumber()
+ * java.Lang.Number emulation support.
+ * given an anonymous wrapped primitive, return its value represented as
+ * an IEEE number of 64 bits.
+ */
+int etchtagdata_get_double_number(etch_object* valobj,  
+    const double fmin, const double fmax, double* outd)
+{
+    float fval = 0.0; double dval = 0.0; int64 longval = 0;
+
+    if (-1 == etchtagdata_get_number(valobj, fmin, fmax, &longval))
+        return -1;
+  
+    switch(((etch_object*)valobj)->class_id)
+    { 
+        case CLASSID_PRIMITIVE_DOUBLE: 
+           dval = ((etch_double*)valobj)->value; 
+           break;
+
+        case CLASSID_PRIMITIVE_FLOAT:  
+            fval = ((etch_float*)valobj)->value;
+            dval = (double) fval;
+            break;
+
+        default:
+            dval = (double) longval;
+    }
+
+    *outd = dval;
+    return 0;
+}
+
+
+/*
+ * etchtagdata_get_float_number()
+ * java.Lang.Number emulation support.
+ * given an anonymous wrapped primitive, return its value represented as
+ * an IEEE number of 32 bits.
+ */
+int etchtagdata_get_float_number(etch_object* valobj,
+    const double fmin, const double fmax, float* outf)
+{
+    float fval = 0.0; double dval = 0.0; int64 longval = 0;
+
+    if (-1 == etchtagdata_get_number(valobj, fmin, fmax, &longval))
+        return -1;
+   
+    switch(((etch_object*)valobj)->class_id)
+    { 
+        case CLASSID_PRIMITIVE_DOUBLE: 
+           dval = ((etch_double*)valobj)->value; 
+           fval = (float) dval;
+           break;
+
+        case CLASSID_PRIMITIVE_FLOAT:  
+            fval = ((etch_float*)valobj)->value;
+            break;
+
+        default:
+            fval = (float) longval;
+    }
+
+    *outf = fval;
+    return 0;
+}
+
+
+/*
+ * etchtagdata_byte_value()
+ * mimic java.Lang.Number.byteValue()
+ */
+int etchtagdata_byte_value(etch_object* valobj, byte* out)
+{
+    int64 longval = 0;
+
+    const int result = etchtagdata_get_number(valobj, 0, 0, &longval);
+
+    if (0 == result && out) 
+       (*out) = (byte) longval;  /* truncate and return value */
+ 
+    return result;  
+}
+
+
+/*
+ * etchtagdata_bool_value()
+ * if there was a java.Lang.Number.booleanValue(), this would mimic it
+ */
+int etchtagdata_bool_value(etch_object* valobj, boolean* out)
+{
+    int64 longval = 0;
+
+    const int result = etchtagdata_get_number(valobj, 0, 0, &longval);
+
+    if (0 == result && out) 
+    {   
+        if (longval != 1) {
+            *out = 1;
+        }
+        else {
+            *out = 0;
+        }
+    } 
+ 
+    return result;  
+}
+
+
+/*
+ * etchtagdata_int16_value()
+ * mimic java.Lang.Number.shortValue()
+ */
+int etchtagdata_int16_value(etch_object* valobj, short* out)
+{
+    int64 longval = 0;
+
+    const int result = etchtagdata_get_number(valobj, 0, 0, &longval);
+
+    if (0 == result && out) 
+       (*out) = (short) longval;  /* truncate and return value */
+ 
+    return result;
+}
+
+
+/*
+ * etchtagdata_int32_value()
+ * mimic java.Lang.Number.intValue()
+ */
+int etchtagdata_int32_value(etch_object* valobj, int* out)
+{
+    int64 longval = 0;
+
+    const int result = etchtagdata_get_number(valobj, 0, 0, &longval);
+
+    if (0 == result && out) 
+       (*out) = (int) longval;  /* truncate and return value */
+ 
+    return result;
+}
+
+
+/*
+ * etchtagdata_int64_value()
+ * mimic java.Lang.Number.longValue()
+ */
+int etchtagdata_int64_value(etch_object* valobj, int64* out)
+{
+    int64 longval = 0;
+
+    const int result = etchtagdata_get_number(valobj, 0, 0,  &longval);
+
+    if (0 == result && out) 
+       (*out) = longval; 
+ 
+    return result;
+}
+
+
+/*
+ * etchtagdata_float_value()
+ * mimic java.Lang.Number.floatValue()
+ */
+int etchtagdata_float_value(etch_object* valobj, float* out)
+{
+    const static double ETCHTYPE_MAX_FLOATF = ETCHTYPE_MAX_FLOAT + 0.4999;
+    const static double ETCHTYPE_MIN_FLOATF = ETCHTYPE_MIN_FLOAT - 0.4999;
+    float floatval = 0.0;
+
+    const int result = etchtagdata_get_float_number(valobj, 
+          ETCHTYPE_MIN_FLOATF, ETCHTYPE_MAX_FLOATF, &floatval);
+
+    if (0 == result && out) 
+       (*out) = floatval; 
+ 
+    return result;
+}
+
+
+/*
+ * etchtagdata_double_value()
+ * mimic java.Lang.Number.doubleValue()
+ */
+int etchtagdata_double_value(etch_object* valobj, double* out)
+{
+    double dval = 0.0;
+
+    const int result = etchtagdata_get_double_number(valobj, 
+          ETCHTYPE_MIN_DOUBLE, ETCHTYPE_MAX_DOUBLE, &dval);
+
+    if (0 == result && out) 
+       (*out) = dval; 
+ 
+    return result;
+}
+
+
+/*
+ * etchtagdata_adjust_tiny_int()
+ * if target value is one byte and value is in range of tiny int,
+ * adjust the type code accordingly, returning it in out parameter
+ */
+int etchtagdata_adjust_tiny_int(const signed char target_type, etch_object* valobj, signed char* out)
+{
+    signed char type_out = target_type;
+    signed char byteval = 0;
+    int result = 0;
+
+    if (target_type == ETCH_XTRNL_TYPECODE_BYTE) {
+        if (0 == (result = etchtagdata_byte_value(valobj, (byte*)&byteval))) {
+            if (is_inrange_tiny_for_signed_chars(byteval)) {
+                type_out = byteval; 
+	    }
+        }
+    }
+    if (out) {
+        (*out = type_out);
+    }
+    return result;
+}
+
+
+/*
+ * etchtagdata_validate_value()
+ * in java binding this is checkValue(object, validator);
+ * defers to validator to determine type code for the value.
+ * adjusts the type to tiny integer if applicable and possible.
+ * returns the type code in the out parameter.
+ */
+int etchtagdata_validate_value(etch_object* valobj, etch_validator* vtor, signed char* out)
+{
+    signed char xtype = 0;
+    int result = 0;
+
+    if (NULL == valobj) {
+        xtype = ETCH_XTRNL_TYPECODE_NULL;
+    } else {
+        if (etchtagdata_is_eod(valobj)) {
+            xtype = ETCH_XTRNL_TYPECODE_NONE;
+	} else {
+	    if (0 == (result = vtor->check_value(vtor, valobj, (byte*)&xtype)))  {
+                result = etchtagdata_adjust_tiny_int(xtype, valobj, &xtype);
+	    }
+	}
+    }
+    if (out) {
+        (*out = xtype);
+    }
+    return result;
+}
+
+
+/**
+ * etchtagdata_check_value()
+ * returns a type code for the specified value
+ * @param valobj an etch value object, caller retains ownership.
+ */
+signed char etchtagdata_check_value (etch_object* valobj)
+{
+    signed char xtype = 0;
+    const unsigned int obj_type = valobj? ((etch_object*)valobj)->obj_type: 0;
+    const unsigned int class_id = valobj? ((etch_object*)valobj)->class_id: 0;
+
+    if (NULL == valobj)
+        xtype = ETCH_XTRNL_TYPECODE_NULL;
+    else
+    if (etchtagdata_is_eod(valobj))
+        xtype = ETCH_XTRNL_TYPECODE_NONE; 
+    else
+    if (is_etch_primitive(valobj))
+    {
+        switch(class_id)
+        {
+           case CLASSID_PRIMITIVE_INT32:  
+                 xtype = etchtagdata_check_integer(((etch_int32*)valobj)->value);
+                 break;
+            case CLASSID_PRIMITIVE_INT16:  
+                 xtype = etchtagdata_check_short(((etch_int16*)valobj)->value);
+                 break;
+            case CLASSID_PRIMITIVE_INT64:  
+                 xtype = etchtagdata_check_long(((etch_int64*)valobj)->value);
+                 break;
+            case CLASSID_PRIMITIVE_BYTE: 
+            case CLASSID_PRIMITIVE_INT8:  
+                 xtype = etchtagdata_check_byte(((etch_byte*)valobj)->value);     
+                 break;
+            case CLASSID_PRIMITIVE_DOUBLE:
+                 xtype = ETCH_XTRNL_TYPECODE_DOUBLE; 
+                 break;      
+            case CLASSID_PRIMITIVE_FLOAT: 
+                 xtype = ETCH_XTRNL_TYPECODE_FLOAT;
+                 break;                 
+            case CLASSID_PRIMITIVE_BOOL:  
+                 xtype = ((etch_boolean*)valobj)->value?   
+                     ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE:  
+                     ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE;  
+                 break; 
+           case CLASSID_STRING:         
+                 xtype = ((etch_string*)valobj)->char_count == 0?
+                     ETCH_XTRNL_TYPECODE_EMPTY_STRING:
+                     ETCH_XTRNL_TYPECODE_STRING;     
+                 break;
+            default: 
+                 xtype = ETCH_XTRNL_TYPECODE_CUSTOM;   
+                 break;
+        }  /* switch(class_id) */
+    }    
+    else switch(obj_type)
+    { 
+        case ETCHTYPEB_STRUCTVAL:
+             xtype = ETCH_XTRNL_TYPECODE_CUSTOM;   
+             break;
+        case ETCHTYPEB_ARRAYVAL:
+             xtype = ((etch_arrayvalue*)valobj)->content_obj_type == ETCHTYPEB_BYTE?
+                 ETCH_XTRNL_TYPECODE_BYTES: ETCH_XTRNL_TYPECODE_ARRAY;  
+             break;
+        case ETCHTYPEB_NATIVEARRAY:
+             if(((etch_nativearray*)valobj)->numdims > 1) {
+                 xtype = ETCH_XTRNL_TYPECODE_ARRAY;
+                 break;
+             }
+             xtype = ((etch_nativearray*)valobj)->content_obj_type == ETCHTYPEB_BYTE?
+                 ETCH_XTRNL_TYPECODE_BYTES: ETCH_XTRNL_TYPECODE_ARRAY;   
+             break;
+        default: 
+             xtype = ETCH_XTRNL_TYPECODE_CUSTOM;   
+    }
+    
+    return xtype;
+}
+
+
+/*
+ * etchtagdata_get_native_typecode()
+ * returns the external type code corresponding to internal type.
+ * see etch_binary_tdi.c for implementation
+ */
+byte etchtagdata_get_native_typecode
+    (const unsigned short obj_type, const unsigned short class_id)
+{
+    return ETCH_XTRNL_TYPECODE_NONE;
+}
+
+
+/*
+ * etchtagdata_get_native_type()
+ * returns the internal type and class ids corresponding to external typecode.
+ * see etch_binary_tdi.c for implementation
+ */
+unsigned etchtagdata_get_native_type (const byte typecode) 
+{
+    return (CLASSID_NONE << 16) | ETCHTYPEB_NONE;
+}
+
+
+/*
+ * etchtagdata_get_custom_structtype()
+ * returns a struct type for the specified class
+ * see etch_binary_tdi for implementation
+ */
+etch_type* etchtagdata_get_custom_structtype (etch_object* thisx, 
+   const unsigned short obj_type, const unsigned short class_id)
+{
+    /* we will return a non-disposable (static) type */
+    etch_type* type = NULL; 
+    return type;    
+}
+
+
+
+
+/**
+ * etchtagdata_from_arrayvalue()
+ * return an etch_nativearray representation of the specified etch_arrayvalue.
+ * note that an arrayvalue, if created from an etch_nativearray, has retained 
+ * the source nativearray as an instance member. is_force indicates if caller
+ * wants to build the nativearray regardless of whether one currently exists.
+ */
+etch_nativearray* etchtagdata_from_arrayvalue(etch_arrayvalue* av, const int is_force)
+{
+    if (av->natarray && !is_force) return av->natarray;
+    return (-1 == arrayvalue_to_nativearray(av))? NULL: av->natarray;    
+}
+
+
+/**
+ * etchtagdata_alloc_arrayvalue()
+ * creates and returns an empty arrayvalue object. this method is here for
+ * for compatibility with the java binding, however it is superfluous.
+ * we can safely substitute the new_arrayvalue call below and lose this method. 
+ */
+etch_arrayvalue* etchtagdata_alloc_arrayvalue(const byte type_code, 
+    etch_type* custom_struct_type, const int dim, const int initsize)
+{
+     return new_arrayvalue(type_code, custom_struct_type, dim, 
+        initsize, initsize, FALSE, ETCHARRAYLIST_SYNCHRONIZED);
+}
+
+
+/*
+ * etchtagdata_check_byte()
+ */
+signed char etchtagdata_check_byte(const signed char val) 
+{
+    byte result = ETCH_XTRNL_TYPECODE_BYTE;
+    if (is_inrange_tiny_for_signed_chars(val))
+        result = val;   
+    return result;
+}  
+
+
+/*
+ * etchtagdata_check_short()
+ */
+signed char etchtagdata_check_short(const short val) 
+{
+    byte result = ETCH_XTRNL_TYPECODE_SHORT;
+    if (is_inrange_byte(val))
+        result = etchtagdata_check_byte((byte)val);
+    return result;
+}  
+
+
+/*
+ * etchtagdata_check_integer()
+ */
+signed char etchtagdata_check_integer(const int val) 
+{
+    byte result = ETCH_XTRNL_TYPECODE_INT;
+    if  (is_inrange_int16(val)) 
+         result = etchtagdata_check_short((short)val);
+    return result;
+}  
+
+
+/*
+ * etchtagdata_check_long()
+ */
+signed char etchtagdata_check_long(const int64 val) 
+{
+    byte result = ETCH_XTRNL_TYPECODE_LONG;
+    if  (is_inrange_int32(val))
+         result = etchtagdata_check_integer((int)val);
+    return result;
+} 
+
+
+/**
+ * etchtagdata_is_null()
+ * indicate whether this object represents a null value
+ */
+int etchtagdata_is_null(etch_object* obj)
+{
+    return obj == NULL || obj->is_null;
+} 
+
+
+/**
+ * etchtagdata_is_eod()
+ * indicate whether this object is the end of stream sentinel
+ */
+int etchtagdata_is_eod(etch_object* obj)
+{
+    return obj && ((etch_object*)obj)->obj_type == ETCHTYPEB_EODMARK;
+}
+
+
+/**
+ * etchtagdata_new_nullobj()
+ * instantiate and return a logically null object
+ */
+etch_object* etchtagdata_new_nullobj(const int is_static)
+{
+   etch_object* obj = new_nullobj();
+   if (is_static) set_etchobj_static_all(obj);
+   return obj;
+}
+
+
+/**
+ * etchtagdata_new_eodmarker()
+ * instantiate and return an end of data marker object
+ */
+etch_object* etchtagdata_new_eodmarker(const int is_static)
+{
+   etch_object* obj = new_object(sizeof(etch_object), ETCHTYPEB_EODMARK, CLASSID_NONE);
+   if (is_static) set_etchobj_static_all(obj);
+   return obj;
+}
+
+
+/**
+ * etchtagdata_new_emptystring()
+ * instantiate and return an empty string object
+ */
+etch_string* etchtagdata_new_emptystring(const int is_static)
+{
+   etch_string* obj = new_stringw(L"");
+   if (is_static) set_etchobj_static_all(obj);
+   return obj;
+}
+
+
+
+
+
+
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_tagdata_inp.c b/binding-c/runtime/c/src/main/bindings/msg/etch_tagdata_inp.c
new file mode 100644
index 0000000..363d94c
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_tagdata_inp.c
@@ -0,0 +1,185 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*  
+ * etch_tagdata_inp.c -- tagged_data_input implementation.
+ */
+
+#include "etch_tagdata_inp.h"
+#include "etch_cache.h"
+#include "etch_message.h"
+#include "etch_flexbuffer.h"
+#include "etch_arrayval.h"
+#include "etch_objecttypes.h"
+/*
+static const char* LOG_CATEGORY = "etch_tdi";
+*/
+/**
+ * tdi_start_message()
+ */
+etch_message* tdi_start_message(tagged_data_input* tdi)
+{
+    return NULL;
+}
+
+
+etch_message* tdi_read_message(tagged_data_input* tdi, etch_flexbuffer* f)
+{
+    return NULL;
+}
+
+
+/**
+ * tdi_end_message()
+ */
+int tdi_end_message(tagged_data_input* tdi, etch_message* msg)
+{
+    return NULL;
+}
+
+
+/**
+ * tdi_start_struct()
+ */
+etch_structvalue* tdi_start_struct(tagged_data_input* tdi)
+{
+    return NULL;
+}
+
+
+/**
+ * tdi_read_struct()
+ */
+etch_structvalue* tdi_read_struct(tagged_data_input* tdi)
+{
+    return NULL;
+}
+
+
+/**
+ * tdi_end_struct()
+ * ends a struct currently being read
+ */
+int tdi_end_struct(tagged_data_input* tdi, etch_structvalue* sv)
+{
+    return 0;
+}
+
+
+/**
+ * tdi_start_array()
+ * starts reading an array from the stream 
+ */
+etch_arrayvalue* tdi_start_array(tagged_data_input* tdi)
+{
+    return NULL;
+}
+
+
+etch_arrayvalue* tdi_read_array(tagged_data_input* tdi, etch_validator* v)
+{
+    return NULL;
+}
+
+
+/**
+ * tdi_end_array()
+ */
+int tdi_end_array(tagged_data_input* tdi, etch_arrayvalue* x)
+{
+    return 0;
+}
+
+
+/**
+ * destroy_tagged_data_input()
+ */
+int destroy_tagged_data_input(void* data)
+{
+    tagged_data_input* tdi = (tagged_data_input*)data;
+
+    if (!is_etchobj_static_content(tdi))
+        etch_object_destroy(tdi->impl);
+
+    destroy_objectex((etch_object*)tdi);
+    return 0;
+}
+
+
+/**
+ * clone_tagged_data_input()
+ */
+void* clone_tagged_data_input(void* data)
+{
+  tagged_data_input* tdi = (tagged_data_input*)data;
+    tagged_data_input* newtdi = (tagged_data_input*) clone_object((etch_object*) tdi);
+
+    if (tdi->impl)
+        newtdi->impl = tdi->impl->clone(tdi->impl);
+
+    return newtdi;
+}
+
+
+/**
+ * new_tdi_vtable()
+ */
+i_tagged_data_input* new_tdi_vtable()
+{
+    i_tagged_data_input* vtab = new_vtable(NULL, sizeof(i_tagged_data_input), CLASSID_TDI_VTAB);
+
+    vtab->start_message = tdi_start_message;
+    vtab->read_message  = tdi_read_message;
+    vtab->end_message   = tdi_end_message;
+    vtab->start_struct  = tdi_start_struct;
+    vtab->read_struct   = tdi_read_struct;
+    vtab->end_struct    = tdi_end_struct;
+    vtab->start_array   = tdi_start_array;
+    vtab->read_array    = tdi_read_array;
+    vtab->end_array     = tdi_end_array;
+    return vtab;
+}
+
+
+/**
+ * new_tagged_data_input()
+ * tagged_data_input constructor 
+ */
+tagged_data_input* new_tagged_data_input()
+{
+    i_tagged_data_input* vtab = NULL;
+
+    tagged_data_input* tdi = (tagged_data_input*) new_object
+        (sizeof(tagged_data_input), ETCHTYPEB_TAGDATAINP, CLASSID_TAGDATAINP);
+
+    ((etch_object*)tdi)->destroy = destroy_tagged_data_input;
+    ((etch_object*)tdi)->clone   = clone_tagged_data_input;
+
+    vtab = etch_cache_find(get_vtable_cachehkey(CLASSID_TDI_VTAB), 0);
+
+    if(!vtab)  
+    {    
+        vtab = new_tdi_vtable();
+        etch_cache_insert(((etch_object*)vtab)->get_hashkey(vtab), vtab, FALSE);
+    } 
+ 
+    ((etch_object*)tdi)->vtab = (vtabmask*)vtab;   
+    return tdi; 
+}
+
+
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_tagdata_out.c b/binding-c/runtime/c/src/main/bindings/msg/etch_tagdata_out.c
new file mode 100644
index 0000000..a167012
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_tagdata_out.c
@@ -0,0 +1,162 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*  
+ * etch_tagdata_out.c -- tagged_data_output base class default implementation.
+ */
+
+#include "etch_tagdata_out.h"
+#include "etch_cache.h"
+#include "etch_message.h"
+#include "etch_flexbuffer.h"
+#include "etch_arrayval.h"
+#include "etch_objecttypes.h"
+
+/*
+static const char* LOG_CATEGORY = "etch_tdo";
+*/
+int tdo_start_message(tagged_data_output* tdo, etch_message* msg)
+{
+    return -1;
+}
+
+
+int tdo_write_message(tagged_data_output* tdo, etch_message* msg, etch_flexbuffer* fb)
+{
+    return -1;
+}
+
+
+
+int tdo_end_message(tagged_data_output* tdo, etch_message* msg)
+{
+    return NULL;
+}
+
+
+int tdo_start_struct(tagged_data_output* tdo, struct etch_structvalue* sv)
+{
+    return -1;
+}
+
+
+int tdo_write_struct(tagged_data_output* tdo, struct etch_structvalue* sv)
+{
+    return -1;
+}
+
+
+int tdo_end_struct(tagged_data_output* tdo, struct etch_structvalue* sv)
+{
+    return -1;
+}
+
+
+int tdo_start_array(tagged_data_output* tdo, etch_arrayvalue* x)
+{
+    return -1;
+}
+
+
+int tdo_write_array(tagged_data_output* tdo, etch_arrayvalue* x, etch_validator* v)
+{
+    return -1;
+}
+
+
+int tdo_end_array(tagged_data_output* tdo, etch_arrayvalue* x)
+{
+    return -1;
+}
+
+
+/**
+ * destroy_tagged_data_output()
+ */
+int destroy_tagged_data_output(void* data)
+{
+    tagged_data_output* tdo = (tagged_data_output*)data;
+
+    if (!is_etchobj_static_content(tdo))
+        etch_object_destroy(tdo->impl);
+
+    destroy_objectex((etch_object*)tdo);
+    return 0;
+}
+
+
+/**
+ * clone_tagged_data_output()
+ */
+void* clone_tagged_data_output(void* data)
+{
+    tagged_data_output* tdo = (tagged_data_output*)data;
+    tagged_data_output* newtdo = (tagged_data_output*) clone_object((etch_object*) tdo);
+
+    if (tdo->impl)
+        newtdo->impl = tdo->impl->clone(tdo->impl);
+
+    return newtdo;
+}
+
+
+i_tagged_data_output* new_tdo_vtable()
+{
+    i_tagged_data_output* vtab 
+        = new_vtable(NULL, sizeof(i_tagged_data_output), CLASSID_TDO_VTAB);
+
+    vtab->start_message = tdo_start_message;
+    vtab->write_message = tdo_write_message;
+    vtab->end_message   = tdo_end_message;
+    vtab->start_struct  = tdo_start_struct; 
+    vtab->write_struct  = tdo_write_struct;   
+    vtab->end_struct    = tdo_end_struct;
+    vtab->start_array   = tdo_start_array;
+    vtab->write_array   = tdo_write_array;
+    vtab->end_array     = tdo_end_array;
+    return vtab;
+}
+
+
+/**
+ * new_tagged_data_output()
+ * tagged_data_output constructor 
+ */
+tagged_data_output* new_tagged_data_output()
+{
+    i_tagged_data_output* vtab = NULL;
+
+    tagged_data_output* tdo = (tagged_data_output*) new_object
+        (sizeof(tagged_data_output), ETCHTYPEB_TAGDATAOUT, CLASSID_TAGDATAOUT);
+
+    ((etch_object*)tdo)->destroy = destroy_tagged_data_output;
+    ((etch_object*)tdo)->clone   = clone_tagged_data_output;
+
+    vtab = etch_cache_find(get_vtable_cachehkey(CLASSID_TDO_VTAB), 0);
+
+    if(!vtab)  
+    {   
+        vtab = new_tdo_vtable();
+        etch_cache_insert(((etch_object*)vtab)->get_hashkey(vtab), vtab, FALSE);
+    } 
+ 
+    ((etch_object*)tdo)->vtab = (vtabmask*)vtab;   
+    return tdo; 
+}
+
+
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_type.c b/binding-c/runtime/c/src/main/bindings/msg/etch_type.c
new file mode 100644
index 0000000..e6c30ee
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_type.c
@@ -0,0 +1,880 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * type.c -- methods on the etch_type object.
+ * type denotes the type of a struct or message. when used with a message
+ * it typically denotes an action or event. an etch_type is a typedef of 
+ * etch_id_name, however it has additional instance data specific to type.
+ */
+
+#include "etch_type.h"
+#include "etch_validator.h"
+#include "etch_map.h"
+#include "etch_serializer.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+
+int fieldmap_clear_handler (void* key, void* value);
+etch_hashtable* new_etchtype_fieldmap();
+etch_hashtable* new_etchtype_vtormap();
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * constructors and destructors
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+
+/** 
+ * destroy_type()
+ * etch_type destructor
+ */
+int destroy_type(void* data)
+{
+    etch_type* type = (etch_type*)data;
+    
+
+    if (!is_etchobj_static_content(type)) /* e.g., not cloned */
+    {          
+        if (type->impl)
+        {   etch_type_impl* impl = (etch_type_impl*) type->impl;
+            etch_object_destroy(impl);
+            type->impl = NULL;
+        }
+    }
+
+    return destroy_id_name(type);
+} 
+
+/** 
+ * clone_type()
+ * etch_type quasi copy constructor
+ * originally, type was simply a name and id. now a type has considerable extra
+ * content. we do not clone that content here, but rather copy its reference 
+ * from the source and mark the clone as having non-disposable content such that 
+ * the type destructor won't try to free it. so the object is not a true clone.
+ * note also that if the original were to be destroyed prior to the clone, the
+ * clone's content memory reference would be hosed; thus we must ensure that we
+ * only clone static types, i.e. types which are instantiated with the service,
+ * (or in the case of unit tests, emulated as such), and destroyed only at 
+ * service teardown.
+ *
+ * note finally that etch_type and etch_idname still have the same footprint, 
+ * with the type instantiating its extra content at the impl* of the id_name.
+ */
+void* clone_type(void* data)
+{
+    const etch_type* type = (const etch_type*)data;
+    etch_type* newtype = clone_id_name((etch_type*)type);
+    newtype->impl = type->impl; 
+    set_etchobj_static_content(newtype);
+    return newtype;
+} 
+
+/** 
+ * destroy_type_impl()
+ * etch_type_impl destructor
+ */
+int destroy_type_impl(void* data)
+{
+    etch_type_impl* impl = (etch_type_impl*)data;
+
+    if (!is_etchobj_static_content(impl))
+    {   /* destruction of the maps causes all fields and non-cached validator
+         * objects, to be destroyed. see etchtype_fieldmap_clear_handler, 
+         * and etchtype_vtormap_clear_handler, below. */
+        etch_object_destroy(impl->vtormap);
+        etch_object_destroy(impl->fieldmap);
+        etch_object_destroy(impl->impexphelper);
+    }
+
+    return destroy_objectex((etch_object*)impl);
+} 
+
+
+/**
+ * new_type() 
+ * etch_type constructor
+ */
+etch_type* new_type(const wchar_t* name) 
+{
+    etch_type_impl* impl = NULL;
+    etchparentinfo* inheritlist = NULL;
+    etch_type* newtype = new_id_name(name);
+    if (NULL == newtype) return NULL;
+    ((etch_object*)newtype)->obj_type = ETCHTYPEB_TYPE;
+    ((etch_object*)newtype)->class_id = CLASSID_ID_TYPE;
+
+    /* ensure parent type keys exist in (one-based) inheritance list */
+    inheritlist = get_vtab_inheritance_list((etch_object*)newtype,
+       2, 1, CLASSID_VTAB_FIELD);
+    inheritlist[1].o.obj_type = ETCHTYPEB_ID_NAME;
+    inheritlist[1].c.class_id = CLASSID_ID_NAME;
+
+    /* instantiate instance data */
+    impl = (etch_type_impl*) new_object(sizeof(etch_type_impl), 
+            ETCHTYPEB_IDNAMEIMPL, CLASSID_TYPEIMPL);
+
+    ((etch_object*)impl)->destroy    = destroy_type_impl;
+    impl->async_mode = ETCH_ASYNCMODE_NONE; /* where is this default reset? */
+
+    impl->fieldmap   = new_etchtype_fieldmap();
+    impl->vtormap    = new_etchtype_vtormap();
+
+    newtype->impl    = (etch_object*) impl;
+
+    ((etch_object*)newtype)->destroy = destroy_type;
+    ((etch_object*)newtype)->clone   = clone_type;    
+
+    return newtype;
+}
+
+
+/**
+ * new__static_type() 
+ * create a type object whose destructor will have no effect.
+ */
+etch_type* new_static_type(const wchar_t* name)
+{
+    etch_type* newtype = new_type(name);
+    set_etchobj_static_all(newtype);
+    return newtype;
+} 
+
+
+
+/** 
+ * destroy_static_type()
+ * etch_type destructor.
+ * this should not be set as the virtual dtor for a type, since the type
+ * would then not be quasi-static as desired. it should be invoked explicitly
+ */
+int destroy_static_type(etch_type* type)
+{
+    clear_etchobj_static_all(type);
+    return destroy_type(type); 
+} 
+
+
+
+
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * get/set
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/* mutators are implemented only for instance data specific to type, i.e.
+ * resident in the etch_type_impl, following the c binding convention that we
+ * implement a mutator only when the datum can't safely be get/set directly. 
+ */
+
+/** 
+ * etchtype_set_type_stubhelper()
+ * set type's 'stub helper', returning existing helper if any.
+ * the stub helper is a function pointer, not an object.
+ */
+opaque_stubhelper etchtype_set_type_stubhelper(etch_type* type, opaque_stubhelper helper)
+{
+    /* sets a callback from message type to the particular API method implementation.
+     * note that in the the java binding this is indirect, that is, this callback
+     * calls a wrapper method which calls the implementation. however in our case,
+     * the methods have same signature, so we call the implementation directly.
+     * keep an eye on this though in case I have missed something.
+     */
+    opaque_stubhelper oldhelper = NULL;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl)  
+    {   oldhelper = impl->stubhelper;
+        impl->stubhelper = helper;
+    }
+    return oldhelper;
+} 
+
+
+/** 
+ * etchtype_get_type_stubhelper()
+ * getter for stub helper - see comments at set_type_stubhelper()
+ */
+opaque_stubhelper etchtype_get_type_stubhelper(etch_type* type)
+{
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    return impl? impl->stubhelper: NULL;
+} 
+
+
+/** 
+ * etchtype_set_result_type()
+ * set result type, returning existing result type if any.
+ * @param type a non-disposable reference to a type.
+ * todo: if result type is set only at construction, lose this.
+ */
+etch_type* etchtype_set_result_type(etch_type* type, etch_type* rtype)
+{
+    etch_type* oldtype = NULL;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl)  
+    {   oldtype = impl->result_type;
+        impl->result_type = rtype;
+    }
+    return oldtype;
+} 
+
+
+/** 
+ * etchtype_get_result_type()
+ * returns a non-disposable reference to result type
+ */
+etch_type* etchtype_get_result_type(etch_type* type)
+{
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    return impl? impl->result_type: NULL;
+} 
+
+
+/** 
+ * etchtype_set_super_type()
+ * todo: if set only at construction, lose this.
+ * @param a non-disposable type
+ * @return the previous type, not disposable.
+ */
+etch_type* etchtype_set_super_type(etch_type* type, etch_type* stype)
+{
+    etch_type* oldtype = NULL;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl)  
+    {   oldtype = impl->super_type;
+        impl->super_type = stype;
+    }
+    return oldtype;
+} 
+
+
+/** 
+ * etchtype_get_super_type()
+ * returns a non-disposable reference to super type
+ */
+etch_type* etchtype_get_super_type(etch_type* type)
+{
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    return impl? impl->super_type: NULL;
+} 
+
+
+/** 
+ * etchtype_set_component_type()
+ * set associated component type and class for an array of this class.
+ * @param type a non-disposable type object. neither owned nor stored here.
+ * @return the existing objtype/classid representing component type.  
+ */
+unsigned int etchtype_set_component_type(etch_type* type, unsigned int typeclass)
+{
+    unsigned int old_class = 0;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl)  
+    {   old_class = impl->component_class;
+        impl->component_class = typeclass;
+    }
+    return old_class;
+} 
+
+
+/** 
+ * etchtype_get_component_type()
+ * returns component obj_type and class_id or zero indicating none set.
+ */
+unsigned int etchtype_get_component_type(etch_type* type)
+{
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    return impl? impl->component_class: 0;
+} 
+
+
+/** 
+ * etchtype_set_async_mode()
+ * set async_mode, which determines if requests are run on the queued or
+ * free thread pool.
+ */
+unsigned char etchtype_set_async_mode (etch_type* type, unsigned char mode)
+{
+    unsigned char old_mode = 0;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl)  
+    {   old_mode = impl->async_mode;
+        impl->async_mode = mode;
+    }
+    return old_mode;
+} 
+
+
+/** 
+ * etchtype_get_async_mode()
+ * returns component async_mode
+ */
+unsigned char etchtype_get_async_mode (etch_type* type)
+{
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    return impl? impl->async_mode: 0;
+} 
+
+
+/** 
+ * etchtype_set_timeout()
+ * set timeout to wait for response, in milliseconds.
+ */
+unsigned int etchtype_set_timeout(etch_type* type, unsigned int ms)
+{
+    unsigned int old_timeout = 0;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl)  
+    {   old_timeout = impl->timeout;
+        impl->timeout = ms;
+    }
+    return old_timeout;
+} 
+
+
+/** 
+ * etchtype_get_timeout()
+ * get timeout to wait for response, in milliseconds.
+ */
+unsigned int etchtype_get_timeout(etch_type* type)
+{
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    return impl? impl->timeout: 0;
+} 
+
+
+/** 
+ * etchtype_set_run_validators()
+ * set boolean run validators flag, returning existing value.
+ */
+unsigned char etchtype_set_run_validators(etch_type* type, unsigned char val)
+{
+    unsigned char old_flag = 0;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl)  
+    {   old_flag = impl->is_run_validators;
+        impl->is_run_validators = val;
+    }
+    return old_flag;
+} 
+
+
+/** 
+ * etchtype_get_response_field()
+ */
+etch_field* etchtype_get_response_field(etch_type* type)
+{
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    return impl? impl->response_field: NULL;
+} 
+
+
+/** 
+ * etchtype_set_response_field()
+ */
+etch_field* etchtype_set_response_field(etch_type* type, etch_field* field)
+{
+    etch_field* old_field = NULL;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl)  
+    {   old_field = impl->response_field;
+        impl->response_field = field;
+    }
+    return old_field;
+} 
+
+
+/** 
+ * etchtype_get_run_validators()
+ * get boolean run validators flag.
+ */
+unsigned char etchtype_get_run_validators(etch_type* type)
+{
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    return impl? impl->is_run_validators: 0;
+} 
+
+
+/** 
+ * etchtype_set_impexphelper()
+ * setter for import/export helper object
+ * @param helper the helper object to be assigned, or null.
+ * caller relinquishes ownership of this object if present.
+ * @return the *disposable* prior helper object if any. 
+ * if present, caller now owns this object.
+ */
+etch_serializer* etchtype_set_impexphelper(etch_type* type, etch_serializer* helper)
+{
+    etch_serializer* oldhelper = NULL;
+    etch_type_impl*  impl = (etch_type_impl*) type->impl;
+    if (impl) 
+    {   oldhelper = impl->impexphelper;
+        impl->impexphelper = helper;
+    }
+    return oldhelper;
+} 
+
+
+/** 
+ * etchtype_get_impexphelper()
+ * getter for import/export helper object
+ * @return a *non-disposable* reference to helper object.
+ * the type retains ownership of this object.
+ */
+etch_serializer* etchtype_get_impexphelper(etch_type* type)
+{
+    etch_type_impl* impl = type? (etch_type_impl*) type->impl: NULL;
+    return impl? impl->impexphelper: NULL;
+} 
+
+
+/** 
+ * etchtype_is_assignable_from()
+ * indicate if this type is assignable from other, i.e. other a subclass of this
+ */
+int etchtype_is_assignable_from(etch_type* type, etch_type* othertype)
+{
+    etch_type* other_supertype;
+    if (NULL == othertype) return FALSE;
+    if (is_equal_types(type, othertype)) return TRUE;
+    other_supertype = othertype->impl? 
+       ((etch_type_impl*)othertype->impl)->super_type: NULL;
+    return etchtype_is_assignable_from(type, other_supertype);
+}
+
+
+/* - - - - - - - - - - - - - - - - - 
+ * fieldmap accessors
+ * - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * get_key_by_name()
+ * look up an etch_id_name key object by a name string. recall that etch_type 
+ * and etch_field each are typedefs of etch_id_name. id_name derivations are
+ * keyed by hash of name, so lookup is direct;
+ */
+etch_id_name* etchtype_get_key_by_name(etch_hashtable* map, const wchar_t* name)
+{
+    etch_hashitem hashbucket, *thisitem = &hashbucket; 
+    const unsigned hashkey = etch_get_wchar_hashkey(name);
+    const int result = ((struct i_hashtable*)((etch_object*)map)->vtab)->findh(map->realtable, hashkey, map, (void**)&thisitem);  
+    return result == 0? (etch_id_name*) thisitem->key: NULL;
+}
+
+
+/**
+ * get_idname_by_id()
+ * given a hashtable and an id_name "id", return the map's id_name key having that id.
+ * note that a non-disposable *reference* is returned, not a copy.
+ */
+etch_id_name* etchtype_get_key_by_id (etch_hashtable* map, const unsigned id)
+{
+    etch_iterator iterator;
+
+    hashtable_getlock(map);
+    set_iterator(&iterator, map, &map->iterable);
+    while(iterator.has_next(&iterator))
+    {
+        etch_id_name* this_idname = (etch_id_name*) iterator.current_key;
+		if (this_idname->id == id) {
+			hashtable_rellock(map);
+			return this_idname;
+		}
+        iterator.next(&iterator);
+    }
+	hashtable_rellock(map);
+    return NULL;
+}
+
+
+/**
+ * etchtype_add_field()
+ * adds a field to set of fields
+ * @param field caller must supply a disposable field object.
+ * @return the argument. If there is a name collision, the existing field
+ * is returned in place of the supplied field, AND the supplied field is
+ * DESTROYED. this simplifies logic up the line, and is consistent with caller
+ * expecting to relinquish responsibility for the field passed.
+ */  
+etch_field* etchtype_add_field (etch_type* type, etch_field* field) 
+{    
+    etch_field *effective_field = field;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    etch_hashtable* map  = impl->fieldmap;
+
+    int result = ((struct i_hashtable*)((etch_object*)impl->fieldmap)->vtab)->inserth
+       (map->realtable, field, NULL, map, 0); 
+
+    if (-1 == result)
+        effective_field = etchtype_get_field_by_name(type, field->name);
+
+    if (effective_field != field)
+        etch_object_destroy(field);
+     
+    #ifdef ETCHTYPE_DEBUG
+    if  (effective_field) 
+         wprintf(L"add field %08x '%s'\n", 
+            (size_t) (void*) effective_field, effective_field->name);
+    else wprintf(L"error adding field '%s'\n", field->name);
+    #endif
+
+    return effective_field;  
+}
+
+
+/**
+ * etchtype_get_field_by_id()
+ * @return a non-disposable reference to the requested field, or null
+ */
+etch_field* etchtype_get_field_by_id (etch_type* type, const unsigned id)
+{
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    return etchtype_get_key_by_id(impl->fieldmap, id);
+}
+
+
+/**
+ * etchtype_get_field_by_name()
+ * works as in the java binding, in that if the type does not include   
+ * a field with that name, a new field is created and added to the type.
+ * @return a non-disposable reference to the requested field, or null
+ */
+etch_field* etchtype_get_field_by_name (etch_type* type, const wchar_t* name)
+{
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    etch_field* field = etchtype_get_key_by_name(impl->fieldmap, name);
+    if (NULL == field)
+        field = etchtype_add_field (type, new_field(name));
+    return field;
+}
+
+
+/**
+ * etchtype_get_fields()
+ * returns a disposable arraylist of references. the list is marked
+ * such that list->destroy() will not attempt to free content.
+ * caller must cast result to etch_arraylist*
+ */
+void* etchtype_get_fields (etch_type* type)
+{
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    return get_map_keys(impl->fieldmap);
+}
+
+
+/* 
+ * etchtype_fields_count()
+ * return count of fields resident in the type.
+ */
+int etchtype_fields_count(etch_type* type)
+{
+    int  count = 0;
+    etch_hashtable* map = NULL;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl) map = impl->fieldmap;
+    if (map)  count = ((struct i_hashtable*)((etch_object*)map)->vtab)->count(map->realtable, 0, 0);
+    return count;
+}
+
+
+/* 
+ * etchtype_set_fields_iterator()
+ * initialize iterator over fields.
+ */
+int etchtype_set_fields_iterator(etch_type* type, etch_iterator* iterator)
+{
+    etch_hashtable* map = NULL;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl) map = impl->fieldmap;
+    return map? set_iterator(iterator, map, &map->iterable): -1;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - 
+ * validator insert/lookup
+ * - - - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * etchtype_get_validator_by_id()
+ * caller will want to cast result to etch_validator*.
+ * note that the etch_type header can't include etch_validator header,
+ * thus the anonymous pointers to etch_validator in these methods.  
+ */
+etch_object* etchtype_get_validator_by_id (etch_type* type, const unsigned id)
+{
+    etch_hashtable* map;
+    etch_iterator iterator;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (!impl || !id) return NULL;
+    map = impl->vtormap;
+
+    set_iterator(&iterator, map, &map->iterable);
+
+    while(iterator.has_next(&iterator))
+    {
+        etch_field* this_field = (etch_field*) iterator.current_key;
+        if (this_field->id == id) 
+            return iterator.current_value;
+        iterator.next(&iterator);
+    }
+
+    return NULL;
+}
+
+
+/**
+ * etchtype_get_validator_by_name()
+ * @param name the name of the etch_field keying the validator.
+ * caller will want to cast result to etch_validator*  
+ */
+etch_object* etchtype_get_validator_by_name (etch_type* type, const wchar_t* name)
+{
+    etch_type_impl* impl = type? (etch_type_impl*) type->impl: NULL;
+
+    if (impl && name) 
+    {  
+        etch_hashitem hashbucket, *thisitem = &hashbucket; 
+        etch_hashtable* map = impl->vtormap;
+        const unsigned  key = etch_get_wchar_hashkey(name);
+        if (0 == ((struct i_hashtable*)((etch_object*)map)->vtab)->findh(map->realtable, key, map, (void**)&thisitem)) 
+            return thisitem->value;
+    }
+
+    return NULL;
+}
+
+
+/**
+ * etchtype_put_validator()
+ * adds a validator to validator chain for specified key
+ * @param field relinquished regardless of result.
+ * @param new_vtor relinquished regardless of result.
+ */  
+int etchtype_put_validator (etch_type* type, etch_field* field, etch_object* new_vtor) 
+{    
+    int result = -1;
+    etch_hashtable *fmap, *vmap;
+    etch_hashitem hashbucket, *mapentry = &hashbucket; 
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    ETCH_ASSERT(impl);
+
+    do  /* validate parameters */
+    {   
+        if (!is_etch_validator(new_vtor)) {
+    	    etch_object_destroy(field);
+            field = NULL;
+            break;
+        }
+        if (NULL == field) {   
+	        etch_object_destroy(new_vtor);
+	        new_vtor = NULL;
+            break;
+        }
+        result = 0;
+    } while(0);
+
+    if (0 != result) return result;
+    
+    if (!impl || !is_etch_validator(new_vtor) || !field) return -1;
+    memset(mapentry, 0, sizeof(etch_hashitem));
+    fmap = impl->fieldmap;
+    vmap = impl->vtormap;
+
+    /* add field to fieldmap. if an eponymous field was present, it is returned
+     * in place of caller's field, and caller's field has been destroyed. */
+    field = etchtype_add_field (type, field); 
+
+    /* if a validator exists under the specified key, we'll chain the new 
+     * validator to the existing validator with a new combo validator object,
+     * and replace the current vtor map entry with the new combo validator.
+     */
+    result = ((struct i_hashtable*)((etch_object*)vmap)->vtab)->removeh   /* if already in vtormap, remove it */
+      (vmap->realtable, ((etch_object*)field)->get_hashkey(field), vmap, (void**)&mapentry);
+
+    if (result == -1)   /* if it was not already in vtormap, insert it */
+        result = ((struct i_hashtable*)((etch_object*)vmap)->vtab)->inserth (vmap->realtable, 
+                    etch_object_clone_func(field), new_vtor, vmap, 0);
+    else                /* ... otherwise insert a new chain head */
+    {   etch_field* existing_key = (etch_field*) mapentry->key;
+        etch_validator* existing_vtor = (etch_validator*) mapentry->value;
+
+        etch_validator* vcombo       /* chain new vtor to existing vtor ... */
+            = new_combo_validator(existing_vtor, (etch_validator*) new_vtor);
+
+        result = ((struct i_hashtable*)((etch_object*)vmap)->vtab)->inserth /* ... and insert the new chained vtor */ 
+           (vmap->realtable, existing_key, vcombo, vmap, 0); 
+    }
+
+    return result;  
+}
+
+
+/* 
+ * etchtype_clear_validator()
+ * remove the validator chain for specified key.
+ */
+int etchtype_clear_validator(etch_type* type, etch_field* key)
+{
+    int  result = -1;
+    etch_hashtable* map = NULL;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl) map = impl->vtormap;
+
+    if (map)
+    {   etch_validator* removed_vtor = NULL;
+        etch_hashitem hashbucket, *mapentry = &hashbucket; 
+        memset(mapentry, 0, sizeof(etch_hashitem));
+ 
+        result = ((struct i_hashtable*)((etch_object*)map)->vtab)->removeh(map->realtable, ((etch_object*)key)->get_hashkey(key), map, (void**)&mapentry);
+
+        if (result == 0)  /* returned content is head of validator chain */ {
+            removed_vtor = (etch_validator*) mapentry->value;
+            destroy_type((etch_type*) mapentry->key);
+        }
+
+        if (removed_vtor) /* destructors are called up the chain */
+            etch_object_destroy(removed_vtor);
+    }
+
+    return 0;
+}
+
+
+/* 
+ * etchtype_clear_validators()
+ * clear all type validators. non-cached validators are destroyed.
+ * returns count of items cleared, or -1 if error.
+ */
+int etchtype_clear_validators(etch_type* type)
+{
+    int result = -1;
+    etch_hashtable* map = NULL;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl) map = impl->vtormap;
+    if (map) /* we ask hashtable clear() to call content destructors */
+        result = ((struct i_hashtable*)((etch_object*)map)->vtab)->clear(map->realtable, FALSE, TRUE, map, 0);
+    return result;
+}
+
+
+/* 
+ * etchtype_validators_count()
+ * return count of validators in chain.
+ */
+int etchtype_validators_count(etch_type* type)
+{
+    int  count = 0;
+    etch_hashtable* map = NULL;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl) map = impl->vtormap;
+    if (map)  count = ((struct i_hashtable*)((etch_object*)map)->vtab)->count(map->realtable, 0, 0);
+    return count;
+}
+
+
+/* 
+ * etchtype_set_validators_iterator()
+ * initialize iterator over validators.
+ */
+int etchtype_set_validators_iterator(etch_type* type, etch_iterator* iterator)
+{
+    etch_hashtable* map = NULL;
+    etch_type_impl* impl = (etch_type_impl*) type->impl;
+    if (impl) map = impl->vtormap;
+    return map? set_iterator(iterator, map, &map->iterable): -1;
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * utility methods
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/* 
+ * etchtype_fieldmap_clear_handler()
+ * callback set to handle freeing of key memory during a clear() of the fields
+ * map. note that this map is used as a quasi set, so the value is always null. 
+ * the etch_fields are owned by the map and destroyed as the map is destroyed.
+ * handlers return FALSE to indicate memory free NOT handled.
+ */
+int etchtype_fieldmap_clear_handler (void* key, void* value)  
+{
+   ((etch_object*)key)->destroy(key);
+    return TRUE; 
+}
+
+
+/**
+ * new_etchtype_fieldmap()
+ * construct and return a hashtable configured as expected for the fieldmap  
+ */
+etch_hashtable* new_etchtype_fieldmap()
+{
+    etch_hashtable* map = new_hashtable_synchronized(ETCHTYPE_DEFSIZE_FIELDMAP); 
+    if (NULL == map) return NULL; 
+    map->content_type       = ETCHHASHTABLE_CONTENT_OBJECT;
+    map->is_tracked_memory  = TRUE;
+    map->is_readonly_keys   = FALSE; /* keys are disposable field objects */ 
+    map->is_readonly_values = FALSE; /* value is always null */
+    map->freehook = etchtype_fieldmap_clear_handler;
+    return map;
+}
+
+
+/* 
+ * etchtype_vtormap_clear_handler()
+ * callback set to handle freeing of field and validator memory   
+ * during a clear() of the validators map.  
+ */
+int etchtype_vtormap_clear_handler (void* key, void* value)  
+{
+    /* note that value->destroy() is invoking the validator destructor,
+     * and that this will have no effect on a validator marked as cached */
+    etch_object_destroy(value);
+    etch_object_destroy(key);
+    return TRUE; 
+}
+
+
+/**
+ * new_etchtype_vtormap()
+ * construct and return a hashtable configured as expected for validators.
+ * this is a map of non-disposable etch_field keys to etch_validator* 
+ * object references. the validators are considered as disposable, in that
+ * clearing the map will result in validator destructor calls; however 
+ * note that destroy() has no effect on a cached validator - these are 
+ * not destroyed until such time as the validator cache is cleared.  
+ */
+etch_hashtable* new_etchtype_vtormap()
+{
+    etch_hashtable* map = new_hashtable_synchronized(ETCHTYPE_DEFSIZE_VTORMAP);
+    if (NULL == map) return NULL;   
+    map->content_type       = ETCHHASHTABLE_CONTENT_OBJECT;
+    map->is_tracked_memory  = TRUE;
+    map->is_readonly_keys   = TRUE;  /* keys are nondisposable field objects */ 
+    map->is_readonly_values = FALSE; /* values are validator function pointers */
+    map->freehook = etchtype_vtormap_clear_handler;
+    return map;
+}
+
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_validator.c b/binding-c/runtime/c/src/main/bindings/msg/etch_validator.c
new file mode 100644
index 0000000..1771251
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_validator.c
@@ -0,0 +1,1767 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*  
+ * etch_validator.c
+ * validators
+ */
+
+#include "etch_validator.h"
+#include "etch_tagged_data.h"
+#include "etch_cache.h"
+#include "etch_arrayval.h"
+#include "etch_structval.h"
+#include "etch_encoding.h"
+#include "etch_nativearray.h"
+#include "etch_objecttypes.h"
+#include "etch_type.h"
+#include "etch_mem.h"
+
+#ifdef WIN32
+#pragma warning (disable:4996)
+#endif
+
+etch_validator* etchvtor_cache[ETCHVTOR_CACHED_TYPE_COUNT * ETCHVTOR_MAX_CACHED];
+
+etch_validator** etchvtor_cache_boolean; /* boolean validator cache address */
+etch_validator** etchvtor_cache_byte;    /* byte validator cache address */
+etch_validator** etchvtor_cache_int8;    /* int8 validator cache address */
+etch_validator** etchvtor_cache_int16;   /* int16 validator cache address */
+etch_validator** etchvtor_cache_int32;   /* int32 validator cache address */
+etch_validator** etchvtor_cache_int64;    /* int64 validator cache address */
+etch_validator** etchvtor_cache_float;   /* float validator cache address */
+etch_validator** etchvtor_cache_double;   /* double validator cache address */
+etch_validator** etchvtor_cache_string;   /* string validator cache address */
+etch_validator** etchvtor_cache_object;   /* object validator cache address */
+etch_validator** etchvtor_cache_exception; /* excp validator cache address */
+etch_validator** etchvtor_cache_eod;   /* eod validator cache address */
+
+
+/* cached validators have private constructors,
+ * get() is the public method of construction and caching 
+ */
+etch_validator*  new_validator_boolean(const int dimensions);
+etch_validator*  new_validator_byte   (const int dimensions);
+etch_validator*  new_validator_int8   (const int dimensions);
+etch_validator*  new_validator_int16  (const int dimensions);
+etch_validator*  new_validator_int32  (const int dimensions);
+etch_validator*  new_validator_int64  (const int dimensions);
+etch_validator*  new_validator_float  (const int dimensions);
+etch_validator*  new_validator_double (const int dimensions);
+etch_validator*  new_validator_string (const int dimensions);
+etch_validator*  new_validator_object (const int dimensions);
+etch_validator*  new_validator_exception();
+etch_validator*  new_validator_eod(); 
+
+int etch_typevtor_validate(etch_validator*, etch_object*);
+int etch_typevtor_check_value(etch_validator*, etch_object*, byte*);
+etch_validator* etch_typevtor_element_validator(etch_validator*);
+
+etch_object* etch_typevtor_validate_value(etch_validator*, etch_object*);
+etch_validator* etchvtor_cache_validator(etch_validator*, etch_validator** cache);
+etch_validator* new_type_validator(const unsigned short vtor_classid, 
+   const unsigned short scalar_obj_type, const unsigned short scalar_classid, 
+   const unsigned short array_classid, const int ndims, char* description);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * contructors, destructors
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * destroy_validator()
+ * validator object destructor
+ */
+int destroy_validator(void* data)
+{
+  etch_validator* vtor = (etch_validator*)data;
+    /* don't honor destroy() request if object is cached */
+    if (vtor->is_cached) return -1;
+
+    if (!is_etchobj_static_content(vtor))
+        etch_free(vtor->description);
+
+    return destroy_objectex((etch_object*)vtor);
+}
+
+
+/**
+ * new_validator_from()
+ * constructor for etch_validator
+ */
+etch_validator* new_validator()
+{
+    return new_validator_from(NULL, NULL, NULL, NULL);
+}
+
+
+/**
+ * new_validator_from()
+ * constructor 2 for etch_validator
+ */
+etch_validator* new_validator_from(etchvtor_validate fv, etchvtor_checkvalue fcv, 
+    etchvtor_element_validator fev, etchvtor_validate_value fvv)
+{
+    etch_validator* newvtor = (etch_validator*) new_object(sizeof(etch_validator), 
+         ETCHTYPEB_VALIDATOR, CLASSID_VALIDATOR);
+
+    ((etch_object*)newvtor)->destroy = destroy_validator;
+    newvtor->validate = fv;
+    newvtor->check_value = fcv;
+    newvtor->element_validator = fev;
+    newvtor->validate_value = fvv;
+
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * validator cache
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchvtor_cache_validator()
+ * convenience method to cache specified validator, marking it cached.  
+ */
+etch_validator* etchvtor_cache_validator(etch_validator* vtor, etch_validator** cache)
+{
+    cache[vtor->numdimensions] = vtor; /* assumed pre-validated by caller */
+    vtor->is_cached = TRUE;
+    return vtor;
+}
+
+
+/**
+ * etchvtor_clear_cache()
+ * clear the validator cache, destroying any validators found
+ */
+void etchvtor_clear_cache() 
+{
+    const int cachebytes = ETCHVTOR_BYTES_PER_CACHE * ETCHVTOR_CACHED_TYPE_COUNT;
+    const int cacheslots = cachebytes / sizeof(void*);
+    int i=0;
+
+    for(; i < cacheslots; i++)
+    {
+        etch_validator* p = etchvtor_cache[i];
+        if (p == NULL || ((etch_object*)p)->obj_type != ETCHTYPEB_VALIDATOR) continue;
+        p->is_cached = FALSE;
+        etch_object_destroy(p);
+    }
+
+    memset(etchvtor_cache, 0, cachebytes);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * combo validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+
+/**
+ * etch_combovtor_validate()
+ * combo validator default validate() virtual
+ */
+int etch_combovtor_validate(etch_validator* vtor, etch_object* value)
+{
+    int resulta = 0, resultb = 0;
+    etch_validator *vtor_a = vtor->vtor_a, *vtor_b = vtor->vtor_b;
+
+    resulta = vtor_a? vtor_a->validate(vtor_a, value): -1;
+    if (0 == resulta) return 0;
+
+    resultb = vtor_b? vtor_b->validate(vtor_b, value): -1;
+    return resultb;
+}
+
+
+/**
+ * etch_combovtor_validate_value()
+ * combo validator default validate_value() virtual
+ * note carefully: the returned value may or may not be the same object   
+ * as the passed value. see comments later in this module.
+ */
+etch_object* etch_combovtor_validate_value(etch_validator* vtor, etch_object* value)
+{
+    etch_validator *vtor_a = vtor->vtor_a, *vtor_b = vtor->vtor_b;
+    etch_object *validatedobj = NULL;
+
+    validatedobj = vtor_a? vtor_a->validate_value(vtor_a, value): NULL;
+
+    if (NULL == validatedobj)      
+    {
+        validatedobj = vtor_b? vtor_b->validate_value(vtor_b, value): NULL;
+    }
+
+    return validatedobj; 
+}
+
+
+/**
+ * etch_combovtor_check_value()
+ * combo validator default check_value() virtual
+ */
+int etch_combovtor_check_value(etch_validator* vtor, 
+    etch_object* value, byte* typecode_out)
+{
+    byte typecode = 0;
+    int  resulta = 0, resultb = 0;
+    etch_validator *vtor_a = vtor->vtor_a, *vtor_b = vtor->vtor_b;
+
+    resulta = vtor_a? vtor_a->check_value(vtor_a, value, &typecode): -1;
+    if (-1 == resulta) 
+    {   resultb = vtor_b? vtor_b->check_value(vtor_b, value, &typecode): -1; 
+        if (-1 == resultb) return -1;
+    }
+
+    *typecode_out = typecode;
+    return 0;
+}
+
+
+/**
+ * etch_combovtor_element_validator()
+ * combo validator default element_validator() virtual
+ */
+etch_validator* etch_combovtor_element_validator(etch_validator* vtor) 
+{
+    etch_validator *vtor_a = vtor->vtor_a, *vtor_b = vtor->vtor_b;
+
+    etch_validator *eltvtor_a = vtor_a? vtor_a->element_validator(vtor_a): NULL;
+    etch_validator *eltvtor_b = vtor_b? vtor_b->element_validator(vtor_b): NULL;
+
+    if (eltvtor_a == NULL && eltvtor_b == NULL) return NULL;
+    if (eltvtor_a == NULL) return eltvtor_b;
+    if (eltvtor_b == NULL) return eltvtor_a;
+    return new_combo_validator(eltvtor_a, eltvtor_b);
+}
+
+
+/**
+ * destroy_combo_validator()
+ * combo validator destructor
+ * destroys all validators in the chain
+ */
+int destroy_combo_validator(void* data)
+{
+  etch_validator* vtor = (etch_validator*)data;
+    if (vtor->is_cached) return -1;
+
+    if (!is_etchobj_static_content(vtor))
+    {
+        etch_object_destroy(vtor->vtor_a);
+        etch_object_destroy(vtor->vtor_b);
+        etch_free(vtor->description);
+    }
+
+    return destroy_objectex((etch_object*)vtor);
+}
+
+
+/**
+ * new_combo_validator()
+ * constructor for combo validator.
+ * caveat: the destructor frees memory for all validators in the chain.
+ * if the same validator reference were to appear more than once in a chain,
+ * it must be either a reference from the cache, or otherwise marked such that 
+ * the destructor will not attempt to free it (validator marked as static, 
+ * or combo parent marked as static content). the safest way to chain non-
+ * cached validators is to ensure that each chained validator reference is
+ * unique, i.e. newly instantiated. 
+ */
+etch_validator* new_combo_validator(etch_validator* vtor_a, etch_validator* vtor_b)
+{
+    etch_validator* newvtor = new_validator_from
+      (etch_combovtor_validate, 
+       etch_combovtor_check_value,
+       etch_combovtor_element_validator, 
+       etch_combovtor_validate_value);
+
+    ((etch_object*)newvtor)->class_id = CLASSID_COMBO_VALIDATOR;
+    ((etch_object*)newvtor)->destroy = destroy_combo_validator;
+    newvtor->vtor_a = vtor_a;
+    newvtor->vtor_b = vtor_b;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * type validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * new_type_validator()
+ * private constructor for a type validator
+ */
+etch_validator* new_type_validator(const unsigned short vtor_classid, 
+   const unsigned short scalar_obj_type, const unsigned short scalar_classid, 
+   const unsigned short array_classid, const int ndims, char* description)
+{
+    etch_validator* newvtor = new_validator();
+    ((etch_object*)newvtor)->class_id = vtor_classid;
+    newvtor->expected_class_id = ndims? array_classid: scalar_classid;
+    newvtor->numdimensions  = ndims;
+    newvtor->description    = new_char(description);
+    newvtor->validate_value = etch_typevtor_validate_value;
+    newvtor->validate = etch_typevtor_validate;
+    newvtor->check_value = etch_typevtor_check_value;
+    newvtor->element_validator = etch_typevtor_element_validator;
+    return newvtor;
+}
+
+
+/**
+ * new_type_validator_1()
+ * constructor for a type validator for types using inheritance scheme 1
+ * @param vtable_class_id the class of the expected class' vtable, zero if the
+ * class inherits only from object. the class inheritance list if any is fetched 
+ * from the cached vtable, and is not disposable.
+ */
+etch_validator* new_type_validator_1(const unsigned short vtor_classid, 
+    const unsigned short scalar_obj_type, const unsigned short scalar_classid,  
+    const unsigned short vtable_class_id, const unsigned short array_classid, 
+    const int ndims, char* description) 
+{
+    etch_validator* newvtor = new_type_validator(vtor_classid, scalar_obj_type, 
+        scalar_classid, array_classid, ndims, description);
+ 
+    if (vtable_class_id)
+    {   /* cache a reference to the expected class' inheritance list if any */
+        vtabmask* vtab = etch_cache_find(get_vtable_cachehkey(vtable_class_id), 0);
+        if (vtab)
+        {   newvtor->inherits_from = vtab->inherits_from;
+            newvtor->is_owned_inherits_from = FALSE;
+        }
+    }
+
+    return newvtor;
+}
+
+
+/**
+ * new_type_validator_2()
+ * constructor for a type validator
+ * @param inherit_list a complete and disposable inheritance list for the class. 
+ * for classes inheriting via method 2 that have more than two objects in the
+ * inheritance chain, this list must be artificially created, since no object  
+ * in the chain will have a complete list.
+ */
+etch_validator* new_type_validator_2(const unsigned short vtor_classid, 
+    const unsigned short scalar_obj_type, const unsigned short scalar_classid,  
+    const unsigned short array_classid, etchparentinfo* inherit_list,
+    const int ndims, char* description) 
+{
+    etch_validator* newvtor = new_type_validator(vtor_classid, scalar_obj_type, 
+        scalar_classid, array_classid, ndims, description);
+ 
+    newvtor->inherits_from  = inherit_list;
+    newvtor->is_owned_inherits_from = TRUE;
+    return newvtor;
+}
+
+
+/**
+ * etch_typevtor_check_dimensions()
+ * convenience function to validate dimension count
+ */
+int etchvtor_check_dimensions(const int ndims)
+{
+    return ndims < 0 || ndims > ETCHVTOR_MAX_NDIMS? -1: 0;
+}
+
+
+/**
+ * etchvtor_set_classparams()
+ * populate arguments to etchobj_is_assignable_from(), for use by validate()
+ */
+void etchvtor_set_classparams(etch_objclass* targetparams, 
+  etch_objclass* sourceparams, etch_validator* targetvtor, etch_object* sourceobj)
+{
+    memset(targetparams, 0, sizeof(etch_objclass)); 
+    ((etch_objclass*)targetparams)->obj_type = targetvtor->expected_obj_type;
+    ((etch_objclass*)targetparams)->class_id = targetvtor->expected_class_id;
+    targetparams->numdims  = targetvtor->numdimensions;
+    targetparams->inherits_from = targetvtor->inherits_from;
+
+    set_etch_assignable_arg_from(sourceparams, sourceobj);
+}
+
+
+/**
+ * etch_typevtor_validate()
+ * type validator default validate() virtual
+ */
+int etch_typevtor_validate(etch_validator* vtor, etch_object* value)
+{
+    int result = 0, source_numdims = 0;
+    if (!value) return -1;
+
+    /* java uses different classes for arrays of the same type but different 
+     * dimensions. we do not, so we also validate dimensions of array objects
+     * to augment class comparison. 
+     */
+    if (is_etch_object_type(((etch_object*)value)->obj_type, ((etch_object*)value)->class_id)) return 0;
+
+    switch(((etch_object*)value)->obj_type)
+    {   case ETCHTYPEB_NATIVEARRAY:
+             source_numdims = ((etch_nativearray*)value)->numdims;
+             break;
+        case ETCHTYPEB_ARRAYVAL:
+             source_numdims = ((etch_arrayvalue*)value)->dim;
+             break;
+        case ETCHTYPEB_ARRAYLIST:
+             source_numdims = 1;
+             break;
+    }
+
+    #if(0)
+    /* this validation was moved to the object validator's validate() */
+    if (is_etch_object_type(((etch_object*)value)->obj_type, ((etch_object*)value)->class_id) && vtor->numdims == 0)
+        result = 0; 
+    else
+    #endif
+    if (source_numdims != vtor->numdimensions) 
+        result = -1;
+    else 
+    if (((etch_object*)value)->class_id != vtor->expected_class_id) 
+    {   
+        /* objects not same class: verify source class assignable to target */
+        etch_objclass target, source;
+        etchvtor_set_classparams(&target, &source, vtor, (etch_object*) value);
+
+        if (etchobj_is_assignable_from(&target, &source));
+        else result = -1;
+    }
+
+    return result;
+}
+
+
+/**
+ * etch_typevtor_check_value()
+ * default implementation
+ */
+int etch_typevtor_check_value(etch_validator* v, etch_object* x, byte* tc)
+{
+    return -1;
+}
+
+
+/**
+ * etch_typevtor_element_validator()
+ * default implementation 
+ */
+etch_validator* etch_typevtor_element_validator(etch_validator* v)
+{
+    return NULL;
+}
+
+
+/**
+ * etch_typevtor_validate_value()
+ * type validator default validate_value() virtual.
+ * note carefully: the returned value may or may not be the same object as the
+ * passed value. the reason for this clunkiness is the port from java, in which
+ * the original could simply be abandoned. the caller must therefore test if the 
+ * objects are the same, and if not, destroy the original. for this reason also,
+ * this method should not be called with the same symbol specified for both the
+ * passed and return objects, for this would leak memory.
+ * note further: the further reason for this is, for example, that the caller 
+ * may get back an etch_byte*, but the object being validated is an etch_int32*
+ * whose value is downsized into a newly instantiated etch_byte. we have padded
+ * out all the primitives to have 8 bytes after the header, so we could, if need
+ * be, morph the object passed to validate_value to be the validated object type.
+ * for example, if we passed an etch_int32 with value 1 to the byte validator, 
+ * currently byte's validate_value would instantiate and return a new etch_byte,
+ * but we could easily change the etch_int32 to an etch_byte, if this would help.
+ */
+etch_object* etch_typevtor_validate_value(etch_validator* vtor, etch_object* value)
+{ 
+    return (0 == vtor->validate(vtor, value))? value: NULL; 
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * boolean validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_validator** etchvtor_cache_boolean  /* boolean validator cache address */
+    = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_BOOLEAN * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_boolean_get()
+ * get a boolean validator for specified dimensions
+ */
+etch_validator* etchvtor_boolean_get(const int ndims)
+{
+    etch_validator* vtor = NULL;
+    if (-1 == etchvtor_check_dimensions(ndims)) return NULL; 
+     
+    if (ndims >= ETCHVTOR_MAX_CACHED)
+        vtor = new_validator_boolean(ndims);
+    else
+    if (NULL == (vtor = etchvtor_cache_boolean[ndims])) 
+        vtor = etchvtor_cache_validator
+                (new_validator_boolean(ndims), etchvtor_cache_boolean); 
+    return vtor;
+}
+
+
+/**
+ * etchvtor_boolean_check_value()
+ * check_value override for boolean validator
+ * returns external type of specified value
+ */
+int etchvtor_boolean_check_value(etch_validator* vtor, 
+    etch_object* value, byte* typecode_out)
+{        
+    if  (-1 == vtor->validate(vtor, value)) return -1;  
+        
+    if  (vtor->numdimensions > 0) 
+         *typecode_out = ETCH_XTRNL_TYPECODE_ARRAY; 
+    else *typecode_out =((etch_boolean*)value)->value?  
+         ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE: ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE;   
+        
+    return 0;
+}
+
+
+/**
+ * etchvtor_boolean_element_validator()
+ * element_validator override for boolean validator
+ * gets validator for array element or scalar
+ */
+etch_validator* etchvtor_boolean_element_validator(etch_validator* vtor)
+{
+    return etchvtor_boolean_get(vtor->numdimensions - 1);
+}
+
+
+/**
+ * new_validator_boolean()
+ * constructor for boolean validator
+ */
+etch_validator* new_validator_boolean(const int numdimensions) 
+{
+    etch_validator* newvtor = NULL;
+    static char* mask = "bool[%d]"; char name[20]; 
+    sprintf(name,mask,numdimensions);
+
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_BOOL, ETCHTYPEB_PRIMITIVE,
+        CLASSID_PRIMITIVE_BOOL, 0, CLASSID_ARRAY_BOOL, numdimensions, name);
+
+    newvtor->check_value = etchvtor_boolean_check_value;
+    newvtor->element_validator = etchvtor_boolean_element_validator;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * byte validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_validator** etchvtor_cache_byte  /* byte validator cache address */
+    = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_BYTE * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_byte_get()
+ * get a byte validator for specified dimensions
+ */
+etch_validator* etchvtor_byte_get(const int ndims)
+{
+    etch_validator* vtor = NULL;
+    if (-1 == etchvtor_check_dimensions(ndims)) return NULL; 
+     
+    if (ndims >= ETCHVTOR_MAX_CACHED)
+        vtor = new_validator_byte(ndims);
+    else
+    if (NULL == (vtor = etchvtor_cache_byte[ndims])) 
+        vtor = etchvtor_cache_validator(
+                 new_validator_byte(ndims), etchvtor_cache_byte); 
+    return vtor;
+}
+    
+
+/**
+ * etchvtor_byte_validate()
+ * validate() override verifying value is in range of byte
+ */
+int etchvtor_byte_validate(etch_validator* vtor, etch_object* value)
+{
+    if (vtor->numdimensions > 0)
+        return etch_typevtor_validate(vtor, value);
+
+    if (NULL == value) return -1;
+
+    switch(((etch_object*)value)->class_id)
+    {   case CLASSID_PRIMITIVE_BYTE: 
+             return 0;
+        case CLASSID_PRIMITIVE_INT32:  
+             return is_inrange_byte(((etch_int32*)value)->value)? 0: -1;
+        case CLASSID_PRIMITIVE_INT64:  
+             return is_inrange_byte(((etch_int64*)value)->value)? 0: -1;
+        case CLASSID_PRIMITIVE_INT16:  
+             return is_inrange_byte(((etch_int16*)value)->value)? 0: -1;
+        case CLASSID_PRIMITIVE_BOOL:
+             return is_inrange_bool(((etch_boolean*)value)->value)? 0: -1; 
+        case CLASSID_PRIMITIVE_INT8:  
+             return 0;
+    }
+
+    return -1;
+}
+
+
+/**
+ * etchvtor_byte_check_value()
+ * check_value override for byte validator
+ * returns external type of specified value
+ */
+int etchvtor_byte_check_value(etch_validator* vtor, 
+    etch_object* value, byte* typecode_out)
+{        
+    if  (-1 == vtor->validate(vtor, value)) return -1;  
+
+    switch(vtor->numdimensions)
+    { case 0:  *typecode_out = ETCH_XTRNL_TYPECODE_BYTE;  break;
+      case 1:  *typecode_out = ETCH_XTRNL_TYPECODE_BYTES; break;
+      default: *typecode_out = ETCH_XTRNL_TYPECODE_ARRAY;
+    }
+   
+    return 0;
+}
+
+
+/**
+ * etchvtor_byte_validate_value()
+ * validate_value override for byte validator
+ */
+etch_object* etchvtor_byte_validate_value(etch_validator* vtor, etch_object* value)
+{     
+    byte byteval = 0;
+
+    etch_object* valobj = etch_typevtor_validate_value(vtor, value);
+    if (NULL == valobj) return NULL;  
+
+    /* here, the returned object is the passed object, caller does no cleanup */
+    if (vtor->numdimensions > 0 || is_etch_byte(value)) return value; 
+
+    if (-1 == etchtagdata_byte_value (value, &byteval)) return NULL;
+
+    /* here, the returned object is not the same as the passed object, 
+     * so caller must replace the reference, and destroy the passed object */
+    return (etch_object*) new_byte(byteval);
+}
+
+
+/**
+ * etchvtor_byte_element_validator()
+ * element_validator override for byte validator
+ * gets validator for array element or scalar
+ */
+etch_validator* etchvtor_byte_element_validator(etch_validator* vtor)
+{
+    return etchvtor_byte_get(vtor->numdimensions - 1);
+}
+
+
+/**
+ * new_validator_byte()
+ * constructor for byte validator
+ */
+etch_validator* new_validator_byte(const int numdimensions) 
+{
+    etch_validator* newvtor = NULL;
+    static char* mask = "byte[%d]"; char name[20]; 
+    sprintf(name,mask,numdimensions);
+
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_BYTE, ETCHTYPEB_PRIMITIVE,
+        CLASSID_PRIMITIVE_BYTE, 0, CLASSID_ARRAY_BYTE, numdimensions, name);
+
+    newvtor->validate          = etchvtor_byte_validate;
+    newvtor->check_value       = etchvtor_byte_check_value;
+    newvtor->validate_value    = etchvtor_byte_validate_value;
+    newvtor->element_validator = etchvtor_byte_element_validator;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * int8 validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_validator** etchvtor_cache_int8  /* int8 validator cache address */
+    = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_INT8 * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_int8_get()
+ * get a int8 validator for specified dimensions
+ */
+etch_validator* etchvtor_int8_get(const int ndims)
+{
+    etch_validator* vtor = NULL;
+    if (-1 == etchvtor_check_dimensions(ndims)) return NULL; 
+     
+    if (ndims >= ETCHVTOR_MAX_CACHED)
+        vtor = new_validator_int8(ndims);
+    else
+    if (NULL == (vtor = etchvtor_cache_int8[ndims])) 
+        vtor = etchvtor_cache_validator(
+                 new_validator_int8(ndims), etchvtor_cache_int8); 
+    return vtor;
+}
+
+
+/**
+ * new_validator_int8()
+ * constructor for int8 validator
+ */
+etch_validator* new_validator_int8(const int numdimensions) 
+{
+    etch_validator* newvtor = NULL;
+    static char* mask = "int8[%d]"; char name[20]; 
+    sprintf(name,mask,numdimensions);
+ 
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_INT8, ETCHTYPEB_PRIMITIVE,
+        CLASSID_PRIMITIVE_INT8, 0, CLASSID_ARRAY_INT8, numdimensions, name);
+
+    newvtor->validate          = etchvtor_byte_validate;
+    newvtor->check_value       = etchvtor_byte_check_value;
+    newvtor->validate_value    = etchvtor_byte_validate_value;
+    newvtor->element_validator = etchvtor_byte_element_validator;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * int16 validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+etch_validator** etchvtor_cache_int16  /* int16 validator cache address */
+  = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_INT16 * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_int16_get()
+ * get a int16 validator for specified dimensions
+ */
+etch_validator* etchvtor_int16_get(const int ndims)
+{
+    etch_validator* vtor = NULL;
+    if (-1 == etchvtor_check_dimensions(ndims)) return NULL; 
+
+    if (ndims >= ETCHVTOR_MAX_CACHED)
+        vtor = new_validator_int16(ndims);
+    else
+    if (NULL == (vtor = etchvtor_cache_int16[ndims])) 
+        vtor = etchvtor_cache_validator(
+                 new_validator_int16(ndims), etchvtor_cache_int16); 
+    return vtor;
+}
+
+
+/**
+ * etchvtor_int16_validate()
+ * validate() override verifying value is in range of short
+ */
+int etchvtor_int16_validate(etch_validator* vtor, etch_object* value)
+{
+    int result = -1;
+
+    if (vtor->numdimensions > 0)
+        result = etch_typevtor_validate(vtor, value);
+    else
+    if (NULL == value) 
+        result = -1;
+    else switch(((etch_object*)value)->class_id)
+    {   case CLASSID_PRIMITIVE_BYTE: 
+        case CLASSID_PRIMITIVE_INT8: 
+        case CLASSID_PRIMITIVE_INT16:  
+             result = 0;
+             break;
+        case CLASSID_PRIMITIVE_INT32:  
+             if (is_inrange_int16(((etch_int32*)value)->value)) 
+                 result = 0;
+             break;
+        case CLASSID_PRIMITIVE_INT64:  
+             if (is_inrange_int16(((etch_int64*)value)->value))
+                 result = 0;
+    }
+
+    return result;
+}
+
+
+/**
+ * etchvtor_int16_check_value()
+ * check_value override for int16 validator
+ * returns external type of specified value
+ */
+int etchvtor_int16_check_value(etch_validator* vtor, 
+    etch_object* value, byte* typecode_out)
+{        
+    short shortval = 0;
+    int result = vtor->validate(vtor, value);
+
+    if  (-1 == result);
+    else    
+    if  (vtor->numdimensions)
+         *typecode_out = ETCH_XTRNL_TYPECODE_ARRAY;
+    else        
+    if  (-1 == (result = etchtagdata_int16_value(value, &shortval)));
+    else
+    if  (is_inrange_byte(shortval))
+         *typecode_out = ETCH_XTRNL_TYPECODE_BYTE;
+    else *typecode_out = ETCH_XTRNL_TYPECODE_SHORT;
+       
+    return result;
+}
+
+
+/**
+ * etchvtor_int16_validate_value()
+ * validate_value override for short int validator
+ */
+etch_object* etchvtor_int16_validate_value(etch_validator* vtor, etch_object* value)
+{     
+    short shortval = 0;
+
+    etch_object* valobj = etch_typevtor_validate_value(vtor, value);
+    if (NULL == valobj) return NULL;  
+
+    /* here, the returned object is the passed object, caller does no cleanup */
+    if (vtor->numdimensions > 0 || is_etch_int16(value))  return value; 
+
+    if (-1 == etchtagdata_int16_value (value, &shortval)) return NULL;
+
+    /* here, the returned object is not the same as the passed object, 
+     * so caller must replace the reference, and destroy the passed object */
+    return (etch_object*) new_int16(shortval);
+}
+
+
+/**
+ * etchvtor_int16_element_validator()
+ * element_validator override for int16 validator
+ * gets validator for array element or scalar
+ */
+etch_validator* etchvtor_int16_element_validator(etch_validator* vtor)
+{
+    return etchvtor_int16_get(vtor->numdimensions - 1);
+}
+
+
+/**
+ * new_validator_int16()
+ * constructor for int16 validator
+ */
+etch_validator* new_validator_int16(const int numdimensions) 
+{
+    etch_validator* newvtor = NULL;
+    static char* mask = "int16[%d]"; char name[20]; 
+    sprintf(name,mask,numdimensions);
+
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_INT16, ETCHTYPEB_PRIMITIVE,
+        CLASSID_PRIMITIVE_INT16, 0, CLASSID_ARRAY_INT16, numdimensions, name);
+
+    newvtor->validate          = etchvtor_int16_validate;
+    newvtor->check_value       = etchvtor_int16_check_value;
+    newvtor->validate_value    = etchvtor_int16_validate_value;
+    newvtor->element_validator = etchvtor_int16_element_validator;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * int32 validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_validator** etchvtor_cache_int32  /* int32 validator cache address */
+    = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_INT32 * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_int32_get()
+ * get a int32 validator for specified dimensions
+ */
+etch_validator* etchvtor_int32_get(const int ndims)
+{
+    etch_validator* vtor = NULL;
+    if (-1 == etchvtor_check_dimensions(ndims)) return NULL; 
+     
+    if (ndims >= ETCHVTOR_MAX_CACHED)
+        vtor = new_validator_int32(ndims);
+    else
+    if (NULL == (vtor = etchvtor_cache_int32[ndims])) 
+        vtor = etchvtor_cache_validator(
+                 new_validator_int32(ndims), etchvtor_cache_int32); 
+    return vtor;
+}
+
+
+/**
+ * etchvtor_int32_validate()
+ * validate() override verifying value is in range of int
+ */
+int etchvtor_int32_validate(etch_validator* vtor, etch_object* value)
+{
+    int result = -1;
+    if (vtor->numdimensions > 0)
+        result = etch_typevtor_validate(vtor, value);
+    else
+    if (NULL == value) 
+        result = -1;
+    else switch(((etch_object*)value)->class_id)
+    {   case CLASSID_PRIMITIVE_BYTE: 
+        case CLASSID_PRIMITIVE_INT8: 
+        case CLASSID_PRIMITIVE_INT16: 
+        case CLASSID_PRIMITIVE_INT32:  
+             result = 0;
+             break;
+        case CLASSID_PRIMITIVE_INT64:  
+             if (is_inrange_int32(((etch_int64*)value)->value))
+                 result = 0;
+    }
+
+    return result;
+}
+
+
+/**
+ * etchvtor_int32_validate_value()
+ * validate_value override for int validator
+ */
+etch_object* etchvtor_int32_validate_value(etch_validator* vtor, etch_object* value)
+{     
+    int intval = 0;
+
+    etch_object* valobj = etch_typevtor_validate_value(vtor, value);
+    if (NULL == valobj) return NULL;  
+
+    /* here, the returned object is the passed object, caller does no cleanup */
+    if (vtor->numdimensions > 0 || is_etch_int32(value))  return value; 
+
+    if (-1 == etchtagdata_int32_value (value, &intval)) return NULL;
+
+    /* here, the returned object is not the same as the passed object, 
+     * so caller must replace the reference, and destroy the passed object */
+    return (etch_object*) new_int32(intval);
+}
+
+
+/**
+ * etchvtor_int32_element_validator()
+ * element_validator override for int32 validator
+ * gets validator for array element or scalar
+ */
+etch_validator* etchvtor_int32_element_validator(etch_validator* vtor)
+{
+    return etchvtor_int32_get(vtor->numdimensions - 1);
+}
+
+
+/**
+ * etchvtor_int32_check_value()
+ * check_value override for int32 validator
+ * returns external type of specified value
+ */
+int etchvtor_int32_check_value(etch_validator* vtor, etch_object* value, byte* typecode_out)
+{        
+    int intval = 0;
+
+    int result = vtor->validate(vtor, value);
+    if (-1 == result);
+    else    
+    if (vtor->numdimensions)
+        *typecode_out = ETCH_XTRNL_TYPECODE_ARRAY;
+    else        
+    if (-1 == (result = etchtagdata_int32_value(value, &intval)));
+    else
+    if  (is_inrange_byte(intval))
+         *typecode_out = ETCH_XTRNL_TYPECODE_BYTE;
+    else
+    if  (is_inrange_int16(intval))
+         *typecode_out = ETCH_XTRNL_TYPECODE_SHORT;
+    else *typecode_out = ETCH_XTRNL_TYPECODE_INT;
+       
+    return result;
+}
+
+
+/**
+ * new_validator_int32()
+ * constructor for int32 validator
+ */
+etch_validator* new_validator_int32(const int numdimensions) 
+{
+    etch_validator* newvtor = NULL;
+    static char* mask = "int32[%d]"; char name[20]; 
+    sprintf(name,mask,numdimensions);
+
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_INT32, ETCHTYPEB_PRIMITIVE,
+       CLASSID_PRIMITIVE_INT32, 0, CLASSID_ARRAY_INT32, numdimensions, name);
+
+    newvtor->validate          = etchvtor_int32_validate;
+    newvtor->check_value       = etchvtor_int32_check_value;
+    newvtor->validate_value    = etchvtor_int32_validate_value;
+    newvtor->element_validator = etchvtor_int32_element_validator;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * int64 validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_validator** etchvtor_cache_int64  /* int64 validator cache address */
+    = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_INT64 * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_int64_get()
+ * get a int64 validator for specified dimensions
+ */
+etch_validator* etchvtor_int64_get(const int ndims)
+{
+    etch_validator* vtor = NULL;
+    if (-1 == etchvtor_check_dimensions(ndims)) return NULL; 
+     
+    if (ndims >= ETCHVTOR_MAX_CACHED)
+        vtor = new_validator_int64(ndims);
+    else
+    if (NULL == (vtor = etchvtor_cache_int64[ndims])) 
+        vtor = etchvtor_cache_validator(
+                new_validator_int64(ndims), etchvtor_cache_int64); 
+    return vtor;
+}
+
+
+/**
+ * etchvtor_int64_validate()
+ * validate() override verifying value is in range of long long
+ */
+int etchvtor_int64_validate(etch_validator* vtor, etch_object* value)
+{
+    int result = -1;
+
+    if (vtor->numdimensions > 0)
+        result = etch_typevtor_validate(vtor, value);
+    else
+    if (NULL == value);
+    else switch(((etch_object*)value)->class_id)
+    {   case CLASSID_PRIMITIVE_BYTE: 
+        case CLASSID_PRIMITIVE_INT8: 
+        case CLASSID_PRIMITIVE_INT16: 
+        case CLASSID_PRIMITIVE_INT32:
+        case CLASSID_PRIMITIVE_INT64:  
+             result = 0;
+    }
+    return result;
+}
+
+
+/**
+ * etchvtor_int64_validate_value()
+ * validate_value override for long validator
+ */
+etch_object* etchvtor_int64_validate_value(etch_validator* vtor, etch_object* value)
+{     
+    int64 longval = 0;
+
+    etch_object* valobj = etch_typevtor_validate_value(vtor, value);
+    if (NULL == valobj) return NULL;  
+
+    /* here, the returned object is the passed object, caller does no cleanup */
+    if (vtor->numdimensions > 0 || is_etch_int64(value)) return value; 
+
+    if (-1 == etchtagdata_int64_value (value, &longval)) return NULL;
+
+    /* here, the returned object is not the same as the passed object, 
+     * so caller must replace the reference, and destroy the passed object */
+    return (etch_object*) new_int64(longval);
+}
+
+
+/**
+ * etchvtor_int64_element_validator()
+ * element_validator override for int64 validator
+ * gets validator for array element or scalar
+ */
+etch_validator* etchvtor_int64_element_validator(etch_validator* vtor)
+{
+    return etchvtor_int64_get(vtor->numdimensions - 1);
+}
+
+
+/**
+ * etchvtor_int64_check_value()
+ * check_value override for int64 validator
+ * returns external type of specified value
+ */
+int etchvtor_int64_check_value(etch_validator* vtor, etch_object* value, byte* typecode_out)
+{        
+    int64 longval = 0;
+
+    int result = vtor->validate(vtor, value);
+    if (-1 == result);
+    else    
+    if (vtor->numdimensions)
+        *typecode_out = ETCH_XTRNL_TYPECODE_ARRAY;
+    else        
+    if (-1 == (result = etchtagdata_int64_value(value, &longval)));
+    else
+    if  (is_inrange_byte(longval))
+         *typecode_out = ETCH_XTRNL_TYPECODE_BYTE;
+    else
+    if  (is_inrange_int16(longval))
+         *typecode_out = ETCH_XTRNL_TYPECODE_SHORT;
+    else
+    if  (is_inrange_int32(longval))
+         *typecode_out = ETCH_XTRNL_TYPECODE_INT;
+    else *typecode_out = ETCH_XTRNL_TYPECODE_LONG;
+       
+    return result;
+}
+
+
+/**
+ * new_validator_int64()
+ * constructor for int64 validator
+ */
+etch_validator* new_validator_int64(const int numdimensions) 
+{
+    etch_validator* newvtor = NULL;
+    static char* mask = "int64[%d]"; char name[20]; 
+    sprintf(name,mask,numdimensions);
+
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_INT64, ETCHTYPEB_PRIMITIVE,
+       CLASSID_PRIMITIVE_INT64, 0, CLASSID_ARRAY_INT64, numdimensions, name);
+
+    newvtor->validate          = etchvtor_int64_validate;
+    newvtor->check_value       = etchvtor_int64_check_value;
+    newvtor->validate_value    = etchvtor_int64_validate_value;
+    newvtor->element_validator = etchvtor_int64_element_validator;
+
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * float validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_validator** etchvtor_cache_float  /* float validator cache address */
+    = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_FLOAT * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_float_get()
+ * get a float validator for specified dimensions
+ */
+etch_validator* etchvtor_float_get(const int ndims)
+{
+    etch_validator* vtor = NULL;
+    if (-1 == etchvtor_check_dimensions(ndims)) return NULL; 
+     
+    if (ndims >= ETCHVTOR_MAX_CACHED)
+        vtor = new_validator_float(ndims);
+    else
+    if (NULL == (vtor = etchvtor_cache_float[ndims])) 
+        vtor = etchvtor_cache_validator(
+                new_validator_float(ndims), etchvtor_cache_float); 
+    return vtor;
+}
+
+
+/**
+ * etchvtor_float_check_value()
+ * check_value override for float validator
+ * returns external type of specified value
+ */
+int etchvtor_float_check_value(etch_validator* vtor, 
+    etch_object* value, byte* typecode_out)
+{        
+   if (-1 == vtor->validate(vtor, value)) return -1;     
+    *typecode_out = (vtor->numdimensions)?
+              ETCH_XTRNL_TYPECODE_ARRAY: ETCH_XTRNL_TYPECODE_FLOAT;     
+    return 0;
+}
+
+
+/**
+ * etchvtor_float_element_validator()
+ * element_validator override for float validator
+ * gets validator for array element or scalar
+ */
+etch_validator* etchvtor_float_element_validator(etch_validator* vtor)
+{
+    return etchvtor_float_get(vtor->numdimensions - 1);
+}
+
+
+/**
+ * new_validator_float()
+ * constructor for float validator
+ */
+etch_validator* new_validator_float(const int numdimensions) 
+{
+    etch_validator* newvtor = NULL;
+    static char* mask = "float[%d]"; char name[20]; 
+    sprintf(name,mask,numdimensions);
+
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_FLOAT, ETCHTYPEB_PRIMITIVE,
+       CLASSID_PRIMITIVE_FLOAT, 0, CLASSID_ARRAY_FLOAT, numdimensions, name);
+
+    newvtor->check_value       = etchvtor_float_check_value;
+    newvtor->element_validator = etchvtor_float_element_validator;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * double validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_validator** etchvtor_cache_double  /* double validator cache address */
+    = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_DOUBLE * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_double_get()
+ * get a double validator for specified dimensions
+ */
+etch_validator* etchvtor_double_get(const int ndims)
+{
+    etch_validator* vtor = NULL;
+    if (-1 == etchvtor_check_dimensions(ndims)) return NULL; 
+     
+    if (ndims >= ETCHVTOR_MAX_CACHED)
+        vtor = new_validator_double(ndims);
+    else
+    if (NULL == (vtor = etchvtor_cache_double[ndims])) 
+        vtor = etchvtor_cache_validator(
+                new_validator_double(ndims), etchvtor_cache_double); 
+    return vtor;
+}
+
+
+/**
+ * etchvtor_double_check_value()
+ * check_value override for double validator
+ * returns external type of specified value
+ */
+int etchvtor_double_check_value(etch_validator* vtor, 
+    etch_object* value, byte* typecode_out)
+{        
+   if (-1 == vtor->validate(vtor, value)) return -1; 
+    
+   *typecode_out = (vtor->numdimensions)?
+              ETCH_XTRNL_TYPECODE_ARRAY: ETCH_XTRNL_TYPECODE_DOUBLE;     
+    return 0;
+}
+
+
+/**
+ * etchvtor_double_element_validator()
+ * element_validator override for double validator
+ * gets validator for array element or scalar
+ */
+etch_validator* etchvtor_double_element_validator(etch_validator* vtor)
+{
+    return etchvtor_double_get(vtor->numdimensions - 1);
+}
+
+
+/**
+ * new_validator_double()
+ * constructor for double validator
+ */
+etch_validator* new_validator_double(const int numdimensions) 
+{
+    etch_validator* newvtor = NULL;
+    static char* mask = "double[%d]"; char name[20]; 
+    sprintf(name,mask,numdimensions);
+
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_DOUBLE, ETCHTYPEB_PRIMITIVE,
+       CLASSID_PRIMITIVE_DOUBLE, 0, CLASSID_ARRAY_DOUBLE, numdimensions, name);
+
+    newvtor->check_value       = etchvtor_double_check_value;
+    newvtor->element_validator = etchvtor_double_element_validator;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * string validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_validator** etchvtor_cache_string  /* string validator cache address */
+    = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_STRING * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_string_get()
+ * get a string validator for specified dimensions
+ */
+etch_validator* etchvtor_string_get(const int ndims)
+{
+    etch_validator* vtor = NULL;
+    if (-1 == etchvtor_check_dimensions(ndims)) return NULL; 
+     
+    if (ndims >= ETCHVTOR_MAX_CACHED)
+        vtor = new_validator_string(ndims);
+    else
+    if (NULL == (vtor = etchvtor_cache_string[ndims])) 
+        vtor = etchvtor_cache_validator(
+                new_validator_string(ndims), etchvtor_cache_string); 
+    return vtor;
+}
+
+
+/**
+ * etchvtor_string_check_value()
+ * check_value override for string validator
+ * returns external type of specified value
+ */
+int etchvtor_string_check_value(etch_validator* vtor, 
+    etch_object* value, byte* typecode_out)
+{     
+    byte typecode = 0;   
+    if (-1 == vtor->validate(vtor, value)) return -1; 
+
+    if  (vtor->numdimensions)
+         typecode = ETCH_XTRNL_TYPECODE_ARRAY;
+    else
+    if  (((etch_string*)value)->char_count)
+         typecode = ETCH_XTRNL_TYPECODE_STRING;
+    else typecode = ETCH_XTRNL_TYPECODE_EMPTY_STRING;
+   
+    if (typecode) *typecode_out = typecode;
+    return 0;
+}
+
+
+/**
+ * etchvtor_string_element_validator()
+ * element_validator override for string validator
+ * gets validator for array element or scalar
+ */
+etch_validator* etchvtor_string_element_validator(etch_validator* vtor)
+{
+    return etchvtor_string_get(vtor->numdimensions - 1);
+}
+
+
+/**
+ * new_validator_string()
+ * constructor for string validator
+ */
+etch_validator* new_validator_string(const int numdimensions) 
+{
+    etch_validator* newvtor = NULL;
+    static char* mask = "string[%d]"; char name[20]; 
+    sprintf(name,mask,numdimensions);
+
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_STRING, ETCHTYPEB_PRIMITIVE,
+       CLASSID_STRING, 0, CLASSID_ARRAY_STRING, numdimensions, name);
+
+    newvtor->check_value       = etchvtor_string_check_value;
+    newvtor->element_validator = etchvtor_string_element_validator;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * object validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_validator** etchvtor_cache_object  /* object validator cache address */
+    = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_OBJECT * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_object_get()
+ * get a object validator for specified dimensions
+ */
+etch_validator* etchvtor_object_get(const int ndims)
+{
+    etch_validator* vtor = NULL;
+    if (-1 == etchvtor_check_dimensions(ndims)) return NULL; 
+     
+    if (ndims >= ETCHVTOR_MAX_CACHED)
+        vtor = new_validator_object(ndims);
+    else
+    if (NULL == (vtor = etchvtor_cache_object[ndims])) 
+        vtor = etchvtor_cache_validator(
+                new_validator_object(ndims), etchvtor_cache_object); 
+    return vtor;
+}
+
+
+/**
+ * etchvtor_object_validate()
+ * any etch c object can be assigned to a scalar etch c object. 
+ * this validation is necessary in the c code whereas it is not in the java version.
+ */
+int etchvtor_object_validate(etch_validator* vtor, etch_object* value)
+{
+    return value? 0: -1;
+}
+
+
+/**
+ * etchvtor_object_check_value()
+ * check_value override for object validator
+ * returns external type of specified value
+ */
+int etchvtor_object_check_value(etch_validator* vtor, 
+    etch_object* value, byte* typecode_out)
+{     
+    if (-1 == vtor->validate(vtor, value)) return -1; 
+
+    if  (vtor->numdimensions)
+         *typecode_out = ETCH_XTRNL_TYPECODE_ARRAY;
+    else *typecode_out = ETCH_XTRNL_TYPECODE_ANY;
+
+    return 0;
+}
+
+
+/**
+ * etchvtor_object_element_validator()
+ * element_validator override for object validator
+ * gets validator for array element or scalar
+ */
+etch_validator* etchvtor_object_element_validator(etch_validator* vtor)
+{
+    return vtor->numdimensions? etchvtor_object_get(vtor->numdimensions - 1): vtor;
+}
+
+
+/**
+ * new_validator_object()
+ * constructor for object validator
+ */
+etch_validator* new_validator_object(const int numdimensions) 
+{
+    etch_validator* newvtor = NULL;
+    static char* mask = "object[%d]"; char name[20]; 
+    sprintf(name,mask,numdimensions);
+
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_OBJECT, ETCHTYPEB_ETCHOBJECT,
+        CLASSID_OBJECT, 0, CLASSID_ARRAY_OBJECT, numdimensions, name);
+
+    newvtor->validate          = etchvtor_object_validate;
+    newvtor->check_value       = etchvtor_object_check_value;
+    newvtor->element_validator = etchvtor_object_element_validator;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * exception validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_validator** etchvtor_cache_exception  /* exception vtor cache address */
+    = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_EXCEPTION * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_exception_get()
+ * get an exception validator  
+ */
+etch_validator* etchvtor_exception_get()
+{
+    etch_validator* vtor = NULL;
+
+    if (NULL == (vtor = etchvtor_cache_exception[0])) 
+        vtor = etchvtor_cache_validator(
+                 new_validator_exception(), etchvtor_cache_exception); 
+    return vtor;
+}
+
+
+/**
+ * etchvtor_exception_check_value()
+ * check_value override for exception validator
+ * returns external type of specified value
+ */
+int etchvtor_exception_check_value(etch_validator* vtor, 
+    etch_object* value, byte* typecode_out)
+{     
+    if (-1 == vtor->validate(vtor, (etch_object*) value)) return -1; 
+    *typecode_out = ETCH_XTRNL_TYPECODE_CUSTOM;
+    return 0;
+}
+
+
+/**
+ * etchvtor_exception_element_validator()
+ */
+etch_validator* etchvtor_exception_element_validator(etch_validator* vtor)
+{
+    return etchvtor_exception_get(0);
+}
+
+
+/**
+ * new_validator_exception()
+ * constructor for exception validator
+ */
+etch_validator* new_validator_exception(const int numdimensions) 
+{
+    etch_validator* newvtor = new_type_validator_1(CLASSID_VALIDATOR_EXCEPTION,
+        ETCHTYPEB_EXCEPTION, CLASSID_EXCEPTION, 0, CLASSID_ARRAY_OBJECT, 0, "excp");
+    newvtor->check_value       = etchvtor_exception_check_value;
+    newvtor->element_validator = etchvtor_exception_element_validator;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * eod object validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_validator** etchvtor_cache_eod  /* eod vtor cache address */
+    = &etchvtor_cache[ETCHVTOR_CACHE_SLOT_EOD * ETCHVTOR_MAX_CACHED];
+
+/**
+ * etchvtor_eod_get()
+ * get an eod object validator  
+ */
+etch_validator* etchvtor_eod_get()
+{
+    etch_validator* vtor = NULL;
+
+    if (NULL == (vtor = etchvtor_cache_eod[0])) 
+        vtor = etchvtor_cache_validator(
+                 new_validator_eod(), etchvtor_cache_eod); 
+    return vtor;
+}
+
+
+/**
+ * etchvtor_eod_validate()
+ * validate() override  
+ */
+int etchvtor_eod_validate(etch_validator* vtor, etch_object* value)
+{
+    return etchtagdata_is_eod(value)? 0: -1;
+}
+
+
+/**
+ * new_validator_eod()
+ * constructor for eod validator
+ */
+etch_validator* new_validator_eod(const int numdimensions) 
+{
+    etch_validator* newvtor = new_type_validator_1(CLASSID_VALIDATOR_EOD,
+        ETCHTYPEB_NONE, CLASSID_NONE, 0, CLASSID_NONE, 0, "eod");
+    newvtor->validate = etchvtor_eod_validate;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * struct validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchvtor_struct_get()
+ * get a struct validator  
+ */
+etch_validator* etchvtor_struct_get(etch_type* type, const int numdims) 
+{
+    etch_validator* vtor = new_validator_struct(type, numdims);
+    /* caller must free this validator since is_cached is false */  
+    return vtor;
+}
+
+
+/**
+ * etchvtor_struct_validate()
+ * validate() override verifying value is struct of expected type
+ */
+int etchvtor_struct_validate(etch_validator* vtor, etch_object* value)
+{
+    int result = etch_typevtor_validate(vtor, value);
+    if (result == -1);
+    else
+    if  (vtor->numdimensions) 
+         if  (is_etch_nativearray(value));
+         else result = -1;
+    else
+    if  (is_etch_struct(value))
+         if  (is_equal_types(vtor->struct_type, 
+                 ((etch_structvalue*)value)->struct_type));
+         else result = -1;
+    else result = -1;
+
+    return result;
+}
+
+
+/**
+ * etchvtor_struct_check_value()
+ * check_value override for struct validator
+ * returns external type of specified value
+ */
+int etchvtor_struct_check_value(etch_validator* vtor, 
+    etch_object* value, byte* typecode_out)
+{     
+    if (-1 == vtor->validate(vtor, (etch_object*) value)) return -1; 
+    *typecode_out = vtor->numdimensions? 
+         ETCH_XTRNL_TYPECODE_ARRAY: ETCH_XTRNL_TYPECODE_CUSTOM;
+    return 0;
+}
+
+
+/**
+ * etchvtor_struct_element_validator()
+ */
+etch_validator* etchvtor_struct_element_validator(etch_validator* vtor)
+{    
+    return etchvtor_struct_get(vtor->struct_type, vtor->numdimensions - 1);
+}
+
+
+/**
+ * new_validator_struct()
+ * constructor for struct validator
+ */
+etch_validator* new_validator_struct (etch_type* type, const int numdimensions)
+{
+    char namebuf[64] = "struct_", ascbuf[64], dimbuf[8], *abuf = ascbuf;
+    etch_validator* newvtor = NULL;
+    if (!type || !is_good_type(type)) return NULL;
+
+    // TODO: pool
+    etch_encoding_transcode_wchar(&abuf, ETCH_ENCODING_UTF8, type->name, NULL);
+
+    strcat(namebuf, abuf); strcat(namebuf, "[");
+    sprintf(dimbuf, "%d", numdimensions);
+    strcat(namebuf, dimbuf); strcat(namebuf, "]");
+    etch_free(abuf);  /* todo change id_name to ascii */     
+
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_STRUCT, ETCHTYPEB_STRUCTVAL,
+        CLASSID_STRUCTVALUE, 0, CLASSID_ARRAY_OBJECT, numdimensions, namebuf);
+
+    newvtor->struct_type = type;
+
+    newvtor->validate          = etchvtor_struct_validate;
+    newvtor->check_value       = etchvtor_struct_check_value;
+    newvtor->element_validator = etchvtor_struct_element_validator;
+    return newvtor;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * custom validator
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchvtor_custom_get()
+ * get a custom validator  
+ */
+etch_validator* etchvtor_custom_get (const unsigned short obj_type, 
+    const unsigned short class_id, etch_type* type, const int numdims) 
+{
+    etch_validator* vtor = new_validator_custom (obj_type, class_id, type, numdims);
+    /* caller must free this validator since is_cached is false */  
+    return vtor;
+}
+
+
+/**
+ * etchvtor_custom_validate()
+ * validate() override verifying value is of expected type
+ */
+int etchvtor_custom_validate (etch_validator* vtor, etch_object* value)
+{
+    int result = etch_typevtor_validate(vtor, value);
+
+    return result;
+}
+
+
+/**
+ * etchvtor_struct_check_value()
+ * check_value override for struct validator
+ * returns external type of specified value.
+ */
+int etchvtor_custom_check_value(etch_validator* vtor, 
+    etch_object* value, byte* typecode_out)
+{     
+    if (-1 == vtor->validate(vtor, (etch_object*) value)) return -1; 
+    *typecode_out = vtor->numdimensions? 
+         ETCH_XTRNL_TYPECODE_ARRAY: ETCH_XTRNL_TYPECODE_CUSTOM;
+    return 0;
+}
+
+
+/**
+ * etchvtor_custom_element_validator()
+ */
+etch_validator* etchvtor_custom_element_validator (etch_validator* vtor)
+{
+    return etchvtor_custom_get(vtor->expected_obj_type, vtor->expected_class_id,  vtor->struct_type, vtor->numdimensions - 1);
+}
+
+
+/**
+ * new_validator_custom()
+ * constructor for custom validator
+ */
+etch_validator* new_validator_custom (const unsigned short obj_type,
+    const unsigned short class_id, etch_type* type, const int numdims)
+{
+    char namebuf[64] = "custom_", ascbuf[64], dimbuf[8], *abuf = ascbuf;
+    etch_validator* newvtor = NULL;
+    if (!type || !is_good_type(type)) return NULL;
+    // TODO: pool
+    etch_encoding_transcode_wchar(&abuf, ETCH_ENCODING_UTF8, type->name, NULL);
+    strcat(namebuf, abuf); strcat(namebuf, "[");
+    sprintf(dimbuf, "%d", numdims);
+    strcat(namebuf, dimbuf); strcat(namebuf, "]");
+    etch_free(abuf);  /* todo change id_name to ascii */
+
+    newvtor = new_type_validator_1(CLASSID_VALIDATOR_CUSTOM, obj_type, class_id, 0, CLASSID_ARRAY_OBJECT, numdims, namebuf);
+
+    newvtor->struct_type = type;
+
+    newvtor->validate          = etchvtor_custom_validate;
+    newvtor->check_value       = etchvtor_custom_check_value;
+    newvtor->element_validator = etchvtor_custom_element_validator;
+    return newvtor;
+}
+
+
+
+
+
+
diff --git a/binding-c/runtime/c/src/main/bindings/msg/etch_value_factory.c b/binding-c/runtime/c/src/main/bindings/msg/etch_value_factory.c
new file mode 100644
index 0000000..ccd7d46
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/msg/etch_value_factory.c
@@ -0,0 +1,169 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_valufact.c
+ * value factory
+ */
+
+#include "etch_value_factory.h"
+#include "etch_tagdata_out.h"
+#include "etch_cache.h"
+#include "etch_message.h"
+#include "etch_objecttypes.h"
+
+/**
+ * value factory virtual function default implementations
+ */
+
+etch_type* vf_add_type (void* vf, etch_type* t) 
+{
+    return NULL;
+}
+
+
+etch_type* vf_get_type_by_id (void* vf, const unsigned id)
+{
+    return NULL;
+}
+
+
+etch_type* vf_get_type_by_name (void* vf, const wchar_t* name) 
+{
+    return NULL;
+}
+	
+
+etch_arraylist* vf_get_types (void* vf)
+{
+    return NULL;
+}
+
+
+wchar_t* vf_get_string_encoding (void* vf)
+{
+    return NULL;
+}
+
+
+etch_int64* vf_get_message_id (void* vf, etch_message* msgobj)
+{
+    return NULL;
+}
+
+
+int vf_set_message_id (void* vf, etch_message* msgobj, etch_int64* msgid)
+{
+    return 0;
+}
+
+  
+etch_int64* vf_get_in_reply_to (void* vf, etch_message* msgobj)
+{
+    return NULL;
+}
+	
+
+int vf_set_in_reply_to (void* vf, etch_message* msgobj, etch_int64* msgid)
+{
+    return 0;
+}
+   
+  
+etch_structvalue* vf_export_custom_value (void* vf, etch_object* value)
+{
+    return NULL;
+}
+	
+
+etch_object* vf_import_custom_value (void* vf, etch_structvalue* svobj)
+{
+    return NULL;
+}
+
+
+etch_type* vf_get_custom_struct_type (void* vf, const unsigned etchclass)
+{
+    return NULL;
+}
+	
+
+etch_type* vf_get_mt_exception (void* vf)
+{
+    return NULL;
+}
+
+
+int destroy_valuefactory(void* data)
+{
+    etch_value_factory* vf = (etch_value_factory*)data;
+
+    if (!is_etchobj_static_content(vf)) {
+        etch_object_destroy(vf->impl);
+    }
+
+    return destroy_objectex((etch_object*)vf);
+}
+
+/**
+ * new_value_factory()
+ * value factory constructor 
+ */
+etch_value_factory* new_value_factory(const int objlen)
+{
+    etch_value_factory* vf = NULL;
+    i_value_factory*  vtab = NULL;
+    const unsigned short CLASS_ID = CLASSID_VALUEFACTORY;
+    int objsize = objlen? objlen: sizeof(etch_value_factory);
+
+    vf = (etch_value_factory*) new_object(objsize, ETCHTYPEB_VALUEFACTORY, CLASSID_VALUEFACTORY);
+    ((etch_object*)vf)->destroy = destroy_valuefactory;
+    ((etch_object*)vf)->clone   = clone_null;
+
+    vtab = etch_cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+    if(!vtab)  
+    {   
+        vtab = new_vtable(NULL, sizeof(i_value_factory), CLASS_ID);
+
+        /* default virtual function implementations */
+        vtab->add_type              = vf_add_type;
+        vtab->export_custom_value   = vf_export_custom_value;
+        vtab->get_in_reply_to       = vf_get_in_reply_to;
+        vtab->get_message_id        = vf_get_message_id;
+        vtab->get_string_encoding   = vf_get_string_encoding;
+        vtab->get_type_by_id        = vf_get_type_by_id;
+        vtab->get_type_by_name      = vf_get_type_by_name;
+        vtab->get_types             = vf_get_types;
+        vtab->import_custom_value   = vf_import_custom_value;
+        vtab->set_in_reply_to       = vf_set_in_reply_to;
+        vtab->set_message_id        = vf_set_message_id;
+        vtab->get_custom_struct_type= vf_get_custom_struct_type;
+        vtab->get_mt_exception      = vf_get_mt_exception;
+
+        etch_cache_insert(((etch_object*)vtab)->get_hashkey(vtab), vtab, FALSE);
+    } 
+
+    ((etch_object*)vf)->vtab = (vtabmask*)vtab;
+    return vf; 
+}
+
+
+
+
+
diff --git a/binding-c/runtime/c/src/main/bindings/support/etch_resources.c b/binding-c/runtime/c/src/main/bindings/support/etch_resources.c
new file mode 100644
index 0000000..ffd22df
--- /dev/null
+++ b/binding-c/runtime/c/src/main/bindings/support/etch_resources.c
@@ -0,0 +1,170 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_resources.c
+ */
+
+#include "etch_resources.h"
+#include "etch_map.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+
+
+
+const wchar_t* ETCH_RESXKEY_SOCKET          = L"SOCKET";
+const wchar_t* ETCH_RESXKEY_ACCEPTED_CONX   = L"ACCEPTED_CONX";
+const wchar_t* ETCH_RESXKEY_POOLTYPE_FREE   = L"FREE_POOL";
+const wchar_t* ETCH_RESXKEY_POOLTYPE_QUEUED = L"QUEUED_POOL";
+const wchar_t* ETCH_RESXKEY_MSGIZER_FORMAT  = L"Messagizer.format";
+const wchar_t* ETCH_RESXKEY_MSGIZER_VALUFACT= L"Messagizer.valueFactory";
+const wchar_t* ETCH_RESXVAL_XPORTFMT_BINARY = L"binary";;
+const wchar_t* ETCH_RESXVAL_XPORTFMT_XML    = L"xml";
+const wchar_t* ETCH_XFACTKEY_TCP   = L"tcp";
+const wchar_t* ETCH_XPORTKEY_START = L"START";
+const wchar_t* ETCH_XPORTKEY_IS_UP = L"IS_UP";
+const wchar_t* ETCH_XPORTKEY_STOP  = L"STOP";
+const wchar_t* ETCH_XPORTKEY_START_AND_WAIT_UP  = L"START_AND_WAIT_UP";
+const wchar_t* ETCH_XPORTKEY_STOP_AND_WAIT_DOWN = L"STOP_AND_WAIT_DOWN";
+
+// TODO - lose the above strings, replacing them with integer constants
+
+const int ETCH_RESKEY_SOCKET           = 0x100;
+const int ETCH_RESKEY_POOLTYPE_FREE    = 0x101;
+const int ETCH_RESKEY_POOLTYPE_QUEUED  = 0x102;
+const int ETCH_RESKEY_MSGIZER_FORMAT   = 0x104;
+const int ETCH_RESKEY_MSGIZER_VALUFACT = 0x105;
+const int ETCH_RESVAL_XPORTFMT_BINARY  = 0x140;
+const int ETCH_RESVAL_XPORTFMT_XML     = 0x141;
+const int ETCH_XPKEY_TCP               = 0x142;
+const int ETCH_XPKEY_START             = 0x160;
+const int ETCH_XPKEY_IS_UP             = 0x161;
+const int ETCH_XPKEY_STOP              = 0x162;
+const int ETCH_XPKEY_START_AND_WAITUP  = 0x163;
+const int ETCH_XPKEY_STOP_AND_WAITDOWN = 0x164;
+const int ETCH_XPKEY_XPORTFMT_XML      = 0x165;
+
+// TODO - I don't think we need these at all, we should use class_id
+// since in this way the object can be identified and we don't need
+// to assume that the enclosing object is an etch_int32. however not
+// all of these IDs are objects, some are table IDs
+ 
+const wchar_t* ETCH_RESXKEY_SOCKET;
+const wchar_t* ETCH_RESXKEY_ACCEPTED_CONX;
+const wchar_t* ETCH_RESXKEY_POOLTYPE_FREE;
+const wchar_t* ETCH_RESXKEY_POOLTYPE_QUEUED;
+const wchar_t* ETCH_RESXKEY_MSGIZER_FORMAT;
+const wchar_t* ETCH_RESXKEY_MSGIZER_VALUFACT;
+const wchar_t* ETCH_RESXVAL_XPORTFMT_BINARY;
+const wchar_t* ETCH_RESXVAL_XPORTFMT_XML;
+const wchar_t* ETCH_XFACTKEY_TCP;
+const wchar_t* ETCH_XPORTKEY_START;
+const wchar_t* ETCH_XPORTKEY_START_AND_WAIT_UP;
+const wchar_t* ETCH_XPORTKEY_IS_UP;
+const wchar_t* ETCH_XPORTKEY_STOP;
+const wchar_t* ETCH_XPORTKEY_STOP_AND_WAIT_DOWN;
+
+
+/*
+ * new_etch_resources 
+ * etch_resources constructor
+ */
+etch_resources* new_etch_resources(const int initialsize)
+{
+    etch_resources* resx   = new_hashtable(initialsize);
+    resx->content_type     = ETCHHASHTABLE_CONTENT_OBJECT; 
+    resx->content_obj_type = ETCHTYPEB_ETCHOBJECT;
+    resx->content_class_id = CLASSID_ANY;
+    resx->is_readonly_keys = resx->is_readonly_values = FALSE;
+    resx->freehook = string_to_object_clear_handler;  /* frees memory on clear */
+    return resx;
+}
+
+
+/*
+ * etch_resources_add()  
+ * adds specified key/value pair to specified resource map
+ */
+int etch_resources_add (etch_resources* resources, const wchar_t* key, etch_object* val)
+{
+    const int hashkey = etchmap_insertxw(resources, (wchar_t*) key, val, TRUE);
+    return hashkey? 0: -1;   
+}
+
+
+/*
+ * etch_resources_get()  
+ */
+etch_object* etch_resources_get (etch_resources* resources, const wchar_t* key)
+{
+    etch_object* founditem = etchmap_findxw(resources, (wchar_t*) key, NULL);
+    return founditem;
+}
+
+
+/*
+ * etch_resources_clear()  
+ * clear a resources map, assuming all objects are owned unless marked as a static resource.
+ * @return count of items both removed from the map and freed.
+ */
+int etch_resources_clear (etch_resources* resources)
+{         // TODO lose this method or augment it to delete the hashtable entry memory also
+          // it leaves the memory the hashtable allocated for the key intact
+    int  freedcount = 0;
+    etch_iterator iterator;
+    wchar_t* thiskey = NULL;
+    if (!is_etch_hashtable(resources)) return 0;
+    set_iterator(&iterator, resources, &resources->iterable);
+
+    while(iterator.has_next(&iterator)) 
+    {
+        etch_object* value = iterator.current_value;
+
+        if (value && !is_etchobj_static_resource(value))
+        {   
+            etch_object_destroy(value);
+            freedcount++;
+        }
+
+        thiskey = iterator.current_key;
+        etch_free(thiskey);
+
+        iterator.next(&iterator);
+    }
+
+    return freedcount;
+}
+
+
+/*
+ * etch_resources_replace()  
+ * adds specified key/value pair to specified resource map, first removing prior item.
+ */
+int etch_resources_replace (etch_resources* resources, const wchar_t* key, etch_object* val)
+{
+    if (etch_resources_get (resources, key))
+    {
+        etch_object* removedobj = etchmap_delxw (resources, (wchar_t*) key);
+
+        if (removedobj)
+            if (!is_etchobj_static_resource(removedobj))
+                etch_object_destroy(removedobj);
+    }
+
+    return etch_resources_add (resources, key, val);
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_arraylist.c b/binding-c/runtime/c/src/main/common/etch_arraylist.c
new file mode 100644
index 0000000..aeaa243
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_arraylist.c
@@ -0,0 +1,789 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_arraylist.c -- implementation of arraylist.
+ */
+
+#include "etch_arraylist.h"
+#include "etch_mutex.h"
+#include "etch_mem.h"
+#include "etch_objecttypes.h"
+
+extern etch_pool_t* g_etch_main_pool;
+
+static int _destroy_arraylist(void*);
+
+/**
+ * new_etch_arraylist()
+ * constructor for an etch_arraylist, which implements i_iterable.
+ * passed initial size, and initial expansion delta, both expressed as 
+ * number of entries.
+ */
+etch_arraylist* new_etch_arraylist(const unsigned int initsize, const unsigned int deltsize)
+{
+    etch_arraylist* list = (etch_arraylist*) new_object(sizeof(etch_arraylist), ETCHTYPEB_ARRAYLIST, CLASSID_ETCH_ARRAYLIST); 
+   
+    list->size  = initsize > 0? initsize: ETCHARRAYLIST_DEFSIZE;
+    list->delta = deltsize > 0? deltsize: list->size;
+    list->size *= sizeof(void**); list->delta *= sizeof(void**);
+    list->base  = etch_malloc(list->size, ETCHTYPEB_BYTES);
+    memset(list->base, 0, list->size);
+
+    ((etch_object*)list)->destroy = _destroy_arraylist;
+
+    new_iterable(&list->iterable, NULL,
+        etch_arraylist_iterable_first, 
+        etch_arraylist_iterable_next, 
+        etch_arraylist_iterable_has_next);
+
+    return list;
+}
+
+
+/**
+ * new_arraylist_from()
+ */
+etch_arraylist* new_etch_arraylist_from(etch_arraylist* thatlist)
+{
+    etch_arraylist* thislist = new_etch_arraylist(thatlist->size, thatlist->delta);
+
+    etch_arraylist_copyattrs(thislist, thatlist);
+
+    memcpy(thislist->base, thatlist->base, thatlist->count * sizeof(void*));
+    thislist->count = thatlist->count;
+
+    return thislist;
+}
+
+/**
+ * new_arraylist_synchronized()
+ * constructor for an etch_arraylist, which implements i_iterable.
+ * passed initial size, and initial expansion delta, both expressed as 
+ * number of entries.
+ */
+etch_arraylist* new_etch_arraylist_synchronized(const unsigned int initialsize, const unsigned int deltasize)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_arraylist* arraylist = NULL;
+    
+    arraylist = new_etch_arraylist(initialsize, deltasize);
+
+    // TODO: pool
+    status = etch_mutex_create(&((etch_object*)arraylist)->synclock, ETCH_MUTEX_NESTED, NULL);
+    if(status != ETCH_SUCCESS) {
+        // errror
+    }
+    return arraylist;
+}
+
+/**
+ * new_etch_arraylist_synchronized_from()
+ */
+etch_arraylist* new_etch_arraylist_synchronized_from(etch_arraylist* thatlist)
+{
+    etch_arraylist* thislist = new_etch_arraylist_synchronized(thatlist->size, thatlist->delta);
+
+    etch_arraylist_copyattrs(thislist, thatlist);
+
+    memcpy(thislist->base, thatlist->base, thatlist->count * sizeof(void*));
+    thislist->count = thatlist->count;
+
+    return thislist;
+}
+
+/**
+ * etcharraylist_destroy()
+ * destructor for an etch_arraylist.
+ * destroys the underlying list, the list shell, and the list content if requested.
+ * note that arraylist always owns its buffer and mutex. setting static content on
+ * an arraylist object applies only to the array content objects, if indeed content
+ * consists of object. if content is other than object, static content has no effect
+ * since the content buffer is freed regardless. 
+ */
+void etch_arraylist_destroy(etch_arraylist* list, const int is_free_content) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+
+    if(((etch_object*)list)->synclock != NULL) {
+        // disallow multiple destroy
+        status = etch_mutex_trylock(((etch_object*)list)->synclock);
+        if(status != ETCH_SUCCESS) {
+            return;
+        }
+    }
+
+
+    if (!is_etchobj_static_content(list)) /* clear and free content */
+        etch_arraylist_clear(list, is_free_content);
+
+    etch_free(list->base);  /* arraylist always owns its buffer */
+
+    if(((etch_object*)list)->synclock) {
+        // release and free mutex
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        status = etch_mutex_destroy(((etch_object*)list)->synclock);
+    
+    }
+
+   if (!is_etchobj_static_shell(list))
+       etch_free(list);    /* free list object */
+}
+
+
+static int _destroy_arraylist(void* data)
+{
+  etch_arraylist* list = data;
+    etch_arraylist_destroy(list, !list->is_readonly);
+    return 0;
+}
+
+
+
+/* - - - - - - - - - - 
+ * list maintenance
+ * - - - - - - - - - - 
+ */
+
+/**
+ * _arraylist_realloc()
+ * private method to resize an arraylist.
+ * if a size greater than current size is specified, the list is realloced to that size,
+ * otherwise it is realloced to current size plus the delta size specified at construction.
+ * @note presumed that this is invoked only via _arraylist_checksize, thus synchronized.
+ */
+int _arraylist_realloc(etch_arraylist* list, const unsigned size)    
+{
+    unsigned int copylength = 0, newsize = 0;
+    void* newbase = NULL;
+
+    newsize = size > list->size? size: list->size + list->delta;
+    newbase = etch_malloc(newsize, ETCHTYPEB_BYTES);
+    memset(newbase, 0, newsize);
+
+    copylength = list->count * sizeof(void**);
+    memcpy(newbase, list->base, copylength); 
+
+    etch_free(list->base);
+    list->base = newbase;
+    list->size = newsize;
+    return 0;
+}
+
+
+/**
+ * _arraylist_checksize()
+ * private method ensures list has space required for pending content insertion.
+ */
+int _arraylist_checksize(etch_arraylist* list, const int pendingitems, const int is_locked)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int result = 1;
+    unsigned currsize = 0, newspace = pendingitems * sizeof(void**);
+
+    if(((etch_object*)list)->synclock != NULL && !is_locked) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    currsize = list->count * sizeof(void**);
+
+    if  (currsize + newspace > list->size)
+         _arraylist_realloc(list, newspace > list->delta? newspace: 0);
+    else
+        result = 0;
+
+    if(((etch_object*)list)->synclock != NULL && !is_locked) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;
+}
+
+
+/*
+ * arraylist_clear() 
+ * remove all content from the arraylist, freeing content memory only if requested. 
+ * note that the list buffer does not shrink, rather retaining its current size.
+ */
+void etch_arraylist_clear(etch_arraylist* list, const int is_free_content) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+    void** p = NULL;
+    arraycallback callback = NULL;
+    int items = 0, is_obj_content = 0, i = 0, freehandled = 0;
+    if (NULL == list || NULL == list->base) return;
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    is_obj_content = list->content_type == ETCHARRAYLIST_CONTENT_OBJECT;
+    callback = list->freehook;
+    items = list->count;
+    p = list->base;
+
+    if (is_free_content && !list->is_readonly)
+        for(; i < (const int) items; i++, p++)
+        {   
+            /* optional callback to handle free */                                    
+            freehandled = callback? callback(i, *p): FALSE; 
+
+            /* if we've marked the array as having etch object content, 
+             * we invoke the object's destructor. */
+            if  (freehandled);
+            else
+            if  (is_obj_content)
+                ((etch_object*)*p)->destroy(*p);
+            else etch_free(*p);
+        }
+
+    memset(list->base, 0, items * sizeof(void**)); 
+    list->count = 0;  
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+}
+
+
+/* - - - - - - - - - - 
+ * list api
+ * - - - - - - - - - - 
+ */
+
+/*
+ * arraylist_add_from() 
+ * add entries to the end of the list.
+ * returns count if items entered, or -1 if error.
+ * note that if the target array is not marked read only, this method must be
+ * used with great caution. since an arraylist not so marked will attempt to
+ * destroy its content when destroyed, and since we are copying memory references
+ * from one array to another here, the second destructor would attempt to free
+ * memory already freed in the first destructor. so to be safe, this method 
+ * should be used only with arrays marked is_readonly = TRUE, and content_type =
+ * ETCHARRAYLIST_CONTENT_OBJECT.
+ */
+int etch_arraylist_add_from(etch_arraylist* list, etch_arraylist* newitems, etch_comparator compare) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int count = 0;
+    etch_iterator iterator;
+    if (!list || !list->base) return -1; 
+    if (newitems->count == 0) return 0;
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    set_iterator(&iterator, newitems, &newitems->iterable);
+
+    while(iterator.has_next(&iterator))
+    {
+        if (etch_arraylist_contains(list, iterator.current_value, 0, compare))
+            continue;
+
+        _arraylist_checksize(list, 1, TRUE);  
+
+        list->base[list->count++] = iterator.current_value;
+        count++;
+
+        iterator.next(&iterator); 
+    }
+ 
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return count;
+}
+
+
+/*
+ * etch_arraylist_add() 
+ * add an entry to the end of the list.
+ */
+int etch_arraylist_add(etch_arraylist* list, void* content) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+
+    if (!list || !list->base) return -1; 
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    _arraylist_checksize(list, 1, TRUE);  
+
+    list->base[list->count++] = content;
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return 0;
+}
+
+
+/*
+ * etch_arraylist_insert() 
+ * add a node anywhere in the list, returning 0 if OK, or -1 if error.
+ * this implementation cannot insert past the current end of list,
+ * in other words to insert at index n, there must be at least n
+ * entries currently in the list (list->count >= n), that is to say,
+ * the insertion must expand the size of the list by exactly one slot.
+ */
+int etch_arraylist_insert(etch_arraylist* list, const unsigned int i, void* content)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    unsigned shiftcount = 0, result = -1, j = 0;
+    void **p = NULL, **q = NULL;
+    if ((NULL == list) || (i < 0)) return -1;
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    _arraylist_checksize(list, 1, TRUE);
+
+    if (i <= list->count)
+    {
+        shiftcount = list->count - i;  /* shift higher entries up */
+        p = &list->base[list->count - 1];  
+        q = &list->base[list->count];
+
+        for(j = 0; j < (const unsigned) shiftcount; j++, p--, q--)
+            *q = *p;
+        
+        list->base[i] = content;
+        ++list->count;
+        result = 0;
+    }  
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;
+}
+
+
+/*
+ * etch_arraylist_containsp() 
+ * return 1 or 0 indicating if the list contains the supplied content pointer.
+ */
+int etch_arraylist_containsp(etch_arraylist* list, void* content, const unsigned startat)
+{
+    return etch_arraylist_indexofp(list, content, startat) == -1? FALSE: TRUE;
+}
+
+/*
+ * etch_arraylist_count()
+ * return the number of elements or -1 if list is NULL
+ */
+int etch_arraylist_count(etch_arraylist* list)
+{
+    if (NULL==list)
+        return -1;
+    else
+        return list->count;
+}
+
+/*
+ * etch_arraylist_indexofp() 
+ * if the list contains the supplied content pointer, return its index;
+ * return -1 if not found or if a parameter was in error.
+ */
+int etch_arraylist_indexofp(etch_arraylist* list, void* content, const unsigned startat)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    void** p = NULL;
+    int result = -1;
+    unsigned int i = startat;
+    if ((NULL == list) || (i < 0)) return result;
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (i < list->count)
+    {
+        p = &list->base[i];
+
+        for(; i < list->count; i++, p++)  
+        {       
+            if (*p == content) 
+            {   result = i;
+                break;
+            }
+        }
+    }  
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;
+}
+
+
+/*
+ * arraylist_contains() 
+ * return 1 or 0 indicating if the list contains the supplied content. 
+ * caller must supply a comparator function int (*f)(void* this, void* that);  
+ * which should return -2 bad params, -1 compares less, 0 equal, 1 greater. 
+ */
+int etch_arraylist_contains(etch_arraylist* list, void* content, const unsigned startat,
+    etch_comparator compare)
+{
+    return etch_arraylist_indexof(list, content, startat, compare) == -1? FALSE: TRUE;
+}
+
+
+/*
+ * etch_arraylist_indexof() 
+ * if the list contains the supplied content, return its index.
+ * return -1 if a parameter was in error.
+ * caller must supply a comparator function int (*f)(void* this, void* that); 
+ * which should return -2 bad params, -1 compares less, 0 equal, 1 greater. 
+ */
+int etch_arraylist_indexof(etch_arraylist* list, 
+    void* content, const unsigned startat, etch_comparator compare)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    void** p   = NULL;
+    unsigned i = startat;
+    int result = -1;
+    if ((NULL == list) || (i < 0)) return result;
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (i < list->count)  
+    {
+        p = &list->base[i];
+
+        for(; i < list->count; i++, p++)
+        {  
+            if (0 == compare(content, *p)) 
+            {   result = i;
+                break;
+            }
+        }
+    }  
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+     
+    return result;
+}
+
+
+/*
+ * etch_arraylist_set() 
+ * replace content at specified index position.
+ */
+int etch_arraylist_set (etch_arraylist* list, const unsigned i, void* content)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int result = -1;
+    if ((NULL == list) || (i < 0)) return -1;
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (i < list->count)  
+    {
+        list->base[i] = content;
+        result = 0;
+    }
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;
+}
+
+
+/*
+ * etch_arraylist_get() 
+ * return content at specified index position, or NULL if parameter error.
+ * a non-disposable reference is returned. 
+ * todo: mark arraylist content objects static, such that destroy() is benign,
+ * unlocking them only at such time as the arraylist itself is cleared or 
+ * destroyed, or a remove() with is_free_content is requested.
+ */
+void* etch_arraylist_get (etch_arraylist* list, const unsigned i)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    void* result = NULL;
+    if ((NULL == list) || (i < 0)) return NULL;
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (i < list->count)  
+        result = list->base[i];
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;
+}
+
+
+/*
+ * etch_arraylist_remove() 
+ * remove entry at specified index position, freeing content memory if requested.
+ * return -1 if a parameter was in error, or zero if OK.
+ */
+int etch_arraylist_remove (etch_arraylist* list, const unsigned i, const int is_free_content)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    unsigned j = 0, newcount = 0, is_obj_content = 0, freehandled = 0, result = -1;
+    arraycallback callback = NULL;
+    void *content = NULL, **p = NULL, **q = NULL;
+    if ((NULL == list) || (i < 0)) return -1;
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (i < list->count) 
+    {
+        is_obj_content = list->content_type == ETCHARRAYLIST_CONTENT_OBJECT;
+        callback = list->freehook;
+        
+        if (is_free_content && !list->is_readonly)
+        {
+            if (content = list->base[i])
+            {                                            
+                freehandled = callback? callback(i, content): FALSE; 
+                if  (freehandled);
+                else
+                if  (is_obj_content)
+                    ((etch_object*)content)->destroy(content);            
+                else etch_free(content);
+            }
+        }
+         
+        newcount = list->count - 1;
+        p = &list->base[i];      /* shift higher entries down */
+        q = &list->base[i + 1];  /* we eschew platform-dependent memmove() */
+
+        for(j = i; j < (const unsigned)newcount; j++, p++, q++)
+            *p = *q;
+
+        list->base[newcount] = NULL;  /* zero the now-extra slot */
+        list->count = newcount;
+        result = 0;
+    }  
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;
+}
+
+
+/*
+ * arraylist_remove_content() 
+ * remove entry whose value is specified.
+ */
+int etch_arraylist_remove_content(etch_arraylist* list, 
+    void* content, const unsigned startat, etch_comparator compare)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int result = -1, index = 0;
+    if (NULL == list) return result;
+
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (-1 != (index = etch_arraylist_indexof(list, content, startat, compare)))     
+        result = etch_arraylist_remove(list, index, TRUE);  
+     
+    if(((etch_object*)list)->synclock != NULL) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result; 
+}
+
+
+/* 
+ * etch_arraylist_copyattrs()
+ * copy array attributes from one array to another
+ */
+void etch_arraylist_copyattrs(etch_arraylist* to, etch_arraylist* from)
+{
+    ((etch_object*)to)->class_id         = ((etch_object*)from)->class_id;
+    to->content_obj_type = from->content_obj_type;
+    to->content_class_id = from->content_class_id; 
+    ((etch_object*)to)->is_static        = ((etch_object*)from)->is_static;
+    to->content_type     = from->content_type;
+    to->is_readonly      = from->is_readonly;
+    to->freehook         = from->freehook;
+}
+
+
+/* - - - - - - - - - - 
+ * iteration lock
+ * - - - - - - - - - - 
+ */
+
+/* 
+ * etch_arraylist_getlock()
+ * explicitly set this list's synchronization lock, waiting if unavailable.
+ * this should be used only for locking a list prior to iterating the list.   
+ * for synchronization of list operations, the presence of list.synchook  
+ * and list.synclock is sufficient. 
+ */
+int etch_arraylist_getlock (etch_arraylist* list)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    ETCH_ASSERT(list && ((etch_object*)list)->synclock);
+    if(((etch_object*)list)->synclock) {
+        status = etch_mutex_lock(((etch_object*)list)->synclock);
+        if(status != ETCH_SUCCESS) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+
+/* 
+ * etch_arraylist_trylock()
+ * explicitly set this list's synchronization lock, failing if unavailable.
+ * this should be used only for locking a list prior to iterating the list.   
+ * for synchronization of list operations, the presence of list.synchook  
+ * and list.synclock is sufficient. 
+ */
+int etch_arraylist_trylock (etch_arraylist* list)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    ETCH_ASSERT(list && ((etch_object*)list)->synclock);
+    if(((etch_object*)list)->synclock) {
+        status = etch_mutex_trylock(((etch_object*)list)->synclock);
+        if(status != ETCH_SUCCESS) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/* 
+ * etch_arraylist_rellock()
+ * release explicitly set this list's synchronization lock.
+ * this should be used only for unlocking a list after iterating the list.   
+ * for synchronization of list operations, the presence of list.synchook  
+ * and list.synclock is sufficient. 
+ */
+int etch_arraylist_rellock (etch_arraylist* list) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+    ETCH_ASSERT(list && ((etch_object*)list)->synclock);
+    if(((etch_object*)list)->synclock) {
+        status = etch_mutex_unlock(((etch_object*)list)->synclock);
+        if(status != ETCH_SUCCESS) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+
+/* - - - - - - - - - - 
+ * i_iterable
+ * - - - - - - - - - - 
+ */
+
+/*
+ * etch_arraylist_iterable_first() 
+ * i_iterable first() implementation
+ */
+int etch_arraylist_iterable_first(etch_iterator* iter)
+{
+    etch_arraylist* list = NULL;
+    if (!iter || !iter->collection)  return -1;
+    list = iter->collection;
+    if (!list->base || !list->count) return -1;
+
+    iter->current_value = etch_arraylist_get(list, 0);   
+    iter->ordinal = iter->current_value? 1: 0;
+    return iter->ordinal? 0: -1;
+}
+
+
+/*
+ * etch_arraylist_iterable_next() 
+ * i_iterable next() implementation
+ * functions as first() if there is no current position.
+ */
+int etch_arraylist_iterable_next(etch_iterator* iter)
+{
+    etch_arraylist* list = iter? iter->collection: NULL;
+    const int count = list? list->count: 0;
+    if (!count || !iter->ordinal) return -1;
+    
+    iter->current_value = etch_arraylist_get(list, iter->ordinal); 
+    iter->ordinal = iter->current_value? ++iter->ordinal: 0;
+    return iter->ordinal? 0: -1;
+}
+
+
+/*
+ * etch_arraylist_iterable_has_next() 
+ * i_iterable has_next() implementation.
+ */
+int etch_arraylist_iterable_has_next(etch_iterator* iter)
+{
+    etch_arraylist* list = iter? iter->collection: NULL;
+    const int count = list? list->count: 0;
+    return count && iter->ordinal && (iter->ordinal <= count);
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_cache.c b/binding-c/runtime/c/src/main/common/etch_cache.c
new file mode 100644
index 0000000..017fcfc
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_cache.c
@@ -0,0 +1,429 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_cache.h -- etch cache methods.
+ */
+
+#include "etch_cache.h"
+#include "etch_hash.h"
+
+#define ETCH_CACHE_USES_ALPHA_KEY
+#define ETCH_CACHE_DEBUG FALSE
+#define ETCH_CACHE_INITIAL_SIZE 32
+#define ETCH_CACHE_KEYBUFLEN 20
+
+etch_cache_t* g_etch_cache = NULL;
+etch_mutex* g_etch_cache_mutex = NULL;
+
+/*
+ * ETCH_CACHE_USES_ALPHA_KEY switches on alpha cache keys rather than the normal
+ * 4-byte integer. experiencing a problem with either the hfirst or hnext 
+ * hashtable functionality, this was an attempt to determine if the 4-byte keys
+ * were causing the problem. it appears not, so we can probably use int keys again.
+ */
+#ifdef ETCH_CACHE_USES_ALPHA_KEY
+
+char ckey[ETCH_CACHE_KEYBUFLEN];
+
+/*
+ * make_cache_key() 
+ * given 32-bit key constructs alpha key for the cache returning key byte length
+ */
+static int etch_make_cache_key(const unsigned int ikey)
+{
+   char* pkey = ckey;
+   sprintf(pkey,"%d", ikey);
+   return (int)strlen(ckey);
+}
+
+/*
+ * etch_cache_populate_out() 
+ * populate caller's out struct
+ */
+static void etch_cache_populate_out(etch_hashitem* useritem, etch_hashitem* curritem)
+{
+    useritem->key   = curritem->key;
+    useritem->value = curritem->value;
+    useritem->hash  = curritem->hash;
+}
+
+/*
+ * cache_findxl() 
+ */
+void* etch_cache_findxl(char* key, unsigned keylen, void** out)
+{
+    etch_hashitem  hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+    int result = jenkins_find
+      (g_etch_cache->realtable, key, keylen, 0, (void**)&founditem);
+
+    #if ETCH_CACHE_DEBUG
+    #pragma warning(disable:4313) 
+    if  (result == 0) 
+         printf("cache_found key %s len %d addr %08x\n", 
+                 key, keylen, founditem->value);
+    else printf("cache_notfound key %s len %d\n", key, keylen);
+    #endif 
+  
+    if (result == -1) return NULL;
+
+    if (out)
+        etch_cache_populate_out(*out, founditem);
+
+    return founditem->value;
+}
+
+
+/*
+ * cache_find() 
+ * locate cached object with specified key, returning it or NULL
+ */
+void* etch_cache_find(const unsigned int objtype, void** out)
+{
+    unsigned keylen = 0;
+    void* res = NULL;
+    etch_mutex_lock(g_etch_cache_mutex);
+    keylen = etch_make_cache_key(objtype);
+    res = etch_cache_findxl(ckey, keylen, out);
+    etch_mutex_unlock(g_etch_cache_mutex);
+    return res;
+}
+
+
+/*
+ * cache_findx() 
+ * locate cached object with specified ansi char key, returning it or NULL
+ */
+void* etch_cache_findx(char* key, void** out)
+{
+    unsigned keylen = (unsigned)strlen(key);
+
+    return etch_cache_findxl(key, keylen, out);
+}
+
+
+/*
+ * cache_find_by_hash() 
+ * locate cached object with specified hashkey, returning it or NULL
+ */
+void* etch_cache_find_by_hash(const unsigned hash, void** out)
+{
+    int result;
+    etch_hashitem  hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+    result = jenkins_findh(g_etch_cache->realtable, hash, 0, (void**)&founditem);
+
+    if (result == -1) return NULL;
+
+    if (out)
+        etch_cache_populate_out(*out, founditem);       
+    
+    return founditem->value;
+}
+
+
+/*
+ * cache_current() 
+ * return cached object at current position
+ */
+etch_hashitem* etch_cache_current()
+{
+    int result;
+    etch_hashitem  hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+    result = jenkins_current(g_etch_cache->realtable, 0, (void**)&founditem);
+
+    return (result == -1)? NULL: founditem;
+}
+
+
+/*
+ * cache_delxl() 
+ * Remove specified object from cache given ansi char key and length.
+ * Return pointer to cached object, which is not freed here.
+ */
+void* etch_cache_delxl(char* key, const unsigned keylen)
+{
+    etch_hashitem hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+    int result = jenkins_remove
+      (g_etch_cache->realtable, ckey, keylen, 0, (void**)&founditem);
+
+    if (result == -1) return NULL;
+    free(founditem->key); /* free 4-byte key allocated in cache_add() */
+    return founditem->value;
+}
+
+
+/*
+ * cache_del() 
+ * Remove specified object from cache given integer key.
+ * Return pointer to cached object, which is not freed here.
+ */
+void* etch_cache_del(const unsigned int objtype)
+{
+    unsigned keylen = 0;
+    void* res = NULL;
+    
+    etch_mutex_lock(g_etch_cache_mutex);
+    keylen = etch_make_cache_key(objtype);
+    res = etch_cache_delxl(ckey, keylen);
+    etch_mutex_unlock(g_etch_cache_mutex);
+    return res;
+}
+
+
+/*
+ * cache_delx() 
+ * Remove specified object from cache given ansi char key.
+ * Return pointer to cached object, which is not freed here.
+ */
+void* etch_cache_delx (char* key)
+{
+    unsigned keylen = (unsigned)strlen(key);
+
+    return etch_cache_delxl(key, keylen);
+}
+
+
+/*
+ * cache_insertxl() 
+ * Add specified object to cache given ansi char key and char length, 
+ * with existence test optional.
+ * Return hash of supplied key, or zero.
+ */
+int etch_cache_insertxl (char* key, const unsigned keylen, void* data, const int is_check)
+{
+    int   result = 0, keylent = 0;
+    char* pkey = NULL;
+    void* pval = NULL;
+    etch_hashitem  hashbucket; 
+    etch_hashitem* inserteditem = &hashbucket;
+    memset(&hashbucket, 0, sizeof(etch_hashitem));
+
+    if (is_check)
+      {   pval = etch_cache_findxl(key, keylen, (void**)&inserteditem);
+        if (pval) return inserteditem->hash; /* entry exists */
+    }
+
+    keylent = keylen + 1;/* add new entry */
+    pkey    = etch_malloc(keylent, 0); 
+	strcpy(pkey, key);
+
+    #if CACHE_DEBUG
+    #pragma warning(disable:4313) 
+    printf("cache_insertxl key %s len %d addr %08x\n", pkey, keylen, data); 
+    #endif
+
+    result = jenkins_insert
+      (g_etch_cache->realtable, pkey, keylen, data, 0, 0, (void**)&inserteditem);
+
+    /* cache_dump(); */
+
+    return inserteditem->hash;
+} 
+
+
+/*
+ * cache_insert() 
+ * Add specified object to cache with existence test optional.
+ * Return inserted item hash, or zero.
+ */
+int etch_cache_insert (const unsigned int key, void* data, const int is_check)
+{
+    int keylen = 0;
+    int res = 0;
+    etch_mutex_lock(g_etch_cache_mutex);
+    keylen = etch_make_cache_key(key);
+    res = etch_cache_insertxl(ckey, keylen, data, is_check);
+    etch_mutex_unlock(g_etch_cache_mutex);
+    return res;
+} 
+
+
+/*
+ * cache_insertx() 
+ * Add specified object to cache with existence test optional.
+ * Return inserted item hash, or zero.
+ */
+int etch_cache_insertx (char* key, void* data, const int is_check)
+{
+    unsigned keylen = (unsigned)strlen(key);
+    
+    return etch_cache_insertxl(key, keylen, data, is_check);
+} 
+
+
+/*
+ * cache_add() 
+ * Add specified object to cache given integer key.
+ * Return 0 or -1.
+ */
+int etch_cache_add(const unsigned int objtype, void* data)
+{
+    return etch_cache_insert (objtype, data, TRUE);
+} 
+
+
+/*
+ * cache_addx() 
+ * Add specified object to cache.
+ * Return 0 or -1.
+ */
+int etch_cache_addx(char* key, void* data)
+{
+    return etch_cache_insertx(key, data, TRUE);
+}
+
+
+#else // #ifdef ETCH_CACHE_USES_ALPHA_KEY
+
+
+/*
+ * cache_find() 
+ * locate cached object with specified key, returning it or NULL
+ */
+void* etch_cache_find(const unsigned int objtype)
+{
+    etch_hashitem hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+    int result = jenkins_find
+       (g_etch_cache->realtable, (char*)&objtype, sizeof(int), 0, &founditem);
+    return result == -1? NULL: founditem->value;
+}
+
+
+/*
+ * cache_del() 
+ * Remove specified object from cache.
+ * Return pointer to cached object, which is not freed here.
+ */
+void* etch_cache_del (const unsigned int objtype)
+{
+    etch_hashitem hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+    int result = jenkins_remove
+       (g_etch_cache->realtable, (char*)&objtype, sizeof(int), 0, &founditem);
+    if (result == -1) return NULL;
+    free(founditem->key); /* free 4-byte key allocated in cache_add() */
+    return founditem->value;
+}
+
+
+*
+ * cache_add() 
+ * Add specified object to cache.
+ * Return pointer to item's data entry, which is not freed here.
+ */
+int etch_cache_add (const unsigned int objtype, void* data)
+{
+    int result = 0;
+    char* pkey = 0;
+    void* pval = cache_find(objtype);
+    if (pval) return 0; /* entry exists */
+
+    pkey = etch_malloc(sizeof(int), 0); /* add new entry */
+    memcpy(pkey, &objtype, sizeof(int));
+
+    result = jenkins_insert
+       (g_etch_cache->realtable, pkey, sizeof(int), data, 0, 0, 0);
+    return result;
+} 
+
+
+#endif // #ifdef ETCH_CACHE_USES_ALPHA_KEY 
+
+
+int etch_cache_freehook(void* key, void* value)
+{
+    etch_free(key);
+    etch_object_destroy((vtabmask*)value);
+
+    return 1;
+}
+
+/*
+ * cache_create() 
+ * create the global cache as an untracked hashtable
+ */
+etch_status_t etch_cache_create()
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    
+    assert(g_etch_cache == NULL);
+    
+    etch_status = etch_mutex_create(&g_etch_cache_mutex, ETCH_MUTEX_NESTED, NULL);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+        return etch_status;
+    }
+    g_etch_cache = new_systemhashtable(ETCH_CACHE_INITIAL_SIZE);
+    g_etch_cache->freehook = etch_cache_freehook;
+
+    return etch_status;
+}
+
+
+etch_status_t etch_cache_set_freehook(etch_cache_freehook_func freehook)
+{
+    etch_status_t rv = ETCH_SUCCESS;
+    g_etch_cache->freehook = freehook;
+    return rv;
+}
+
+
+/*
+ * cache_clear() 
+ * remove all objects from the runtime list, freeing both key memory and
+ * data object memory for each. Returns the count of buckets so cleared.
+ */
+int etch_cache_clear()
+{
+    int result = jenkins_clear(g_etch_cache->realtable, TRUE, TRUE, g_etch_cache, 0);
+    return result;
+}
+
+/*
+ * cache_destroy() 
+ * clear the cache and destroy the cache object
+ */
+int etch_cache_destroy()
+{
+    int result = etch_cache_clear();
+    result = jenkins_destroy(g_etch_cache->realtable, 0, 0);
+    etch_free(g_etch_cache);
+    g_etch_cache = NULL;
+    etch_object_destroy(g_etch_cache_mutex);
+    g_etch_cache_mutex = NULL;
+    return result;
+}
+
+/*
+ * cache_count() 
+ * return number of items in the runtime cache
+ */
+int etch_cache_count()
+{
+    return jenkins_count(g_etch_cache->realtable, 0, 0);
+} 
+
diff --git a/binding-c/runtime/c/src/main/common/etch_collection.c b/binding-c/runtime/c/src/main/common/etch_collection.c
new file mode 100644
index 0000000..63b8445
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_collection.c
@@ -0,0 +1,188 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_collection.c -- collection support
+ */
+
+#include "etch_collection.h" 
+#include "etch_object.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+
+int default_iterable_first   (etch_iterator*);
+int default_iterable_next    (etch_iterator*);
+int default_iterable_has_next(etch_iterator*);
+
+
+/**
+ * new_iterable()
+ * constructor for an i_iterable interface
+ */
+i_iterable* new_iterable(i_iterable* thisp, i_iterable* parent, iterable_first func_first, 
+    iterable_next func_next, iterable_has_next func_hasnext)
+{
+    i_iterable* vtab = NULL;
+
+    if  (thisp) /* initializing existing object? */
+         vtab = thisp;
+    else vtab = new_vtable(parent, sizeof(i_iterable), CLASSID_ITERABLE_VTAB);
+
+    if (NULL == vtab) return NULL;
+
+    vtab->first    = func_first?   func_first:   default_iterable_first;
+    vtab->next     = func_next?    func_next:    default_iterable_next;
+    vtab->has_next = func_hasnext? func_hasnext: default_iterable_has_next;
+
+    return vtab;
+}
+
+
+/**
+ * destroy_iterator()
+ * iterator destructor
+ */
+int destroy_iterator(void* data)
+{   
+    etch_iterator* iterator = data;
+
+    /* iterator owns itself, and possibly the collection. 
+     * its vtable is owned by the collection. */
+    if (!is_etchobj_static_shell(iterator))
+    {
+        if (iterator->is_own_collection)
+           ((etch_object*)iterator->collection)->destroy(iterator->collection);
+            
+        etch_free(iterator); 
+    }
+
+    return 0;
+}
+
+
+/**
+ * clone_iterator()
+ * iterator copy constructor
+ */
+void* clone_iterator(void* data)
+{   
+  etch_iterator* iterator = data;
+    etch_iterator* newobj = etch_malloc(sizeof(struct etch_iterator), ETCHTYPEB_ITERATOR); 
+    memcpy(newobj, iterator, sizeof(struct etch_iterator));
+    return newobj;
+}
+
+
+/**
+ * new_iterator()
+ * constructor for an etch_iterator object.
+ */
+etch_iterator* new_iterator(void* collection, i_iterable* iterable)
+{
+    etch_iterator* iterator = etch_malloc(sizeof(etch_iterator), ETCHTYPEB_ITERATOR);
+
+    set_iterator(iterator, collection, iterable);
+
+    return iterator;
+}
+
+
+/**
+ * set_iterator()
+ * constructor for an existing etch_iterator object.
+ */
+int set_iterator(etch_iterator* iterator, void* collection, i_iterable* iterable)
+{
+    memset(iterator, 0, sizeof(etch_iterator));
+
+    ((etch_object*)iterator)->obj_type = ETCHTYPEB_ITERATOR;
+    ((etch_object*)iterator)->class_id = CLASSID_ITERATOR; 
+
+    ((etch_object*)iterator)->vtab = (vtabmask*)iterable;
+    iterator->collection = collection;
+
+    ((etch_object*)iterator)->destroy  = destroy_iterator;
+    ((etch_object*)iterator)->clone    = clone_iterator;
+
+    iterator->first    = iterable->first;
+    iterator->next     = iterable->next;
+    iterator->has_next = iterable->has_next;
+
+    iterator->first(iterator); /* establish initial position */
+    return 0;
+}
+
+
+/**
+ * new_empty_iterator()
+ * constructor for an empty etch_iterator object, i.e. has_next() is false
+ */
+etch_iterator* new_empty_iterator()
+{
+    etch_iterator* iterator = etch_malloc(sizeof(etch_iterator), ETCHTYPEB_ITERATOR);
+
+    ((etch_object*)iterator)->obj_type = ETCHTYPEB_ITERATOR;
+    ((etch_object*)iterator)->class_id = CLASSID_ITERATOR; 
+    ((etch_object*)iterator)->destroy  = destroy_iterator;
+
+    iterator->first    = default_iterable_first;
+    iterator->next     = default_iterable_next;
+    iterator->has_next = default_iterable_has_next;
+
+    return iterator;
+}
+
+
+/**
+ * default_iterable_first()
+ * i_iterable first() default virtual method 
+ */
+int default_iterable_first(etch_iterator* i) 
+{
+    return -1;
+}
+
+
+/**
+ * default_iterable_next()
+ * i_iterable next() default virtual method 
+ */
+int default_iterable_next(etch_iterator* i) 
+{
+    return -1;
+}
+
+
+/**
+ * default_iterable_has_next()
+ * i_iterable has_next() default virtual method 
+ */
+int default_iterable_has_next (etch_iterator* i)
+{
+    return FALSE;
+}
+
+
+/**
+ * etch_comparator_noteq(), etch_comparator_equal
+ * comparators to use when a result not dependent on parameters is desired,
+ * such as when using an add_from method to add to a collection when the
+ * target collection is empty and thus no contains() comparison is needed. 
+ */
+int etch_comparator_noteq(void* a, void* b) { return -1;}
+int etch_comparator_equal(void* a, void* b) { return 0; }
diff --git a/binding-c/runtime/c/src/main/common/etch_config.c b/binding-c/runtime/c/src/main/common/etch_config.c
new file mode 100644
index 0000000..995f1a0
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_config.c
@@ -0,0 +1,322 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_config.c
+ * config items and config file parse.
+ * config file is formatted as a java-style properties file expected as ansi or utf-8.
+ */
+
+#include "etch.h"
+#include "etch_config.h"
+#include "etch_general.h"
+
+#define ETCH_CONFIG_LINE_MAX 1024
+
+/*
+static const char* ETCH_CONFIG_CATEGORY = "etch_config";
+*/
+struct etch_config_t
+{
+    struct etch_config_entry*   data;
+    uint16                      length;
+    uint16                      size;
+};
+
+struct etch_config_entry
+{
+    char* name;
+    char* value;
+};
+
+etch_status_t etch_config_create(etch_config_t** config)
+{
+    etch_config_t* newconfig = NULL;
+
+    if(config == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    newconfig = etch_malloc(sizeof(etch_config_t), 0);
+    if(newconfig == NULL) {
+        return ETCH_ENOMEM;
+    }
+    memset(newconfig, 0, sizeof(etch_config_t));
+    *config = newconfig;
+
+    // default properties
+    etch_config_set_property(*config, "etch.validate.write", "1");
+    etch_config_set_property(*config, "etch.validate.read", "1");
+    etch_config_set_property(*config, "etch.mailbox.timeout.read", "3000");
+    etch_config_set_property(*config, "etch.mailbox.timeout.write", "3000");
+    // destroy message with mailbox
+    etch_config_set_property(*config, "etch.mailbox.destroy.message", "1");
+    // TODO: add default values
+    etch_config_set_property(*config, "etch.log", "error");
+    
+    etch_config_set_property(*config, "etch.log.consoleappender", "consoleappender");
+    
+    etch_config_set_property(*config, "etch.log.fileappender", "fileappender");
+    etch_config_set_property(*config, "etch.log.fileappender.file", "C:/dfdr.log");
+
+    etch_config_set_property(*config, "etch.maxconnections", "40");
+
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_config_open(struct etch_config_t* config, const char* filepath)
+{
+    FILE *file = NULL;
+    int   c         = 0;
+    char  linebuf[ETCH_CONFIG_LINE_MAX];
+    int16 linepos   = 0;
+    char  lineend   = 0;
+
+    if(config == NULL) {
+        return ETCH_EINVAL;
+    }
+    
+    file = fopen(filepath, "r");
+    if(file == NULL) {
+        return ETCH_EFILENOTFOUND;
+    }
+
+    while(c != EOF) {
+        char ch = 0;
+        c = fgetc(file);
+        ch = c;
+        // determine end of config line
+        if(c == EOF || c == '\n') {
+            ch = '\0';
+            if(linepos > 0 && linebuf[linepos - 1] == '\r') {
+                linepos--;
+            }
+            lineend = 1;
+        }
+        if(linepos >= ETCH_CONFIG_LINE_MAX - 1) {
+            // error
+            lineend = 0;
+            linepos = 0;
+            continue;
+        }
+
+        linebuf[linepos++] = ch;
+        if(lineend) {
+            char *name   = NULL;
+            char *value = NULL;
+            char *line = strtrim(linebuf);
+            
+            // check for comments or empty lines
+            if(line[0] != '#' && line[0] != '\0') {
+                // parse line
+                name = strtok(line, "=");
+                name = strtrim(name);
+                if(name != NULL) {
+                    value = strtok(NULL, "=");
+                    value = strtrim(value);
+                }
+                etch_config_set_property(config, name, value);
+            }
+            lineend = 0;
+            linepos = 0;
+        }
+    }
+
+    fclose(file);
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_config_set_property(etch_config_t* config, const char* name, const char* value)
+{
+    int16 i = 0;
+    int16 index = -1;
+
+    if(config == NULL) {
+        return ETCH_EINVAL;
+    }
+    if(name == NULL || value == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    // check if resize is neccesary
+    if(config->length == config->size) {
+        uint16 newsize = config->size + 10;
+        struct etch_config_entry* temp = etch_malloc(sizeof(struct etch_config_entry) * newsize, 0);
+        memset(temp, 0, sizeof(struct etch_config_entry) * newsize);
+        if(config->size > 0) {
+            memcpy(temp, config->data, sizeof(struct etch_config_entry) * config->size);
+            etch_free(config->data);
+        }
+        config->data = temp;
+        config->size = newsize;
+    }
+
+    // check if key exists
+    for(i = 0; i < config->length; i++) {
+        if(strcmp(config->data[i].name, name) == 0) {
+            index = i;
+            break;
+        }
+    }
+
+    // if index == -1 append new entry
+    if(index == -1) {
+        // write key
+        config->data[config->length].name = etch_malloc(strlen(name) + 1, 0);
+        memset(config->data[config->length].name, 0, (size_t)(strlen(name) + 1));
+        strcpy(config->data[config->length].name, name);
+        index = config->length++;
+    } else {
+        etch_free(config->data[index].value);
+        config->data[index].value = NULL;
+    }
+
+    // write value
+    config->data[index].value = etch_malloc(strlen(value) + 1, 0);
+    memset(config->data[index].value, 0, (size_t)(strlen(value) + 1));
+    strcpy(config->data[index].value, value);
+
+    return ETCH_SUCCESS;
+}
+
+int etch_config_has_property(struct etch_config_t* config, const char* name)
+{
+    int16 i = 0;
+
+    if(config == NULL || name == NULL) {
+        return 0;
+    }
+
+    // check if key exists
+    for(i = 0; i < config->length; i++) {
+        if(strcmp(config->data[i].name, name) == 0) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+etch_status_t etch_config_get_property_string(struct etch_config_t* config, const char* name, char** value)
+{
+    int16 i = 0;
+    int16 index = -1;
+    
+    if(config == NULL || name == NULL|| value == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    // check if key exists
+    for(i = 0; i < config->length; i++) {
+        if(strcmp(config->data[i].name, name) == 0) {
+            index = i;
+            break;
+        }
+    }
+
+    if(index != -1) {
+        *value = config->data[i].value;
+    } else {
+        *value = NULL;
+    }
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_config_get_property_int(struct etch_config_t* config, const char* name, int32* value)
+{
+    int16 i = 0;
+    int16 index = -1;
+    
+    if(config == NULL || name == NULL|| value == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    // check if key exists
+    for(i = 0; i < config->length; i++) {
+        if(strcmp(config->data[i].name, name) == 0) {
+            index = i;
+            break;
+        }
+    }
+
+    if(index != -1) {
+        *value = atoi(config->data[i].value);
+    } else {
+        *value = 0;
+    }
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_config_get_property_by_index(struct etch_config_t* config, uint16 index, char** value)
+{
+    if(config == NULL || value == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    if(index < config->length) {
+        *value = config->data[index].value;
+    } else {
+        *value = NULL;
+    }
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_config_clear(etch_config_t* config)
+{
+    int16 i = 0;
+
+    if(config == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    // check if key exists
+    for(i = 0; i < config->length; i++) {
+        etch_free(config->data[i].name);
+        etch_free(config->data[i].value);
+    }
+    config->length = 0;
+
+
+    return ETCH_SUCCESS;
+}
+
+uint16 etch_config_get_length(struct etch_config_t* config)
+{
+    if(config == NULL) {
+        return 0;
+    }
+    return config->length;
+}
+
+uint16 etch_config_get_size(struct etch_config_t* config)
+{
+    if(config == NULL) {
+        return 0;
+    }
+    return config->size;
+}
+
+etch_status_t etch_config_destroy(etch_config_t* config)
+{
+    if(config == NULL) {
+        return ETCH_EINVAL;
+    }
+    etch_config_clear(config);
+    etch_free(config->data);
+    etch_free(config);
+    return ETCH_SUCCESS;
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_encoding.c b/binding-c/runtime/c/src/main/common/etch_encoding.c
new file mode 100644
index 0000000..dcf8fbb
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_encoding.c
@@ -0,0 +1,231 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_encoding.c -- character encoding
+ */
+
+#include <apr_iconv.h>
+#include "etch_encoding.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+#include <wchar.h>
+
+static const char* LOG_CATEGORY = "etch_encoding";
+
+extern apr_pool_t*         g_etch_main_pool;
+extern apr_thread_mutex_t* g_etch_main_pool_mutex;
+
+static const unsigned char CODEPAGE_TABLE_SIZE = 6;
+
+
+static apr_iconv_t* codepage_table = NULL;
+
+etch_status_t etch_encoding_initialize()
+{
+    size_t s       = CODEPAGE_TABLE_SIZE * CODEPAGE_TABLE_SIZE * sizeof(apr_iconv_t);
+    codepage_table = etch_malloc(s,0);
+    memset(codepage_table, 0, s);
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_encoding_shutdown()
+{
+    int i = 0;
+    
+	apr_thread_mutex_lock(g_etch_main_pool_mutex);
+    for(i = 0; i < CODEPAGE_TABLE_SIZE * CODEPAGE_TABLE_SIZE; i++) {
+        if(codepage_table[i] != NULL) {
+	        apr_iconv_close(codepage_table[i], g_etch_main_pool);    
+        }
+    }
+    apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+    etch_free(codepage_table);
+    codepage_table = NULL;
+    return ETCH_SUCCESS;
+}
+
+
+static char* etch_encoding_get_encoding(unsigned char encoding)
+{
+    switch (encoding) {
+    case ETCH_ENCODING_ASCII:
+      return "iso-8859-1";
+    case ETCH_ENCODING_UTF8:
+      return "utf-8";
+    case ETCH_ENCODING_UCS2:
+      return "ucs2-internal";
+    case ETCH_ENCODING_UCS4:
+      return "ucs4-internal";
+    case ETCH_ENCODING_UTF16:
+      return "utf-16";
+    default:
+      ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "unsupported src-encoding %d\n", encoding);
+      ETCH_ASSERT(!"encoding not supported");
+      return 0;
+    }
+}
+
+
+etch_status_t etch_encoding_get_codepage(unsigned char src, unsigned char dst, apr_iconv_t* codepage)
+{
+    apr_iconv_t* temp   = NULL;
+	apr_status_t status = APR_SUCCESS;
+	char*        apr_codepage_src = NULL;
+	char*        apr_codepage_dst = NULL;
+
+	apr_codepage_src = etch_encoding_get_encoding(src);
+	apr_codepage_dst = etch_encoding_get_encoding(dst);
+	if (apr_codepage_src == NULL || apr_codepage_dst == NULL) {
+		return ETCH_EINVAL;
+    }
+
+	apr_thread_mutex_lock(g_etch_main_pool_mutex);
+	temp = &codepage_table[(CODEPAGE_TABLE_SIZE * src) + dst];
+	if (*temp == NULL) {
+        status = apr_iconv_open(apr_codepage_dst, apr_codepage_src, g_etch_main_pool, temp);
+    }
+	*codepage = *temp;
+	apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+	
+	if(status != APR_SUCCESS){
+		return ETCH_ERROR;
+    }
+    return ETCH_SUCCESS;
+}
+
+
+int etch_encoding_transcode(char** out, unsigned char outEncoding, const char* in, unsigned char inEncoding, unsigned int inByteCount, int* resultingByteCount, etch_pool_t* pool)
+{
+    // in
+    const char* apr_in_buf = in;
+    apr_size_t apr_in_bytecount = inByteCount;
+    
+    // out
+    char* apr_out_buf = NULL;
+    apr_size_t apr_out_bytecount = 0;
+    apr_size_t apr_out_bytecount_original;
+
+    // translated
+    apr_size_t apr_translated = 0;
+
+    // converter
+    apr_iconv_t apr_cd   = NULL;
+
+    apr_status_t apr_status = 0;
+    etch_status_t etch_status;
+
+    // chech input params
+    if (NULL == out) {
+        return -1;
+    }
+
+    if(pool == NULL) {
+        pool = g_etch_main_pool;
+    }
+
+    apr_out_bytecount = apr_in_bytecount*4; // worst case ascii->ucs4
+    apr_out_bytecount_original = apr_out_bytecount;
+    apr_out_buf = etch_malloc(apr_out_bytecount, ETCHTYPEB_BYTES);
+    (*out) = apr_out_buf;
+    memset(apr_out_buf, 0, apr_out_bytecount);
+
+    if(inEncoding == outEncoding){
+        memcpy(apr_out_buf,in,inByteCount);
+        return 0;
+    }
+
+    // open iconv
+    etch_status = etch_encoding_get_codepage(inEncoding, outEncoding, &apr_cd);
+
+    if(etch_status != ETCH_SUCCESS)
+    {
+        char buffer[512];
+        apr_strerror(apr_status, buffer, 512);
+        printf("%s", buffer);
+
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "encoding conversion error %d\n", apr_status);
+        return -1;
+    }
+
+    // convert
+    apr_status = apr_iconv(apr_cd, &apr_in_buf, &apr_in_bytecount, &apr_out_buf, &apr_out_bytecount, &apr_translated);
+    if(apr_status != APR_SUCCESS)
+    {
+        char buffer[512];
+        apr_strerror(apr_status, buffer, 512);
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "encoding conversion error-code: %d error-msg: %s\n", apr_status, buffer);
+
+        //clean up
+        etch_free((*out));
+        (*out) = NULL;
+        return -1;
+    }
+    *resultingByteCount = (int)(apr_out_bytecount_original - apr_out_bytecount);
+
+    return 0;
+}
+
+unsigned char etch_encoding_for_wchar()
+{
+  switch (sizeof(wchar_t)) {
+  case 2:
+    return ETCH_ENCODING_UCS2;
+  case 4:
+    return ETCH_ENCODING_UCS4;
+  default:
+    ETCH_ASSERT(!"unknown wchar_t size");
+    return 0;
+  }
+}
+
+int etch_encoding_transcode_wchar(char** out, unsigned char outEncoding, const wchar_t* in, etch_pool_t* pool)
+{
+  int outByteCount;
+  unsigned int charcount;
+  unsigned char srcEncoding;
+  charcount = (unsigned int)wcslen(in);
+  srcEncoding = etch_encoding_for_wchar();
+  return etch_encoding_transcode(out, outEncoding, (const char*)in, srcEncoding, charcount * sizeof(wchar_t), &outByteCount, pool);
+}
+
+int etch_encoding_transcode_to_wchar(wchar_t** out, const void* in, unsigned char inEncoding, unsigned int inByteCount, etch_pool_t* pool)
+{
+  int outByteCount;
+  unsigned char dstEncoding;
+  dstEncoding = etch_encoding_for_wchar();
+  return etch_encoding_transcode((char**)out, dstEncoding, in, inEncoding, inByteCount, &outByteCount, pool);
+}
+
+unsigned int etch_encoding_get_sizeof_terminator(unsigned char encoding)
+{
+  switch (encoding) {
+  case ETCH_ENCODING_ASCII:
+  case ETCH_ENCODING_UTF8:
+    return 1;
+  case ETCH_ENCODING_UCS2:
+    return 2;
+  case ETCH_ENCODING_UCS4:
+    return 4;
+  case ETCH_ENCODING_UTF16:
+  case ETCH_ENCODING_UTF32:
+  default:
+    ETCH_ASSERT(!"encoding not supported");
+    return 0;
+  }
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_exception.c b/binding-c/runtime/c/src/main/common/etch_exception.c
new file mode 100644
index 0000000..5cad320
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_exception.c
@@ -0,0 +1,167 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_excp.c -- exception objects native and boxed  
+ */
+
+#include "etch_encoding.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+static const char* LOG_CATEGORY = "etch_exception";
+/* builtin exception text */
+const wchar_t* excptext_excp_builtin    = L"etch builtin exception"; 
+const wchar_t* excptext_excp_user       = L"etch user defined exception"; 
+
+/**
+ * etch_exception
+ */
+struct etch_exception
+{
+    etch_object object;
+
+    etch_string*    message;
+    uint32          errorcode;
+    excptype_t      excptype;
+
+};
+
+/*
+ * default_excptext() 
+ * find and return default text for exception type
+ */
+etch_string* default_excptext(const excptype_t type)
+{
+    wchar_t* text = NULL;
+    etch_string* res = NULL;
+    switch(type)
+    {   
+       case EXCPTYPE_BUILTIN:       text = (wchar_t*) excptext_excp_builtin;    break;
+       case EXCPTYPE_USERDEFINED:   text = (wchar_t*) excptext_excp_user;       break;
+       default:
+           text = (wchar_t*) L"unknown error";
+           ETCH_LOG(LOG_CATEGORY, ETCH_LOG_WARN, "no default exception text for type %d", type);
+           break;
+    }
+    res = new_stringw(text);
+    return res;
+}
+
+
+/**
+ * destroy_etch_exception()
+ */
+int destroy_etch_exception(void* p)
+{   
+    etch_exception* ee = (etch_exception*) p;
+
+    if ((! is_etchobj_static_content(ee)) && ee->message) {
+        etch_object_destroy(ee->message);
+    }
+
+    return destroy_objectex((etch_object*) ee);
+}
+
+
+/**
+ * clone_etch_exception()
+ */
+void* clone_etch_exception(void* data)
+{   
+    etch_exception* ee = (etch_exception*)data;
+    etch_exception* newobj = NULL;
+    newobj = new_etch_exception (ee->excptype);
+    if(ee->message) {
+        newobj->message = (etch_string*)etch_object_clone_func(ee->message);
+    }else {
+        newobj->message = NULL;
+    }
+    newobj->errorcode = ee->errorcode;
+    return newobj;
+}
+
+/**
+ * new_etch_exception()
+ * constructor for wrapped exception
+ */ 
+etch_exception* new_etch_exception(const excptype_t type) 
+{
+    etch_exception* newobj = (etch_exception*) new_object
+        (sizeof(struct etch_exception), ETCHTYPEB_EXCEPTION, CLASSID_EXCEPTION);
+
+    ((etch_object*)newobj)->destroy = destroy_etch_exception;
+    ((etch_object*)newobj)->clone   = clone_etch_exception;
+    newobj->errorcode = 0;
+    newobj->excptype = type;
+    newobj->message = default_excptext(type);
+
+    return newobj;
+}
+
+/**
+ * create a new builtin etch exception with errorcode
+ */
+etch_exception* new_etch_exception_from_errorcode(int errorcode){
+    etch_exception* result = new_etch_exception(EXCPTYPE_BUILTIN);
+    result->errorcode = errorcode;
+    return result;
+}
+
+void etch_exception_set_message(etch_exception* ex, etch_string* mess)
+{
+    if(ex->message){ 
+        etch_object_destroy(ex->message);
+    }
+    ex->message = mess;
+}
+
+uint32 etch_exception_get_errorcode(etch_exception* ex) {
+    if(ex){
+        return ex->errorcode;
+    }
+    return 0;
+}
+
+etch_string* etch_exception_get_message(etch_exception* ex)
+{
+    return ex->message;
+}
+
+etch_status_t etch_exception_get_type(etch_exception* exception, excptype_t* type)
+{
+    if(exception == NULL || type == NULL) {
+        return ETCH_EINVAL;
+    }
+    *type = exception->excptype;
+    return ETCH_SUCCESS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/binding-c/runtime/c/src/main/common/etch_flexbuffer.c b/binding-c/runtime/c/src/main/common/etch_flexbuffer.c
new file mode 100644
index 0000000..aa16f29
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_flexbuffer.c
@@ -0,0 +1,722 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etchflexbuf.c
+ * flex buffer
+ */
+
+#include "etch_flexbuffer.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+#define ETCH_INIT_FLEXBUFSIZE 2048
+#define ETCH_MAX_FLEXBUFSIZE (4*1024*1024)
+
+static void    etch_flexbuf_fix_length  (etch_flexbuffer*);
+static int etch_flexbuf_ensure_size (etch_flexbuffer*, size_t);
+
+/* 
+ * java binding syntax is confusing and ambiguous so we change it a bit. java 
+ * calls the data region in the buffer "length". since "length" is non-specific,
+ * and there are other "length"s, such as "buffer.length", and "object.length", 
+ * we'll call it "datalen", to mean "meaningful bytes within the buffer". java
+ * also uses "buffer.length", which is the size of the allocated buffer. c of
+ * course does not associate properties with arrays, so we carry an additional
+ * property "bufsize" to indicate the allocated length of the byte array.  
+ */
+
+
+/**
+ * new_flexbuffer()
+ * etch_flexbuffer constructor
+ */
+etch_flexbuffer *new_flexbuffer (size_t bufsize)
+{
+    void *buf;
+    if (bufsize <= 0 || bufsize > ETCH_MAX_FLEXBUFSIZE) bufsize = ETCH_INIT_FLEXBUFSIZE;
+
+    buf = etch_malloc(bufsize, ETCHTYPEB_BYTES);
+    memset(buf, 0, bufsize);
+   
+    return etch_flexbuf_create_bi (buf, bufsize, 0, 0);
+}
+
+
+/**
+ * new_flexwriter_from()
+ * etch_flexbuffer constructor with index set to write
+ */
+etch_flexbuffer *new_flexwriter_from (void *buf, size_t datalen, size_t bufsize) 
+{
+    return new_flexbuffer_from (buf, datalen, bufsize, datalen);       
+}
+
+
+/**
+ * new_flexbuffer_from()
+ * etch_flexbuffer constructor.
+ * @param buf data which is to become the internal buffer. caller relinquishes this memory.
+ * @param datalen length of real data in bytes.
+ * @param bufsize size of buffer in bytes.  
+ * @param buffer index at which to start.
+ */
+etch_flexbuffer *new_flexbuffer_from (void* buf, size_t datalen, size_t bufsize, size_t index)
+{
+    if (bufsize <= 0 || bufsize > ETCH_MAX_FLEXBUFSIZE) bufsize = ETCH_INIT_FLEXBUFSIZE;
+    if (datalen > bufsize || (!buf && datalen)) return NULL;
+    if (NULL == buf) 
+    {   buf = etch_malloc(bufsize, ETCHTYPEB_BYTES);
+        memset(buf, 0, bufsize);
+    }
+   
+    return etch_flexbuf_create_bi (buf, bufsize, datalen, index);
+}
+
+
+/**
+ * etch_flexbuf_create_b()
+ * create a flex buffer out of an existing buffer, ready to read to, 
+ * using specified size and an index of zero.
+ *
+ * @param buf the existing buffer.
+ * @param bufsize the buffer size.
+ * @param datalen the data length in the buffer
+ *
+ * @return the created and initialized the flex buffer.
+ *
+ */
+etch_flexbuffer *etch_flexbuf_create_b (void *buf, size_t bufsize, size_t datalen)
+{
+    return etch_flexbuf_create_bi(buf, bufsize, datalen, 0);
+}
+
+
+/**
+ * etch_flexbuf_create_bi()
+ * create a flex buffer out of an existing buffer, ready to read with specified 
+ * index and size.
+ * @param buf the existing buffer.
+ * @param bufsize the buffer size.
+ * @param datalen the data length in the buffer
+ * @param index current position of the buffer.
+ */
+etch_flexbuffer *etch_flexbuf_create_bi(void *buf, size_t bufsize, size_t datalen, size_t index)
+{
+    etch_flexbuffer *fbuf = (etch_flexbuffer*) new_object(sizeof(etch_flexbuffer), ETCHTYPEB_FLEXBUF, CLASSID_FLEXBUF);
+
+    ((etch_object*)fbuf)->destroy = destroy_etch_flexbuffer;
+
+    fbuf->buf     = buf;
+    fbuf->bufsize = bufsize;
+    fbuf->datalen = datalen;
+    fbuf->index   = index;
+    fbuf->is_littleendian = IS_ETCH_TRANSPORT_LITTLEENDIAN;
+    return fbuf;
+}
+
+
+/**
+ * etch_flexbuf_get_buffer()
+ * @return the current byte array. might change if any operation
+ * needs to extend length past the end of the array.
+ */
+byte* etch_flexbuf_get_buffer (etch_flexbuffer *fbuf)
+{
+	return fbuf->buf;
+}
+
+
+/**
+ * etch_flexbuf_clear()
+ * zero fill the internal buffer
+ */
+void etch_flexbuf_clear (etch_flexbuffer *fbuf)
+{
+	memset (fbuf->buf, 0, fbuf->bufsize);
+}
+
+
+/**
+ * etch_flexbuf_ensure_size().
+ * verify sufficient buffer capacity, reallocating if necessary.
+ * @return boolean value indicating if buffer is as requested.
+ */
+static int etch_flexbuf_ensure_size (etch_flexbuffer *fbuf, size_t reqsize)
+{
+    byte *newbuf = NULL;
+    size_t newsize = fbuf->bufsize;
+	if (reqsize  < ETCH_INIT_FLEXBUFSIZE)
+		reqsize  = ETCH_INIT_FLEXBUFSIZE;
+	if (reqsize <= newsize) return TRUE;	
+    if (reqsize  > ETCH_MAX_FLEXBUFSIZE) return FALSE;
+	
+	while(reqsize > newsize) newsize += ETCH_INIT_FLEXBUFSIZE;
+	newbuf = etch_realloc (fbuf->buf, newsize, 0);
+	
+    fbuf->buf = newbuf;
+    fbuf->bufsize = newsize; 
+    return TRUE;
+}
+
+
+/**
+ * destroy_etch_flexbuffer()
+ * etch_flexbuffer destructor
+ */
+int destroy_etch_flexbuffer(void* obj)
+{
+    etch_flexbuffer* fbuf = (etch_flexbuffer*)obj;
+    if (fbuf == NULL) return 0; 
+    
+    if (!is_etchobj_static_content(fbuf))
+        etch_free(fbuf->buf);  /* OK if null */
+
+    destroy_objectex((etch_object*) fbuf);
+    return 0;
+}
+
+
+/**
+ * sets a new data length. If the index is larger than new length, 
+ * the index is set to the new length as well. 
+ * the method name was retained from java, however it is more properly 
+ * set_data_length, since as noted previously, "length" is ambiguous,
+ * referring to data length, not to allocated bytes. 
+ */
+int etch_flexbuf_set_length (etch_flexbuffer *fbuf, size_t new_datalen)
+{
+    int result = 0;
+
+    if (new_datalen >= 0 && etch_flexbuf_ensure_size(fbuf, new_datalen))
+    {   
+        fbuf->datalen = new_datalen;  
+
+        if (fbuf->index > new_datalen)
+            fbuf->index = new_datalen;
+    }
+    else result = -1;
+
+   return result;
+}
+
+
+/**
+ * sets a new buffer index. the index must be greater than 0 and less
+ * than the buffer size
+ * @param fbuf the buffer pointer to be set.
+ * @param index the new index for the buffer.
+ */
+int etch_flexbuf_set_index (etch_flexbuffer *fbuf, size_t index)
+{
+    if (index < 0 || index > fbuf->datalen) return -1;
+    fbuf->index = index;
+    return 0;
+}
+
+
+/**
+ * get the number of bytes available in the buffer.
+ * @return the available space in the buffer.
+ */
+size_t etch_flexbuf_avail (etch_flexbuffer *fbuf)
+{
+    return (fbuf->datalen - fbuf->index);
+}
+
+
+/**
+ * etch_flexbuffer_reset_to()
+ * set index to zero and length to specified length.
+ */
+int etch_flexbuffer_reset_to (etch_flexbuffer *fbuf, size_t new_datalen)
+{
+    const int result = etch_flexbuf_set_length (fbuf, new_datalen);
+    fbuf->index = 0;
+    return result;
+}
+
+
+/**
+ * etch_flexbuf_reset()
+ * set index and length to zero, same as etch_flexbuf_set_index(buf, 0)
+ */
+etch_flexbuffer *etch_flexbuf_reset (etch_flexbuffer *fbuf)
+{
+    fbuf->index = fbuf->datalen = 0;
+	return fbuf;
+}
+
+
+/**
+ * Compacts the buffer by moving remaining data (from index to length)
+ * to the front of the buffer. Sets index to 0, and sets length to
+ * avail (before index was changed).
+ * @return this flex buffer object.
+ */
+etch_flexbuffer *etch_flexbuf_compact(etch_flexbuffer *fbuf)
+{
+    size_t curlen;
+	if (fbuf->index == 0) return fbuf;
+	
+	if (0 == (curlen = etch_flexbuf_avail(fbuf)))
+	{
+		etch_flexbuf_set_length(fbuf, 0);
+		return fbuf;
+	}
+	
+    memmove(fbuf->buf, fbuf->buf+fbuf->index, curlen);
+	fbuf->index = 0;
+	fbuf->datalen = curlen;
+	
+	return fbuf;
+}
+
+
+/**
+ * Copies data from the internal buffer to buf.
+ *
+ * @param fbuf the flex buffer to get data from.
+ * @param buf a buffer to receive the data. At most
+ * min( len, avail() ) bytes are transferred, starting
+ * at off.
+ * @param off the index in buf to receive the data.
+ * Off must be >= 0 && <= buf.datalen.
+ * @param len the max amount of data to transfer. Len
+ * must be >= 0 and <= buf.datalen - off.
+ * @return the amount of data transferred.
+ */
+size_t etch_flexbuf_get(etch_flexbuffer *fbuf, byte *buf, size_t off, size_t len)
+{
+    size_t bytecount = 0, avail = etch_flexbuf_avail(fbuf);
+	if (len <= 0 || NULL == buf) return 0;
+
+	bytecount = len < avail ? len : avail ;	
+                     /* changed 6/16 to add index */
+    memcpy(buf + off, fbuf->buf + fbuf->index + off, bytecount);
+	fbuf->index += bytecount;
+	
+	return bytecount;
+}
+
+
+/**
+ * etch_flexbuf_get_allfrom()
+ * return buffer contents starting at index, in a byte vector, caller owns returned memory
+ */
+byte* etch_flexbuf_get_allfrom(etch_flexbuffer* fbuf, size_t index, size_t* out_count)
+{
+    byte* newbuf = 0;
+    size_t bytecount = 0;
+    if (index < 0) index = fbuf->index;
+    if (index > fbuf->datalen) index = fbuf->datalen;
+    fbuf->index = index;  /* 6/16 so etch_flexbuf_get can skip index */
+
+    bytecount = fbuf->datalen - index;  
+    newbuf    = etch_malloc(bytecount, ETCHTYPEB_BYTES);
+
+    bytecount = etch_flexbuf_get(fbuf, newbuf, 0, bytecount);
+
+    if (out_count) *out_count = bytecount; 
+    return newbuf;
+}
+
+
+/**
+ * etch_flexbuf_get_all()
+ * return buffer contents in a byte array, caller owns memory
+ */
+byte* etch_flexbuf_get_all(etch_flexbuffer* fbuf, size_t* out_count)
+{
+    return etch_flexbuf_get_allfrom(fbuf, fbuf->index, out_count); 
+}
+
+
+/**
+ * return next byte in buffer
+ */
+int etch_flexbuf_get_byte(etch_flexbuffer *fbuf, byte* out)
+{
+   if (etch_flexbuf_avail(fbuf) < sizeof(byte)) return -1;  
+   *out = fbuf->buf[fbuf->index++];
+   return 0;
+}
+
+/**
+ * etch_flexbuf_get_short()
+ * @return a short composed from the next 2 bytes.
+ */
+int etch_flexbuf_get_short(etch_flexbuffer *fbuf, short* out)
+{   
+    int value, svalue;
+    if (etch_flexbuf_avail(fbuf) < sizeof(short)) return -1;
+
+	if (fbuf->is_littleendian)
+	{
+		value = fbuf->buf[fbuf->index++] & 255;
+		svalue = (short) (value + ((fbuf->buf[fbuf->index++] & 255) << 8));
+	}
+	else
+    {   value  = fbuf->buf[fbuf->index++]; /* big endian */
+	    svalue = (short) ((value << 8) + (fbuf->buf[fbuf->index++] & 255));
+    }
+
+    *out = svalue;
+    return 0;
+}
+
+
+/**
+ * etch_flexbuf_get_int()
+ * @return an int composed from the next 4 bytes.
+ */
+int etch_flexbuf_get_int(etch_flexbuffer *fbuf, int32* out)
+{
+    int32  value        = 0;
+    size_t bytes_avail  = 0;
+
+    bytes_avail = etch_flexbuf_avail(fbuf);
+    if(bytes_avail < sizeof(int32))
+    {
+        return -1;
+    }
+
+    if(fbuf->is_littleendian)
+    {
+        value = value | fbuf->buf[fbuf->index+0] << 0;
+        value = value | fbuf->buf[fbuf->index+1] << 8;
+        value = value | fbuf->buf[fbuf->index+2] << 16;
+        value = value | fbuf->buf[fbuf->index+3] << 24;
+        fbuf->index += sizeof(int32);
+    }
+    else
+    {
+        value = value | fbuf->buf[fbuf->index+3] << 0;
+        value = value | fbuf->buf[fbuf->index+2] << 8;
+        value = value | fbuf->buf[fbuf->index+1] << 16;
+        value = value | fbuf->buf[fbuf->index+0] << 24;
+        fbuf->index += sizeof(int32);
+    }
+    *out = value;
+    return 0;
+}
+
+/**
+ * etch_flexbuf_get_long()
+ * @return a long composed from the next 8 bytes.
+ * note jim are we taking sign into consideration on reversal?
+ */
+int etch_flexbuf_get_long(etch_flexbuffer *fbuf, int64* out)
+{
+    int64 value         = 0;
+    size_t bytes_avail  = 0;
+
+    bytes_avail = etch_flexbuf_avail(fbuf);
+    if(bytes_avail < sizeof(int64))
+    {
+        return -1;
+    }
+
+    if (fbuf->is_littleendian)
+    {
+        // little endian
+        value = value | (uint64)fbuf->buf[fbuf->index+0] << 0;
+        value = value | (uint64)fbuf->buf[fbuf->index+1] << 8;
+        value = value | (uint64)fbuf->buf[fbuf->index+2] << 16;
+        value = value | (uint64)fbuf->buf[fbuf->index+3] << 24;
+        value = value | (int64)fbuf->buf[fbuf->index+4] << 32;
+        value = value | (int64)fbuf->buf[fbuf->index+5] << 40;
+        value = value | (int64)fbuf->buf[fbuf->index+6] << 48;
+        value = value | (int64)fbuf->buf[fbuf->index+7] << 56;
+        fbuf->index += sizeof(int64);
+    }
+    else
+    {
+        // big endian
+        value = value | (uint64)fbuf->buf[fbuf->index+7] << 0;
+        value = value | (uint64)fbuf->buf[fbuf->index+6] << 8;
+        value = value | (uint64)fbuf->buf[fbuf->index+5] << 16;
+        value = value | (uint64)fbuf->buf[fbuf->index+4] << 24;
+        value = value | (uint64)fbuf->buf[fbuf->index+3] << 32;
+        value = value | (uint64)fbuf->buf[fbuf->index+2] << 40;
+        value = value | (uint64)fbuf->buf[fbuf->index+1] << 48;
+        value = value | (uint64)fbuf->buf[fbuf->index+0] << 56;
+        fbuf->index += sizeof(int64);
+    }
+    *out = value;
+    return 0;
+}
+
+
+/**
+ * etch_flexbuf_get_float()
+ * @return a float from the next available bytes.
+ */
+int etch_flexbuf_get_float(etch_flexbuffer *fbuf, float* out)
+{
+    float value;
+    if (-1 == etch_flexbuf_get_int(fbuf, (int*) &value)) return -1;
+    *out = value;
+    return 0;
+}
+
+
+/**
+ * etch_flexbuf_get_double()
+ * @return a double from the next available bytes.
+ */
+int etch_flexbuf_get_double(etch_flexbuffer *fbuf, double* out)
+{
+    double value;
+    if (-1 == etch_flexbuf_get_long(fbuf, (int64*) &value)) return -1;
+    *out = value;
+    return 0;
+}
+
+
+
+/**
+ * fills a buffer fully from the next available bytes.
+ * @param b
+ * @throws IOException if avail() < b.datalen.
+ */
+size_t etch_flexbuf_get_fully( etch_flexbuffer *fbuf, byte *b, size_t bufsize )
+{
+    return etch_flexbuf_get( fbuf, b, 0, bufsize );
+}
+
+
+/**
+ * If index has moved past length during a put, then adjust length
+ * to track index.
+ */
+static void etch_flexbuf_fix_length(etch_flexbuffer *fbuf)
+{
+	if (fbuf->index > fbuf->datalen)
+		fbuf->datalen = fbuf->index;
+}
+
+
+/**
+ * Puts some bytes into the buffer as if by repeated calls to put().
+ * @param buf the source of the bytes to put.
+ * @param off the index to the first byte to put.
+ * @param bytecount the number of bytes to put.
+ * @return count of bytes put
+ */
+size_t etch_flexbuf_put (etch_flexbuffer *fbuf, byte *buf, size_t off, size_t bytecount)
+{
+	if (bytecount <= 0) return 0;	
+	if (!etch_flexbuf_ensure_size (fbuf, fbuf->index + bytecount)) return 0;
+
+    memcpy(fbuf->buf + fbuf->index, buf + off, bytecount);
+	fbuf->index += bytecount;
+	etch_flexbuf_fix_length (fbuf);	
+	return bytecount;
+}
+
+
+/**
+ * Copies the specified number of bytes from buf[index] into buffer
+ * as if by repeated execution of put( buf.get() ).
+ * @param buf the source of the bytes to put.
+ * @param len the number of bytes to put. if -1, copy everything.  
+ * @return number of bytes put
+ */
+size_t etch_flexbuf_put_from(etch_flexbuffer *dstfb, etch_flexbuffer *srcfb, size_t bytecount)
+{
+    size_t bytes_put = 0;
+    if (bytecount == -1) 
+        bytecount = srcfb->datalen - srcfb->index;
+
+	bytes_put = etch_flexbuf_put (dstfb, srcfb->buf, srcfb->index, bytecount);
+
+	etch_flexbuf_skip (srcfb, bytes_put, FALSE);
+
+	return bytes_put;
+}
+
+
+/**
+ * etch_flexbuf_put_byte()
+ * @return number of bytes put
+ */
+size_t etch_flexbuf_put_byte (etch_flexbuffer *fbuf, byte value)
+{
+    size_t bytes_put = 0;
+
+	if (etch_flexbuf_ensure_size(fbuf, fbuf->index + 1))
+    {
+        fbuf->buf[fbuf->index++] = value;
+    	etch_flexbuf_fix_length(fbuf);
+        bytes_put = sizeof(value);
+    }
+
+    return bytes_put;
+}
+
+
+/**
+ * etch_flexbuf_put_short()
+ */
+size_t etch_flexbuf_put_short(etch_flexbuffer *fbuf, short value)
+{
+    if (!etch_flexbuf_ensure_size( fbuf, fbuf->index + sizeof(value) ))
+        return 0;
+
+	if (fbuf->is_littleendian)
+	{
+		fbuf->buf[fbuf->index++] = (byte) value;
+		fbuf->buf[fbuf->index++] = (byte) (value >> 8);
+	}
+	else
+	{
+		fbuf->buf[fbuf->index++] = (byte) (((unsigned short)value) >> 8);
+		fbuf->buf[fbuf->index++] = (byte) value;
+	}
+	
+	etch_flexbuf_fix_length(fbuf);
+
+    return sizeof(value);
+}
+
+
+/**
+ * etch_flexbuf_put_int()
+ */
+size_t etch_flexbuf_put_int( etch_flexbuffer *fbuf, int value )
+{
+    if (!etch_flexbuf_ensure_size( fbuf, fbuf->index + sizeof(int) ))
+        return 0;
+
+    if (fbuf->is_littleendian)
+	{
+		fbuf->buf[fbuf->index++] = (byte) value;
+		fbuf->buf[fbuf->index++] = (byte) (value >> 8);
+		fbuf->buf[fbuf->index++] = (byte) (value >> 16);
+		fbuf->buf[fbuf->index++] = (byte) (value >> 24);
+	}
+	else
+	{
+		fbuf->buf[fbuf->index++] = (byte) ( ((unsigned int) value) >> 24);
+		fbuf->buf[fbuf->index++] = (byte) ( ((unsigned int) value) >> 16);
+		fbuf->buf[fbuf->index++] = (byte) ( ((unsigned int) value) >> 8);
+		fbuf->buf[fbuf->index++] = (byte) value;
+	}
+	
+	etch_flexbuf_fix_length(fbuf);
+
+    return sizeof(value);
+}
+
+
+/**
+ * etch_flexbuf_put_long()
+ */
+size_t etch_flexbuf_put_long(etch_flexbuffer *fbuf, int64 value )
+{
+    if (!etch_flexbuf_ensure_size( fbuf, fbuf->index + sizeof(value) ))
+        return 0;
+
+	if (fbuf->is_littleendian)
+	{
+		fbuf->buf[fbuf->index++] = (byte) value;
+		fbuf->buf[fbuf->index++] = (byte) (value >> 8);
+		fbuf->buf[fbuf->index++] = (byte) (value >> 16);
+		fbuf->buf[fbuf->index++] = (byte) (value >> 24);
+		fbuf->buf[fbuf->index++] = (byte) (value >> 32);
+		fbuf->buf[fbuf->index++] = (byte) (value >> 40);
+		fbuf->buf[fbuf->index++] = (byte) (value >> 48);
+		fbuf->buf[fbuf->index++] = (byte) (value >> 56);
+	}
+	else
+	{
+		fbuf->buf[fbuf->index++] = (byte) ( ((uint64) value ) >> 56);
+		fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 48);
+		fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 40);
+		fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 32);
+		fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 24);
+		fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 16);
+		fbuf->buf[fbuf->index++] = (byte) (( (uint64) value ) >> 8);
+		fbuf->buf[fbuf->index++] = (byte) value;
+	}
+	
+	etch_flexbuf_fix_length(fbuf);
+
+    return sizeof(value);
+}
+
+
+/**
+ * etch_flexbuf_put_float()
+ */
+size_t etch_flexbuf_put_float( etch_flexbuffer *fbuf, float value )
+{
+	/* return etch_flexbuf_put_int( fbuf, * ((int *)( &value )) ); */
+    const unsigned int u = * ( (int*)&value );
+    return etch_flexbuf_put_int(fbuf, u); 
+}
+
+
+/**
+ * etch_flexbuf_put_double()
+ */
+size_t etch_flexbuf_put_double(etch_flexbuffer *fbuf, double value )
+{
+	/* return etch_flexbuf_put_long( fbuf, *( (int64*) &value ) ); */
+    const int64 u = * ( (int64*)&value );
+    return etch_flexbuf_put_long(fbuf, u);
+}
+
+
+/**
+ * Adjusts index as if by a get or put but without transferring
+ * any data. This could be used to skip over a data item in an
+ * input or output buffer.
+ * 
+ * @param len the number of bytes to skip over. Len must be
+ * >= 0. If put is false, it is an error if len > avail().
+ * If put is true, the buffer may be extended (and the buffer
+ * length adjusted).
+ * 
+ * @param put if true it is ok to extend the length of the
+ * buffer.
+ * 
+ * @return this flex buffer object.
+ * 
+ * @throws EOFException if put is false and len > avail().
+ * 
+ * @throws IOException if the max buffer size is exceeded.
+ */
+etch_flexbuffer *etch_flexbuf_skip(etch_flexbuffer *fbuf, size_t len, int put )
+{
+	if (len  < 0) return NULL;	
+	if (len == 0) return fbuf;
+	
+	if (put)
+	{
+		etch_flexbuf_ensure_size( fbuf, fbuf->index+len );
+		fbuf->index += len;
+		etch_flexbuf_fix_length(fbuf);
+		return fbuf;
+	}
+	
+	fbuf->index += len;	
+	return fbuf;
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_general.c b/binding-c/runtime/c/src/main/common/etch_general.c
new file mode 100644
index 0000000..15d487a
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_general.c
@@ -0,0 +1,161 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_general.h -- general stuff.
+ */
+
+#include "etch_general.h"
+#include "etch_objecttypes.h"
+#include "etch_hash.h"
+#include "etch_arraylist.h"
+#include <wchar.h>
+
+
+// current offset from CLASSID_DYNAMIC_START (etchobjtypes.h)
+// TODO: make atomic
+// TODO: check range
+static unsigned short g_etch_curr_classid;
+
+//TODO: make atomic
+unsigned short get_dynamic_classid() 
+{
+    if (g_etch_curr_classid == 0)
+        g_etch_curr_classid = CLASSID_DYNAMIC_START;
+
+    return g_etch_curr_classid++;
+} 
+
+//TODO: make atomic
+unsigned short get_dynamic_classid_unique(unsigned short* globalid) 
+{
+    if (*globalid == 0) 
+        *globalid = get_dynamic_classid();
+    return (*globalid);
+} 
+
+char* strtrim(char* str)
+{
+    char *startpos = str;
+    {
+        // left trim
+        if(str != NULL) {
+            size_t i = 0;
+            size_t l = strlen(str);
+            for(i = 0; i < l; i++) {
+                if(str[i] == ' ' || str[i] == '\t') {
+                    continue;
+                }
+                startpos = &str[i];
+                break;
+            }
+        }
+    }
+
+    {
+        // right trim
+        if(startpos != NULL) {
+            size_t i = 0;
+            for(i = strlen(startpos); i > 0; i--) {
+                if(startpos[i-1] == ' ' || startpos[i-1] == '\n') {
+                    startpos[i-1] = '\0';
+                    continue;
+                }
+                break;
+            }
+        }
+    }
+    return startpos;
+}
+
+void waitkey()
+{
+    printf("any key ...\n");
+#ifndef _WIN32_WCE    
+    while(!getc(stdin)) {}
+#else    
+    MessageBox(NULL, L"Press any key!", L"Waiting...", NULL);
+#endif    
+}
+
+/**
+ * hexchar_to_int()
+ */
+int hexchar_to_int (const unsigned char hexchar)
+{
+    switch(hexchar) 
+    {   case '0': return 0;
+        case '1': return 1;
+        case '2': return 2;
+        case '3': return 3;
+        case '4': return 4;
+        case '5': return 5;
+        case '6': return 6;
+        case '7': return 7;
+        case '8': return 8;
+        case '9': return 9;
+        case 'a': case 'A': return 10;
+        case 'b': case 'B': return 11;
+        case 'c': case 'C': return 12;
+        case 'd': case 'D': return 13;
+        case 'e': case 'E': return 14;
+        case 'f': case 'F': return 15;
+    }
+    return -1;
+}
+
+
+/**
+ * hexwchar_to_int()
+ */
+int hexwchar_to_int (const wchar_t hexwchar)
+{
+    switch(hexwchar) 
+    {   case L'0': return 0;
+        case L'1': return 1;
+        case L'2': return 2;
+        case L'3': return 3;
+        case L'4': return 4;
+        case L'5': return 5;
+        case L'6': return 6;
+        case L'7': return 7;
+        case L'8': return 8;
+        case L'9': return 9;
+        case L'a': case L'A': return 10;
+        case L'b': case L'B': return 11;
+        case L'c': case L'C': return 12;
+        case L'd': case L'D': return 13;
+        case L'e': case L'E': return 14;
+        case L'f': case L'F': return 15;
+    }
+    return -1;
+}
+
+
+int etch_snwprintf(wchar_t* buffer, size_t count, const wchar_t *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+#if defined(_WIN32)
+    return _vsnwprintf(buffer, count, format, args);
+#elif defined(__APPLE__) || defined(__QNX__) || defined(__LINUX__)
+    return vswprintf(buffer, count, format, args);
+#else
+    return vswprintf(buffer, /*count,*/ format, args);
+#endif
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_hash.c b/binding-c/runtime/c/src/main/common/etch_hash.c
new file mode 100644
index 0000000..4b95905
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_hash.c
@@ -0,0 +1,1143 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+   etch_hash.c -- implementation of an underlying hashtable.
+   provided herein are implementations for the jenkins hashtable APIs.
+*/
+
+#include "etch_hash.h"
+#include "etch_cache.h"
+#include "etch_mem.h"
+#include "etch_mutex.h"
+#include "etch_objecttypes.h"
+#include "etch_arraylist.h"
+#include "jenkhtab.h"
+#include "jenklook.h"
+
+#define ETCH_HASH_MAX_KEYLENGTH 1024 /* arbitrary max byte length of a hashtable key */
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/**
+ * implementation of etch_hashtable.insert() for the jenkins hashtable. 
+ * key and data are pointers to memory owned by the caller. The hashtable does 
+ * not make copies of this data. The caller is responsible for freeing said 
+ * memory, however note that etch_hashtable.clear() frees this memory.
+ * key cannot be null but data can be null.  
+ * datalen parameter is ignored for this implementation.
+ * if out is non_null, *out is assumed to point at a etch_hashitem struct,
+ * and this struct is populated with pointers to the inserted item.
+ * result is zero if OK, otherwise -1;
+ */
+int jenkins_insert(void* realtable, void* key, const int keylen, 
+    void* data, const int datalen, void* in, void** out) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int  result = 0;
+
+    etch_hashtable* ht = (etch_hashtable*)in; 
+
+    if (!realtable || !key || !keylen)
+        return -1;
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_lock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (FALSE == hadd((htab*)realtable, key, keylen, data)) /* jenkhash.lib */
+        result = -1;    /* key already exists most likely */
+    else
+    if (out)
+     {  etch_hashitem* outentry = (etch_hashitem*) *out; 
+        outentry->key   = hkey  ((htab*)realtable);
+        outentry->value = hstuff((htab*)realtable);
+        outentry->hash  = ((htab*)realtable)->ipos->hval;         
+     }
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_unlock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;
+}
+
+
+/**
+ * implementation of etch_hashtable.inserth() for the jenkins hashtable. 
+ * key and data are pointers to memory owned by the caller. the hashtable does 
+ * not make copies of this data. the caller is responsible for freeing said 
+ * memory, however note that etch_hashtable.clear() frees this memory.
+ * key cannot be null but data can be null. 
+ * key object is expected to contain its hashkey value in its first 4 bytes. 
+ * jenkins will use this value, rather than compute a hash value.
+ * if out is non_null, *out is assumed to point at a etch_hashitem struct,
+ * and this struct is populated with pointers to the inserted item.
+ * result is zero if OK, otherwise -1;
+ */
+int jenkins_inserth(void* realtable, void* key, void* data, void* in, void** out) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int  result = 0;
+    etch_hashtable* ht = (etch_hashtable*) in; 
+    
+    if (!realtable || !key)
+        return -1;
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_lock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (FALSE == haddx((htab*)realtable, key, data)) /* jenkhash.lib */
+        result = -1;    /* key already exists most likely */
+    else
+    if (out)
+    {
+        etch_hashitem* outentry = (etch_hashitem*) *out; 
+        outentry->key   = hkey  ((htab*)realtable);
+        outentry->value = hstuff((htab*)realtable);
+        outentry->hash  = ((htab*)realtable)->ipos->hval;         
+     }
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_unlock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;
+}
+
+
+/**
+ * implementation of etch_hashtable.find() for the jenkins hashtable. 
+ * moves the current position on the underlying table to that of supplied key.
+ * if out is non_null, *out is assumed to point at a etch_hashitem struct,
+ * and this struct is populated with pointers to the located item's key and value.
+ * result is zero if OK, otherwise -1;
+ */
+int jenkins_find(void* realtable, void* key, const int keylen, 
+    void* in, void** out) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int  result = 0;
+    etch_hashtable* ht = (etch_hashtable*) in; 
+
+    if (!realtable || !key || !keylen)
+        return -1;
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_lock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (FALSE == hfind((htab*)realtable, (unsigned char*)key, keylen))  
+        result = -1;
+    else
+    if (out)
+    {   etch_hashitem* outentry = (etch_hashitem*) *out; 
+        outentry->key   = hkey  ((htab*)realtable);
+        outentry->value = hstuff((htab*)realtable);
+        outentry->hash  = ((htab*)realtable)->ipos->hval; 
+    }
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_unlock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;  
+}
+
+
+/**
+ * implementation of etch_hashtable.findh() for the jenkins hashtable. 
+ * Implements a find by hashed key, otherwise see comments for find().
+ * result is zero if OK, otherwise -1;
+ */
+int jenkins_findh(void* realtable, const unsigned int hashed, 
+    void* in, void** out) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int result = 0;
+    etch_hashtable* ht = (etch_hashtable*) in; 
+
+    if (!realtable || !hashed)
+        return -1;
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_lock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (FALSE == hfindx((htab*)realtable, hashed)) 
+        result = -1;
+    else     
+    if (out)
+    {   char* tkey = hkey  ((htab*)realtable);
+        void* data = hstuff((htab*)realtable);
+        etch_hashitem* outentry = (etch_hashitem*) *out; 
+        outentry->key   = tkey;
+        outentry->value = data;
+    }
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_unlock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;  
+}
+
+
+/**
+ * implementation of etch_hashtable.first() for the jenkins hashtable. 
+ * moves the current position on the underlying table to that of the first item.
+ * If out is non_null, *out is assumed to point at a etch_hashitem struct,
+ * and this struct is populated with pointers to the located item's key and value.
+ * in parameter is ignored for this implementation.
+ * result is zero if OK, otherwise -1, indicating bad params or an empty table.
+ * @note this method is NOT SYNCHRONIZED, since in most or all cases it is invoked 
+ * only during iteration of the map, and in that case the map is locked explicitly 
+ * by the caller (hashtable_setlock()), and the mutex may not support nesting. 
+ * if there is a need to synch it otherwise, wrap the call as follows:
+ *    map->synchook(ETCH_SYNC_SET_, ((etch_object*)map)->synclock);
+ *    map->first(...);
+ *    map->synchook(ETCH_SYNC_REL_, ((etch_object*)map)->synclock);
+ */
+int jenkins_first(void* realtable, void* in, void** out) 
+{
+    int result = 0;
+
+    if (FALSE == hfirst((htab*)realtable))  
+        result = -1; /* table is empty most likely */
+    else            
+    if (out)
+    {   char* tkey = hkey  ((htab*)realtable);
+        void* data = hstuff((htab*)realtable);
+        etch_hashitem* outentry = (etch_hashitem*) *out; 
+        outentry->key   = tkey;
+        outentry->value = data;
+    }
+
+    return result;  
+}
+
+
+/**
+ * implementation of etch_hashtable.next() for the jenkins hashtable. 
+ * Moves the current position on the underlying table to that of the next item 
+ * in the table. If out is non_null, *out is assumed to point at a etch_hashitem,
+ * and this struct is populated with pointers to the located item's key and value.
+ * in parameter is ignored for this implementation.
+ * result is zero if OK, otherwise -1, indicating either bad params, or that 
+ * there are no more entries, in which case the current position will have wrapped
+ * to the first item, if any entries in fact still remain.
+ * @note this method is NOT SYNCHRONIZED, since in most or all cases it is invoked 
+ * only during iteration of the map, and in that case the map is locked explicitly 
+ * by the caller (hashtable_setlock()), and the mutex may not support nesting. 
+ * if there is a need to synch it otherwise, wrap the call as follows:
+ *    map->synchook(ETCH_SYNC_SET_, ((etch_object*)map)->synclock);
+ *    map->next(...);
+ *    map->synchook(ETCH_SYNC_REL_, ((etch_object*)map)->synclock);
+ */
+int jenkins_next(void* realtable, void* in, void** out) 
+{
+    int is_next_found = 0, is_table_empty = 0;
+    char* tkey = NULL; 
+    void* data = NULL;
+    if (!realtable) return -1;
+
+    /* hnext returns 1 if there is a next entry, or 0 if there is no next entry
+     * and the position has wrapped to the beginning of the table. However if  
+     * the table is now empty, there is no current position, and so we test for
+     * that condition before attempting to reference the current position.
+     */
+    is_next_found  = hnext((htab*)realtable);  /* jenkhash.h */
+    is_table_empty = NULL == ((htab*)realtable)->ipos;
+
+    if (out)  /* return data at current position if requested */
+    {   etch_hashitem* outentry = (etch_hashitem*) *out; 
+
+        if (!is_table_empty)
+        {   tkey = hkey  ((htab*)realtable);
+            data = hstuff((htab*)realtable);
+        }
+        outentry->key   = tkey;
+        outentry->value = data;
+    }
+
+    return is_next_found? 0: -1; 
+}
+
+
+/**
+ * implementation of etch_hashtable.current() for the jenkins hashtable. 
+ * retrieves data for the entry at the current hashtable position.
+ * *out is assumed to point at a etch_hashitem struct; this struct is populated 
+ * with pointers to the current item's key and value.
+ * in parameter is ignored for this implementation.
+ * result is zero if OK, otherwise -1, indicating bad params or an empty table.
+ * @note this method is NOT SYNCHRONIZED, since it is not meaningful for a shared
+ * hashtable (current position will change with every operation).  
+ * if there is a need to synch it, wrap the call as follows:
+ *    map->synchook(ETCH_SYNC_SET_, ((etch_object*)map)->synclock);
+ *    map->current(...);
+ *    map->synchook(ETCH_SYNC_REL_, ((etch_object*)map)->synclock);
+ */
+int jenkins_current(void* realtable, void* in, void** out) 
+{
+    unsigned hash = 0;
+    char* tkey = NULL; 
+    void* data = NULL;
+    etch_hashitem* outentry = NULL; 
+    if (!realtable || !out || !((htab*)realtable)->count) return -1;
+
+    tkey = hkey  ((htab*)realtable);    
+    data = hstuff((htab*)realtable);
+    hash =((htab*)realtable)->ipos->hval;
+
+    outentry = (etch_hashitem*) *out; 
+    outentry->key   = tkey;
+    outentry->value = data;
+    outentry->hash  = hash; 
+
+    return tkey? 0: -1;
+}
+
+/**
+ * Implementation of etch_hashtable.remove() for the jenkins hashtable. 
+ * Frees the entry for the key supplied , but neither the key nor the value, 
+ * are freed, recall that neither of these is a copy but are instead pointers.
+ * To actually free memory for these items, pass etch_hashitem** &out),
+ * and you can then free(out->key), and free(out->value), at your leisure. 
+ * Result is zero if OK, otherwise -1;
+ */
+int jenkins_remove(void* realtable, void* key, const int keylen, 
+    void* in, void** out) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+
+    int result = 0;
+    etch_hashtable* ht = (etch_hashtable*) in; 
+
+    if (!realtable || !key || !keylen)
+        return -1;
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_lock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (FALSE == hfind((htab*)realtable, key, keylen)) /* locate entry */
+        result = -1;                    /* key nonexistent most likely */
+    else
+    {   if (out)           /* save off the entry contents if requested */
+        {   etch_hashitem* outentry = (etch_hashitem*) *out; 
+            outentry->key   = hkey  ((htab*)realtable);
+            outentry->value = hstuff((htab*)realtable);
+            outentry->hash  = ((htab*)realtable)->ipos->hval;   
+        }
+
+        hdel((htab*)realtable);    /* delete entry at current position */
+    } 
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_unlock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;  
+}
+
+/**
+ * jenkins_removeh()
+ */
+int jenkins_removeh(void* realtable, const unsigned key, void* in, void** out) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int result = 0;
+    etch_hashtable* ht = (etch_hashtable*) in; 
+    
+    if (!realtable || !key)
+        return -1;
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_lock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+    
+    if (FALSE == hfindx((htab*)realtable, key)) /* locate entry */
+        result = -1;
+    else  
+    {   if (out)
+        {   etch_hashitem* outentry = (etch_hashitem*) *out; 
+            outentry->key   = hkey  ((htab*)realtable);
+            outentry->value = hstuff((htab*)realtable);
+        }
+
+        hdel((htab*)realtable);    /* delete entry at current position */
+    }
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_unlock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return result;  
+}
+
+/**
+ * implementation of etch_hashtable.clear() for the jenkins hashtable. 
+ * empties the table and, if requested, frees memory for keys/and/or values. 
+ * out parameter is ignored for this implementation.
+ * Result is count of table entries freed, or -1 if error.
+ * Use the freeuser parameter with care. recall that the hashtable stores
+ * pointers to keys and data, plus key length. If user did not allocate each
+ * key separately then setting freeuser would cause a crash. for example,  
+ * if I used a vector of keys and a vector of key lengths; setting freeuser
+ * would ask to free (key length) bytes at some vector offset, obviously
+ * an error. also, currently freeuser does not check the memtable, so if
+ * allocations are being tracked, freeuser should not be used. we could
+ * change this code to query the memtable first, or alternatively, change
+ * etch_free to not complain about allegedly missing memtable entries.
+ */
+int jenkins_clear (void* realtable, const int freekey, const int freeval, void* in, void** out) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int   freecount = 0, currcount = 0, freehandled = 0;
+    int   is_static_keys = 0, is_static_values = 0, is_etch_free = 0;
+    mapcallback callback = NULL;
+    char* key, *value;
+    htab* jenktable;
+    etch_hashtable* ht = (etch_hashtable*) in; 
+
+    if (!(jenktable = (htab*)realtable))
+        return -1;
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_lock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    if (ht) 
+    {   is_static_keys   = ht->is_readonly_keys;
+        is_static_values = ht->is_readonly_values;
+        is_etch_free     = ht->is_tracked_memory;
+        callback         = ht->freehook;
+    }   
+
+    while (0 < (currcount = hcount(jenktable)))
+    {         
+        key   = hkey(jenktable);    /* free entry's key if asked */
+        value = hstuff(jenktable);
+                                    /* optional callback to handle free */
+        freehandled = callback? callback(key, value): FALSE; 
+
+        if (freekey && !is_static_keys && !freehandled)  
+            if(is_etch_free)
+                etch_free(key);
+            else
+                free(key);
+
+        if (freeval && !is_static_values && !freehandled)
+            if  (is_etch_free)
+                etch_free(value);
+            else free(value); 
+    
+        hdel(jenktable);  /* free current table slot */
+        freecount++;
+     }
+
+    if (ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_unlock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return freecount;     /* return count of items freed */
+}
+
+/**
+ * implementation of etch_hashtable.count() for the jenkins hashtable. 
+ * in and out parameters are ignored for this implementation.
+ * result is current number of table entries, or -1 if error.
+ */
+int jenkins_count(void* realtable, void* in, void** out) 
+{                                   
+    const int count = realtable? ((htab*)realtable)->count: -1;   
+    return count;  
+}
+
+/**
+ * implementation of etch_hashtable.size() for the jenkins hashtable. 
+ * in and out parameters are ignored for this implementation.
+ * result is current maximum number of table entries, or -1 if error.
+ */
+int jenkins_size(void* realtable, void* in, void** out) 
+{                                  
+    const int count = realtable? 1 << ((htab*)realtable)->logsize: -1;   
+    return count;  
+}
+
+/**
+ * implementation of etch_hashtable.stats() for the jenkins hashtable. 
+ * in and out parameters are ignored for this implementation.
+ * result is current maximum number of table entries, or -1 if error.
+ */
+int jenkins_stats(void* realtable, void* in, void** out) 
+{                                 
+    if (realtable) hstat((htab*)realtable);     
+    return realtable? 0: -1;  
+}
+
+/**
+ * jenkins_hash
+ * implementation of etch_hashtable.hash() for the jenkins hashtable. 
+ * priorhash is result of the previous operation, or any arbitrary value.
+ * in and out parameters are ignored for this implementation. result is a 
+ * hash of the supplied key, as used by the jenkins hashtable, or zero
+ * if parameters were in error.
+ * author's comments: If you need less than 32 bits, use a bitmask.  
+ * for example, if you need only 10 bits, do h = (h & hashmask(10)),
+ * in which case, the hash table should have hashsize(10) elements.
+ * if you are hashing n strings (unsigned char**)k, do it like this:
+ * for (i=0, h=0; i < n; ++i) h = lookup(k[i], len[i], h);   
+ */
+int jenkins_hash(void* realtable, char* key, const int keylen, const int priorhash, void* in, void** out)  
+{
+    if (!realtable || !key || keylen < 1 || keylen > ETCH_HASH_MAX_KEYLENGTH) {
+        //TODO: log error
+        return 0;
+    }
+    return lookup(key, keylen, priorhash); 
+}
+
+/**
+ * jenkins_hashx
+ * see comments at jenkins_hash
+ */
+int jenkins_hashx(char* key, const int keylen, const int priorhash)  
+{                                 
+    if (!key || keylen < 1 || keylen > ETCH_HASH_MAX_KEYLENGTH) return 0;
+    return lookup(key, keylen, priorhash); 
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - 
+ * constructors, destructors
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * constructor for a hashtable implementation. implements iterable.
+ * creates the underlying hashtable and returns a populated etch_hashtable
+ * interface to it. initialsize is the number of items the hashtable can hold 
+ * before it reallocates itself. note that this value may be altered by the
+ * implementation, e.g. if it is out of range or if it is not a power of 2.
+ */
+etch_hashtable* new_hashtable(const unsigned int initialsize)
+{
+    etch_hashtable* hashtable = ctor_jenkins_hashtable(initialsize);
+
+    new_iterable(&hashtable->iterable, NULL, hashtable_iterable_first, hashtable_iterable_next, hashtable_iterable_has_next); 
+
+    hashtable->is_readonly_keys   = HASHTABLE_DEFAULT_READONLY_KEYS;
+    hashtable->is_readonly_values = HASHTABLE_DEFAULT_READONLY_VALUES;
+    hashtable->is_tracked_memory  = HASHTABLE_DEFAULT_TRACKED_MEMORY;
+    hashtable->content_type       = HASHTABLE_DEFAULT_CONTENT_TYPE;
+
+    return hashtable; 
+}
+
+etch_hashtable* new_hashtable_synchronized(const unsigned int initialsize)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_hashtable* hashtable = NULL;
+
+    hashtable = new_hashtable(initialsize);
+    // TODO: pool
+    status = etch_mutex_create(&((etch_object*)hashtable)->synclock, ETCH_MUTEX_NESTED, NULL);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+    return hashtable;
+}
+
+/**
+ * constructor for etch_set, which is a hashtable containing object keys
+ * and null values
+ */
+etch_set* new_set (const int initialsize)
+{
+    etch_set* newset = new_hashtable_synchronized(initialsize);
+    newset->content_type = ETCHHASHTABLE_CONTENT_OBJECT_NONE;
+    newset->is_readonly_values = TRUE;
+    return newset;
+}
+
+/**
+ * destructor for a hashtable implementation.
+ * is_free_keys parameter asks that memory pointed to by hashbucket keys be freed.
+ * Use this with care, since this obviously requires that you have malloc'ed keys 
+ * individually, and did not, for example, hash your keys out of a memory vector, 
+ * static variables, or the like. is_free_values likewise for the table content. 
+ * The readonly flags set on the hashtable take precedence over either. 
+ * Use of either of course means your pointers to content will now be dangling.  
+ */
+int destroy_hashtable(etch_hashtable* map, const int is_free_keys, const int is_free_values)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int is_free_keymem = 0, is_free_valmem = 0;
+    if (NULL == map) return -1;
+
+    if (((etch_object*)map)->synclock) {
+        status = etch_mutex_trylock(((etch_object*)map)->synclock);
+        if(status != ETCH_SUCCESS) {
+            return -1;
+        }
+    }
+
+    if (!is_etchobj_static_content(map))
+    {
+        struct i_hashtable* vtab = (struct i_hashtable*)((etch_object*)map)->vtab;
+        is_free_keymem = !map->is_readonly_keys   && is_free_keys;
+        is_free_valmem = !map->is_readonly_values && is_free_values;
+        
+        /* free all buckets, and also contents only if is_free_contents is set */
+        if (map->realtable && vtab && !is_etchobj_static_content(map)) 
+        {   
+            vtab->clear(map->realtable, is_free_keymem, is_free_valmem, map, 0);  
+            vtab->hdestroy(map->realtable, map, 0);
+        }
+    } else {
+    }
+
+    if (((etch_object*)map)->synclock) {
+        status = etch_mutex_unlock(((etch_object*)map)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+        if (!is_etchobj_static_content(map)) {
+            status = etch_mutex_destroy(((etch_object*)map)->synclock);
+            ETCH_ASSERT(status == ETCH_SUCCESS);
+        }
+    }
+
+    //TODO:
+    // cleanup synclock
+    // maybe it is done by map->synchook(ETCH_SYNC_DEL
+
+    if (!is_etchobj_static_shell(map)) {
+        etch_free(map);
+    }
+
+    return 0;
+}
+
+
+/**
+ * implementation of etch_hashtable.destroy() for the jenkins hashtable.
+ * destroys the table, but not the memory allocated for the individual item 
+ * keys and values. use clear(), not destroy(), for that purpose.
+ * out parameter is ignored for this implementation.
+ * result is zero if OK, otherwise -1;
+ */
+int jenkins_destroy(void* realtable, void* in, void** out)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_hashtable* ht = (etch_hashtable*) in; 
+    
+    if (!realtable)
+        return -1;
+
+    if(ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_trylock(((etch_object*)ht)->synclock);
+        if(status != ETCH_SUCCESS) {
+            return -1;
+        }
+    }
+
+    if (((htab*)realtable)->table)
+        hdestroy((htab*) realtable);  /* jenkhash.lib */
+
+    if(ht && ((etch_object*)ht)->synclock) {
+        status = etch_mutex_unlock(((etch_object*)ht)->synclock);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+
+    return 0;
+}
+
+
+/**
+ * implementation of etch_hashtable.create() for the jenkins hashtable.
+ * this is the constructor for the underlying hashtable.
+ * we receive initial size in items and convert this to bit width.
+ * If initial size supplied is not a power of 2 we make it so.
+ * jenkins takes a log2 value as size, e.g. size 6 means size is 6 bits wide = 64.
+ * returns in *out, a pointer to a jenkins htab struct describing the underlying table.
+ * in parameter is ignored for this implementation.
+ * result is zero if OK, otherwise -1;
+ */
+int jenkins_create(const int initialsize_items, void* in, void** out)
+{
+    htab* hashtable = NULL;
+    int initialsize_bits_plus1 = 0, initialsize, divby2;
+    if (out == NULL) return -1; 
+
+    if  (initialsize_items <= 0)
+         initialsize = ETCH_DEFAULT_HASHTABLE_SIZE;
+    else
+    if  (initialsize_items < MIN_INITIAL_HASHTABLE_SIZE)
+         initialsize = MIN_INITIAL_HASHTABLE_SIZE;
+    else initialsize = initialsize_items;
+
+    if  (initialsize > MAX_INITIAL_HASHTABLE_SIZE) 
+         initialsize = MAX_INITIAL_HASHTABLE_SIZE;
+
+    for (divby2 = initialsize; divby2; divby2 >>= 1)      
+         initialsize_bits_plus1++; 
+
+    hashtable = hcreate(initialsize_bits_plus1 - 1); /* jenkhash.lib */
+
+    *out = hashtable;
+    return hashtable? 0: -1;
+}
+
+
+/**
+ * destroy_hashtable_default()
+ * default destructor for jenkins hashtable
+ */
+int destroy_hashtable_default(etch_hashtable* map)
+{
+    destroy_hashtable(map, !map->is_readonly_keys, !map->is_readonly_values);
+    return 0;
+}
+
+
+/**
+ * clone_hashtable_default()
+ * default copy constructor for jenkins hashtable.
+ * we won't do an implementation at this level, since we would need to also clone
+ * content, and only the instantiator knows key/value sizes
+ */
+etch_hashtable* clone_hashtable_default(etch_hashtable* map)
+{
+    return NULL;
+}
+
+/**
+ * constructor for the etch_hashtable interface. constructs and initializes 
+ * the interface shell, but not the underlying hashtable.
+ */
+etch_hashtable* _new_etch_hashtable()
+{
+    etch_hashtable* newht = 0;
+    newht = (etch_hashtable*) new_object(sizeof(etch_hashtable),ETCHTYPEB_HASHTABLE,CLASSID_HASHTABLE);
+    return newht; 
+}
+
+/**
+ * ctor_jenkins_hashtable()
+ * constructor for jenkins hashtable interface. 
+ * populates interface implementation methods and creates the underlying hashtable.
+ * returns pointer to etch_hashtable, or NULL if table could not be created.
+ */
+etch_hashtable* ctor_jenkins_hashtable(const int initialsize_items)
+{
+    htab* jenkins_hashtable   = NULL;
+    etch_hashtable* hashtable = NULL;
+    i_etch_hashtable* vtab    = NULL;
+    const unsigned short CLASS_ID = CLASSID_HASHTABLE_VTAB;
+    int result = 0, is_just_cached = FALSE;
+
+    hashtable = _new_etch_hashtable(); 
+
+    vtab = etch_cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+    if(!vtab)  
+    { 
+        vtab = new_vtable(((etch_object*)hashtable)->vtab, sizeof(i_etch_hashtable), CLASS_ID);
+        vtab->create   = jenkins_create;
+        vtab->hdestroy = jenkins_destroy; 
+        vtab->insert   = jenkins_insert;
+        vtab->inserth  = jenkins_inserth;
+        vtab->find     = jenkins_find;
+        vtab->findh    = jenkins_findh;
+        vtab->first    = jenkins_first;
+        vtab->next     = jenkins_next;
+        vtab->current  = jenkins_current;
+        vtab->remove   = jenkins_remove;
+        vtab->removeh  = jenkins_removeh;
+        vtab->clear    = jenkins_clear;
+        vtab->count    = jenkins_count;
+        vtab->size     = jenkins_size;
+        vtab->stats    = jenkins_stats;
+
+        etch_cache_insert(((etch_object*)vtab)->get_hashkey(vtab), vtab, FALSE);
+        is_just_cached = TRUE;
+    }
+
+    ((etch_object*)hashtable)->vtab = (vtabmask*)vtab;
+
+    /* create the underlying real hashtable */
+    result = vtab->create(initialsize_items, NULL, &jenkins_hashtable);
+    hashtable->realtable = jenkins_hashtable;
+
+    ((etch_object*)hashtable)->destroy = destroy_hashtable_default;
+    ((etch_object*)hashtable)->clone   = clone_hashtable_default;
+
+    if (result == -1)   
+    {   
+        if (is_just_cached) {
+            etch_cache_del(CLASS_ID);
+        }
+        etch_object_destroy(hashtable);
+    }
+
+    return hashtable; 
+}
+
+
+/*
+ * new_systemhashtable()
+ * for such a hashtable we will not use the vtab interface
+ * but rather will call the implementation methods directly.
+ */
+etch_hashtable* new_systemhashtable(const int initialsize_items)
+{
+    int result = 0;
+    htab* jenkins_hashtable = NULL;
+    etch_hashtable* hashtable = 0;
+  
+    hashtable = etch_malloc(sizeof(etch_hashtable), 0); 
+    memset(hashtable, 0, sizeof(etch_hashtable)); 
+
+    result = jenkins_create(initialsize_items, NULL, &jenkins_hashtable);
+    hashtable->realtable = jenkins_hashtable;
+
+    if (result == 0) 
+        new_iterable(&hashtable->iterable, NULL, hashtable_iterable_first, 
+            hashtable_iterable_next, hashtable_iterable_has_next); 
+
+    else /* some problem creating hashtable */  
+    {
+        delete_systemhashtable(hashtable);
+        hashtable = NULL;
+    }
+ 
+    return hashtable; 
+}
+
+
+/*
+ * delete_systemhashtable()
+ * delete an untracked hashtable
+ */
+void delete_systemhashtable(etch_hashtable* hashtable)
+{
+   if (!hashtable) return;
+   jenkins_destroy(hashtable->realtable, NULL, NULL);
+   free(hashtable);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - 
+ * hashtable synchronization
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/*
+ * hashtable_defsynchook()
+ * hashtable synchronization hook usable for most purposes.
+ * to enable synchronization, set map.synchook to this function, 
+ * and set map.synclock to an instantiated mutex.
+ */
+//int hashtable_defsynchook(void* action, void* mutex)
+//{
+//    /* all the casting is to quash pointer cast warnings */
+//    return etch_mutex_default_hookproc((int)(((size_t) action) & 0xf), mutex);
+//}
+
+
+/* 
+ * hashtable_getlock()
+ * explicitly set this map's synchronization lock, waiting if unavailable.
+ * this should be used only for locking a map prior to iterating the map.   
+ * for synchronization of map operations, the presence of map.synchook  
+ * and map.synclock is sufficient. 
+ */
+int hashtable_getlock (etch_hashtable* map)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    ETCH_ASSERT(map && ((etch_object*)map)->synclock);
+    if(((etch_object*)map)->synclock) {
+        status = etch_mutex_lock(((etch_object*)map)->synclock);
+        if(status != ETCH_SUCCESS) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/* 
+ * hashtable_trylock()
+ * explicitly set this map's synchronization lock, failing if unavailable.
+ * this should be used only for locking a map prior to iterating the map.   
+ * for synchronization of map operations, the presence of map.synchook  
+ * and map.synclock is sufficient. 
+ */
+int hashtable_trylock (etch_hashtable* map)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    ETCH_ASSERT(map && ((etch_object*)map)->synclock);
+    if(((etch_object*)map)->synclock) {
+        status = etch_mutex_trylock(((etch_object*)map)->synclock);
+        if(status != ETCH_SUCCESS) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/* 
+ * hashtable_rellock()
+ * release explicitly set this map's synchronization lock.
+ * this should be used only for unlocking a map after iterating the map.   
+ * for synchronization of map operations, the presence of map.synchook  
+ * and map.synclock is sufficient. 
+ */
+int hashtable_rellock (etch_hashtable* map) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+    ETCH_ASSERT(map && ((etch_object*)map)->synclock);
+    if(((etch_object*)map)->synclock) {
+        status = etch_mutex_unlock(((etch_object*)map)->synclock);
+        if(status != ETCH_SUCCESS) {
+            return -1;
+        }
+    }
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - 
+ * i_iterable implementations
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/*
+ * hashtable_iterable_first() 
+ * i_iterable first() implementation
+ */
+int hashtable_iterable_first(etch_iterator* iter)
+{
+    etch_hashtable* hash = NULL;
+    etch_hashitem   hashbucket, *outentry = &hashbucket;
+    if (!iter || !iter->collection) return -1;
+    iter->current_key = iter->current_value = NULL;
+    hash = iter->collection;
+
+    if (-1 == ((struct i_hashtable*)((etch_object*)hash)->vtab)->first(hash->realtable, 0, &outentry))
+        return -1;
+
+    iter->current_key   = outentry->key;
+    iter->current_value = outentry->value;     
+    iter->ordinal++;
+    return 0;
+}
+
+
+/*
+ * hashtable_iterable_next() 
+ * i_iterable next() implementation
+ * functions as first() if there is no current position.
+ */
+int hashtable_iterable_next(etch_iterator* iter)
+{
+    etch_hashtable* hash = NULL;
+    etch_hashitem   hashbucket, *outentry = &hashbucket;
+    if (!iter || !iter->collection || !iter->ordinal) return -1;
+    iter->current_key = iter->current_value = NULL;
+    hash = iter->collection;
+
+    if (-1 == ((struct i_hashtable*)((etch_object*)hash)->vtab)->next(hash->realtable, 0, &outentry))   
+        return -1;
+
+    iter->current_key   = outentry->key;
+    iter->current_value = outentry->value;     
+    iter->ordinal++;
+    return 0;
+}
+
+
+/*
+ * hashtable_iterable_has_next() 
+ * i_iterable has_next() implementation.
+ */
+int hashtable_iterable_has_next(etch_iterator* iter)
+{
+    return iter && iter->collection && iter->current_key && iter->ordinal;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - 
+ * clear() callbacks
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/* 
+ * string_to_object_clear_handler()
+ * callback set to handle freeing of key/value memory during destroy()  
+ * and subsequent clear() of a string-to-etch_object hashtable.
+ * handlers return FALSE to indicate memory management NOT handled,
+ */
+int string_to_object_clear_handler (void* data1, void* data2)  
+{
+  wchar_t* key = (wchar_t*)data1;
+  etch_object* value = (etch_object*)data2;
+    etch_free(key); /* free string key */
+    etch_object_destroy(value); /* free etch object value */
+    return TRUE;
+}
+
+
+/* 
+ * object_to_object_clear_handler()
+ * callback set to handle freeing of key/value memory during destroy()  
+ * and subsequent clear() of a etch_object-to-etch_object hashtable.
+ * handlers return FALSE to indicate memory management NOT handled.
+ */
+int object_to_object_clear_handler (void* data1, void* data2)
+{
+    etch_object* key = (etch_object*)data1;
+    etch_object* value = (etch_object*)data2;
+    etch_object_destroy(key);     /* free etch object key */
+    etch_object_destroy(value); /* free etch object value */
+    return TRUE;
+}
+
+
+/* 
+ * etch_noop_clear_handler()
+ * callback set to handle freeing of key/value memory during destroy()  
+ * and subsequent clear() of a etch_object-to-etch_object hashtable.
+ */
+int etch_noop_clear_handler (void* key, void* value)  
+{
+    return TRUE;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - 
+ * etch_map, etch_set
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/* 
+ * new_etch_map()
+ * an etch_map is a hashtable having object keys and object values. 
+ * an object key should of course have its hashkey pre-computed appropriately.
+ * if instantiator wants to use non-disposable objects as keys and/or values,
+ * is_readonly_keys and/or is_readonly_values should be set, and the freehook
+ * callback overridden. furthermore if caller chooses to use the same object  
+ * as both key and value, similar steps should be taken to ensure that code  
+ * does not try to destroy both key and value.
+ */
+etch_hashtable* new_etch_map(const unsigned int initialsize)
+{
+    etch_hashtable* newmap = new_hashtable(initialsize);
+    newmap->content_type = ETCHHASHTABLE_CONTENT_OBJECT_OBJECT;
+    newmap->freehook = object_to_object_clear_handler;
+    newmap->is_readonly_keys = newmap->is_readonly_values = FALSE;
+    return newmap;
+}
+
+/* 
+ * new_etch_set()
+ * an etch_set is a hashtable having object keys and null values. 
+ */
+etch_hashtable* new_etch_set(const unsigned int initialsize)
+{
+    etch_hashtable* newset = new_hashtable(initialsize);
+    ((etch_object*)newset)->class_id = CLASSID_ETCH_SET; /* serializer will expect this */
+    newset->content_type = ETCHHASHTABLE_CONTENT_OBJECT_NONE;
+    newset->freehook = object_to_object_clear_handler; 
+    newset->is_readonly_keys   = FALSE;
+    newset->is_readonly_values = TRUE; 
+    return newset;
+}
+
+
+/**
+ * get_map_keys()
+ * return a collection of the specified map's keys.
+ * caller must invoke the destructor on the returned list. the returned list 
+ * is marked as readonly content, in order that arraylist_destroy() will not 
+ * attempt to free memory for the list content, which remains owned by the map.
+ */
+etch_arraylist* get_map_keys(etch_hashtable* map)
+{    
+    etch_iterator iterator; 
+    etch_arraylist* list = NULL;
+
+    const int typecount = ((struct i_hashtable*)((etch_object*)map)->vtab)->count(map->realtable,0,0);
+    list = new_etch_arraylist(typecount, 0);
+    list->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
+    list->is_readonly  = TRUE; /* content is refs to objects owned by map */
+
+    set_iterator(&iterator, map, &map->iterable);
+
+    while(((struct i_iterable*)iterator.object.vtab)->has_next(&iterator))
+    {
+        etch_arraylist_add(list, iterator.current_key);
+        ((struct i_iterable*)iterator.object.vtab)->next(&iterator);
+    }
+
+    return list;
+}
+
+/**
+ * get_map_values()
+ * return a collection of the specified map's values.
+ * caller must invoke the destructor on the returned list. the returned list 
+ * is marked as readonly content, in order that arraylist_destroy() will not 
+ * attempt to free memory for the list content, which remains owned by the map.
+ */
+etch_arraylist* get_map_values(etch_hashtable* map)
+{    
+    etch_iterator iterator; 
+    etch_arraylist* list = NULL;
+
+    const int typecount = ((struct i_hashtable*)((etch_object*)map)->vtab)->count(map->realtable,0,0);
+    list = new_etch_arraylist(typecount, 0);
+    list->content_type = map->content_type;
+    list->is_readonly  = TRUE;  /* content is refs to objects owned by map */
+
+    set_iterator(&iterator, map, &map->iterable);
+
+    while(((struct i_iterable*)iterator.object.vtab)->has_next(&iterator))
+    {
+        etch_arraylist_add(list, iterator.current_value);
+        ((struct i_iterable*)iterator.object.vtab)->next(&iterator);
+    }
+
+    return list;
+}
+
+
diff --git a/binding-c/runtime/c/src/main/common/etch_hashfunc.c b/binding-c/runtime/c/src/main/common/etch_hashfunc.c
new file mode 100644
index 0000000..b24061b
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_hashfunc.c
@@ -0,0 +1,49 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * hashfunc.c -- implementation of a hash function.
+ * we use the hash function from the jenkins hashtable.
+ */
+
+#include "etch.h"
+#include "jenklook.h"
+
+#define ETCH_HASH_MAX_KEYLENGTH 1024 /* arbitrary max byte length of a hashtable key */
+
+/**
+ * etchhash -- global method to hash an arbitrary byte string to 32 bits.
+ * note that keylen is the key byte length, not string length, as these of
+ * course differ for unicode.
+ * priorhash is result of the previous operation, or any arbitrary value --
+ * see jenkin's comments below for an example.
+ * returns hash of the supplied key, as used by the jenkins hashtable, 
+ * or zero if parameters were in error.
+ *
+ * jenkins' comments: if you need less than 32 bits, use a bitmask.  
+ * for example, if you need only 10 bits, do h = (h & hashmask(10)),
+ * in which case, the hash table should have hashsize(10) elements.
+ * if you are hashing n strings (unsigned char**)k, do it like this:
+ * for (i=0, h=0; i < n; ++i) h = lookup(k[i], len[i], h);   
+*/
+uint32 etchhash(const void* pkey, const int keylen, const unsigned priorhash)  
+{                                 /* jenkhash.lib */
+    if (!pkey || keylen < 1 || keylen > ETCH_HASH_MAX_KEYLENGTH) return 0;    
+    return lookup((ub1*)pkey, keylen, priorhash); 
+}
+
diff --git a/binding-c/runtime/c/src/main/common/etch_linked_list.c b/binding-c/runtime/c/src/main/common/etch_linked_list.c
new file mode 100644
index 0000000..8748fae
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_linked_list.c
@@ -0,0 +1,670 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_linklist.c -- implementation of linklist.
+ */
+
+#include "etch_linked_list.h"
+
+/*
+TODO:
+- no etch_object currently
+*/
+
+
+struct etch_linked_list_node
+{
+    void* data;
+    struct etch_linked_list_node* next;
+};
+
+typedef struct etch_linked_list_node etch_linked_list_node;
+
+
+struct etch_linked_list_t
+{
+    etch_object object;
+
+    void**   impl;                    /*TODO: check why this is a ** here */
+    unsigned short content_obj_type;  /* etch obj_type of a native value */
+    unsigned short content_class_id;  /* etch class_id of a native value */
+    unsigned int count;
+
+    /* this object may be masked by etch_collection_mask to determine content
+     * type and class, so do not add any fields above this comment */
+
+    etch_linked_list_node* head;
+    etch_linked_list_node* tail;
+    uint8                  flags;
+};
+
+etch_status_t etch_linked_list_create(etch_linked_list_t** list, uint8 flags)
+{
+    etch_status_t       rv      = ETCH_SUCCESS;
+    etch_linked_list_t* newlist = NULL;
+
+    if(list == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    newlist = etch_malloc(sizeof(etch_linked_list_t), ETCHTYPEB_COLLECTION);
+    memset(newlist, 0, sizeof(etch_linked_list_t));
+    newlist->flags = flags;
+    
+    *list = newlist;
+
+    return rv;
+}
+
+etch_status_t etch_linked_list_add(etch_linked_list_t* list, void* data)
+{
+    etch_status_t          rv      = ETCH_SUCCESS;
+    etch_linked_list_node* newnode = NULL;
+
+    if(list == NULL || data == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    newnode = etch_malloc(sizeof(etch_linked_list_node), 0);
+    newnode->data = data;
+    newnode->next = NULL;
+
+    if(list->head == NULL) {
+        list->head = newnode;
+    }
+    else {
+        ETCH_ASSERT(list->tail != NULL);
+        list->tail->next = newnode;
+    }
+    list->tail = newnode;
+    list->count++;
+
+    return rv;
+}
+
+
+
+etch_status_t etch_linked_list_insert(etch_linked_list_t* list, int32 index, void* data)
+{
+    etch_status_t          rv      = ETCH_SUCCESS;
+    etch_linked_list_node* newnode = NULL;
+    etch_linked_list_node* node    = NULL;
+    uint32                 i       = 0;
+
+    if(list == NULL ||data == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    if((uint32)index >= list->count || index < 0) {
+        return ETCH_EOUTOFBOUNDS;
+    }
+
+    /* check if index is fist element in the list or last position */
+    if(list->head == NULL) {
+        return etch_linked_list_add(list, data);
+    }
+
+    newnode = etch_malloc(sizeof(etch_linked_list_node), 0);
+    newnode->data = data;
+    newnode->next = NULL;
+
+    rv = ETCH_ERROR;
+    node = list->head;
+    while(node != NULL) {
+        if(index == 0) {
+            newnode->next = list->head;
+            list->head = newnode;
+            rv = ETCH_SUCCESS;
+            break;
+        }
+        if(index - 1 == i) {
+            newnode->next = node->next;
+            node->next = newnode;
+            rv = ETCH_SUCCESS;
+            break;
+        }
+        node = node->next;
+        i++;
+    }
+
+    ETCH_ASSERT(rv == ETCH_SUCCESS);
+    list->count++;
+
+    return rv;
+}
+
+etch_status_t etch_linked_list_get(etch_linked_list_t* list, int32 index, void** data)
+{
+    etch_status_t          rv      = ETCH_SUCCESS;
+    etch_linked_list_node* node    = NULL;
+    uint32                 i       = 0;
+
+    if(list == NULL ||data == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    if((uint32)index >= list->count || index < 0) {
+        return ETCH_EINVAL;
+    }
+
+    node = list->head;
+    while(node != NULL) {
+        if(index == i) {
+            *data = node->data;
+            break;
+        }
+        node = node->next;
+        i++;
+    }
+    return rv;
+}
+
+int32 etch_linked_list_index_of(etch_linked_list_t* list, const void* data)
+{
+    etch_linked_list_node* node    = NULL;
+    int32                  i       = 0;
+    int32                  index   = -1;
+
+    if(list == NULL ||data == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    node = list->head;
+    while(node != NULL) {
+        if(node->data == data) {
+            index = i;
+            break;
+        }
+        node = node->next;
+        i++;
+    }
+    return index;
+}
+
+uint8 etch_linked_list_contains(etch_linked_list_t* list, const void* data)
+{
+    etch_linked_list_node* node = NULL;
+
+    if(list == NULL || data == NULL) {
+        return FALSE;
+    }
+
+    node = list->head;
+    while(node != NULL) {
+        if(node->data == data) {
+            return TRUE;
+        }
+        node = node->next;
+    }
+    return FALSE;
+}
+
+etch_status_t etch_linked_list_remove_at(etch_linked_list_t* list, const int32 index)
+{
+    etch_status_t          rv     = ETCH_SUCCESS;
+    etch_linked_list_node* rmnode = NULL;
+    etch_linked_list_node* node   = NULL;
+    uint32                 i      = 0;
+
+    if(list == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    if((uint32)index >= list->count || index < 0) {
+        return ETCH_EOUTOFBOUNDS;
+    }
+
+    /* check if only one element available */
+    if(list->count == 1) {
+        if(list->flags & ETCH_LINKED_LIST_DATA_FREE) {
+            etch_free(list->head->data);
+        }
+        etch_free(list->head);
+        list->head = NULL;
+        list->tail = NULL;
+        list->count = 0;
+        return ETCH_SUCCESS;
+    }
+
+    node = list->head;
+    while(node != NULL) {
+        if(index == 0) {
+            rmnode = node;
+            list->head = node->next;
+            break;
+        }
+        if(index - 1 == i && index == list->count - 1 ) {
+            rmnode = node->next;
+            node->next = NULL;
+            list->tail = node;
+            break;
+        }
+        if(index - 1 == i) {
+            rmnode = node->next;
+            node->next = node->next->next;
+            break;
+        }
+        node = node->next;
+        i++;
+    }
+
+    /* delete node */
+    ETCH_ASSERT(rmnode != NULL);
+    if(rmnode != NULL) {
+        if(list->flags & ETCH_LINKED_LIST_DATA_FREE) {
+            etch_free(rmnode->data);
+        }
+        etch_free(rmnode);
+        list->count--;
+    } else {
+        rv = ETCH_ERROR;
+    }
+
+    return rv;
+}
+
+etch_status_t etch_linked_list_remove(etch_linked_list_t* list, void* data)
+{
+    etch_status_t rv    = ETCH_SUCCESS;
+    int32         index = -1;
+
+    if(list == NULL || data == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    index = etch_linked_list_index_of(list, data);
+    rv = etch_linked_list_remove_at(list, index);
+
+    return rv;
+}
+
+etch_status_t etch_linked_list_clear(etch_linked_list_t* list)
+{
+    etch_status_t           rv   = ETCH_SUCCESS;
+    etch_linked_list_node*  node = NULL;
+    etch_linked_list_node*  temp = NULL;
+
+    if(list == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    node = list->head;
+    while(node != NULL) {
+        temp = node;
+        node = node->next;
+
+        if(list->flags & ETCH_LINKED_LIST_DATA_FREE) {
+            etch_free(temp->data);
+        }
+        etch_free(temp);
+    }
+
+    list->head = NULL;
+    list->tail = NULL;
+    list->count = 0;
+
+    return rv;
+}
+
+uint32 etch_linked_list_count(etch_linked_list_t* list)
+{
+    if(list == NULL) {
+        return 0;
+    }
+    return list->count;
+}
+
+static etch_status_t etch_linked_list_cleanup(void* p)
+{
+    etch_status_t       rv   = ETCH_SUCCESS;
+    etch_linked_list_t* list = NULL;
+
+    if(p == NULL) {
+        return ETCH_EINVAL;
+    }
+    list = p;
+    etch_linked_list_clear(list);
+    etch_free(list);
+
+    return rv;
+}
+
+etch_status_t etch_linked_list_destroy(etch_linked_list_t* list)
+{
+    etch_status_t rv = ETCH_SUCCESS;
+    rv = etch_linked_list_cleanup(list);
+    return rv;
+}
+
+
+
+
+
+
+
+
+
+///**
+// * new_linkist()
+// * constructor for an etch_linklist.
+// * Creates the underlying list and returns a pointer to the list.
+// */
+//etch_linklist* new_linklist()
+//{
+//    etch_linklist* list = etch_malloc(sizeof(etch_linklist), ETCHTYPEB_COLLECTION);
+//    memset(list, 0, sizeof(etch_linklist));
+//    return list;
+//}
+//
+//
+///*
+// * linklist_clear() 
+// * remove all content from the arraylist, freeing bucket memory always, 
+// * and content memory if requested.  
+// */
+//void linklist_clear(etch_linklist* list, const int is_free_content) 
+//{
+//    linklist_node *p = NULL, *nextp = NULL;
+//    if (NULL == list) return;
+//
+//    for(p = list->head; p; p = nextp)
+//    {   
+//        if (is_free_content && p->content) 
+//            etch_free(p->content);
+//        nextp = p->next;
+//        free(p);               
+//    }
+//
+//    memset(list, 0, sizeof(etch_linklist));          
+//}
+//
+//
+///**
+// * linklist_destroy()
+// * Destructor for an etch_linklist.
+// * Destroys the underlying list, the list shell, and the list content if requested.
+// */
+//void linklist_destroy(etch_linklist* list, const int is_free_content) 
+//{    
+//    if (NULL == list) return;
+//    linklist_clear(list, is_free_content);
+//    etch_free(list);
+//}
+//
+//
+///*
+// * linklist_add() 
+// * add a node to the end of the list, returning the new node's index
+// */
+//int linklist_add(etch_linklist* list, void* content) 
+//{
+//    linklist_node* node = NULL;
+//    if (NULL == list) return -1;
+//
+//    node = etch_malloc(sizeof(linklist_node), ETCHTYPEB_LINKLIST);
+//    node->content = content;
+//    node->next = NULL;
+//    
+//    if (list->head == NULL) /* first entry? */
+//        list->head = node;
+//    else                   
+//    {   assert(list->tail);    
+//        list->tail->next = node;
+//    }
+//
+//    list->tail = node;
+//    return ++list->count;
+//}
+//
+//
+///*
+// * linklist_insert() 
+// * add a node anywhere in the list, returning the new node's index,
+// * or -1 if a parameter was in error.
+// * this implementation cannot insert past the current end of list,
+// * in other words to insert at index n, there must be at least n
+// * entries currently in the list.
+// */
+//int linklist_insert(etch_linklist* list, const unsigned int i, void* content)
+//{
+//    unsigned count = 0;
+//    linklist_node* newnode = NULL, *p = NULL, *priorp = NULL;
+//    if ((NULL == list) || (i > list->count) || (i < 0)) return -1;
+//
+//    newnode = etch_malloc(sizeof(linklist_node), ETCHTYPEB_LINKLIST);
+//    newnode->content = content;
+//    p = priorp = list->head;
+//
+//    if (list->head == NULL)
+//        list->head = list->tail = newnode;
+//    else
+//    if (i == list->count)
+//        list->tail->next = list->tail = newnode;
+//    else
+//    {   for(p = list->head; p, count < i; p = p->next, count++)
+//            priorp = p;
+//        
+//        newnode->next = priorp->next;
+//        priorp->next = newnode;
+//    }
+//
+//    ++list->count;
+//    return i;
+//}
+//
+//
+///*
+// * linklist_moveto() 
+// * private method to move to an indicated index in the list.
+// * returns -1 if a parameter was in error, else 0;
+// * returns also in outp, a pointer to the node at the requested position.
+// */
+//int linklist_moveto(etch_linklist* list, const unsigned startat, const linklist_node** outp)
+//{
+//    unsigned count = 0;
+//    linklist_node* p = NULL;
+//    if ((NULL == list) || (startat > list->count) || (startat < 0)) return -1;
+//  
+//    p = list->head;
+//    while(p != NULL && count < startat){
+//        p = p->next;
+//        count++;
+//    }
+//    if(p != NULL) {
+//        *outp = p;
+//        return 0;
+//    }else{
+//        *outp = NULL;
+//        return -1;
+//    }
+//}
+//
+//
+///*
+// * linklist_containsp() 
+// * return 1 or 0 indicating if the list contains the supplied content pointer,
+// * or -1 if a parameter was in error.
+// */
+//int linklist_containsp(etch_linklist* list, void* content, const unsigned startat)
+//{
+//    struct linklist_node *p = NULL;
+//
+//    if (-1 == linklist_moveto(list, startat, &p)) return -1;
+//
+//    for(; p; p = p->next) 
+//        if (p->content == content) 
+//            return TRUE; 
+//     
+//    return FALSE;
+//}
+//
+//
+///*
+// * linklist_indexofp() 
+// * if the list contains the supplied content pointer, return its index;
+// * return -1 if not found or if a parameter was in error.
+// */
+//int linklist_indexofp(etch_linklist* list, void* content, const unsigned startat)
+//{
+//    struct linklist_node *p = NULL;
+//    int count = startat, foundat = -1;
+//
+//    if (-1 == linklist_moveto(list, startat, &p)) return -1;
+//
+//    for(; p; p = p->next) 
+//    {    
+//        if (p->content == content) 
+//        {   foundat = count;
+//            break;
+//        }        
+//        else count++;
+//    }
+//     
+//    return foundat;
+//}
+//
+//
+///*
+// * linklist_contains() 
+// * return 1 or 0 indicating if the list contains the supplied content 
+// * or -1 if a parameter was in error.
+// * caller must supply a comparator function of signature int f(void* this, void* that), 
+// * which returns -1 if less, 0 if equal, 1 if greater. 
+// */
+//int linklist_contains(etch_linklist* list, void* content, const unsigned startat, etch_comparator compare)
+//{
+//    struct linklist_node *p = NULL;
+//    int result = 0;
+//
+//    if (!list || !compare) return -1;
+//    if (-1 == linklist_moveto(list, startat, &p)) return -1;
+//
+//    for(; p; p = p->next) 
+//    {
+//        result = compare(content, p->content);
+//        if (result == 0) return TRUE;
+//    }
+//     
+//    return FALSE;
+//}
+//
+//
+///*
+// * linklist_indexof() 
+// * if the list contains the supplied content pointer, return its index.
+// * return -1 if a parameter was in error.
+// * caller must supply a comparator function of signature: int (*f)(void* this, void* that); 
+// * which must return -1 if less, 0 if equal, 1 if greater. 
+// */
+//int linklist_indexof(etch_linklist* list, void* content, const unsigned startat, etch_comparator compare)
+//{
+//    struct linklist_node *p = NULL;
+//    int result = 0, count = startat, foundat = -1;
+//
+//    if (!list || !compare) return -1;
+//
+//    if (-1 == linklist_moveto(list, startat, &p)) return -1;
+//
+//    for(; p; p = p->next) 
+//    {
+//        result = compare(content, p->content);
+//        if (result == 0) 
+//        {   foundat = count;
+//            break;
+//        }        
+//        else count++;
+//    }
+//     
+//    return foundat;
+//}
+//
+//
+///*
+// * linklist_get() 
+// * return entry at specified index position, or NULL if parameter error.
+// * if we find the lists are not generally short, we'll supply an indexed version of this list,
+// * and/or implement a resizable array of pointers which we block memcpy to insert and delete.
+// */
+//linklist_node* linklist_get(etch_linklist* list, const unsigned i)
+//{
+//    unsigned count = 0;
+//    struct linklist_node *p = NULL;
+//    if ((NULL == list) || (i >= list->count) || (i < 0)) return NULL;
+//
+//    if(linklist_moveto(list, i, &p) != -1){
+//        return p;
+//    }
+//
+//    return NULL; /* can't arrive here */
+//}
+//
+//
+///*
+// * linklist_remove() 
+// * remove entry at specified index position, free bucket memory; free content memory on request
+// * return -1 if a parameter was in error, or zero if OK.
+// */
+//int linklist_remove(etch_linklist* list, const unsigned i, const int is_free_content)
+//{
+//    int count = 0;
+//    struct linklist_node *p = NULL, *priorp = NULL, *tmp = NULL;
+//    if (!list || (i >= list->count) || (i < 0)) return -1;
+//
+//    if(i == 0 && list->head){
+//        if(list->head == list->tail) 
+//            list->tail = NULL;
+//        tmp = list->head;
+//        list->head = list->head->next;
+//    } else {
+//        p = linklist_get(list,i-1);
+//        tmp = p->next;
+//        if(p && p->next && p->next->next){
+//            p->next = p->next->next;
+//        } else if (p->next && !p->next->next){
+//            list->tail = p;
+//            p->next = NULL;
+//        } else {
+//            return -1;
+//        }
+//    }
+//
+//    if(tmp) {
+//        if (is_free_content && tmp->content)
+//            etch_free(tmp->content);
+//        etch_free(tmp);
+//        if(list->count) {
+//            list->count--; 
+//        }
+//    }
+//
+//    return 0;
+//}
+//
+//
+//int linklist_size(etch_linklist* list)
+//{
+//    linklist_node* cur = list->head;
+//    int length = 0;
+//    while(cur != NULL) {
+//        length++;
+//        cur = cur->next;
+//    }
+//    return length;
+//}
+//
diff --git a/binding-c/runtime/c/src/main/common/etch_log.c b/binding-c/runtime/c/src/main/common/etch_log.c
new file mode 100644
index 0000000..5a01077
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_log.c
@@ -0,0 +1,346 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_log.c
+ * etch c binding logger
+ */
+
+#include "etch_log.h"
+#include "etch_runtime.h"
+#include "etch_mem.h"
+#include "etch_general.h"
+#include "etch_thread.h"
+
+#define ETCH_LOG_MAX_APPENDER 5
+
+static const char* etch_log_level_str[] = {
+    "XDEBUG",
+    "DEBUG",
+    "INFO",
+    "WARN",
+    "ERROR"
+};
+
+//
+// etch console appender
+//
+etch_status_t etch_log_appender_console_create(void** appender, etch_config_t* config)
+{
+    *appender = NULL;
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_log_appender_console_open(void* appender)
+{
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_log_appender_console_log(void* appender, etch_log_message_t* logmsg)
+{
+    struct tm* ts = NULL;
+   
+    if(logmsg == NULL) {
+        return ETCH_EINVAL;
+    }
+    // log message
+    // 23-09-2009 02:52:01 [012345] XDEBUG etch_thread - Located nearest gas station - etch_thread.h, 2223
+    ts = localtime(&logmsg->timestamp);
+    printf("\r%02d-%02d-%04d %02d:%02d:%02d [%06d] %-6s %-25.25s - %s - %s %d\n", 
+        ts->tm_mday,
+        ts->tm_mon + 1,
+        ts->tm_year +1900,
+        ts->tm_hour,
+        ts->tm_min,
+        ts->tm_sec,
+        logmsg->threadid,
+        etch_log_level_str[logmsg->level],
+        logmsg->category,
+        logmsg->message,
+        logmsg->file,
+        logmsg->line
+        );
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_log_appender_console_close(void* appender)
+{
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_log_appender_console_destroy(void* appender)
+{
+    return ETCH_SUCCESS;
+}
+
+static struct etch_log_appender_desc etch_log_appender_console_desc = {
+    etch_log_appender_console_create,
+    etch_log_appender_console_open,
+    etch_log_appender_console_log,
+    etch_log_appender_console_close,
+    etch_log_appender_console_destroy
+};
+
+//
+// etch file appender
+//
+
+struct etch_log_appender_file_t
+{
+    FILE* file;
+};
+
+etch_status_t etch_log_appender_file_create(void** appender, etch_config_t* config)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    // add custome data here
+    *appender = etch_malloc(sizeof(struct etch_log_appender_file_t), 0);
+    ETCH_ASSERT(*appender != NULL);
+    return status;
+}
+
+etch_status_t etch_log_appender_file_open(void* appender)
+{
+    // check if file exists
+    // save file inside archiv
+    // open logfile
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_log_appender_file_log(void* appender, etch_log_message_t* message)
+{
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_log_appender_file_close(void* appender)
+{
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_log_appender_file_destroy(void* appender)
+{
+    if(appender != NULL) {
+        etch_free(appender);
+    }
+    return ETCH_SUCCESS;
+}
+
+static struct etch_log_appender_desc etch_log_appender_file_desc = {
+    etch_log_appender_file_create,
+    etch_log_appender_file_open,
+    etch_log_appender_file_log,
+    etch_log_appender_file_close,
+    etch_log_appender_file_destroy
+};
+
+struct etch_log_appender_desc_entry {
+    const char*             name;
+    etch_log_appender_desc* desc;
+};
+
+static struct etch_log_appender_desc_entry appenders[] = {
+    {"consoleappender", &etch_log_appender_console_desc},
+    {"fileappender", &etch_log_appender_file_desc},
+    {NULL, NULL},
+    {NULL, NULL},
+    {NULL, NULL}
+};
+
+struct etch_log_t
+{
+    etch_log_level    level;
+    etch_log_appender appenders[ETCH_LOG_MAX_APPENDER];
+};
+
+etch_status_t etch_log_register_appender(const char* name, etch_log_appender_desc* desc)
+{
+    uint16 i = 0;
+    for(i = 0; i < ETCH_LOG_MAX_APPENDER; i++) {
+        if(appenders[i].name == NULL) {
+            appenders[i].name = name;
+            appenders[i].desc = desc;
+            return ETCH_SUCCESS;
+        }
+    }
+    return ETCH_ERROR;
+}
+
+static etch_status_t etch_log_get_appender(const char* name, etch_log_appender_desc** desc)
+{
+    uint16 i = 0;
+
+    if(name == NULL || desc == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    for(i = 0; i < ETCH_LOG_MAX_APPENDER; i++) {
+        if(appenders[i].name != NULL && strcmp(appenders[i].name, name) == 0) {
+            *desc = appenders[i].desc;
+            return ETCH_SUCCESS;
+        }
+    }
+    return ETCH_ERROR;
+}
+
+
+etch_status_t etch_log_create(etch_log_t** logger, etch_config_t* config)
+{
+    etch_status_t   status    = ETCH_SUCCESS;
+    etch_log_t*     newlogger = NULL;
+    char*           propvalue = NULL;
+
+    if(logger == NULL || config == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    newlogger = etch_malloc(sizeof(etch_log_t), 0);
+    if(newlogger == NULL) {
+        return ETCH_ENOMEM;
+    }
+    memset(newlogger, 0, sizeof(etch_log_t));
+
+    status = etch_config_get_property_string(config, "etch.log", &propvalue);
+    if(propvalue != NULL) {
+        // parse log configuration
+        char* token  = NULL;
+        char* buffer = NULL;
+        unsigned char  i      = 0;
+        
+        buffer = etch_malloc(strlen(propvalue) + 1, 0);
+        strcpy(buffer, propvalue);
+        
+        // read log level
+        token = strtok(buffer, ",");
+        if(strcmp(token, "xdebug") == 0) {
+            newlogger->level = ETCH_LOG_XDEBUG;
+        } else
+        if(strcmp(token, "debug") == 0) {
+            newlogger->level = ETCH_LOG_DEBUG;
+        } else
+        if(strcmp(token, "info") == 0) {
+            newlogger->level = ETCH_LOG_INFO;
+        } else
+        if(strcmp(token, "warn") == 0) {
+            newlogger->level = ETCH_LOG_WARN;
+        } else
+        if(strcmp(token, "error") == 0) {
+            newlogger->level = ETCH_LOG_ERROR;
+        } else {
+            newlogger->level = ETCH_LOG_WARN;
+        }
+
+        // read appenders
+        do {
+            token = strtok(NULL, ",");
+            token = strtrim(token);
+            if(token != NULL) {
+                etch_log_appender_desc* appender_desc = NULL;
+                status = etch_log_get_appender(token, &appender_desc);
+                if(status == ETCH_SUCCESS && i < ETCH_LOG_MAX_APPENDER) {
+                    // add new appender
+                    newlogger->appenders[i].desc = appender_desc;
+		    newlogger->appenders[i].desc->create(&newlogger->appenders[i].data, config);
+                    newlogger->appenders[i].desc->open(&newlogger->appenders[i].data);
+                    i++;
+                } else {
+                    // WARN appender not found or max appender count reached
+                }
+            }
+        } while(token != NULL);
+
+        // release buffer
+        etch_free(buffer);
+    }
+
+    *logger = newlogger;
+
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_log_log(etch_log_t* logger, const char* category, etch_log_level level, const char* file, int line, const char* fmt, ...)
+{
+    etch_status_t       status     = ETCH_SUCCESS;
+    uint16              i          = 0;
+    etch_log_message_t* logmsg     = NULL;
+    va_list             args;
+    size_t              msg_length = 0;
+    
+    status = etch_runtime_get_logger(&logger);
+    if(! logger || status != ETCH_SUCCESS) {
+        // error: no logger available
+        return ETCH_ERROR;
+    }
+
+    if(!(level >= logger->level)) {
+        return ETCH_SUCCESS;
+    }
+
+    // create message and log to registered appenders
+    logmsg = etch_malloc(sizeof(etch_log_message_t), 0);
+    ETCH_ASSERT(logmsg != NULL);
+    memset(logmsg, 0, sizeof(etch_log_message_t));
+
+    logmsg->category  = category;
+    logmsg->level     = level;
+    logmsg->file      = file;
+    logmsg->line      = line;
+    logmsg->threadid  = etch_thread_current_id();
+    time(&logmsg->timestamp);
+    // format message
+    va_start(args, fmt);
+    msg_length = apr_vsnprintf(NULL, 0, fmt, args);
+    logmsg->message = etch_malloc(msg_length + 1, 0);
+    memset(logmsg->message, 0, msg_length + 1);
+    apr_vsnprintf(logmsg->message, msg_length + 1, fmt, args);
+    va_end(args);
+
+    // TODO: add message to log runner / separate thread
+    for(i = 0; i < ETCH_LOG_MAX_APPENDER; i++) {
+        if(logger->appenders[i].desc != NULL) {
+            logger->appenders[i].desc->log(&logger->appenders[i].data, logmsg);
+        }
+    }
+    etch_free(logmsg->message);
+    etch_free(logmsg);
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_log_logw(etch_log_t* logger, const char* category, etch_log_level level, const char* file, int line, const wchar_t* fmt, ...)
+{
+    //TODO: encode wchar_t to asci or utf-8 string
+    return ETCH_ENOTIMPL;
+}
+
+etch_status_t etch_log_destroy(etch_log_t* logger)
+{
+    uint16 i = 0;
+
+    if(logger != NULL) {
+        // free appenders
+        for(i = 0; i < ETCH_LOG_MAX_APPENDER; i++) {
+            if(logger->appenders[i].desc != NULL) {
+                logger->appenders[i].desc->close(&logger->appenders[i].data);
+                logger->appenders[i].desc->destroy(&logger->appenders[i].data);
+                logger->appenders[i].desc = NULL;
+                logger->appenders[i].data = NULL;
+            }
+        }
+        etch_free(logger);
+    }
+    return ETCH_SUCCESS;
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_map.c b/binding-c/runtime/c/src/main/common/etch_map.c
new file mode 100644
index 0000000..ee0de34
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_map.c
@@ -0,0 +1,495 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etchmap.c -- generic int or string to object map.
+ * note that this code does not implement an etch_map type, that type was added
+ * to etch after we had already defined this particular API.
+ * todo: convert global cache to use this code.
+ */
+
+#include "etch_map.h"
+#include "etch_mem.h"
+#include <wchar.h>
+
+#ifdef WIN32
+#pragma warning (disable:4996)
+#endif
+
+/*
+ * make_etchmap_key() 
+ * given 32-bit key constructs alpha key for the map returning key byte length
+ */
+int make_etchmap_key(const unsigned int key, char* buf, const int buflen)
+{
+   //_itoa_s(key, buf, buflen, 10);
+   sprintf(buf, "%d", key);
+   return (int)strlen(buf);
+}
+
+
+/*
+ * etchmap_populate_out() 
+ * populate caller's out struct
+ */
+void etchmap_populate_out(etch_hashitem* useritem, etch_hashitem* curritem)
+{
+    useritem->key   = curritem->key;
+    useritem->value = curritem->value;
+    useritem->hash  = curritem->hash;
+}
+
+
+/*
+ * etchmap_findxl() 
+ * @return a reference to map content, not owned by caller.
+ * if the etch_hashitem out parameter is specified, it is populated on success.
+ */
+void* etchmap_findxl(etch_hashtable* map, char* key, unsigned keylen, void** out)
+{
+    etch_hashitem  hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+    int result = jenkins_find(map->realtable, key, keylen, 0, (void**)&founditem);
+
+    #if ETCHMAP_DEBUG
+    #pragma warning(disable:4313) 
+    if  (result == 0) 
+         printf("etchmap_found key %s len %d addr %08x\n", 
+                 key, keylen, founditem->value);
+    else printf("etchmap_notfound key %s len %d\n", key, keylen);
+    #endif 
+  
+    if (result == -1) return NULL;
+
+    if (out)
+        etchmap_populate_out(*out, founditem);        
+
+    return founditem->value;
+}
+
+
+/*
+ * etchmap_find() 
+ * locate object with specified key, returning it or NULL.
+ * @return a reference to map content, not owned by caller.
+ * if the etch_hashitem out parameter is specified, it is populated on success.
+ */
+void* etchmap_find(etch_hashtable* map, const unsigned int objkey, void** out)
+{
+    char ckey[ETCHMAP_MAX_IKEYSIZE+1];
+
+    unsigned keylen = make_etchmap_key(objkey, ckey, ETCHMAP_MAX_IKEYSIZE);
+
+    return etchmap_findxl(map, ckey, keylen, out);
+}
+
+
+/*
+ * etchmap_findx() 
+ * locate object with specified ansi char key, returning it or NULL
+ */
+void* etchmap_findx(etch_hashtable* map, char* key, void** out)
+{
+    unsigned keylen = (unsigned)strlen(key);
+
+    return etchmap_findxl(map, key, keylen, out);
+}
+
+
+/*
+ * etchmap_findxw() 
+ * locate object with specified unicode key, returning it or NULL
+ * @return a reference to map content, not owned by caller.
+ * if the etch_hashitem out parameter is specified, it is populated on success.
+ */
+void* etchmap_findxw(etch_hashtable* map, wchar_t* key, void** out)
+{
+    unsigned keylen = (unsigned)(wcslen(key) * sizeof(wchar_t));
+
+    return etchmap_findxl(map, (char*) key, keylen, out);
+}
+
+
+/*
+ * etchmap_find_by_hash() 
+ * locate object with specified hashkey, returning it or NULL.
+ * @return a reference to map content, not owned by caller.
+ * if the etch_hashitem out parameter is specified, it is populated on success.
+ */
+void* etchmap_find_by_hash(etch_hashtable* map, const unsigned hash, void** out)
+{
+    etch_hashitem  hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+int result = jenkins_findh(map->realtable, hash, map, (void**)&founditem);
+    if (result == -1) return NULL;
+
+    if (out)
+        etchmap_populate_out(*out, founditem);       
+    
+    return founditem->value;
+}
+
+
+/*
+ * etchmap_current() 
+ * return object at current position
+ */
+etch_hashitem* etchmap_current(etch_hashtable* map)
+{
+    etch_hashitem  hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+int result = jenkins_current(map->realtable, 0, (void**)&founditem);
+    return (result == -1)? NULL: founditem;
+}
+
+
+/*
+ * etchmap_delxl() 
+ * remove specified object from map given ansi char key and length.
+ * return pointer to object, which is not freed here, it is owned by caller.
+ */
+void* etchmap_delxl (etch_hashtable* map, char* ckey, const unsigned keylen)
+{
+    etch_hashitem hashbucket;
+    etch_hashitem* founditem = &hashbucket;
+
+int result = jenkins_remove(map->realtable, ckey, keylen, 0, (void**)&founditem);
+    if (result == -1) return NULL;
+
+    free(founditem->key); /* free 4-byte key allocated in etchmap_add() */
+    return founditem->value;
+}
+
+
+/*
+ * etchmap_del() 
+ * remove specified object from map given integer key.
+ * return pointer to object, which is not freed here, it is owned by caller.
+ */
+void* etchmap_del (etch_hashtable* map, const unsigned int objkey)
+{
+    char ckey[ETCHMAP_MAX_IKEYSIZE+1];
+
+    unsigned keylen = make_etchmap_key(objkey, ckey, ETCHMAP_MAX_IKEYSIZE);
+
+    return etchmap_delxl(map, ckey, keylen);
+}
+
+
+/*
+ * etchmap_delx() 
+ * remove specified object from map given ansi char key.
+ * return pointer to object, which is not freed here, it is owned by caller.
+ */
+void* etchmap_delx (etch_hashtable* map, char* key)
+{
+    const unsigned keylen = (unsigned)strlen(key);
+
+    return etchmap_delxl(map, key, keylen);
+}
+
+
+/*
+ * etchmap_delxw() 
+ * remove specified object from map given unicode key.
+ * return pointer to object, which is not freed here, it is owned by caller.
+ */
+void* etchmap_delxw (etch_hashtable* map, wchar_t* key)
+{
+    const unsigned keylen = (unsigned)(wcslen(key) * sizeof(wchar_t));
+
+    return etchmap_delxl(map, (char*) key, keylen);
+}
+
+
+/*
+ * etchmap_insertxl() 
+ * add specified object to map given ansi char key and char length, 
+ * with preexistence test optional.
+ * @param key a string for which caller retains ownership, map makes a copy.
+ * @param data an object owned by map or not depending on map attributes.
+ * @return hash of supplied key, or zero if insertion error.
+ */
+int etchmap_insertxl (etch_hashtable* map, 
+    char* key, const unsigned keylen, void* data, const int is_check)
+{
+    int   result = 0, keylent = 0;
+    char* pkey = NULL;
+    void* pval = NULL;
+    etch_hashitem  hashbucket; 
+    etch_hashitem* inserteditem = &hashbucket;
+    memset(&hashbucket, 0, sizeof(etch_hashitem));
+
+    if (is_check)
+      {   pval = etchmap_findxl(map, key, keylen, (void**)&inserteditem);
+        if (pval) return inserteditem->hash; /* entry exists */
+    }
+
+    keylent = keylen + 1;/* add new entry */
+    pkey    = etch_malloc(keylent, 0); 
+    //strcpy_s(pkey, keylent, key);
+	strcpy(pkey, key);
+
+    #if ETCHMAP_DEBUG
+    #pragma warning(disable:4313) 
+    printf("etchmap_insertxl key %s len %d addr %08x\n", pkey, keylen, data); 
+    #endif
+
+    result = jenkins_insert
+      (map->realtable, pkey, keylen, data, 0, 0, (void**)&inserteditem);
+
+    /* etchmap_dump(); */
+
+    return inserteditem->hash;
+} 
+
+
+/*
+ * etchmap_insertxlw() 
+ * add specified object to map given unicode key and char length, 
+ * with preexistence test optional.
+ * @param key a string for which caller retains ownership, map makes a copy.
+ * @param data an object owned by map or not depending on map attributes.
+ * @return hash of supplied key, or zero if insertion error.
+ */
+int etchmap_insertxlw (etch_hashtable* map, 
+    wchar_t* key, const unsigned keylen, void* data, const int is_check)
+{
+    int result = 0, keylent = 0;
+    wchar_t* pkey = NULL;
+    void*    pval = NULL;
+    etch_hashitem  hashbucket; 
+    etch_hashitem* inserteditem = &hashbucket;
+    memset(&hashbucket, 0, sizeof(etch_hashitem));
+
+    if (is_check)
+      {   pval = etchmap_findxl(map, (char*) key, keylen, (void**)&inserteditem);
+        if (pval) return inserteditem->hash; /* entry exists */
+    }
+
+    keylent = keylen + sizeof(wchar_t);     /* add new entry */
+    /* watch this spot. issue observed here where etch_malloc reports that it 
+     * "could not add x to heap tracking store". my guess is that a heap item
+     * at address x had been etch_freed, but key x was for some reason not
+     * removed from the tracking table. memory address x was subsequently
+     * re-issued by malloc, and when etch_malloc attempts to add it to the
+     * tracking table, the address already exists there (or there is a hash
+     * collision?). regardless, this is a tracking error, is probably not a 
+     * leak (because etch_free frees the memory regardless of this error), 
+     * however the error messages are a problem so we need to address this.
+     */
+    pkey = etch_malloc(keylent, 0);   
+    wcscpy(pkey, key);
+
+    result = jenkins_insert
+      (map->realtable, pkey, keylen, data, 0, 0, (void**)&inserteditem);
+
+    return inserteditem->hash;
+} 
+
+
+/*
+ * etchmap_insert() 
+ * add specified object to map with preexistence test optional.
+ * return inserted item hash, or zero if insertion error.
+ */
+int etchmap_insert (etch_hashtable* map, 
+    const unsigned int key, void* data, const int is_check)
+{
+    char  ckey[ETCHMAP_MAX_IKEYSIZE+1];
+    unsigned keylen = make_etchmap_key(key, ckey, ETCHMAP_MAX_IKEYSIZE);
+
+    return etchmap_insertxl(map, ckey, keylen, data, is_check);
+} 
+
+
+/*
+ * etchmap_insertx() 
+ * add specified object to map with preexistence test optional.
+ * param key a string for which caller retains ownership, map makes a copy.
+ * @param data the value of the key/value pair, owned by map or not depending
+ * on map attributes.
+ * return inserted item hash, or zero if insertion error.
+ */
+int etchmap_insertx (etch_hashtable* map, char* key, void* data, const int is_check)
+{
+    unsigned keylen = (unsigned)strlen(key);
+    
+    return etchmap_insertxl(map, key, keylen, data, is_check);
+} 
+
+
+/*
+ * etchmap_insertxw() 
+ * add specified object to map with preexistence test optional.
+ * param key a string for which caller retains ownership, map makes a copy.
+ * @param data the value of the key/value pair, owned by map or not depending
+ * on map attributes.
+ * return inserted item hash, or zero if insertion error.
+ */
+int etchmap_insertxw (etch_hashtable* map, wchar_t* key, void* data, const int is_check)
+{
+    unsigned keylen = (unsigned)(wcslen(key) * sizeof(wchar_t));
+    
+    return etchmap_insertxlw(map, key, keylen, data, is_check);
+} 
+
+
+/*
+ * etchmap_add() 
+ * add specified object to map given integer key.
+ * return 0 or -1.
+ */
+int etchmap_add (etch_hashtable* map, const unsigned int objkey, void* data)
+{
+    /* zero back from etchmap_insert() indicates insert error */ 
+    return etchmap_insert (map, objkey, data, TRUE)? 0: -1;
+} 
+
+
+/*
+ * etchmap_addx() 
+ * add specified object to map.
+ * return 0 or -1.
+ */
+int etchmap_addx(etch_hashtable* map, char* key, void* data)
+{
+    /* zero back from etchmap_insert() indicates insert error */ 
+    return etchmap_insertx (map, key, data, TRUE)? 0: -1;
+} 
+
+
+/*
+ * etchmap_addxw() 
+ * add specified object to map.
+ * return 0 or -1.
+ */
+int etchmap_addxw(etch_hashtable* map, wchar_t* key, void* data)
+{
+    /* zero back from etchmap_insert() indicates insert error */ 
+    return etchmap_insertxw (map, key, data, TRUE)? 0: -1;
+} 
+
+
+/*
+ * etchmap_count() 
+ * return count of items in map.
+ */
+int etchmap_count(etch_hashtable* map)
+{
+    return map? ((struct i_hashtable*)((etch_object*)map)->vtab)->count(map->realtable, 0, 0): 0;
+}
+
+
+/* 
+ * string_to_etchobject_clear_handler()
+ * callback set to handle freeing of key memory during a clear() of  
+ * a string to object type map, where the objects are etch_objects. 
+ * handlers return FALSE to indicate memory free NOT handled.
+ */
+int string_to_etchobject_clear_handler (char* key, etch_object* value)  
+{
+    etch_free(key);
+    etch_object_destroy(value);
+    return TRUE; 
+}
+
+
+/* 
+ * string_to_genericobject_clear_handler()
+ * callback set to handle freeing of key memory during a clear() of  
+ * a string to object type map, where the objects are not etch_objects. 
+ * handlers return FALSE to indicate memory free NOT handled.
+ */
+int string_to_genericobject_clear_handler (char* key, void* value)  
+{
+    etch_free(key);
+    etch_free(value);
+    return TRUE; 
+}
+
+
+/* - - - - - - - - - - - - - - - -
+ * etch_map (object to object map)
+ * - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchmap_is_object_key
+ * @return boolean value indicating whether hashtable key is an etch object
+ */  
+int etchmap_is_object_key(etch_hashtable* map)
+{
+    int result = FALSE;
+    if (map) switch(map->content_type)
+    {   case ETCHHASHTABLE_CONTENT_OBJECT_OBJECT:
+        case ETCHHASHTABLE_CONTENT_OBJECT_NONE:
+             result = TRUE;
+    }
+    return result;
+}
+
+
+/**
+ * etchmap_map_add
+ * inserts item to object/object hashtable
+ * it is assumed that hashkey has been pre-computed on the key object.
+ */  
+int etchmap_map_add (etch_hashtable* map, etch_object* key, etch_object* value) 
+{    
+    int result = 0;
+    key->get_hashkey(key);
+    result = ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth(map->realtable, key, value, map, 0); 
+    return result;  
+}
+
+
+/**
+ * etchmap_map_find()
+ * finds object with specified object key .
+ * it is assumed that hashkey has been pre-computed on the key object.
+ * @return 0 or -1
+ * found item is returned via out parameter, if supplied.
+ */  
+int etchmap_map_find(etch_hashtable* map, etch_object* key, etch_hashitem** out)
+{
+    const int result = ((struct i_hashtable*)((etch_object*)map)->vtab)->findh(map->realtable, key->get_hashkey(key), map, out); 
+    return result;
+}
+
+
+/**
+ * etchmap_set_add
+ * inserts item to object/null hashtable
+ * it is assumed that hashkey has been pre-computed on the key object.
+ */  
+int etchmap_set_add (etch_hashtable* set, etch_object* key) 
+{   
+    int result = 0; 
+    key->get_hashkey(key);
+    result = ((struct i_hashtable*)((etch_object*)set)->vtab)->inserth(set->realtable, key, NULL, set, 0); 
+    return result;
+}
+
+
+
+
+
diff --git a/binding-c/runtime/c/src/main/common/etch_mem.c b/binding-c/runtime/c/src/main/common/etch_mem.c
new file mode 100644
index 0000000..1b48b20
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_mem.c
@@ -0,0 +1,73 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etchmem.c -- heap memory allocate and free.
+ * the c binding wraps the heap allocator in order to track allocations. 
+ * we supply the etch_malloc macro which, when ETCH_DEBUGALLOC is defined, 
+ * will accept module name and code line number, along with object type and
+ * allocation byte length, in order to track allocations and frees, and thus 
+ * enable identification of memory leaks. 
+ */
+
+#include "etch_mem.h"
+#include "etch_log.h"
+
+static mallocFunc g_malloc = NULL;
+static freeFunc   g_free = NULL;
+static reallocFunc g_realloc = NULL;
+
+void* _etch_malloc(size_t size, char* file, int line) {
+    void* p = NULL;
+    
+    if (g_malloc == NULL)
+        p = malloc(size);
+    else
+        p = g_malloc(size);
+        
+    //printf("malloc Mem: %p, File: %s, Line: %d\n", p, file, line);
+    //fflush(stdout);
+    return p;
+}
+
+void _etch_free(void* mem, char* file, int line) {
+    //printf("free Mem: %p, File: %s, Line: %d\n", mem, file, line);
+    //fflush(stdout);
+    if (g_free == NULL)
+        free(mem);
+    else
+        g_free(mem);
+}
+
+void* _etch_realloc(void* p, size_t size, char* file, int line) {
+    void* res = NULL;
+
+    if (g_realloc == NULL)
+        res = realloc(p, size);
+    else
+        res = g_realloc(p, size);
+
+    return res;        
+}
+
+void etch_set_mallocator(mallocFunc myMallocFunc, freeFunc myFreeFunc, reallocFunc myReallocFunc)
+{
+    g_malloc = myMallocFunc;
+    g_free = myFreeFunc;
+    g_realloc = myReallocFunc;
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_mutex.c b/binding-c/runtime/c/src/main/common/etch_mutex.c
new file mode 100644
index 0000000..99c3d96
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_mutex.c
@@ -0,0 +1,207 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_mutex.c
+ * currently wraps apr mutex. our wrapper carries with it the benefit of 
+ * tracking memory for our mutex, and thus for the underlying apr mutex.
+ */
+
+#include "etch_mutex.h"
+#include "etch_object.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+#include "etch_thread.h"
+
+static const char* LOG_CATEGORY = "etch_mutex";
+
+extern apr_pool_t*         g_etch_main_pool;
+extern apr_thread_mutex_t* g_etch_main_pool_mutex;
+
+/** 
+ *  etchmutex: mutex object
+ */
+struct etch_mutex_t
+{
+    etch_object object;
+
+    void* impl;
+    int32 lockcount;
+};
+
+etch_status_t etch_mutex_create(etch_mutex_t** mutex, unsigned int flags, etch_pool_t* pool)
+{
+    etch_status_t       status      = ETCH_SUCCESS;
+    etch_mutex_t*       newmutex    = NULL;
+    apr_status_t        apr_status  = APR_SUCCESS;
+    apr_thread_mutex_t* apr_mutex   = NULL;
+
+    if(mutex == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    if(pool == NULL) {
+        pool = g_etch_main_pool;
+    }
+
+    if(flags != ETCH_MUTEX_NESTED && flags != ETCH_MUTEX_UNNESTED) {
+        return ETCH_EINVAL;
+    }
+
+    newmutex = (etch_mutex_t*)new_object(sizeof(etch_mutex_t), ETCHTYPEB_MUTEX, CLASSID_MUTEX);
+    ETCH_ASSERT(newmutex != NULL);
+
+    apr_thread_mutex_lock(g_etch_main_pool_mutex);
+    apr_status = apr_thread_mutex_create(&apr_mutex, flags, g_etch_main_pool);
+    apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+    if(apr_status != APR_SUCCESS) {
+        char temp[1024];
+        apr_strerror(apr_status, temp, sizeof(temp));
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+        etch_free(newmutex);
+        *mutex = NULL;
+        return ETCH_ERROR;
+    }
+    newmutex->impl      = apr_mutex;
+    newmutex->lockcount = 0;
+    *mutex = newmutex;
+    return status;
+}
+
+etch_status_t etch_mutex_lock(etch_mutex_t* mutex)
+{
+    etch_status_t       status      = ETCH_SUCCESS;
+    apr_status_t        apr_status  = APR_SUCCESS;
+    apr_thread_mutex_t* apr_mutex   = NULL;
+
+    if(mutex == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    apr_mutex = mutex->impl;
+    ETCH_ASSERT(apr_mutex);
+    apr_status = apr_thread_mutex_lock(apr_mutex);
+    switch(apr_status) {
+        case APR_SUCCESS:
+            mutex->lockcount++;
+            status = ETCH_SUCCESS;
+            break;
+        default: {
+            char temp[1024];
+            apr_strerror(apr_status, temp, sizeof(temp));
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+            status = ETCH_ERROR;
+            break;
+        }
+    }
+    return status;
+}
+
+etch_status_t etch_mutex_trylock(etch_mutex_t* mutex)
+{
+    etch_status_t       status     = ETCH_SUCCESS;
+    apr_status_t        apr_status = APR_SUCCESS;
+    apr_thread_mutex_t* apr_mutex  = NULL;
+
+    if(mutex == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    apr_mutex = mutex->impl;
+    ETCH_ASSERT(apr_mutex);
+    apr_status = apr_thread_mutex_trylock(apr_mutex);
+    switch(apr_status) {
+        case APR_SUCCESS:
+            mutex->lockcount++;
+            status = ETCH_SUCCESS;
+            break;
+        case APR_EBUSY:
+            status = ETCH_EBUSY;
+            break;
+        default: {
+            char temp[1024];
+            apr_strerror(apr_status, temp, sizeof(temp));
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s\n", temp);
+            status = ETCH_EBUSY;
+            break;
+        }
+    }
+    return status;
+}
+
+etch_status_t etch_mutex_unlock(etch_mutex_t* mutex)
+{
+    etch_status_t       status     = ETCH_SUCCESS;
+    apr_status_t        apr_status = APR_SUCCESS;
+    apr_thread_mutex_t* apr_mutex  = NULL;
+    
+    if(mutex == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    if(mutex->lockcount > 0) {
+        mutex->lockcount--;
+    }
+
+    apr_mutex = mutex->impl;
+    ETCH_ASSERT(apr_mutex);
+    apr_status = apr_thread_mutex_unlock(apr_mutex);
+    switch(apr_status) {
+        case APR_SUCCESS:
+            status = ETCH_SUCCESS;
+            break;
+        default: {
+            char temp[1024];
+            apr_strerror(apr_status, temp, sizeof(temp));
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+            status = ETCH_ERROR;
+            break;
+        }
+    }
+    return status;
+}
+
+etch_status_t etch_mutex_destroy(etch_mutex_t* mutex)
+{
+    etch_status_t       status     = ETCH_SUCCESS;
+    apr_status_t        apr_status = APR_SUCCESS;
+    apr_thread_mutex_t* apr_mutex  = NULL;
+    
+    if(mutex == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    if(!is_etchobj_static_content(mutex)) {
+        apr_mutex  = mutex->impl;
+        apr_thread_mutex_lock(g_etch_main_pool_mutex);
+        apr_status = apr_thread_mutex_destroy(apr_mutex);
+        apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+        if(apr_status != APR_SUCCESS) {
+            char temp[1024];
+            apr_strerror(apr_status, temp, sizeof(temp));
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+            status = ETCH_ERROR;
+        }
+    }
+
+    if (!is_etchobj_static_shell(mutex)) {
+        etch_free(mutex);
+    }
+    return status;
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_nativearray.c b/binding-c/runtime/c/src/main/common/etch_nativearray.c
new file mode 100644
index 0000000..2c78f52
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_nativearray.c
@@ -0,0 +1,553 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_nativearray.c  
+ * etch_nativearray implementation
+ * does allocation and subscripting for n-dimensional arrays stored as a single
+ * byte vector, to overcome the well-known C compiler issues with passing around
+ * multi dimensioned arrays when the low order dimension is not known at compile
+ * time. the mapping here from byte vector to array tests out as k&r compliant,
+ * this is verified by constructing from a static array using new_etch_nativearray_from
+ * and testing that the get methods return the same result as statically indexed
+ * array items. as it stands, this code handles a max of 3 dimensions. it can be 
+ * generalized to n dimensions, however the caller would have to allocate, populate, 
+ * and pass arrays of subscripts for this to happen.
+ */
+
+#include <stdio.h>
+#include "etch_nativearray.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+
+etch_nativearray* init_etch_nativearray(unsigned short, const size_t, const int, const int, const int, const int);
+int etch_nativearray_put1 (etch_nativearray*, void*, int);
+int etch_nativearray_put2 (etch_nativearray*, void*, int, int);
+int etch_nativearray_put3 (etch_nativearray*, void*, int, int, int);
+int etch_nativearray_get1 (etch_nativearray*, void*, int);
+int etch_nativearray_get2 (etch_nativearray*, void*, int, int);
+int etch_nativearray_get3 (etch_nativearray*, void*, int, int, int);
+int etch_nativearray_set_content_type(etch_nativearray*);
+
+/*
+ * new_etch_nativearray() 
+ * etch_nativearray constructor
+ * note that when creating arrays, the dimensions are passed low-order first,
+ * so for x[2][3][4], dim0 is 4, dim1 is 3, dim2 is 2. for y[7][9], dim0 is 9,
+ * dim1 is 7, and dim2 is zero of course.
+ */
+etch_nativearray* new_etch_nativearray(unsigned short class_id, const size_t itemsize,  
+    const int numdims, const int dim0, const int dim1, const int dim2)
+{
+    etch_nativearray* newarray = init_etch_nativearray(class_id, itemsize, numdims, dim0, dim1, dim2);
+    if (NULL == newarray) return NULL;
+
+    newarray->values = etch_malloc(newarray->bytecount, ETCHTYPEB_BYTES);
+    memset(newarray->values, 0, newarray->bytecount);
+    newarray->is_content_owned = TRUE;
+  
+    etch_nativearray_set_content_type(newarray);
+    return newarray;
+}
+
+/*
+ * new_etch_nativearray_from() 
+ * etch_nativearray constructor from existing byte vector
+ * @param values source array, caller retains ownership.
+ */
+etch_nativearray* new_etch_nativearray_from(void* values, unsigned short class_id, const size_t itemsize, 
+    const int numdims, const int dim0, const int dim1, const int dim2)
+{
+    etch_nativearray* newarray = init_etch_nativearray(class_id, itemsize, numdims, dim0, dim1, dim2);
+    if (NULL == newarray) return NULL;
+
+    newarray->values = values;
+    newarray->is_content_owned = FALSE;
+
+    etch_nativearray_set_content_type(newarray);
+    return newarray;
+}
+
+/*
+ * new_etch_nativearray_of() 
+ * etch_nativearray constructor for array of objects of specified type and class
+ */
+etch_nativearray* new_etch_nativearray_of(unsigned short content_obj_type, unsigned short content_class_id, const int numdims, const int dim0, const int dim1, const int dim2)
+{
+    etch_nativearray* newarray = init_etch_nativearray(CLASSID_ARRAY_OBJECT, sizeof(void*), numdims, dim0, dim1, dim2);
+    if (NULL == newarray) return NULL;
+
+    newarray->content_obj_type = content_obj_type;
+    newarray->content_class_id = content_class_id;
+    return newarray;
+}
+
+/*
+ * init_etch_nativearray() 
+ * etch_nativearray private constructor
+ * assumes max number of dimensions is 3
+ */
+etch_nativearray* init_etch_nativearray(unsigned short class_id, const size_t itemsize,  
+    const int numdims, const int dim0, const int dim1, const int dim2)
+{
+    etch_nativearray* newarray = NULL;
+    int i,j;
+    if (numdims < 1 || itemsize < 1) return NULL;
+    if (numdims > 1 && dim1 < 1)     return NULL;
+    if (numdims > 2 && dim2 < 1)     return NULL;
+
+    newarray = (etch_nativearray*)new_object(sizeof(etch_nativearray), ETCHTYPEB_NATIVEARRAY, class_id);
+
+    newarray->numdims  = numdims;
+    newarray->itemsize = itemsize;
+
+    /* dimension array contains the array dimensions, 
+     * e.g., for x[2][3][4], [0] is 4, [1] is 3, [2] is 2 
+     */
+    newarray->dimension[0] = dim0;
+    newarray->dimension[1] = numdims > 1? dim1: 0;
+    newarray->dimension[2] = numdims > 2? dim2: 0;
+
+    /* dimsize array contains size in bytes of the next lower dimension, 
+     * stored so that the values need not be calculated on each array access. 
+     * [0] is item size, so for int x[5][7][9], [0] is sizeof(int), 
+     * [1] is 9*sizeof(int), [2] is 7*9*sizeof(int)
+     */
+    newarray->dimsize[0] = itemsize;
+    newarray->bytecount  = itemsize * dim0;
+
+    for(i = 1, j = 0; i < numdims; i++, j++)
+    {
+        newarray->dimsize[i] = newarray->dimension[j] * newarray->dimsize[j];
+        newarray->bytecount *= newarray->dimension[i];
+    }
+
+    ((etch_object*)newarray)->clone   = etch_nativearray_clone;
+    ((etch_object*)newarray)->destroy = destroy_etch_nativearray;
+
+    newarray->put1 = etch_nativearray_put1;
+    newarray->put2 = etch_nativearray_put2;
+    newarray->put3 = etch_nativearray_put3;
+    newarray->get1 = etch_nativearray_get1;
+    newarray->get2 = etch_nativearray_get2;
+    newarray->get3 = etch_nativearray_get3;
+
+    return newarray;      
+}
+
+
+
+void* etch_nativearray_clone(void* obj)
+{
+    etch_nativearray* source = (etch_nativearray*)obj;
+    etch_nativearray* newarray = NULL;
+
+    if(source == NULL) {
+        return NULL;
+    }
+
+    newarray = new_etch_nativearray_from(source->values, source->content_class_id, source->itemsize, source->numdims, (int)source->dimension[0], (int)source->dimension[1], (int)source->dimension[2]);
+
+
+    // always own copies of unwrapped content
+    if(source->content_class_id == CLASSID_UNWRAPPED){
+        newarray->values = etch_malloc(source->bytecount, ETCHTYPEB_BYTES);
+        memcpy(newarray->values,source->values,source->bytecount);
+        newarray->is_content_owned = TRUE;
+    }else {
+        //never own anything else
+        newarray->is_content_owned = FALSE;
+        newarray->values = source->values;
+    }
+    newarray->content_class_id = source->content_class_id;
+    newarray->content_obj_type = source->content_obj_type;
+    ((etch_object*)newarray)->class_id = ((etch_object*)source)->class_id;
+    return newarray;
+
+}
+
+/**
+ * destroy_etch_nativearray_content()
+ * destroy nativearray's content vector.
+ * return -1 if content not owned by nativearray and therefore not destroyed;
+ * otherwise return zero, regardless of whether content was null.
+ */
+int destroy_etch_nativearray_content(etch_nativearray* a)
+{
+    int  result = 0;
+    if  (!is_etchobj_static_content(a) && a->is_content_owned) {
+        if(a->content_class_id != CLASSID_UNWRAPPED){
+            size_t i = 0;
+            size_t length = a->bytecount / sizeof(etch_object*);
+            ETCH_ASSERT(a->bytecount % sizeof(etch_object*) == 0);
+            for(; i < length; i++){
+                void** temp = a->values;
+                if( temp[i] ){
+                    etch_object_destroy(temp[i]);
+                }
+            }
+        }
+        etch_free(a->values);  /* OK if values null */  
+    }
+ 
+    else result = -1;
+    return result;
+}
+
+
+/**
+ * destroy_etch_nativearray()
+ * etch_nativearray destructor
+ */
+int destroy_etch_nativearray(void* obj) 
+{
+    etch_nativearray* a = (etch_nativearray*)obj;
+    if (a->is_content_owned && !is_etchobj_static_content(a)) 
+        destroy_etch_nativearray_content(a);
+    destroy_objectex((etch_object*)a);
+    return 0;
+}
+
+
+/*
+ * new_subarray() 
+ * construct and return subaarray[i] of this array.
+ * subarray points into parent content and so does not own its content
+ */
+etch_nativearray* new_subarray(etch_nativearray* a, const int i) 
+{
+    etch_nativearray* subarray = NULL;
+    const int sub_numdims = a->numdims - 1;
+
+    if (a->numdims > 1 && i < (int) a->dimension[sub_numdims]) 
+    {   
+        const size_t sub_bytelen = a->dimsize[sub_numdims];
+        const size_t vector_offset = i * sub_bytelen;
+        byte* subvector = (byte*) a->values + vector_offset;
+
+        subarray = new_etch_nativearray_from(subvector, 
+            ((etch_object*)a)->class_id, (int) a->itemsize, sub_numdims,  
+            (int) a->dimension[0], (int) a->dimension[1], 0);
+
+        subarray->bytecount = sub_bytelen;
+        subarray->content_obj_type = a->content_obj_type;
+        subarray->content_class_id = a->content_class_id;
+        subarray->is_content_owned = a->is_content_owned;
+
+        subarray->counts[0] = a->counts[0]; /* user-maintained counts */  
+        subarray->counts[1] = a->counts[1];  
+        subarray->counts[2] = 0;
+    }
+
+    return subarray;
+}
+
+
+/*
+ * etch_nativearray_get_element() 
+ * return element[i] of specified array, which, if array is multi-dimensioned,
+ * will be another native array, otherwise an etch object. for example, if
+ * the supplied array is byte[2][4], a native array of byte[4] is returned.
+ * if the supplied array is byte[4], an etch_byte object is returned.
+ * returned subarrays do not own content, their content references the content
+ * of their parent.
+ */
+etch_object* etch_nativearray_get_element(etch_nativearray* a, const int i) 
+{
+    int result = 0;
+    etch_object* wrapped_element = NULL;
+
+    const int sub_numdims = a->numdims - 1;
+    if (sub_numdims < 0) return NULL;
+
+    if (sub_numdims > 0) 
+        return (etch_object*) new_subarray(a, i);
+
+    result = etch_nativearray_get_wrapped_component(a, i, &wrapped_element);
+
+    return wrapped_element;
+}
+
+
+/*
+ * etch_nativearray_set_content_type() 
+ * set content_obj_type and content_class_id based on array class_id.
+ * returns zero if content type was set, otherwise -1
+ */
+int etch_nativearray_set_content_type(etch_nativearray* a)
+{
+    unsigned short obj_type = 0;
+    int result = 0;
+
+    switch(((etch_object*)a)->class_id) 
+    {
+        case CLASSID_ARRAY_BYTE:    obj_type = ETCHTYPEB_BYTE;   break;
+        case CLASSID_ARRAY_BOOL:    obj_type = ETCHTYPEB_BOOL;   break;
+        case CLASSID_ARRAY_INT8:    obj_type = ETCHTYPEB_INT8;   break;
+        case CLASSID_ARRAY_INT16:   obj_type = ETCHTYPEB_INT16;  break;
+        case CLASSID_ARRAY_INT32:   obj_type = ETCHTYPEB_INT32;  break;
+        case CLASSID_ARRAY_INT64:   obj_type = ETCHTYPEB_INT64;  break;
+        case CLASSID_ARRAY_FLOAT:   obj_type = ETCHTYPEB_IEEE32; break;
+        case CLASSID_ARRAY_DOUBLE:  obj_type = ETCHTYPEB_IEEE64; break;
+    }
+
+    if (obj_type) {
+        a->content_obj_type = obj_type;
+        a->content_class_id = CLASSID_UNWRAPPED;
+    }
+    else switch(((etch_object*)a)->class_id) 
+    {
+        case CLASSID_ARRAY_OBJECT: 
+            a->content_obj_type = ETCHTYPEB_ETCHOBJECT; 
+            a->content_class_id = CLASSID_OBJECT;
+            break;
+
+        case CLASSID_ARRAY_STRING:  
+            a->content_obj_type = ETCHTYPEB_STRING; 
+            a->content_class_id = CLASSID_STRING;
+            break;
+
+        default:
+            result = -1; /* indicates content type not set */
+    }
+    
+    return result;
+}
+
+
+/**
+ * put1()
+ * insert item to singly dimensioned array
+ * array access can be generalized by passing an array of subscripts; however
+ * since we are currently handling max 3 dimensions, the calling sequence is 
+ * much simpler when we have separate accessors for each dimensionality.
+ */
+int etch_nativearray_put1(etch_nativearray* a, void* value, int i) 
+{
+    size_t offset = etch_nativearray_off1(a, i);
+    if (value == NULL || offset < 0) return -1;
+    memcpy((byte*)a->values + offset, value, a->itemsize); 
+    return 0;
+}
+
+
+/**
+ * put2()
+ * insert item to 2-dimensional array
+ */
+int etch_nativearray_put2(etch_nativearray* a, void* value, int i, int j) 
+{
+    size_t offset = etch_nativearray_off2(a, i, j);
+    if (value == NULL || offset < 0) return -1;
+    memcpy((byte*)a->values + offset, value, a->itemsize);  
+    return 0;
+}
+
+
+/**
+ * put3()
+ * insert item to 3-dimensional array
+ */
+int etch_nativearray_put3(etch_nativearray* a, void* value, int i, int j, int k) 
+{
+    size_t offset = etch_nativearray_off3(a, i, j, k);
+    if (value == NULL || offset < 0) return -1;
+    memcpy((byte*)a->values + offset, value, a->itemsize); 
+    return 0;
+}
+
+
+/**
+ * get1()
+ * access and return item from singly dimensioned array
+ */
+int etch_nativearray_get1(etch_nativearray* a, void* value, int i) 
+{
+    size_t offset = etch_nativearray_off1(a, i);
+    if (value == NULL || offset < 0) return -1;
+    memcpy(value, (byte*)a->values + offset, a->itemsize); 
+    return 0;
+}
+
+
+/**
+ * get2()
+ * access and return item from 2-dimensional array
+ */
+int etch_nativearray_get2(etch_nativearray* a, void* value, int i, int j) 
+{
+    size_t offset = etch_nativearray_off2(a, i, j);
+    if (value == NULL || offset < 0) return -1;
+    memcpy(value, (byte*)a->values + offset, a->itemsize); 
+    return 0;
+}
+
+
+/**
+ * get3()
+ * access and return item from 3-dimensional array
+ */
+int etch_nativearray_get3(etch_nativearray* a, void* value, int i, int j, int k) 
+{
+    size_t offset = etch_nativearray_off3(a, i, j, k);
+    if (value == NULL || offset < 0) return -1;
+    memcpy(value, (byte*)a->values + offset, a->itemsize); 
+    return 0;
+}
+
+
+/*
+ * etch_nativearray_off1() 
+ * calculate byte offset into byte vector for a 1-dimension array
+ */
+size_t etch_nativearray_off1(etch_nativearray* a, int i)
+{
+    size_t offset = 0;    
+    if (i >= (int) a->dimension[0] || i < 0) return -1; 
+
+    offset = i * a->dimsize[0];
+    return offset;
+}
+
+
+/*
+ * etch_nativearray_off2() 
+ * calculate byte offset into byte vector for a 2-dimension array
+ */
+size_t etch_nativearray_off2(etch_nativearray* a, int i, int j)
+{
+    size_t offset = 0;    
+    if ((i >= (int) a->dimension[1] || i < 0)  
+     || (j >= (int) a->dimension[0] || j < 0)) return -1; 
+
+    offset = (i * a->dimsize[1]) + (j * a->dimsize[0]);
+    return offset;
+}
+
+
+/*
+ * etch_nativearray_off3() 
+ * calculate byte offset into byte vector for a 3-dimension array
+ */
+size_t etch_nativearray_off3(etch_nativearray* a, int i, int j, int k)
+{
+    size_t offset = 0;    
+    if ((i >= (int) a->dimension[2] || i < 0)  
+     || (j >= (int) a->dimension[1] || j < 0)   
+     || (k >= (int) a->dimension[0] || k < 0)) return -1; 
+
+    offset = (i * a->dimsize[2]) + (j * a->dimsize[1]) + (k * a->dimsize[0]);
+    return offset;
+}
+
+
+
+
+/** 
+ * etch_nativearray_get_wrapped_component()
+ * get wrapped component[i] from the single-dimensioned native array.
+ * caller owns returned object.
+ * todo: test that if array content was wrapped, the is_value_owned
+ * setting is sufficient for tranparent memory management of returned object.
+ */
+int etch_nativearray_get_wrapped_component(etch_nativearray* a, const int i, etch_object** out)
+{
+    const int numentries = (int) a->dimension[0];
+    const int is_wrapped_content = a->content_class_id != 0;
+    int result = 0;
+    union
+    { char  vbyte; short  vint16; int   vint32; int64 vint64; 
+      float vfloat;double vdouble;void* vaddr;  int64 all;
+    } v;
+
+    if (a->numdims != 1 || i >= numentries) return -1;
+    v.all = 0;
+
+    if (is_wrapped_content)
+    {   /* content of the native array is wrapped, e.g, etch_object*,   
+         * so we return the item as is */   
+         result = a->get1(a, &v.vaddr, i);
+         *out = v.vaddr;        
+    }
+    else 
+    {
+       
+        
+        switch(a->content_obj_type)
+        {   /* content of the native array is unwrapped, e.g, int[], so we wrap   
+             * the array item with an etch object prior to returning it */
+            case ETCHTYPEB_BYTE: 
+                 result = a->get1(a, &v.vbyte, i);
+                 *out = (etch_object*) new_byte(v.vbyte);
+                 break;
+      
+            case ETCHTYPEB_BOOL: 
+                 result = a->get1(a, &v.vbyte, i);
+                 *out = (etch_object*) new_boolean(v.vbyte);
+                 break;   
+
+            case ETCHTYPEB_INT8: 
+                 result = a->get1(a, &v.vbyte, i);
+                 *out = (etch_object*) new_int8(v.vbyte);
+                 break; 
+         
+            case ETCHTYPEB_INT16:  
+                 result = a->get1(a, &v.vint16, i);
+                 *out = (etch_object*) new_int16(v.vint16);
+                 break; 
+
+            case ETCHTYPEB_INT32: 
+                 result = a->get1(a, &v.vint32, i);
+                 *out = (etch_object*) new_int32(v.vint32);
+                 break; 
+
+            case ETCHTYPEB_INT64: 
+                 result = a->get1(a, &v.vint64, i);
+                 *out = (etch_object*) new_int64(v.vint64);
+                 break;  
+
+            case ETCHTYPEB_IEEE32:  
+                 result = a->get1(a, &v.vfloat, i);
+                 *out = (etch_object*) new_float(v.vfloat);
+                 break;      
+
+            case ETCHTYPEB_IEEE64:
+                 result = a->get1(a, &v.vdouble, i);
+                 *out = (etch_object*) new_double(v.vdouble);
+                 break; 
+
+            case ETCHTYPEB_STRING: 
+                 result = a->get1(a, &v.vaddr, i);
+                 *out = (etch_object*) new_stringw(v.vaddr);
+		 printf("warning\n");
+                 break; 
+
+            default: /* item is an anonymous pointer to a value owned by caller */
+            {    
+                result = a->get1(a, &v.vaddr, i);   
+                *out = (etch_object*) v.vaddr;
+            } 
+        }
+        /*
+        if(out && *out && ! a->is_content_owned)
+           set_etchobj_static_content((*out));
+        */
+    }  /* switch(a->content_obj_type) */ 
+
+    return result;
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_object.c b/binding-c/runtime/c/src/main/common/etch_object.c
new file mode 100644
index 0000000..9f4b269
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_object.c
@@ -0,0 +1,1102 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_object.c
+ */
+
+#include "etch_cache.h"
+#include "etch_exception.h"
+#include "etch_nativearray.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+#include <wchar.h>
+
+
+unsigned int primitive_objsize[] =
+{
+    sizeof(etch_byte),  sizeof(etch_boolean), sizeof(etch_int8),  sizeof(etch_int16), 
+    sizeof(etch_int32), sizeof(etch_int64),   sizeof(etch_float), sizeof(etch_double),
+    sizeof(etch_string),sizeof(etch_date),  
+};
+
+/**
+ * destroy_object()
+ * default virtual destructor for an etch_object* based object 
+ * (other than etch_object), invoked by all other object dtors.
+ */
+int destroy_object(void* thisx)
+{
+    etch_object* thisobj = (etch_object*)thisx;
+    etch_object* parentobj = NULL;
+    if (thisobj == NULL) return -1;
+    parentobj = thisobj->parent;
+
+    if (thisobj->result)
+    {   
+        etch_free(thisobj->result);
+    }
+ 
+    if (!is_etchobj_static_shell(thisobj))
+        etch_free(thisobj);
+
+    etch_object_destroy(parentobj);
+    
+    return 0;
+}
+
+/**
+ * destroy_objectex()
+ * mark object as "refcount already decremented" and invoke destroy_object
+ */
+int destroy_objectex(etch_object* thisobj)
+{   
+    return destroy_object(thisobj);
+}
+
+etch_status_t etch_object_destroy(void* pobject)
+{
+    if(pobject){
+        ((etch_object*)pobject)->destroy((etch_object*)pobject);
+    }
+    return ETCH_SUCCESS;
+}
+
+
+etch_object* etch_object_clone_func(void* pobject)
+{
+    etch_object* object = (etch_object*)pobject;
+    if(object != NULL) {
+        return object->clone(object);
+    }
+    return NULL;
+}
+
+
+/**
+ * set_etch_assignable_arg_from()
+ * populate an argument to etchobj_is_assignable_from() from specified object
+ */
+void set_etch_assignable_arg_from(etch_objclass* arg, etch_object* obj)
+{
+    vtabmask* vtab = NULL;
+    memset(arg, 0, sizeof(etch_objclass));
+    if (NULL == obj) return;
+
+    ((etch_objclass*)arg)->obj_type = obj->obj_type;
+    ((etch_objclass*)arg)->class_id = obj->class_id;
+    arg->parent   = obj->parent;
+
+    if (vtab = (vtabmask*) ((etch_object*)obj)->vtab)
+    {   
+        arg->vtable_class_id = ((etch_object*)vtab)->class_id;
+        arg->inherits_from   = vtab->inherits_from;
+    }   
+
+    switch(((etch_object*)obj)->obj_type)
+    {
+        case ETCHTYPEB_NATIVEARRAY:
+           arg->numdims          = ((etch_nativearray*)obj)->numdims;
+           arg->content_obj_type = ((etch_nativearray*)obj)->content_obj_type;
+           arg->content_class_id = ((etch_nativearray*)obj)->content_class_id;
+           break;
+        case ETCHTYPEB_ARRAYVAL:
+           arg->numdims          = ((etch_collection_mask*)obj)->n;
+           arg->content_obj_type = ((etch_collection_mask*)obj)->content_obj_type;
+           arg->content_class_id = ((etch_collection_mask*)obj)->content_class_id;
+           break;
+        case ETCHTYPEB_ARRAYLIST:
+           arg->numdims          = 1;
+           arg->content_obj_type = ((etch_collection_mask*)obj)->content_obj_type;
+           arg->content_class_id = ((etch_collection_mask*)obj)->content_class_id;
+    }
+}
+
+/**
+ * etchobj_is_assignable_from()
+ * determines if the class of thisobj is the same as, or is a superclass of,
+ * the class specified by that_class_id. tests whether the type represented 
+ * by that_obj_type and that_class_id can be converted to the type of thisobj 
+ * via an identity conversion or via a widening reference conversion. 
+ *
+ * @param target the class of left side of the assignment (to). 
+ * during validation, this is the class of object the validator expects
+ * to validate. if target object is an array, this is the array content class.
+
+ * @param source the class of right side of the assignment (from). 
+ * during validation, this is the class of the object being validated.
+ * if target object is an array, this is the array content class.
+ */
+int etchobj_is_assignable_from(etch_objclass* target, etch_objclass* source)  
+{
+    if (((etch_objclass*)source)->class_id == target->class_id && source->numdims == 0) 
+        return TRUE;  /* identity case */
+
+    /* if left side is Object wrapper (not Object[]), anything can be assigned 
+     * to it, since the c binding does not receive anything that is unwrapped.
+     * i.e. in java Object.class is not assignable from int.class; however here
+     * we don't have an int.class, only wrapped integers. if this were not the
+     * case this test would come after the etch primitives test, since a class
+     * not derived from object can't be assigned to object.
+     */
+    if (is_etch_object_type(((etch_objclass*)target)->obj_type, ((etch_objclass*)target)->class_id)) return TRUE;
+
+    if (((etch_objclass*)target)->obj_type == ETCHTYPEB_PRIMITIVE   
+     || ((etch_objclass*)source)->obj_type == ETCHTYPEB_PRIMITIVE) return FALSE;  
+
+    /* if left (target) side is an array, and right (source) side is an 
+     * array of the same dimensions, and either of the same content type,    
+     * or an array of Object, then it is assignable.
+     * this code is not robust - need to rethink assignability for default
+     * array validator with various validation object array types.
+     * currently we are validating very loosely for array types. we need
+     * a more general means of validating arrays, i.e. common attributes
+     * among array types (native, value, list)
+     */
+    if (is_etch_objarray_type   (((etch_objclass*)target)->obj_type, ((etch_objclass*)target)->class_id)
+     || is_etch_arraylist_type  (((etch_objclass*)target)->obj_type, ((etch_objclass*)target)->class_id) 
+     || is_etch_nativearray_type(((etch_objclass*)target)->obj_type, ((etch_objclass*)target)->class_id))
+    {   
+        if (target->numdims == source->numdims)
+        {
+           /* this line added to pass anything using default array validator */
+           if (target->content_obj_type == 0 && target->content_class_id == 0)
+               return TRUE;
+
+           if (target->content_class_id == CLASSID_UNWRAPPED)
+               return target->content_obj_type == source->content_obj_type;
+                 
+           if (target->content_class_id == CLASSID_OBJECT 
+            || target->content_class_id == source->content_class_id) 
+               return TRUE; 
+        }
+      
+        return FALSE;   
+    }
+    else /* if source inherits from target, source can be assigned to target */ 
+    if (source->parent)
+    {   /* inheritance model 2 - inherited objects are instantiated and chained */
+        etch_object* thisparent = source->parent;   
+
+        while(thisparent) /* walk source object's inheritance chain */
+        {
+            if (((etch_object*)thisparent)->class_id == target->class_id) return TRUE;
+            thisparent = thisparent->parent;
+        }
+    }
+    else
+    {   int ndx = 0;
+        etchparentinfo* parentinfo;
+        /* inheritance model 1 - inherited data flattened into single object */
+
+        while(1) /* iterate source object's inheritance list */
+        { 
+            if (NULL == (parentinfo = get_next_etch_parentex 
+                   (((etch_objclass*)source)->class_id, source->inherits_from, ndx++)))
+                break;
+
+            if (((etch_objclass*)parentinfo)->class_id == target->class_id)
+                return TRUE;
+        } 
+    } 
+
+    return FALSE;  
+}
+
+/**
+ * etchobj_is_assignable_from_ex()
+ * see comments for etchobj_is_assignable_from()
+ */
+int etchobj_is_assignable_fromobj(etch_object* targetobj, etch_object* sourceobj)
+{
+    etch_objclass targetarg, sourcearg;  
+    set_etch_assignable_arg_from(&targetarg, targetobj);
+    set_etch_assignable_arg_from(&sourcearg, sourceobj);
+    return etchobj_is_assignable_from(&targetarg, &sourcearg);
+}
+
+
+
+/**
+ * destroy_string()
+ */
+int destroy_string(void* data) 
+{
+    etch_string* thisp = data;
+    if (!is_etchobj_static_content(thisp))
+        etch_free(thisp->v.value);  /* OK if null */
+    destroy_objectex((etch_object*)thisp);
+    return 0;
+}
+
+/**
+ * default virtual copy constructor for etch object.   
+ */
+void* clone_object(void* thisx)
+{
+    etch_object* pthis = (etch_object*)thisx;
+    void* pnew = NULL; 
+    unsigned objsize = pthis->length;
+    if (objsize < sizeof(etch_object)) objsize = sizeof(etch_object);
+    
+    pnew = etch_malloc (objsize, ((etch_object*)pthis)->obj_type); 
+    memcpy(pnew, pthis, objsize);  
+
+    return pnew;  
+}
+
+/**
+ * default virtual copy constructor for objects requiring deep copy  
+ */
+void* clone_null(void* pthis)
+{
+    return NULL;
+}
+
+/**
+ * clone_string()
+ */
+void* clone_string(void* obj) 
+{
+  etch_string* thisp = (etch_string*)obj;
+    etch_string* newobj = (etch_string*) clone_object((etch_object*)thisp);
+
+    newobj->v.value = etch_malloc(thisp->byte_count, ETCHTYPEB_STRING);
+    memcpy(newobj->v.value, thisp->v.value, thisp->byte_count);
+    newobj->byte_count = thisp->byte_count;
+    newobj->char_count = thisp->char_count;
+
+    return newobj;
+}
+
+/**
+ *  new_etchresult()
+ *  generate etchobject result object
+ */
+etchresult* new_etchresult(const int result, const int reason)
+{
+    etchresult* newresult = etch_malloc(sizeof(etchresult), ETCHTYPEB_RESULT);
+    memset(newresult, 0, sizeof(etchresult));
+    newresult->resultcode = result;
+    newresult->reasoncode = reason;
+    return newresult;
+}
+
+/**
+ * defgethashkey
+ * default hashkey computation for an etch object
+ */
+uint32 defgethashkey(void* data)
+{
+    etch_object* obj = (etch_object*)data;
+    void* hashitem = obj; /* uses the object address as hash source */
+    if (NULL == hashitem) return 0;
+    if(obj->hashkey == 0){
+        obj->hashkey = etchhash((char*)&hashitem, sizeof(void*), 0);
+    }
+    return obj->hashkey;
+}
+
+/**
+ *  new_object()
+ *  basic object constructor 
+ *  sets type, class, size, default destructor, and copy constructor. 
+ */
+etch_object* new_object(const int objsize, const unsigned short obj_type, const unsigned short class_id)
+{
+    etch_object* newobj = 0;
+
+    newobj = etch_malloc(objsize, obj_type);
+
+    memset(newobj, 0, objsize);
+    ((etch_object*)newobj)->obj_type = obj_type;
+    ((etch_object*)newobj)->class_id = class_id;
+    newobj->length   = objsize;
+    newobj->destroy  = destroy_object; 
+    newobj->clone    = clone_object;
+    newobj->get_hashkey = defgethashkey;
+    //newobj->get_hashkey(newobj);  
+    return newobj;
+}
+
+/**
+ * short_type()
+ * return a 16-bit type code of 2 8-bit parts
+ */
+short short_type(unsigned i, unsigned j) 
+{ 
+    return (short) (  ( ((byte)i) << 16 ) | ((byte)j)  );
+} 
+
+
+
+/**
+ * verify_object()
+ * verify that the object passed is of the specified type and class.
+ * zero is a match for either so pass zero to not validate either.
+ */
+int verify_object(etch_object* obj, const unsigned short type, const unsigned short id, void** out)
+{
+    if (obj == NULL) return -1;
+    if (type != 0 && ((etch_object*)obj)->obj_type != type) return -1;
+    if (id   != 0 && ((etch_object*)obj)->class_id != id)   return -1;  
+    return 0; 
+}
+
+/**
+ * get_base_vtable()
+ * walks a vtable chain returning the final vtab in the chain
+ */
+void* get_base_vtable(etch_object* obj) 
+{
+    vtabmask* basevtab = ((etch_object*)obj)->vtab;
+    while (basevtab && ((etch_object*)basevtab)->vtab) 
+        basevtab = ((etch_object*)basevtab)->vtab;
+    return basevtab;
+}
+
+/**
+ * destroy_vtable()
+ */
+int destroy_vtable(void* data) 
+{
+  etch_object* vtab = (etch_object*)data;
+    etchparentinfo* inheritlist = ((vtabmask*)vtab)->inherits_from;
+
+    if (inheritlist && !is_etchobj_static_content(vtab)) 
+    {
+        free(inheritlist); /* vtables not tracked */
+        ((vtabmask*)vtab)->inherits_from = NULL;
+    }
+
+    if (!is_etchobj_static_shell(vtab))
+        free(vtab); /* vtables not tracked */
+
+    return 0;
+}
+
+/**
+ * get_class_cachekey()
+ * get the unique value used for keying the indicated class in a class cache.
+ */
+unsigned get_class_cachekey(unsigned short obj_type, unsigned short class_id)
+{
+    unsigned key = (obj_type << 16) | class_id;
+    return etchhash(&key, 4, 0);
+}
+
+/**
+ * get_vtable_cachehkey()
+ * calculates ad returns the *cache* key for specified vtable object
+ * the hashkey on the vtable object is not an object key, it is a class key,
+ * since vtables are cached by class.
+ */
+unsigned get_vtable_cachehkey(unsigned short class_id)
+{
+    return get_class_cachekey(ETCHTYPEB_VTABLE, class_id);
+}
+
+ /**
+ * get_vtabobj_hashkey()
+ * sets and gets the *cache* key for specified vtable object
+ * the hashkey on the vtable object is not an object key, it is a class key,
+ * since vtables are cached by class.
+ */
+uint32 get_vtabobj_hashkey(void* data)
+{
+  etch_object* vtabobj = (etch_object*)data;
+    return vtabobj->hashkey = get_vtable_cachehkey(((etch_object*)vtabobj)->class_id);
+}
+
+/**
+ * new_vtable()
+ * instantiate a new virtual function table of the specified type, 
+ * defaulting all methods to those of specified parent if requested
+ */
+void* new_vtable(const void* parentvtab, const size_t size, const short classid)
+{
+    etch_object* newvtab = etch_malloc(size, 0);  /* vtable memory is not tracked */
+
+    if(parentvtab)
+        memcpy(newvtab, parentvtab, size);
+    else
+        memset(newvtab, 0, size);
+   
+    ((etch_object*)newvtab)->obj_type = ETCHTYPEB_VTABLE;   
+    ((etch_object*)newvtab)->class_id = classid;
+    newvtab->length   = (unsigned) size;
+    newvtab->destroy  = destroy_vtable;
+    newvtab->clone    = clone_object;
+
+    newvtab->get_hashkey = get_vtabobj_hashkey;
+    //newvtab->get_hashkey(newvtab);
+
+    return newvtab;
+}
+
+
+/**
+ * get_vtab_inheritance_list()
+ * add an inheritance list to the specified object, or fetch existing list.
+ * an inheritance list exists in the vtable since we don't need to duplicate it
+ * for every instance. if there is no vtable in the specified object, a place-
+ * holder vtable is instantiated in the object. recall that vtables are freed
+ * when the global cache is cleared. the first entry in an inheritance list 
+ * contains the list attributes, therefore the list is one-based. 
+ * if an appropriately-sized list is already cached, the cached list is 
+ * returned. if a shorter list exists it is resized, copied, and returned. 
+ * @param size total number of entries to be allocated
+ * @param count number of populated entries 
+ */ 
+etchparentinfo* get_vtab_inheritance_list(etch_object* obj, const short size, const short count, const short vtabclass)
+{
+   etchparentinfo *oldlist = NULL, *newlist = NULL;
+
+   /* if such a list is already cached, return it now */
+   vtabmask* vtab = ((etch_object*)obj)->vtab? obj->vtab: etch_cache_find(get_vtable_cachehkey(vtabclass), 0); 
+   oldlist = vtab? vtab->inherits_from: NULL; 
+   
+   if (oldlist && oldlist->o.list_size >= size)
+   {
+       oldlist[0].c.list_count = count;
+       ((etch_object*)obj)->vtab = vtab;
+       return oldlist;
+   }
+
+   newlist = new_etch_inheritance_list(size, count, oldlist);
+   if(newlist == NULL) return NULL;
+      
+   /* note that we are creating a placeholder vtable here. we could not add
+    * virtuals to such a vtable, since this vtable consists of the vtable 
+    * header only, per sizeof(vtabmask), following.
+    */
+   if(vtab == NULL) {
+       vtab = new_vtable(NULL, sizeof(vtabmask), vtabclass);
+       vtab->inherits_from = newlist;
+       etch_cache_insert(((etch_object*)vtab)->get_hashkey(vtab), vtab, FALSE);
+       ((etch_object*)obj)->vtab = vtab;
+   }
+       
+   vtab->inherits_from = newlist;
+   return newlist;
+}
+
+
+/**
+ * new_etch_inheritance_list()
+ * allocate and return an inheritance list of the specified size
+ * @param size total number of entries to be allocated
+ * @param count number of populated entries 
+ */ 
+etchparentinfo* new_etch_inheritance_list(const short size, const short count, 
+   etchparentinfo* oldlist)
+{
+   etchparentinfo *newlist = NULL;
+   const int newbytes = size * sizeof(etchparentinfo), MAXPARENTS = 15;
+   if (count < 0 || count > MAXPARENTS || size < 0 || count > size) 
+       return NULL;
+  
+   newlist = etch_malloc(newbytes, 0);  /* vtables not tracked */
+   memset(newlist, 0, newbytes);
+
+   if (oldlist) /* we may be expanding an existing list, copy into new list */
+   {   const int oldbytes = oldlist->o.list_size * sizeof(etchparentinfo);
+       memcpy(newlist, oldlist, oldbytes);  
+//       free(oldlist); /* vtables not tracked */
+//       oldlist = NULL;
+   }
+   else newlist[0].c.list_count = count;
+
+   newlist[0].o.list_size = size;  /* list attributes are in first entry */     
+   return newlist;
+}
+
+
+/**
+ * is_derives_from_object()
+ * determine if specified object derives from object. 
+ * all etch_object-masked objects are etch c objects by definition; however it is
+ * here that we would artificially specify that certain wrapped objects are not
+ * derived from object in the logical etch sense, if such a need arises.
+ */ 
+int is_derives_from_object(etch_object* obj)
+{
+    return obj? is_derives_from_object_class(((etch_object*)obj)->class_id): FALSE;
+}
+
+
+/**
+ * is_derives_from_object_class()
+ * see comments at is_derives_from_object()
+ */ 
+int is_derives_from_object_class(const unsigned short class_id)
+{
+    return TRUE;
+}
+
+
+/**
+ * get_next_etch_parent()
+ * see comments at get_next_etch_parentex() below
+ */ 
+etchparentinfo* get_next_etch_parent(etch_object* obj, int current_index)
+{
+    etchparentinfo* inherit_list = obj && ((etch_object*)obj)->vtab? obj->vtab->inherits_from: NULL;
+    return get_next_etch_parentex(((etch_object*)obj)->class_id, inherit_list, current_index);
+}
+
+
+/**
+ * get_next_etch_parentex()
+ * returns a non-disposable reference to etchparentinfo struct containing the
+ * class of next parent in this object's inheritance hierarchy, relative to the
+ * specified index. if specified object does in fact inherit from other than
+ * object, its inheritance list must have been previously instantiated via
+ * get_vtab_inheritance_list(), above, and populated accordingly, presumably
+ * int the object's constructor. the inheritance list implicitly ends with 
+ * object, if the specified object's class derives from object; however object 
+ * does not explicitly appear in the list and in fact must not be so populated. 
+ * @param obj the etch object for which a parent is requested.
+ * @param current_index the index of the currently requested parent. on the
+ * first call specify zero, on subsequent calls increment current_index.
+ * @return etchparentinfo as described above, or NULL if no more parents.
+ * the returned reference is valid while its containing inheritance list remains
+ * instantiated, which ordinarily is while its associated vtable exists, which
+ * ordinarily is until service teardown.
+ */ 
+etchparentinfo* get_next_etch_parentex
+(const unsigned short class_id, etchparentinfo* inherit_list, int current_index)
+{
+  static etchparentinfo object_parent = { {ETCHTYPEB_ETCHOBJECT}, {CLASSID_OBJECT} };
+    etchparentinfo* nextparent  = NULL;
+
+    if  (NULL == inherit_list && current_index > 0);
+    else
+    if ((NULL == inherit_list) || (current_index == inherit_list[0].c.list_count))    
+         if  (is_derives_from_object_class(class_id))
+              nextparent = &object_parent;
+         else; 
+    else
+    if  (current_index < inherit_list[0].c.list_count) 
+         nextparent = &inherit_list[++current_index]; /* list is one-based */
+
+    return nextparent;
+}
+
+
+/**
+ * new_primitive()
+ * allocate, initialize and return a primitive object
+ */
+etch_object* new_primitive(const unsigned obj_len, const unsigned short class_id) 
+{
+    etch_object* newobj  = new_object(obj_len, ETCHTYPEB_PRIMITIVE, class_id);
+    newobj->destroy  = destroy_object;
+    newobj->clone    = clone_object;
+    newobj->get_hashkey = etch_number_get_hashkey;
+    return newobj;
+}
+
+
+/**
+ * new_wchar()
+ * wide character string clone
+ */
+wchar_t* new_wchar(const wchar_t* s)
+{   
+#ifdef WIN32
+    #pragma warning(disable:4996) /* wcscpy unsafe warning */
+#endif
+    unsigned bytelen;
+    wchar_t* clone; 
+    if (NULL == s) return NULL;
+    bytelen = (unsigned)(wcslen(s) + 1) * sizeof(wchar_t);
+    clone   = etch_malloc(bytelen, ETCHTYPEB_STRING);
+    wcscpy(clone, s);
+    return clone;
+}
+
+
+/**
+ * new_char()
+ * narrow character string clone
+ */
+char* new_char(const char* s)
+{   
+    char* clone; 
+    if (NULL == s) return NULL;
+    clone = etch_malloc(strlen(s) + 1, ETCHTYPEB_STRING);
+    return strcpy(clone, s);
+}
+
+
+/**
+ * new_byte()
+ */
+etch_byte* new_byte(const signed char v)
+{
+    etch_byte* newobj = (etch_byte*) new_primitive
+        (sizeof(struct etch_byte), CLASSID_PRIMITIVE_BYTE);
+    newobj->value = v;
+    //newobj->get_hashkey((etch_object*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_boolean()
+ */ 
+etch_boolean* new_boolean(boolean v) 
+{
+    etch_boolean* newobj = (etch_boolean*) new_primitive
+        (sizeof(struct etch_boolean), CLASSID_PRIMITIVE_BOOL);
+    newobj->value = v? TRUE: FALSE;
+    //newobj->get_hashkey((etch_object*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_int8()
+ */ 
+etch_int8* new_int8(signed char v) 
+{
+    etch_int8* newobj = (etch_int8*) new_primitive
+        (sizeof(struct etch_int8), CLASSID_PRIMITIVE_INT8);
+    newobj->value = v;
+    //newobj->get_hashkey((etch_object*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_int16()
+ */  
+etch_int16* new_int16(short v) 
+{
+    etch_int16* newobj = (etch_int16*) new_primitive
+        (sizeof(struct etch_int16), CLASSID_PRIMITIVE_INT16);
+    newobj->value = v;
+    //newobj->get_hashkey((etch_object*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_int32()
+ */
+etch_int32* new_int32(int v) 
+{
+    etch_int32* newobj = (etch_int32*) new_primitive
+            (sizeof(struct etch_int32), CLASSID_PRIMITIVE_INT32);
+    newobj->value = v;
+    //newobj->get_hashkey((etch_object*)newobj);
+    return newobj;
+}
+
+ 
+/**
+ * new_int64()
+ */
+etch_int64* new_int64(int64 v) 
+{
+    etch_int64* newobj = (etch_int64*) new_primitive
+            (sizeof(struct etch_int64), CLASSID_PRIMITIVE_INT64);
+    newobj->value = v;
+    //newobj->get_hashkey((etch_object*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_float()
+ */ 
+etch_float* new_float(float v) 
+{
+    etch_float* newobj = (etch_float*) new_primitive
+            (sizeof(struct etch_float), CLASSID_PRIMITIVE_FLOAT);
+    newobj->value = v;
+    //newobj->get_hashkey((etch_object*)newobj);
+    return newobj;
+}
+
+
+/**
+ * new_double()
+ */  
+etch_double* new_double(double v) 
+{
+    etch_double* newobj = (etch_double*) new_primitive
+            (sizeof(struct etch_double), CLASSID_PRIMITIVE_DOUBLE);
+    newobj->value = v;
+    //newobj->get_hashkey((etch_object*)newobj);
+    return newobj;
+}
+
+
+int32 etch_number_as_int32(const void* object) 
+{
+    if(is_etch_byte(object)){
+        return (int32)((etch_byte*)object)->value;
+    }else if(is_etch_int16(object)){
+        return (int32)((etch_int16*)object)->value;
+    }else if(is_etch_int32(object)){
+        return (int32)((etch_int32*)object)->value;
+    }
+    return 0;
+}
+
+/**
+ * etch_string_get_hashkey
+ * hashkey computation override for an etch_string.
+ * hash key is computed using the raw string as hash source.
+ */
+uint32 etch_string_get_hashkey(void* data)
+{
+    etch_object* etchobj = (etch_object*)data;
+
+    etch_string* sobj = (etch_string*) etchobj;
+    ((etch_object*)sobj)->hashkey = ETCH_ENCODING_ASCII != sobj->encoding?
+          etch_get_wchar_hashkey(sobj->v.valw):
+          etch_get_char_hashkey(sobj->v.valc);
+    return ((etch_object*)sobj)->hashkey;
+}
+
+static unsigned int utf8_string_length(const void* s) {
+  unsigned int res = 0;
+  const char* help = (const char*) s;
+  while (*help) {
+    if ((*help & 0xC0) != 0x80) {
+      ++res;
+    }
+    ++help;
+  }
+  return res;
+}
+
+static unsigned int ucs_string_length(const void* s, int width) {
+  unsigned int res = 0;
+
+  switch (width) {
+  case 1: {
+    const char* help = (const char*)s;
+    while (1) {
+      if (*help == 0) {
+	break;
+      }
+      ++help;
+      ++res;
+    }
+    break;
+  }
+  case 2: {
+    const int16* help = (const int16*)s;
+    while (1) {
+      if (*help == 0) {
+	break;
+      }
+      ++help;
+      ++res;
+    }
+    break;
+  }
+  case 4: {
+    const int32* help = (const int32*)s;
+    while (1) {
+      if (*help == 0) {
+	break;
+      }
+      ++help;
+      ++res;
+    }
+    break;
+  }
+  default:
+    ETCH_ASSERT(!"only widths of 2 and 4 supported");
+    break;
+  }
+
+  return res;
+}
+
+/**
+ * etch_string_init()
+ * private constructor for opaque string
+ */
+etch_string* etch_string_init(const void* s, const unsigned char encoding)
+{
+    etch_string* newobj = (etch_string*)new_primitive(sizeof(struct etch_string), CLASSID_STRING);
+
+    newobj->encoding = encoding;
+
+    if (s) {
+        switch(encoding) {
+        case ETCH_ENCODING_ASCII:
+	        newobj->char_count  = ucs_string_length(s, 1);
+	        newobj->byte_count  = (newobj->char_count + 1) * 1;
+	    break;
+        case ETCH_ENCODING_UCS2:
+	        newobj->char_count  = ucs_string_length(s, 2);
+	        newobj->byte_count  = (newobj->char_count + 1) * 2;
+	    break;
+        case ETCH_ENCODING_UCS4:
+	        newobj->char_count  = ucs_string_length(s, 4);
+	        newobj->byte_count  = (newobj->char_count + 1) * 4;
+	    break;
+        case ETCH_ENCODING_UTF8:
+	        newobj->char_count  = utf8_string_length(s);
+	        newobj->byte_count  = (unsigned int)(strlen(s) + 1);
+	    break;
+        default:
+	        newobj->char_count  = 0;
+	        newobj->byte_count  = 0;
+	        printf("encoding: %d\n", encoding);
+	        ETCH_ASSERT(!"encoding not supported");
+	    break;
+        }
+    } else {
+      newobj->char_count = 0;
+      newobj->byte_count = 0;
+      ((etch_object*)newobj)->is_null = TRUE;
+    }
+
+    ((etch_object*)newobj)->destroy = destroy_string;
+    ((etch_object*)newobj)->clone   = clone_string;
+
+    return newobj;
+}
+
+/**
+ * new_string()
+ * clones supplied string
+ * @param s a raw string to be assigned to the new string object.
+ * caller retains ownership of s.
+ */
+etch_string* new_string(const void* s, const unsigned char encoding)
+{
+    etch_string* newobj = etch_string_init(s, encoding);
+
+    if (s)
+    {
+      newobj->v.valc = etch_malloc(newobj->byte_count, ETCHTYPEB_STRING);
+      memcpy(newobj->v.valc, s, (size_t)newobj->byte_count);
+    }
+
+    ((etch_object*)newobj)->get_hashkey = etch_string_get_hashkey;
+    //newobj->get_hashkey((etch_object*)newobj);
+
+    return newobj;
+}
+
+
+/**
+ * new_stringw()
+ * convenience constructor for string type ETCH_ENCODING_UTF16;
+ * @param s a raw string to be assigned to the new string object.
+ * caller retains ownership of s.
+ */ 
+etch_string* new_stringw(const void* s) 
+{
+  switch (sizeof(wchar_t)) {
+  case 2:
+    return new_string(s, ETCH_ENCODING_UCS2);
+  case 4:
+    return new_string(s, ETCH_ENCODING_UCS4);
+  default:
+    ETCH_ASSERT(!"illegal sizeof(wchar_t)");
+    return 0;
+  }
+}
+ 
+
+/**
+ * new_stringa()
+ * convenience constructor for string type ETCH_ENCODING_UTF8);
+ * @param s a raw string to be assigned to the new string object.
+ * caller retains ownership of s.
+ */ 
+etch_string* new_stringa(const void* s) 
+{
+    return new_string(s, ETCH_ENCODING_UTF8);
+}
+
+
+/**
+ * new_string_from()
+ * does not clone supplied string
+ * @param s a disposable raw string to be assigned to the new string object.
+ * caller relinquishes ownership of s.
+ */ 
+etch_string* new_string_from(const void* s, const unsigned char encoding) 
+{
+    etch_string* newobj = etch_string_init(s, encoding);
+    newobj->v.value = (void*) s;
+    ((etch_object*)newobj)->get_hashkey = etch_string_get_hashkey;
+    return newobj;
+}
+
+
+/**
+ * new_etch_event()
+ */ 
+etch_event* new_etch_event(const unsigned short class_id, const int value) 
+{
+    etch_event* newobj = (etch_event*) new_int32(value);
+    if (class_id) ((etch_object*)newobj)->class_id = class_id; 
+    return newobj;
+}
+
+
+/**
+ * new_etch_query()
+ */ 
+etch_query* new_etch_query(const unsigned short class_id, const int value) 
+{
+    etch_query* newobj = (etch_query*) new_int32(value);
+    if (class_id) ((etch_object*)newobj)->class_id = class_id; 
+    return newobj;
+}
+
+
+/**
+ * new_etch_control()
+ */ 
+etch_control* new_etch_control(const unsigned short class_id, const int value) 
+{
+    etch_control* newobj = (etch_control*) new_int32(value);
+    if (class_id) ((etch_object*)newobj)->class_id = class_id; 
+    return newobj;
+}
+
+
+/**
+ * new_date()
+ */ 
+etch_date* new_date() 
+{
+    etch_date* newobj = (etch_date*) 
+        new_primitive(sizeof(struct etch_date), CLASSID_DATE);
+
+    time (&newobj->value);
+    newobj->ticks = clock();
+ 
+    return newobj;
+}
+
+
+/**
+ * new_who()
+ * a who is an etch_object wrapper around some etch object type, its purpose
+ * to be a disposable object which opaquely specifies the object which is the 
+ * sender or receiver component of a method. 
+ * @param whoobj the object which is the actual source or destination.
+ * if this object is a nondisposable refrerence, of course it must be assured
+ * that the object is not destroyed prior to destruction of the etch_who
+ * which references it. 
+ */ 
+etch_who* new_who(void* whoobj)
+{
+    etch_who* newobj = (etch_who*) new_object(sizeof(etch_who),ETCHTYPEB_ETCHOBJECT,CLASSID_WHO);
+    newobj->value = whoobj;
+    return newobj;
+}
+
+/**
+ * new_nullobj()
+ * instantiate and return a logically null object
+ */
+etch_object* new_nullobj()
+{
+   etch_object* obj = (etch_object*) new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT,CLASSID_NONE);
+   obj->is_null = TRUE;
+   return obj;
+}
+
+/**
+ * etch_get_char_hashkey
+ * hashkey computation using a narrow string as source
+ */
+unsigned etch_get_char_hashkey(const char* s)
+{
+    unsigned keybytelen = 0, hashkey = 0;
+    if (NULL != s) 
+        keybytelen = (unsigned) strlen(s);
+    if (keybytelen) 
+        hashkey = etchhash(s, keybytelen, 0);
+    return hashkey;
+}
+
+
+/**
+ * etch_get_wchar_hashkey
+ * hashkey computation using a unicode string as source
+ */
+unsigned etch_get_wchar_hashkey(const wchar_t* s)
+{
+    unsigned keybytelen = 0, hashkey = 0;
+    if (NULL != s) 
+        keybytelen = (unsigned) (wcslen(s) * sizeof(wchar_t));
+    if (keybytelen) 
+        hashkey = etchhash(s, keybytelen, 0);
+    return hashkey;
+}
+
+ 
+/**
+ * etch_number_get_hashkey
+ * hashkey computation override for an etch wrapped primitive number.
+ * hash key is computed using the numeric value as hash source.
+ */
+uint32 etch_number_get_hashkey(void* data)
+{
+    etch_object* etchobj = (etch_object*)data;
+    unsigned bytelength, hashkey;
+
+    switch(((etch_object*)etchobj)->class_id)
+    {   case CLASSID_PRIMITIVE_INT32: 
+            bytelength = 4;
+            hashkey = etchhash(&((etch_int32*)etchobj)->value, bytelength, 0);
+            break;
+        case CLASSID_PRIMITIVE_FLOAT:  
+            bytelength = 4;
+            hashkey = etchhash(&((etch_float*)etchobj)->value, bytelength, 0);
+            break;
+        case CLASSID_PRIMITIVE_INT64: 
+            bytelength = 8;
+            hashkey = etchhash(&((etch_int64*)etchobj)->value, bytelength, 0);
+            break;
+        case CLASSID_PRIMITIVE_DOUBLE: 
+            bytelength = 8;
+            hashkey = etchhash(&((etch_double*)etchobj)->value, bytelength, 0);
+            break;
+        case CLASSID_DATE: 
+            bytelength = 8;
+            hashkey = etchhash(&((etch_date*)etchobj)->value, bytelength, 0);
+            break;
+        case CLASSID_PRIMITIVE_INT16: 
+            bytelength = 2; 
+            hashkey = etchhash(&((etch_int16*)etchobj)->value, bytelength, 0);
+            break;
+        default: 
+            bytelength = 1;     
+            hashkey = etchhash(&((etch_int8*)etchobj)->value, bytelength, 0);
+            break;
+    } 
+    
+    return etchobj->hashkey = hashkey;
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_object_types.c b/binding-c/runtime/c/src/main/common/etch_object_types.c
new file mode 100644
index 0000000..76959dd
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_object_types.c
@@ -0,0 +1,40 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/* 
+ * etch_object_types.h -- constants for internal object types.
+ */
+
+#include "etch.h"
+#include "etch_objecttypes.h"
+
+static const char* objtype_b_names[] = {
+    "ETCHTYPEB_UNDEFINED",  // 0x00 also "ETCHTYPEB_NONE"
+    "ETCHTYPEB_BYTE",       // 0x01
+    "ETCHTYPEB_BOOL",       // 0x02
+    "ETCHTYPEB_INT8",       // 0x03
+    "ETCHTYPEB_INT16",      // 0x04
+    "ETCHTYPEB_INT32",      // 0x05
+    "ETCHTYPEB_INT64",      // 0x06
+    "ETCHTYPEB_IEEE32",     // 0x07
+};
+
+const char* etch_object_type_get_name(objtype_b type)
+{
+    return objtype_b_names[type];
+}
\ No newline at end of file
diff --git a/binding-c/runtime/c/src/main/common/etch_runtime.c b/binding-c/runtime/c/src/main/common/etch_runtime.c
new file mode 100644
index 0000000..1628ba3
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_runtime.c
@@ -0,0 +1,281 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_runtime.h -- runtime methods.
+ */
+
+#include "etch_runtime.h"
+#include "etch_cache.h"
+#include "etch_default_value_factory.h"
+#include "etch_mem.h"
+#include "etch_mutex.h"
+#include "etchinternal_single_linked_list.h"
+#include "apr_pools.h"
+#include "apr_thread_mutex.h"
+#include "etch_encoding.h"
+
+#define MAX_SHUTDOWN_HOOKS_SIZE 5
+
+// global data
+apr_pool_t*         g_etch_main_pool       = NULL;
+apr_thread_mutex_t* g_etch_main_pool_mutex = NULL;
+
+static etch_runtime_shutdown_hook_func shutdown_hooks[5] = 
+    {NULL,NULL,NULL,NULL,NULL};
+
+static uint16 etch_runtime_version_major    = 1;
+static uint16 etch_runtime_version_minor    = 1;
+static uint16 etch_runtime_version_revision = 2;
+
+//TODO
+etch_global_constants etchgc;
+
+/**
+ * etch_instantiate_global_constants()
+ * instantiate global constants. these are constants which can't be statically intialized.
+ * some of these may need to be freed in etch_free_global_constants in order that tests
+ * can show all memory freed. any etch objects instantiated here may need to have their  
+ * is_static marker set in order that they remain instantiated throughout execution.
+ */
+void etch_instantiate_global_constants()
+{
+    etchgc.etch_charsetname_us_ascii = L"us-ascii";
+    etchgc.etch_charsetname_utf8     = L"utf-8";
+    etchgc.etch_charsetname_utf16    = L"utf-16";
+    etchgc.pctd = "%d";
+}
+
+/* runtime data */
+struct etch_runtime_t
+{
+    uint32          count;          /* ref counting value */
+    unsigned char   state;          /* state or runtime*/
+    etch_config_t*  config;
+    unsigned char   config_owned;
+    etch_log_t*     logger;
+};
+
+/* init runtime data */
+static struct etch_runtime_t etch_runtime = {
+    0,
+    0,
+    NULL,
+    0,
+    NULL
+};
+
+static etch_status_t etch_statics_create()
+{
+    etch_instantiate_global_constants();
+
+    return ETCH_SUCCESS;
+}
+
+int etch_runtime_mem_abort(int retcode)
+{
+   printf("*** APR MEMORY ERROR! Code=%d***\n", retcode);
+   // sleep 1 s
+   apr_sleep(1000 * 1000);
+   return APR_SUCCESS;
+}
+
+etch_status_t etch_runtime_initialize(etch_config_t* config)
+{
+    etch_status_t  etch_status  = ETCH_SUCCESS;
+    apr_status_t   apr_status   = APR_SUCCESS;
+
+    if(etch_runtime.count++ > 0) {
+        return ETCH_SUCCESS;
+    }
+
+    if(etch_runtime.state == 0) {
+        // initialize apr
+        apr_status = apr_initialize();
+        if(apr_status != APR_SUCCESS) {
+            // log error
+            return -1;
+        }
+        // create apr memory pool
+        
+        apr_status = apr_pool_create(&g_etch_main_pool, NULL);
+        //printf("1 creating apr pool %p\n",g_etch_main_pool);
+        if(apr_status != APR_SUCCESS) {
+            // log error
+            // shutdown apr
+            apr_terminate();
+            return ETCH_ERROR;
+        }
+        /* set pool abort function */
+        apr_pool_abort_set(etch_runtime_mem_abort, g_etch_main_pool);
+        /* set apr pool tag */
+        apr_pool_tag(g_etch_main_pool, "etch_apr_pool");
+
+        apr_status = apr_thread_mutex_create(&g_etch_main_pool_mutex, APR_THREAD_MUTEX_NESTED, g_etch_main_pool);
+        if(apr_status != APR_SUCCESS) {
+            // log error
+            // shutdown apr
+            apr_terminate();
+            return ETCH_ERROR;
+        }
+
+        etch_status = etch_encoding_initialize();
+        if(etch_status != ETCH_SUCCESS) {
+            apr_terminate();
+            return ETCH_ERROR;
+        }
+
+        // set configuration
+        if(config == NULL) {
+            etch_status = etch_config_create(&config);
+            if(etch_status != ETCH_SUCCESS) {
+                // error
+            }
+            etch_runtime.config_owned = 1;
+        }
+        etch_runtime.config = config;
+
+        // create logger
+        etch_status = etch_log_create(&etch_runtime.logger, etch_runtime.config);
+        if(etch_status != ETCH_SUCCESS) {
+            // error opening logger
+        }
+
+        // create etch cache
+        etch_status = etch_cache_create();
+        if(etch_status != ETCH_SUCCESS) {
+            // error opening logger
+        }
+
+        // create etch statics
+        etch_status = etch_statics_create();
+        if(etch_status != ETCH_SUCCESS) {
+            // error opening logger
+        }
+
+        // set initialized flag
+        etch_runtime.state = 1;
+    }
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_runtime_get_version(uint16* major, uint16* minor, uint16* revision)
+{
+    etch_status_t rv = ETCH_SUCCESS;
+
+    if(major == NULL || minor == NULL || revision == NULL) {
+        return ETCH_EINVAL;
+    }
+    *major    = etch_runtime_version_major;
+    *minor    = etch_runtime_version_minor;
+    *revision = etch_runtime_version_revision;
+    return rv;
+}
+
+etch_status_t etch_runtime_get_config(etch_config_t** config)
+{
+    if(config == NULL) {
+        return ETCH_EINVAL;
+    }
+    *config = etch_runtime.config;
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_runtime_get_logger(etch_log_t** logger)
+{
+    if(logger == NULL) {
+        return ETCH_EINVAL;
+    }
+    *logger = etch_runtime.logger;
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_runtime_shutdown()
+{
+    int i = 0;
+    etch_status_t etch_status;
+
+    if(etch_runtime.count > 0) {
+        if(etch_runtime.count-- > 1) {
+            return ETCH_SUCCESS;
+        }
+    }
+
+    if(etch_runtime.state == 1) {
+        
+        // destroy etch statics
+        for(; i < MAX_SHUTDOWN_HOOKS_SIZE; i++) {
+            if(shutdown_hooks[i]){
+                shutdown_hooks[i]();
+            }
+        }
+
+        etchvf_free_builtins();
+        
+        // destroy cache
+        etch_cache_destroy();
+        // destroy logger
+        if(etch_runtime.logger != NULL) {
+            etch_log_destroy(etch_runtime.logger);
+            etch_runtime.logger = NULL;
+        }
+        // destroy config
+        if(etch_runtime.config_owned) {
+            etch_config_destroy(etch_runtime.config);
+            etch_runtime.config       = NULL;
+            etch_runtime.config_owned = 0;
+        }
+
+        etch_status = etch_encoding_shutdown();
+        if(etch_status != ETCH_SUCCESS) {
+            apr_terminate();
+            return ETCH_ERROR;
+        }
+
+        /* destroy apr memory pool mutex */
+        apr_thread_mutex_destroy(g_etch_main_pool_mutex);
+
+        
+        /* destroy apr memory pool */
+        //printf("1 destroying apr pool %p\n",g_etch_main_pool);
+        apr_pool_destroy(g_etch_main_pool);
+        
+
+        g_etch_main_pool = NULL;
+
+        /* terminate apr */
+        apr_terminate();
+        /* set shutdown flag */
+        etch_runtime.state = 0;
+    }
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_runtime_shutdown_hook_add(etch_runtime_shutdown_hook_func func)
+{
+    int i = 0;
+    for(; i < MAX_SHUTDOWN_HOOKS_SIZE; i++)
+    {
+        if(shutdown_hooks[i] == NULL)
+        {
+            shutdown_hooks[i] = func;
+            return ETCH_SUCCESS;
+        }
+    }
+    return ETCH_ERROR;
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_thread.c b/binding-c/runtime/c/src/main/common/etch_thread.c
new file mode 100644
index 0000000..ec9fb26
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_thread.c
@@ -0,0 +1,932 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etchthread.c
+ * threads, thread pool
+ */
+#include "etch_thread.h"
+#include "etch_log.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+
+const char* LOG_CATEGORY =  "etch_thread";
+
+extern apr_pool_t*         g_etch_main_pool;
+extern apr_thread_mutex_t* g_etch_main_pool_mutex;
+
+// TODO: refactoring this stuff
+
+etch_threadpool* global_free_threadpool;
+
+size_t etch_get_threadid(void* threadstruct);
+int default_on_threadstart(void* param);
+int default_on_threadexit (void* param);
+int destroy_thread   (void*);
+int etch_thread_start(void*);
+int etch_thread_stop(void*);
+int destroy_threadparams(etch_thread*);
+etch_mutex* loglock; // remove ??
+
+unsigned short etch_threadpool_id_farm;
+unsigned thread_id_farm;
+etch_mutex* loglock; // remove ??
+
+#ifdef APR_POOL_DEBUG
+APR_DECLARE(apr_size_t) apr_pool_num_bytes(apr_pool_t *p, int recurse);
+#endif
+
+typedef struct os_thread_and_etch_thread {
+  apr_os_thread_t* os_thread;
+  etch_thread* etch_thread;
+} os_thread_and_etch_thread;
+
+int etch_thread_find_by_os_thread(void* data, void* to_find) {
+  apr_os_thread_t* os_thread_to_find = (apr_os_thread_t*)to_find;
+  os_thread_and_etch_thread* both = (os_thread_and_etch_thread*)data;
+
+  return both->os_thread == os_thread_to_find;
+}
+
+/**
+ * etch_apr_threadproc()
+ * internal thread proc. this is a wrapper around the user thread proc.
+ * @param data expected to point at an etch_thread_params, which contains the
+ * thread start amd stop handlers, and the real threadproc and threadproc data.
+ */
+static void* APR_THREAD_FUNC etch_apr_threadproc(apr_thread_t *thread, void *data)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_thread_params* params = (etch_thread_params*) data;
+    etch_thread_callback on_exit;   
+    etch_thread* threadobj;
+    if(!params) return (void*)(-1);
+    on_exit   = params->on_exit;
+    threadobj = params->etchobj;
+
+    if (threadobj && threadobj->waiter)  /* wait for signal to start */
+      {
+        status = etch_wait_wait(threadobj->waiter, 1);
+        if(status != ETCH_SUCCESS) {
+            // erro
+        }
+
+        /* fyi we can't destroy the waiter here since etchwait_signal  
+         * holds etchwait.mutex and will try to release it.  
+         * destroy_etchwait (threadobj->waiter);  no!  
+         * threadobj->waiter = NULL;  
+         */              
+    }
+
+    params->threadstate = ETCH_THREADSTATE_STARTED;
+
+    if (params->on_start)    /* call threadproc start hook */
+        params->on_start(threadobj);
+
+    if (params->threadproc)  /* run user threadproc */
+        params->threadproc(params);
+
+    params->threadstate = ETCH_THREADSTATE_STOPPED;
+
+
+    if (on_exit)             /* call threadproc exit hook */
+        on_exit(threadobj);    
+
+    apr_thread_exit(thread, APR_SUCCESS);
+
+    return 0;
+}
+
+
+/**
+ * new_thread()
+ * etch_thread constructor
+ */
+etch_thread* new_thread (etch_threadproc proc, void* tdata)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_thread_params* tp  = NULL;
+    apr_pool_t* newsubpool = NULL;
+    etch_thread* newthread = NULL;
+    /* size_t poolsize = apr_pool_num_bytes(get_etch_aprpool(), FALSE); */  
+
+    newthread = (etch_thread*) new_object
+        (sizeof(etch_thread), ETCHTYPEB_THREAD, CLASSID_THREAD);
+
+    ((etch_object*)newthread)->destroy = destroy_thread;
+    ((etch_object*)newthread)->clone   = clone_null;
+
+    tp = &newthread->params;
+    etch_init_threadparams(tp);
+    tp->etchobj  = newthread;
+    tp->libdata  = &newthread->aprdata;
+    tp->on_start = default_on_threadstart;
+    tp->on_exit  = default_on_threadexit;
+    tp->etch_thread_id = next_etch_threadid();
+    tp->threadproc = proc;
+    tp->data = tdata;
+
+    newthread->start = etch_thread_start;
+    newthread->stop  = etch_thread_stop; 
+
+    // TODO: pool
+    status = etch_wait_create(&newthread->waiter, NULL);
+    if(status != ETCH_SUCCESS) {
+        // error log it
+    }
+    newthread->startCond  = 0;
+
+    //newthread->waiter->cond_var = &newthread->startCond;
+
+	if (0 != etch_createthread(tp)) 
+	{
+        etch_wait_destroy(newthread->waiter);
+		etch_free(newthread);
+        newthread = NULL;
+        //printf("2 destroying apr pool %p\n",newsubpool);
+        apr_pool_destroy(newsubpool);
+        
+    } 
+
+    return newthread;
+} 
+
+
+/**
+ * etch_createthread()
+ * to invoke: 1) initalize an etch_apr_threaddata with the mempool; 
+ * 2) initialize an etch_thread_params with threadproc plus the etch_apr_threaddata,
+ *    plus the thread user data.
+ * 2) call with the threaddata, and the userdata.
+ */
+int etch_createthread(etch_thread_params* params)
+{
+    int result = 0;
+    apr_status_t aprstatus;
+
+    if (!params->on_start) params->on_start = default_on_threadstart;
+    if (!params->on_exit)  params->on_exit  = default_on_threadexit;
+
+    /* fyi: this sets thread.aprdata.threadattr */
+    // TODO: pool
+    apr_thread_mutex_lock(g_etch_main_pool_mutex);
+    result = (APR_SUCCESS == apr_threadattr_create(&params->libdata->threadattr, g_etch_main_pool))? 0: -1;
+    apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+    if (result == 0) {
+        // TODO: pool
+        apr_thread_mutex_lock(g_etch_main_pool_mutex);
+        aprstatus = apr_thread_create(&params->libdata->thread, params->libdata->threadattr, etch_apr_threadproc, params, g_etch_main_pool);
+        apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+        if (aprstatus != APR_SUCCESS) {
+            char buffer[512];
+            apr_strerror(aprstatus, buffer, 512);
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "thread create error error-code: %d error-msg: %s\n", aprstatus, buffer);
+        }
+    }
+    return result;
+}
+
+int find_etch_thread_by_os_thread(void* listentry, void* apr_os_thread)
+{
+    os_thread_and_etch_thread* pair = (os_thread_and_etch_thread*) listentry;
+    return pair->os_thread == apr_os_thread;
+}   
+
+/**
+ * destroy_thread()
+ * etch_thread destructor
+ */
+int destroy_thread(void* data)
+{
+    etch_thread* threadx = (etch_thread*)data;
+    
+
+    if (!is_etchobj_static_content(threadx))
+    {
+        if (threadx->waiter) {
+            etch_wait_destroy(threadx->waiter);
+        }
+    }
+
+    return destroy_objectex((etch_object*)threadx);   
+}
+
+
+/**
+ * destroy_threadparams()
+ * free memory for any heap parameters passed to an etch_thread.
+ */
+int destroy_threadparams(etch_thread* thisx)
+{
+    etch_thread_params* params = &thisx->params;
+    void* userdata = params->data;
+
+    if (params->waitobj)
+        etch_wait_destroy(params->waitobj);
+
+    if (params->is_own_data)
+        if (params->is_data_etchobject)
+           ((etch_object*)userdata)->destroy(userdata);
+        else etch_free(userdata);
+
+    return 0;
+}
+
+
+/**
+ * etch_init_threadparams()
+ */
+void etch_init_threadparams(etch_thread_params* p)
+{
+    if (NULL == p) return;
+    memset(p, 0, sizeof(etch_thread_params));
+    p->signature = ETCH_THREAD_PARAMS_SIGNATURE;
+}
+
+
+/**
+ * etch_thread_start()
+ * default thread start method for etch_threads which wait for a start signal
+ */
+int etch_thread_start(void* data)
+{
+  etch_thread* threadx = (etch_thread*)data;
+    etch_status_t status = ETCH_SUCCESS;
+    int result = -1;
+    const int thread_id = threadx->params.etch_thread_id;
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "thread %d starting ...\n", thread_id); 
+
+    if (threadx->waiter) {
+        status = etch_wait_set(threadx->waiter, 1);
+        // log error
+    }
+
+    /* etch_tcpsvr_acceptproc: while(lxr->is_started) was not seeing the started 
+     * flag set, because the thread had not received control after the above signal.
+     * so this sleep forces it to run, the visual indication of the accept thread 
+     * running being the "accepting ..." log message. TODO lose the sleep().
+     * NOTE that by the time this thread regains control, its connection may
+     * have been closed, or the started thread may possibly even have exited. 
+     */
+    etch_sleep(30);  /* see comments above */
+
+    /* there is currently no pressing need to log this info, 
+     * and since it may indeed be stale, we'll not present it for now. */
+    #if(0) 
+    threadstate = is_etch_thread(threadx)? 
+        threadx->params.threadstate: ETCH_THREADSTATE_DEFUNCT;
+
+    switch(threadstate)
+    {   case ETCH_THREADSTATE_STARTED:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "thread %d started\n", thread_id); 
+             break;
+        case ETCH_THREADSTATE_STOPPED:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "thread %d stopped\n", thread_id); 
+             break;
+        case ETCH_THREADSTATE_DEFUNCT:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "thread %d was started now destroyed\n", thread_id); 
+             break;
+        default: ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "thread %d state %d\n", thread_id, threadstate);
+    }
+    #endif
+
+    return result;
+}
+
+
+/**
+ * etch_thread_stop()
+ * default etch_thread thread stop method.
+ * currently never invoked. causes serious grief.
+ */
+int etch_thread_stop(void* data)
+{
+    etch_thread* thread = (etch_thread*)data;
+    apr_status_t tresult = 0;   
+    etch_thread_params* p = thread? &thread->params: NULL;
+    if (NULL == p) return -1;
+
+    tresult = apr_thread_detach(p->libdata->thread);
+
+    tresult = apr_thread_exit(p->libdata->thread, 0);
+
+    return APR_SUCCESS == tresult? 0: -1;
+}
+
+int etch_thread_current_id()
+{
+#if defined(WIN32)
+    return GetCurrentThreadId();
+#elif defined(__QNX__) || defined(__LINUX__) || defined(__APPLE__)
+    #warning  not implemented for this os
+    return 0;
+#else
+    #error OS no support
+#endif
+
+    //int tid = -1;
+    //void* p = NULL;
+    //apr_os_thread_t thread_t = apr_os_thread_current();
+    //apr_os_threadkey_t threadkey_t;
+    //apr_os_threadkey_get(&threadkey_t, );
+    //p = thread_t;
+    ////tid = p;
+    //printf("%p", p);
+    //tid = *(int*)p;
+    
+    return 0;
+}
+
+/**
+ * etch_threadpool_run_freethread()
+ * instantiate and possibly run a free thread.
+ */
+etch_thread* etch_threadpool_run_freethread (etch_threadpool* pool, 
+    etch_threadproc threadproc, void* threaddata)
+{
+    etch_thread* newthread = NULL;
+    if (!pool || pool->is_defunct) return NULL;
+
+    /* create thread in a wait state. it may be started below. */
+    if (NULL == (newthread = new_thread (threadproc, threaddata)))
+        return NULL;
+
+	newthread->params.etchpool = pool;
+    newthread->params.is_own_data = pool->is_free_data;
+    newthread->params.is_data_etchobject = pool->is_data_etchobject;
+
+    etch_arraylist_add(pool->threadlist, newthread);  
+    /* an etch_thread object in the threadpool gets freed when a thread exits, 
+     * finds its threadpool, and removes itself from that pool's threadlist. 
+     */
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "thread %d created on pool %d\n", 
+        newthread->params.etch_thread_id, pool->threadpool_id); 
+
+    if (!pool->is_manual_start) /* start thread unless requested otherwise */
+        newthread->start(newthread);  
+
+    return newthread;
+}
+
+
+/**
+ * etch_threadpool_run_poolthread()
+ * run a thread from a queued pool.
+ */
+etch_thread* etch_threadpool_run_poolthread (etch_threadpool* pool, 
+    etch_threadproc threadproc, void* threaddata)
+{
+    if (!pool || pool->is_defunct) return NULL;
+    return NULL; /* we have not yet implemented or integrated a queued thread pool */
+}
+
+
+/**
+ * thread_cancel()
+ * cancel a running thread
+ */
+int etch_thread_cancel(etch_thread* thread)
+{
+    thread->params.threadstate = ETCH_THREADSTATE_STOPPING;
+    etch_join(thread);
+    return 0;
+}
+
+
+/**
+ * etch_join()
+ * block until specified thread exits
+ */
+int etch_join(etch_thread* thread)
+{
+   int  result = 0;
+   etch_thread_params* tp = &thread->params;
+   apr_status_t tresult = 0;   /* result returned from dead thread */
+   thread->is_joined = TRUE;  /* mark to avoid on_exit destruction */
+   result = apr_thread_join (&tresult, tp->libdata->thread); 
+   return result;
+}
+
+
+/**
+ * etch_thread_join()
+ * block until specified thread exits
+ */
+int etch_thread_join(etch_thread_params* params)
+{
+   apr_status_t tresult = 0;  /* result returned from dead thread */
+   const int result = apr_thread_join(&tresult, params->libdata->thread); 
+   return result;
+}
+
+
+/**
+ * etch_thread_yield()
+ */
+void etch_thread_yield()
+{
+   apr_thread_yield();
+}
+
+
+/**
+ * etch_thread_arraylist_comparator()
+ * arraylist comparator function to compare a specified thread ID 
+ * with the ID of a specified etch_thread
+ */
+int etch_thread_arraylist_comparator (void* id, void* etchobj)
+{
+    const int this_id = (int) (size_t) id;
+    const int that_id = ((etch_thread*) etchobj)->params.etch_thread_id;
+    return this_id < that_id? -1: this_id > that_id? 1: 0;
+}
+
+
+/**
+ * threadpool_removeentry()
+ * remove a thread from a thread pool, not destroying the etch_thread content.
+ * @return the removed etch_thread object.
+ */
+etch_thread* threadpool_remove_entry (etch_threadpool* pool, const int etch_thread_id)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int result = -1, i = 0;
+    etch_thread* outthread = NULL;
+    ETCH_ASSERT(is_etch_threadpool(pool));
+    if (pool->is_defunct) return NULL;
+
+    status = etch_mutex_lock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+
+    i = etch_arraylist_indexof (pool->threadlist, (void*) (size_t) etch_thread_id,   
+         0, etch_thread_arraylist_comparator);
+
+    if (i >= 0)  
+    {   outthread = etch_arraylist_get (pool->threadlist, i);
+        result = etch_arraylist_remove (pool->threadlist, i, FALSE); 
+    }
+
+    status = etch_mutex_unlock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+
+    return 0 == result? outthread: NULL;
+}
+
+
+/**
+ * threadpool_remove()
+ * remove a thread from a thread pool, destroying the etch_thread object.
+ * this should not be invoked by thread pool destructor, since is_defunct is then true.
+ */
+int threadpool_remove(etch_threadpool* pool, const int etch_thread_id)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int result = 0;
+    ETCH_ASSERT(is_etch_threadpool(pool));
+    if (pool->is_defunct) return -1;
+
+    status = etch_mutex_lock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+
+    result = etch_arraylist_remove_content (pool->threadlist, 
+        (void*) (size_t) etch_thread_id, 0, etch_thread_arraylist_comparator); 
+
+    status = etch_mutex_unlock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+
+    return result;
+}
+
+
+/**
+ * threadpool_waitfor_all()
+ * block until all threads in the pool exit.
+ * @param is_cancel if true, signal the thread to exit asap, 
+ * otherwise wait for normal thread exit.
+ */
+int threadpool_waitfor_all(etch_threadpool* pool, const int is_cancel)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_iterator iterator;
+    etch_arraylist* listcopy = NULL;
+    int  threadcount = 0, is_iterable = 0;
+    if (NULL == pool) return -1;
+
+    status = etch_mutex_lock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+    if ((threadcount = pool->count(pool)) > 0 && !pool->is_iterating)
+        pool->is_iterating = is_iterable = TRUE;
+    status = etch_mutex_unlock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+
+    if (threadcount == 0) return 0;  /* no active threads to wait for */
+    if (!is_iterable) return -1;    /* another thread is iterating this pool */
+    
+    /* iterate a copy since canceled threads remove themselves from their pool */
+    /* note that iterating the actual pool may however be preferable if the
+     * locking is done right, since if a thread ahead of the index exits 
+     * during this iteration, it would presumably then not show up here. */
+    status = etch_mutex_lock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+    listcopy = new_etch_arraylist_from(pool->threadlist);
+    status = etch_mutex_unlock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+    listcopy->is_readonly = TRUE; /* so destructor will not free copied content */
+    set_iterator(&iterator, listcopy, &listcopy->iterable);
+
+    /* note that if pool.is_defunct is true, exiting threads which belong to  
+     * that pool will not remove themselves from the pool and self-destruct. 
+     * so, if is_defunct is true, threads exiting while we are iterating here 
+     * will not be destroyed. the threadpool destructor destroy_threadpool() 
+     * sets is_defunct. however if threadpool_waitforall() is invoked elsewhere,
+     * care must be taken to ensure that pool threads do not exit while we
+     * are iterating them here. */
+
+    while(iterator.has_next(&iterator))  /* wait for each pool thread to exit */
+    {
+        etch_thread* thisthread = (etch_thread*) iterator.current_value;
+        etch_thread* removedthread = NULL;
+
+        if (thisthread) 
+        {   const int thread_id = thisthread->params.etch_thread_id;
+            char x[60];
+            apr_snprintf(x, sizeof(x), "thread %d in pool %d", thread_id, pool->threadpool_id);
+          
+            if  (is_cancel)
+            {    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "canceling %s ...\n", x); 
+                 etch_thread_cancel (thisthread); /* BLOCK here */
+            }
+            else
+            {    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "joining %s ...\n", x);
+                 etch_join (thisthread);          /* BLOCK here */
+            }
+
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s ended\n", x);
+            
+            status = etch_mutex_lock(pool->pool_lock);
+            if(status != ETCH_SUCCESS) {
+                // error
+            }
+            if (pool->pooltype == ETCH_THREADPOOLTYPE_FREE)
+            {   removedthread = threadpool_remove_entry (pool, thread_id);  
+                etch_object_destroy (thisthread);   
+            }
+            status = etch_mutex_unlock(pool->pool_lock);
+            if(status != ETCH_SUCCESS) {
+                // error
+            }
+        }
+         
+        iterator.next(&iterator);
+    } 
+
+    pool->is_iterating = FALSE;
+    etch_object_destroy(listcopy); /* readonly set above so no content destroyed */
+    return 0;
+}
+
+
+/**
+ * destroy_threadpool()
+ * etch_threadpool destructor.
+ * @todo add logic for queued pool, or create separate destructor.
+ */
+int destroy_threadpool(void* data)
+{
+    etch_threadpool* pool = (etch_threadpool*)data;
+    etch_status_t status = ETCH_SUCCESS;
+    int can_destroy = TRUE;
+    if (NULL == pool) return 0;
+
+    status = etch_mutex_lock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+    if  (pool->is_defunct)  /* ensure no race */
+         can_destroy = FALSE;
+    else pool->is_defunct = TRUE; 
+    status = etch_mutex_unlock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+    if (!can_destroy) return -1;
+
+    threadpool_waitfor_all (pool, TRUE);  /* BLOCK until all threads exited */
+
+    /* destroy the threadlist, destroying the etch_thread content in the process.
+     * note that each thread's parameter list was destroyed as the thread exited. 
+     * threadlist owns the mutex assigned to it and will destroy threadlist_lock.
+     */
+    if (!is_etchobj_static_content(pool))
+    {
+        etch_object_destroy(pool->threadlist);
+        status = etch_mutex_destroy(pool->pool_lock);
+        if(status != ETCH_SUCCESS) {
+            // error
+        }
+    }
+
+    return destroy_objectex((etch_object*)pool);
+} 
+
+
+/**
+ * threadpool_count()
+ * return count of threads in list 
+ */
+int threadpool_count(etch_threadpool* pool)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int count = 0;
+    ETCH_ASSERT(pool);
+    status = etch_mutex_lock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+    count = pool->threadlist? pool->threadlist->count: 0;
+    status = etch_mutex_unlock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+    return count;
+}
+
+
+/**
+ * threadpool_thread()
+ * return thread[i] from specified threadpool.
+ * @param i the index.
+ * @return the etch_thread*, or null if no thread at that index.
+ */
+etch_thread* threadpool_thread(etch_threadpool* pool, const int i)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_thread* thisthread = NULL;
+    if (NULL == pool)  return NULL;
+
+    status = etch_mutex_lock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+    thisthread = i < pool->count(pool)? pool->threadlist->base[i]: NULL;
+    status = etch_mutex_unlock(pool->pool_lock);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+    return thisthread;
+}
+
+
+/**
+ * new_threadpool_list()
+ * return an arraylist configured appropriately for a thread pool. 
+ */
+etch_arraylist* new_threadpool_list(const int initsize, etch_mutex* mutex)
+{
+    //TODO: Check if arraylist has to be synchronized
+    etch_arraylist* list = new_etch_arraylist(initsize,0);
+    /* ETCHARRAYLIST_CONTENT_OBJECT lets list call destroy() on its content */
+    list->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
+    list->is_readonly  = TRUE; /* list does not own content */
+    ((etch_object*)list)->synclock = mutex;    /* list owns this mutex */
+    return list;
+} 
+   
+
+/**
+ * new_threadpool()
+ * etch_threadpool constructor
+ * @param pooltype ETCH_THREADPOOLTYPE_FREE (default); ETCH_THREADPOOLTYPE_QUEUED 
+ * @param initsize initial number of threads, ignored for ETCH_THREADPOOLTYPE_FREE. 
+ */
+etch_threadpool* new_threadpool(const unsigned pooltype, const int initsize)
+{
+    etch_status_t status = ETCH_SUCCESS;
+
+    etch_threadpool* pool = (etch_threadpool*) new_object
+        (sizeof(etch_threadpool), ETCHTYPEB_THREADPOOL, CLASSID_THREADPOOL);
+
+    ((etch_object*)pool)->destroy = destroy_threadpool;
+    ((etch_object*)pool)->clone   = clone_null;
+    pool->count   = threadpool_count;
+    pool->run     = pooltype == ETCH_THREADPOOLTYPE_QUEUED?
+                    etch_threadpool_run_poolthread : etch_threadpool_run_freethread;
+
+    // TODO: pool
+    status = etch_mutex_create(&pool->pool_lock, ETCH_MUTEX_NESTED, NULL);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+
+    // TODO: pool
+    status = etch_mutex_create(&pool->threadlist_lock, ETCH_MUTEX_NESTED, NULL);
+    if(status != ETCH_SUCCESS) {
+        // error
+    }
+
+    pool->threadlist = new_threadpool_list(initsize, pool->threadlist_lock);
+
+    pool->is_free_data = TRUE;
+    pool->is_data_etchobject = FALSE;
+    pool->threadpool_id = ++etch_threadpool_id_farm;
+  
+    return pool;
+} 
+
+
+/**
+ * etch_glopool_exit()
+ * wait on all threads in global pool to exit, destroy global pool.
+ */
+int etch_glopool_exit()
+{
+    destroy_threadpool(global_free_threadpool);
+    global_free_threadpool = NULL;
+    return 0;
+}
+
+
+/**
+ * global_pool()
+ * return singleton global free thread pool
+ */
+etch_threadpool* etch_glopool()
+{
+    if (global_free_threadpool == NULL)
+        global_free_threadpool = new_threadpool(ETCH_THREADPOOLTYPE_FREE, 0);
+    return global_free_threadpool;
+}
+
+
+
+/**
+ * global_pool()
+ * return singleton global free thread pool
+ * todo destroy this pool somewhere
+ */
+etch_threadpool* global_pool()
+{
+    if (global_free_threadpool == NULL)
+        global_free_threadpool = new_threadpool(ETCH_THREADPOOLTYPE_FREE, 0);
+    return global_free_threadpool;
+}
+
+
+/**
+ * getter for APR thread id
+ * seems to be wrong - the ID is the same for each thread
+ */
+size_t etch_get_threadid (void* threadstruct)
+{   
+    /* can't address apr_thread_t content so we remap part of apr_thread_t */
+    struct x { void* mempool; void* threadid; };
+    return threadstruct? (size_t) ((struct x*)threadstruct)->threadid: 0;
+}
+
+
+/**
+ * next_etch_threadid()
+ * get a sequential ID we use to key threads
+ */
+unsigned int next_etch_threadid()
+{
+    do 
+    {
+        apr_atomic_inc32((volatile apr_uint32_t*) &thread_id_farm);
+    } while(thread_id_farm == 0);
+
+    return thread_id_farm;
+}
+
+
+/**
+ * default_on_threadstart()
+ * default thread start callback.
+ * the argument passed to start and exit callbacks is the etch_thread*
+ */
+int default_on_threadstart(void* param)
+{
+    int  thread_id = 0;
+    etch_thread* threadx = (etch_thread*) param;
+    etch_thread_params* p = threadx? &threadx->params: 0;
+    if (p) thread_id = p->etch_thread_id;
+    ETCH_ASSERT(thread_id);
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "thread %d enter\n", thread_id); 
+    return 0;
+}
+
+
+/**
+ * default_on_threadexit()
+ * default thread exit callback.
+ * the argument passed to start and exit callbacks is the etch_thread*
+ */
+int default_on_threadexit(void* param)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_thread* thisthread = (etch_thread*) param;
+    etch_thread* removedthread = NULL;
+    etch_threadpool* pool = NULL;
+    etch_thread_params* p;
+    int  thread_id = 0;
+    ETCH_ASSERT(thisthread);
+    ETCH_ASSERT(is_etch_thread(thisthread));
+    p = &thisthread->params;
+    thread_id = p->etch_thread_id;
+    pool = p->etchpool;
+   
+    /* we remove the thread from its threadpool if a free pool, and unless the
+     * pool is being destroyed, and unless the pool is otherwise being iterated
+     * elswhere - we can't destroy a thread that another thread has joined, for
+     * instance, the joiner will do that once unblocked. and we do not remove a
+     * pool entry if we are currently iterating the pool.
+     */
+    if (pool && !pool->is_defunct) 
+    {
+        const int is_freethread = (pool->pooltype == ETCH_THREADPOOLTYPE_FREE);
+        char x[40]; sprintf(x, "thread %d from pool %d", thread_id, pool->threadpool_id);
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "removing %s ...\n", x); 
+
+        status = etch_mutex_lock(pool->pool_lock);
+        if(status != ETCH_SUCCESS) {
+            // error
+        }
+        /* todo dispose of thread elsewhere when is_iterating is true */
+
+        removedthread = threadpool_remove_entry (pool, thread_id); 
+
+        if (NULL == removedthread) /* occasionally observed while in debugger */
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_WARN, "%s was previously removed\n", x); 
+        else    
+        if (removedthread != thisthread)  /* condition never observed to date */
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s removed unexpectedly\n", x); 
+        else {
+            /* if either the pool is configured to free threads on exit,
+             * or this is a free pool that we are not currently iterating over ... */
+            if  (!removedthread->is_joined && is_freethread 
+             && (pool->is_free_threads || !pool->is_iterating))
+            {    
+                etch_object_destroy(removedthread);   
+                ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "%s removed and destroyed\n", x);  
+            }
+            else 
+                ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "%s removed\n", x); 
+        }
+
+        status = etch_mutex_unlock(pool->pool_lock);
+        if(status != ETCH_SUCCESS) {
+            // error
+        }
+    }   
+    else 
+        destroy_threadparams(thisthread);   
+
+    /* we always destroy the thread's caller-allocated parameter memory, but we
+     * do not however destroy the etch_thread wrapper when the thread is not in 
+     * a threadpool. memory for non-pool threads is managed by caller.
+     */
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "thread %d exit\n", thread_id); 
+    return 0;
+}
+
+
+/**
+ * etch_sleep()
+ * interface to OS sleep in milliseconds
+ */
+void etch_sleep(const int ms)
+{
+    apr_sleep(ms * 1000);
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_thread2.c b/binding-c/runtime/c/src/main/common/etch_thread2.c
new file mode 100644
index 0000000..320c536
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_thread2.c
@@ -0,0 +1,125 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+#ifdef _THREAD2_
+/*
+ * etcht_hread.c
+ */
+#include "etch_thread2.h"
+#include "etch_log.h"
+#include "etch_object.h"
+#include "etch_objecttypes.h"
+#include "etch_wait.h"
+#include "etch_mem.h"
+
+static const char* LOG_CATEGORY = "etch_thread";
+
+extern etch_pool_t* g_etch_main_pool;
+
+
+
+etch_status_t etch_thread_attr_create(etch_thread_attr_t** attr)
+{
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_thread_attr_set_detachstate(etch_thread_attr_t* attr, int state)
+{
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_thread_attr_get_detachstate(etch_thread_attr_t* attr, int* state)
+{
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_thread_attr_destroy(etch_thread_attr_t* attr)
+{
+    return ETCH_SUCCESS;
+}
+
+
+struct etch_thread_t
+{
+    etch_object object;
+
+    // thread member types
+    apr_thread_t*    apr_thread;
+    apr_pool_t*      apr_pool;
+
+    etch_thread_func func;
+    void*            data;
+    etch_wait_t*     event_start;
+};
+
+/**
+ * etch_apr_threadproc()
+ * internal thread proc. this is a wrapper around the user thread proc.
+ * @param data expected to point at an etch_thread_params, which contains the
+ * thread start amd stop handlers, and the real threadproc and threadproc data.
+ */
+static void* APR_THREAD_FUNC apr_thread_func(apr_thread_t* apr_thread, void *data)
+{
+    //etch_status_t  rv     = ETCH_SUCCESS;
+    //etch_status_t  status = ETCH_SUCCESS;
+    //etch_thread_t* thread = NULL;
+
+    //thread = data;
+    //ETCH_ASSERT(thread == NULL);
+
+    //status = etch_wait_wait_and_set(thread->event_start, 1, 0);
+    //ETCH_ASSERT(status == ETCH_SUCCESS);
+
+    //etch_thread_exit(thread, rv);
+    return NULL;
+}
+
+
+etch_status_t etch_thread_create(etch_thread_t** thread, const etch_thread_attr_t* attr, etch_thread_func thread_proc, void* data)
+{
+    etch_status_t   rv         = ETCH_SUCCESS;
+    //etch_status_t   status     = ETCH_SUCCESS;
+    //etch_thread_t*  newthread  = NULL;
+    //apr_status_t    apr_status = NULL;
+
+    //if(thread == NULL) {
+    //    return ETCH_EINVAL;
+    //}
+
+    //newthread = (etch_thread_t*)new_object(sizeof(etch_thread_t), ETCHTYPEB_THREAD, CLASSID_THREAD);
+    //ETCH_ASSERT(newthread == NULL);
+
+
+    return rv;
+}
+
+etch_status_t etch_thread_join(etch_thread_t* thread, etch_status_t* status)
+{
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_thread_yield()
+{
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_thread_exit(etch_thread_t* thread, etch_status_t status)
+{
+    return ETCH_SUCCESS;
+}
+
+#endif
\ No newline at end of file
diff --git a/binding-c/runtime/c/src/main/common/etch_threadpool.c b/binding-c/runtime/c/src/main/common/etch_threadpool.c
new file mode 100644
index 0000000..90707a4
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_threadpool.c
@@ -0,0 +1,84 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_threadpool.c.c 
+ */
+
+#include "etch_threadpool.h"
+#include "etch_object.h"
+#include "etch_objecttypes.h"
+#include "etch_mutex.h"
+
+/*
+static const char* LOG_CATEGORY = "etch_threadpool";
+*/
+static apr_uint32_t g_etch_threadpool_id = 0;
+
+struct etch_threadpool_t
+{
+    etch_object object;
+
+    // threadpool id
+    uint32          id;
+};
+
+etch_status_t etch_threadpool_create(etch_threadpool_t** threadpool, uint8 type, const uint16 init_size)
+{
+    etch_status_t       rv            = ETCH_SUCCESS;
+    etch_threadpool_t*  newthreadpool = NULL;
+
+    if(threadpool == NULL || (type != ETCH_THREADPOOL_TYPE_FREE && type != ETCH_THREADPOOL_TYPE_QUEUED)) {
+        return ETCH_EINVAL;
+    }
+
+    newthreadpool = (etch_threadpool_t*)new_object(sizeof(etch_threadpool_t), ETCHTYPEB_THREADPOOL, CLASSID_THREADPOOL);
+    ETCH_ASSERT(newthreadpool != NULL);
+
+    newthreadpool->id = apr_atomic_inc32(&g_etch_threadpool_id);
+
+    switch(type) {
+        case ETCH_THREADPOOL_TYPE_FREE:
+            break;
+        case ETCH_THREADPOOL_TYPE_QUEUED:
+            break;
+        default:
+            break;
+    }
+
+
+    *threadpool = newthreadpool;
+    return rv;
+
+}
+
+etch_status_t etch_threadpool_remove(etch_threadpool_t* threadpool, const uint16 thread_id)
+{
+    return ETCH_ENOTIMPL;
+}
+
+etch_status_t etch_threadpool_join(etch_threadpool_t* threadpool)
+{
+    return ETCH_ENOTIMPL;
+}
+
+etch_status_t etch_threadpool_destroy(etch_threadpool_t* threadpool)
+{
+    etch_status_t       rv            = ETCH_SUCCESS;
+    return rv;
+}
diff --git a/binding-c/runtime/c/src/main/common/etch_wait.c b/binding-c/runtime/c/src/main/common/etch_wait.c
new file mode 100644
index 0000000..7bc1468
--- /dev/null
+++ b/binding-c/runtime/c/src/main/common/etch_wait.c
@@ -0,0 +1,320 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_wait.c -- thread wait implementation
+ */
+
+#include "etch_wait.h"
+#include "etch_object.h"
+#include "etch_objecttypes.h"
+#include "etch_mutex.h"
+#include "etch_log.h"
+
+static const char* LOG_CATEGORY = "etch_wait";
+
+extern apr_pool_t*         g_etch_main_pool;
+extern apr_thread_mutex_t* g_etch_main_pool_mutex;
+
+struct etch_wait_t
+{
+    etch_object object;
+
+    void*  mutex;         /* associated mutex - owned */
+    void*  cond;          /* wait implementation - owned */
+    int64  cond_var;      /* wait condition var */
+    int32  threadcount;   /* count of threads waiting */
+
+};
+
+etch_status_t etch_wait_create(etch_wait_t** waiter, etch_pool_t* pool)
+{
+    etch_wait_t*        newwaiter  = NULL;
+    apr_status_t        apr_status = APR_SUCCESS;
+    apr_thread_cond_t*  apr_cond   = NULL;
+    apr_thread_mutex_t* apr_mutex  = NULL;
+
+    if(waiter == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    /* if pool is null use global pool */
+    if(pool == NULL) {
+        pool = g_etch_main_pool;
+    }
+
+    newwaiter = (etch_wait_t*)new_object(sizeof(etch_wait_t), ETCHTYPEB_WAIT, CLASSID_WAIT);
+    ETCH_ASSERT(newwaiter != NULL);
+
+    apr_thread_mutex_lock(g_etch_main_pool_mutex);
+    apr_status = apr_thread_mutex_create(&apr_mutex, APR_THREAD_MUTEX_UNNESTED, g_etch_main_pool);
+    apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+    if(apr_status != APR_SUCCESS) {
+        char temp[1024];
+        apr_strerror(apr_status, temp, sizeof(temp));
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+        etch_free(newwaiter);
+        *waiter = NULL;
+        return ETCH_ERROR;
+    }
+
+    apr_thread_mutex_lock(g_etch_main_pool_mutex);
+    apr_status = apr_thread_cond_create(&apr_cond, g_etch_main_pool);
+    apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+    if(apr_status != APR_SUCCESS) {
+        char temp[1024];
+        apr_strerror(apr_status, temp, sizeof(temp));
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+        apr_thread_mutex_destroy(apr_mutex);
+        etch_free(newwaiter);
+        *waiter = NULL;
+        return ETCH_ERROR;
+    }
+
+    newwaiter->mutex     = apr_mutex;
+    newwaiter->cond      = apr_cond;
+    newwaiter->cond_var  = 0;
+    *waiter = newwaiter;
+    return ETCH_SUCCESS;
+}
+
+etch_status_t etch_wait_set(etch_wait_t* waiter, int64 cond_value)
+{
+    etch_status_t       status = ETCH_SUCCESS;
+    apr_status_t        apr_status = APR_SUCCESS;
+    apr_thread_mutex_t* apr_mutex  = NULL;
+    apr_thread_cond_t*  apr_cond   = NULL;
+
+    if(waiter == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    apr_mutex = waiter->mutex;
+    ETCH_ASSERT(apr_mutex != NULL);
+    apr_cond  = waiter->cond;
+    ETCH_ASSERT(apr_cond != NULL);
+
+    apr_thread_mutex_lock(apr_mutex);
+
+    waiter->cond_var = cond_value;
+    apr_status = apr_thread_cond_broadcast(apr_cond);
+    if(apr_status != APR_SUCCESS) {
+        char temp[1024];
+        apr_strerror(apr_status, temp, sizeof(temp));
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+        status = ETCH_ERROR;
+    }
+
+    apr_thread_mutex_unlock(apr_mutex);
+
+    return status;
+}
+
+etch_status_t etch_wait_reset(etch_wait_t* waiter, int64 cond_value)
+{
+    etch_status_t       status = ETCH_SUCCESS;
+    apr_thread_mutex_t* apr_mutex  = NULL;
+
+    if(waiter == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    apr_mutex = waiter->mutex;
+    ETCH_ASSERT(apr_mutex != NULL);
+
+    apr_thread_mutex_lock(apr_mutex);
+    waiter->cond_var = cond_value;
+    apr_thread_mutex_unlock(apr_mutex);
+
+    return status;
+}
+
+etch_status_t etch_wait_wait_helper(etch_wait_t* waiter, int64 cond_value, int64* new_cond_value)
+{
+    etch_status_t       status     = ETCH_SUCCESS;
+    apr_status_t        apr_status = APR_SUCCESS;
+    apr_thread_mutex_t* apr_mutex  = NULL;
+    apr_thread_cond_t*  apr_cond   = NULL;
+
+    if(waiter == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    apr_mutex = waiter->mutex;
+    ETCH_ASSERT(apr_mutex != NULL);
+    apr_cond  = waiter->cond;
+    ETCH_ASSERT(apr_cond != NULL);
+
+    apr_thread_mutex_lock(apr_mutex);
+
+    while(waiter->cond_var != cond_value) {
+        apr_status = apr_thread_cond_wait(apr_cond, apr_mutex);
+        if(apr_status != APR_SUCCESS) {
+            char temp[1024];
+            apr_strerror(apr_status, temp, sizeof(temp));
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+            status = ETCH_ERROR;
+            break;
+        }
+    }
+
+    if(status == ETCH_SUCCESS && new_cond_value != NULL) {
+        waiter->cond_var = *new_cond_value;
+        apr_status = apr_thread_cond_broadcast(apr_cond);
+        if(apr_status != APR_SUCCESS) {
+            char temp[1024];
+            apr_strerror(apr_status, temp, sizeof(temp));
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+        }
+    }
+
+    apr_thread_mutex_unlock(apr_mutex);
+
+    return status;
+}
+
+etch_status_t etch_wait_wait(etch_wait_t* waiter, int64 cond_value)
+{
+    etch_status_t status;
+    status = etch_wait_wait_helper(waiter, cond_value, NULL);
+    return status;
+}
+
+etch_status_t etch_wait_wait_and_set(etch_wait_t* waiter, int64 cond_value, int64 new_cond_value)
+{
+    etch_status_t status;
+    status = etch_wait_wait_helper(waiter, cond_value, &new_cond_value);
+    return status;
+}
+
+static etch_status_t etch_wait_timedwait_helper(etch_wait_t* waiter, int64 cond_value, uint32 timeout, int64* new_cond_value)
+{
+    etch_status_t       status     = ETCH_SUCCESS;
+    apr_status_t        apr_status = APR_SUCCESS;
+    apr_thread_mutex_t* apr_mutex  = NULL;
+    apr_thread_cond_t*  apr_cond   = NULL;
+    apr_time_t          now        = 0;
+    apr_time_t          end        = 0;
+    apr_time_t          diff       = 0;
+
+    if(waiter == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    apr_mutex = waiter->mutex;
+    ETCH_ASSERT(apr_mutex != NULL);
+    apr_cond  = waiter->cond;
+    ETCH_ASSERT(apr_cond != NULL);
+
+    now = apr_time_now();
+    end = now + timeout * 1000;
+
+    apr_thread_mutex_lock(apr_mutex);
+
+    diff = end - now;
+    while(waiter->cond_var != cond_value && diff > 0) {
+        apr_status = apr_thread_cond_timedwait(apr_cond, apr_mutex, diff);
+        if(apr_status != APR_TIMEUP && apr_status != APR_SUCCESS) {
+            char temp[1024];
+            apr_strerror(apr_status, temp, sizeof(temp));
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+            status = ETCH_ERROR;
+            break;
+        }
+
+        now = apr_time_now();
+        diff = end - now;
+    }
+
+    if(status != ETCH_ERROR && waiter->cond_var != cond_value) {
+        status = ETCH_ETIMEOUT;
+    }
+
+    if(status == ETCH_SUCCESS && new_cond_value != NULL) {
+        waiter->cond_var = *new_cond_value;
+        apr_status = apr_thread_cond_broadcast(apr_cond);
+        if(apr_status != APR_SUCCESS) {
+            char temp[1024];
+            apr_strerror(apr_status, temp, sizeof(temp));
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+        }
+    }
+
+    apr_thread_mutex_unlock(apr_mutex);
+
+    return status;
+}
+
+etch_status_t etch_wait_timedwait(etch_wait_t* waiter, int64 cond_value, uint32 timeout)
+{
+    etch_status_t status;
+    status = etch_wait_timedwait_helper(waiter, cond_value, timeout, NULL);
+    return status;
+}
+
+etch_status_t etch_wait_timedwait_and_set(etch_wait_t* waiter, int64 cond_value, uint32 timeout, int64 new_cond_value)
+{
+    etch_status_t status;
+    status = etch_wait_timedwait_helper(waiter, cond_value, timeout, &new_cond_value);
+    return status;
+}
+
+etch_status_t etch_wait_destroy(etch_wait_t* waiter)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    apr_status_t        apr_status = APR_SUCCESS;
+    apr_thread_mutex_t* apr_mutex  = NULL;
+    apr_thread_cond_t*  apr_cond   = NULL;
+
+    if(waiter == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    apr_mutex = waiter->mutex;
+    ETCH_ASSERT(apr_mutex != NULL);
+    apr_cond  = waiter->cond;
+    ETCH_ASSERT(apr_cond != NULL);
+
+
+    if (!is_etchobj_static_content(waiter)) {
+        apr_thread_mutex_lock(g_etch_main_pool_mutex);
+        apr_status = apr_thread_cond_destroy(apr_cond);
+        apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+        if(apr_status != APR_SUCCESS) {
+            char temp[1024];
+            apr_strerror(apr_status, temp, sizeof(temp));
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+            status = ETCH_ERROR;
+        }
+
+        apr_thread_mutex_lock(g_etch_main_pool_mutex);
+        apr_status = apr_thread_mutex_destroy(apr_mutex);
+        apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+        if(apr_status != APR_SUCCESS) {
+            char temp[1024];
+            apr_strerror(apr_status, temp, sizeof(temp));
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", temp);
+            status = ETCH_ERROR;
+        }
+
+        if(!is_etchobj_static_shell(waiter)) {
+            etch_free(waiter);
+        }
+    }
+    return status;
+}
diff --git a/binding-c/runtime/c/src/main/etch-c.vcproj b/binding-c/runtime/c/src/main/etch-c.vcproj
new file mode 100644
index 0000000..ed306e2
--- /dev/null
+++ b/binding-c/runtime/c/src/main/etch-c.vcproj
@@ -0,0 +1,890 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8,00"

+	Name="etch-c"

+	ProjectGUID="{C49054D6-0122-4F20-A0A2-06197D08567B}"

+	RootNamespace="etchc"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)target/win32/$(ConfigurationName)"

+			IntermediateDirectory="$(SolutionDir)target/win32/$(ConfigurationName)"

+			ConfigurationType="4"

+			InheritedPropertySheets=".\etch-c.vsprops"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="..\..\include;..\extern\jenkhash;&quot;$(APR)\include&quot;;&quot;$(APR_ICONV)\include&quot;"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="3"

+				UsePrecompiledHeader="0"

+				ProgramDataBaseFileName="$(IntDir)\etch-c.pdb"

+				WarningLevel="3"

+				WarnAsError="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+				LinkLibraryDependencies="true"

+				AdditionalLibraryDirectories=""

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)target/win32/$(ConfigurationName)"

+			IntermediateDirectory="$(SolutionDir)target/win32/$(ConfigurationName)"

+			ConfigurationType="4"

+			InheritedPropertySheets=".\etch-c.vsprops"

+			CharacterSet="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				AdditionalIncludeDirectories="..\..\include;..\extern\jenkhash;&quot;$(APR)\include&quot;;&quot;$(APR_ICONV)\include&quot;"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"

+				RuntimeLibrary="2"

+				UsePrecompiledHeader="0"

+				ProgramDataBaseFileName="$(IntDir)\etch-c.pdb"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug Static|Win32"

+			OutputDirectory="$(SolutionDir)target/win32/$(ConfigurationName)"

+			IntermediateDirectory="$(SolutionDir)target/win32/$(ConfigurationName)"

+			ConfigurationType="4"

+			InheritedPropertySheets=".\etch-c.vsprops"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="..\..\include;..\extern\jenkhash;&quot;$(APR)\include\win32_x86&quot;;&quot;$(APR)\include&quot;;&quot;$(APR_ICONV)\include&quot;"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;APR_DECLARE_STATIC;API_DECLARE_STATIC"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="3"

+				WarningLevel="3"

+				WarnAsError="true"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release Static|Win32"

+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="4"

+			InheritedPropertySheets=".\etch-c.vsprops"

+			CharacterSet="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"

+				RuntimeLibrary="2"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLibrarianTool"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Quelldateien"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<Filter

+				Name="common"

+				>

+				<File

+					RelativePath=".\common\etch_arraylist.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_arrayval.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_cache.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_collection.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_config.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_encoding.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_exception.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_flexbuffer.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_general.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_hash.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_hashfunc.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_linked_list.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_log.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_map.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_mem.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_mutex.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_nativearray.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_object.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_object_types.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_runtime.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_thread.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_thread2.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_threadpool.c"

+					>

+				</File>

+				<File

+					RelativePath=".\apr\etch_threadpool_apr.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_url.c"

+					>

+				</File>

+				<File

+					RelativePath=".\common\etch_wait.c"

+					>

+				</File>

+			</Filter>

+			<Filter

+				Name="internal"

+				>

+				<File

+					RelativePath=".\internal\etchinternal_single_linked_list.c"

+					>

+				</File>

+			</Filter>

+			<Filter

+				Name="message"

+				>

+				<File

+					RelativePath=".\bindings\msg\etch_default_value_factory.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_field.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_id_name.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_message.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_structval.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_tagdata.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_type.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_validator.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_value_factory.c"

+					>

+				</File>

+			</Filter>

+			<Filter

+				Name="transport"

+				>

+				<File

+					RelativePath=".\bindings\msg\etch_binary_tdi.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_binary_tdo.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_connection.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_connection_event.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_mailbox_manager.c"

+					>

+				</File>

+				<File

+					RelativePath=".\support\etch_mailboxint.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_messagizer.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_packetizer.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_plain_mailbox.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_plain_mailbox_manager.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_session_data.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_session_listener.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_session_message.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_session_packet.c"

+					>

+				</File>

+				<File

+					RelativePath=".\support\etch_sessionint.c"

+					>

+				</File>

+				<File

+					RelativePath=".\support\etch_simpletimer.c"

+					>

+				</File>

+				<File

+					RelativePath=".\support\etch_sourceint.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_tagdata_inp.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\msg\etch_tagdata_out.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_tcp_connection.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_tcp_server.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_tdformat.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_transport.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_transport_data.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_transport_message.c"

+					>

+				</File>

+				<File

+					RelativePath=".\transport\etch_transport_packet.c"

+					>

+				</File>

+				<File

+					RelativePath=".\support\etch_transportint.c"

+					>

+				</File>

+			</Filter>

+			<Filter

+				Name="support"

+				>

+				<File

+					RelativePath=".\transport\etch_queue.c"

+					>

+				</File>

+				<File

+					RelativePath=".\support\etch_queue_apr.c"

+					>

+				</File>

+				<File

+					RelativePath=".\support\etch_remote.c"

+					>

+				</File>

+				<File

+					RelativePath=".\bindings\support\etch_resources.c"

+					>

+				</File>

+				<File

+					RelativePath=".\support\etch_serializer.c"

+					>

+				</File>

+				<File

+					RelativePath=".\support\etch_stub.c"

+					>

+				</File>

+			</Filter>

+		</Filter>

+		<Filter

+			Name="Headerdateien"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath="..\..\include\etch.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_arraylist.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_arrayval.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_binary_tdi.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_binary_tdo.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_cache.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_collection.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_config.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_connection.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_default_value_factory.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_encoding.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_errno.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_exception.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_field.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_flexbuffer.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_general.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_hash.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_id_name.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_id_name_map.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_linked_list.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_log.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_mailbox.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_mailbox_manager.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_map.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_mem.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_message.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_messagizer.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_msgutl.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_mutex.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_nativearray.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_object.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_objecttypes.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_packetizer.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_plain_mailbox.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_plain_mailbox_manager.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_queue.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_queue_apr.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_remote.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_resources.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_runtime.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_serializer.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_session_data.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_session_listener.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_session_message.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_session_packet.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_sessionint.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_simpletimer.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_sourceint.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_structval.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_stub.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_svcobj_masks.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_tagdata_inp.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_tagdata_out.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_tagged_data.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_tcp_connection.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_tcp_server.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_tdformat.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_thread.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_thread2.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_threadpool.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_threadpool_apr.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_transport.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_transport_data.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_transport_message.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_transport_packet.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_transportint.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_type.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_url.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_validator.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_value_factory.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_wait.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etch_warn.h"

+				>

+			</File>

+			<File

+				RelativePath="..\..\include\etchinternal_single_linked_list.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Ressourcendateien"

+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"

+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"

+			>

+			<File

+				RelativePath="..\..\README.TXT"

+				>

+			</File>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/binding-c/runtime/c/src/main/etch-c.vsprops b/binding-c/runtime/c/src/main/etch-c.vsprops
new file mode 100644
index 0000000..2cd7374
--- /dev/null
+++ b/binding-c/runtime/c/src/main/etch-c.vsprops
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioPropertySheet

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="etch-c"

+	>

+	<UserMacro

+		Name="APR"

+		Value="$(SolutionDir)src\extern\apr\apr"

+		PerformEnvironmentSet="true"

+	/>

+	<UserMacro

+		Name="APR_ICONV"

+		Value="$(SolutionDir)src\extern\apr\apr-iconv"

+		PerformEnvironmentSet="true"

+	/>

+</VisualStudioPropertySheet>

diff --git a/binding-c/runtime/c/src/main/internal/etchinternal_single_linked_list.c b/binding-c/runtime/c/src/main/internal/etchinternal_single_linked_list.c
new file mode 100644
index 0000000..1e70b81
--- /dev/null
+++ b/binding-c/runtime/c/src/main/internal/etchinternal_single_linked_list.c
@@ -0,0 +1,75 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "etchinternal_single_linked_list.h"
+
+#include <string.h>
+#include "etch_mem.h"
+
+
+etchinternal_single_linked_list_node* etchinternal_single_linked_list_node_create(void* data, etchinternal_single_linked_list_node* next) {
+  etchinternal_single_linked_list_node* res = (etchinternal_single_linked_list_node*)etch_malloc(sizeof(etchinternal_single_linked_list_node), 0);
+  res->data = data;
+  res->next = next;
+
+  return res;
+}
+
+etchinternal_single_linked_list* etchinternal_single_linked_list_create() {
+  etchinternal_single_linked_list* res = (etchinternal_single_linked_list*)etch_malloc(sizeof(etchinternal_single_linked_list), 0);
+  memset(res, 0, sizeof(etchinternal_single_linked_list));
+  return res;
+}
+
+
+void etchinternal_single_linked_list_destroy(etchinternal_single_linked_list* list) {
+  etchinternal_single_linked_list_node* help = list->head;
+  etchinternal_single_linked_list_node* help2;
+  while (help) {
+    help2 = help->next;
+
+    free(help->data);
+    free(help);
+
+    help = help2;
+  }
+  free(list);
+}
+
+void etchinternal_single_linked_list_add(etchinternal_single_linked_list* list, void* data, size_t size) {
+  void* new_data = etch_malloc(size, 0);
+  etchinternal_single_linked_list_node* new_node;
+  memcpy(new_data, data, size);
+  new_node = etchinternal_single_linked_list_node_create(new_data, list->head);
+  list->head = new_node;
+}
+
+void* etchinternal_single_linked_list_find(etchinternal_single_linked_list* list, etchinternal_find_func find, void* find_data) {
+  etchinternal_single_linked_list_node* help = list->head;
+  while (help) {
+    if (find(help->data, find_data)) {
+      return help->data;
+    }
+
+    help = help->next;
+  }
+  return 0;
+}
diff --git a/binding-c/runtime/c/src/main/support/etch_mailboxint.c b/binding-c/runtime/c/src/main/support/etch_mailboxint.c
new file mode 100644
index 0000000..eedb053
--- /dev/null
+++ b/binding-c/runtime/c/src/main/support/etch_mailboxint.c
@@ -0,0 +1,264 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_mailboxint.c
+ * mailbox interface
+ */
+
+#include "etch_mailbox.h"
+#include "etch_plain_mailbox.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+
+/*
+static const char* LOG_CATEGORY = "etch_mailbox";
+*/
+
+int etchmbi_def_message(void* thisx, etch_who* whofrom, etch_message* msg);
+int etchmbi_def_read   (void* thisx, etch_mailbox_element** out);
+int etchmbi_def_read_withwait (void* thisx, const int maxdelay, etch_mailbox_element** out);
+int etchmbi_def_close_delivery (void* thisx);
+int etchmbi_def_close_read (void* thisx);
+int etchmbi_def_register_notify (void* thisx, etch_mailbox_notify, etch_object* state, const int maxdelay);
+int etchmbi_def_unregister_notify (void* thisx, etch_mailbox_notify);
+int etchmbi_def_is_empty  (void* thisx);
+int etchmbi_def_is_closed (void* thisx);
+int etchmbi_def_is_full   (void* thisx);
+int64 etchmbi_def_get_message_id (void* thisx);
+int destroy_mailbox_interface(void*);
+
+
+/**
+ * new_default_mailbox_interface
+ * return a mailbox interface populated with defaults for virtuals.
+ */
+i_mailbox* new_default_mailbox_interface(void* thisx)
+{
+    i_mailbox* newi = (i_mailbox*) etch_malloc(sizeof(i_mailbox), ETCHTYPEB_RAWOBJECT); 
+
+    newi->thisx = thisx;
+    newi->destroy = destroy_mailbox_interface;
+    newi->mailbox = etchmbox_get_implobj;
+    newi->manager = etchmbox_get_manager;
+
+    newi->message           = etchmbi_def_message;
+    newi->read              = etchmbi_def_read;
+    newi->read_withwait     = etchmbi_def_read_withwait;
+    newi->close_delivery    = etchmbi_def_close_delivery;
+    newi->close_read        = etchmbi_def_close_read;
+    newi->register_notify   = etchmbi_def_register_notify;
+    newi->unregister_notify = etchmbi_def_unregister_notify;
+    newi->is_empty          = etchmbi_def_is_empty;
+    newi->is_closed         = etchmbi_def_is_closed;
+    newi->is_full           = etchmbi_def_is_full;
+    newi->get_message_id    = etchmbi_def_get_message_id;
+
+    return newi;    
+}
+
+
+/**
+ * new_mailbox_interface
+ * return a mailbox interface populated with specified virtuals.
+ */
+i_mailbox* new_mailbox_interface(void* thisx,
+    etch_mailbox_message mbm,
+    etch_mailbox_read    mbr,
+    etch_mailbox_read_withwait     mbrd,
+    etch_mailbox_close_delivery    mbcd,
+    etch_mailbox_close_read        mbcr,
+    etch_mailbox_register_notify   mbrn,
+    etch_mailbox_unregister_notify mbun,
+    etch_mailbox_is_empty  mbise,
+    etch_mailbox_is_closed mbisc,
+    etch_mailbox_is_full   mbisf,
+    etch_mailbox_get_message_id    mbgmi) 
+{
+    i_mailbox* newi = (i_mailbox*) new_object
+       (sizeof(i_mailbox), ETCHTYPEB_MAILBOXINT, CLASSID_MAILBOXINT);
+
+    newi->thisx = thisx;
+    newi->destroy = destroy_mailbox_interface;
+    newi->mailbox = etchmbox_get_implobj;
+    newi->manager = etchmbox_get_manager;
+
+    newi->message           = mbm?   mbm:   etchmbi_def_message;
+    newi->read              = mbr?   mbr:   etchmbi_def_read;
+    newi->read_withwait     = mbrd?  mbrd:  etchmbi_def_read_withwait;
+    newi->close_delivery    = mbcd?  mbcd:  etchmbi_def_close_delivery;
+    newi->close_read        = mbcr?  mbcr:  etchmbi_def_close_read;
+    newi->register_notify   = mbrn?  mbrn:  etchmbi_def_register_notify;
+    newi->unregister_notify = mbun?  mbun:  etchmbi_def_unregister_notify;
+    newi->is_empty          = mbise? mbise: etchmbi_def_is_empty;
+    newi->is_closed         = mbisc? mbisc: etchmbi_def_is_closed;
+    newi->is_full           = mbisf? mbisf: etchmbi_def_is_full;
+    newi->get_message_id    = mbgmi? mbgmi: etchmbi_def_get_message_id;
+
+    return newi;    
+}
+
+
+/**
+ * destroy_mailbox_interface()
+ * i_mailbox destructor
+ */
+int destroy_mailbox_interface (void* data)
+{
+  i_mailbox* mb = (i_mailbox*)data;
+    int result = 0;
+    if (mb && !is_etchobj_static_content(mb))
+    {
+        i_mailbox* temp = mb->thisx; //destroying thisx will also destroy mb...
+	//        ETCHOBJ_DESTROY();	
+	if(temp)
+	  ((etch_object*)temp)->destroy((etch_object*)temp);
+	temp = NULL;
+
+    }
+    else result = -1;
+    return result;
+}  
+
+
+/**
+ * etch_mailbox_get_implobj()
+ * verify and return the concrete mailbox implementation
+ */
+etch_mailbox* etchmbox_get_implobj(i_mailbox* imb) 
+{
+    etch_mailbox* mbox = imb? imb->thisx: NULL;
+    return is_etch_mailbox(mbox)? mbox: NULL;
+}
+
+
+/**
+ * etch_mailbox_get_manager()
+ * verify and return the mailbox's mailbox manager
+ */
+i_mailbox_manager* etchmbox_get_manager(i_mailbox* imb)
+{
+    etch_mailbox* mbox = imb? imb->thisx: NULL;
+    i_mailbox_manager* mgr = mbox? mbox->manager: NULL;
+    return is_etch_mailboxmgr(mgr)? mgr: NULL;
+} 
+
+
+int etchmbi_def_message(void* thisx, etch_who* whofrom, etch_message* msg)
+{
+    return -1;
+}
+
+
+int etchmbi_def_read   (void* thisx, etch_mailbox_element** out)
+{
+    return -1;
+}
+
+
+int etchmbi_def_read_withwait (void* thisx, const int maxdelay, etch_mailbox_element** out)
+{
+    return -1;
+}
+
+
+int etchmbi_def_close_delivery (void* thisx)
+{
+    return -1;
+}
+
+
+int etchmbi_def_close_read (void* thisx)
+{
+    return -1;
+}
+
+
+int etchmbi_def_register_notify (void* thisx, etch_mailbox_notify fn, etch_object* state, const int maxdelay)
+{
+    return -1;
+}
+
+int etchmbi_def_unregister_notify (void* thisx, etch_mailbox_notify fn)
+{
+    return -1;
+}
+
+
+int etchmbi_def_is_empty  (void* thisx) 
+{
+    return FALSE;
+}
+
+
+int etchmbi_def_is_closed (void* thisx)
+{
+    return FALSE;
+}
+
+
+int etchmbi_def_is_full   (void* thisx)
+{
+    return FALSE;
+}
+
+
+int64 etchmbi_def_get_message_id (void* thisx)
+{
+    return 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - 
+ * etch_mailbox_element
+ * - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * destroy_mailbox_element()
+ * etch_mailbox_element destructor
+ */
+int destroy_mailbox_element(void* data)
+{
+    etch_mailbox_element* thisx = (etch_mailbox_element*)data;
+
+    if (!is_etchobj_static_content(thisx))
+    {
+        etch_object_destroy(thisx->msg);
+        thisx->msg = NULL;
+    }
+
+   return destroy_objectex((etch_object*) thisx);
+}
+
+
+/**
+ * new_mailbox_element()
+ * etch_mailbox_element constructor
+ * @param msg todo document ownership
+ * @param whofrom todo document ownership
+ */
+etch_mailbox_element* new_mailbox_element(etch_message* msg, etch_who* who)
+{
+    etch_mailbox_element* elt = (etch_mailbox_element*) new_object
+        (sizeof(etch_mailbox_element), ETCHTYPEB_MBOX_ELEMENT, CLASSID_MBOX_ELEMENT); 
+    elt->msg     = msg;
+    elt->whofrom = who;
+    elt->destroy = destroy_mailbox_element;
+    return elt;
+}
diff --git a/binding-c/runtime/c/src/main/support/etch_queue_apr.c b/binding-c/runtime/c/src/main/support/etch_queue_apr.c
new file mode 100644
index 0000000..07bbed3
--- /dev/null
+++ b/binding-c/runtime/c/src/main/support/etch_queue_apr.c
@@ -0,0 +1,441 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_queue_apr.c
+ * based on apr_queue, modified by Cisco as follows: 
+ * timeouts were added on the push and pop waits, and functions were modified
+ * to release their lock at a single exit point.
+ */
+
+#include "apr.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+//#include "apu.h"
+#include "apr_portable.h"
+#include "apr_thread_mutex.h"
+#include "apr_thread_cond.h"
+#include "apr_errno.h"
+
+#include "etch_queue_apr.h"  /* Cisco */
+
+/* #define QUEUE_DEBUG */
+
+#ifdef QUEUE_DEBUG
+static void Q_DBG(char*msg, etch_apr_queue_t *q) {
+    fprintf(stderr, "%ld\t#%d in %d out %d\t%s\n", 
+                    (size_t) apr_os_thread_current(), /* cast - Cisco */
+                    q->nelts, q->in, q->out,
+                    msg
+                    );
+    fflush(stdout);  /* Cisco */
+}
+#else
+#define Q_DBG(x,y) 
+#endif
+
+
+/**
+ * Detects when the etch_apr_queue_t is full. This utility function is expected
+ * to be called from within critical sections, and is not threadsafe.
+ */
+#define etch_apr_queue_full(queue) ((queue)->nelts == (queue)->bounds)
+
+
+/**
+ * Detects when the etch_apr_queue_t is empty. This utility function is expected
+ * to be called from within critical sections, and is not threadsafe.
+ */
+#define etch_apr_queue_empty(queue) ((queue)->nelts == 0)
+
+
+/**
+ * Callback routine that is called to destroy this
+ * etch_apr_queue_t when its pool is destroyed.
+ */
+static apr_status_t etch_apr_queue_destroy(void *data) 
+{
+    etch_apr_queue_t *queue = data;
+
+    apr_thread_cond_destroy(queue->not_empty);
+    apr_thread_cond_destroy(queue->not_full);
+    apr_thread_mutex_destroy(queue->one_big_mutex);
+
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Initialize the etch_apr_queue_t.
+ */
+apr_status_t etch_apr_queue_create(etch_apr_queue_t **q, 
+                                   unsigned int queue_capacity, 
+                                   apr_pool_t *a)
+{
+    apr_status_t rv;
+    etch_apr_queue_t *queue;
+    queue = apr_palloc(a, sizeof(etch_apr_queue_t));
+    *q = queue;
+
+    /* nested doesn't work ;( */
+    rv = apr_thread_mutex_create(&queue->one_big_mutex,
+                                 APR_THREAD_MUTEX_UNNESTED,
+                                 a);
+    if (rv != APR_SUCCESS)  
+        return rv;
+
+    rv = apr_thread_cond_create(&queue->not_empty, a);
+    if (rv != APR_SUCCESS)  
+        return rv;
+
+    rv = apr_thread_cond_create(&queue->not_full, a);
+    if (rv != APR_SUCCESS) 
+        return rv;
+
+    /* Set all the data in the queue to NULL */
+    queue->data = apr_pcalloc(a, queue_capacity * sizeof(void*));
+    queue->bounds = queue_capacity;
+    queue->nelts = 0;
+    queue->in = 0;
+    queue->out = 0;
+    queue->terminated = 0;
+    queue->full_waiters = 0;
+    queue->empty_waiters = 0;
+
+    apr_pool_cleanup_register(a, queue, etch_apr_queue_destroy, apr_pool_cleanup_null);
+
+    return APR_SUCCESS;
+}
+
+
+/**
+ * Push new data onto the queue. Blocks if the queue is full. Once
+ * the push operation has completed, it signals other threads waiting
+ * in apr_queue_pop() that they may continue consuming sockets.
+ * @param timeout added by Cisco. now uses apr_thread_cond_timewait(). 
+ * interval of time to wait. zero means forever, negative indicates no wait, 
+ * otherwise wait time in *microseconds*.
+ * @return APR_SUCCESS, APR_EAGAIN, APR_EOF, APR_EINTR, APR_TIMEUP, 
+ * or some APR error
+ */
+apr_status_t etch_apr_queue_push(etch_apr_queue_t *queue, 
+                                 apr_interval_time_t timeout, 
+                                 void *data)
+{
+    apr_status_t rv;
+
+    if (queue->terminated)  
+        rv = APR_EOF; /* no more elements ever again */
+    else
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    {
+        do 
+        {   if (etch_apr_queue_full(queue)) 
+            {
+                if (!queue->terminated) 
+                {
+                    if (-1 == timeout) 
+                    {   rv = APR_EAGAIN; /* asked to not wait */
+                        break;
+                    }
+
+                    queue->full_waiters++;
+
+                    if (0 == timeout)
+                        rv = apr_thread_cond_wait(queue->not_full, queue->one_big_mutex);
+                    else
+                        rv = apr_thread_cond_timedwait(queue->not_full, queue->one_big_mutex, timeout);
+
+                    queue->full_waiters--;
+                    if (rv != APR_SUCCESS)  
+                        break;
+                }
+
+                /* If we wake up and it's still empty, then we were interrupted */
+                if (etch_apr_queue_full(queue)) 
+                {
+                    Q_DBG("queue full (intr)", queue);
+                    rv = queue->terminated? APR_EOF: APR_EINTR; 
+                    break;
+                }
+            }
+
+            queue->data[queue->in] = data;
+            queue->in = (queue->in + 1) % queue->bounds;
+            queue->nelts++;
+
+            if (queue->empty_waiters) 
+            {
+                Q_DBG("sig !empty", queue);
+                rv = apr_thread_cond_signal(queue->not_empty);
+            }
+
+        } while(0);
+
+        apr_thread_mutex_unlock(queue->one_big_mutex);
+    }
+
+    return rv;
+}
+
+
+/**
+ * Push new data onto the queue. Blocks if the queue is full. Once
+ * the push operation has completed, it signals other threads waiting
+ * in apr_queue_pop() that they may continue consuming sockets.
+ */
+apr_status_t etch_apr_queue_trypush(etch_apr_queue_t *queue, void *data)
+{
+    apr_status_t rv;
+
+    if (queue->terminated)  
+        rv = APR_EOF;  
+    else
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    {
+        if (etch_apr_queue_full(queue))
+            rv = APR_EAGAIN;  
+        else
+        {   queue->data[queue->in] = data;
+            queue->in = (queue->in + 1) % queue->bounds;
+            queue->nelts++;
+
+            if (queue->empty_waiters) 
+            {
+                Q_DBG("sig !empty", queue);
+                rv  = apr_thread_cond_signal(queue->not_empty);               
+            }
+       }
+
+       apr_thread_mutex_unlock(queue->one_big_mutex);
+    }
+
+    return rv;
+}
+
+
+/**
+ * not thread safe
+ */
+unsigned int etch_apr_queue_size(etch_apr_queue_t *queue) {
+    return queue->nelts;
+}
+
+
+/**
+ * Retrieves the next item from the queue. If there are no
+ * items available, it will block until one becomes available.
+ * Once retrieved, the item is placed into the address specified by
+ * 'data'.
+ * @param timeout added by Cisco. now uses apr_thread_cond_timewait(). 
+ * interval of time to wait. zero means forever, -1 means no wait, 
+ * -2 means don't wait and ignore queue closed indicator,
+ * otherwise timeout is blocking time in microseconds.
+ * @return APR_SUCCESS, APR_EAGAIN, APR_EOF, APR_EINTR, APR_TIMEUP, 
+ * or some APR error
+ */
+apr_status_t etch_apr_queue_pop(etch_apr_queue_t *queue, 
+                                apr_interval_time_t timeout, 
+                                void **data)
+{
+    apr_status_t rv;
+
+    if (queue->terminated)  /* Cisco back door to clear closed queue */
+    {   if (timeout != ETCHQUEUE_CLEARING_CLOSED_QUEUE)  
+            return APR_EOF; /* no more elements ever again */
+    }
+
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    {
+        do 
+        {   /* Keep waiting until we wake up and find that the queue is not empty. */
+            if (etch_apr_queue_empty(queue)) 
+            {
+                if (-1 == timeout) 
+                {   rv = APR_EAGAIN; /* asked to not wait */
+                    break;
+                }
+
+                if (!queue->terminated) 
+                {
+                    queue->empty_waiters++;
+
+                    if (0 == timeout)
+                        rv = apr_thread_cond_wait(queue->not_empty, queue->one_big_mutex);
+                    else 
+                        rv = apr_thread_cond_timedwait(queue->not_empty, queue->one_big_mutex, timeout);
+
+                    queue->empty_waiters--;
+
+                    if (rv != APR_SUCCESS) /* rv will be APR_TIMEUP if timed out */ 
+                        break;
+                }
+
+                /* If we wake up and it's still empty, then we were interrupted */
+                if (etch_apr_queue_empty(queue)) 
+                {
+                    Q_DBG("queue empty (intr)", queue);
+                    rv = queue->terminated? APR_EOF: APR_EINTR;
+                    break;
+                }
+            } 
+
+            *data = queue->data[queue->out];
+            queue->nelts--;
+
+            queue->out = (queue->out + 1) % queue->bounds;
+
+            if (queue->full_waiters) 
+            {
+                Q_DBG("signal !full", queue);
+                rv = apr_thread_cond_signal(queue->not_full);
+            }
+
+        } while(0);
+
+        apr_thread_mutex_unlock(queue->one_big_mutex);
+    }  
+
+    return rv;
+}
+
+
+/**
+ * Retrieves the next item from the queue. If there are no
+ * items available, return APR_EAGAIN.  Once retrieved,
+ * the item is placed into the address specified by 'data'.
+ */
+apr_status_t etch_apr_queue_trypop(etch_apr_queue_t *queue, void **data)
+{
+    apr_status_t rv;
+
+    if (queue->terminated)  
+        rv = APR_EOF; /* no more elements ever again */
+    else
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    {
+        if (etch_apr_queue_empty(queue)) 
+            rv = APR_EAGAIN;
+        else
+        {   *data = queue->data[queue->out];
+            queue->nelts--;
+
+            queue->out = (queue->out + 1) % queue->bounds;
+
+            if (queue->full_waiters) 
+            {
+                Q_DBG("signal !full", queue);
+                rv = apr_thread_cond_signal(queue->not_full);
+            }
+       }
+
+       apr_thread_mutex_unlock(queue->one_big_mutex);
+    }
+
+    return rv;
+}
+
+
+apr_status_t etch_apr_queue_interrupt_all(etch_apr_queue_t *queue)
+{
+    apr_status_t rv;
+    Q_DBG("intr all", queue); 
+   
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    { 
+        apr_thread_cond_broadcast(queue->not_empty);
+        apr_thread_cond_broadcast(queue->not_full);
+
+        apr_thread_mutex_unlock(queue->one_big_mutex);
+    }
+
+    return rv;
+}
+
+
+/**
+ * etch_apr_queue_unsafe_interrupt_all()
+ * added by Cisco to opeate when lock already held since queue lock is not nestable.
+ */
+apr_status_t etch_apr_queue_unsafe_interrupt_all(etch_apr_queue_t *queue)
+{
+    Q_DBG("intr all", queue);    
+ 
+    apr_thread_cond_broadcast(queue->not_empty);
+    apr_thread_cond_broadcast(queue->not_full);
+
+    return APR_SUCCESS;
+}
+
+
+apr_status_t etch_apr_queue_term(etch_apr_queue_t *queue)
+{
+    apr_status_t rv;
+  
+    if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+    {
+        /* we must hold one_big_mutex when setting this... otherwise,
+         * we could end up setting it and waking everybody up just after a 
+         * would-be popper checks it but right before they block
+         */
+        queue->terminated = 1;
+
+        apr_thread_mutex_unlock(queue->one_big_mutex);
+    }
+
+    return etch_apr_queue_interrupt_all(queue);
+}
+
+
+/**
+ * added by Cisco to close queue when lock already held
+ */
+apr_status_t etch_apr_queue_unsafeclose(etch_apr_queue_t *queue)
+{
+    queue->terminated = 1;
+    return etch_apr_queue_unsafe_interrupt_all(queue);
+}
+
+
+/**
+ * added by Cisco to access lock externally
+ */
+apr_status_t etch_apr_queue_lock(etch_apr_queue_t *queue)
+{
+    return apr_thread_mutex_lock(queue->one_big_mutex);
+}
+
+
+/**
+ * added by Cisco to access lock externally
+ */
+apr_status_t etch_apr_queue_unlock(etch_apr_queue_t *queue)
+{
+    return apr_thread_mutex_unlock(queue->one_big_mutex);
+}
+
+
+/**
+ * etch_apr_queue_trylock()
+ * added by Cisco to access lock externally
+ */
+int etch_apr_queue_trylock(etch_apr_queue_t *queue) 
+{
+    return apr_thread_mutex_trylock(queue->one_big_mutex);
+}
diff --git a/binding-c/runtime/c/src/main/support/etch_remote.c b/binding-c/runtime/c/src/main/support/etch_remote.c
new file mode 100644
index 0000000..33bf0b8
--- /dev/null
+++ b/binding-c/runtime/c/src/main/support/etch_remote.c
@@ -0,0 +1,330 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_remote.c 
+ * base methods for either type of remote
+ */
+
+#include "etch_remote.h"
+#include "etch_exception.h"
+#include "etch_url.h"
+#include "etch_log.h"
+#include "etch_objecttypes.h"
+
+static const char* LOG_CATEGORY = "etch_remote";
+
+/**
+ * is_etch_remote()
+ */
+int is_etch_remote(void* x)
+{
+    int result = FALSE, objtype = x? ((etch_object*)x)->obj_type: 0;
+    switch(objtype)
+    { case ETCHTYPEB_REMOTE: case ETCHTYPEB_REMOTECLIENT: case ETCHTYPEB_REMOTESERVER:
+           result = TRUE;
+    }
+    return result;
+}            
+
+
+/**
+ * etchremote_new_message()
+ * instantiates a message to be sent via this.send() or this.begin_call().
+ * @param thisx this remote object.
+ * @param message_type type of message, caller retains.
+ * @return message object, or an etch object wrapping an exception.
+ */
+etch_message* etchremote_new_message (void* data, etch_type* message_type)
+{
+  xxxx_remote* thisx = (xxxx_remote*)data;
+    etch_message* msg = new_message (message_type, ETCH_DEFSIZE, thisx->vf);
+
+    /* removed this throw because caller (remote) can't use the exception
+     * without rethrowing it to the mailbox object */
+    #if(0)
+    if (NULL == msg) /* warning this is not a usable message object */
+        msg = (etch_message*) throw_from(EXCPTYPE_ETCHRUNTIME, ETCHTYPEB_MESSAGE, 
+            L"could not create message", ETCHEXCP_COPYTEXT);
+    #endif
+
+    return msg;
+}
+
+
+/**
+ * etchremote_send()
+ * sends message to recipient without waiting for a response.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_send (void* data, etch_message* msg)
+{
+    xxxx_remote* thisx = (xxxx_remote*)data;
+    int result = 0;
+    ETCH_ASSERT(is_etch_remote(thisx));
+    
+    result = thisx->dsvc->itm->transport_message(thisx->dsvc, NULL, msg);
+
+    if (0 != result)
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "remote server send failed for msg %x\n", msg);
+
+    return result;
+}
+
+
+/**
+ * etchremote_sendex()
+ * sends message to recipient without waiting for a response.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return NULL or exception
+ */
+void* etchremote_sendex (void* data, etch_message* msg)
+{
+    xxxx_remote* thisx = (xxxx_remote*)data;
+    etch_object* resultobj = NULL;
+
+    if (0 != etchremote_send (thisx, msg)){
+        etch_object_destroy(resultobj);
+        resultobj = (etch_object*)new_etch_exception_from_errorcode(ETCH_EIO);
+
+        etch_exception_set_message((etch_exception*)resultobj,new_stringw(L"remote server send failed"));
+    }
+    
+    return resultobj;
+}
+
+
+/**
+ * etchremote_begincall()
+ * sends message beginning a call sequence.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return in out parameter, a mailbox which can be used to retrieve the response.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_begincall (void* data, etch_message* msg, void** out)
+{
+    xxxx_remote* thisx = (xxxx_remote*)data;
+    int result = 0;
+    ETCH_ASSERT(is_etch_remote(thisx));
+
+    result = thisx->dsvc->begin_call(thisx->dsvc, msg, out);
+
+    if (0 != result) 
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not create mailbox for msg %x\n", msg);
+         
+    return result;
+}
+
+
+/**
+ * etchremote_endcall()
+ * finishes a call sequence by waiting for a response message.
+ * @param thisx this remote object.
+ * @param mbox a mailbox which will be used to read an expected message response.
+ * @param response_type the message type of the expected response.
+ * @return in out parameter, on success, the response etch_object* masked object.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_endcall (void* data, i_mailbox* mbox, etch_type* response_type, void** out)
+{   
+    xxxx_remote* thisx = (xxxx_remote*)data;
+    ETCH_ASSERT(is_etch_remote(thisx));
+
+    return thisx->dsvc->end_call(thisx->dsvc, mbox, response_type, out);
+}
+
+
+/**
+ * etchremote_transport_control()
+ * @param evt caller relinquishes
+ * @param value caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+int etchremote_transport_control (void* data, etch_event* evt, etch_object* value)
+{
+  xxxx_remote* thisx = (xxxx_remote*)data;
+    ETCH_ASSERT(is_etch_remote(thisx));
+
+    return thisx->dsvc->itm->transport_control(thisx->dsvc, evt, value);
+}
+
+
+/**
+ * etchremote_transport_notify()
+ * @param evt caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+int etchremote_transport_notify  (void* data, etch_event* evt)
+{
+  xxxx_remote* thisx = (xxxx_remote*)data;
+    ETCH_ASSERT(is_etch_remote(thisx));
+    
+    return thisx->dsvc->itm->transport_notify(thisx->dsvc, evt);
+}
+
+
+/**
+ * etchremote_transport_query()
+ * @param query caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+etch_object* etchremote_transport_query (void* data, etch_query* query) 
+{
+  xxxx_remote* thisx = (xxxx_remote*)data;
+    ETCH_ASSERT(is_etch_remote(thisx));
+    
+    return thisx->dsvc->itm->transport_query(thisx->dsvc, query);
+}
+
+
+/**
+ * etchremote_set_session()
+ * @param session caller retains  
+ * @return 0 success, -1 failure.
+ */
+void etchremote_set_session (void* data, void* session) 
+{
+  xxxx_remote* thisx = (xxxx_remote*)data;
+    ETCH_ASSERT(is_etch_remote(thisx)); 
+}
+
+
+/**
+ * etchremote_get_session()
+ * @param session caller retains  
+ * @return 0 success, -1 failure.
+ */
+i_session* etchremote_get_session (void* data)
+{           
+  xxxx_remote* thisx = (xxxx_remote*)data;
+    ETCH_ASSERT(is_etch_remote(thisx)); 
+    return (i_session*)thisx->dsvc->ism;
+}
+
+
+/**
+ * etchremote_start_waitup()
+ * start the transport and wait for it to come up.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_start_waitup (void* data, const int waitms)
+{
+  xxxx_remote* thisx = (xxxx_remote*)data;
+    ETCH_ASSERT(is_etch_remote(thisx)); 
+    ETCH_ASSERT(thisx->transport_control); 
+
+    /* indicate to transport start whether this request is from a client 
+    * (remote server) or a server (remote client) */
+    {  const int is_client = thisx->remote_type == ETCH_REMOTETYPE_SERVER;
+       etch_int32* txvalue = is_client? new_int32(is_client): NULL;
+       etch_event* txevent = new_etch_event(CLASSID_CONTROL_START_WAITUP, waitms);
+
+       return thisx->transport_control (thisx, txevent, (etch_object*)txvalue);
+    }
+}
+
+
+/**
+ * etchremote_stop_waitdown()
+ * stop the transport and wait for it to go down.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_stop_waitdown (void* data, const int waitms)
+{
+  xxxx_remote* thisx = (xxxx_remote*)data;
+    ETCH_ASSERT(is_etch_remote(thisx)); 
+    ETCH_ASSERT(thisx->transport_control); 
+
+    /* indicate to transport start whether this request is from a client 
+     * (remote server) or a server (remote client) */
+    {  const int is_client = thisx->remote_type == ETCH_REMOTETYPE_SERVER;
+       etch_int32* txvalue = is_client? new_int32(is_client): NULL;
+       etch_event* txevent = new_etch_event(CLASSID_CONTROL_STOP_WAITDOWN, waitms);
+
+       #ifdef ETCH_SHORTCIRCUIT_CLIENT_DEMO
+       if (is_client)  /* dead end chain here for client demo */
+       {   
+	    etch_object_destroy(txevent);
+	    txevent = NULL;
+
+	    etch_object_destroy(txvalue);
+	    txvalue = NULL;
+
+        return -1;                  
+       }
+       #endif  /* ETCH_SHORTCIRCUIT_CLIENT_DEMO */
+
+       return thisx->transport_control (thisx, txevent, (etch_object*)txvalue);
+    }
+}
+
+
+/**
+ * new_etch_remote_base
+ * generic constructor for remote base 
+ * @param thisx parent object such as remote server or client.
+ * @param objsize byte length of actual remote base object,  
+ * specifying ETCH_DEFSIZE defaults to sizeof(xxxx_remote).
+ * @param class_id etch class id of this object.
+ * @param ids delivery service -- caller retains.
+ * @param vf default value factory -- caller retains. 
+ * @param ixxxx service interface -- caller retains.
+ * @return xxxx_remote* mask over either remote type.
+ * fyi xxxx_remote typedefs to etch_remote.
+ */
+xxxx_remote* new_etch_remote_base (void* thisx, 
+    const int objsize, const unsigned short class_id,  
+    i_delivery_service* ids, etch_value_factory* vf, etch_object* ixxxx)
+{
+    const int nbytes = objsize? objsize: sizeof(xxxx_remote);
+
+    xxxx_remote* remote = (xxxx_remote*) new_object (nbytes, ETCHTYPEB_REMOTE, class_id);
+
+    /* xxxx_remote instance data and methods */
+    remote->dsvc = ids; 
+    remote->vf   = vf;
+    remote->start_waitup  = etchremote_start_waitup;
+    remote->stop_waitdown = etchremote_stop_waitdown;
+
+    /* transport methods */
+    remote->transport_control = etchremote_transport_control;
+    remote->transport_notify  = etchremote_transport_notify;
+    remote->transport_query   = etchremote_transport_query;
+    remote->set_session       = etchremote_set_session;
+    remote->get_session       = etchremote_get_session;
+
+    /* remote base */
+    remote->new_message = etchremote_new_message;
+    remote->send        = etchremote_send;
+    remote->sendex      = etchremote_sendex;
+    remote->begin_call  = etchremote_begincall;
+    remote->end_call    = etchremote_endcall;
+ 
+    return remote;
+}
+
+
+
diff --git a/binding-c/runtime/c/src/main/support/etch_serializer.c b/binding-c/runtime/c/src/main/support/etch_serializer.c
new file mode 100644
index 0000000..7f408ed
--- /dev/null
+++ b/binding-c/runtime/c/src/main/support/etch_serializer.c
@@ -0,0 +1,926 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_serializer.c
+ */
+
+#include "etch_serializer.h"
+#include "etch_default_value_factory.h"
+#include "etch_arrayval.h"
+#include "etch_encoding.h"
+#include "etch_nativearray.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+#include "etch_map.h"
+#include "etch_log.h"
+
+// etch_log vars
+const char* ETCH_SERIALIZER_CATEGORY = "etch_serializer";
+
+etch_object* etchserializer_defexportval (etch_serializer* thisx, etch_object* objval);
+etch_object* etchserializer_defimportval (etch_serializer* thisx, etch_object* structval);
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * constructors/destructors
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/** 
+ * destroy_etch_serializer()
+ * etch_serializer destructor
+ */
+int destroy_etch_serializer(void* data) 
+{
+    etch_serializer* thisx = (etch_serializer*)data;
+
+    if (!is_etchobj_static_content(thisx)){
+        etch_object_destroy(thisx->impl);
+        thisx->impl = NULL;
+    }
+
+    return destroy_objectex((etch_object*) thisx);
+} 
+
+
+/**
+ * new_etch_serializer() 
+ * etch_serializer constructor
+ */
+etch_serializer* new_etch_serializer(const int objsize) 
+{
+    etch_serializer* newobj = (etch_serializer*) new_object
+        (sizeof(etch_serializer), ETCHTYPEB_SERIALIZER, CLASSID_NONE);
+
+    ((etch_object*)newobj)->destroy = destroy_etch_serializer;
+    newobj->import_value = etchserializer_defimportval;
+    newobj->export_value = etchserializer_defexportval;
+
+    return newobj;
+}
+
+
+
+
+/**
+ * etch_serializer_init() 
+ * generic static intitializer for import export helper serializers.
+ * caller retains ownership of *all* parameters to this method.
+ * @param obj_type type of the object being serialized
+ * @param keyname name of an existing etch_field which will key the import
+ * and export object in its serialization map. 
+ * @param obj_class numeric etch object type and class id of the object 
+   being serialized.  
+ * @param c2tmap a vf's map of numeric class to object type associations.
+ * @param vtor the validator object used to vet objects of this type.
+ * @param new_szr a pointer to the constructor for serializers of the 
+ * specified type.
+ */
+int etch_serializer_init(etch_type* obj_type, const wchar_t* keyname, 
+    const unsigned obj_class, etch_hashtable* c2tmap, etch_validator* vtor, 
+    etch_serializer_ctor new_szr)
+{
+    etch_serializer* newimpexhelper = NULL;
+    /* serializer instantiation is awkward, since we are installing serializers 
+     * to singleton types, but the class to type map is not singleton. 
+     * investigate, and if reasonable, move the c2t maintenance to a higher  
+     * level, and invoke this code only once per type instantiation.
+     * unfortunately a type does not indicate its correpsonding class,
+     * i.e. we know a type is "foo", but the type does not know it maps to
+     * ETCHTYPE_FOO, CLASSID_FOO. so here, the serializers, in their ctors,
+     * determine that mapping, and pass that class here. ideally we can eliminate
+     * both the c2t and class parameters from the serializer initialization.
+     */
+
+    /* get reference to field key having specified name, not owned here */
+    etch_field* szr_key = etchtype_get_field_by_name (obj_type, keyname);
+    if (NULL == szr_key) return -1; 
+ 
+    /* map this class identifier to associated type object */
+    class_to_type_map_put(c2tmap, obj_class, obj_type);
+
+    /* if the type's serializer is already instantiated, we don't want   
+     * to do so again. this is the awkardness commented above. */
+    if (etchtype_get_component_type(obj_type)) return 0; 
+
+    /* set component type for arrays of specified class */
+    etchtype_set_component_type(obj_type, obj_class);
+
+    /* instantiate the new import/export helper */ 
+    newimpexhelper = new_szr(obj_type, szr_key); 
+   
+    /* attach, and assign ownership of, the new helper object to the type */
+    etchtype_set_impexphelper(obj_type, newimpexhelper);
+    
+    return NULL == vtor? 0: /* attach the supplied validator to the type */
+           etchtype_put_validator(obj_type, clone_field(szr_key), (etch_object*) vtor);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * exception serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_exception_export_value() 
+ * export value for any exception
+ * @param objval an etch_exception object. caller owns it,
+ * and presumably will destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+etch_object* etchserializer_exception_export_value (etch_serializer* thisx, etch_object* objval)
+{
+    int result = 0;
+    const int THISINITSIZE = 2;
+    etch_structvalue* structval = NULL;
+    etch_exception* excpobj = NULL;
+    
+
+    if (!is_etch_exception(objval)) 
+    {
+        ETCH_LOG(ETCH_SERIALIZER_CATEGORY, ETCH_LOG_ERROR, "value is not exception\n");
+        return NULL;
+    }
+    excpobj = (etch_exception*) objval;
+    
+    structval = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+    result = structvalue_put(structval, clone_field(thisx->field),((etch_object*)etch_exception_get_message(excpobj))->clone(((etch_object*)etch_exception_get_message(excpobj))));
+    return (etch_object*) structval;
+}
+
+
+/**
+ * etchserializer_exception_import_value() 
+ * import value for any exception.
+ * @param objval an etch_structvalue of appropriate type for the exception.
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported exception. 
+ *
+ * caller owns and must destroy the returned object.  
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+etch_object* etchserializer_exception_import_value
+   (etch_serializer* thisx, etch_object* objval, excptype_t xtype) 
+{
+    wchar_t* unistring = NULL;
+    etch_string* impstring = NULL;
+    etch_exception* exception = NULL;
+    int result;
+
+    etch_structvalue* structval = (etch_structvalue*) objval;
+    if (!is_etch_struct(structval)) return NULL;
+    if (!structvalue_is_type(structval, thisx->type)) return NULL;
+
+    /* fetch the exception string out of the struct. not owned here. */
+    impstring = (etch_string*) structvalue_get (structval, thisx->field);
+    if (!is_etch_string(impstring)) return NULL;
+
+    // TODO: pool
+    result = etch_encoding_transcode_to_wchar(&unistring, impstring->v.value, impstring->encoding, impstring->byte_count, NULL);
+    ETCH_ASSERT(result != -1);
+
+    /* create an exception object from the deserialized string. this object 
+     * manages the exception memory according to flags supplied it. we set 
+     * such a flag here, ETCHEXCP_FREETEXT, indicating that the exception 
+     * owns the text buffer we give it. thus we no longer own unistring */
+    exception = new_etch_exception (xtype);
+
+    etch_exception_set_message(exception, new_stringw(unistring));
+    etch_free(unistring);
+    return (etch_object*) exception;
+}
+
+
+/**
+ * etchserializer_excp_import_value() 
+ * virtual import value for runtime exception.
+ * @param objval an etch_structvalue of type etch runtime exception.
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported exception. 
+ *
+ * caller owns and must destroy the returned object.  
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+etch_object* etchserializer_excp_import_value(etch_serializer* thisx, etch_object* objval) 
+{
+    return etchserializer_exception_import_value(thisx, objval, EXCPTYPE_BUILTIN);
+}
+
+
+
+/**
+ * new_exception_serializer() 
+ * etch_serializer_excp constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_exception_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    ((etch_object*)newobj)->class_id = CLASSID_SERIALIZER_EXCP;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_exception_export_value;
+    newobj->import_value = etchserializer_excp_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_exception_init() 
+ * static intitializer for runtime exception serializer.
+ * creates the impexp serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (runtime exception)
+ */
+int etch_serializer_exception_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_msg; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_EXCEPTION, CLASSID_EXCEPTION);
+    
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_string_get(0), new_exception_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * runtime exception serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_rtxcp_export_value() 
+ * virtual export value for runtime exception
+ * @param objval a, etchexception blob, caller owns it and presumably will
+ * destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+etch_object* etchserializer_rtxcp_export_value(etch_serializer* thisx, etch_object* objval) 
+{
+    return etchserializer_exception_export_value(thisx, objval);
+}
+
+
+/**
+ * etchserializer_rtxcp_import_value() 
+ * virtual import value for runtime exception.
+ * @param objval an etch_structvalue of type etch runtime exception.
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported exception. 
+ *
+ * caller owns and must destroy the returned object.  
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+etch_object* etchserializer_rtxcp_import_value(etch_serializer* thisx, etch_object* objval) 
+{
+    return etchserializer_exception_import_value(thisx, objval, EXCPTYPE_BUILTIN);
+}
+
+
+/**
+ * new_runtime_exception_serializer() 
+ * etch_serializer_rtxcp constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_runtime_exception_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    ((etch_object*)newobj)->class_id = CLASSID_SERIALIZER_RTXCP;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_rtxcp_export_value;
+    newobj->import_value = etchserializer_rtxcp_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_rtxcp_init() 
+ * static intitializer for runtime exception serializer.
+ * creates the impexp serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (runtime exception)
+ */
+int etch_serializer_rtxcp_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_msg; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_EXCEPTION, CLASSID_RUNTIME_EXCEPTION);
+    
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_string_get(0), new_runtime_exception_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * auth exception serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_authxcp_export_value() 
+ * virtual export value for auth exception
+ * @param objval a, etchexception blob, caller owns it and presumably will
+ * destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+etch_object* etchserializer_authxcp_export_value(etch_serializer* thisx, etch_object* objval) 
+{
+    return etchserializer_exception_export_value(thisx, objval);
+}
+
+
+/**
+ * etchserializer_authxcp_import_value() 
+ * virtual import value for runtime exception.
+ * @param objval an etch_structvalue of type etch runtime exception.
+ * caller retains ownership of this object as with all imports.
+ * @return a nonspecific etch object containing the imported exception. 
+ *
+ * caller owns and must destroy the returned object.  
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+etch_object* etchserializer_authxcp_import_value(etch_serializer* thisx, etch_object* objval) 
+{
+    return etchserializer_exception_import_value(thisx, objval, EXCPTYPE_BUILTIN);
+}
+
+
+/**
+ * new_auth_exception_serializer() 
+ * etch_serializer_auth exception constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_auth_exception_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    ((etch_object*)newobj)->class_id = CLASSID_SERIALIZER_AUTHXCP;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_authxcp_export_value;
+    newobj->import_value = etchserializer_authxcp_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_authxcp_init() 
+ * static intitializer for auth exception serializer.
+ * creates the impexp serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (runtime exception)
+ */
+int etch_serializer_authxcp_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_msg; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_EXCEPTION, CLASSID_AUTH_EXCEPTION);
+
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_string_get(0), new_auth_exception_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * list serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_list_export_value() 
+ * virtual export value for list
+ * @param objval an etch_arraylist containing values to export to tdo. 
+ * caller retains ownership of this object; this method however sets the readonly
+ * mark on this object, such that it will not destroy its content, which was
+ * assigned to the arraylist wrapped in the returned struct. 
+ * the c binding internally models a list type as an etch_arraylist.
+ * @return the exported structvalue object, containing an etch_arraylist. 
+ * since we can't pass around raw arrays as does the java binding in this case,
+ * this serializer chooses to use an arraylist as the export object type for lists.
+ * while it may seem convoluted that the exported from and exported to objects are
+ * the same object type (not the same object however), the reason is the vf export
+ * interface contract, i.e. caller relinquishes memory for the export from object,
+ * and acquires memory for the export to objects.
+ */
+etch_object* etchserializer_list_export_value(etch_serializer* thisx, etch_object* objval) 
+{
+    const int THISINITSIZE = 2;
+    int result = 0;
+    
+    etch_arraylist* listobj = NULL;
+    etch_nativearray* param = NULL;
+	etch_iterator* iterator = NULL;
+    etch_structvalue* outstruct = NULL;
+	etch_object* current = NULL;
+	int i = 0;
+    
+	if (!is_etch_arraylist(objval)) return NULL;
+	listobj = (etch_arraylist*) objval;
+	
+	param = new_etch_nativearray(CLASSID_ARRAY_OBJECT, sizeof(etch_object*),1,listobj->count,0,0);
+    
+	param->content_obj_type = ETCHTYPEB_PRIMITIVE;
+	param->content_class_id = CLASSID_OBJECT;
+
+    //take ownership of elements
+    listobj->is_readonly = TRUE;
+    param->is_content_owned = TRUE;
+
+    iterator = new_iterator(listobj, &listobj->iterable);
+
+	while(iterator->has_next(iterator)){
+		current = iterator->current_value;
+
+		param->put1(param,&current,i++);
+		iterator->next(iterator);
+	}
+    etch_object_destroy(iterator);
+
+    /* assign ownership of the new list to the returned struct */
+    outstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+
+	result = structvalue_put(outstruct, clone_field(thisx->field), (etch_object*) param);
+    return (etch_object*) outstruct; /* caller owns this structvalue */
+}
+
+
+/**
+ * etchserializer_list_import_value() 
+ * virtual import value for etch list.
+ * @param objval an etch_structvalue of type etch list.
+ * caller retains ownership of this object as with all imports.
+ * @return a *disposable* etch_arraylist containing the imported data objects. 
+ *
+ * note that the c binding works a bit differently that does the java here.
+ * java tdi populates the structvalue with an object[]. in c the tdi inserts a 
+ * synchronized etch_arraylist to the structvalue. 
+ */
+etch_object* etchserializer_list_import_value(etch_serializer* thisx, etch_object* objval) 
+{
+    etch_arrayvalue* inarray = NULL;
+	etch_arraylist* outarray = NULL;
+    etch_structvalue* instruct = (etch_structvalue*) objval;
+	etch_iterator iterator;
+	etch_object* current = NULL;
+
+    if (!is_etch_struct(instruct)) return NULL;
+    if (!structvalue_is_type(instruct, thisx->type)) return NULL;
+
+    /* fetch the arrayvalue from the struct. struct owns it. */
+    inarray = (etch_arrayvalue*) structvalue_get(instruct, thisx->field);
+	if (!is_etch_arrayvalue(inarray)) return NULL;
+
+	outarray = new_etch_arraylist(0,0);
+	arrayvalue_set_iterator(inarray, &iterator);
+	while(iterator.has_next(&iterator)){
+		current = iterator.current_value;
+		etch_arraylist_add(outarray,current);
+		iterator.next(&iterator);
+	}
+	
+    /* value factory import_custom_value() will destroy() the import struct
+     * which will call destructors on its content. we mark the import list
+     * object such that its content will not be destroyed with it, since
+     * we just copied that content to the return list */
+    arrayvalue_set_static_content(inarray, TRUE);
+
+    return (etch_object*) outarray;  /* caller owns the returned list */
+}
+
+
+/**
+ * new_list_serializer() 
+ * etch_serializer_list constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_list_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    ((etch_object*)newobj)->class_id = CLASSID_SERIALIZER_LIST;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_list_export_value;
+    newobj->import_value = etchserializer_list_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_list_init() 
+ * static intitializer for list serializer.
+ * creates the list impex serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (list)
+ */
+int etch_serializer_list_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* key_name = str_values; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_ETCHLIST, CLASSID_ETCH_LIST);
+
+    return etch_serializer_init(thistype, key_name, thisclass, c2tmap, 
+        etchvtor_object_get(1), new_list_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * map serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_map_export_value() 
+ * virtual export value for etch map
+ * @param objval an etch_hashtable containing values to export. caller owns it,
+ * and presumably will destroy it on return from this method. this method marks
+ * this object such that its destructor will not destroy its content objects, 
+ * ownership of which is transferred here to the returned arraylist.
+ * @return the exported structvalue object in which the lone entry is an
+ * etch_arraylist containing the map keys and values as consecutive entries.
+ * caller owns this returned structvalue.
+ */
+etch_object* etchserializer_map_export_value(etch_serializer* thisx, etch_object* objval) 
+{
+    int result = 0, mapsize = 0, listsize = 0, is_expected_maptype = 0;
+    etch_iterator iterator;
+    const int THISINITSIZE = 2;
+    const int is_this_a_set = (thisx->type->id == builtins._mt__etch_set->id);
+    etch_hashtable* impmap  = NULL;
+    etch_nativearray* explist = NULL;
+    etch_structvalue* expstruct = NULL;
+    int i = 0;
+    if (!is_etch_hashtable(objval)) return NULL;
+
+    impmap   = (etch_hashtable*) objval;
+    mapsize  = etchmap_count(impmap);
+    listsize = is_this_a_set? mapsize: mapsize * 2;
+
+
+    /* the underlying hashtable for an etch map must be explicitly marked 
+     * as having object-key, object-value content, since the export list
+     * content is object-key, object-value, object-key, object value, etc. */
+    is_expected_maptype = is_this_a_set?
+        impmap->content_type == ETCHHASHTABLE_CONTENT_OBJECT_NONE:
+        impmap->content_type == ETCHHASHTABLE_CONTENT_OBJECT_OBJECT;
+    if (!is_expected_maptype) return NULL;
+   
+    /* create native array for export, marked such that 
+     * destructors will not be called on list content */
+    explist = new_etch_nativearray(CLASSID_ARRAY_OBJECT, sizeof(etch_object*),1,listsize,0,0);
+    explist->content_obj_type = ETCHTYPEB_PRIMITIVE;
+    explist->content_class_id = CLASSID_OBJECT;
+
+    set_iterator(&iterator, impmap, &impmap->iterable);
+
+    while(iterator.has_next(&iterator))  /* copy map data to array */
+    {   
+		explist->put1(explist,&iterator.current_key,i++);
+        if  (!is_this_a_set)
+		{
+			explist->put1(explist,&iterator.current_value,i++);
+		}
+        iterator.next(&iterator);
+    }
+
+    /* mark caller's map such that it will not destroy its content, 
+     * ownership of which we just transferred to the export array */
+    impmap->is_readonly_keys = impmap->is_readonly_values = TRUE;
+    impmap->freehook = etch_noop_clear_handler;
+    
+    expstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+
+    /* here we assign ownership of the new arraylist to the struct */
+    result = structvalue_put(expstruct, clone_field(thisx->field), (etch_object*)explist);
+
+    return (etch_object*) expstruct; /* caller owns this structvalue */
+}
+
+
+/**
+ * etchserializer_map_import_value() 
+ * virtual import value for etch map.
+ * @param objval an etch_structvalue of type etch map, wrapping a
+ * single entry of etch_arrayvalue, wrapping an etch_arraylist in which
+ * consecutive entries represent a map key and a map value. this method
+ * will mark the arraylist such that it will not destroy its object content.
+ * caller retains ownership of this object as with all imports.
+ * @return a disposable etch_hashtable containing the imported data objects.
+ * caller must cast it and destroy it. 
+ *
+ * note that the c binding works a bit differently that does the java here.
+ * java tdi populates the structvalue with an object[]. in c the tdi inserts a 
+ * synchronized etch_arraylist wrapped by an etch_arrayvalue, to the structvalue. 
+ */
+etch_object* etchserializer_map_import_value(etch_serializer* thisx, etch_object* objval) 
+{
+    int i = 0, result = 0, listcount = 0;
+    etch_hashtable* expmap = NULL;
+    etch_arrayvalue* implist = NULL;
+    etch_structvalue* impstruct = NULL;
+    const int is_this_a_set = thisx->type->id == builtins._mt__etch_set->id;
+    if (!is_etch_struct(objval)) return NULL;
+
+    impstruct = (etch_structvalue*) objval;
+    if (!structvalue_is_type(impstruct, thisx->type)) return NULL;
+
+    /* get the synchronized arraylist out of the struct and mark the list 
+     * such that it no longer owns its object content, ownership of which we
+     * are transferring to the exported map. 
+     */
+    implist = (etch_arrayvalue*) structvalue_get(impstruct, thisx->field);
+    if (!is_etch_arrayvalue(implist)) return NULL;
+    arrayvalue_set_static_content(implist, TRUE);
+	listcount = implist->list->count;
+
+    /* instantiate a map configured appropriately for the import data */
+    /* todo code a new_synchronized_map() constructor and use it here */
+    if(is_this_a_set) {
+        expmap = new_etch_set(listcount);
+    }
+    else {
+        expmap = new_etch_map(listcount / 2);
+    }
+    expmap->content_obj_type = implist->content_obj_type;
+    expmap->content_class_id = implist->content_class_id;  
+
+    while(i < (const int) listcount) /* copy data objects to the map */ 
+    {   
+		etch_object* key = arrayvalue_get(implist, i++);
+        if (NULL == key) continue;
+        
+        if  (is_this_a_set)
+            result = etchmap_set_add(expmap, key);
+        else
+            result = etchmap_map_add(expmap, key, arrayvalue_get(implist, i++));
+
+        if (-1 == result)
+            ETCH_LOG(ETCH_SERIALIZER_CATEGORY, ETCH_LOG_ERROR, "map insert error on key %u", key);
+    }
+    return (etch_object*) expmap;
+}
+
+/**
+ * new_map_serializer() 
+ * etch_serializer_map constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_map_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    ((etch_object*)newobj)->class_id = CLASSID_SERIALIZER_MAP;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_map_export_value;
+    newobj->import_value = etchserializer_map_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_map_init() 
+ * static intitializer for map serializer.
+ * creates the map serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (map)
+ */
+int etch_serializer_map_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_keys_values; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_ETCHMAP, CLASSID_ETCH_MAP);
+   
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_object_get(1), new_map_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * set serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_set_export_value() 
+ * virtual export value for etch set
+ * @param objval an etch_hashtable containing values to export. caller owns it,
+ * and presumably will destroy it on return from this method. this method marks
+ * the map object such that it will not destroy its content objects.
+ * @return the exported structvalue object in which the lone entry is an
+ * etch_arrayvalue containing the map keys
+ * caller owns memory for the returned object.
+ */
+etch_object* etchserializer_set_export_value(etch_serializer* thisx, etch_object* objval) 
+{
+    return etchserializer_map_export_value(thisx, objval); /* caller owns */
+}
+
+
+/**
+ * etchserializer_set_import_value() 
+ * virtual import value for etch set.
+ * @param objval an etch_structvalue of type etch set, wrapping a single entry
+ * of etch_arrayvalue, wrapping an etch_arraylist containing the set values.
+ * this method will mark the arraylist such that it will not destroy its content.
+ * caller retains ownership of this object as with all imports.
+ * @return a disposable etch_hashtable containing the imported data objects.
+ * caller must cast it and destroy it. 
+ * note that the c binding works a bit differently that does the java here.
+ * java tdi populates the structvalue with an object[]. in c the tdi inserts a 
+ * synchronized etch_arraylist wrapped by an etch_arrayvalue, to the structvalue. 
+ */
+etch_object* etchserializer_set_import_value(etch_serializer* thisx, etch_object* objval) 
+{
+    return etchserializer_map_import_value(thisx, objval); 
+}
+
+
+/**
+ * new_set_serializer() 
+ * etch_serializer_set constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_set_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    ((etch_object*)newobj)->class_id = CLASSID_SERIALIZER_SET;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_set_export_value;
+    newobj->import_value = etchserializer_set_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_set_init() 
+ * static intitializer for set serializer.
+ * creates the set serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (set)
+ */
+int etch_serializer_set_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_keys; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_HASHTABLE, CLASSID_ETCH_SET);
+       
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_object_get(1), new_set_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * date serializer
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchserializer_date_export_value() 
+ * virtual export value for date
+ * @param objval an etch_date object for export to tdo. 
+ * caller retains ownership of this object. 
+ * @return the exported structvalue object. caller owns it and must cast it.
+ */
+etch_object* etchserializer_date_export_value(etch_serializer* thisx, etch_object* objval) 
+{
+    const int THISINITSIZE = 2;
+    etch_structvalue* expstruct = NULL;
+    if (!is_etch_date(objval)) return NULL;
+
+    expstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+#ifdef WIN32
+    // assign ownership of the wrapped 64-bit integer to the struct
+    // on win32 systems the time_t struct is a int64
+    structvalue_put(expstruct, clone_field(thisx->field), 
+       (etch_object*) new_int64(((etch_date*)objval)->value));
+#else
+    // assign ownership of the wrapped 32-bit integer to the struct
+    // on linux systems the time_t struct is a int32, to get no negativ
+    // value here, we cast the 32-bit value to unsigned long int
+    structvalue_put(expstruct, clone_field(thisx->field), 
+       (etch_object*) new_int64((unsigned long int)((etch_date*)objval)->value));
+#endif
+    return (etch_object*) expstruct; /* caller owns this structvalue */
+}
+
+
+/**
+ * etchserializer_date_import_value() 
+ * virtual import value for etch date.
+ * @param objval an etch_structvalue of type etch date.
+ * caller retains ownership of this object as with all imports.
+ * @return a *disposable* etch_date object
+ */
+etch_object* etchserializer_date_import_value(etch_serializer* thisx, etch_object* objval) 
+{
+    etch_date* outdate = NULL;
+    etch_int64* timeval = NULL;
+    etch_structvalue* instruct = NULL;
+    if (!is_etch_struct(objval)) return NULL;
+
+    instruct = (etch_structvalue*) objval;
+    if (!structvalue_is_type(instruct, thisx->type)) return NULL;
+
+    /* fetch the arrayvalue out of the struct. struct owns it */
+    timeval = (etch_int64*) structvalue_get(instruct, thisx->field);
+    if (!is_etch_int64(timeval)) return NULL;
+
+    outdate = new_date();
+    outdate->value = (time_t) timeval->value;
+
+    return (etch_object*) outdate;  /* caller owns this object */
+}
+
+
+/**
+ * new_date_serializer() 
+ * etch_serializer_date constructor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_date_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    ((etch_object*)newobj)->class_id = CLASSID_SERIALIZER_DATE;
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_date_export_value;
+    newobj->import_value = etchserializer_date_import_value;
+
+    return newobj;
+}
+
+
+/**
+ * etch_serializer_date_init() 
+ * static intitializer for date serializer.
+ * creates the date serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (date)
+ */
+int etch_serializer_date_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+    const wchar_t* keyname = str_date_time; /* vf static constant */
+    const unsigned thisclass 
+        = ETCHMAKECLASS(ETCHTYPEB_PRIMITIVE, CLASSID_DATE);
+          
+    return etch_serializer_init(thistype, keyname, thisclass, c2tmap, 
+        etchvtor_int64_get(0), new_date_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * misc  
+ * - - - - - - - - - - - - - - - - - -  
+ */
+
+ etch_object* etchserializer_defexportval(etch_serializer* s, etch_object* x)
+{
+    return NULL;
+}
+
+etch_object* etchserializer_defimportval (etch_serializer* s, etch_object* x)
+{
+    return NULL;
+}
+
diff --git a/binding-c/runtime/c/src/main/support/etch_sessionint.c b/binding-c/runtime/c/src/main/support/etch_sessionint.c
new file mode 100644
index 0000000..3eb4b82
--- /dev/null
+++ b/binding-c/runtime/c/src/main/support/etch_sessionint.c
@@ -0,0 +1,231 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sessionint.c
+ * session interface
+ */
+
+#include "etch_sessionint.h"
+#include "etch_default_value_factory.h"
+#include "etch_message.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+/*
+static const char* LOG_CATEGORY = "etch_session";
+*/
+
+int etchsession_def_session_control (void*, etch_event*, etch_object*);
+int etchsession_def_session_notify  (void*, etch_event*);
+etch_object* etchsession_def_session_query (void*, etch_query*);
+
+char* ETCHDSIF = "DSIF";
+
+
+/**
+ * new_default_sessson_interface
+ * return a session interface populated with defaults for virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_session* new_default_session_interface(void* thisx)
+{
+    i_session* newi = etch_malloc(sizeof(i_session), ETCHTYPEB_RAWOBJECT);
+    newi->session_control = etchsession_def_session_control;
+    newi->session_notify  = etchsession_def_session_notify;
+    newi->session_query   = etchsession_def_session_query;
+    newi->thisx = thisx;
+    return newi;    
+}
+
+
+/**
+ * new_session_interface
+ * return a session interface populated with specified virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_session* new_session_interface(void* thisx,
+    etch_session_control sc, etch_session_notify sn, etch_session_query sq)
+{
+    i_session* newi = new_default_session_interface(thisx);
+    if (sc) newi->session_control = sc;
+    if (sn) newi->session_notify  = sn;
+    if (sq) newi->session_query   = sq;
+    return newi;    
+}
+
+
+/**
+ * clone_session() 
+ */
+i_session* clone_session(void* thisx, const i_session* thatsession) 
+{
+    i_session* newsession = thatsession? new_default_session_interface(thisx): NULL;
+
+    if (newsession)
+        memcpy(newsession, thatsession, sizeof(i_session));
+     
+    return newsession;
+}
+
+
+/**
+ * new_default_objsessson_interface
+ * return an objsession interface populated with defaults for virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_objsession* new_default_objsession_interface (void* thisx)
+{
+    i_objsession* newi = etch_malloc(sizeof(i_objsession), ETCHTYPEB_RAWOBJECT);
+    newi->_session_control = etchsession_def_session_control;
+    newi->_session_notify  = etchsession_def_session_notify;
+    newi->_session_query   = etchsession_def_session_query;
+    newi->thisx = thisx;
+    return newi;    
+}
+
+
+/**
+ * new_objsession_interface
+ * return an objsession interface populated with specified virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_objsession* new_objsession_interface (void* thisx,
+    etch_session_control sc, etch_session_notify sn, etch_session_query sq)
+{
+    return (i_objsession*) new_session_interface(thisx, sc, sn, sq);
+}
+
+
+/**
+ * etchsession_get_objinfo()
+ * extract object info from the object passed to session methods.
+ */
+void etchsession_get_objinfo (etch_objsession_objinfo* p, void* evt)
+{
+    memset(p, 0, sizeof(etch_objsession_objinfo));
+    if (NULL == evt) return;
+    p->obj = (etch_object*) evt;
+    ((etch_object*)p)->obj_type = ((etch_object*) evt)->obj_type;
+    ((etch_object*)p)->class_id = ((etch_object*) evt)->class_id;
+
+    if (is_etch_unwantedmsg (p->obj))
+    {   p->msg = (etch_object*) ((etch_unwanted_message*) p->obj)->message;
+        p->whofrom = ((etch_unwanted_message*) p->obj)->whofrom;  
+    }
+    else
+    if (is_etch_message (p->obj))
+        p->msg = p->obj;
+
+    if (is_etch_message (p->msg))
+    {   
+        p->is_message = TRUE; 
+        p->msg_aname  = message_aname ((etch_message*) p->msg);
+
+        if (is_etch_exception(p->msg))
+        {   p->is_exception = TRUE;
+            p->exception = ((etch_exception*) p->msg);
+        }
+        else
+        {   p->resobj = message_get ((etch_message*) p->msg, builtins._mf_result);
+            if (is_etch_exception(p->resobj))
+            {   p->is_exception = TRUE;
+                p->exception = (etch_exception*) p->resobj;
+            }
+        }
+    }     
+}
+
+
+/**
+ * etchsession_destroy_objparam()
+ * identify, log and destroy the specified session parameter object.
+ */
+void etchsession_destroy_objparam (void* evt, char* caller) 
+{
+    char *msgmask = 0, *descrip = 0, *SESSION_ = "session_";
+    etch_objsession_objinfo objinfo;
+    if (NULL == evt) return;
+
+    etchsession_get_objinfo (&objinfo, evt);
+
+    if (objinfo.is_message)
+    {  
+        if (objinfo.is_exception)
+        {   msgmask = "%s%s disposing '%s'\n";
+            descrip = objinfo.exception? etch_exception_get_message((etch_exception*) objinfo.exception)->v.valc: 0;
+        }
+        else
+        {   msgmask = "%s%s disposing message '%s'\n";
+            descrip = objinfo.msg_aname;
+        }
+
+        if (!descrip) descrip = "?";
+        ETCH_LOG(ETCHDSIF, ETCH_LOG_DEBUG, msgmask, SESSION_, caller, descrip);
+    }
+    else
+    {   msgmask = "%s%s disposing type %x class %x\n";
+        ETCH_LOG(ETCHDSIF, ETCH_LOG_XDEBUG, msgmask, SESSION_, caller, 
+                objinfo.obj_type, objinfo.class_id);
+    }
+
+    etch_object_destroy(objinfo.obj);
+    objinfo.obj = NULL;
+
+}
+
+
+/**
+ * etchsession_def_session_control()
+ * @param obj caller this.
+ * @param evt some etch object or null.
+ * @param v some etch object or null.
+ */
+int etchsession_def_session_control (void* obj, etch_event* evt, etch_object* v)
+{
+    etchsession_destroy_objparam (evt, "control");
+    //    ETCHOBJ_DESTROY();
+    if(((etch_object*)v))
+      ((etch_object*)v)->destroy(((etch_object*)v));
+    v = NULL;
+    return 0;
+}
+
+
+/**
+ * etchsession_def_session_notify()
+ * @param obj caller this.
+ * @param evt some etch object or null.
+ */
+int etchsession_def_session_notify  (void* obj, etch_event* evt)
+{
+    etchsession_destroy_objparam (evt, "notify");
+    return 0;
+}
+
+
+/**
+ * etchsession_def_session_query()
+ * @param obj caller this.
+ * @param query some etch object or null.
+ */
+etch_object* etchsession_def_session_query (void* obj, etch_query* query) 
+{
+    etchsession_destroy_objparam (obj, "query");
+    return NULL;
+}
diff --git a/binding-c/runtime/c/src/main/support/etch_simpletimer.c b/binding-c/runtime/c/src/main/support/etch_simpletimer.c
new file mode 100644
index 0000000..e2e8b07
--- /dev/null
+++ b/binding-c/runtime/c/src/main/support/etch_simpletimer.c
@@ -0,0 +1,186 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_simpletimer.c  
+ * thread-per-use one-shot relative timer
+ * this should be replaced with a timer pool implementation when development resources permit 
+ */
+
+#include "etch_simpletimer.h"
+#include "etch_mutex.h"
+#include "etch_exception.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+typedef struct etch_timerdata
+{
+    void* userdata;
+    int   durationms;
+    int   is_started;
+    etch_timer_callback usercallback;
+
+} etch_timerdata;
+
+void   etch_timerproc(void* data);
+etch_timerdata* new_timerdata(const int, void*, etch_timer_callback);
+
+
+
+/**
+ * new_timer() 
+ * etch_timer constructor
+ * @param durationms timer duration in milliseconds.
+ * @param passthrudata user data to be returned in expiration callback.
+ * caller retains ownership of this memory.
+ * @param callback expiration callback void (*callback) (void*, int);
+ * in which creator's passthrudata is passed as the first parameter, and the timeout
+ * reason passed in parameter 2 (reason value 0 is signaled, 1 is timeout, -1 error).
+ * @return the timer object. caller owns this object but must not destroy it until 
+ * after the expiration callback has completed and returned.
+ */
+etch_timer* new_timer(const int durationms, void* passthrudata, etch_timer_callback callback)
+{
+    etch_thread* timer_thread = NULL;
+    etch_timerdata* timerdata = NULL;
+    if (NULL == callback || durationms <= 0) return NULL;
+    timerdata = new_timerdata(durationms, passthrudata, callback);
+
+    /* create thread in wait state */
+    if (NULL == (timer_thread = new_thread(etch_timerproc, timerdata)))
+        etch_free(timerdata);
+    else  /* timerdata wrapper freed in etch_timerproc */
+    {   timer_thread->params.is_own_data = FALSE;
+          /* semikludge to complete thread start and thus avoid crash in the 
+           * event timer is destroyed without having been started. 
+           * surely there is a cleaner way to do this. */
+        etch_sleep(1);
+    }
+
+    return timer_thread;
+}
+
+
+/**
+ * etch_timer_start() 
+ * start the specified timer. a timer must always be explicitly started.
+ */
+int etch_timer_start(etch_timer* timer_thread)
+{
+    int result = -1;
+    etch_thread_params* params = timer_thread? &timer_thread->params: NULL;
+    etch_timerdata* timerdata = params? (etch_timerdata*) params->data: NULL;
+
+    if (timerdata)
+        if (0 == (result = timer_thread->start(timer_thread)))
+            timerdata->is_started = TRUE;
+
+    return result; 
+}
+
+ 
+/**
+ * etch_timer_stop()
+ * signal specified timer to stop waiting and exit its thread. 
+ */
+int etch_timer_stop(etch_timer* timer_thread)
+{
+    int result = -1;
+    etch_wait_t* waiter;
+    if (NULL == timer_thread) return -1;
+    waiter = timer_thread->params.waitobj;
+
+    if (waiter && timer_thread->params.threadstate == ETCH_THREADSTATE_STARTED)
+    {
+        etch_wait_set(waiter, 1);
+        etch_join(timer_thread); //wait until timer thread finished
+    }
+
+    return result;
+}
+
+
+/* - - - - - - - 
+ * private   
+ * - - - - - - - 
+ */
+
+/**
+ * new_timerdata() 
+ * create timer thread data
+ */
+struct etch_timerdata* new_timerdata(const int durationms, void* passthrudata, 
+    etch_timer_callback callback)
+{
+    etch_timerdata* timerdata = etch_malloc(sizeof(etch_timerdata), 0);
+    timerdata->userdata     = passthrudata;
+    timerdata->durationms   = durationms;
+    timerdata->usercallback = callback;
+    timerdata->is_started   = FALSE;
+    return timerdata;
+}
+
+
+/**
+ * etch_timerproc() 
+ * timer thread procedure
+ */
+void etch_timerproc(void* data)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_thread_params* params = (etch_thread_params*) data;
+    etch_timerdata* timerdata = (etch_timerdata*) params->data; 
+    etch_timer_callback usercallback = timerdata->usercallback;
+    etch_thread* threadx = params->etchobj;
+    const int durationms = timerdata->durationms;
+    void* userdata = timerdata->userdata;
+    int   result = 0;
+    ETCH_ASSERT(usercallback);
+
+    if (NULL == threadx->params.waitobj) {
+        // TODO: pool
+        status = etch_wait_create(&threadx->params.waitobj, NULL);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+    }
+    /* start timer and wait for expiration or signal */
+    status = etch_wait_timedwait(threadx->params.waitobj, 1, durationms);
+    switch(status) {
+        // TODO refactor this stuff and remove ETCH_TIMEOUT ..
+        case ETCH_SUCCESS:
+            result = ETCH_INTERRUPTED;
+            break;
+        case ETCH_ETIMEOUT:
+            result = ETCH_TIMEOUT;
+            break;
+        default:
+            result = -1;
+    }
+
+	//ETCHOBJ_FREE();  /* etch_timerdata wrapper */ 
+	if (params->data) 
+		etch_free(params->data); 
+	params->data = NULL;
+    
+
+    etch_wait_destroy(threadx->params.waitobj);
+    threadx->params.waitobj = NULL;
+
+    /* pass ownership of userdata back to user */
+    usercallback(userdata, result);
+}
+
diff --git a/binding-c/runtime/c/src/main/support/etch_sourceint.c b/binding-c/runtime/c/src/main/support/etch_sourceint.c
new file mode 100644
index 0000000..3d0a2f6
--- /dev/null
+++ b/binding-c/runtime/c/src/main/support/etch_sourceint.c
@@ -0,0 +1,101 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sourceint.c
+ * source interface
+ */
+
+#include "etch_sourceint.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+
+/*
+static const char* LOG_CATEGORY = "etch_source_intf";
+*/
+
+void* etch_source_def_get_handler (void* thisx);
+void  etch_source_def_set_handler (void* thisx, void* handler);
+int destroy_i_source(void*);
+
+
+/**
+ * new_default_source_interface
+ * return a source interface populated with defaults for virtuals.
+ * this interface *is* an etch object, use destroy()
+ */
+i_source* new_default_source_interface()
+{
+    i_source* newi = (i_source*) new_object(sizeof(i_source), ETCHTYPEB_SOURCE, CLASSID_SOURCE);
+
+    ((etch_object*)newi)->destroy     = destroy_i_source;
+    newi->get_handler = etch_source_def_get_handler;
+    newi->set_handler = etch_source_def_set_handler;
+    newi->itransport  = new_default_transport_interface();
+    return newi;    
+}
+
+
+/**
+ * new_source_interface
+ * return a source interface populated with specified virtuals.
+ * this interface object *is* an etch object, use destroy()
+ */
+i_source* new_source_interface(void* thisx,
+    etch_source_get_handler gh, etch_source_set_handler sh, i_transport* xp) 
+{
+    i_source* newi = (i_source*) new_object(sizeof(i_source), 
+        ETCHTYPEB_SOURCE, CLASSID_SOURCE);
+
+    ((etch_object*)newi)->destroy     = destroy_i_source;
+    newi->get_handler = gh? gh: etch_source_def_get_handler;
+    newi->set_handler = sh? sh: etch_source_def_set_handler;
+    newi->itransport  = xp? xp: new_default_transport_interface();
+    newi->thisx = thisx;
+    return newi;    
+}
+
+
+/**
+ * destroy_i_source
+ * i_source destructor
+ */
+int destroy_i_source(void* data)
+{
+    i_source* thisx = (i_source*)data;
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx))
+    {   etch_free(thisx->itransport);
+    }
+            
+    return destroy_objectex((etch_object*)thisx);      
+}
+
+
+void* etch_source_def_get_handler (void* thisx) 
+{
+    return NULL;
+}
+
+
+void  etch_source_def_set_handler (void* thisx, void* handler) 
+{ 
+   
+}
+
diff --git a/binding-c/runtime/c/src/main/support/etch_stub.c b/binding-c/runtime/c/src/main/support/etch_stub.c
new file mode 100644
index 0000000..a78892f
--- /dev/null
+++ b/binding-c/runtime/c/src/main/support/etch_stub.c
@@ -0,0 +1,877 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_stub.c
+ * contains the base runtime code for either type of stub.
+ *
+ * the generated stub_xxxx_server will define the thread procedures for each message
+ * type in the service. for each such type, it will set the virtual stub helpers in 
+ * the type objects, to point to these thread functions. each such thread procedure  
+ * will call the user-coded calculation in the impl_xxxx_server for that message  
+ * type; for example, for an "add" message, it will get the fields from the service
+ * value factory which are the arguments to the calculation, call the calculation in
+ * the server impl, insert the result of the calculation into the reply message, and
+ * call the delivery service transport_message to send the reply back to the sender.  
+ */
+
+#include "etch.h"
+#include "etch_svcobj_masks.h"
+#include "etch_stub.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+#include "etch_object.h"
+#include "etch_message.h"
+static const char* LOG_CATEGORY = "etch_stub";
+
+int etchstub_session_notify_ex (void*, void*, etch_event*);
+int etchstub_session_message(void*, etch_who*, etch_message*);
+int etchstub_session_control(void*, etch_event*, etch_object*);
+int etchstub_session_notify (void*, etch_event*);
+etch_object* etchstub_session_query (void*, etch_query*); 
+i_objsession* etchstub_get_session_callbacks_from (void* _obj);
+
+char* scstr = "session control", *snstr = "session notify", *sqstr = "session query";
+char* logmask1 = "%s not routed to client\n", *logmask2 = "%s not registered\n";
+ 
+
+
+#if(0)
+____________________________________________________________________________________
+the inheritance hierarchy becomes indefinite at this point. a stub should be able
+to query a service object for a particular interface, down through its inheritance
+chain. for example, we need to find who has implemented obj_session and call methods
+on it. a use case is a custom transport implemented as a dynamically loaded dll.
+the stub needs therefore to be able to call into objects it has never seen before. 
+
+for the present we will make some assumptions as to the inheritance hierarchy, that
+being that given a service interface, we know its inheritance hierarchy. following
+is a diagram illustrating the inheritance of a service interface named XXXX. 
+all arrows direct down unless indicated by an arrowhead. (e) indicates extends,
+(i) indicates implements. this diagram is upside-down to the way we normally see
+the hierarchy.
+                                     (obj)
+                                       |
+                                     XXXX  <- - - - - - - - - - (stub)
+                                     |  |
+                       (e)  ---------    ----------  (e)
+                           |                       |
+                      XXXX_server            remote_XXXX
+                           |      \ (i)            | (e)
+                       (i) |        ------> remote_XXXX_server             
+  obj_session <--  base_XXXX_server      
+                       (e) |
+                   impl_XXXX_server
+____________________________________________________________________________________
+#endif
+
+
+#if(0)
+
+IMPL_XXXX_SERVER
+   - ctor(REMOTE_XXXX_CLIENT)
+   - usermethod_1_impl(); ...
+   - usermethod_n_impl();
+
+   BASE_XXXX_SERVER
+      - usermethod_1_stub(); ...
+      - usermethod_n_stub();
+      OBJSESSION
+      - _session_control; _session_notify; _session_query; (stubs)
+      XXXX_SERVER
+      - any server-directed methods go here
+         XXXX
+         - see user method impls above
+
+
+STUBXXXX<T extends XXXX> extends STUBBASE<T>
+   - ctor(DeliveryService, pool, pool);
+   - stubhelper();
+
+   STUBBASE<T> (DeliveryService, pool, pool)
+      T obj;
+      DeliveryService, Pool, Pool;
+      stub_helper();  
+
+      STUBPOOLRUNNABLE
+      - set(stub_helper, who, msg); (set state, not in java)
+      - stubhelper(stub, delsvc, obj, who, msg);  
+
+      SESSIONMESSAGE
+      - session_message(who, message); 
+        { stubhelper = message.type.get_helper() 
+          stubhelper(delsvc, obj, who, msg); // the stubhelper impl calls threadpool run()
+        }
+      - session_control; session_notify; session_query;  
+
+
+STUBXXXSERVER  (generated, hand-codable)
+   - ctor(DeliveryService, XXXXSERVER, pool, pool);
+   - for each type in the vf, 
+        -- implement a run method (threadproc) for the message type 
+        -- implement a stub helper method which calls the threadpool run using the threadproc above
+    
+   STUBXXXX
+
+#endif
+
+
+/* - - - - - - - - - - - - - - - - - -  
+ * stub base method implementations
+ * - - - - - - - - - - - - - - - - - -  
+ */ 
+
+/**
+ * destroy_stub()
+ * etch_stub destructor. destroy stub base object.
+ * the stub base does not destroy its xxxx_either_stub wrapper.
+ */
+int destroy_stub(void* data)
+{
+    etch_stub* thisx = (etch_stub*)data;
+
+    if (!is_etchobj_static_content(thisx))
+    {
+        /* note that a delivery service session is the stub's session.
+         * the delivery service owns the stub, and the stub owns this shared
+         * session. the stub wrapper is the session interface's thisx.
+         * the delivery service gets xxxx_either_stub* stubbobj from its  
+         * isessionmsg->thisx, and etch_stub* stubbase from stubobj.stub_base.
+         * destroying the stub will destroy the shared i_sessionmessage, so 
+         * the delivery service's session will become invalid once its stub 
+         * is destroyed. see transport.destroy_delivery_service_stub().
+         */
+        etch_object_destroy(thisx->isessionmsg);
+
+        if (thisx->obj && thisx->is_implobj_owned)
+            etch_object_destroy(thisx->obj);
+    }
+
+    return destroy_objectex((etch_object*) thisx);
+}
+
+
+/**
+ * new_stub()
+ * etch_stub (stub base) constructor.  
+ */
+etch_stub* new_stub (void* implobj, unsigned char stubtype, 
+   i_delivery_service* ids, etch_threadpool* qp, etch_threadpool* fp) 
+{
+    i_sessionmessage* ism = NULL;
+
+    etch_stub* stubbase = (etch_stub*) new_object  
+       (sizeof(etch_stub), ETCHTYPEB_STUB, CLASSID_STUB);
+
+    ETCH_ASSERT(implobj && stubtype && qp && fp);
+    ETCH_ASSERT(is_etch_ideliverysvc(ids));
+
+    stubbase->stub_type = stubtype;
+    ((etch_object*)stubbase)->destroy   = destroy_stub; 
+
+    stubbase->obj = implobj; /* server or client impl e.g. i_xxxx_server* */
+    stubbase->delivery_service  = ids;
+
+    /* instantiate i_sessionmessage session interface. note that the interface's
+     * thisx pointer is this base stub object, and that the base stub's container
+     * xxxx_either_stub* is the base stub.stubobj.
+     */
+    ism = new_sessionmsg_interface (stubbase, etchstub_session_message, NULL); 
+    stubbase->isessionmsg = ism;
+    stubbase->session_message = ism->session_message = etchstub_session_message;
+    stubbase->session_control = ism->session_control = etchstub_session_control;
+    stubbase->session_notify  = ism->session_notify  = etchstub_session_notify;
+    stubbase->session_query   = ism->session_query   = etchstub_session_query;
+
+    /* set delivery service session interface to be the stub's i_sessionmessage.
+     * in a c binding translation from java binding, a reference to a stub object 
+     * is only via via the delivery service's session_message interface, shared
+     * between the stub and the delivery service.  
+     * the delivery service must have provided i_transportmessage implementations,
+     * in particular for set_session(). the instantiator of the delivery service
+     * must therefore override the delivery service's i_transportmessage.
+
+     * fyi: ids->itm->thisx is mailbox manager.
+     * ids->itm is mboxmgr's transport interface, which is the delivery service.
+     * set session of next lower level (delivery service) to the stub's session.
+     */
+    ids->itm->set_session (ids, stubbase->isessionmsg);   
+
+    /* copy impl's i_objsession to the stub for convenience */
+    stubbase->impl_callbacks = etchstub_get_session_callbacks_from (implobj); 
+ 
+    return stubbase;
+}
+
+ 
+/**
+ * etchstub_get_session_callbacks_from()
+ * extract objsession interface from specified stub implementor object.
+ */
+i_objsession* etchstub_get_session_callbacks_from (void* _obj)
+{
+    i_objsession* iobjsession = NULL;
+    etch_object*  obj = (etch_object*) _obj; 
+    const int this_objtype = obj? ((etch_object*)obj)->obj_type: 0;
+
+    switch(this_objtype)
+    {
+        case ETCHTYPEB_EXESERVERIMPL:
+        {    xxxx_server_impl* server_impl = (xxxx_server_impl*) obj;
+             iobjsession = server_impl->iobjsession;
+             break;
+        }
+
+        case ETCHTYPEB_EXECLIENTIMPL:
+        {    xxxx_client_impl* client_impl = (xxxx_client_impl*) obj;
+             iobjsession = client_impl->iobjsession;
+             break;
+        }
+
+        case ETCHTYPEB_EXESERVERBASE:
+        {   i_xxxx_server* iserver = (i_xxxx_server*) obj;
+            xxxx_server_impl* server_impl = (xxxx_server_impl*) iserver->thisx;
+            ETCH_ASSERT(server_impl && ((etch_object*)server_impl)->obj_type == ETCHTYPEB_EXESERVERIMPL);
+            iobjsession = server_impl->iobjsession;
+            break;
+        }
+
+        case ETCHTYPEB_EXECLIENTBASE:
+        {   i_xxxx_client* iclient = (i_xxxx_client*) obj;
+            xxxx_client_impl* client_impl = (xxxx_client_impl*) iclient->thisx;
+            ETCH_ASSERT(client_impl && ((etch_object*)client_impl)->obj_type == ETCHTYPEB_EXECLIENTIMPL);
+            iobjsession = client_impl->iobjsession;
+            break;
+        }
+    }
+
+    return iobjsession;
+}
+ 
+/**
+ * etchstub_put_resultobj
+ * insert specified result object to message.
+ * @param replymsg the message, caller retains.
+ * @param resultobj the result object, caller relinquishes regardless of result.
+ * @return 0 success, -1 failure. 
+ */
+int etchstub_put_resultobj (etch_stub* stub, etch_message* replymsg, etch_object* resultobj)
+{
+    int result = 0;
+    etch_field* key_result = builtins._mf_result;
+
+    /* check if the message already has a result object, i.e., an exception */
+    if (message_get (replymsg, key_result))
+        etch_object_destroy(resultobj);  /* if so, discard the passed result */
+    else  /* resultobj is relinquished here regardless of result */
+        result = message_put (replymsg, clone_field(key_result), (etch_object*) resultobj); 
+
+    return result;
+}
+
+ 
+/**
+ * etchstub_send_reply
+ * private method invoked by all "stub helpers" (message logic implementation 
+ * runners) for messages requiring a reply, in order to instantiate a reply
+ * message and transmit it back to sender.
+ */
+int etchstub_send_reply (etch_stub* stub, i_delivery_service* dsvc, etch_who* whofrom, etch_message* msg, etch_object* resultobj, boolean putResultObj)
+{
+    int result = 0; 
+    const int is_exception_resobj  = is_etch_exception(resultobj);
+    
+    etch_type* newtype = NULL; /* see comment following */
+
+    /* instantiate the reply message  
+     * note that if we are called for a one-way message, it is only if an 
+     * exception was thrown by the implementation, and the exception is 
+     * therefore to be the reply. in such a case, the etch compiler generates
+     * a message type as newtype above, which is the second parameter to 
+     * message_reply(), in order that in_reply_to can be instantiated. 
+     * (our example below makes newtype the 1-way exception reply type in  
+     * this case). for two-way messages, newtype, and thus the second parameter
+     * to message_reply() is null.  
+     */
+    etch_message* replymsg = message_reply (msg, newtype);
+
+    if (NULL == replymsg && is_exception_resobj)
+    {   newtype  = builtins._mt__exception;
+        replymsg = message_reply (msg, newtype);
+    }
+
+    if (NULL == replymsg) {
+        etch_type* replytype = newtype? newtype: message_type(msg);
+        char* logmask = "could not create reply message for type %s\n";
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, logmask, replytype->aname);
+        return -1;
+    }
+
+    if(putResultObj) {
+        result = etchstub_put_resultobj (stub, replymsg, resultobj);
+        if(result){
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "invalid return value.\n");
+            return result;
+        }
+    }
+
+    if (0 == result) {  /* forward reply message for serialization */
+        result = dsvc->itm->transport_message (dsvc, whofrom, replymsg);
+        if(result){
+            etch_object_destroy(replymsg);
+        }
+    } 
+
+    return result;
+}
+
+
+/**
+ * etchstub_validate_args
+ * private method invoked by all "stub helpers" to validate parameters
+ * to the individual stub helper and populate some objects for the helper.
+ */
+int etchstub_validate_args (etch_stub* stub, i_delivery_service* dsvc, 
+    etch_message* msg, void* client, default_value_factory** vf, 
+    void** vfimpl, void** climpl)
+{
+    int result = 0;
+    i_xxxx_client* iclient = NULL;
+    etch_object* clientimpl = NULL, *valufactimpl = NULL;
+    /* any assertion failure in this method indicates a coding error in etch core */
+    ETCH_ASSERT(stub && dsvc && client && msg && stub->params && vf && vfimpl && climpl);  
+
+    iclient = (i_xxxx_client*) client;
+    clientimpl = iclient->thisx;  
+    //HCG Check this for client!
+    //ETCH_ASSERT(is_etch_server_impl(clientimpl));
+    *climpl = clientimpl;
+
+    *vf = (default_value_factory*) stub->params->in_valufact;
+    ETCH_ASSERT(is_etch_valuefact(*vf));
+    valufactimpl = (*vf)->impl;
+    ETCH_ASSERT(is_etch_valuefactimpl(valufactimpl));
+    *vfimpl = valufactimpl;
+
+    return result;
+}
+
+
+/**
+ * etchstub_session_notify_ex()
+ *
+ * @param thisx the object which will receive an exception if any.
+ * may be the same object as _obj. caller retains. 
+ *
+ * @param _obj caller retains. usually a xxxx_server_impl. may be null, or
+ * may be the same object as thisx. obj will belong to a known and limited set  
+ * of classes, e.g. ETCHTYPEB_EXESERVERIMPL, so we can test _obj.obj_type 
+ * if needed, and cast _obj to one of the mask objects (etch_svcobj_masks.h) 
+ * such as xxxx_server_impl, in order to reference the maskable content.
+ * 
+ * @param evt a notification event or a throwable exception, caller relinquishes.
+ *
+ * @return 0 success, -1 failure.
+ */
+int etchstub_session_notify_ex (void* thisx, void* _obj, etch_event* evt)     
+{
+    int result = -1, is_evtparm_relinquished = FALSE;
+
+    /* this call arrives from type "stub helpers" implemented in xxxx_server_stub.
+     * these are thread procedures with arguments delivery service, some object
+     * _obj (possibly implementing objsession or throwable), who, and message, 
+     * viz:  int (*stubhelper) (stub, deliverysvc, _obj, sender, message);  
+     * so from argument _obj, we extract the objsession interface and if present,    
+     * call its _session_notify. 
+     */
+
+    /* a server implementation (xxxx_server_impl) can request notifications of 
+     * exceptions and the like by implementing and registering i_objsession 
+     * callbacks. the presence of these function pointers in the implementation
+     * serves as the indicator of whether to forward the notification.
+     */
+    i_objsession* impl_callbacks = etchstub_get_session_callbacks_from (_obj);  
+
+    etch_session_notify impl_session_notify = impl_callbacks? 
+        impl_callbacks->_session_notify: NULL;
+
+    if (impl_session_notify) /* if impl has requested this event, forward it */
+    {   /* event is relinquished to notify handlers by contract */
+        result = impl_session_notify (impl_callbacks, evt);
+        is_evtparm_relinquished = TRUE;  
+    }else {
+        if(((xxxx_either_impl*)_obj)->_session_notify) {
+            result = ((xxxx_either_impl*)_obj)->_session_notify ((xxxx_either_impl*)_obj, evt);
+            is_evtparm_relinquished = TRUE;  
+        }
+    }
+
+    if (0 != result)
+    {
+        char* logmask = impl_session_notify? logmask1: logmask2;
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, logmask, snstr);
+    }
+
+    if (!is_evtparm_relinquished)  
+	{
+		etch_object_destroy(evt); 
+		evt = NULL;
+		//ETCHOBJ_DESTROY(evt);
+	}
+
+    return result;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - -
+ * stub helper threadpool execution support
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchstub_loghelper()
+ * convenience method to log entry or exit of a stub helper function.
+ */
+void etchstub_loghelper(opaque_stubhelper f, const int result, const int thread_id, const int is_start)
+{
+    if(is_start) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "start stub runner %x [%d]\n", f, thread_id); 
+    } else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "exit stub runner %x (%d) [%d]\n", f, result, thread_id); 
+    }
+}
+
+/**
+ * etchstub_proxy_threadproc()
+ * a thread procedure conforming to the signature expected by etch_threadpool,
+ * which accepts a stub parameter bundle as params.data, unbundles the parameters, 
+ * and invokes the included stub helper function with those parameters.
+ */
+void etchstub_proxy_threadproc (void* data)
+{
+  etch_thread_params* tp = (etch_thread_params*)data;
+    int result = 0;
+    etchstub_runparams* p = tp? tp->data: NULL;
+    ETCH_ASSERT(p && p->run && (p->sig == ETCH_STUBPARAMS_SIGNATURE));
+    etchstub_loghelper (p->run, 0, tp->etch_thread_id, 1);
+
+    /* run "stub helper" procedure */
+    result = p->run (p->stub, p->ds, p->server, p->who, p->msg); 
+
+    etchstub_loghelper (p->run, result, tp->etch_thread_id, 0);
+
+    //tp->etchobj->destroy(tp->etchobj);
+    etch_free(p);
+    
+
+}
+
+
+/**
+ * new_etch_stubparams()
+ * bundle up stub runner parameters in order they can become 
+ * etch_thread_params.data, passed in to the etchstub_proxy_threadproc. 
+ */
+etchstub_runparams* new_etch_stubparams (etch_stub* stub, opaque_stubhelper runproc, 
+    i_delivery_service* ds, i_xxxx_server* server, etch_who* whofrom, etch_message* msg)
+{
+    etchstub_runparams* p = etch_malloc(sizeof(etchstub_runparams), 0); 
+    p->sig  = ETCH_STUBPARAMS_SIGNATURE;
+    p->stub = stub;
+    p->run  = runproc;
+    p->ds   = ds;
+    p->who  = whofrom;
+    p->msg  = msg;
+    p->server = server;
+    return p;
+}
+
+
+/**
+ * etchstub_run()
+ * execute the service method helper function (stub helper). if no threadpool
+ * is specified, execute the helper function inline (on caller's thread);  
+ * otherwise wrap the stub helper arguments and launch a thread on the supplied  
+ * threadpool to execute the helper function.
+ * @param stub caller retains.
+ * @param runproc the service function for this message type. 
+ * @param threadpool caller retains.
+ * @param server caller retains.
+ * @param who caller retains.
+ * @param msg caller retains.
+ * @return 0 success, -1 failure.
+ */
+int etchstub_run (etch_stub* stub, opaque_stubhelper runproc, etch_threadpool* threadpool, 
+    i_xxxx_server* server, etch_who* who, etch_message* msg)
+{
+    int result = 0;
+    i_delivery_service* ds = stub->delivery_service;
+    ETCH_ASSERT(runproc && ds && server && msg);
+
+    if (threadpool)
+    {   
+        /* a pointer to this parameter bundle will become etch_thread_params.data. 
+         * etch_thread_params.is_own_data determines if the thread frees data on exit.
+         * is_own_data assumes the value of threadpool.is_free_data, which is true
+         * by default. so unless we have reset is_free_data on this pool, the pool  
+         * thread will free this allocation at thread exit. and since also by default
+         * pool->is_data_etchobject is false, the deallocation will use etch_free;
+         */
+        etchstub_runparams* p = new_etch_stubparams(stub, runproc, ds, server, who, msg); 
+        etch_thread* poolthread = NULL;
+        threadpool->is_manual_start = TRUE;
+
+        /* run stub helper function on a pool thread */
+        poolthread = threadpool->run (threadpool, etchstub_proxy_threadproc, p);
+
+        //poolthread->is_joined = TRUE;
+        //poolthread->on_exit()
+        poolthread->start(poolthread);
+//        threadpool->is_manual_start = FALSE;
+
+        //if  (poolthread) /* switch context and block on pool thread exit */
+        //{    const int id = poolthread->params.etch_thread_id;
+        //     //etch_log(etchstub, etch_log_xdebug, "stub runner joining pool thread %d ...\n", id);
+        //     etch_join (poolthread);  
+        //}
+        //else result = -1;
+    }
+    else  
+    {   etchstub_loghelper(runproc, 0, 0, 1);
+
+        /* run stub helper function on this thread */
+        result = runproc (stub, ds, server, who, msg); 
+ 
+        etchstub_loghelper(runproc, result, 0, 0); 
+
+    }
+    return result;
+}
+
+
+/* - - - - - - - - - -
+ * i_sessionmessage
+ * - - - - - - - - - - 
+ */
+
+/**
+ * etchstub_session_message()
+ * @param whofrom caller retains, can be null.
+ * @param msg caller relinquishes
+ * @return 0 (message handled), or -1 (error, closed, or timeout)  
+ */
+int etchstub_session_message (void* data, etch_who* whofrom, etch_message* msg)
+{
+    etch_stub* thisx = (etch_stub*)data;
+    xxxx_either_stub* stubimpl   = (xxxx_either_stub*) thisx->stubobj;
+    i_xxxx_server*  serverimpl   = NULL;
+    etch_session* sessionparams  = NULL;
+    opaque_stubhelper stubhelper = NULL;
+    etch_threadpool*  threadpool = NULL;
+    int result = -1, session_id = 0;
+    unsigned char async_mode = 0;
+
+    /* get the message type object associated with this message */
+    etch_type*  thistype = message_type(msg);
+    ETCH_ASSERT(thistype);
+    ETCH_ASSERT(is_etch_stub(stubimpl));
+
+    session_id = stubimpl->owner_id;
+    do
+    { 
+  /* get the message type's stub helper (runner) function.
+         * the stub helper is a pointer to a thread procedure function specific    
+         * to the message type, which executes the associated service method.
+         */
+    if (NULL == (stubhelper = etchtype_get_type_stubhelper (thistype)))
+    {   char* msgmask = "type '%s' missing stub runner procedure\n";
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, msgmask, thistype->aname);
+        break;
+    }
+
+        /* get the thread pool, if any, appropriate for the 
+         * configured mode of execution for this message type 
+         */
+    switch(async_mode = etchtype_get_async_mode (thistype))
+    {   
+        //default:	threadpool = thisx->params->qpool; break;
+		case ETCH_ASYNCMODE_QUEUED: threadpool = thisx->params->qpool; break;
+		case ETCH_ASYNCMODE_FREE:   threadpool = thisx->params->fpool; break;
+        default: threadpool = NULL;
+    }
+
+
+    if(is_etch_client_stub(stubimpl)){
+        result = etchstub_run (thisx, stubhelper, threadpool, ((etch_client_factory*)thisx->params)->iclient, whofrom, msg);
+    }
+    else{
+         
+            get_etch_session (thisx->params, session_id, &sessionparams);
+            ETCH_ASSERT (sessionparams);
+            serverimpl = sessionparams->server;
+
+        /* execute the service method execution function (stub helper),  
+         * either on a thread or inline. 
+         */
+            result = etchstub_run (thisx, stubhelper, threadpool, serverimpl, whofrom, msg);
+        
+    }
+    } while(0);
+    /* this is the end of the line for the message */
+    
+
+    return result;
+}
+
+
+/**
+ * etchstub_session_control()
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+int etchstub_session_control (void* data, etch_event* control, etch_object* value)
+{
+  etch_stub* thisx = (etch_stub*)data;
+    int result = -1, is_params_relinquished = FALSE;
+
+    /* a server implementation (xxxx_server_impl) can request notifications of 
+     * exceptions and the like by implementing and registering i_objsession 
+     * callbacks. the presence of these function pointers in the implementation
+     * serves as the indicator of whether to forward the notification.
+     */
+    i_objsession* impl_callbacks = thisx->impl_callbacks; 
+ 
+    etch_session_control impl_session_control = impl_callbacks? 
+        impl_callbacks->_session_control: NULL;     
+
+    if (impl_session_control) /* if impl has requested this event, forward it */
+        if (0 == (result = impl_session_control (impl_callbacks, control, value)))
+            is_params_relinquished = TRUE;
+
+    if (0 != result)
+    {   char* logmask = impl_session_control? logmask1: logmask2;
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, logmask, scstr);
+    }
+
+    if (!is_params_relinquished) 
+    {   
+	    etch_object_destroy(control);
+        control = NULL;
+
+        etch_object_destroy(value);
+        value = NULL;
+    }
+
+    return result;
+}
+
+
+/**
+ * etch_etchstub_session_notify()
+ * @param evt event, caller relinquishes.
+ */
+int etchstub_session_notify(void* data, etch_event* evt)
+{
+  etch_stub* thisx = (etch_stub*)data;
+    const int result = etchstub_session_notify_ex (thisx, thisx->obj, evt);
+    return result;
+}
+
+
+/**
+ * etch_etchstub_session_query()
+ * @param query, caller relinquishes.
+ */
+etch_object* etchstub_session_query (void* data, etch_query* query) 
+{
+  etch_stub* thisx = (etch_stub*)data;
+   etch_object* resultobj = NULL;
+   int is_params_relinquished = FALSE;
+
+    /* a server implementation (xxxx_server_impl) can request notifications of 
+     * exceptions and the like by implementing and registering i_objsession 
+     * callbacks. the presence of these function pointers in the implementation
+     * serves as the indicator of whether to forward the notification.
+     */
+    i_objsession* impl_callbacks = thisx->impl_callbacks;
+ 
+    etch_session_query impl_session_query = impl_callbacks? 
+        impl_callbacks->_session_query: NULL;
+
+    if (impl_session_query) /* if impl has requested this event, forward it */
+        if (NULL != (resultobj = impl_session_query (impl_callbacks, query)))
+            is_params_relinquished = TRUE;
+
+    if (NULL == resultobj)
+    {   char* logmask = impl_session_query? logmask1: logmask2;
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, logmask, sqstr);
+    }
+
+    if (!is_params_relinquished) {
+      etch_object_destroy(query);
+      query = NULL;
+    }
+
+    return resultobj;
+}
+
+
+/* - - - - - - - - - - - - - - -  
+ * constructors, destructor 
+ * - - - - - - - - - - - - - - -  
+ */ 
+
+/**
+ * destroy_stub_object()
+ * stub implementation private destructor.
+ * calls back to hand-coded destructor for possible custom deallocation,
+ * then destroys the stub base, including the shared session interface.
+ */
+int destroy_stub_object (void* thisx)
+{
+    xxxx_either_stub* stubobj = NULL;
+    if (NULL == thisx) return -1;
+
+    stubobj = (xxxx_either_stub*) thisx;
+    if (!is_etch_stub(thisx)) return -1;
+
+    if (!is_etchobj_static_content(stubobj))
+    {    
+        if (stubobj->destroyex) /* call back to user dtor */
+            stubobj->destroyex(thisx);
+
+        if (stubobj->stub_base)
+            etch_object_destroy(stubobj->stub_base);
+    }
+            
+    return destroy_objectex((etch_object*)stubobj);
+} 
+
+
+/**
+ * is_etch_stub()
+ */
+int is_etch_stub(void* x)
+{
+    int result = FALSE, objtype = x? ((etch_object*)x)->obj_type: 0;
+    switch(objtype)
+    { case ETCHTYPEB_STUB: case ETCHTYPEB_CLIENTSTUB: case ETCHTYPEB_SERVERSTUB:
+           result = TRUE;
+    }
+    return result;
+}
+
+
+/**
+ * new_stubimpl_init()
+ * generic stub implementation constructor
+ * @param implobj i_xxxx_client* or i_xxxx_server*.
+ * @param objsize number of bytes in the stub object implementation. 
+ * all we know about here is the mask, or object header if you will.
+ * @param stubtype ETCH_STUBTYPE_CLIENT or ETCH_STUBTYPE_SERVER.
+ * @param userdtor a hand-coded callback in the implementation conforming 
+ * to signature etch_destructor, for the purpose of freeing any custom 
+ * memory allocations.
+ * @param ids the delivery service, caller retains.
+ * @param qp the queued thread pool, optional, caller retains. 
+ * @param fp the free thread pool, optional, caller retains. 
+ * @param params a etch_server_factory* parameter bundle, caller retains.
+ * if it is always the case that this parameter is present and is a
+ * etch_server_factory*, we can lose the ids, qp, and fp ctor parameters.
+ */
+void* new_stubimpl_init (void* implobj, const int objsize, 
+      const unsigned char stubtype, etch_object_destructor userdtor,
+      i_delivery_service* ids, etch_threadpool* qp, etch_threadpool* fp, 
+      void* params)  
+{
+    unsigned short obj_type, class_id;
+    xxxx_either_stub* newstub = NULL;
+
+    switch(stubtype)
+    {  
+        case ETCH_STUBTYPE_CLIENT:
+             obj_type = ETCHTYPEB_CLIENTSTUB;
+             class_id = CLASSID_CLIENTSTUB;
+             break;
+        case ETCH_STUBTYPE_SERVER:
+             obj_type = ETCHTYPEB_SERVERSTUB;
+             class_id = CLASSID_SERVERSTUB;
+             break;
+        default: return NULL;
+    }
+
+    newstub = (xxxx_either_stub*) new_object (objsize, obj_type, class_id);  
+    ((etch_object*)newstub)->destroy   = destroy_stub_object; /* private */
+    newstub->destroyex = userdtor;           /* public */
+    newstub->stub_base = new_stub (implobj, stubtype, ids, qp, fp);
+    newstub->stub_base->stubobj = (etch_object*) newstub;
+    newstub->stub_base->params  = params;
+ 
+    return newstub;
+}
+
+
+/**
+ * new_clientstub_init()
+ * generic client stub implementation constructor.
+ * @param bytelen number of bytes in the client stub object implementation. 
+ * all we know about here is the mask, or object header if you will.
+ * @param dtor a hand-coded callback in the implementation conforming 
+ * to signature etch_destructor, for the purpose of freeing any custom 
+ * memory allocations.
+ * @param ids the delivery service, caller retains.
+ * @param qp the queued thread pool, optional, caller retains. 
+ * @param fp the free thread pool, optional, caller retains. 
+ * @param params a etch_server_factory* parameter bundle, caller retains.
+ * if it is always the case that this parameter is present and is a
+ * etch_server_factory*, we can lose the ids, qp, and fp ctor parameters.
+ */
+void* new_clientstub_init (void* implobj, const int bytelen, etch_object_destructor dtor, 
+    i_delivery_service* ids, etch_threadpool* qp, etch_threadpool* fp, void* params)  
+{
+    return new_stubimpl_init (implobj, bytelen, ETCH_STUBTYPE_CLIENT, 
+        dtor, ids, qp, fp, params);  
+}
+
+
+/**
+ * new_serverstub_init()
+ * generic server stub implementation constructor.
+ * @param bytelen number of bytes in the server stub object implementation. 
+ * all we know about here is the mask, or object header if you will.
+ * @param dtor a hand-coded callback in the implementation conforming 
+ * to signature etch_destructor, for the purpose of freeing any custom 
+ * memory allocations.
+ * @param ids the delivery service, caller retains.
+ * @param qp the queued thread pool, optional, caller retains. 
+ * @param fp the free thread pool, optional, caller retains. 
+ * @param params a etch_server_factory* parameter bundle, caller retains.
+ * if it is always the case that this parameter is present and is a
+ * etch_server_factory*, we can lose the ids, qp, and fp ctor parameters.
+ */
+void* new_serverstub_init (void* implobj, const int bytelen, etch_object_destructor dtor, 
+    i_delivery_service* ids, etch_threadpool* qp, etch_threadpool* fp, void* params)  
+{
+    return new_stubimpl_init (implobj, bytelen, ETCH_STUBTYPE_SERVER, 
+        dtor, ids, qp, fp, params);  
+}
+
+
+
diff --git a/binding-c/runtime/c/src/main/support/etch_transportint.c b/binding-c/runtime/c/src/main/support/etch_transportint.c
new file mode 100644
index 0000000..42bd910
--- /dev/null
+++ b/binding-c/runtime/c/src/main/support/etch_transportint.c
@@ -0,0 +1,130 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_transportint.c
+ * transport interface
+ */
+
+#include "etch_transportint.h"
+#include "etch_sessionint.h"
+#include "etch_mem.h"
+#include "etch_session_message.h"
+
+int etchtransport_def_transport_control    (void*, etch_event*, etch_object*);
+int etchtransport_def_transport_notify     (void*, etch_event*);
+etch_object* etchtransport_def_transport_query (void*, etch_query*);
+
+i_session* etchtransport_def_get_session(void* thisx);
+void  etchtransport_def_set_session(void* thisx, void* session);
+
+
+/**
+ * new_default_transport_interface
+ * return a transport interface populated with defaults for virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_transport* new_default_transport_interface(void* thisx)
+{
+    i_transport* newi = etch_malloc(sizeof(i_transport), ETCHTYPEB_RAWOBJECT);
+
+    newi->transport_control = etchtransport_def_transport_control;
+    newi->transport_notify  = etchtransport_def_transport_notify;
+    newi->transport_query   = etchtransport_def_transport_query;
+    newi->get_session = etchtransport_def_get_session;
+    newi->set_session = etchtransport_def_set_session;
+    newi->thisx = thisx;
+    return newi;    
+}
+
+
+/**
+ * new_transport_interface
+ * return a transport interface populated with specified virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_transport* new_transport_interface(void* thisx,
+  etch_transport_control sc, etch_transport_notify sn, etch_transport_query sq)
+{
+    i_transport* newi = new_default_transport_interface(thisx);
+
+    if (sc) newi->transport_control = sc;
+    if (sn) newi->transport_notify  = sn;
+    if (sq) newi->transport_query   = sq;
+    return newi;    
+}
+
+
+/**
+ * new_transport_interface_ex
+ * return a transport interface populated with specified virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_transport* new_transport_interface_ex(void* thisx, 
+  etch_transport_control sc, etch_transport_notify sn, etch_transport_query sq,
+  etch_transport_get_session gs, etch_transport_set_session ss)
+{   
+    i_transport* newi = new_transport_interface(thisx, sc, sn, sq);
+
+    if (gs) newi->get_session = gs;
+    if (ss) newi->set_session = ss;
+    return newi;    
+}
+
+
+/**
+ * clone_transport() 
+ */
+i_transport* clone_transport(void* thisx, const i_transport* thattransport) 
+{
+    i_transport* newtransport 
+        = thattransport? new_default_transport_interface(thisx): NULL;
+
+    if (newtransport)
+        memcpy(newtransport, thattransport, sizeof(i_transport));
+     
+    return newtransport;
+}
+
+
+int etchtransport_def_transport_control (void* obj, etch_event* evt, etch_object* v)
+{
+    return -1;
+}
+
+int etchtransport_def_transport_notify  (void* obj, etch_event* evt)
+{
+    return -1;
+}
+
+
+etch_object* etchtransport_def_transport_query (void* obj, etch_query* query) 
+{
+    return NULL;
+}
+
+
+i_session* etchtransport_def_get_session(void* thisx) 
+{
+    return NULL;
+}
+
+
+void etchtransport_def_set_session(void* thisx, void* session)
+{
+}
diff --git a/binding-c/runtime/c/src/main/transport/etch_connection.c b/binding-c/runtime/c/src/main/transport/etch_connection.c
new file mode 100644
index 0000000..2c5c2b7
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_connection.c
@@ -0,0 +1,243 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_connection.c
+ * connection client and server classes - tcp, udp
+ */
+#include "etch.h"
+#include "etch_runtime.h"
+#include "etch_thread.h"
+#include "etch_connection.h"
+#include "etch_encoding.h"
+#include "etch_flexbuffer.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+static const char* LOG_CATEGORY = "etch_connection";
+
+// extern types
+extern etch_pool_t*        g_etch_main_pool;
+extern apr_thread_mutex_t* g_etch_main_pool_mutex;
+
+const wchar_t* ETCH_CONNECTION_RECONDELAY   = L"TcpConnection.reconnect_delay";
+const wchar_t* ETCH_CONNECTION_AUTOFLUSH    = L"TcpConnection.autoFlush";
+const wchar_t* ETCH_CONNECTION_KEEPALIVE    = L"TcpConnection.keepAlive";
+const wchar_t* ETCH_CONNECTION_LINGERTIME   = L"TcpConnection.lingerTime";
+const wchar_t* ETCH_CONNECTION_NODELAY      = L"TcpConnection.noDelay";
+const wchar_t* ETCH_CONNECTION_TRAFCLASS    = L"TcpConnection.trafficClass";
+const wchar_t* ETCH_CONNECTION_BUFSIZE      = L"TcpConnection.bufferSize";
+const wchar_t* ETCH_TCPLISTENER_BACKLOG     = L"TcpListener.backlog";
+
+unsigned next_etch_connection_id();
+
+unsigned connection_id_farm;
+
+/*
+ * is_good_tcp_params()
+ */
+int is_good_tcp_params(etch_url* url, void* resources, etch_rawsocket* socket)
+{
+    int whicherr = 0;
+
+    if (NULL == socket)
+    {
+        if (NULL == url->host) whicherr  = 0x1; 
+        if (url->port <= 0 || url->port > 0xffff) whicherr |= 0x2; 
+    }
+
+    return whicherr == 0;
+}
+
+
+/*
+ * etch_socket_set_timeout
+ * set timeout for specified socket
+ */
+int etch_socket_set_timeout(etch_rawsocket* socket, const unsigned ms)
+{
+    const int result = apr_socket_timeout_set(socket, ms * 1000);
+    return 0 == result? 0: -1;
+}
+
+
+/*
+ * etch_socket_get_timeout
+ * get timeout set on specified socket
+ */
+int etch_socket_get_timeout(etch_rawsocket* socket, unsigned* retms)
+{
+    int64 val = 0;
+    if (0 != apr_socket_timeout_get(socket, &val)) return -1;
+    if (retms) *retms = (unsigned) (val / 1000);
+    return 0;  
+}
+
+
+/**
+ * etchconx_set_socket_options()
+ */
+int etchconx_set_socket_options(void *c)
+{
+    return 0;
+}
+
+
+/**
+ * next_etch_connection_id()
+ * return a unique ID used to identify a connection instance
+ */
+unsigned next_etch_connection_id()
+{
+    do { apr_atomic_inc32 ((volatile apr_uint32_t*) &connection_id_farm);
+       } while(connection_id_farm == 0); 
+
+    return connection_id_farm;
+}
+
+
+/**
+ * etch_defconx_on_data()
+ * default receive data handler  
+ */
+int etch_defconx_on_data (void* conx, const int unused, int length, void* voidData)
+{
+    char* msgmask = "connxn %d no data handler provided for %d bytes\n";
+    etch_connection* cx = (etch_connection*) conx;
+    ETCH_ASSERT(is_etch_connection(cx));
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_WARN, msgmask, cx->conxid, length);
+    return 0;
+}
+
+
+/*
+ * etch_defconx_on_event()
+ * default handler for connection events
+ */
+int etch_defconx_on_event (void* c, const int e, int p1, void* p2)
+{
+    return 0;
+}
+
+/*
+ * etchconx_wait_up() 
+ * block until connection comes up or timeout
+ */
+int etchconx_wait_up(etch_connection* cx, int timeoutms)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    status = etch_wait_timedwait(cx->wait_up, ETCH_CONXEVT_UP, timeoutms);
+    if(status != ETCH_SUCCESS) {
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * etchconx_wait_down() 
+ * block until connection is closed or timeout
+ */
+int etchconx_wait_down(etch_connection* cx, int timeoutms)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    status = etch_wait_timedwait(cx->wait_down, ETCH_CONXEVT_DOWN, timeoutms);
+    if(status != ETCH_SUCCESS) {
+        return -1;
+    }
+    return 0;
+}
+
+/*
+ * etch_destroy_connection() 
+ * free memory owned by connection.
+ */
+int etch_destroy_connection(etch_connection* cx)
+{
+    if (cx)
+    {
+        etch_wait_destroy(cx->wait_up);
+        etch_wait_destroy(cx->wait_down);
+        etch_mutex_destroy(cx->mutex);
+        etch_free(cx->hostname);
+        /* free apr subpool */
+        //printf("5 destroying apr pool %p\n",cx->aprpool);
+        apr_pool_destroy(cx->aprpool);
+        
+    }
+    return 0;
+}
+
+/*
+ * etch_init_connection()  
+ * initialize an etch_connection (abstract base)
+ */
+int etch_init_connection (etch_connection* cx, etch_rawsocket* socket, void* owner)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    memset(cx, 0, sizeof(etch_connection));
+
+    cx->conxid = next_etch_connection_id();
+    cx->owner  = owner;
+
+    // TODO: pool handling
+
+    /* set memory pool used for APR objects associated with this connection.
+     * if the connection is being created with an existing socket, use the
+     * memory pool already assigned to it, otherwise partition a new subpool. 
+     * if connection allocates a subpool, connection will free it on destroy.
+     */
+    if (socket) {
+        cx->aprpool = apr_socket_pool_get(socket);
+    }
+
+    if (cx->aprpool == NULL) {
+        // TODO: pool
+        apr_pool_create(&cx->aprpool, g_etch_main_pool);
+        //printf("3 creating apr pool %p\n",cx->aprpool);
+        /* set pool abort function */
+        apr_pool_abort_set(etch_runtime_mem_abort, cx->aprpool);
+        
+        cx->is_ownpool = TRUE;
+    }
+
+    if (cx->aprpool == NULL)
+    {   cx->aprpool = g_etch_main_pool;
+        cx->is_ownpool = FALSE;
+    }
+
+    cx->sig      = ETCH_CONX_SIG;
+
+    // TODO: pool
+    status = etch_mutex_create(&cx->mutex, ETCH_MUTEX_NESTED, NULL);
+    ETCH_ASSERT(status == ETCH_SUCCESS);
+    // TODO: pool
+    status = etch_wait_create(&cx->wait_up, NULL);
+    ETCH_ASSERT(status == ETCH_SUCCESS);
+    // TODO: pool
+    status = etch_wait_create(&cx->wait_down, NULL);
+    ETCH_ASSERT(status == ETCH_SUCCESS);
+
+    cx->bufsize  = ETCH_CONX_DEFAULT_BUFSIZE;
+    cx->on_event = etch_defconx_on_event;
+    cx->on_data  = etch_defconx_on_data;
+    cx->set_socket_options = etchconx_set_socket_options;
+    return 0;
+}
+
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_connection_event.c b/binding-c/runtime/c/src/main/transport/etch_connection_event.c
new file mode 100644
index 0000000..251cee4
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_connection_event.c
@@ -0,0 +1,336 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_conxevent.c
+ * event handler overrides for the various connection superclasses
+ */
+
+#include "etch_thread.h"
+#include "etch_tcp_connection.h"
+#include "etch_tcp_server.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+
+static const char* LOG_CATEGORY = "etch_connection_event";
+
+/*
+ * etch_deftcplistener_on_event()
+ * default handler for listener events
+ */
+int etch_deftcplistener_on_event(etch_tcp_server* l, etch_tcp_connection* c, const int e, int p1, void* p2)
+{
+    char cxstr[24], *smask = "server %u";  
+       
+    if (c)
+    {   c->cx.listener = (etch_object*) l;
+        return  c->cx.on_event(c, e, p1, p2);   
+    }
+
+    apr_snprintf(cxstr, sizeof(cxstr), smask, l->listener_id);
+      
+    switch(e)
+    {
+       case ETCH_CONXEVT_CREATED:
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s created\n", cxstr);
+            break;
+
+       case ETCH_CONXEVT_CREATERR:
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s not created\n", cxstr);
+            break;
+
+       case ETCH_CONXEVT_OPENING:
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s opening ...\n", cxstr);
+            break;
+
+       case ETCH_CONXEVT_DESTROYING:
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s destroying ...\n", cxstr);
+            break;
+
+       case ETCH_CONXEVT_DESTROYED:
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s destroyed\n", cxstr);
+            break;
+
+       case ETCH_CONXEVT_SHUTDOWN:
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_WARN, "%s shutdown request detected\n", cxstr);
+            break;
+    }
+
+    return 0;
+}
+
+
+/*
+ * etch_tcpconx_on_event()
+ * default handler for connection events
+ */
+int etch_tcpconx_on_event(void* data, const int e, int p1, void* p2)
+{
+    etch_tcp_connection* c = (etch_tcp_connection*)data;
+    int result = 0, lid = 0;
+    char cxstr[32], estr[128]; 
+    char *scmask = "server %u connxn %u", *cmask = "connxn %u";
+
+    if  (is_etch_tcpserver(c->cx.listener))
+         lid = ((etch_tcp_server*)(c->cx.listener))->listener_id;
+    if  (lid)
+         sprintf(cxstr, scmask, lid, c->cx.conxid);     
+    else sprintf(cxstr, cmask, c->cx.conxid);
+
+    switch(e)
+    {
+        case ETCH_CONXEVT_RECEIVING:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "%s begin receive (block) ...\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_RECEIVERR:
+             apr_strerror(p1, estr, 128);
+             if(IS_ETCH_SOCKET_TIMEOUT(p1))
+                  ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s socket receive timed out\n", cxstr); 
+             else
+             if(p1 == APR_OTHER_END_CLOSED)
+                  ETCH_LOG(LOG_CATEGORY, ETCH_LOG_WARN,"%s connection was broken\n", cxstr);  
+             else
+                 ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR,  "%s apr_socket_recv() %s\n", cxstr, estr); 
+             break;
+
+        case ETCH_CONXEVT_RECEIVED:   /* "eod=%d", p1 */
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s end receive %d bytes\n", cxstr, (int)(size_t)p2);    
+             break;
+
+       case ETCH_CONXEVT_CONXCLOSED:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s local connection closed\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_PEERCLOSED:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s peer connection closed\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_RECEIVEND:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "%s exit receive loop\n", cxstr, p1);                
+             break;
+
+        case ETCH_CONXEVT_SENDING:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "%s begin send\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_SENDERR:
+             apr_strerror(p1, estr, 128);
+             if(IS_ETCH_SOCKET_TIMEOUT(p1))
+                ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s socket send timed out\n", cxstr); 
+             else
+                ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s apr_socket_send() %s\n", cxstr, estr); 
+             break;
+
+        case ETCH_CONXEVT_SENDEND:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s end send %d bytes\n", cxstr, p1);                
+             break;
+
+        case ETCH_CONXEVT_RCVPUMP_START:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s start receive pump\n", cxstr, p1);                
+             break;
+
+        case ETCH_CONXEVT_RCVPUMP_RECEIVING:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s thread %d receiving ...\n", cxstr, p1);                
+             break;
+
+        case ETCH_CONXEVT_RCVPUMP_ERR:
+             result = -1;   
+             if(p1 == APR_OTHER_END_CLOSED)
+                ETCH_LOG(LOG_CATEGORY, ETCH_LOG_WARN, "%s connection was broken\n", cxstr);  
+             else
+                ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s receive failed\n", cxstr);  
+             break;
+
+        case ETCH_CONXEVT_RCVPUMP_STOP:
+             result = p1;
+             if (result >= 0)
+                 ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s receive pump on thread %d exited\n", cxstr, (int) (size_t) p2);
+             else
+                 ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s receive pump abnormal exit\n", cxstr);
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s destroying accepted connection\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_ACCEPTING:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s accepting ...\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_ACCEPTERR:
+             result = -1;
+             apr_strerror((apr_status_t)(size_t)p2, estr, 128);
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s apr_socket_accept() %s\n", cxstr, estr);
+             break;
+
+        case ETCH_CONXEVT_ACCEPTED:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s accepted\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_CREATED:
+             if(p1)
+                ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s created for socket %x\n", cxstr, p1);
+             else
+                ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s created\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_CREATERR:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s not created\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_OPENING:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s opening ...\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_OPENERR:
+             result = -1;
+
+             switch(p1)
+             {
+                case 0:
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s not opened\n", cxstr);
+                    break;
+                case 2:
+                    apr_strerror((apr_status_t)(size_t)p2, estr, 128);
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_WARN, "%s socket connect: %s\n", cxstr, estr);
+                    break;
+                case 3:
+                    apr_strerror((apr_status_t)(size_t)p2, estr, 128);
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, 
+                        "%s socket create: %s\n", cxstr, estr);
+                    break;
+                case 4:
+                    apr_strerror((apr_status_t)(size_t)p2, estr, 128);
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, 
+                        "%s sockaddr info: %s\n", cxstr, estr);
+                    break;
+                case 5:
+                    apr_strerror((apr_status_t)(size_t)p2, estr, 128);
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, 
+                        "%s socket bind: %s\n", cxstr, estr);
+                    break;
+                case 6:
+                    apr_strerror((apr_status_t)(size_t)p2, estr, 128);
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s socket listen: %s\n", cxstr, estr);
+                    break;
+             }
+             break;
+
+        case ETCH_CONXEVT_OPENED:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s opened\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_STARTING:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s starting ...\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_STARTERR:
+             result = -1;
+             switch(p1)
+             {
+                case 0:
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s not started\n", cxstr);
+                    break;
+                case 1:
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s etch_threadpool.run()\n", cxstr);
+                    break;
+             }
+             break;
+
+        case ETCH_CONXEVT_STARTED:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s started\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_ACCEPTPUMPEXIT:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s accept pump on thread %d exited\n", cxstr, p1);
+             break;
+
+        case ETCH_CONXEVT_ACCEPTPUMPEXITERR:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s accept pump abnormal exit\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_LISTENED:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s server id is %d\n", cxstr, p1);
+             break;
+
+        case ETCH_CONXEVT_UP:
+        case ETCH_CONXEVT_DOWN:
+             break;
+
+        case ETCH_CONXEVT_SOCKOPTERR:
+             result = 1; /* to increment counter */
+             apr_strerror(p1, estr, 128);
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s set socket option %s: %s\n", cxstr, p2, estr);
+             break;
+
+        case ETCH_CONXEVT_SHUTDOWN:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_WARN, "%s shutdown request detected\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_STOPPING:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s stopping ...\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_STOPERR:
+             result = -1;
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s not stopped\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_STOPPED:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s stopped\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_CLOSING:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s closing ...\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_CLOSERR:
+             result = -1;
+
+             switch(p1)
+             {
+                case 0:
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s not closed\n", cxstr);
+                    break;
+                case 1:
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s close when not open\n", cxstr);
+                    break;
+                case 2:
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s concurrent close denied\n", cxstr);
+                    break;
+                case 3:
+                    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, 
+                        "%s apr_socket_close() error %d\n", cxstr, (int)(size_t)p2);
+                    break;
+             }
+             break;
+
+        case ETCH_CONXEVT_CLOSED:    
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s closed\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_DESTROYING:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s destroying ...\n", cxstr);
+             break;
+
+        case ETCH_CONXEVT_DESTROYED:
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "%s destroyed\n", cxstr);
+             break;
+    }
+
+    return result;
+}
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_mailbox_manager.c b/binding-c/runtime/c/src/main/transport/etch_mailbox_manager.c
new file mode 100644
index 0000000..2773cee
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_mailbox_manager.c
@@ -0,0 +1,120 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_mailboxmgr.c
+ * i_mailbox manager interface
+ */
+
+#include "etch_mailbox_manager.h"
+#include "etch_message.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+/*
+static const char* LOG_CATEGORY = "etch_mailbox_manager";
+*/
+
+int destroy_mailbox_manager_interface(void*);
+int etchmailboxmgr_def_headersize(i_mailbox_manager*);
+int etchmailboxmgr_def_transport_call(i_mailbox_manager*, etch_who*, etch_message*, i_mailbox**);
+int etchmailboxmgr_def_redeliver (void*, etch_who*, etch_message*);
+int etchmailboxmgr_def_unregister(void*, i_mailbox*);
+
+
+/**
+ * new_mailboxmgr_interface()
+ * i_mailbox_manager constructor.
+ * @param thisx the mailbox manager object.
+ * @param itm transportmesssage interface, caller retains, can be null.
+ * @param ism sessionmessage interface, caller retains, can be null.
+ */
+i_mailbox_manager* new_mailboxmgr_interface(void* thisx, 
+    i_transportmessage* itm, i_sessionmessage* ism)  
+{
+    i_mailbox_manager* newi = (i_mailbox_manager*) new_object(sizeof(i_mailbox_manager), ETCHTYPEB_MBOX_MANAGER, CLASSID_MBOX_MANAGER);
+
+    newi->thisx   = thisx;
+    ((etch_object*)newi)->clone   = clone_null;
+    ((etch_object*)newi)->destroy = destroy_mailbox_manager_interface;  
+
+    newi->transport_call = (etch_mbm_transport_call)etchmailboxmgr_def_transport_call;
+    newi->redeliver      = etchmailboxmgr_def_redeliver;
+    newi->unregister     = etchmailboxmgr_def_unregister;
+
+    newi->itm = itm? itm: new_transportmsg_interface(newi, NULL, NULL); 
+    newi->transport_message = newi->itm->transport_message;
+    newi->transport_message = newi->itm->transport_message;
+    newi->transport_control = newi->itm->transport_control;
+    newi->transport_notify  = newi->itm->transport_notify;
+    newi->transport_query   = newi->itm->transport_query;
+    newi->get_session       = newi->itm->get_session;
+    newi->set_session       = newi->itm->set_session;
+
+    return newi;
+}
+
+
+/**
+ * destroy_mailbox_manager_interface()
+ * i_mailbox_manager destructor
+ */
+int destroy_mailbox_manager_interface(void* data)
+{
+  i_mailbox_manager* mgr = (i_mailbox_manager*)data;
+    if (NULL == mgr) return -1;
+
+    if (!is_etchobj_static_content(mgr))
+    {    
+        etch_object_destroy(mgr->ism);
+
+        etch_object_destroy(mgr->itm);
+    }
+            
+    return destroy_objectex((etch_object*)mgr);
+}
+
+
+/**
+ * etchmailboxmgr_def_transport_call()
+ * default implementation of i_mailbox_manager::transport_call() 
+ */
+int etchmailboxmgr_def_transport_call(i_mailbox_manager* imbm, etch_who* whoto, etch_message* msg, i_mailbox** out)
+{
+    return -1;
+} 
+
+
+/**
+ * etchmailboxmgr_def_redeliver()
+ * default implementation of i_mailbox_manager::redeliver() 
+ */
+int etchmailboxmgr_def_redeliver(void* mailbox, etch_who* whofrom, etch_message* msg)
+{
+    return -1;
+}
+
+
+/**
+ * etchmailboxmgr_def_unregister()
+ * default implementation of i_mailbox_manager::unregister() 
+ */
+int etchmailboxmgr_def_unregister(void* imbm, i_mailbox* mbox)
+{
+    return -1;
+}
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_messagizer.c b/binding-c/runtime/c/src/main/transport/etch_messagizer.c
new file mode 100644
index 0000000..1036669
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_messagizer.c
@@ -0,0 +1,470 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_msgizer.c
+ * messagizer accepts packets and translates them to messages,
+ * and it accepts messages and translates them to packets.
+ */
+
+#include "etch_messagizer.h"
+#include "etch_tdformat.h"
+#include "etch_thread.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+
+static const char* LOG_CATEGORY = "etch_messagizer";
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+int destroy_messagizer(void*);
+int      etch_msgizer_transport_message(void*, void*, void*);
+int      etch_msgizer_session_packet   (void*, void*, void*);
+int      etch_msgizer_session_control  (void*, etch_event*, etch_object*);
+int      etch_msgizer_session_notify   (void*, etch_event*);
+etch_object* etch_msgizer_session_query    (void*, etch_query*); 
+int      etch_msgizer_transport_control(void*, etch_event*, etch_object*);
+int      etch_msgizer_transport_notify (void*, etch_event*);
+etch_object* etch_msgizer_transport_query  (void*, etch_query*); 
+
+
+/* - - - - - - - - - - - - - - -
+ * etch_messagizer
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * new_messagizer()
+ * etch_messagizer public constructor
+ * @param ixport transport interface owned by caller
+ * @param uri a URI string owned by caller.
+ * @param resx a resources map owned by caller.
+ */
+
+etch_messagizer* new_messagizer (i_transportpacket* ixp, wchar_t* uri, etch_resources* resx)
+{
+    etch_url* url = new_url(uri);
+
+    etch_messagizer* messagizer = new_messagizer_a(ixp, url, resx);
+
+    etch_object_destroy(url);
+    return messagizer;
+}
+
+
+/**
+ * new_messagizer_a()
+ * etch_messagizer private constructor
+ * @param ipacket transport interface owned by caller
+ * @param uri a URI string owned by caller.
+ * @param resxmap a resources map owned by caller.
+ */
+etch_messagizer* new_messagizer_a (i_transportpacket* ixp, etch_url* url, etch_resources* resxmap)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    tagdata_format_factory* formatfactory = NULL;
+    etch_messagizer* messagizer = NULL;
+    i_transport* itransport = NULL;
+    etch_value_factory* vf  = NULL;
+    etch_string* formatobj  = NULL;
+    i_session* isession = NULL;
+    etch_mutex* mutex = NULL;
+    int result = -1;
+
+    do
+    {
+        formatobj = (etch_string*) etchurl_get_term (url, ETCH_RESXKEY_MSGIZER_FORMAT);
+
+        if (NULL == formatobj && NULL != resxmap)
+            formatobj = (etch_string*) etch_resources_get (resxmap, ETCH_RESXKEY_MSGIZER_FORMAT);
+
+        if (NULL == formatobj) {
+            ETCH_LOGW(LOG_CATEGORY, ETCH_LOG_ERROR, L"URI missing format specifier '%s'\n", ETCH_RESXKEY_MSGIZER_FORMAT); 
+            break;
+        }
+
+        formatfactory = get_format_factory(formatobj->v.valw);
+        if (NULL == formatfactory) {
+            ETCH_LOGW(LOG_CATEGORY, ETCH_LOG_ERROR, L"no format '%s' is installed\n", 
+            formatobj->v.valw); 
+            break;
+        }
+
+        vf = resxmap? (etch_value_factory*) etch_resources_get(resxmap,
+                          ETCH_RESXKEY_MSGIZER_VALUFACT): NULL;
+        if (NULL == vf)
+        {
+            ETCH_LOGW(LOG_CATEGORY, ETCH_LOG_ERROR, L"no value factory '%s' is installed\n", ETCH_RESXKEY_MSGIZER_VALUFACT);
+            break;
+        }
+
+        // TODO: pool
+        status = etch_mutex_create(&mutex, ETCH_MUTEX_NESTED, NULL);
+        if(status != ETCH_SUCCESS) {
+            // error
+            break;
+        }
+
+        /* - - - - - - - - - - - - - - -
+         * etch_messagizer
+         * - - - - - - - - - - - - - - -
+         */
+        messagizer = (etch_messagizer*) new_object(sizeof(etch_messagizer), ETCHTYPEB_MESSAGIZER, CLASSID_MESSAGIZER);
+
+        ((etch_object*)messagizer)->destroy = destroy_messagizer;
+        ((etch_object*)messagizer)->clone   = clone_null;
+        messagizer->msglock = mutex;
+        messagizer->msgbuf  = new_flexbuffer(ETCH_DEFSIZE);  /* 2K default */
+
+        /* set our transport to that of next lower layer (packetizer) */
+        messagizer->transport = ixp;  /* i_transportpacket owned by caller */
+
+        /* - - - - - - - - - - - - - - -
+         * i_transportmessage
+         * - - - - - - - - - - - - - - -
+         */
+        itransport = new_transport_interface_ex (messagizer,  
+            (etch_transport_control) etch_msgizer_transport_control, 
+            (etch_transport_notify)  etch_msgizer_transport_notify, 
+            (etch_transport_query)   etch_msgizer_transport_query,
+             etch_msgizer_get_session, 
+             etch_msgizer_set_session);
+
+        /* instantiate i_transportmessage interface which messagizer implements */
+        messagizer->transportmsg = new_transportmsg_interface(messagizer, 
+            etch_msgizer_transport_message, 
+            itransport);  /* transportmsg now owns itransport */
+
+        /* copy i_transportmessage interface methods up to messagizer */
+        messagizer->transport_message = etch_msgizer_transport_message;
+        messagizer->transport_control = itransport->transport_control;
+        messagizer->transport_notify  = itransport->transport_notify;
+        messagizer->transport_query   = itransport->transport_query;
+        messagizer->get_session       = itransport->get_session;
+        messagizer->set_session       = itransport->set_session;     
+
+        /* - - - - - - - - - - - - - - -
+         * i_sessionpacket
+         * - - - - - - - - - - - - - - -
+         */
+        isession = new_session_interface(messagizer,  
+            (etch_session_control) etch_msgizer_session_control, 
+            (etch_session_notify)  etch_msgizer_session_notify, 
+            (etch_session_query)   etch_msgizer_session_query);
+
+        /* instantiate i_sessionpacket interface which messagizer implements */
+        messagizer->sessionpkt = new_sessionpkt_interface(messagizer, 
+            etch_msgizer_session_packet, 
+            isession);  /* transportmsg now owns isession */
+
+        /* copy session interface to parent */
+        messagizer->session_packet  = etch_msgizer_session_packet;
+        messagizer->session_control = isession->session_control;
+        messagizer->session_notify  = isession->session_notify;
+        messagizer->session_query   = isession->session_query;
+
+        /* finally set session of next lower layer to our session */
+        /* fyi we must pass the implementor of transport as thisx, i.e. packetizer */
+        messagizer->transport->set_session (messagizer->transport->thisx, messagizer->sessionpkt);
+
+        /* - - - - - - - - - - - - - - -
+         * tagged data in out
+         * - - - - - - - - - - - - - - -
+         */
+        messagizer->tdi = formatfactory->new_tagdata_input(vf);
+        if (NULL == messagizer->tdi) break;
+
+        messagizer->tdo = formatfactory->new_tagdata_output(vf);
+        if (NULL == messagizer->tdo) break;
+        
+        result = 0;
+
+    } while(0);
+
+
+    if (-1 == result) {   
+        etch_object_destroy(vf);
+        etch_object_destroy(messagizer);
+        messagizer = NULL;
+    } 
+
+    etch_object_destroy(formatfactory);
+
+    return messagizer;
+}
+
+
+/**
+ * destroy_messagizer()
+ * destructor for etch_messagizer
+ */
+int destroy_messagizer (void* data)
+{
+    etch_messagizer* thisx = (etch_messagizer*)data;
+    if (!is_etchobj_static_content(thisx))
+    {   
+        etch_object_destroy(thisx->transportmsg);
+        etch_object_destroy(thisx->sessionpkt);
+        etch_object_destroy(thisx->tdi);
+        etch_object_destroy(thisx->tdo);
+        etch_object_destroy(thisx->msgbuf);
+        etch_object_destroy(thisx->msglock);
+        
+    }
+
+   return destroy_objectex((etch_object*) thisx);
+}
+
+
+/**
+ * etch_msgizer_get_transport()
+ * @return a reference to the messagizer transport interface.
+ * this object is owned by whatever object created the messagizer.
+ */
+i_transportpacket* etch_msgizer_get_transport (etch_messagizer* thisx)
+{
+    ETCH_ASSERT(is_etch_messagizer(thisx));
+    return thisx->transport;   
+}
+
+
+/* - - - - - - - - - - - - - - -
+ * i_transportmessage
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etch_msgizer_transport_message()
+ * i_transportmessage::transport_message override.
+ * serializes message and delivers its data to transport  
+ * @param whoto recipient - caller retains this memory, can be null.
+ * @param message the message
+ * caller relinquishes this memory on success, retains on failure.  
+ * @return 0 success, -1 error.
+ */
+int etch_msgizer_transport_message (void* data, void* whoData, void* messageData)
+{
+
+    etch_who* whoto = (etch_who*)whoData;
+    etch_message* msg = (etch_message*)messageData;
+
+    etch_messagizer* thisx = (etch_messagizer*)data;
+    etch_status_t status = ETCH_SUCCESS;
+    int result = 0;
+    ETCH_ASSERT(is_etch_messagizer(thisx));
+
+    status = etch_mutex_lock(thisx->msglock);
+    ETCH_ASSERT(status == ETCH_SUCCESS);
+
+    do
+    {   const int headersize = thisx->transport->get_headersize (thisx->transport);
+
+        etch_flexbuf_skip (thisx->msgbuf, headersize, TRUE);
+
+        /* serialize the message to the buffer */
+        result = ((struct i_tagged_data_output*)
+                        (((etch_object*)thisx->tdo)->vtab))
+                            ->write_message (thisx->tdo, msg, thisx->msgbuf);
+
+        if (-1 == result) {
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR,"serialization of message to buffer failed");
+            etch_flexbuf_reset(thisx->msgbuf);
+            break;
+        }
+
+        etch_flexbuf_set_index (thisx->msgbuf, 0);
+
+
+        /* deliver packet buffer to transport */    /* msgizer->itp->pktizer */
+        result = thisx->transport->transport_packet (thisx->transport->thisx, whoto, thisx->msgbuf);
+
+        if (0 == result) {
+            etch_object_destroy(msg);
+        }
+
+    } while(0);
+
+    status = etch_mutex_unlock(thisx->msglock);
+    ETCH_ASSERT(status == ETCH_SUCCESS);
+
+    return result;
+}
+
+
+/**
+ * etch_msgizer_get_session()
+ * @return a reference to the messagizer i_sessionmessage interface.
+ * this object is owned by whatever object set the messagizer session.
+ */
+i_session* etch_msgizer_get_session (void* data) 
+{
+    etch_messagizer* thisx = (etch_messagizer*)data;
+    ETCH_ASSERT(is_etch_messagizer(thisx));
+    return (i_session*)thisx->session;
+}
+
+
+/**
+ * etch_msgizer_set_session()
+ * @param session an i_sessionmessage reference. caller owns this object.
+ */
+void etch_msgizer_set_session (void* data, void* sessionData)
+{
+    i_session* session = (i_session*)sessionData;
+    etch_messagizer* thisx = (etch_messagizer*)data;
+    ETCH_ASSERT(is_etch_messagizer(thisx));
+    ETCH_ASSERT(is_etch_sessionmsg(session));  
+    thisx->session = (i_sessionmessage*)session;
+}
+
+
+/**
+ * etch_msgizer_transport_control()
+ * i_transportmessage::transport_control override.
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+int etch_msgizer_transport_control (void* data, etch_event* control, etch_object* value)
+{
+  etch_messagizer* thisx = (etch_messagizer*)data;
+    ETCH_ASSERT(is_etch_messagizer(thisx));
+    /*     mzr    itp                           mzr    itp   packetizer */
+    return thisx->transport->transport_control (thisx->transport->thisx, control, value);  
+}
+
+
+/**
+ * etch_msgizer_transport_notify()
+ * i_transportmessage::transport_notify override.
+ * @param evt, caller relinquishes.
+ */
+int etch_msgizer_transport_notify (void* data, etch_event* evt)
+{
+  etch_messagizer* thisx = (etch_messagizer*)data;
+    ETCH_ASSERT(is_etch_messagizer(thisx));
+    return thisx->transport->transport_notify (thisx->transport->thisx, evt);
+}
+
+
+/**
+ * etch_msgizer_transport_query()
+ * i_transportmessage::transport_query override.
+ * @param query, caller relinquishes.
+ */
+etch_object* etch_msgizer_transport_query (void* data, etch_query* query) 
+{
+    etch_messagizer* thisx = (etch_messagizer*)data;
+    ETCH_ASSERT(is_etch_messagizer(thisx));
+    return thisx->transport->transport_query (thisx->transport->thisx, query);
+}
+
+
+/* - - - - - - - - - - - - - - -
+ * i_sessionpacket
+ * - - - - - - - - - - - - - - -
+ */
+  
+/**
+ * etch_msgizer_session_packet()
+ * i_sessionpacket::session_packet override.
+ * delivers data to the session from the transport.
+ * @param from from who sent the packet.
+ * caller retains memory for this object, can be null.
+ * @param buffer the packet from the packet source.
+ * caller retains memory for this object. 
+ * @return 0 success, -1 error (exception condition)
+ */
+int etch_msgizer_session_packet (void* data, void* whoData, void* bufferData)
+{
+
+    etch_who* whofrom = (etch_who*)whoData;
+    etch_flexbuffer* fbuf = (etch_flexbuffer*)bufferData;
+    etch_messagizer* thisx = (etch_messagizer*)data;
+    etch_message* msg = NULL;
+    int is_message_handled = FALSE;
+    ETCH_ASSERT(is_etch_messagizer(thisx));
+
+    /* create an etch message from the packetized data */
+    msg = ((struct i_tagged_data_input*)((etch_object*)thisx->tdi)->vtab)->read_message (thisx->tdi, fbuf);
+    
+    /* send the new message up via session.
+     * memory management rules are: if session_message() handles the message, 
+     * it owns msg memory. otherwise (if not handled), msg memory is owned by  
+     * the unwanted_message wrapper created here, which itself is owned by the 
+     * session_notify() destination.
+     */
+    is_message_handled = (0 == thisx->session->session_message (thisx->session->thisx, whofrom, msg));
+    
+    /* if the message was not handled, e.g. the message is an exception returned 
+     * from a one-way message and there was therefore no mailbox to receive it, 
+     * forward the message to the session via mailbox manager.
+     */
+    if (!is_message_handled) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "unable to post message to a mailbox\n");
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "deferring '%s' to session\n", message_aname(msg));
+        thisx->session->session_notify(thisx->session->thisx, (etch_event*)new_unwanted_message(whofrom, msg));
+        //etch_object_destroy(msg);
+        return -1;
+    }
+
+    /* regardless we have relinquished msg at this point. it is now either queued up 
+     * in a mailbox, or forwarded in the unwanted message wrapper above. */
+    return 0;
+}
+
+
+/**
+ * etch_msgizer_session_control()
+ * i_sessionpacket::session_control override.
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+int etch_msgizer_session_control (void* data, etch_event* control, etch_object* value)
+{
+  etch_messagizer* thisx = (etch_messagizer*)data;
+    ETCH_ASSERT(is_etch_messagizer(thisx));       /* ism    mbmgr */
+    return thisx->session->session_control (thisx->session->thisx, control, value);
+}
+
+
+/**
+ * etch_msgizer_session_notify()
+ * i_sessionpacket::session_notify override.
+ * @param event, caller relinquishes.
+ */
+int etch_msgizer_session_notify  (void* data, etch_event* evt)
+{
+  etch_messagizer* thisx = (etch_messagizer*)data;
+    ETCH_ASSERT(is_etch_messagizer(thisx));      /* ism    mbmgr */
+    return thisx->session->session_notify (thisx->session->thisx, evt);
+}
+
+
+/**
+ * etch_msgizer_session_query()
+ * i_sessionpacket::session_query override.
+ * @param query, caller relinquishes.
+ */
+etch_object* etch_msgizer_session_query (void* data, etch_query* query) 
+{
+    etch_messagizer* thisx = (etch_messagizer*)data;
+    ETCH_ASSERT(is_etch_messagizer(thisx));     /* ism    mbmgr */
+    return thisx->session->session_query (thisx->session->thisx, query);
+}
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_packetizer.c b/binding-c/runtime/c/src/main/transport/etch_packetizer.c
new file mode 100644
index 0000000..58ad191
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_packetizer.c
@@ -0,0 +1,520 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_packetizer.c
+ * packetizes a stream data source. Reads and verfifies a packet header consisting
+ * of a 32-bit signature and 32-bit length. verifies the flag, using length extracted
+ * from header; reads packet data and forwards it to the packet handler. as a packet 
+ * source, accepts a packet and prepends a packet header prior to delivering it to a 
+ * data source.
+ */
+
+#include "etch_packetizer.h"
+#include "etch_objecttypes.h"
+#include "etch_url.h"
+#include "etch_log.h"
+
+static const char* LOG_CATEGORY = "etch_packetizer";
+
+etch_packetizer* new_packetizer_b (i_transportdata*, const int maxpktsize);
+int      etch_pktizer_session_control  (void*, etch_event*, etch_object*);
+int      etch_pktizer_session_notify   (void*, etch_event*);
+etch_object* etch_pktizer_session_query    (void*, etch_query*); 
+int      etch_pktizer_transport_control(void*, etch_event*, etch_object*);
+int      etch_pktizer_transport_notify (void*, etch_event*);
+etch_object* etch_pktizer_transport_query  (void*, etch_query*); 
+
+const wchar_t* ETCH_PKTIZER_MAX_PKT_SIZE_TERM = L"Packetizer.maxPktSize";
+const int ETCH_PKTIZER_DEFMAXPKTSIZE = 10240;
+const int ETCH_PKTIZER_HEADERSIZE = 8;
+const int ETCH_PKTIZER_SIG = 0xdeadbeef;
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * packetizer constructor/destructor
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * new_packetizer()
+ * * etch_packetizer public constructor
+ * @param itd i_transportdata interface owned by caller
+ * @param uri a URI string owned by caller.
+ * @param resources a resources map owned by caller.
+ */
+etch_packetizer* new_packetizer (i_transportdata* itd, wchar_t* uri, etch_resources* resxmap) 
+{
+    etch_url* url = new_url(uri);   
+
+    etch_packetizer* packetizer = new_packetizer_a (itd, url, resxmap);  
+
+    etch_object_destroy(url);
+    return packetizer;
+}
+
+
+/**
+ * new_packetizer_a()
+ * etch_packetizer constructor 2
+ */
+etch_packetizer* new_packetizer_a (i_transportdata* itd, etch_url* url, etch_resources* resxmap)
+{
+    int maxpktsize = 0, result = 0;
+
+    result = etchurl_get_integer_term (url, ETCH_PKTIZER_MAX_PKT_SIZE_TERM, &maxpktsize);
+    if (-1 == result || maxpktsize <= 0) maxpktsize = ETCH_PKTIZER_DEFMAXPKTSIZE;
+
+    return new_packetizer_b (itd, maxpktsize);
+}
+
+
+/*
+ * destroy_packetizer()
+ * etch_packetizer destructor
+ */
+int destroy_packetizer(void* data)
+{
+    etch_packetizer* thisx = (etch_packetizer*)data;
+    etch_status_t status = ETCH_SUCCESS;
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx))
+    {  
+        etch_object_destroy(thisx->sessiondata);
+
+        etch_object_destroy(thisx->transportpkt);
+
+        if (thisx->datalock) {
+            status = etch_mutex_destroy(thisx->datalock);
+            ETCH_ASSERT(status == ETCH_SUCCESS);
+        }
+
+        etch_object_destroy(thisx->savebuf); 
+    }
+            
+    return destroy_objectex((etch_object*)thisx);
+}
+
+
+/**
+ * etch_pktizer_transport_packet()
+ * delivers packet to transport after adding packet header.
+ * @param whoto recipient - caller retains this memory.
+ * @param fbuf buffer positioned at the packet data, with space for header
+ * @return 0 success, -1 error
+ */
+int etch_pktizer_transport_packet(void* data, void* whoData, void* bufferData)
+{
+    etch_who* whoto = (etch_who*)whoData;
+    etch_flexbuffer* fbuf = (etch_flexbuffer*)bufferData;
+    etch_packetizer* thisx = (etch_packetizer*)data;
+    int result = -1;
+    ETCH_ASSERT(is_etch_packetizer(thisx));
+
+    do
+    {   size_t saveindex = 0;
+        const int datalen = (int) etch_flexbuf_avail(fbuf);
+
+        if (datalen < ETCH_PKTIZER_HEADERSIZE) break;
+
+        saveindex = fbuf->index;
+
+        etch_flexbuf_put_int(fbuf, ETCH_PKTIZER_SIG);
+        etch_flexbuf_put_int(fbuf, datalen - ETCH_PKTIZER_HEADERSIZE);
+
+        fbuf->index = saveindex;       
+
+        /* deliver packet buffer to transport */        
+        result = thisx->transport->transport_data(thisx->transport->thisx, whoto, fbuf);
+
+    } while(0);
+
+    return result;
+}
+
+/**
+ * etch_pktizer_session_data()
+ * i_sessiondata::session_data override.
+ * delivers data to the session from the transport
+ * @param whofrom from who sent the packet data
+ * caller retains this memory, can be null.
+ * @param fbuf the packet from the packet source positioned at the data, caller retains.
+ * @return 0 success, -1 error. 
+ */
+int etch_pktizer_session_data (void* data, void* whoData, void* bufferData)
+{
+    etch_packetizer* pzr = (etch_packetizer*)data;
+    etch_who* whofrom = (etch_who*)whoData;
+    etch_flexbuffer* fbuf = (etch_flexbuffer*)bufferData;
+    /* two scenarios: the first is that we have no buffered data and the 
+     * entire packet is contained within the buffer. in that case we can skip  
+	 * the details and ship the packet directly to the handler.
+     */
+    size_t curlen, curndx, bytes_avail, fbuf_avail, packet_bodylen, bytes_put;
+    int  bytes_needed;
+    etch_flexbuffer* savebuf = NULL;
+    ETCH_ASSERT(is_etch_packetizer(pzr));
+    savebuf = pzr->savebuf;
+
+    while(1) /* while(fbuf.avail() > 0 ... */
+    {   if (0 >= (fbuf_avail = etch_flexbuf_avail(fbuf))) break; 
+
+        bytes_avail = savebuf->datalen + fbuf_avail;
+
+        if (pzr->is_wantheader)
+        {   
+            if (bytes_avail >= (unsigned) ETCH_PKTIZER_HEADERSIZE)
+            {   /* there are enough bytes in the pipeline for a header */
+                if (savebuf->datalen == 0)
+                {   /* save buffer is empty, entire header in fbuf */ 
+                    packet_bodylen = etch_pktizer_process_header(pzr, fbuf, FALSE);  
+                }
+                else /* save non empty, header split across save and buf, so ... */
+                {    /* move enough bytes from buf to save to complete a header */
+                    bytes_needed = ETCH_PKTIZER_HEADERSIZE - (int) savebuf->datalen;
+
+                    bytes_put = etch_flexbuf_put_from (savebuf, fbuf, bytes_needed);
+                    if (0 == bytes_put) return -1;
+                    etch_flexbuf_set_index(savebuf, 0);
+                    packet_bodylen = etch_pktizer_process_header(pzr, savebuf, TRUE);
+                }	
+			
+                if (packet_bodylen == -1) return -1;  /* bad header */
+				if (packet_bodylen == 0)  continue;	  /* header with empty body */					 
+				pzr->bodylength = packet_bodylen;	
+				pzr->is_wantheader = FALSE;
+            }
+            else /* want header, but too few bytes in the pipeline */
+			{    /* ... so save fbuf to the save buffer */
+                etch_flexbuf_set_index (savebuf, savebuf->datalen);
+                etch_flexbuf_put_from(savebuf, fbuf, -1);
+		    }
+        }
+        else /* didn't need a header, so ... */
+        if (bytes_avail >= pzr->bodylength)
+        {
+			/* we need the body, and there are enough bytes in the pipeline.
+			 * three scenarios: the body is entirely in savebuf, the body is 
+			 * split, or the body is entirely in fbuf. assert that the body   
+             * is not entirely in save, or we'd have processed it last time.  
+             */
+            ETCH_ASSERT(savebuf->datalen < pzr->bodylength);
+
+            if (savebuf->datalen == 0)
+            {   /* saved buffer is empty, entire body is in fbuf */
+                curlen = fbuf->datalen;
+                curndx = fbuf->index;
+                etch_flexbuf_set_length(fbuf, curndx + pzr->bodylength);
+
+                /* send the packet in the input buffer up the chain to the next 
+                 * higher layer of the transport stack. fyi packetizer.session.thisx 
+                 * is that layer object, ordinarily the messagizer.
+                 */
+                pzr->session->session_packet (pzr->session->thisx, whofrom, fbuf);
+
+                /* fyi the input buffer can contain a partial packet, multiple 
+                 * packets, or whatever, so we may not be done with it yet. */
+                etch_flexbuf_set_length(fbuf, curlen);   
+                etch_flexbuf_set_index (fbuf, curndx + pzr->bodylength);
+                pzr->is_wantheader = TRUE;
+            }
+            else 
+            {   /* savebuf.datalen not zero, so body is split across the save buffer 
+                 * and the input buffer. move enough bytes from input buffer fbuf 
+                 * to complete the packet body. 
+                 */
+                bytes_needed = (int) (pzr->bodylength - savebuf->datalen);
+                bytes_put = etch_flexbuf_put_from (savebuf, fbuf, bytes_needed);
+                if (bytes_put <= 0) return -1;
+                etch_flexbuf_set_index(savebuf, 0);
+
+                /* send the newly-isolated packet up the chain to the next higher
+                 * layer of the transport stack. fyi packetizer.session.thisx 
+                 * is that layer object, ordinarily the messagizer.
+                 */
+                pzr->session->session_packet (pzr->session->thisx, whofrom, savebuf);
+                
+                etch_flexbuf_reset(savebuf);
+                pzr->is_wantheader = TRUE;                
+            }
+        }
+        else /* need body but too few bytes in pipeline to complete it */
+        {    /* ... so save the input buffer to the save buffer */
+            bytes_put = etch_flexbuf_put_from (savebuf, fbuf, ETCH_FLEXBUF_PUT_ALL);
+        }
+    }
+
+    /* buffer is now empty and we're done */
+    return fbuf_avail == 0? 0: -1;
+}
+
+
+/**
+ * etch_pktizer_set_session()
+ * set packetizer session interface presumably to that of the next higher layer.
+ * @param session an i_sessionpacket reference. caller owns this object.
+ */
+void etch_pktizer_set_session (void* data, void* sessionData)
+{
+    etch_packetizer* thisx = (etch_packetizer*)data;
+    i_session* newsession = (i_session*)sessionData;
+    ETCH_ASSERT(is_etch_packetizer(thisx));
+    ETCH_ASSERT(is_etch_sessionpacket(newsession));
+    thisx->session = (i_sessionpacket*)newsession;
+}
+
+
+/**
+ * new_packetizer_b()
+ * etch_packetizer private constructor
+ * @param transport the transport interface of the next lower layer of the stack,
+ * that being the connection, e.g. etch_tcp_connection. not owned.
+ * @param maxpktsize maximum number of bytes in a packet (default currently 10240)
+ */
+etch_packetizer* new_packetizer_b (i_transportdata* itd, const int maxpktsize)
+{
+    etch_packetizer* packetizer = NULL;
+    i_transport* itransport = NULL;
+    i_session* isession = NULL;
+    etch_mutex* mutex = NULL;
+    int result = -1;
+    ETCH_ASSERT(is_etch_transportdata(itd));
+
+    do
+    {   
+        #if(ETCHPZR_HAS_MUTEX)
+        if (NULL == (mutex = new_mutex(etch_apr_mempool, ETCHMUTEX_NESTED))) break;
+        #endif
+
+        /* - - - - - - - - - - - - - - -
+         * etch_packetizer
+         * - - - - - - - - - - - - - - -
+         */
+        packetizer = (etch_packetizer*) new_object
+            (sizeof(etch_packetizer), ETCHTYPEB_PACKETIZER, CLASSID_PACKETIZER);
+
+        ((etch_object*)packetizer)->destroy  = destroy_packetizer;  
+        ((etch_object*)packetizer)->clone    = clone_null;
+        packetizer->datalock = mutex;
+
+        packetizer->headersize    = ETCH_PKTIZER_HEADERSIZE;
+        packetizer->is_wantheader = TRUE;
+        packetizer->maxpacketsize = maxpktsize > 0? maxpktsize: ETCH_PKTIZER_DEFMAXPKTSIZE;
+
+        packetizer->savebuf = new_flexbuffer(ETCH_DEFSIZE); /* 2K default */
+
+        /* set our transport to that of next lower layer (connection) */
+        packetizer->transport = itd;  /* not owned */
+            
+
+        /* - - - - - - - - - - - - - - -
+         * i_transportpacket
+         * - - - - - - - - - - - - - - -
+         */
+        itransport = new_transport_interface_ex (packetizer,  
+            (etch_transport_control) etch_pktizer_transport_control, 
+            (etch_transport_notify)  etch_pktizer_transport_notify, 
+            (etch_transport_query)   etch_pktizer_transport_query,
+             etch_pktizer_get_session, 
+             etch_pktizer_set_session);
+
+        /* instantiate i_transportpacket interface which packetizer implements */
+        packetizer->transportpkt = new_transportpkt_interface (packetizer, 
+            etch_pktizer_transport_packet, 
+            itransport);  /* transportpkt now owns itransport */
+
+        /* copy i_transportpacket interface methods up to packetizer */
+        packetizer->transport_packet  = etch_pktizer_transport_packet;
+        packetizer->transport_control = itransport->transport_control;
+        packetizer->transport_notify  = itransport->transport_notify;
+        packetizer->transport_query   = itransport->transport_query;
+        packetizer->get_session       = itransport->get_session;
+        packetizer->set_session       = itransport->set_session;
+
+
+        /* - - - - - - - - - - - - - - -
+         * i_sessiondata
+         * - - - - - - - - - - - - - - -
+         */
+        isession = new_session_interface (packetizer,  
+            (etch_session_control) etch_pktizer_session_control, 
+            (etch_session_notify)  etch_pktizer_session_notify, 
+            (etch_session_query)   etch_pktizer_session_query);
+
+        /* instantiate i_sessiondata interface which packetizer implements */
+        packetizer->sessiondata = new_sessiondata_interface(packetizer, 
+            etch_pktizer_session_data, 
+            isession);  /* sessiondata now owns isession */ 
+
+        /* copy session interface to parent */
+        packetizer->session_data    = etch_pktizer_session_data;
+        packetizer->session_control = isession->session_control;
+        packetizer->session_notify  = isession->session_notify;
+        packetizer->session_query   = isession->session_query;
+
+        /* finally set session of next lower layer (tcp connection) to our session */
+        /* fyi we must pass the implementor of transport as thisx, i.e. tcpconnection */
+        packetizer->transport->set_session (packetizer->transport->thisx, packetizer->sessiondata);
+        
+        result = 0;
+
+    } while(0);
+
+
+    if (-1 == result) { 
+        etch_object_destroy(packetizer);
+        packetizer = NULL;
+    } 
+
+    return packetizer;
+}
+
+
+
+
+/* - - - - - - - - - - - - - - -
+ * i_transportpacket
+ * - - - - - - - - - - - - - - -
+ */
+
+
+/**
+ * etch_pktizer_get_session()
+ * @return a reference to the packetizer i_sessiondata interface.
+ * this object is owned by whatever object set the packetizer session.
+ */
+i_session* etch_pktizer_get_session (void* data)
+{
+    etch_packetizer* thisx = (etch_packetizer*)data;
+    ETCH_ASSERT(is_etch_packetizer(thisx));
+    return (i_session*)thisx->session;
+}
+
+
+
+
+/**
+ * etch_pktizer_transport_control()
+ * i_transportpacket::transport_control override.
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+int etch_pktizer_transport_control (void* data, etch_event* control, etch_object* value)
+{
+  etch_packetizer* thisx = (etch_packetizer*)data;
+    ETCH_ASSERT(is_etch_packetizer(thisx));
+    /*      pzr     itd                          pzr      itd    tcpconx */
+    return thisx->transport->transport_control (thisx->transport->thisx, control, value); 
+}
+
+
+/**
+ * etch_pktizer_transport_notify()
+ * i_transportpacket::transport_notify override.
+ * @param evt, caller relinquishes.
+ */
+int etch_pktizer_transport_notify (void* data, etch_event* evt)
+{
+  etch_packetizer* thisx = (etch_packetizer*)data;
+    ETCH_ASSERT(is_etch_packetizer(thisx));
+    return thisx->transport->transport_notify (thisx->transport->thisx, evt);
+}
+
+
+/**
+ * etch_pktizer_transport_query()
+ * i_transportpacket::transport_query override.
+ * @param query, caller relinquishes.
+ */
+etch_object* etch_pktizer_transport_query (void* data, etch_query* query) 
+{
+    etch_packetizer* thisx = (etch_packetizer*)data;
+    ETCH_ASSERT(is_etch_packetizer(thisx));
+    return thisx->transport->transport_query (thisx->transport->thisx, query);
+}
+
+
+/* - - - - - - - - - - - - - - -
+ * i_sessiondata
+ * - - - - - - - - - - - - - - -
+ */
+  
+/*
+ * etch_pktizer_process_header()
+ * extract header information from packet
+ * returns data length from header, or -1 if bad header
+ */
+int etch_pktizer_process_header (etch_packetizer* pzr, etch_flexbuffer* fbuf, const int is_reset)
+{
+    int curlen = 0, signature = 0;
+    int result = etch_flexbuf_get_int(fbuf, &signature);
+    if (-1 == result || ETCH_PKTIZER_SIG != signature) return -1;
+
+    result = etch_flexbuf_get_int(fbuf, &curlen);
+
+    if (is_reset)
+        etch_flexbuf_reset(fbuf);
+
+    if( curlen > (int) pzr->maxpacketsize) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_WARN, "Packetsize in header is too long, dropping header.");
+    }
+
+    return result == -1 || curlen < 0 || curlen > (int) pzr->maxpacketsize? 
+        -1: curlen;
+}
+
+
+/**
+ * etch_pktizer_session_control()
+ * i_sessiondata::session_control override.
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+int etch_pktizer_session_control (void* data, etch_event* control, etch_object* value)
+{
+  etch_packetizer* thisx = (etch_packetizer*)data;
+    ETCH_ASSERT(is_etch_packetizer(thisx));
+    return thisx->session->session_control (thisx->session->thisx, control, value);
+}
+
+
+/**
+ * etch_pktizer_session_notify()
+ * i_sessiondata::session_notify override.
+ * @param event, caller relinquishes.
+ */
+int etch_pktizer_session_notify  (void* data, etch_event* evt)
+{
+  etch_packetizer* thisx = (etch_packetizer*)data;
+    ETCH_ASSERT(is_etch_packetizer(thisx));
+    return thisx->session->session_notify (thisx->session->thisx, evt);
+}
+
+
+/**
+ * etch_pktizer_session_query()
+ * i_sessiondata::session_query override.
+ * @param query, caller relinquishes.
+ */
+etch_object* etch_pktizer_session_query (void* data, etch_query* query) 
+{
+    etch_packetizer* thisx = (etch_packetizer*)data;
+    ETCH_ASSERT(is_etch_packetizer(thisx));
+    return thisx->session->session_query (thisx->session->thisx, query);
+}
diff --git a/binding-c/runtime/c/src/main/transport/etch_plain_mailbox.c b/binding-c/runtime/c/src/main/transport/etch_plain_mailbox.c
new file mode 100644
index 0000000..2f8bdc8
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_plain_mailbox.c
@@ -0,0 +1,927 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_plainmailbox.c
+ * standard mailbox using a fixed size queue
+ */
+
+#include "etch_runtime.h"
+#include "etch_plain_mailbox.h"
+#include "etch_encoding.h"
+#include "etch_thread.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+static const char* LOG_CATEGORY = "etch_plain_mailbox";
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+etch_plainmailbox* new_mailbox_a(const int);
+int  destroy_mailbox(void*);
+void  etchmbox_alarm_wakeup (void*, const int); 
+int  etchmbox_is_alarm_set(etch_plainmailbox*);
+int  etchmbox_set_duration (etch_plainmailbox*, const int);
+int  etchmbox_test_and_set_alarm_set(etch_plainmailbox*, const int); 
+
+int  etchmbox_message(void*, etch_who* whofrom, etch_message* msg);
+int  etchmbox_read   (void*, etch_mailbox_element** out);
+int  etchmbox_read_withwait (void*, const int maxdelay, etch_mailbox_element** out);
+int  etchmbox_close_delivery (void*);
+int  etchmbox_close_read (void* );
+int  etchmbox_register_notify (void*, etch_mailbox_notify, etch_object* state, const int maxdelay);
+int  etchmbox_unregister_notify (void*, etch_mailbox_notify);
+int  etchmbox_is_empty   (void*);
+int  etchmbox_is_closed  (void*);
+int  etchmbox_is_full    (void*);
+int  etchmbox_fire_notify(void*);  
+int64 etchmbox_get_message_id (void*);
+
+
+/* - - - - - - - - - - - - - - -
+ * constructor/destructor
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * new_mailbox()
+ * etch_plainmailbox public constructor
+ * @param mbmgr the manager to use to unregister this mailbox 
+ * and to forward undelivered messages.
+ * @param message_id
+ * @param max_msgdelay the maximum delay in milliseconds to wait when attempting 
+ * to put a message to the mailbox.
+ * @param lifetime time in milliseconds to keep the mailbox open.
+ * a lifetime of zero means keep it open until explicitly closed. 
+ * @param capacity maximum number of messages. zero indicates use default capacity.
+ */
+etch_plainmailbox* new_mailbox (i_mailbox_manager* mbmgr, const int64 message_id, 
+    const int max_msgdelay, const int lifetime, const int capacity)
+{
+    etch_plainmailbox* mbox = NULL;
+    if (message_id == 0 || lifetime < 0 || capacity < 0) return NULL;
+
+    if (NULL == (mbox = new_mailbox_a(capacity))) return NULL;
+
+    mbox->manager  = mbmgr;
+    mbox->lifetime = lifetime;
+    mbox->rwlock   = mbmgr->rwlock; /* not owned */
+    mbox->message_id = message_id;
+    mbox->max_message_delay = max_msgdelay;
+    mbox->max_messages = capacity > 0? capacity: MBOX_DEFMAXMESSAGES;
+
+    if (lifetime)
+        etchmbox_set_duration(mbox, lifetime);
+
+    return mbox;
+}
+
+
+/**
+ * new_mailbox_a()
+ * etch_plainmailbox private constructor
+ */
+etch_plainmailbox* new_mailbox_a(const int capacity)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_plainmailbox* mailbox = NULL;
+    i_mailbox* imailbox = NULL;
+    etch_queue* queue = NULL;
+    etch_mutex_t* mutex  = NULL;
+    int result = -1;
+
+    do
+    {
+        // TODO: pool
+        status = etch_mutex_create(&mutex, ETCH_MUTEX_UNNESTED, NULL);
+        if(status != ETCH_SUCCESS) {
+            // error
+            break;
+        }
+        if (NULL == (queue  = new_queue(capacity))) break;
+
+        /* - - - - - - - - - - - - - - -
+         * i_mailbox 
+         * - - - - - - - - - - - - - - -
+         */
+        imailbox = new_mailbox_interface( NULL, /* parent set below */
+            etchmbox_message, 
+            etchmbox_read,  
+            etchmbox_read_withwait,  
+            etchmbox_close_delivery,  
+            etchmbox_close_read,   
+            etchmbox_register_notify, 
+            etchmbox_unregister_notify,  
+            etchmbox_is_empty,  
+            etchmbox_is_closed,  
+            etchmbox_is_full,   
+            etchmbox_get_message_id);
+
+        /* - - - - - - - - - - - - - - -
+         * etch_plainmailbox
+         * - - - - - - - - - - - - - - -
+         */
+        mailbox = (etch_plainmailbox*) new_object(sizeof(etch_plainmailbox), ETCHTYPEB_MAILBOX, CLASSID_MAILBOX);
+
+        ((etch_object*)mailbox)->destroy  = destroy_mailbox;
+        ((etch_object*)mailbox)->clone    = clone_null;
+        mailbox->readlock = mutex;
+        mailbox->queue    = queue;
+       
+        /* copy i_mailbox virtuals to parent */
+        imailbox->thisx   = mailbox;
+        mailbox->imailbox = imailbox;
+        mailbox->message  = etchmbox_message; 
+        mailbox->read     = etchmbox_read;  
+        mailbox->read_withwait     = etchmbox_read_withwait;  
+        mailbox->close_delivery    = etchmbox_close_delivery;  
+        mailbox->close_read        = etchmbox_close_read;   
+        mailbox->register_notify   = etchmbox_register_notify; 
+        mailbox->unregister_notify = etchmbox_unregister_notify;  
+        mailbox->is_empty  = etchmbox_is_empty;  
+        mailbox->is_closed = etchmbox_is_closed;  
+        mailbox->is_full   = etchmbox_is_full;   
+        mailbox->get_message_id = etchmbox_get_message_id;
+        
+        mailbox->mailbox_state = ETCH_MAILBOX_STATE_OPEN;
+        result = 0;
+
+    } while(0);
+
+    if (-1 == result)
+    {
+        etch_mutex_destroy(mutex);
+        etch_object_destroy(queue);
+        if (imailbox)
+            etch_free(imailbox);
+    } 
+
+    return mailbox;
+}
+
+
+/**
+ * destroy_mailbox()
+ * destructor for etch_plainmailbox (etch_mailbox)
+ */
+int destroy_mailbox(void* data)
+{
+    etch_plainmailbox* thisx = (etch_plainmailbox*)data;
+
+    if (!is_etchobj_static_content(thisx))
+    {   
+        const int is_locked = 0 == etchqueue_lock(thisx->queue);
+        const int current_state = thisx->mailbox_state;
+        thisx->mailbox_state = ETCH_MAILBOX_STATE_SHUTDOWN;
+        if (is_locked) etchqueue_unlock(thisx->queue);
+
+        if (current_state < ETCH_MAILBOX_STATE_CLOSED_READ)
+        {   /* if the mailbox has not been closed, do it now. we do this
+             * in order to close the queue, cancel any active timer, and  
+             * reroute any messages remaining in the mailbox. */
+            etchmbox_close_read(thisx->imailbox);
+            etch_sleep(100);  /* todo: remove sleep when tested out */
+        }
+
+        if (thisx->impl)
+           ((etch_object*) thisx->impl)->destroy(thisx->impl);
+
+	
+	    etch_object_destroy(thisx->queue);
+	    thisx->queue = NULL;
+
+
+	    etch_object_destroy(thisx->notify_state);
+	    thisx->notify_state = NULL;
+
+
+	    etch_object_destroy(thisx->lifetimer);
+	    thisx->lifetimer = NULL;
+
+
+        etch_mutex_destroy(thisx->readlock);
+        thisx->readlock = NULL;
+
+        /* debug heap issue note: this is/was the spot */
+        etch_free(thisx->imailbox);  
+    }
+
+   return destroy_objectex((etch_object*) thisx);
+}
+
+
+/* - - - - - - - - - - - - - - -
+ * etch_plainmailbox public
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchmbox_contains_message() 
+ * determines if the mailbox contains a message with the same memory address
+ * as the specified message.   
+ * @return TRUE or FALSE.   
+ */
+int etchmbox_contains_message(etch_plainmailbox* thisx, etch_message* thismsg)
+{
+    int result = FALSE, entrycount = 0;
+
+    if (0 == etchqueue_lock(thisx->queue)) 
+    {
+        entrycount = thisx && thisx->queue? etch_apr_queue_size(thisx->queue->aprq): 0;
+
+        if (entrycount) 
+        {
+            etch_iterator iterator;
+            set_iterator(&iterator, thisx->queue, &thisx->queue->iterable);
+
+            while(iterator.has_next(&iterator))
+            {
+                etch_mailbox_element* content = (etch_mailbox_element*) iterator.current_value;
+
+                if (content && content->msg && content->msg == thismsg)  
+                {   result = TRUE;
+                    break;
+                }               
+                
+                iterator.next(&iterator);
+            }  
+        }
+
+        etchqueue_unlock(thisx->queue);
+    } 
+
+    return result;
+}
+
+
+/* - - - - - - - - - - - - - - -
+ * alarm interface 
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchmbox_alarm_wakeup()
+ * callback from alarm timer indicating timer expired or signaled.
+ */
+void etchmbox_alarm_wakeup (void* passthrudata, const int wakeupreason) 
+{    
+    etch_plainmailbox* thisx = (etch_plainmailbox*) passthrudata;
+
+    ETCH_ASSERT(is_etch_mailbox(thisx));
+    /* note that the timer can not be destroyed here - its thread has not exited */
+
+    /* if we are called back in the middle of closing the mailbox we will block here 
+     * until the close is complete. the close_delivery() below will then do nothing. 
+     * related scenario: another thread's call to close_delivery() is blocked on this 
+     * etchmbox_test_and_set_alarm_set. etchmbox_test_and_set_alarm_set releases the  
+     * lock, the other close_delivery() acquires the lock and proceeds. meanwhile,  
+     * close_delivery() called here (3 lines below), blocks, since the other thread
+     * has the the lock. when the the other thread completes close_delivery(), the 
+     * lock is released and this close_delivery() proeceeds to find that the queue 
+     * is now closed, so it takes no action and returns. 
+     */
+
+    #ifdef ETCH_DEBUG
+    ETCH_LOG(ETCH_PLAINMAILBOX_LOGID, ETCH_LOG_XDEBUG, "wakeup reason %s\n", reasons[wakeupreason+1]);
+    #endif
+
+    if (wakeupreason == ETCH_TIMEOUT)   
+        thisx->close_delivery(thisx->imailbox);
+}
+
+
+/**
+ * etchmbox_set_duration()       
+ */
+int etchmbox_set_duration(etch_plainmailbox* thisx, const int ms)
+{
+    thisx->is_alarm_set = TRUE; /* todo implement proper alarm manager */
+    thisx->lifetimer = new_timer(ms, thisx, etchmbox_alarm_wakeup);
+
+    if (thisx->lifetimer)
+        thisx->lifetimer->start(thisx->lifetimer);
+
+    return NULL != thisx->lifetimer;
+}
+
+
+/* - - - - - - - - - - - - - - -
+ * i_mailbox
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchmbox_message() 
+ * queues specified message to this mailbox.
+ * @param whofrom caller retains
+ * @param msg caller relinquishes on success, retains on other than success.
+ * message is not destroyed here on failure case since caller may want to reroute.
+ * @return 0 sucesss, -1 failure, ETCH_MAILBOX_TIMEOUT (-2) timeout,
+ * or ETCH_MAILBOX_DUPLICATE (-3), message already queued.
+ */
+int etchmbox_message (void* data, etch_who* whofrom, etch_message* msg)
+{
+  i_mailbox* ibox = (i_mailbox*)data;
+    int  result = 0;
+    etch_mailbox_element* msgelt;
+    const char* thistext = "etchmbox_message";
+    etch_plainmailbox* thisx = ibox? ibox->thisx: NULL; 
+    if (NULL == thisx) return -1;
+
+    if (etchmbox_contains_message(thisx, msg)) 
+        return ETCH_MAILBOX_DUPLICATE;
+
+    msgelt = new_mailbox_element(msg, whofrom);
+
+    /* block the mailbox from being read until the put returns and the status 
+     * change notification completes. without this lock, the message could be read
+     * from the mailbox, causing all client processing to complete, resulting in
+     * destruction of the mailbox before the put returns, resulting in a race
+     * condition when the notify references a mailbox which has now been destroyed.
+     * the lock is released below prior to return from this method.
+     */
+    etchmbox_get_readlock (thisx, thistext);
+
+    /* insert message to mailbox - relinquishes message on success */
+    result = etchqueue_put_withwait (thisx->queue, thisx->max_message_delay, msgelt);
+    
+    switch(result)
+    {   
+        case 0: break;
+
+        case ETCH_QUEUE_OPERATION_TIMEOUT:
+             result = ETCH_MAILBOX_TIMEOUT;
+             break;
+
+        case ETCH_QUEUE_OPERATION_CANCELED: /* wait signaled */
+        default:
+             result = -1;
+    }
+
+    if (0 == result) 
+        etchmbox_fire_notify ((etch_plainmailbox*)thisx);   
+    else /* on failure case, we destroy the message element wrapper here,
+          * but leave the message intact, since caller may want to reroute.
+          * if we were to instead invoke the msgelt destructor, the message 
+          * would also be destroyed, so we simply etch_free the wrapper. */
+        etch_free(msgelt); 
+
+    etchmbox_release_readlock (thisx, thistext);
+    return result;
+}
+
+
+/**
+ * etchmbox_check_read_result()
+ * check result of mailbox read, ensure presence of out reference, 
+ * and throw exception into the out object if indicated.
+ * @param readresult result of the mailbox queue read operation in question.
+ * @param out pointer to location currently hosting mailbox element read
+ * from queue, or which will receive such an object to be instantiated here.
+ * @return the passed readresult, assumed to be one of these five values:
+ * 0: read result was OK and present in the *out mailbox element.
+ * -1: some error occurred reading the queue, and *out is an empty mailbox
+ * element hosting an exception so indicating.
+ * ETCH_QUEUE_OPERATION_TIMEOUT: the queue read timed out, and *out is an empty 
+ * mailbox element hosting an exception so indicating.
+ * ETCH_QUEUE_OPERATION_CANCELED: the queue read was programmatically interrupted,
+ * and *out is an empty mailbox element hosting an exception so indicating.
+ * ETCH_QUEUE_EOF: queue was empty, and *out is now null.
+ */
+int etchmbox_check_read_result (const int readresult, etch_mailbox_element** out)
+{
+    ETCH_ASSERT(out);
+
+    switch(readresult)
+    {   case 0:  /* normal result, verify that a return object was created */
+             ETCH_ASSERT(*out); 
+             break;
+
+        case ETCH_QUEUE_EOF: /* mailbox was empty, ensure no return object */
+             *out = NULL;
+             break;
+
+        default:   /* error result, create return object to wrap exception */
+        {
+            char*            txt = NULL;
+             etch_exception* ex  = NULL;
+             /* determine exception text */
+             switch(readresult) {
+                case ETCH_QUEUE_OPERATION_TIMEOUT:
+                    txt = "mailbox read timed out";
+                    break;
+                case ETCH_QUEUE_OPERATION_CANCELED:
+                    txt = "mailbox read canceled";
+                    break;
+                default:
+                    txt = "mailbox read error";
+                    break;
+             }
+
+             *out = (etch_mailbox_element*) new_etch_exception_from_errorcode(ETCH_ETIMEOUT);
+             ex = (etch_exception*)*out;
+             etch_exception_set_message(ex, new_stringa(txt));
+             clear_etchobj_static_content(((etch_object*)ex));
+             ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "%s\n", txt); 
+         }
+    }
+
+    return readresult;
+}
+
+
+/**
+ * etchmbox_read()
+ * get an entry from mailbox, block until available.
+ * @param out pointer to caller's location to receive the mailbox entry.
+ * @return 0, ETCH_QUEUE_EOF, ETCH_QUEUE_OPERATION_TIMEOUT, ETCH_QUEUE_OPERATION_CANCELED, or -1.
+ * if result is 0, return via the out parameter, the message read from the mailbox, wrapped in an
+ * etch_mailbox_element object. if result is ETCH_QUEUE_EOF, mailbox was empty, and the out
+ * parameter will be null. any other result, and a placeholder etch_mailbox_element is returned
+ * via the out parameter, containing a null message, and wrapping an exception indicating the 
+ * reason for mailbox read failure.
+ */
+int etchmbox_read (void* data, etch_mailbox_element** out)
+{
+  i_mailbox* ibox = (i_mailbox*)data;
+    int  result = 0;
+    etch_plainmailbox* thisx = ibox? ibox->thisx: NULL; 
+    ETCH_ASSERT(thisx && out);
+    *out = NULL;
+   
+    result = etchqueue_get (thisx->queue, (void**)out);
+
+    return etchmbox_check_read_result (result, out);
+}
+
+
+/**
+ * etchmbox_read_withwait() 
+ * @param maxdelay time interval to wait for a message to arrive in the queue. 
+ * this will be one of:
+ * a) ETCH_NOWAIT, to specify no wait;
+ * b) ETCHQUEUE_CLEARING_CLOSED_QUEUE, to ask for read from a closed queue
+ *    without blocking; or
+ * c) wait time in milliseconds.
+ * @param out pointer to caller's location to receive the mailbox entry.
+ * @return 0, ETCH_QUEUE_EOF, ETCH_QUEUE_OPERATION_TIMEOUT, ETCH_QUEUE_OPERATION_CANCELED, or -1.
+ * if result is 0, return via the out parameter, the message read from the mailbox, wrapped in an
+ * etch_mailbox_element object. if result is ETCH_QUEUE_EOF, mailbox was empty, and the out
+ * parameter will be null. any other result, and a placeholder etch_mailbox_element is returned
+ * via the out parameter, containing a null message, and wrapping an exception indicating the 
+ * reason for mailbox read failure.
+ */
+int etchmbox_read_withwait (void* data, const int maxdelay, 
+    etch_mailbox_element** out)
+{
+  i_mailbox* ibox = (i_mailbox*)data;
+    int  result = 0;
+    etch_plainmailbox* thisx = ibox? ibox->thisx: NULL; 
+    ETCH_ASSERT(thisx && out);
+    *out = NULL; 
+ 
+    result = etchqueue_get_withwait (thisx->queue, maxdelay, (void**)out);
+
+    return etchmbox_check_read_result (result, out);
+}
+
+
+/**
+ * etchmbox_get_readlock() 
+ * acquire the mailbox read mutex.
+ * we wrap the lock thusly to provide logging to aid in deadlock debugging.
+ * @return 0 success, -1 failure
+ */
+int etchmbox_get_readlock (etch_plainmailbox* thisx, const char* caller)
+{
+    return etchmbox_get_readlockex (thisx->rwlock, caller);
+}
+
+
+/**
+ * etchmbox_release_readlock() 
+ * release the mailbox read mutex.
+ * we wrap the lock thusly to provide logging to aid in deadlock debugging.
+ * @return 0 success, -1 failure
+ */
+int etchmbox_release_readlock (etch_plainmailbox* thisx, const char* caller)
+{
+    return etchmbox_release_readlockex (thisx->rwlock, caller);
+}
+
+
+/**
+ * etchmbox_get_readlockex() 
+ * acquire the specified read mutex.
+ * we wrap the lock thusly to provide logging to aid in deadlock debugging.
+ * @return 0 success, -1 failure
+ */
+int etchmbox_get_readlockex (etch_mutex* mutex, const char* caller)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "%s gets mbox lock\n", caller); 
+    
+    status = etch_mutex_lock(mutex);
+    if(status != ETCH_SUCCESS) {
+        return -1;
+    }
+    return 0;
+}
+
+
+/**
+ * etchmbox_release_readlock() 
+ * release the mailbox read mutex.
+ * we wrap the lock thusly to provide logging to aid in deadlock debugging.
+ * @return 0 success, -1 failure
+ */
+int etchmbox_release_readlockex (etch_mutex* mutex, const char* caller)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "%s rels mbox lock\n", caller); 
+
+    status = etch_mutex_unlock(mutex);
+    if(status != ETCH_SUCCESS) {
+        return -1;
+    }
+    return 0;
+}
+
+
+
+/**
+ * etchmbox_close_delivery() 
+ * @return 0 success, -1 failure
+ */
+int etchmbox_close_delivery (void* data)
+{
+  i_mailbox* ibox = (i_mailbox*)data;
+    int result = -1;
+    etch_plainmailbox* thisx = NULL;
+    ETCH_ASSERT(is_etch_imailbox(ibox));
+    thisx = ibox->thisx;
+    ETCH_ASSERT(is_etch_mailbox(thisx));
+
+    /* when arriving here via mailbox destructor, mailbox state will be  
+     * ETCH_MAILBOX_STATE_SHUTDOWN but queue may not yet be closed */
+    if (thisx->mailbox_state >= ETCH_MAILBOX_STATE_CLOSED_DELIVERY        
+     && etchqueue_is_closed(thisx->queue)) /* 12/24 */
+        return ETCH_MAILBOX_RESULT_ALREADY_CLOSED;  
+
+    if (0 == etchqueue_lock(thisx->queue)) 
+    {        
+        if (!etchqueue_is_closed(thisx->queue)) 
+        {
+            if (thisx->mailbox_state < ETCH_MAILBOX_STATE_CLOSED_DELIVERY)
+                thisx->mailbox_state = ETCH_MAILBOX_STATE_CLOSED_DELIVERY;
+
+            if (thisx->is_alarm_set)   
+            {                 
+                thisx->is_alarm_set = FALSE;
+
+                /* this signal will usually trigger a callback to the timer    
+                 * expiration handler, which will block until we release this 
+                 * lock, and then do nothing, since the reason code will indicate 
+                 * signaled rather than timer expiration. however if the timer 
+                 * were to have expired while we are here but before we signal it,  
+                 * the handler would again block, we would signal it below which 
+                 * would do nothing since the timer had already fired, and when  
+                 * we finally release the lock here, the handler would continue,
+                 * attempting to close the mailbox, which it would now find to be
+                 * already closed since we just closed it here. if on the other
+                 * hand the handler got the lock before we did, then it would
+                 * close the mailbox, and we would find it closed instead.
+                 */
+                etch_timer_stop(thisx->lifetimer);
+            }
+
+            /* todo when shutting down, ensure that the mailbox manager is not 
+             * destroyed prior to the mailboxes, and ensure that the manager can
+             * handle an unregister call on the mailbox and that the manager does
+             * not destroy the mailbox on unregister.
+             */
+            if (thisx->manager)
+                thisx->manager->unregister (thisx->manager, thisx->imailbox);
+
+            etchqueue_close(thisx->queue, ETCHQUEUE_NOLOCK);
+            result = 0;
+        }
+
+        etchqueue_unlock(thisx->queue);
+    } 
+
+    if (0 == result) 
+        etchmbox_fire_notify((etch_plainmailbox*)thisx);
+
+    return result;
+}
+
+
+/**
+ * etchmbox_close_read() 
+ */
+int etchmbox_close_read (void* data)
+{
+  i_mailbox* ibox = (i_mailbox*)data;
+    etch_config_t*  config      = NULL;
+    int32           propvalue   = 0;
+    etch_mailbox_element* qitem = NULL;
+    int         is_destroyentry = 0;
+    etch_int64* msgidobj        = NULL;
+    int64       msgid           = 0;
+    const char* delmsg   = "destroyed mailbox message %d\n";
+    const char* rrerrmsg = "could not reroute message %d from closed mailbox\n";
+    etch_plainmailbox* thisx    = NULL;
+
+    etch_runtime_get_config(&config);
+    ETCH_ASSERT(config);
+
+    if(ibox != NULL) {
+        thisx = ibox->thisx;
+    }
+    if(thisx == NULL) {
+        // error
+        return -1;
+    }
+
+    if (0 > etchmbox_close_delivery(ibox)) return -1;
+
+    /* state is ETCH_MAILBOX_CLOSED_DELIVERY or ETCH_MAILBOX_STATE_SHUTDOWN */
+    if (thisx->mailbox_state < ETCH_MAILBOX_STATE_CLOSED_READ)
+        thisx->mailbox_state = ETCH_MAILBOX_STATE_CLOSED_READ;
+
+    while(1)   /* pop entries off queue and reroute or destroy */
+    {
+        if (0 != etchmbox_read_withwait(ibox, ETCHQUEUE_CLEARING_CLOSED_QUEUE, &qitem))
+            break;
+
+        msgidobj = qitem->msg? message_get_id(qitem->msg): NULL;
+        msgid = msgidobj? msgidobj->value: 0;
+        is_destroyentry = FALSE;
+
+        etch_config_get_property_int(config, "etch.mailbox.destroy.message", &propvalue);
+        if (propvalue == 1 && thisx->mailbox_state == ETCH_MAILBOX_STATE_SHUTDOWN)
+            is_destroyentry = TRUE;
+        else   /* try to reroute the message */
+        if (0 != thisx->manager->redeliver(thisx->manager, qitem->whofrom, qitem->msg))
+        {    
+            is_destroyentry = TRUE;
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, rrerrmsg, msgid); 
+        }
+
+        if (is_destroyentry)   /* if message was not rerouted destroy it */
+        {
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, delmsg, msgid); 
+            etch_object_destroy(qitem->msg);
+            qitem->msg = NULL;
+        }
+
+        qitem->msg = NULL;     /* message has been disposed in some manner */
+        etch_object_destroy(qitem); /* destroy popped element wrapper */
+    }
+
+    return 0;
+}
+
+
+/**
+ * etchmbox_register_notify() 
+ * @param pfx etch_mailbox_notify callback
+ * @param state an etch object relinquishes by caller, owned by mailbox, 
+ * used to pass mailbox state on notification.
+ * @param maxdelay max time in milliseconds to wait for delivery, 0 forever, -1 no wait.
+ * @return 0 success, -1 failure.
+ */
+int etchmbox_register_notify (void* data, etch_mailbox_notify pfn, 
+    etch_object* state, const int maxdelay)
+{
+  i_mailbox* ibox = (i_mailbox*)data;
+    int result = -1, isqueue_notempty_or_closed = FALSE;
+    etch_plainmailbox* thisx = ibox? ibox->thisx: NULL;   
+    if (!thisx || !pfn || !state) return -1;
+
+    if (0 == etchqueue_lock(thisx->queue)) 
+    {
+        thisx->notify = pfn;
+        thisx->notify_state = state; /* caller relinquishes */
+        
+        if (maxdelay > 0 && !thisx->is_alarm_set)
+            etchmbox_set_duration(thisx, maxdelay);
+     
+        isqueue_notempty_or_closed 
+            = etchqueue_size(thisx->queue) || etchqueue_is_closed(thisx->queue);
+
+        result = etchqueue_unlock(thisx->queue);
+    } 
+
+    if (isqueue_notempty_or_closed)
+        etchmbox_fire_notify((etch_plainmailbox*)thisx);
+
+    return result;
+}
+
+
+/**
+ * etchmbox_unregister_notify() 
+ */
+int etchmbox_unregister_notify (void* data, etch_mailbox_notify pfn)
+{
+  i_mailbox* ibox = (i_mailbox*)data;
+    int result = -1;
+    etch_plainmailbox* thisx = ibox? ibox->thisx: NULL;   
+    if (!thisx || !pfn || pfn != thisx->notify) return -1;
+
+    if (0 == etchqueue_lock(thisx->queue)) 
+    {
+        if (thisx->is_alarm_set)
+        {
+            thisx->is_alarm_set = FALSE;
+
+            /* this signal will usually trigger a callback to the timer expiration   
+             * handler, which will block until we release this lock, and then do
+             * nothing, since the reason code will indicate signaled rather than
+             * timer expiration. however if the timer were to have expired while
+             * we are here but before we signal it, the handler would again block,  
+             * we would signal it below which would do nothing since the timer had
+             * already fired, and when we finally release the lock here, the handler
+             * would continue to presumably close the mailbox. if on the other hand
+             * the handler got the lock before we did, then the mailbox will now be
+             * closed when we finally get the lock.
+             */
+            etch_timer_stop(thisx->lifetimer);
+        }
+
+        thisx->notify = NULL;
+	    etch_object_destroy(thisx->notify_state);
+	    thisx->notify_state = NULL;
+
+
+        result = etchqueue_unlock(thisx->queue);
+    }
+
+    return result;
+}
+
+
+/**
+ * etchmbox_fire_notify() 
+ * notify registered party of mailbox status change
+ */
+int etchmbox_fire_notify (void* data)
+{
+    etch_plainmailbox* thisx = (etch_plainmailbox*)data;
+    int result = -1, is_closed = 0;
+    etch_mailbox_notify notify = NULL;
+    etch_object* notify_state = NULL;
+
+    if (0 == etchqueue_lock(thisx->queue)) 
+    {   
+        notify = thisx->notify;
+        is_closed = etchqueue_is_closed(thisx->queue);
+        notify_state = thisx->notify_state;
+
+        etchqueue_unlock(thisx->queue);
+    }
+
+    if (notify)
+        result = notify (thisx, thisx->imailbox, notify_state, is_closed);
+
+    return result;
+}
+
+
+/**
+ * etchmbox_is_empty() 
+ */
+int etchmbox_is_empty (void* data)
+{
+  i_mailbox* ibox = (i_mailbox*)data;
+    int is_locked = FALSE, is_empty = TRUE;
+    etch_plainmailbox* thisx = ibox? ibox->thisx: NULL; 
+
+    if (thisx) 
+    {   is_locked = 0 == etchqueue_trylock(thisx->queue);
+        is_empty  = etchqueue_size(thisx->queue) == 0;
+        if (is_locked) 
+            etchqueue_unlock(thisx->queue);
+    }
+
+    return is_empty;
+}
+
+
+/**
+ *  
+ */
+int etchmbox_is_closed (void* data)
+{
+  i_mailbox* ibox = (i_mailbox*)data;
+    int is_locked = FALSE, is_closed = TRUE;
+    etch_plainmailbox* thisx = ibox? ibox->thisx: NULL; 
+
+    if (thisx) 
+    {   is_locked = 0 == etchqueue_trylock(thisx->queue);
+        is_closed = etchqueue_is_closed(thisx->queue);
+        if (is_locked) 
+            etchqueue_unlock(thisx->queue);
+    }
+
+    return is_closed;
+}
+
+
+/**
+ * etchmbox_is_full() 
+ */
+int etchmbox_is_full (void* data)
+{
+  i_mailbox* ibox = (i_mailbox*)data;
+    int is_locked = FALSE, is_full = TRUE;
+    etch_plainmailbox* thisx = ibox? ibox->thisx: NULL; 
+
+    if (thisx) 
+    {   is_locked = 0 == etchqueue_trylock(thisx->queue);
+        is_full   = etchqueue_is_full(thisx->queue);
+        if (is_locked) 
+            etchqueue_unlock(thisx->queue);
+    }
+
+    return is_full;
+}
+
+
+/**
+ * etchmbox_get_message_id() 
+ */
+int64 etchmbox_get_message_id (void* data)
+{
+  i_mailbox* imailbox = (i_mailbox*)data;
+     etch_plainmailbox* thisx = (etch_plainmailbox*) imailbox->thisx;
+     return thisx? thisx->message_id: 0;
+}
+
+
+/* - - - - - - - - -
+ * private
+ * - - - - - - - - - 
+*/
+
+/**
+ * etchmbox_is_alarm_set()
+ * used to test is_alarm_set from outside a queue lock only.
+ * do not use inside a queue lock, test is_alarm_set directly in that case.
+ * use from inside a queue lock will deadlock since the lock is non-recursive.
+ */
+int etchmbox_is_alarm_set(etch_plainmailbox* thisx) 
+{
+    int result = FALSE;
+
+    if (0 == etchqueue_lock(thisx->queue)) 
+    {
+        result = thisx->is_alarm_set;
+        etchqueue_unlock(thisx->queue);
+    }
+    
+    return result;
+}
+
+
+/**
+ * etchmbox_test_and_set_alarm_set()
+ * used to test and set is_alarm_set from outside a queue lock only.
+ * do not use inside a queue lock, set is_alarm_set directly in that case.
+ * use from inside a queue lock will deadlock since the lock is non-recursive
+ */
+int etchmbox_test_and_set_alarm_set(etch_plainmailbox* thisx, const int value) 
+{
+    int result = FALSE;
+
+    if (0 == etchqueue_lock(thisx->queue)) 
+    {
+        result = thisx->is_alarm_set;
+        thisx->is_alarm_set = value? TRUE: FALSE;
+        etchqueue_unlock(thisx->queue);
+    }
+
+    return result;
+}
diff --git a/binding-c/runtime/c/src/main/transport/etch_plain_mailbox_manager.c b/binding-c/runtime/c/src/main/transport/etch_plain_mailbox_manager.c
new file mode 100644
index 0000000..fa4ffda
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_plain_mailbox_manager.c
@@ -0,0 +1,761 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_plainmailboxmgr.c
+ * mailbox manager accepts packets for potential delivery to a mailbox or to an
+ * alternate message handler if an appropriate mailbox is not available. 
+ * a mailbox can be created on request keyed by the a message's ID.
+ */
+
+#include "etch_runtime.h"
+#include "etch.h"
+#include "etch_plain_mailbox_manager.h"
+#include "etch_plain_mailbox.h"
+#include "etch_objecttypes.h"
+#include "etch_thread.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+#include "etch_arrayval.h"
+
+static const char* LOG_CATEGORY = "etch_plain_mailbox_manager";
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+static int64         g_message_id       = 0;
+static etch_mutex_t* g_message_id_mutex = NULL;
+
+// forward declarations
+static int64 etch_plain_mailbox_manager_generate_message_id();
+
+
+
+etch_plainmailboxmgr* new_plain_mailbox_manager_a(i_transportmessage*, const int, etch_mutex*); 
+int destroy_plainmailboxmgr(void*);
+etch_hashtable* new_pmboxmgr_mailboxmap();
+etch_status_t etch_plain_mailbox_manager_shutdown_hook_func();
+
+int      pmboxmgr_transport_call   (void*, etch_who*, etch_message*, i_mailbox**); 
+int      pmboxmgr_redeliver        (void*, etch_who*, etch_message*); 
+int      pmboxmgr_unregister       (void*, i_mailbox*);
+int      pmboxmgr_session_message  (void*, etch_who*, etch_message*);
+int      pmboxmgr_session_control  (void*, etch_event*, etch_object*);
+int      pmboxmgr_session_notify   (void*, etch_event*);
+etch_object* pmboxmgr_session_query    (void*, etch_query*); 
+int      pmboxmgr_transport_control(void*, etch_event*, etch_object*);
+int      pmboxmgr_transport_notify (void*, etch_event*);
+etch_object* pmboxmgr_transport_query  (void*, etch_query*);
+i_session* pmboxmgr_get_session(void*); 
+
+
+/* - - - - - - - - - - - - - - -
+ * ctor/dtor
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * new_plain_mailbox_manager()
+ * etch_plainmailboxmgr public constructor
+ * @param itm i_transportmessage interface object, caller retains ownership.
+ * @param uri url string, caller relinquishes ownership.
+ * @param resxmap caller retains ownership.
+ * @param rwlock global mutex for mailbox read write sync, caller retains.
+ */
+etch_plainmailboxmgr* new_plain_mailbox_manager (i_transportmessage* itm, 
+    wchar_t* uri, etch_resources* resxmap, etch_mutex* rwlock) 
+{
+    etch_plainmailboxmgr* mgr = new_plain_mailbox_manager_a(itm, ETCH_INFWAIT, rwlock);
+    if (NULL == mgr) return NULL;
+
+    return mgr;
+}
+
+
+/**
+ * pmboxmgr_set_session()
+ * @param newsession an i_sessionmessage reference. caller owns this object.
+ * this will be invoked from delivery service constructor.
+ */
+void pmboxmgr_set_session (void* data, void* sessionData)
+{
+    etch_plainmailboxmgr* thisx = (etch_plainmailboxmgr*)data;
+    i_session* newsession = (i_session*)sessionData;
+    ETCH_ASSERT(is_etch_mailboxmgr(thisx));
+    ETCH_ASSERT(is_etch_sessionmsg(newsession));
+
+    /* set our session to passed (delivery service's) session */
+    thisx->session = (i_sessionmessage*)newsession;   
+}
+
+/**
+ * pmboxmgr_transport_message()
+ * i_transportmessage::transport_message override.
+ * @param whoto, caller retains, can be null.
+ * @param msg caller abandons on success, retains on failure.
+ */
+int pmboxmgr_transport_message (void* data, void* whoData, void* messageData)
+{
+    etch_plainmailboxmgr* mgr = (etch_plainmailboxmgr*)data;
+    etch_who* whoto = (etch_who*)whoData;
+    etch_message* msg = (etch_message*)messageData;
+    int result = 0;
+
+    etch_int64* msgid = message_get_id(msg);  /* expect NULL (not yet sent) */
+    if (NULL != msgid) return -1;  /* already sent */
+
+    msgid  = new_int64(etch_plain_mailbox_manager_generate_message_id()); /* assign ID to message */
+    result = message_set_id(msg, msgid);  /* relinquish msgid object */
+
+    if (0 == result)  
+        result = mgr->transport->transport_message (mgr->transport->thisx, whoto, msg);
+
+    return result;
+}
+
+
+/**
+ * new_plain_mailbox_manager_a()
+ * etch_plainmailboxmgr private constructor
+ * @param itm transportmessage interface, not owned.
+ * @param maxdelay maximum time in milliseconds to wait for a full mailbox
+ * @param rwlock global mutex for mailbox read write sync, caller retains.
+ * to become unfull before giving up and delivering to the message handler. 
+ * ETCH_INFWAIT indicates wait forever, ETCH_NOWAIT indicates do not block.
+ */
+etch_plainmailboxmgr* new_plain_mailbox_manager_a (i_transportmessage* itm, 
+    const int maxdelay, etch_mutex* rwlock)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_plainmailboxmgr* mgr = NULL;
+    i_mailbox_manager* imgr = NULL;
+    etch_hashtable* mboxmap = NULL;
+    i_transport* itransport = NULL;
+    i_session* isession = NULL;
+    etch_mutex* mutex = NULL;  /* not used - lose it */
+    int result = -1;
+
+    do
+    {
+
+        if(g_message_id_mutex == NULL) {
+            // TODO: this should be removed, and added to .._module_initialize
+            // TODO: pool
+            status = etch_mutex_create(&g_message_id_mutex, ETCH_MUTEX_NESTED, NULL);
+            ETCH_ASSERT(status == ETCH_SUCCESS);
+            ETCH_ASSERT(g_message_id_mutex != NULL);
+            etch_runtime_shutdown_hook_add(etch_plain_mailbox_manager_shutdown_hook_func);
+            g_message_id = apr_time_now();
+        }
+
+        // TODO: pool
+        status = etch_mutex_create(&mutex, ETCH_MUTEX_NESTED, NULL);
+        if(status != ETCH_SUCCESS) {
+            // error
+            break;
+        }
+        if (NULL == (mboxmap = new_pmboxmgr_mailboxmap())) break;
+
+        /* - - - - - - - - - - - - - - -
+         * etch_plainmailboxmgr
+         * - - - - - - - - - - - - - - -
+         */
+        mgr = (etch_plainmailboxmgr*) new_object(sizeof(etch_plainmailboxmgr), ETCHTYPEB_MBOXMGR_IMPL, CLASSID_PLAIN_MBOXMGR);
+
+        ((etch_object*)mgr)->destroy = destroy_plainmailboxmgr;
+        ((etch_object*)mgr)->clone   = clone_null;
+        mgr->xlock   = mutex;   /* not used - lose it */
+        mgr->rwlock  = rwlock;  /* not owned */
+        mgr->mailboxes = mboxmap;
+        mgr->max_delay = maxdelay;
+
+        /* set our transport to that of next lower layer (messagizer) */
+        mgr->transport = itm;  /* not owned */
+        /* note that mgr::transport::session has not been set yet. it will be set  
+         * to mgr::session in mgr::set_session(), assuming that code invokes it.
+         * it is safer to leave mgr::transport::session null, than to point it to
+         * a session which is null. this effectively precludes code from setting
+         * mgr::session directly; code should use mgr::set_session() to do so.
+         */
+
+        /* - - - - - - - - - - - - - - -
+         * i_transportmessage (forward)
+         * - - - - - - - - - - - - - - -
+         */
+        itransport = new_transport_interface (mgr,  
+            (etch_transport_control) pmboxmgr_transport_control, 
+            (etch_transport_notify)  pmboxmgr_transport_notify, 
+            (etch_transport_query)   pmboxmgr_transport_query);
+        itransport->get_session    = pmboxmgr_get_session;
+        itransport->set_session    = pmboxmgr_set_session;
+
+        /* instantiate i_transportmessage interface which messagizer implements */
+        mgr->transportmsg = new_transportmsg_interface (mgr, 
+            pmboxmgr_transport_message, 
+            itransport);  /* transportmsg now owns itransport */
+
+        /* copy i_transportmessage interface methods up to messagizer */
+        mgr->transport_message = pmboxmgr_transport_message;
+        mgr->transport_control = itransport->transport_control;
+        mgr->transport_notify  = itransport->transport_notify;
+        mgr->transport_query   = itransport->transport_query;
+        mgr->get_session       = itransport->get_session;
+        mgr->set_session       = itransport->set_session;  
+
+        /* - - - - - - - - - - - - - - -
+         * i_mailbox_manager 
+         * - - - - - - - - - - - - - - -
+         */
+        imgr = new_mailboxmgr_interface (mgr, mgr->transportmsg, mgr->session);
+        mgr->imanager = imgr;
+        imgr->rwlock  = rwlock;
+
+        imgr->transport_call = mgr->transport_call = (etch_mbm_transport_call)pmboxmgr_transport_call;
+        imgr->redeliver      = mgr->redeliver      = pmboxmgr_redeliver;
+        imgr->unregister     = mgr->unregister     = pmboxmgr_unregister; 
+
+        /* i_mailbox_manager::i_transport */
+        imgr->transport_message = mgr->transport_message = pmboxmgr_transport_message;
+        imgr->transport_control = mgr->transport_control = pmboxmgr_transport_control;
+        imgr->transport_notify  = mgr->transport_notify  = pmboxmgr_transport_notify;
+        imgr->transport_query   = mgr->transport_query   = pmboxmgr_transport_query;  
+        imgr->get_session       = mgr->get_session       = pmboxmgr_get_session; 
+        imgr->set_session       = mgr->set_session       = pmboxmgr_set_session;  
+
+        /* - - - - - - - - - - - - - - -
+         * i_sessionmessage (backward) 
+         * - - - - - - - - - - - - - - -
+         */
+        isession = new_session_interface(mgr,  
+            (etch_session_control) pmboxmgr_session_control, 
+            (etch_session_notify)  pmboxmgr_session_notify, 
+            (etch_session_query)   pmboxmgr_session_query);
+
+        /* instantiate the i_sessionmessage interface which mbox mgr implements */
+        mgr->isessionmsg = new_sessionmsg_interface(mgr, 
+            pmboxmgr_session_message, 
+            isession);  /* isessionmsg now owns isession */
+
+        imgr->ism = mgr->isessionmsg;  /* relinquish isessionmsg to imgr */
+
+        /* copy sessionmsg interface methods to parent */
+        mgr->session_message = imgr->session_message = pmboxmgr_session_message;
+        mgr->session_control = imgr->session_control = isession->session_control;
+        mgr->session_notify  = imgr->session_notify  = isession->session_notify;
+        mgr->session_query   = imgr->session_query   = isession->session_query;
+
+        /* finally set session of next lower layer (messagizer) to our session */
+        /* fyi mgr->transport->thisx is messagizer, the transport implementor */
+        if (mgr->transport) /* transport always supplied except by unit test */
+            mgr->transport->set_session (mgr->transport->thisx, mgr->isessionmsg);  
+
+        result = 0;    
+
+    } while(0);
+
+    if (-1 == result)
+    {
+        status = etch_mutex_destroy(mutex);
+        ETCH_ASSERT(status == ETCH_SUCCESS);
+        
+        etch_object_destroy(mboxmap);
+        etch_object_destroy(imgr);
+        if (mgr)     
+            etch_free(mgr);
+        mgr = NULL;
+    } 
+
+    return mgr;
+}
+
+
+/**
+ * destroy_plainmailboxmgr()
+ * destructor for etch_plainmailboxmgr
+ */
+int destroy_plainmailboxmgr(void* data)
+{
+    etch_plainmailboxmgr* thisx = (etch_plainmailboxmgr*)data;
+    etch_iterator iterator;
+    int count = 1;
+    //signal interrupt to all mailboxes
+    set_iterator(&iterator, thisx->mailboxes, &thisx->mailboxes->iterable);
+    while(iterator.has_next(&iterator))
+    {
+        i_mailbox* mb = (i_mailbox*) iterator.current_value;
+        etch_apr_queue_interrupt_all(((etch_plainmailbox*)mb->thisx)->queue->aprq);
+        iterator.next(&iterator);
+    }
+    
+    //wait until all mailboxes are unregistered
+    while(count != 0){
+        count = ((struct i_hashtable*)((etch_object*)thisx->mailboxes)->vtab)->count(thisx->mailboxes->realtable,0,0);
+        apr_sleep(1000 * 1000);
+    }
+    
+    if (!is_etchobj_static_content(thisx))
+    {
+        etch_mutex_destroy(thisx->xlock);
+        thisx->xlock = NULL;
+
+		etch_object_destroy(thisx->mailboxes);
+		thisx->mailboxes = NULL;
+
+		etch_object_destroy(thisx->imanager);
+		thisx->imanager = NULL;
+
+    }
+
+   return destroy_objectex((etch_object*) thisx);
+}
+
+
+/* - - - - - - - - - - - - - - -
+ * i_sessionmessage
+ * - - - - - - - - - - - - - - -
+ */
+
+ /**
+ * get_etchmbm_session()
+ * convenience method to validate the etch_plainmailboxmgr, get, validate,
+ * and return the etch_plainmailboxmgr's session.
+ */
+i_sessionmessage* get_etchmbm_session (etch_plainmailboxmgr* mgr)
+{
+    i_sessionmessage* session = NULL;
+    ETCH_ASSERT(is_etch_mailboxmgr(mgr));
+    session = mgr->session;
+    ETCH_ASSERT(is_etch_sessionmsg(session));
+    return session;
+}   
+
+
+/**
+ * pmboxmgr_session_message()
+ * queue specified message to the message's mailbox.
+ * @param whofrom caller retains, can be null.
+ * @param msg caller abandons on success (0), retains on other than success.
+ * @return 0 (message handled), or -1 (error, mailbox closed, or timeout)  
+ */
+int pmboxmgr_session_message (void* data, etch_who* whofrom, etch_message* msg)
+{
+    etch_plainmailboxmgr* mgr = (etch_plainmailboxmgr*)data;
+    int result = 0;
+    i_mailbox* ibox = NULL;
+    etch_int64* msgid = NULL; 
+    i_sessionmessage* session = get_etchmbm_session (mgr);
+
+    if(msg == NULL) {
+        return -1;
+    }
+
+    if (NULL == (msgid = message_get_in_reply_to (msg)))  /* msgid not ours */
+        return session->session_message (session->thisx, whofrom, msg);  
+
+    /* fyi no mailbox will exist for a one-way message */
+    ibox = pmboxmgr_get_mailbox (mgr, msgid);
+
+    /* todo ensure that caller destroys message on error return */
+    if (NULL == ibox || ibox->is_closed(ibox)) return -1;
+
+    result = ibox->message (ibox, whofrom, msg);  
+
+    if (0 != result)  /* ETCH_MAILBOX_TIMEOUT (-2) or mailbox closed (-1) */
+        result = -1;
+ 
+    return result;
+}
+
+
+/**
+ * pmboxmgr_session_control()
+ * i_sessionmsg::session_control override.
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+int pmboxmgr_session_control (void* data, etch_event* control, etch_object* value)
+{
+  etch_plainmailboxmgr* mgr = (etch_plainmailboxmgr*)data;
+    i_sessionmessage* session = get_etchmbm_session (mgr);
+    return session->session_control(session->thisx, control, value);
+}
+
+
+/**
+ * pmboxmgr_session_notify()
+ * i_sessionmsg::session_notify override.
+ * @param event, caller relinquishes.
+ */
+int pmboxmgr_session_notify (void* data, etch_event* evt)
+{
+  etch_plainmailboxmgr* mgr = (etch_plainmailboxmgr*)data;
+    int result = 0;
+    const int event_type = evt->value;
+    i_sessionmessage* session = get_etchmbm_session (mgr);
+
+    switch(event_type)
+    {   case ETCHEVT_SESSION_UP:   
+             mgr->is_connection_up = TRUE; 
+             break;
+        case ETCHEVT_SESSION_DOWN: 
+             mgr->is_connection_up = FALSE; 
+             result = pmboxmgr_unregister_all (mgr);
+    }
+
+    return session->session_notify (session->thisx, evt);
+}
+
+
+/**
+ * pmboxmgr_session_query()
+ * i_sessionmsg::session_query override.
+ * @param query, caller relinquishes.
+ */
+etch_object* pmboxmgr_session_query (void* data, etch_query* query) 
+{
+    etch_plainmailboxmgr* mgr = (etch_plainmailboxmgr*)data;
+    i_sessionmessage* session = get_etchmbm_session (mgr);
+    return session->session_query (session->thisx, query);
+}
+
+
+/* - - - - - - - - - - - - - - -
+ * i_transportmessage
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * get_etchmbm_transport()
+ * convenience method to validate the etch_plainmailboxmgr, get, validate,
+ * and return the etch_plainmailboxmgr's transport.
+ */
+i_transportmessage* get_etchmbm_transport(etch_plainmailboxmgr* mgr)
+{
+    i_transportmessage* transport = NULL;
+    ETCH_ASSERT(is_etch_mailboxmgr(mgr));
+    transport = mgr->transport;
+    ETCH_ASSERT(is_etch_transportmsg(transport));
+    return transport;
+}
+
+
+/**
+ * pmboxmgr_transport_control()
+ * i_transportmessage::transport_control override.
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+int pmboxmgr_transport_control (void* data, etch_event* control, etch_object* value)
+{
+  etch_plainmailboxmgr* mgr = (etch_plainmailboxmgr*)data;
+    i_transportmessage* transport = get_etchmbm_transport(mgr);
+    return transport->transport_control (transport->thisx, control, value);
+}
+
+
+/**
+ * pmboxmgr_transport_notify()
+ * i_transportmessage::transport_notify override.
+ * @param evt, caller relinquishes.
+ */
+int pmboxmgr_transport_notify (void* data, etch_event* evt)
+{
+  etch_plainmailboxmgr* mgr = (etch_plainmailboxmgr*)data;
+    i_transportmessage* transport = get_etchmbm_transport(mgr);
+    return transport->transport_notify(transport->thisx, evt);
+}
+
+
+/**
+ * pmboxmgr_transport_query()
+ * i_transportmessage::transport_query override.
+ * @param query, caller relinquishes.
+ */
+etch_object* pmboxmgr_transport_query (void* data, etch_query* query) 
+{
+    etch_plainmailboxmgr* mgr = (etch_plainmailboxmgr*)data;
+    i_transportmessage* transport = get_etchmbm_transport(mgr);
+    return transport->transport_query(transport->thisx, query);
+}
+
+
+/**
+ * pmboxmgr_get_session()
+ * @return a reference to the messagizer i_sessionmessage interface.
+ * this object is owned by whatever object set the messagizer session.
+ */
+i_session* pmboxmgr_get_session (void* data) 
+{
+    etch_plainmailboxmgr* mgr = (etch_plainmailboxmgr*)data;
+    ETCH_ASSERT(is_etch_mailboxmgr(mgr));
+    return (i_session*)mgr->session;
+}
+
+
+
+
+/* - - - - - - - - - - - - - - -
+ * i_mailbox_manager
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * pmboxmgr_transport_call()
+ */
+ int pmboxmgr_transport_call (void* data, etch_who* whoto, 
+    etch_message* msg, i_mailbox** out) 
+{
+  i_mailbox_manager* imgr = (i_mailbox_manager*)data;
+    int result = 0;
+    i_mailbox* ibox = NULL;
+    etch_plainmailbox* mbox = NULL;
+    etch_plainmailboxmgr* mgr = NULL;
+    etch_int64 *msgid = NULL, *inreplyto = NULL;
+    const int MAXMESSAGES_ONE = 1, lifetime = MBOX_LIFETIME_UNTIL_CLOSE;
+    ETCH_ASSERT(is_etch_imailboxmgr(imgr));
+    mgr = imgr->thisx;
+    ETCH_ASSERT(is_etch_mailboxmgr(mgr));
+
+    msgid     = message_get_id(msg);   /* expect NULL (not yet sent) */
+    inreplyto = message_get_in_reply_to(msg);
+    if (NULL != msgid)     return -1;  /* already sent */
+    if (NULL != inreplyto) return -1;  /* marked as reply */
+
+    msgid  = new_int64(etch_plain_mailbox_manager_generate_message_id());
+    result = message_set_id(msg, msgid);  /* assign ID to message */
+    if (0 != result) return -1;
+
+    mbox = new_mailbox (imgr, msgid->value, mgr->max_delay, lifetime, MAXMESSAGES_ONE);
+
+    if (mbox) ibox = mbox->imailbox;
+    if (NULL == ibox) return -1;
+ 
+    result = pmboxmgr_register_mailbox (mgr, ibox);
+
+    /* currently lifetime is always zero (until explictly closed); however if
+     * lifetime were to be > 0, a timer would enter the picture, and since we
+     * do not currently have a proper timer pool, our simple timer thread   
+     * might need a start cushion.
+     */
+    if (0 == result && lifetime > 0)
+        etch_sleep(100);  
+
+    if (0 == result)  
+        result = mgr->transport->transport_message (mgr->transport->thisx, whoto, msg);
+
+    if (0 == result)
+        if (out) 
+            *out = ibox;
+        else;
+    else 
+        pmboxmgr_unregister(imgr, ibox);
+
+    return result;
+}
+
+
+/**
+ * pmboxmgr_redeliver()
+ * forwards specified message
+ */
+int pmboxmgr_redeliver (void* data, etch_who* whofrom, etch_message* msg) 
+{
+    i_mailbox_manager* imgr = (i_mailbox_manager*)data;
+    etch_iterator iterator;
+    etch_hashtable* map = NULL;
+    etch_plainmailboxmgr* mgr = NULL;
+    ETCH_ASSERT(is_etch_imailboxmgr(imgr));
+    mgr = imgr->thisx;
+    ETCH_ASSERT(is_etch_mailboxmgr(mgr));
+
+    map = mgr->mailboxes;
+    hashtable_getlock(map);
+    set_iterator(&iterator, map, &map->iterable);
+
+    while(iterator.has_next(&iterator))
+    {   /* TODO if change i_mailbox to be etch_object based, check class_id here */
+        i_mailbox* ibox = (i_mailbox*) iterator.current_value;
+        if (ibox)
+            ibox->close_delivery(ibox);
+
+        iterator.next(&iterator);
+    }
+
+    hashtable_rellock(map);
+    return 0;
+}
+
+
+/**
+ * pmboxmgr_unregister()
+ * remove specified mailbox from manager.
+ * the unregistered box is *not* destroyed - whoever registered it owns it.
+ */
+int pmboxmgr_unregister (void* data, i_mailbox* ibox)
+{
+  i_mailbox_manager* imgr = (i_mailbox_manager*)data;
+    int64 msgid;   
+    unsigned hashval;
+    etch_hashtable* map;
+    etch_int64* itemkey;
+    etch_hashitem hi, *removed = &hi; 
+    etch_plainmailboxmgr* mgr = imgr? imgr->thisx: NULL;
+    if (NULL == mgr) return -1;
+
+    map   = mgr->mailboxes;
+    msgid = ibox->get_message_id(ibox);
+    hashval = etchhash(&msgid, sizeof(int64), 0);
+
+    if (-1 == ((struct i_hashtable*)((etch_object*)map)->vtab)->removeh (map->realtable, hashval, map, (void**)&removed))
+        return -1;
+    itemkey = (etch_int64*) removed->key;
+    ETCH_ASSERT(is_etch_int64(itemkey));
+    etch_free(itemkey);  /* once we remove the entry, we own the key */
+    return 0;
+}
+
+
+/* - - - - - - - - - - - - - - 
+ * etch_plaingmboxmgr public 
+ * - - - - - - - - - - - - - - 
+ */
+
+/**
+ * pmboxmgr_register_mailbox()
+ * add specified mailbox to set of mailboxes receiving responses to messages.
+ * @param ibox caller retains ownership. 
+ * TODO does mgr need to own and destroy mailboxes? if so, i_mailbox
+ * destructor must destroy its parent object. maybe it needs to do this anyway.
+ */
+int pmboxmgr_register_mailbox(etch_plainmailboxmgr* mgr, i_mailbox* ibox)
+{
+    int result = -1;
+
+    if (mgr->is_connection_up)
+    {   etch_hashtable* map = mgr->mailboxes;
+        int64 message_id  = ibox->get_message_id(ibox);
+        etch_int64* idobj = new_int64(message_id);
+        /* insert mailbox to synchronized map */
+        ((etch_object*)idobj)->get_hashkey(idobj);
+        result = ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth(map->realtable, idobj, ibox, map, 0);
+        if (-1 == result) etch_free(idobj); /* duplicate id */
+    }
+    else
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "attempt to register disconnected mailbox\n");
+
+    return result;
+}
+
+
+/**
+ * pmboxmgr_get_mailbox()
+ * return interface to mailbox having specified message id, or NULL.
+ */
+ i_mailbox* pmboxmgr_get_mailbox(etch_plainmailboxmgr* mgr, etch_int64* msgid) 
+{
+    etch_hashtable* map = mgr->mailboxes;
+    etch_hashitem hi, *entry = &hi; 
+
+    const int result = ((struct i_hashtable*)((etch_object*)map)->vtab)->findh(map->realtable, ((etch_object*)msgid)->get_hashkey(msgid), map, (void**)&entry);
+    return result == 0? (i_mailbox*) entry->value: NULL;
+}
+
+
+/**
+ * pmboxmgr_unregister_all()
+ * unregisters all mailboxes
+ */
+ int pmboxmgr_unregister_all(etch_plainmailboxmgr* mgr) 
+{
+    etch_hashtable* map = mgr->mailboxes;
+    etch_iterator iterator;
+    hashtable_getlock(map);
+    set_iterator(&iterator, map, &map->iterable);
+
+    while(iterator.has_next(&iterator))
+    {
+        i_mailbox* ibox = (i_mailbox*) iterator.current_value;
+        if (ibox)
+            ibox->close_delivery(ibox);
+
+        iterator.next(&iterator);
+    }
+
+    hashtable_rellock(map);
+    return 0;
+}
+
+
+/**
+ * pmboxmgr_size()
+ * return count of registered mailboxes
+ */
+ int pmboxmgr_size(etch_plainmailboxmgr* mgr) 
+{
+    etch_hashtable* map = mgr->mailboxes;
+    return ((struct i_hashtable*)((etch_object*)map)->vtab)->count(map->realtable, map, 0);
+}
+
+
+/* - - - - - - - - - - - - - - -
+ * etch_plaingmboxmgr private
+ * - - - - - - - - - - - - - - -
+ */
+ 
+/**
+ * new_pmboxmgr_mailboxmap()
+ * construct and return a hashtable configured as expected for the mailbox map.
+ * this map's destructor will destroy neither key objects nor value objects.  
+ */
+etch_hashtable* new_pmboxmgr_mailboxmap()
+{
+    etch_hashtable* map = new_hashtable_synchronized(ETCHMBMGR_DEFNUMMAILBOXES); 
+    map->content_type = ETCHHASHTABLE_CONTENT_OBJECT_OBJECT;
+    map->is_readonly_keys = FALSE;  /* owns key objects */
+    map->is_readonly_values = TRUE; /* does not own mailbox */
+    return map;
+}
+
+
+
+
+etch_status_t etch_plain_mailbox_manager_shutdown_hook_func()
+{
+    if(g_message_id_mutex != NULL) {
+        etch_mutex_destroy(g_message_id_mutex);
+        g_message_id_mutex = NULL;
+    }
+    return ETCH_SUCCESS;
+}
+
+/**
+ * etch_generate_message_id()
+ * atomically generate a new message ID
+ */
+static int64 etch_plain_mailbox_manager_generate_message_id()
+{
+    etch_status_t status     = ETCH_SUCCESS;
+    int64         message_id = 0;
+
+    status = etch_mutex_lock(g_message_id_mutex);
+    ETCH_ASSERT(status == ETCH_SUCCESS);
+    message_id = ++g_message_id;
+    status = etch_mutex_unlock(g_message_id_mutex);
+    ETCH_ASSERT(status == ETCH_SUCCESS);
+    return message_id;
+}
diff --git a/binding-c/runtime/c/src/main/transport/etch_queue.c b/binding-c/runtime/c/src/main/transport/etch_queue.c
new file mode 100644
index 0000000..e59b1ea
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_queue.c
@@ -0,0 +1,445 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/**
+ * etch_queue.c  
+ */
+
+#include "etch_queue.h"
+#include "etch_thread.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+#include "etch_runtime.h"
+#include "etch_objecttypes.h"
+
+/*
+static const char* LOG_CATEGORY = "etch_queue";
+*/
+
+extern apr_pool_t*         g_etch_main_pool;
+
+int  destroy_etch_queue(void*);
+void etchqueue_clear(etch_queue*); 
+int  etchqueue_iterable_first(etch_iterator*);
+int  etchqueue_iterable_next(etch_iterator*);
+int  etchqueue_iterable_has_next(etch_iterator*);
+
+
+
+/**
+ * new_queue()
+ * etch_queue constructor
+ */
+etch_queue* new_queue(const int initialsize)
+{
+    etch_queue* newq = NULL;
+    etch_apr_queue_t* aprq = NULL;
+    apr_pool_t* newsubpool = NULL;
+    int result = -1, qsize = initialsize > 0? initialsize: ETCH_DEFQSIZE;
+
+    do
+    {
+
+        // TODO: pool
+        result = apr_pool_create(&newsubpool, g_etch_main_pool);
+        //printf("2 creating apr pool %p\n",newsubpool);
+        if (0 != result) break; 
+        /* set pool abort function */
+        apr_pool_abort_set(etch_runtime_mem_abort, newsubpool);
+        
+
+        result = etch_apr_queue_create (&aprq, qsize, newsubpool);
+        if (0 != result) break;
+
+        newq = (etch_queue*) new_object(sizeof(etch_queue), ETCHTYPEB_ETCHQUEUE, CLASSID_ETCHQUEUE);
+
+        newq->aprq = aprq;
+        newq->subpool = newsubpool;
+        newq->qcapacity = initialsize;
+        ((etch_object*)newq)->destroy = destroy_etch_queue;
+        /* assume content to be etch objects owned by the queue */
+        newq->is_readonly  = FALSE; 
+        newq->content_type = ETCHQUEUE_CONTENT_OBJECT;
+
+        new_iterable(&newq->iterable, NULL, etchqueue_iterable_first, 
+            etchqueue_iterable_next, etchqueue_iterable_has_next); 
+
+        result = 0;
+
+    } while(0);
+
+    if (0 != result)
+    {
+        if (newsubpool) {
+            //printf("3 destroying apr pool %p\n",newsubpool);
+            apr_pool_destroy(newsubpool);
+        }
+    }
+
+    return newq;
+}
+
+
+/*
+ * destroy_etch_queue()
+ * etch_queue destructor
+ */
+int destroy_etch_queue(void* data)
+{
+    etch_queue* queue = (etch_queue*)data;
+    if (NULL == queue) return -1; 
+
+    if  (-1 == etch_apr_queue_trylock(queue->aprq))
+         return -1; 
+    else etch_apr_queue_unlock(queue->aprq); 
+               
+    if (!is_etchobj_static_content(queue))
+    {
+        /* free etch-managed memory */
+        etchqueue_clear(queue);
+
+        /* free APR-managed memory - APR queue sets a callback such that 
+         * destroying the memory pool destroys the APR queue object */
+        if (queue->subpool)  {
+            //printf("4 destroying apr pool %p\n",queue->subpool);
+            apr_pool_destroy(queue->subpool);
+        }
+
+        queue->subpool = NULL;
+        queue->aprq = NULL;
+    }
+
+    return destroy_objectex((etch_object*)queue);
+}
+
+
+/*
+ * etchqueue_clear() 
+ * frees queue content memory. 
+ * this ensures the underlying queue is closed, so it is only invoked prior to
+ * destruction of the queue in order to free any remaining queued etch objects.
+ * all other memory associated with the queue, other than the shell object, 
+ * is managed by APR. 
+ */
+void etchqueue_clear(etch_queue* thisx) 
+{
+    if (NULL == thisx || NULL == thisx->aprq || thisx->is_readonly) return;
+    etchqueue_close(thisx, TRUE); /* close queue and notify all waiters */
+
+    do
+    {   void* qobj = NULL;
+        queuecallback callback = thisx->freehook;
+        int i = 0, is_freehandled = 0, result = 0;
+        const int is_obj_content = thisx->content_type == ETCHQUEUE_CONTENT_OBJECT;
+
+        while(1)
+        {
+            result = etchqueue_get_withwait (thisx, ETCHQUEUE_CLEARING_CLOSED_QUEUE, &qobj);
+            if (0 != result) break;
+
+            is_freehandled = callback? callback(i, qobj): FALSE; 
+
+            if  (is_freehandled);
+            else
+            if  (is_obj_content)
+                ((etch_object*)qobj)->destroy(qobj);            
+            else etch_free(qobj);
+        }  
+
+    } while(0);
+}
+
+            
+/**
+ * etchqueue_size()
+ * @return current queue depth
+ * not thread-safe, caller should hold the mailbox queue lock
+ */
+int etchqueue_size(etch_queue* thisx) 
+{
+    return thisx && thisx->aprq? etch_apr_queue_size(thisx->aprq): 0;
+}
+
+
+/**
+ * etchqueue_is_closed()
+ * not thread-safe, caller should hold the mailbox queue lock
+ */
+int etchqueue_is_closed(etch_queue* thisx)
+{
+    return thisx && thisx->aprq? thisx->aprq->terminated != 0: TRUE; 
+}
+
+
+/**
+ * etchqueue_is_full()
+ * not thread-safe, caller should hold the mailbox queue lock
+ */
+int etchqueue_is_full(etch_queue* thisx)
+{
+    return thisx && thisx->aprq? thisx->aprq->nelts == thisx->aprq->bounds: TRUE; 
+}
+
+
+/**
+ * etchqueue_close()
+ * underlying implementation ensures operation atomicity
+ */
+int etchqueue_close(etch_queue* thisx, const int is_needlock)
+{
+    int result = 0;
+
+    if (!etchqueue_is_closed(thisx)) 
+    {
+        if (is_needlock)
+            result = etch_apr_queue_term(thisx->aprq);
+        else
+            result = etch_apr_queue_unsafeclose(thisx->aprq);
+
+        result = result == 0? 0: -1;
+    }
+    return result;
+}
+
+
+/**
+ * etchqueue_put()
+ * push specified item onto the queue. if the queue is full, 
+ * wait indefinitely until space becomes available.
+ * @return 0 success, -1 error.
+ */
+int etchqueue_put(etch_queue* thisx, void* item)
+{
+    const int result = etchqueue_put_withwait(thisx, ETCH_INFWAIT, item);
+    return result;
+}
+
+
+/**
+ * etchqueue_put_withwait()
+ * push specified item onto the queue. if the queue is full, 
+ * waitms specified time interval until space becomes available.
+ * @param waitms wait interval in milliseconds. specify ETCH_INFWAIT to wait
+ * forever, ETCH_NOWAIT to not wait.
+ * @return 0 success, -1 unsuccessful.
+ * 
+ */
+int etchqueue_put_withwait(etch_queue* thisx, const int waitms, void* item)
+{
+    int result = 0, aprresult = 0;
+    const int64 wait_usec = waitms < 0? -1: waitms * 1000;
+    if (NULL == item || etchqueue_is_closed(thisx)) return -1;
+
+    /*
+     * etch_apr_queue_push() takes care of notifying threads waiting on a
+     * queue slot to become available, if any.
+     */
+    aprresult = etch_apr_queue_push (thisx->aprq, wait_usec, item);
+
+    switch(aprresult)
+    {   case APR_SUCCESS: break;
+
+        case APR_EAGAIN: /* timed out and queue still full */
+        case APR_TIMEUP:
+             result = ETCH_QUEUE_OPERATION_TIMEOUT;
+             break;
+
+        case APR_EINTR:  /* wait interrupted and queue still full */
+             result = ETCH_QUEUE_OPERATION_CANCELED;
+             break;
+
+        case APR_EOF:    /* queue closed */
+             default:    /* some error */
+             result = -1;
+    }
+
+    return result;
+}
+
+
+/**
+ * etchqueue_get()
+ * pop specified item off the queue and return it. if the queue is empty, 
+ * wait indefinitely for an item to arrive. popped item is returned in
+ * out parameter.
+ * @return 0 success, -1 error.
+ */
+int etchqueue_get(etch_queue* thisx, void** itemout)
+{
+    const int result = etchqueue_get_withwait(thisx, ETCH_INFWAIT, itemout);
+    return result;
+}
+
+
+/**
+ * etchqueue_get_withwait()
+ * pop specified item off the queue and return it. if the queue is empty, 
+ * wait specified time interval for an item to arrive. popped item is
+ * returned in out parameter.
+ * @param waitms wait interval in milliseconds. specify ETCH_INFWAIT to wait
+ * forever, ETCH_NOWAIT to not wait, ETCHQUEUE_CLEARING_CLOSED_QUEUE to do a
+ * get with no wait regardless of whether queue has been closed.
+ * @return 0 success, -1 unsuccessful.
+ * 
+ */
+int etchqueue_get_withwait(etch_queue* thisx, const int waitms, void** itemout)
+{
+    int result = 0, aprresult = 0;
+    const int64 wait_usec = waitms < 0? waitms: waitms * 1000;
+
+    if (etchqueue_is_closed(thisx))
+        if (waitms != ETCHQUEUE_CLEARING_CLOSED_QUEUE)
+            return -1;
+
+    /*
+     * etch_apr_queue_pop() takes care of notifying waiters if necessary
+     */
+    aprresult = etch_apr_queue_pop (thisx->aprq, wait_usec, itemout);
+
+    switch(aprresult)
+    {   case APR_SUCCESS: break;
+
+        case APR_EAGAIN: /* timed out and queue still full */
+        case APR_TIMEUP:
+             result = ETCH_QUEUE_OPERATION_TIMEOUT; break;
+
+        case APR_EINTR:  /* wait interrupted and queue still empty */
+             result = ETCH_QUEUE_OPERATION_CANCELED; break;
+
+        case APR_EOF:    /* queue empty */
+             result = ETCH_QUEUE_EOF; break;
+
+        default:         /* some error */
+             result = -1;
+    }
+
+    return result;
+}
+
+
+/**
+ * etchqueue_try_put()
+ * @return 0 success, -1 unsuccessful.
+ * 
+ */
+int etchqueue_try_put(etch_queue* thisx, void* item)
+{
+    const int result = etch_apr_queue_trypush(thisx->aprq, item);
+    return result == 0? 0: -1;
+}
+
+
+/**
+ * etchqueue_try_get()
+ * @return 0 success, -1 unsuccessful.
+ */
+int etchqueue_try_get(etch_queue* thisx, void** itemout)
+{
+    const int result = etch_apr_queue_trypop(thisx->aprq, itemout);
+    return result == 0? 0: -1;
+}
+
+
+ /**
+ * etchqueue_notify_all()
+ * wake up all waiters, 
+ * @return 0 success, -1 unsuccessful.
+ */
+int etchqueue_notify_all(etch_queue* thisx)
+{
+    const int aprresult = etch_apr_queue_interrupt_all(thisx->aprq);
+    return aprresult == 0? 0: -1;
+}
+
+ 
+/**
+ * acquire the lock guarding the queue
+ */
+int etchqueue_lock(etch_queue* thisx) 
+{
+    return 0 == etch_apr_queue_lock(thisx->aprq)? 0: -1;
+}
+
+
+/**
+ * release the lock guarding the queue
+ */
+int etchqueue_unlock(etch_queue* thisx)
+{
+    return 0 == etch_apr_queue_unlock(thisx->aprq)? 0: -1;
+} 
+
+
+/**
+ * acquire the lock guarding the queue if currently availbale
+ */
+int etchqueue_trylock(etch_queue* thisx)
+{
+    return 0 == etch_apr_queue_trylock(thisx->aprq)? 0: -1;
+}
+
+
+/* - - - - - - - - - - 
+ * i_iterable
+ * - - - - - - - - - - 
+ */
+
+/*
+ * etchqueue_iterable_first() 
+ * i_iterable first() implementation
+ */
+int etchqueue_iterable_first(etch_iterator* iter)
+{
+    etch_queue* etchq = NULL;
+    if (!iter || !iter->collection)  return -1;
+    etchq = iter->collection;
+    if (!etchqueue_size(etchq)) return -1;
+
+    iter->current_value = etchq->aprq->data[0];   
+    iter->ordinal = iter->current_value? 1: 0;
+    return iter->ordinal? 0: -1;
+}
+
+
+/*
+ * etchqueue_iterable_next() 
+ * i_iterable next() implementation
+ * functions as first() if there is no current position.
+ */
+int etchqueue_iterable_next(etch_iterator* iter)
+{
+    etch_queue* etchq = iter? iter->collection: NULL;
+    const int count = etchqueue_size(etchq);
+    if (!count || !iter->ordinal) return -1;
+    
+    iter->current_value = etchq->aprq->data[iter->ordinal]; 
+    iter->ordinal = iter->current_value? ++iter->ordinal: 0;
+    return iter->ordinal? 0: -1;
+}
+
+
+/*
+ * etchqueue_iterable_has_next() 
+ * i_iterable has_next() implementation.
+ */
+int etchqueue_iterable_has_next(etch_iterator* iter)
+{
+    etch_queue* etchq = iter? iter->collection: NULL;
+    const int count = etchqueue_size(etchq);
+    return count && iter->ordinal && (iter->ordinal <= count);
+}
diff --git a/binding-c/runtime/c/src/main/transport/etch_session_data.c b/binding-c/runtime/c/src/main/transport/etch_session_data.c
new file mode 100644
index 0000000..71d30d0
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_session_data.c
@@ -0,0 +1,87 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sessiondata.c
+ * i_sessiondata interface
+ */
+
+#include "etch_session_data.h"
+#include "etch_flexbuffer.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+/*
+static const char* LOG_CATEGORY = "etch_session_data";
+*/
+
+/*
+ * destroy_sessiondata()
+ * i_sessiondata destructor
+ */
+int destroy_sessiondata(void* data)
+{
+    i_sessiondata* sm = (i_sessiondata*)data;
+    if (NULL == sm) return -1;
+
+    if (!is_etchobj_static_content(sm))
+    {   etch_free(sm->isession);
+    }
+            
+    return destroy_objectex((etch_object*)sm);
+}
+
+
+/*
+ * etch_msghandler_defmessage()
+ * default virtual implementation   
+ * @param sender caller retains
+ * @param buf caller retains
+ */
+int etchsessiondata_def_sessiondata (void* data, void* whoData, void* bufferData)
+{
+      return -1;
+}
+
+
+/**
+ * new_sessiondata_interface()
+ * i_sessiondata constructor
+ * @param sm i_sessiondata::session_data() virtual function override. 
+ * caller relinquishes ownership of this memory
+ * @param isession session interface virtual function overrides. 
+ * caller relinquishes ownership of this memory
+ */
+i_sessiondata* new_sessiondata_interface(void* thisx, etch_session_data sm, i_session* isession)  
+{
+    i_sessiondata* newi = (i_sessiondata*) new_object(sizeof(i_sessiondata), ETCHTYPEB_SESSIONDATA, CLASSID_SESSIONDATA);
+
+    newi->thisx   = thisx;
+    ((etch_object*)newi)->clone   = clone_null;
+    ((etch_object*)newi)->destroy = destroy_sessiondata;  
+
+    newi->session_data = sm ? sm : etchsessiondata_def_sessiondata;
+
+    newi->isession = isession? isession: new_default_session_interface(thisx);
+    newi->session_control = newi->isession->session_control;
+    newi->session_notify  = newi->isession->session_notify;
+    newi->session_query   = newi->isession->session_query;
+
+    return newi;
+}
diff --git a/binding-c/runtime/c/src/main/transport/etch_session_listener.c b/binding-c/runtime/c/src/main/transport/etch_session_listener.c
new file mode 100644
index 0000000..398009e
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_session_listener.c
@@ -0,0 +1,102 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sessionlisten.c
+ * i_sessionlistener interface
+ */
+
+#include "etch_session_listener.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+/*
+static const char* LOG_CATEGORY = "etch_session_listener";
+*/
+int etchseslxr_def_session_accepted (void* thisx, void*);
+
+
+/*
+ * destroy_sessionlistener()
+ * i_sessionlistener destructor
+ */
+int destroy_sessionlistener(void* data)
+{
+    i_sessionlistener* sa = (i_sessionlistener*)data;
+    if (NULL == sa) return -1;
+
+    if (!is_etchobj_static_content(sa))
+    {   
+        if (sa->is_session_owned)
+            etch_free(sa->isession);
+
+        if (sa->is_transport_owned)
+            etch_free(sa->itransport);
+
+	//        ETCHOBJ_DESTROY();
+	if(((etch_object*)sa->url))
+	  ((etch_object*)sa->url)->destroy(((etch_object*)sa->url));
+	sa->url = NULL;
+
+    }
+            
+    return destroy_objectex((etch_object*)sa);
+}
+
+
+/**
+ * new_sessionlistener_interface()
+ * i_sessionlistener constructor
+ * @params sa server on accept callback confirming to typedef etch_session_accepted.
+ * @param isession session interface virtual function overrides, 
+ * caller relinquishes ownership of this memory.
+ */
+i_sessionlistener* new_sessionlistener_interface (void* thisx, etch_session_accepted sa, i_session* isession)  
+{
+    i_sessionlistener* newi = (i_sessionlistener*) new_object
+        (sizeof(i_sessionlistener), ETCHTYPEB_SESSIONLXR, CLASSID_SESSIONLXR);
+
+    newi->thisx   = thisx;
+    ((etch_object*)newi)->clone   = clone_null;
+    ((etch_object*)newi)->destroy = destroy_sessionlistener;  
+
+    newi->session_accepted = sa? sa: etchseslxr_def_session_accepted;
+
+    newi->isession = isession? isession: new_default_session_interface(thisx);
+    newi->isession->thisx  = newi;
+    newi->session_control  = newi->isession->session_control;
+    newi->session_notify   = newi->isession->session_notify;
+    newi->session_query    = newi->isession->session_query;
+    newi->is_session_owned = TRUE;
+
+    newi->itransport = new_default_transport_interface(thisx);
+    newi->is_transport_owned = TRUE;
+
+    return newi;
+}
+
+
+
+/*
+ * etchseslxr_def_session_accepted()
+ * @param socket caller retains
+ */
+int etchseslxr_def_session_accepted (void* thisx, void* socket)
+{
+    return -1;
+}
diff --git a/binding-c/runtime/c/src/main/transport/etch_session_message.c b/binding-c/runtime/c/src/main/transport/etch_session_message.c
new file mode 100644
index 0000000..7b4a145
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_session_message.c
@@ -0,0 +1,94 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sessionmsg.c
+ * i_sessionmessage interface
+ */
+
+#include "etch_session_message.h"
+#include "etch_message.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+/*
+static const char* LOG_CATEGORY = "etch_session_message";
+*/
+/*
+ * destroy_sessionmessage()
+ * i_sessionmessage destructor
+ */
+int destroy_sessionmessage(void* data)
+{
+    i_sessionmessage* sm = (i_sessionmessage*)data;
+    if (NULL == sm) return -1;
+
+    if (!is_etchobj_static_content(sm))
+    {   etch_free(sm->isession);
+    }
+
+    return destroy_objectex((etch_object*)sm);
+}
+
+
+/*
+ * etch_msghandler_defmessage()
+ * default virtual implementation  
+ * @param sender caller retains
+ * @param msg caller retains 
+ * memory management rules are: if session_message handles the message, it owns
+ * msg memory. otherwise, if not handled, msg is retained by the caller for 
+ * redirection via session_notify destination.
+ */
+int etchsessionmsg_def_sessionmessage (void* sm, etch_who* sender, etch_message* msg)
+{
+      return -1;
+}
+
+
+/**
+ * new_sessionmsg_interface()
+ * i_sessionmessage constructor
+ * @param isession session interface virtual function overrides, 
+ * caller relinquishes ownership of this memory
+ * @param itransport transport interface virtual function overrides, 
+ * caller relinquishes ownership of this memory
+ */
+i_sessionmessage* new_sessionmsg_interface(void* thisx, etch_session_message sm, i_session* isession)  
+{
+    i_sessionmessage* newi = (i_sessionmessage*) new_object
+        (sizeof(i_sessionmessage), ETCHTYPEB_SESSIONMSG, CLASSID_SESSIONMSG);
+
+    newi->thisx   = thisx;
+    ((etch_object*)newi)->clone   = clone_null;
+    ((etch_object*)newi)->destroy = destroy_sessionmessage;  
+
+    if (sm) {
+      newi->session_message = sm;
+    } else {
+      newi->session_message = etchsessionmsg_def_sessionmessage;
+    }
+
+    newi->isession = isession? isession: new_default_session_interface(thisx);
+    newi->session_control = newi->isession->session_control;
+    newi->session_notify  = newi->isession->session_notify;
+    newi->session_query   = newi->isession->session_query;
+
+    return newi;
+}
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_session_packet.c b/binding-c/runtime/c/src/main/transport/etch_session_packet.c
new file mode 100644
index 0000000..8c76a96
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_session_packet.c
@@ -0,0 +1,90 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_sessionpkt.c
+ * i_sessionpacket interface
+ */
+
+#include "etch_session_packet.h"
+#include "etch_message.h"
+#include "etch_flexbuffer.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+/*
+static const char* LOG_CATEGORY = "etch_session_package";
+*/
+
+/*
+ * destroy_sessionpacket()
+ * i_sessionpacket destructor
+ */
+int destroy_sessionpacket(void* data)
+{
+  i_sessionpacket* sm = (i_sessionpacket*)data;
+    if (NULL == sm) return -1;
+
+    if (!is_etchobj_static_content(sm))
+    {   etch_free(sm->isession);
+    }
+            
+    return destroy_objectex((etch_object*)sm);
+}
+
+
+/*
+ * etchsessionpkt_def_sessionpacket()
+ * default virtual implementation   
+ * @param sender caller retains
+ * @param buf caller retains
+ */
+int etchsessionpkt_def_sessionpacket (void* data, void* whoData, void* bufferData)
+{
+      return -1;
+}
+
+
+/**
+ * new_sessionpkt_interface()
+ * i_sessionpacket constructor
+ * @param sp session_packetvirtual function overrides, 
+ * @param itransport transport interface virtual function overrides, 
+ * caller relinquishes ownership of this memory
+ */
+i_sessionpacket* new_sessionpkt_interface(void* thisx, etch_session_packet sp, i_session* isession)  
+{
+    i_sessionpacket* newi = (i_sessionpacket*) new_object (sizeof(i_sessionpacket), ETCHTYPEB_SESSIONPKT, CLASSID_SESSIONPKT);
+
+    newi->thisx   = thisx;
+    ((etch_object*)newi)->clone   = clone_null;
+    ((etch_object*)newi)->destroy = destroy_sessionpacket;  
+
+    newi->session_packet = sp ? sp: etchsessionpkt_def_sessionpacket;
+
+    newi->isession = isession? isession: new_default_session_interface(thisx);
+    newi->session_control = newi->isession->session_control;
+    newi->session_notify  = newi->isession->session_notify;
+    newi->session_query   = newi->isession->session_query;
+
+    return newi;
+}
+
+
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_tcp_connection.c b/binding-c/runtime/c/src/main/transport/etch_tcp_connection.c
new file mode 100644
index 0000000..8d0b8f4
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_tcp_connection.c
@@ -0,0 +1,1062 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_tcpconxn.c
+ * tcp connection class
+ */
+
+#include "etch_thread.h"
+#include "etch_tcp_connection.h"
+#include "etch_encoding.h"
+#include "etch_flexbuffer.h"
+#include "etch_log.h"
+#include "etch_objecttypes.h"
+
+static const char* LOG_CATEGORY = "etch_tcp_connection";
+
+// extern types
+extern apr_pool_t*         g_etch_main_pool;
+extern apr_thread_mutex_t* g_etch_main_pool_mutex;
+
+int   etch_tcpconx_closex(etch_tcp_connection*, const int, const int);
+i_session* etch_tcpclient_get_session      (void*); 
+
+
+//extern char* ETCH_CONNECTION_LOGID;
+#define ETCH_SHUTDOWNSIGNALSIZE (sizeof(ETCH_SHUTDOWNSIGNAL)-1)
+
+unsigned connection_id_farm;
+
+#if(0)
+
+ TCPCONNECTION
+ |  Socket, hostIP, port, delay, isKeepalive, isNoDelay
+ |  buffersize, isAutoflush, trafficclass
+ |  InputStream, OutputStream
+ |  stop0(); openSocket(); setupSocket(); readSocket();
+ |  close(); send(); flush(); shutdownInput(); shutdownOutput();
+ |  remoteAddress(); fireData(); transportData();
+ |
+  - CONNECTION<SESSIONDATA>
+ |  |  Monitor status;
+ |  |  Connection(); started(); stopped(); exception();
+ |  |  run0(); localAddress(); translateHost();
+ |  |  openSocket(); setupSocket(); readSocket(); close();
+ |  |  transportQuery(); transportControl(); transportNotify();
+ |  |  fireUp(); fireDown(); 
+ |  |  void* getSession(); setSession(void*); waitUp(); waitDown();
+ |  |  
+ |   - SESSION
+ |  |     sessionQuery(); sessionControl(); sessionNotify();
+ |  |
+ |   - RUNNER
+ |  |  |  Thread thread;
+ |  |  |  RunnerHandler handler;
+ |  |  |  start0()
+ |  |  |  stop0()
+ |  |  |  run()
+ |  |  |  run0()
+ |  |  |  fireStarted()
+ |  |  |  fireStopped()
+ |  |  |  fireException()
+ |  |   - ABSTRACTSTARTABLE
+ |  |
+ |   - TRANSPORT<SESSIONDATA>
+ |  |     transportQuery(); transportControl(); transportNotify();
+ |  |
+ |   - RUNNERHANDLER interface
+ |        started(); stopped(); exception();
+ | 
+  - TRANSPORTDATA 
+    |  int transportData(to, buffer);
+    |  int headerSize;
+     - TRANSPORT
+          transportQuery(); transportControl(); transportNotify();
+#endif
+
+
+
+
+/**
+ * etch_tcpconx_set_socket_options()
+ */
+int etch_tcpconx_set_socket_options(void* data)
+{
+    etch_tcp_connection *c = (etch_tcp_connection*)data;
+    int arc = 0, ecount = 0;
+    etch_connection_event_handler eventx;
+    etch_rawsocket* socket = c? c->cx.socket: NULL;
+	if (!socket) return -1;
+    eventx = c->cx.on_event;
+      
+    /*
+     * APR_SO_DEBUG      -  turn on debugging information 
+     * APR_SO_KEEPALIVE  -  keep connections active
+     * APR_SO_LINGER     -  lingers on close if data is present
+     * APR_SO_NONBLOCK   -  turns blocking on/off for socket
+     *   when this option is enabled, use the APR_STATUS_IS_EAGAIN() macro  
+     *   to determine if a send or receive function could not transfer data 
+     *   without blocking.                                  
+     * APR_SO_REUSEADDR  -  the rules used in validating addresses
+     *   supplied to bind should allow reuse of local addresses.
+     * APR_SO_SNDBUF     -  set the send buffer size
+     * APR_SO_RCVBUF     -  set the receive buffer size
+     */
+
+    if (0 != (arc = apr_socket_opt_set(socket, APR_SO_KEEPALIVE, c->is_keepalive)))
+        ecount += eventx(c, ETCH_CONXEVT_SOCKOPTERR, arc, "keepalive");   
+ 
+    if (0 != (arc = apr_socket_opt_set(socket, APR_SO_LINGER, c->linger)))
+        ecount += eventx(c, ETCH_CONXEVT_SOCKOPTERR, arc, "linger");   
+
+    if (0 != (arc = apr_socket_opt_set(socket, APR_TCP_NODELAY, c->is_nodelay)))
+        ecount += eventx(c, ETCH_CONXEVT_SOCKOPTERR, arc, "nodelay");   
+
+    /* 
+    if (0 != (arc = apr_socket_opt_set(socket, APR_SO_NONBLOCK, FALSE)))
+        ecount += eventx(c, ETCH_CONXEVT_SOCKOPTERR, arc, "do not block");
+     */
+
+    /* timeout < 0 = block, 0 = never block, > 0 = block until timeout
+    if (0 != (arc = apr_socket_timeout_set(socket, -1)))
+        ecount +=  eventx(c, ETCH_CONXEVT_SOCKOPTERR, arc, "socket timeout");   
+    */
+
+    return ecount == 0? 0: -1;
+}
+
+
+/**
+ * etch_tcpclient_on_data()
+ * tcp socket received data handler.  
+ * @param cx the connection object.
+ * @param unused parameter not currently used.
+ * @param length number of bytes in the supplied data buffer.
+ * @param data the data as received via the socket wrapped in a flexbuffer.
+ * caller retains this memory.
+ * @remarks todo: if this remains the same as etch_tcpsvr_on_data, replace both 
+ * methods with a etch_tcpconx_on_data() containing the same code.
+ */
+int etch_tcpclient_on_data (void* thisData, const int unused, int length, void* bufferData)
+{
+    etch_connection* cx = (etch_connection*)thisData;
+    etch_flexbuffer* data = (etch_flexbuffer*)bufferData;
+    int result = 0;
+    i_sessiondata* session = NULL;
+    etch_tcp_connection* tcpx = cx? (etch_tcp_connection*) cx->owner: NULL;
+    ETCH_ASSERT(is_etch_tcpconnection(tcpx));
+    ETCH_ASSERT(is_etch_flexbuffer(data));
+    session = tcpx->session;
+                                           
+    /* send the data up the chain to be packetized. note that tcpx->session->thisx
+     * is the owner of the i_sessiondata* session, which is the next higher layer 
+     * of the transport stack, which is ordinarily the packetizer.  
+     */
+    if (-1 == (result = session->session_data (session->thisx, NULL, data)))
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "current %d bytes on connxn %d rejected\n", length, cx->conxid);
+    return result;
+}
+
+/*
+ * new_tcp_connection()
+ * etch_tcp_connection tcp client constructor
+ */
+etch_tcp_connection* new_tcp_connection(etch_url* url, void* resources, etch_rawsocket* socket)
+{
+    int result = -1, item = 0;
+    etch_tcp_connection* newcon = NULL;    
+    if (!is_good_tcp_params (url, resources, socket)) return NULL;
+
+    newcon = (etch_tcp_connection*)new_object (sizeof(etch_tcp_connection), ETCHTYPEB_CONNECTION, CLASSID_TCP_CONNECTION);
+    ((etch_object*)newcon)->destroy = destroy_etch_tcp_connection;
+
+    do  /* populate connection's transport and session interfaces */
+    {   if (-1 == (result = init_etch_tcpconx_interfaces(newcon))) break;
+
+        if (-1 == (result = etch_init_connection (&newcon->cx, socket, newcon))) break;
+
+        newcon->cx.set_socket_options = etch_tcpconx_set_socket_options;
+        newcon->cx.on_event = etch_tcpconx_on_event;  /* connection state handler */
+
+        if (socket)
+            newcon->cx.socket = socket;
+        else
+        {   
+            // TODO: pool
+            etch_encoding_transcode_wchar(&newcon->cx.hostname, ETCH_ENCODING_UTF8, url->host, NULL);
+            newcon->cx.port = url->port;
+            etchurl_get_integer_term (url, ETCH_CONNECTION_RECONDELAY, &newcon->cx.delay);
+        }
+        
+        /* set term default values - values for any terms not set here are zero */
+        newcon->is_nodelay = ETCH_CONNECTION_DEFNODELAY;
+        newcon->linger     = ETCH_CONNECTION_DEFLINGERTIME;
+
+        /* set any terms which may have been supplied with URL */
+        etchurl_get_boolean_term(url, ETCH_CONNECTION_AUTOFLUSH,  &newcon->is_autoflush);
+        etchurl_get_boolean_term(url, ETCH_CONNECTION_KEEPALIVE,  &newcon->is_keepalive);
+        etchurl_get_boolean_term(url, ETCH_CONNECTION_NODELAY,    &newcon->is_nodelay);
+        etchurl_get_integer_term(url, ETCH_CONNECTION_LINGERTIME, &newcon->linger);
+        etchurl_get_integer_term(url, ETCH_CONNECTION_TRAFCLASS,  &newcon->traffic_class);
+        etchurl_get_integer_term(url, ETCH_CONNECTION_BUFSIZE,    &item);
+        if (item > 0) newcon->cx.bufsize = item;
+        result = 0;
+
+    } while(0);
+
+    newcon->cx.on_data = etch_tcpclient_on_data;
+    newcon->cx.on_event(newcon, result? ETCH_CONXEVT_CREATERR: ETCH_CONXEVT_CREATED, 0, 0);
+
+    if (-1 == result)
+    {   destroy_etch_tcp_connection(newcon);
+        return NULL;
+    }       
+    else return newcon;
+}
+
+/**
+ * etch_tcpclient_set_session()
+ * i_transport::set_session() override
+ * @param session an i_sessiondata*. caller retains this object.
+ */
+void etch_tcpclient_set_session (void* data, void* newsession)
+{
+    etch_tcp_connection* thisx = (etch_tcp_connection*)data;
+    ETCH_ASSERT(is_etch_tcpconnection(thisx));
+    ETCH_ASSERT(is_etch_sessiondata(newsession));
+    if (thisx->is_session_owned){
+        etch_object_destroy(thisx->session);
+        thisx->session = NULL;
+    }
+    thisx->is_session_owned = FALSE;
+    thisx->session = newsession;
+}
+
+/**
+ * etch_tcpconx_transport_control()
+ * connection::i_transport::transport_control override.
+ * this is the base connection class' implementation of i_transport.
+ * this is java binding's Connection.transportControl(), and serves as the
+ * Transport part of the java TcpConnection TransportData. 
+ * while tcp connection does implement i_transportdata, tcp connection's
+ * implementation of i_transport comes from its inheritance of connection,
+ * and its implementation of TransportData. since we do not separately implement
+ * the connection class, the i_transport methods are implemented here.
+ * @param control the event, sender relinquishes.
+ * @param value control value, sender relinquishes.
+ */
+int etch_tcpconx_transport_control (void* data, etch_event* control, etch_object* value)
+{
+    etch_tcp_connection* thisx = (etch_tcp_connection*)data;
+    etch_connection* cx = NULL;
+    int result = 0, timeoutms = 0;
+    const int objclass  = control? ((etch_object*)control)->class_id: 0;
+    const int is_client = is_etch_int32(value)? ((etch_int32*)value)->value: NULL;
+    ETCH_ASSERT(is_etch_tcpconnection(thisx));
+    cx = &thisx->cx;
+    
+
+    switch(objclass)
+    {  
+       case CLASSID_CONTROL_START:
+
+            result = etch_tcpconx_start (thisx);  
+
+            if (is_client && 0 == result)
+                result = etch_tcpclient_start_listener (thisx);  
+            break; 
+           
+       case CLASSID_CONTROL_START_WAITUP: 
+ 
+            /* open the connection, and wait for completion. caller blocks by virtue
+             * of the fact that this is of course a function call, not a message handler.
+             * timeout is communicated to caller via result code 1 = ETCH_TIMEOUT. 
+             * it is not clear why wait up is implemented here. since a tcp server
+             * implements transport interface itself, a server will never invoke this
+             * implementation. on the other hand, the requester of a client connection  
+             * and the socket itself are the same thread, wait up therefore being
+             * meaningless since the socket open is known to be complete prior to
+             * invoking wait up.
+             */
+            if (0 == (result = etch_tcpconx_open (thisx, ETCH_CONX_NOT_RECONNECTING)))
+            {   timeoutms = value? ((etch_int32*) value)->value: 0;         
+                result = etchconx_wait_up (cx, timeoutms);
+            }
+            break;  
+
+       case CLASSID_CONTROL_STOP:  
+
+            if (is_client)
+                result = etch_tcpclient_stop_listener (thisx);  
+            else
+                result = etch_tcpconx_close (thisx, ETCH_CONX_NO_LINGER);
+            break;
+
+       case CLASSID_CONTROL_STOP_WAITDOWN: 
+ 
+            /* see comments above at CLASSID_CONTROL_START_WAITUP */
+            if (0 == (result = etch_tcpconx_close (thisx, ETCH_CONX_NO_LINGER)))
+            {   timeoutms = value? ((etch_int32*) value)->value: 0;
+                result = etchconx_wait_down (cx, timeoutms);
+            }
+            break;
+    }
+
+    etch_object_destroy(control);
+    etch_object_destroy(value);
+    return result;
+}
+
+/**
+ * etch_tcpconx_transport_notify()
+ * i_transport::transport_notify override.
+ * @param evt, caller relinquishes.
+ */
+int etch_tcpconx_transport_notify (void* data, etch_event* evt)
+{
+    etch_tcp_connection* thisx = (etch_tcp_connection*)data;
+    ETCH_ASSERT(is_etch_tcpconnection(thisx));
+    etch_object_destroy(evt);
+    return 0;  /* nothing to do */
+}
+
+
+
+/**
+ * etch_tcpconx_transport_query()
+ * i_transport::transport_query override.
+ * @param query, caller relinquishes.
+ */
+etch_object* etch_tcpconx_transport_query (void* data, etch_query* query) 
+{
+    etch_tcp_connection* thisx = (etch_tcp_connection*)data;
+    int result = 0;
+    etch_object*  resultobj = NULL;
+    etch_connection* cx = NULL;
+    const int timeoutms = query? query->value: 0;
+    const int objclass  = query? ((etch_object*)query)->class_id: 0;
+    ETCH_ASSERT(is_etch_tcpconnection(thisx));
+    cx = &thisx->cx;
+
+    switch(objclass)
+    {  
+       case CLASSID_QUERY_LOCALADDR:
+            /* TODO return wrapped local address */
+            break; 
+           
+       case CLASSID_QUERY_REMOTEADDR:  
+            /* TODO return wrapped remote address */
+            break;  
+
+       case CLASSID_QUERY_WAITUP:   
+            result = etchconx_wait_up(cx, timeoutms);
+            break;
+
+       case CLASSID_QUERY_WAITDOWN:  
+            result = etchconx_wait_down(cx, timeoutms);
+            break;
+    }
+
+    etch_object_destroy(query);
+    return resultobj;
+}
+
+
+/*
+ * etch_tcpclient_sendex()
+ * send data with specified timeout
+ */
+int etch_tcpclient_sendex (etch_tcp_connection *conx, unsigned char* buf, 
+    const size_t totallen, const int timeout_ms, int* rc)
+{
+    int arc = 0, is_eod = 0;
+    int64 existing_timeout_us = 0;
+    apr_size_t datalen = 0, totalsent = 0, remaining = totallen;
+    etch_connection *cx  = conx? &conx->cx:  NULL;
+    etch_rawsocket* socket = cx? cx->socket: NULL;
+	if (!socket) return -1;
+    cx->on_event(conx, ETCH_CONXEVT_SENDING, 0, 0);
+
+    if (timeout_ms) 
+    {   apr_socket_timeout_get(cx->socket, &existing_timeout_us);
+        apr_socket_timeout_set(cx->socket, timeout_ms * 1000);
+    }
+
+    /* note socket currently blocking write with no timeout */
+
+    while(cx->is_started && !is_eod && remaining > 0)
+    {
+        datalen = totallen;
+       
+        is_eod = (APR_EOF == (arc = apr_socket_send(socket, (char*)(buf + totalsent), &datalen)));
+
+        totalsent += datalen; remaining -= datalen;
+
+        if (arc != 0 && !is_eod)
+        {   cx->on_event(conx, ETCH_CONXEVT_SENDERR, arc, 0);  
+            break;
+        }
+
+        cx->on_event(conx, ETCH_CONXEVT_SENT, is_eod, (char*)datalen);
+    }
+
+    if (timeout_ms) /* restore socket timeout property */
+        apr_socket_timeout_set(cx->socket, existing_timeout_us);
+
+    cx->on_event(conx, ETCH_CONXEVT_SENDEND, (int)totalsent, 0); 
+    if (rc) *rc = arc;
+    return remaining > 0? -1: 0;
+}
+
+/*
+ * etch_tcpclient_send()
+ */
+int etch_tcpclient_send (etch_tcp_connection *conx, unsigned char* buf, const size_t totallen, int* rc)
+{
+    return etch_tcpclient_sendex(conx, buf, totallen, 0, rc);
+}
+
+
+/*
+ * etch_tcpconx_transport_data()
+ * etch_tcp_connection::i_transportdata::transport_data
+ * @param whoto caller retains
+ * @param fbuf caller retains 
+ */
+int etch_tcpconx_transport_data (void* data, etch_who* whoto, etch_flexbuffer* fbuf)
+{
+    etch_tcp_connection* thisx = (etch_tcp_connection*)data;
+    int result = 0, apr_rc = 0;
+    ETCH_ASSERT(is_etch_tcpconnection(thisx));
+
+    result = etch_tcpclient_send (thisx, fbuf->buf, fbuf->datalen, &apr_rc);
+    
+    etch_flexbuf_reset(fbuf);
+    return result;
+} 
+
+/*
+ * init_etch_tcpcon_interfaces()
+ * populate transport and placeholder session interfaces to tcp connection.
+ */
+int init_etch_tcpconx_interfaces (etch_tcp_connection* tcpx)
+{
+    i_transport* itransport = NULL;
+    ETCH_ASSERT(is_etch_tcpconnection(tcpx));
+    if (tcpx->itd) return 0;  /* already initialized */
+
+    itransport = new_transport_interface_ex (tcpx, 
+        etch_tcpconx_transport_control, 
+        etch_tcpconx_transport_notify, 
+        etch_tcpconx_transport_query,
+        etch_tcpclient_get_session,
+        etch_tcpclient_set_session);
+
+    tcpx->itd = new_transportdata_interface (tcpx, 
+					     (void*)etch_tcpconx_transport_data, itransport);  /* itd now owns itransport */
+
+    /* establish placeholder session interface which is expected   
+     * to be replaced by the connection host (e.g. packetizer) */
+    tcpx->session = new_sessiondata_interface (tcpx, NULL, NULL);
+    tcpx->is_session_owned = TRUE;
+
+    return 0;
+}
+
+
+/**
+ * etch_tcpconx_start()
+ * start means open. generally we would come through here with an accepted socket,
+ * in which case it is currently marked already open and we will return success. 
+ * @return 0 success, -1 failure.
+ */
+int etch_tcpconx_start (etch_tcp_connection *conx)
+{
+    etch_connection* cx = conx? &conx->cx: NULL;
+    ETCH_ASSERT(cx);
+    cx->on_event (conx, ETCH_CONXEVT_STARTING, 0, 0);  
+    if (cx->is_started) return 0;
+
+    return etch_tcpconx_open (conx, ETCH_CONX_NOT_RECONNECTING);
+}
+
+
+/**
+ * etch_tcpconx_open()
+ * open connection to server based on host name/port set at construction.
+ * @note we have omitted reconnect logic for now, pending logic to detect 
+ * listen socket down and initiate reconnect.
+ * @return 0 success, -1 failure (already open, hostname or socket error, etc)
+ */
+int etch_tcpconx_open(etch_tcp_connection *conx, const int is_reconnect)
+{
+	int result = -1, arc = 0, attempt = 0, is_already_open = TRUE;
+    apr_status_t        apr_status;
+	apr_interval_time_t apr_timeout;
+    etch_connection* cx = &conx->cx;
+    etch_connection_event_handler eventx = cx->on_event;
+    eventx(conx, ETCH_CONXEVT_OPENING, 0, 0);   
+
+    do 
+    {   if (cx->is_started) break;
+        is_already_open = FALSE;
+
+        apr_thread_mutex_lock(g_etch_main_pool_mutex);
+        arc = apr_sockaddr_info_get(&cx->sockdata, cx->hostname, ETCH_DEFAULT_SOCKET_FAMILY, cx->port, 0, g_etch_main_pool);
+        apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+        if (0 != arc) {
+            eventx(conx, ETCH_CONXEVT_OPENERR, 4, (void*)(size_t)arc);  
+            break;
+        }
+
+        if (!cx->socket)
+        {
+            if (0 != (arc = new_tcpsocket (&cx->socket, cx->aprpool)))
+            {   eventx(conx, ETCH_CONXEVT_OPENERR, 3, (void*)(size_t)arc);  
+                break;
+            }
+
+            /* set socket options here: NONBLOCK, TIMEOUT */ 
+        }
+        
+		apr_status = apr_socket_timeout_get(cx->socket, &apr_timeout);
+		if(apr_status != APR_SUCCESS){
+			char buffer[1024];
+			apr_strerror(apr_status, buffer, sizeof(buffer));
+			ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not get socket options: %s\n", buffer);
+		}
+		
+		apr_status = apr_socket_timeout_set(cx->socket, 5 * APR_USEC_PER_SEC);
+		if(apr_status != APR_SUCCESS){
+			char buffer[1024];
+			apr_strerror(apr_status, buffer, sizeof(buffer));
+			ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not set socket options: %s\n", buffer);
+		}
+				
+        while(attempt++ < ETCH_CONNECTION_DEFRETRYATTEMPTS+1)   
+        {   /* possibly todo: configure number of retry attempts */
+            /* open socket */
+			
+            apr_status = apr_socket_connect (cx->socket, cx->sockdata);
+            if(apr_status != APR_SUCCESS){
+                char buffer[1024];
+                apr_strerror(apr_status, buffer, sizeof(buffer));
+                ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not connect to server reson: %s\n", buffer);
+            } else {
+                cx->is_started = TRUE;
+                break;
+            }
+
+            cx->on_event(conx, ETCH_CONXEVT_OPENERR, 2, (void*)(size_t)arc); 
+            etch_sleep(ETCH_CONNECTION_DEFRETRYDELAYMS);
+	    }
+		
+		apr_status = apr_socket_timeout_set(cx->socket, apr_timeout);
+		if(apr_status != APR_SUCCESS){
+			char buffer[1024];
+			apr_strerror(apr_status, buffer, sizeof(buffer));
+			ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not set socket options: %s\n", buffer);
+		}
+
+    } while(0);
+    
+    if (cx->is_started && !is_already_open) result = 0;
+    eventx(conx, result? ETCH_CONXEVT_OPENERR: ETCH_CONXEVT_OPENED, 0, 0);
+
+    if (cx->wait_up) {
+
+        /* java binding inserts a flow of control discontinuity here by assigning
+         * the responsibility for notifying the session of the new connection state
+         * to the separate thread it calls the todo manager (see jave fireUp()), 
+         * the purpose being to avoid a race condition by delaying the state change 
+         * until after return from this method. we may eventually have to implement 
+         * something like this, but as of this writing we are not doing so. the fact
+         * that we change state and then unblock as two separate actions here may
+         * well preclude the need for such a discontinuity here.
+         */
+
+        /* notify session that connection is up (see comment above) */
+        /* fyi: conx->session->thisx is packetizer */
+        if (0 == result) {
+            conx->session->session_notify (conx->session->thisx, new_etch_event(0, ETCHEVT_SESSION_UP));
+        }
+
+        /* unblock the thread waiting for connection to come up */
+        /* todo permit unblock with something other than UP, when result != 0 */
+        etch_wait_set(cx->wait_up, ETCH_CONXEVT_UP);
+    }
+
+	return result;  
+}
+
+/*
+ * etch_tcpcconx_close()
+ * close tcp connection
+ */
+int etch_tcpconx_close(etch_tcp_connection* conx, const int is_linger)
+{
+    return etch_tcpconx_closex(conx, is_linger, FALSE);
+}
+
+
+/*
+ * etch_tcpcconx_closex()
+ * close tcp connection
+ * @param is_linger whether to set the socket to linger.
+ * @param is_dtor true only if this call is from the tcp connection destructor.
+ * @return 0 success, -1 failure.
+ */
+int etch_tcpconx_closex(etch_tcp_connection* conx, const int is_linger, const int is_dtor)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    int result = 0, arc = 0, is_locked = 0, is_teardown = 0, is_logged = 0;
+    etch_connection* cx = 0;
+    if (NULL == conx) return -1;
+    cx = &conx->cx;
+    is_teardown = is_dtor && !cx->is_started;
+
+    do {
+
+    if (is_teardown) break;
+    cx->on_event(conx, ETCH_CONXEVT_CLOSING, 0, 0); 
+     
+    if (cx->socket) 
+    {         
+        if (cx->is_closing || !cx->is_started) 
+        {   cx->on_event(conx, ETCH_CONXEVT_CLOSERR, 1, 0);
+            is_logged = TRUE;
+            break;
+        }
+    }
+
+    status = etch_mutex_trylock(cx->mutex);
+    if(status != ETCH_SUCCESS) {
+        cx->on_event(conx, ETCH_CONXEVT_CLOSERR, 2, 0);
+        is_logged = TRUE;
+        break;
+    }
+
+    is_locked = TRUE;
+    cx->is_closing = TRUE; 
+    cx->is_started = FALSE;
+    if (NULL == cx->socket) break; /* never opened */
+    
+    if (is_linger)
+        apr_socket_opt_set(cx->socket, APR_SO_LINGER, conx->linger);
+    /* else flush(); shutdown_output(); */
+
+    if (0 != (arc = apr_socket_close(cx->socket))) {
+        cx->on_event(conx, ETCH_CONXEVT_CLOSERR, 3, (void*)(size_t)arc);
+        result = -1;
+        break;
+    }
+
+    // join thread on client receiver thread
+    if(conx->rcvlxr != NULL) {
+        etch_join(conx->rcvlxr->thread);
+    }
+
+    cx->socket = NULL;
+    cx->is_closing = FALSE;
+
+    /* anything else we may need to do on close here */
+
+    } while(0);
+
+    if (is_locked) {
+        etch_mutex_unlock(cx->mutex);
+    }
+
+    if (!is_teardown && !is_logged)
+         cx->on_event(conx, result? ETCH_CONXEVT_CLOSERR: ETCH_CONXEVT_CLOSED, 0, 0);
+
+    if (cx->wait_down) {
+        /* if another thread is blocking on this condition variable,
+         * we set the condition to DOWN, and UNBLOCK all waiters. */
+        etch_wait_set(cx->wait_down, ETCH_CONXEVT_DOWN);
+    }
+
+    return result; 
+}
+
+
+/*
+ * destroy_etch_tcp_connection()
+ * etch_tcp_connection destructor
+ */
+int destroy_etch_tcp_connection(void* thisx)
+{
+    etch_tcp_connection* tcpx = (etch_tcp_connection*)thisx;
+    if (NULL == tcpx) return -1;
+    tcpx->cx.on_event(tcpx, ETCH_CONXEVT_DESTROYING, 0, 0);
+               
+    etch_tcpconx_closex (tcpx, FALSE, TRUE);  /* close if open */
+
+    if (!is_etchobj_static_content(tcpx)) {
+        
+        /* free listener if any */
+        etch_object_destroy(tcpx->rcvlxr);
+        tcpx->rcvlxr = NULL;
+
+        /* free mem owned by tcpx */
+        etch_destroy_connection (&tcpx->cx);
+
+        /* free session interface */
+        if (tcpx->is_session_owned) {
+            etch_object_destroy(tcpx->session);
+            tcpx->session = NULL;
+        }
+
+        /* free transport interface */
+        etch_object_destroy(tcpx->itd);
+        tcpx->itd = NULL;
+    }
+
+    tcpx->cx.on_event(tcpx, ETCH_CONXEVT_DESTROYED, 0, 0);
+    return destroy_objectex((etch_object*)tcpx);
+}
+
+
+/*
+ * new_tcpsocket()
+ */
+int new_tcpsocket (apr_socket_t** outsock, apr_pool_t* mempool)
+{
+    int rv = 0;
+    apr_thread_mutex_lock(g_etch_main_pool_mutex);
+    rv = apr_socket_create (outsock, APR_INET, SOCK_STREAM, APR_PROTO_TCP, g_etch_main_pool);
+    apr_thread_mutex_unlock(g_etch_main_pool_mutex);
+    
+    return rv;
+} 
+
+
+
+
+
+/*
+ * etch_tcpclient_receive()
+ * receive data on socket
+ * returns length received or -1
+ */
+int etch_tcpclient_receive (etch_tcp_connection *tcpx, unsigned char* buf, const size_t buflen, int* rc)
+{
+    return etch_tcpclient_receivex (tcpx, buf, buflen, 0, rc);
+}
+
+
+/*
+ * etch_tcpclient_receivex()
+ * receive data on socket with specified timeout, into specified character buffer.
+ * @return number of bytes received on success; otherwise -2 (ETCH_OTHER_END_CLOSED)
+ * if peer closed, or -1 if error. 
+ */
+int etch_tcpclient_receivex (etch_tcp_connection *tcpx, unsigned char* buf, const size_t buflen, const int timeout_ms, int* rc)
+{
+    int result = 0, arc = 0, is_eod = 0, eventid = 0;
+    int64 existing_timeout_us = 0;
+    apr_size_t datalen = 0; 
+    etch_connection *cx = tcpx? &tcpx->cx: NULL;
+    if (NULL == cx) return -1;
+    cx->on_event(tcpx, ETCH_CONXEVT_RECEIVING, 0, 0);
+
+    if (timeout_ms) {
+        apr_socket_timeout_get(cx->socket, &existing_timeout_us);
+        apr_socket_timeout_set(cx->socket, timeout_ms * 1000);
+    }
+
+    datalen = buflen; /* BLOCK on receive data here */
+    
+    arc = apr_socket_recv (cx->socket, (char*)buf, &datalen);
+    is_eod = arc == APR_EOF;
+
+    if (arc && !is_eod) {
+        switch(arc) {
+            case APR_OTHER_END_CLOSED:
+                eventid = ETCH_CONXEVT_PEERCLOSED; 
+                result  = ETCH_OTHER_END_CLOSED; 
+                break;
+            case APR_THIS_END_CLOSED:
+                eventid = ETCH_CONXEVT_CONXCLOSED; 
+                result  = ETCH_THIS_END_CLOSED;
+                break;
+            default: 
+                eventid = ETCH_CONXEVT_RECEIVERR;
+                result = -1;
+        }
+        cx->on_event (tcpx, eventid, arc, 0); 
+        
+    }
+    else
+    if (0 == datalen)
+    {   cx->on_event(tcpx, ETCH_CONXEVT_PEERCLOSED, 0, 0);
+        result = ETCH_OTHER_END_CLOSED;
+    }
+    else /* check for signal to shut down server */
+    if (datalen == ETCH_SHUTDOWNSIGNALSIZE 
+     && 0 == memcmp(buf, ETCH_SHUTDOWNSIGNAL, ETCH_SHUTDOWNSIGNALSIZE))
+    {   cx->on_event(tcpx, ETCH_CONXEVT_SHUTDOWN, 0, 0);
+        result = ETCH_SHUTDOWN_NOTIFIED;
+    }
+    else
+    {   cx->on_event (tcpx, ETCH_CONXEVT_RECEIVED, is_eod, (char*)datalen);   
+        if (-1 != result) result = (int) datalen;  /* return bytecount */
+    }
+
+    if (timeout_ms) /* restore socket timeout property */
+        apr_socket_timeout_set(cx->socket, existing_timeout_us);
+     
+    if (rc) *rc = arc;
+    return result;
+}
+
+
+static etch_status_t etch_tcp_client_cleanup(void* p)
+{
+    etch_status_t    rv     = ETCH_SUCCESS;
+    etch_status_t    status = ETCH_SUCCESS;
+    etch_tcp_client* client = p;
+
+    status = etch_object_destroy(client->thread);
+    // TODO: check status
+    client->thread = NULL;
+
+    status = destroy_objectex((etch_object*)client);
+    // TODO: check status
+
+    rv = status;
+
+    return rv;
+}
+
+
+/**
+ * destroy_etch_tcp_client()
+ * tcp client (tcp connection read listener) destructor.
+ */
+int destroy_etch_tcp_client(void* data)
+{
+    etch_tcp_client* thisx = (etch_tcp_client*)data;
+    etch_status_t rv     = ETCH_SUCCESS;
+    rv = etch_tcp_client_cleanup(thisx);
+    return rv;
+}
+
+
+/**
+ * etch_tcpclient_listenerproc()
+ * tcp socket receive thread procedure. 
+ */
+static void etch_tcp_client_receiver_proc(void* data)
+{ 
+    etch_thread_params* params = (etch_thread_params*)data;
+    int result = 0, arc = 0;
+    etch_tcp_connection* tcpx = (etch_tcp_connection*) params->data;
+    etch_connection* cx = &tcpx->cx;
+    const int thread_id = params->etch_thread_id;
+    const int blen = cx->bufsize? cx->bufsize: ETCH_CONX_DEFAULT_BUFSIZE;
+    //params->data->threas = params->threadob
+    etch_flexbuffer* fbuf = new_flexbuffer(blen);  
+    cx->on_event(tcpx, ETCH_CONXEVT_RCVPUMP_START, 0, 0); 
+
+    while(cx->is_started)
+    {
+        etch_flexbuf_clear(fbuf);  /* for debugging otherwise unnecessary */
+        cx->on_event(tcpx, ETCH_CONXEVT_RCVPUMP_RECEIVING, thread_id, 0);
+
+        /* receive data from tcp socket into buffer owned by flexbuffer.
+         * note that if this receive were to stop blocking, for example 
+         * if the peer went down without it being detected here, we would
+         * see unfettered looping of this listener procedure. BLOCK.
+         */
+        result = etch_tcpclient_receive (tcpx, fbuf->buf, blen, &arc);   
+
+        switch(result)
+        {
+            case ETCH_THIS_END_CLOSED: case ETCH_OTHER_END_CLOSED:
+               /* a socket is down so close connection and exit thread */ 
+               cx->is_started = FALSE; /* this is new: exit thread now */
+               result = 0;   /* was break here but next line catches it*/
+        }
+
+        if (!cx->is_started) break;  /* client shutdown */
+        
+        if (result < 0)
+        {   cx->on_event(tcpx, ETCH_CONXEVT_RCVPUMP_ERR, arc, 0);
+            break;
+        }
+
+        etch_flexbuffer_reset_to (fbuf, result); /* received (result) bytes */
+
+        if (result > 0) /* forward (result) bytes to data handler for packetization */ 
+            cx->on_data (cx, 0, result, fbuf);     
+    }
+
+    tcpx->session->session_notify (tcpx->session->thisx, new_etch_event(0, ETCHEVT_SESSION_DOWN));
+    
+    cx->on_event(tcpx, ETCH_CONXEVT_RCVPUMP_STOP, result, (void*) (size_t) thread_id);
+    etch_object_destroy(fbuf);  
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "leaving listener thread ...\n");   
+}
+
+/**
+ * new_tcp_client()
+ * tcp client (tcp connection read listener) constructor.
+ * this class is an afterthought so it is backwards, the connection hosting
+ * the client class. maybe we'll change it later to move to client and server
+ * connection class symmetry. however this works. when a client connection
+ * needs a read listener it hosts and owns one of these.
+ * @param tcpx the tcp connection which is the client's receive listener.
+ */
+etch_tcp_client* new_tcp_client (etch_tcp_connection* tcpx)
+{
+    etch_tcp_client* newclient = NULL;
+
+    newclient = (etch_tcp_client*)new_object(sizeof(etch_tcp_client), ETCHTYPEB_TCPCLIENT, CLASSID_TCP_CLIENT);
+    
+    ((etch_object*)newclient)->destroy  = destroy_etch_tcp_client;
+    newclient->cxlisten = tcpx;  /* client's receive listener is tcpx */
+
+    newclient->thread = new_thread(etch_tcp_client_receiver_proc, tcpx);
+    if(newclient->thread == NULL) {
+        tcpx->cx.on_event (tcpx, ETCH_CONXEVT_STARTERR, 1, 0);
+        etch_object_destroy(newclient);
+        newclient = NULL;
+    }
+    newclient->thread->start(newclient->thread);
+
+
+    //status = etch_thread_start(newclient->thread);
+    // TODO: check error
+
+
+    /* the threadpool acts as the server's thread manager. it creates threads
+     * on request and destroys them at thread exit. */
+    //newclient->threadpool = new_threadpool (ETCH_THREADPOOLTYPE_FREE, 1);
+
+    /* data passed to threads will be either this object, or tcp connection
+     * objects. here we configure thread mgr to not free these at thread exit */
+    //newclient->threadpool->is_free_data = FALSE;
+    //newclient->threadpool->is_data_etchobject = TRUE;
+    //newclient->is_started = TRUE;
+
+    /* start the receive thread on the local thread manager */
+    //if (NULL == newclient->threadpool->run(newclient->threadpool, etch_tcp_client_receiver_proc, tcpx)) {
+    //    tcpx->cx.on_event (tcpx, ETCH_CONXEVT_STARTERR, 1, 0);
+    //    newclient->destroy(newclient);
+    //    newclient = NULL;
+    //}
+
+    return newclient;
+}
+
+
+/**
+ * etch_tcpclient_start_listener
+ * start a receive listener thread on the client connection
+ */
+int etch_tcpclient_start_listener (etch_tcp_connection *tcpx)
+{
+    etch_connection *cx = tcpx? &tcpx->cx:  NULL;
+	//if (NULL == cx || NULL != tcpx->rcvlxr) return -1;
+    if (NULL == cx)
+        return -1;
+    else if (NULL != tcpx->rcvlxr)
+    {
+        etch_object_destroy(tcpx->rcvlxr);
+        tcpx->rcvlxr = NULL;
+    }
+    
+    tcpx->rcvlxr = new_tcp_client (tcpx);
+
+    return NULL == tcpx->rcvlxr? -1: 0;
+}
+
+
+/**
+ * etch_tcpclient_stop_listener
+ * stop the receive listener thread on the client connection
+ */
+int etch_tcpclient_stop_listener (etch_tcp_connection *tcpx)
+{
+    int result = 0;
+    etch_tcp_client* tcpclient = NULL;
+    etch_tcp_connection* clientconx = NULL;
+    etch_connection *cx = tcpx? &tcpx->cx:  NULL;
+	if (NULL == cx || NULL == tcpx->rcvlxr) return -1;
+
+    tcpclient = tcpx->rcvlxr;
+    clientconx = tcpclient->cxlisten;
+
+    tcpclient->is_started = FALSE;
+
+    result = etch_tcpconx_close (clientconx, FALSE);
+
+    // aprrc = apr_socket_send (clientconx->cx.socket, ETCH_SHUTDOWNSIGNAL, &datalen);
+
+    // result = etch_tcpclient_send (tcpx, ETCH_SHUTDOWNSIGNAL, ETCH_SHUTDOWNSIGNALSIZE, &aprrc);
+    
+    return result;
+    //return aprrc == 0? 0: -1;
+}
+
+
+
+
+
+
+/*
+ * etch_tcpclient_stop()
+ */
+int etch_tcpclient_stop (etch_tcp_connection *conx)
+{
+    return etch_tcpconx_close(conx, 0);
+}
+
+
+/* - - - - - - - - - - - - - - - - - 
+ * tcp client :: i_transportdata
+ * - - - - - - - - - - - - - - - - - 
+ */
+
+
+
+/* - - - - - - - - - - - - - - -
+ * tcpclient :: i_transport 
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etch_tcpclient_get_session
+ * i_transport::get_session implementation
+ */
+i_session* etch_tcpclient_get_session (void* data) 
+{
+    etch_tcp_connection* thisx = (etch_tcp_connection*)data;
+    ETCH_ASSERT(is_etch_tcpconnection(thisx));
+    return (i_session*)thisx->session;
+}
+
+
+
+
+
+
+
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_tcp_server.c b/binding-c/runtime/c/src/main/transport/etch_tcp_server.c
new file mode 100644
index 0000000..d6e3f21
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_tcp_server.c
@@ -0,0 +1,1100 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_connection.c
+ * connection client and server classes - tcp, udp
+ */
+
+#include "etch_thread.h"
+#include "etch_tcp_server.h"
+#include "etch_encoding.h"
+#include "etch_flexbuffer.h"
+#include "etch_session_message.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+#include "etch_runtime.h"
+#include "etch_config.h"
+
+static const char* LOG_CATEGORY = "etch_tcpserver";
+
+// extern types
+extern apr_pool_t*         g_etch_main_pool;
+extern apr_thread_mutex_t* g_etch_main_pool_mutex;
+
+// TODO: module wide
+// - etch_tcpserver_static_create
+// - etch_tcpserver_static_destroy
+// - synchronize tcp servicer id
+// - synchronize tco connection id
+// - separating extern and static functions inside module
+
+
+char* ETCHTCPS = "TCPS";
+
+#define ETCH_CONNECTION_DEFLINGERTIME 30
+#define ETCH_CONNECTION_DEFNODELAY  TRUE
+#define ETCH_CONNECTION_DEFRETRYDELAYMS  1000
+
+unsigned next_etch_tcpserver_id();
+unsigned next_etch_connection_id();
+
+etch_tcp_connection* new_accepted_tcp_connection
+    (char* host, const int port, etch_rawsocket*);
+
+int  etch_tcpsvr_dummy_connection(etch_tcp_connection*);
+int  etch_deftcplistener_on_event(etch_tcp_server*, etch_tcp_connection*, const int, int, void*);
+
+/* transport interface */
+int etch_tcpsvr_transport_control(void*, etch_event*, etch_object*);
+int etch_tcpsvr_transport_notify (void*, etch_event*);
+etch_object* etch_tcpsvr_transport_query (void*, etch_query*);
+i_session* etch_tcpsvr_get_session(void*);
+
+/* session listener interface stubs */
+etch_object* etch_tcpsvr_stub_session_query (void*, etch_query*);
+
+
+#if(0)
+
+ TCPSERVER
+ |  Socket, hostIP, port, delay, isKeepalive, isNoDelay
+ |  buffersize, isAutoflush, trafficclass
+ |  InputStream, OutputStream
+ |  stop0(); openSocket(); setupSocket(); readSocket();
+ |  close(); send(); flush(); shutdownInput(); shutdownOutput();
+ |  remoteAddress(); fireData(); transportData();
+ |
+  - CONNECTION<SESSIONLISTENER>
+ |  |  sessionListener session;
+ |  |      sessionAccepted(socket);
+ |  |      SESSION
+ |  |         sessionQuery(); sessionControl(); sessionNotify(); 
+ |  |       
+ |  |  Monitor status;
+ |  |  Connection(); started(); stopped(); exception();
+ |  |  run0(); localAddress(); translateHost();
+ |  |  openSocket(); setupSocket(); readSocket(); close();
+ |  |  transportQuery(); transportControl(); transportNotify();
+ |  |  fireUp(); fireDown(); 
+ |  |  waitUp(); waitDown();
+ |  |
+ |   - RUNNER
+ |  |  |  Thread thread;
+ |  |  |  RunnerHandler handler;
+ |  |  |  start0()
+ |  |  |  stop0()
+ |  |  |  run()
+ |  |  |  run0()
+ |  |  |  fireStarted()
+ |  |  |  fireStopped()
+ |  |  |  fireException()
+ |  |   - ABSTRACTSTARTABLE
+ |  |
+ |   - TRANSPORT<SESSIONDATA>
+ |  |     transportQuery(); transportControl(); transportNotify();
+ |  |
+ |   - RUNNERHANDLER interface
+ |        started(); stopped(); exception();
+ | 
+  - TRANSPORT<SESSIONLISTENER>
+    |  SessionListener getSession(); setSession(SessionListener);
+    |  transportQuery(); transportControl(); transportNotify();
+
+#endif
+
+
+
+/* - - - - - - - - - - - - - - - - - 
+ * constructors / destructors
+ * - - - - - - - - - - - - - - - - - 
+ */
+
+
+/**
+ * etch_tcpsvr_on_data()
+ * tcp socket received data handler.  
+ * @param cx the connection object.
+ * @param uu parameter currently unused.
+ * @param length number of bytes in the supplied data buffer.
+ * @param data the data as received via the socket wrapped in a flexbuffer.
+ * caller retains this memory.
+ */
+int etch_tcpsvr_on_data (void* connectionData, const int uu, int length, void* bufferData)
+{
+    etch_connection* cx = (etch_connection*)connectionData;
+    etch_flexbuffer* data = (etch_flexbuffer*)bufferData;
+    int result = 0;
+    i_sessiondata* session = NULL;
+    etch_tcp_connection* tcpx = cx? (etch_tcp_connection*) cx->owner: NULL;
+    ETCH_ASSERT(is_etch_tcpconnection(tcpx));
+    ETCH_ASSERT(is_etch_flexbuffer(data));
+    ETCH_ASSERT(is_etch_sessiondata(tcpx->session));
+    session = tcpx->session;
+                                           
+    /* send the data up the chain to be packetized. note that tcpx->session->thisx
+     * is the owner of the i_sessiondata* session, which is the next higher layer 
+     * of the transport stack, which is ordinarily the packetizer. 
+     */
+    if (-1 == (result = session->session_data (session->thisx, NULL, data)))
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_WARN, "%d bytes via connxn %d discarded\n", 
+                 length, cx->conxid);
+    return result;
+}
+
+
+/*
+ * new_accepted_tcp_connection()
+ * etch_tcp_connection constructor for use with an accepted socket
+ * receive thread exit must delete this object
+ */
+etch_tcp_connection* new_accepted_tcp_connection(char* host, const int port, etch_rawsocket* accepted_socket)
+{
+    int result = 0;
+    etch_tcp_connection* newcon = NULL;
+    if (!host || !accepted_socket) return NULL;
+
+    newcon = (etch_tcp_connection*) new_object (sizeof(etch_tcp_connection), ETCHTYPEB_CONNECTION, CLASSID_TCP_CONNECTION);
+    ((etch_object*)newcon)->destroy = destroy_etch_tcp_connection;  
+
+    /* 1/1/09 need to verify this is correct - unit test failed since it expected 
+     * tcpconx.session to be non-null - while new_tcp_connection() initialized 
+     * these interfaces, the new_accepted_connection() did not - watch this spot 
+     * in case it turns out that the transport and session interfaces now plugged  
+     * in here are incorrect. fyi unit test now passes but must re-vet runtime.
+     */
+    if (0 != init_etch_tcpconx_interfaces (newcon)) return NULL; /* 1/1/09 */  
+
+    etch_init_connection (&newcon->cx, accepted_socket, newcon);
+
+    newcon->cx.socket = accepted_socket;
+    newcon->cx.hostname = etch_malloc(strlen(host)+1, ETCHTYPEB_BYTES);
+    strcpy(newcon->cx.hostname, host);
+    newcon->cx.port = port;       
+    newcon->is_nodelay = ETCH_CONNECTION_DEFNODELAY;
+    newcon->linger = ETCH_CONNECTION_DEFLINGERTIME;
+    newcon->cx.on_event = etch_tcpconx_on_event;  /* connection state handler */
+    #ifndef IS_ETCH_NO_SESSIONDATA                /* dead-end data for testing */
+    newcon->cx.on_data  = etch_tcpsvr_on_data;    /* received data handler */
+    #endif
+
+    if (0 == result)
+        newcon->cx.on_event (newcon, ETCH_CONXEVT_CREATED, (int) (size_t) accepted_socket, 0);
+    else 
+    {   newcon->cx.on_event (newcon, ETCH_CONXEVT_CREATERR, 0, 0);
+        destroy_etch_tcp_connection(newcon);
+        newcon = NULL;
+    } 
+      
+    return newcon;
+}
+
+
+/*
+ * destroy_etch_tcp_server()
+ * etch_tcp_server destructor
+ */
+int destroy_etch_tcp_server (void* data)
+{
+    etch_tcp_server* svr = (etch_tcp_server*)data;
+    int result = 0, serverid = 0;
+    if (NULL == svr) return -1;
+    serverid = svr->listener_id; 
+    svr->on_event(svr, 0, ETCH_CONXEVT_DESTROYING, 0, 0);               
+    
+    etch_tcpsvr_close(svr);  /* close if open */
+
+    if (!is_etchobj_static_content(svr))
+        destroy_etch_tcp_connection(svr->cxlisten);
+
+    if (svr->session && svr->is_session_owned)
+       ((etch_object*)svr->session)->destroy (svr->session);
+
+    if (svr->itransport)
+        etch_free(svr->itransport);
+
+    if (svr->threadpool && svr->is_threadpool_owned)
+        etch_object_destroy(svr->threadpool);
+
+    etch_object_destroy(svr->thread);
+    svr->thread = NULL;
+
+    etch_mutex_destroy(svr->client_connections_mutex);
+    svr->client_connections_mutex = NULL;
+
+    etch_linked_list_destroy(svr->client_connections);
+    svr->client_connections = NULL;
+
+    svr->on_event(svr, 0, ETCH_CONXEVT_DESTROYED, 0, 0);
+
+    result = destroy_objectex((etch_object*)svr);
+    return result;
+}
+
+
+/**
+ * etch_tcpsvr_set_session()
+ * i_transport::set_session() override
+ * @param session an i_sessionlistener*. caller owns this object.
+ */
+void etch_tcpsvr_set_session(void* data, void* sessionData)
+{
+    etch_tcp_server* thisx = (etch_tcp_server*)data;
+    i_sessionlistener* session = (i_sessionlistener*)sessionData;
+    ETCH_ASSERT(is_etch_tcpserver(thisx));
+    ETCH_ASSERT(is_etch_sessionlxr(session));
+
+    thisx->is_session_owned = FALSE;  /* internal caller will re-set */
+
+    if (thisx->session)  /* replacing? */
+    {   ETCH_ASSERT(is_etch_sessionlxr(thisx->session));
+        etch_object_destroy(thisx->session);
+    }
+
+    thisx->session  = session;
+    thisx->isession = session->isession;
+    thisx->session_control = session->session_control;
+    thisx->session_notify  = session->session_notify;
+    thisx->session_query   = session->session_query;
+    thisx->on_session_accepted = session->session_accepted;    
+}
+
+int etch_tcpsvr_stub_session_control (void* obj, etch_event* evt, etch_object* v)
+{
+    return -1;
+}
+
+int etch_tcpsvr_stub_session_notify  (void* obj, etch_event* event)
+{
+    return -1;
+}
+
+/*
+ * etch_tcpsvr_stub_on_session_accepted()
+ * i_sessionlistener::session_accepted default implementation
+ * @param thisx
+ * @param socket presumably an etch_socket wrapper. caller relinquishes.
+ */
+int etch_tcpsvr_stub_on_session_accepted(void* thisx, void* socket)
+{
+
+    return -1;
+} 
+
+
+/**
+ * new_tcp_server()
+ * etch_tcp_server constructor
+ */
+etch_tcp_server* new_tcp_server(etch_url* url, etch_threadpool* mp, etch_threadpool* sp, etch_resources* resxmap, i_sessionlistener* insession)
+{
+    etch_tcp_server* svr = NULL;
+    
+    // check parameters
+    if (NULL == url)
+    {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "Invalid argument url is null\n");
+        return NULL;
+    }
+
+    svr = (etch_tcp_server*) new_object(sizeof(etch_tcp_server), ETCHTYPEB_TCPSERVER, CLASSID_TCP_LISTENER);
+    svr->listener_id = next_etch_tcpserver_id();
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "creating tcp server %d ...\n", svr->listener_id);
+
+    ((etch_object*)svr)->destroy     = destroy_etch_tcp_server;
+    ((etch_object*)svr)->clone       = clone_null;
+    svr->on_event    = etch_deftcplistener_on_event;
+    svr->on_data     = etch_defconx_on_data;
+    svr->resxmap     = resxmap; /* not owned, can be null */
+    svr->threadpool  = mp;  /* currently always passed in */
+    svr->subpool     = sp;  /* currently always passed in */
+    svr->url         = url;
+    svr->thread      = NULL;
+
+    etch_linked_list_create(&svr->client_connections, 0);
+
+    etch_mutex_create(&svr->client_connections_mutex , ETCH_MUTEX_NESTED, NULL);
+
+    /* - - - - - - - - - - - - - - -
+     * transport (i_transport) 
+     * - - - - - - - - - - - - - - -
+     */
+    svr->itransport = new_transport_interface(svr,  
+        (etch_transport_control) etch_tcpsvr_transport_control, 
+        (etch_transport_notify)  etch_tcpsvr_transport_notify, 
+        (etch_transport_query)   etch_tcpsvr_transport_query);
+
+    svr->transport_control = etch_tcpsvr_transport_control;
+    svr->transport_notify  = etch_tcpsvr_transport_notify;
+    svr->transport_query   = etch_tcpsvr_transport_query;
+
+    svr->get_session = etch_tcpsvr_get_session;
+    svr->set_session = etch_tcpsvr_set_session;
+
+          
+    /* - - - - - - - - - - - - - - -
+     * session (i_sessionlistener)       
+     * - - - - - - - - - - - - - - -
+     */
+
+    if (insession)
+    {
+        svr->set_session(svr, insession);
+        svr->is_session_owned = FALSE; 
+    }
+    else
+    {   i_session* isession = new_session_interface(svr, 
+            etch_tcpsvr_stub_session_control, 
+            etch_tcpsvr_stub_session_notify, 
+            etch_tcpsvr_stub_session_query);
+
+        i_sessionlistener* newsession = new_sessionlistener_interface(svr, 
+            etch_tcpsvr_stub_on_session_accepted,
+            isession);
+
+        svr->set_session(svr, newsession);
+        svr->is_session_owned = TRUE; 
+    }  
+
+
+    /* - - - - - - - - - - - - - - -
+     * etch_tcp_server continued 
+     * - - - - - - - - - - - - - - -
+     */
+
+    /* create the listener's tcp connection */
+    svr->cxlisten = new_tcp_connection (url, NULL, NULL);
+
+    if (svr->cxlisten)
+    {
+        svr->cxlisten->cx.listener = (etch_object*) svr;
+        svr->on_event(svr, 0, ETCH_CONXEVT_CREATED, 0, 0);
+    }
+    else
+    {   svr->on_event(svr, 0, ETCH_CONXEVT_CREATERR, 0, 0);
+        destroy_etch_tcp_server(svr);
+        svr = NULL;
+    }
+
+    if (svr)
+        ETCH_LOG(ETCHTCPS, ETCH_LOG_DEBUG, "tcp server %d created\n", svr->listener_id);
+    else
+        ETCH_LOG(ETCHTCPS, ETCH_LOG_ERROR, "could not create tcp server\n");
+
+    return svr;
+}
+
+/* - - - - - - - - - - - - - - - - - 
+ * tcp server methods
+ * - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * etch_tcpsvr_open()
+ * open the server accept listener socket.
+ */
+int etch_tcpsvr_open (etch_tcp_server *svr, const int is_reconnect)
+{
+	int result = -1, is_new_socket = 0, arc = 0, attempt = 0;  
+    etch_tcp_connection* tcpx = NULL;
+    etch_connection* cx = NULL;
+    ETCH_ASSERT(is_etch_tcpserver(svr));
+    tcpx = svr->cxlisten;
+    cx   = &tcpx->cx;
+    if (svr->state != ETCH_TCPSERVER_STATE_CLOSED) return 0;
+    svr->on_event(svr, tcpx, ETCH_CONXEVT_OPENING, 0, 0); 
+    is_new_socket = cx->socket == NULL;  
+
+    if (is_reconnect)
+        if (!cx->socket || !cx->hostname || !*cx->hostname || !cx->delay) 
+            return svr->on_event(svr, tcpx, ETCH_CONXEVT_OPENERR, 0, 0);  
+    do 
+    {  if (0 != (arc = apr_sockaddr_info_get(&cx->sockdata, cx->hostname, 
+            ETCH_DEFAULT_SOCKET_FAMILY, cx->port, 0, cx->aprpool)))
+        {   svr->on_event(svr, tcpx, ETCH_CONXEVT_OPENERR, 4, (void*)(size_t)arc);  
+            break;
+        }
+
+        if (is_new_socket) /* not reconnecting, create a socket */
+        {
+            if (0 != (arc = new_tcpsocket (&cx->socket,cx->aprpool)))
+            {   svr->on_event(svr, tcpx, ETCH_CONXEVT_OPENERR, 3, (void*)(size_t)arc);  
+                break;
+            }
+
+            /* set socket options here: NONBLOCK, TIMEOUT */ 
+        }
+
+	apr_socket_opt_set(cx->socket, APR_SO_REUSEADDR, 1);
+
+        while(attempt++ < ETCH_CONNECTION_DEFRETRYATTEMPTS+1)   
+        {
+            if (is_reconnect || attempt > 0)
+                etch_sleep(cx->delay);
+
+            if (0 != (arc = apr_socket_bind(cx->socket, cx->sockdata)))
+            {   svr->on_event(svr, tcpx, ETCH_CONXEVT_OPENERR, 5, (void*)(size_t)arc);   
+                continue;
+            }
+
+            if (0 == (arc = apr_socket_listen(cx->socket, svr->backlog)))
+            {   cx->is_started = TRUE;
+                svr->on_event(svr, tcpx, ETCH_CONXEVT_LISTENED, cx->conxid, 0);
+                break;
+            } 
+     
+            svr->on_event(svr, tcpx, ETCH_CONXEVT_OPENERR, 6, (void*)(size_t)arc);  
+        }         
+
+    } while(0);
+    
+    if (cx->is_started) 
+    {   result = 0;  /* stopped means no longer closed but not yet started */
+        svr->state = ETCH_TCPSERVER_STATE_STOPPED;  
+    }
+    else 
+    if (is_new_socket)
+        cx->socket = NULL;
+
+    svr->on_event(svr, tcpx, 
+        result? ETCH_CONXEVT_OPENERR: ETCH_CONXEVT_OPENED, 0, 0);
+
+	return result;  
+}
+
+
+/*
+ * etch_tcpsvr_close()
+ * close server socket
+ */
+int etch_tcpsvr_close (etch_tcp_server* lxr)
+{
+    int  result = 0;
+    etch_connection* cx = NULL;
+    ETCH_ASSERT(is_etch_tcpserver(lxr));
+
+    if (lxr->state < ETCH_TCPSERVER_STATE_STOPPED)
+        return -1;  
+
+    if (lxr->state > ETCH_TCPSERVER_STATE_STOPPED) 
+        result = etch_tcpsvr_stop(lxr);  /* SVR BREAK 007 */
+
+    if (lxr->state != ETCH_TCPSERVER_STATE_STOPPED) 
+        return -1;
+
+    cx = &lxr->cxlisten->cx;
+    lxr->state = ETCH_TCPSERVER_STATE_CLOSING;
+    lxr->on_event(lxr, 0, ETCH_CONXEVT_CLOSING, 0, 0); 
+
+    result = etch_tcpconx_close(lxr->cxlisten, 0); /* close listen socket */
+
+    lxr->state = ETCH_TCPSERVER_STATE_CLOSED;
+    lxr->on_event(lxr, 0, result? ETCH_CONXEVT_CLOSERR: ETCH_CONXEVT_CLOSED, 0, 0);
+
+    if (cx->wait_down) 
+    {
+        /* if another thread is blocking on this condition variable, we set   
+         * the condition to DOWN, which is presumably what the other thread  
+         * will unblock on. 
+         */
+        etch_wait_set(cx->wait_down, ETCH_CONXEVT_DOWN);
+    }
+
+    return result; 
+}
+
+
+/**
+ * etch_tcp_listener_client_connection_proc
+ * tcp receive thread procedure for accepted session connections.
+ * this is the client session lifetime pump. it runs in its own thread, which
+ * exists until the peer socket is closed, the session requests closure of the
+ * session or server, or a socket error is detected.
+ */
+static void etch_tcp_listener_client_connection_proc(void* data)
+{ 
+    etch_thread_params* params = (etch_thread_params*)data;
+    unsigned char* buf = NULL;
+    int result = 0, arc = 0;
+    etch_flexbuffer* fbuf = NULL;   
+    const int thread_id = params->etch_thread_id;
+    int is_shutdown_request = FALSE;
+    int is_other_end_closed = FALSE, is_this_end_closed = FALSE;
+    etch_tcp_connection* accx = (etch_tcp_connection*) params->data;
+    etch_connection* cx  = &accx->cx;
+    etch_tcp_server* svr =(etch_tcp_server*) cx->listener;  
+    const int session_id = cx->conxid;
+    const int blen = cx->bufsize? cx->bufsize: ETCH_CONX_DEFAULT_BUFSIZE;
+    
+    ETCH_ASSERT(is_etch_tcpconnection(accx));
+    cx->on_event = etch_tcpconx_on_event; 
+
+ 
+    svr->on_event(svr, accx, ETCH_CONXEVT_RCVPUMP_START, 0, 0);
+    fbuf = new_flexbuffer(blen);   
+    buf  = etch_flexbuf_get_buffer(fbuf);   
+  
+    /* we are using blocking sockets. fyi if we switch to non-blocking mode
+     * in the future, the APR_STATUS_IS_EAGAIN(rc) macro is the test we want
+     * to make on the read or write result to determine if the socket was not
+     * ready to read or write - that macro tests multiple apr result codes.
+     */
+
+    accx->session->session_notify (accx->session->thisx, new_etch_event(0, ETCHEVT_SESSION_UP));
+
+    /* receive pump -- blocking read */
+    while (svr->state == ETCH_TCPSERVER_STATE_STARTED && cx->is_started) {
+        memset(buf, 0, blen); /* nice for debugging but otherwise unnecessary */
+        svr->on_event(svr, accx, ETCH_CONXEVT_RCVPUMP_RECEIVING, thread_id, 0);
+
+        /* receive data from tcp socket into buffer owned by flexbuffer.
+         * note that if this receive were to stop blocking, for example if the  
+         * peer went down without it being detected here, we would see serious 
+         * slowdown begin here due to unfettered looping of the listener proc. 
+         */
+        result = etch_tcpclient_receive (accx, buf, blen, &arc);  /* block */
+
+        /* if result is >= 0, it is the number of bytes received */
+
+        if (svr->state != ETCH_TCPSERVER_STATE_STARTED || !cx->is_started){
+            //in this case the svr stops the conx
+            params->is_own_data = 0;
+            break; /* if server stopped, exit */
+        }
+
+        if (APR_OTHER_END_CLOSED == arc || ETCH_OTHER_END_CLOSED == result)
+        {   is_other_end_closed = TRUE;  /* if peer down, exit */
+            break;
+        }
+
+        if (APR_THIS_END_CLOSED == arc)
+        {   is_this_end_closed = TRUE;  /* if this end down, exit */
+            break;
+        }
+
+        if (ETCH_SHUTDOWN_NOTIFIED == result)    
+        {   is_shutdown_request = TRUE;  /* client sent server shutdown request */
+            svr->is_started = FALSE;     /* (as opposed to client stop request) */
+            break;
+        }
+
+        if (result < 0) /* if socket error, exit */
+        {   svr->on_event(svr, svr->cxlisten, ETCH_CONXEVT_RCVPUMP_ERR, arc, 0);
+            break;
+        }  
+
+        etch_flexbuf_set_length(fbuf, result);   
+        etch_flexbuf_set_index (fbuf, 0);        
+
+        if (result > 0) /* forward (result) bytes to data handler for packetization */ 
+            result = cx->on_data (cx, 0, result, fbuf);  
+    }
+
+    /* at this point the client receive loop has exited, most likely due to 
+     * socket closed on either end, but could also be due to a socket error.
+     */
+
+    etch_mutex_lock(svr->client_connections_mutex);
+    svr->connections--; // TODO: connection count can also be accessed by client_connection list
+    etch_linked_list_remove(svr->client_connections, accx);
+    etch_mutex_unlock(svr->client_connections_mutex);
+
+    if (is_this_end_closed || is_other_end_closed || is_shutdown_request) result = 0;
+    svr->on_event(svr, accx, ETCH_CONXEVT_RCVPUMP_STOP, result, (void*)(size_t)thread_id);
+
+    accx->session->session_notify (accx->session->thisx, new_etch_event(0, ETCHEVT_SESSION_DOWN));
+
+    if (is_shutdown_request)
+    {   /* if this receive caught a server shutdown request from a client, do not destroy
+         * this session, but rather message back to the main listener to shut itself down.
+         * the main thread is blocking on the main listener thread, and will iterate and 
+         * destroy all the server's sessions once the listener thread unblocks.
+         */
+        i_sessionlistener* mainlistener = svr->session;
+
+        const int resultx = mainlistener->transport_control (mainlistener->thisx, new_etch_event(CLASSID_CONTROL_STOP_WAITDOWN, ETCH_INFWAIT), NULL);
+
+        /* we will not return here until after main listener has been destroyed */
+        result = resultx;    /* this extra local is simply a breakpoint target */
+    }
+    else
+    {   /* this code is executed when a session is terminates normally, either due to 
+         * peer connection closing, or client stop request. this code is not executed
+         * if the client is forced down from the main thread.
+         */
+        ETCH_LOG(ETCHTCPS, ETCH_LOG_DEBUG, "session %d begin teardown ...\n", session_id);
+
+        /* tear down client session not including accx */
+        etch_object_destroy(cx->session);
+        cx->session = NULL;
+
+        /* destroy client connection object */
+        etch_object_destroy(accx);
+        accx = NULL;
+
+        ETCH_LOG(ETCHTCPS, ETCH_LOG_DEBUG, "session %d destroyed\n", session_id);
+    }
+
+    etch_object_destroy(fbuf);  /* we now exit the client session receive thread */
+    ETCH_LOG(ETCHTCPS, ETCH_LOG_INFO, "client session %d ends\n", session_id);
+    ETCH_LOG(ETCHTCPS, ETCH_LOG_DEBUG, "session %d thread exit ...\n", session_id);
+}
+
+
+
+
+/**
+ * etch_tcpsvr_acceptproc()
+ * accept pump
+ */
+static void etch_tcp_listener_accept_proc(void* data)
+{
+    etch_thread_params* params = (etch_thread_params*)data;
+    int result = 0, arc = 0;
+    etch_tcp_server* listener = (etch_tcp_server*) params->data; 
+    const int thread_id  = params->etch_thread_id;
+    etch_tcp_connection* newx = 0;  
+    etch_tcp_connection* tcpx = listener->cxlisten;
+    etch_connection* cx = &tcpx->cx;
+    etch_rawsocket* listensock = cx->socket;
+    etch_rawsocket* newsock = NULL;
+    etch_thread* newthread  = NULL;
+    apr_pool_t* temp_pool  = NULL;
+    int max_number_of_connections = 0;
+    etch_config_t* config;
+
+    ETCH_ASSERT(is_etch_tcpserver(listener));
+
+    while (listener->is_started) {
+        listener->on_event(listener, tcpx, ETCH_CONXEVT_ACCEPTING, 0, 0);
+
+        /* each accepted connection gets its own apr subpool, which is freed when 
+         * the connection is destroyed. this accounts for apr memory specific to  
+         * the connection which is not explicitly freed, such as apr_socket_t */
+        ETCH_ASSERT(g_etch_main_pool != NULL);
+
+        apr_pool_create(&temp_pool, NULL); 
+        //printf("4 creating apr pool %p\n",temp_pool);
+
+        /* socket block here for a client connection request */
+        if (0 != (arc = apr_socket_accept (&newsock, listensock, temp_pool))) {
+            listener->on_event(listener, tcpx, ETCH_CONXEVT_ACCEPTERR, 0,(void*)(size_t)arc); 
+            /* if server shutdown, no error */
+            if (listener->is_started) {
+                result = -1; 
+            }
+            /* TODO: catch other conditions in which nonzero return not error */
+            break;
+        }
+        
+        if (!listener->is_started) {
+            /* Even when we disconnect, close the newly created socket. So we don't have to wait
+               for the timeout. */
+            if (newsock != NULL)
+                apr_socket_close(newsock);
+            break; /* server shutdown */
+        }
+        ETCH_LOG(ETCHTCPS, ETCH_LOG_DEBUG, "connect request for socket %x\n", (size_t)newsock);
+	
+        etch_runtime_get_config(&config);
+        ETCH_ASSERT(config);
+        etch_config_get_property_int(config, "etch.maxconnections", &max_number_of_connections);
+        if(max_number_of_connections == 0) {
+            max_number_of_connections = 40;
+        }
+
+        if(listener->connections >= max_number_of_connections){
+            ETCH_LOG(ETCHTCPS, ETCH_LOG_DEBUG, "max number of connections (%d) reached, not accepting more connection requests\n", listener->connections);
+            apr_socket_close(newsock);
+            continue;
+        }
+
+        /* create the new accepted connection object. note that this object 
+         * will be freed when its listener thread exits. SVR BREAK 004 
+         */
+        newx = new_accepted_tcp_connection (cx->hostname, cx->port, newsock);
+
+        newx->cx.listener   = (etch_object*)listener;
+        newx->cx.is_started = TRUE;
+        
+        listener->on_event (listener, newx, ETCH_CONXEVT_ACCEPTED, 0, 0);
+
+        /* 1/4/09 permit socket data handler to be overridden, e.g. by a unit test */
+        if (listener->on_data && listener->on_data != etch_defconx_on_data)
+            newx->cx.on_data = listener->on_data;
+
+        /* TODO use the sessionlistener interface to call back to the accepted handler.
+         * we temporarily plugged it in directly to the tcp server object in new_etch_listener().
+         */
+        /* e.g. transport.tcpxfact_session_accepted */
+        if (listener->on_session_accepted) {
+            listener->on_session_accepted (listener->session, newx);   /* SVR BREAK 005 */
+        }
+
+        /* on return from on_session_accepted, the connection cx.session is a reference
+         * to the etch_session* client session data object. the thread we start below
+         * will call the destructor on this object when it exits, in order to destroy  
+         * the client session objects such as delivery service, stub, etc.
+         */
+
+        etch_mutex_lock(listener->client_connections_mutex);
+        listener->connections++;
+        etch_linked_list_add(listener->client_connections, newx);
+        etch_mutex_unlock(listener->client_connections_mutex);
+
+        /* run a read listener for the client connection, on a thread from the client pool,
+         * via etch_threadpool_run_freethread, etch_thread_start, etch_tcpserver_listenerproc.
+         * SVR BREAK 006  
+         */
+        if (NULL == ( newx->cx.thread = newthread = listener->threadpool->run (listener->subpool, etch_tcp_listener_client_connection_proc, newx))) 
+        {
+            listener->on_event (listener, newx, ETCH_CONXEVT_STARTERR, 1, 0);
+            etch_object_destroy(newx); 
+            newx = NULL;  /* todo newx should cx.session.destroy() */
+            result = -1;
+            break;
+        }
+
+        /* the new client session is now executing on its own thread. 
+         * loop back to continue listening for client connection requests. 
+         */
+
+    }
+
+    if(0 == result) {
+         listener->on_event(listener, tcpx, ETCH_CONXEVT_ACCEPTPUMPEXIT, thread_id, 0);
+    } else {
+        listener->on_event(listener, tcpx, ETCH_CONXEVT_ACCEPTPUMPEXITERR, 0, 0);
+    }
+}
+
+
+
+/**
+ * etch_tcpsvr_start()
+ * start accepting connections
+ */
+int etch_tcpsvr_start (etch_tcp_server* tcpsvr)
+{
+	int result = 0;
+    etch_tcp_connection* tcpx = tcpsvr->cxlisten;   
+    etch_connection* cx = &tcpx->cx;
+
+    if (tcpsvr->state != ETCH_TCPSERVER_STATE_STOPPED) 
+        return tcpsvr->on_event(tcpsvr, tcpx, ETCH_CONXEVT_STARTERR, 0, 0);  
+
+    /* the threadpool acts as the server's thread manager. it creates threads
+     * on request and destroys them at thread exit. the main pool is always
+     * present here in the runtime, but could be null for unit tests. */
+    if (tcpsvr->threadpool == NULL) /* currently only null for unit tests */  
+    {   tcpsvr->threadpool = new_threadpool (ETCH_THREADPOOLTYPE_FREE, 0); 
+        tcpsvr->is_threadpool_owned = TRUE;  
+    }
+
+    /* data passed to threads will be either this object, or accepted connection
+     * objects. configure thread manager to not free this data at thread exit. */
+    tcpsvr->threadpool->is_free_data = FALSE;
+    tcpsvr->threadpool->is_data_etchobject = TRUE;
+
+    tcpsvr->state = ETCH_TCPSERVER_STATE_STARTED;
+    tcpsvr->is_started = TRUE;
+    tcpsvr->on_event(tcpsvr, tcpx, ETCH_CONXEVT_STARTING, 0, 0);  
+
+    tcpsvr->thread = new_thread(etch_tcp_listener_accept_proc, tcpsvr);
+    if(tcpsvr->thread == NULL) {
+        // TODO: error handling thread could not be started
+        tcpsvr->on_event (tcpsvr, tcpx, ETCH_CONXEVT_STARTERR, 1, 0);
+        result = -1;
+    }
+    tcpsvr->thread->start(tcpsvr->thread);
+    // TODO: error logging
+
+    /* start the accept thread on the main thread manager. SVR BREAK 003 */
+    // TODO: run this as default thread
+    //if (NULL == tcpsvr->threadpool->run (tcpsvr->threadpool, etch_tcp_listerner_proc, tcpsvr))
+    //{
+    //    tcpsvr->on_event (tcpsvr, tcpx, ETCH_CONXEVT_STARTERR, 1, 0);
+    //    result = -1;
+    //}
+     
+    tcpsvr->on_event(tcpsvr, tcpx, result? ETCH_CONXEVT_STARTERR: ETCH_CONXEVT_STARTED, 0, 0);
+
+    if (cx->wait_up) 
+    {
+        /* if another thread is blocking on this condition variable, we set the wait 
+         * variable to UP, which is presumably what the waiting thread will unblock on. */
+        //ETCH_ASSERT(is_etch_wait(cx->waiter));
+        etch_wait_set(cx->wait_up, ETCH_CONXEVT_UP);
+    }
+
+    return result;
+}
+
+
+/**
+ * etch_tcpsvr_stop()
+ * stop accepting connections and shut down the accept listener.
+ */
+int etch_tcpsvr_stop (etch_tcp_server* server)
+{
+    int result = 0;
+    etch_tcp_connection* tcpx = NULL;
+    etch_tcp_connection* client_con = NULL;
+    int connection_count = 0;
+
+    ETCH_ASSERT(is_etch_tcpserver(server));
+    tcpx = server? server->cxlisten: NULL;
+    if (!tcpx) return -1;
+
+    if (server->state <  ETCH_TCPSERVER_STATE_STARTED)  
+        return server->on_event(server, tcpx, ETCH_CONXEVT_STOPERR, 0, 0);  
+ 
+    server->is_started = FALSE; /* pump threads conditional */
+    server->state = ETCH_TCPSERVER_STATE_STOPPING;
+    server->on_event(server, tcpx, ETCH_CONXEVT_STOPPING, 0, 0);
+    
+    /* unblock the accept thread so it will recognize that it should exit */
+    result = etch_tcpsvr_dummy_connection (tcpx);
+
+    // wait to server thread finished
+    etch_join(server->thread);
+
+    //etch_sleep(ACCEPTWAITMS); /* pause here avoids accept thread hang */
+    
+    etch_mutex_lock(server->client_connections_mutex);
+    connection_count = server->connections;
+    ETCH_ASSERT(connection_count == etch_linked_list_count(server->client_connections));
+    for(;connection_count > 0; connection_count--){
+        etch_linked_list_get(server->client_connections, 0, (void*)&client_con);
+        ETCH_ASSERT(client_con);
+        result = etch_tcpconx_close(client_con,0);
+    }
+    etch_mutex_unlock(server->client_connections_mutex);
+
+    /* BLOCK here until all threads exited */
+    result = threadpool_waitfor_all (server->threadpool, TRUE); 
+
+    server->state = ETCH_TCPSERVER_STATE_STOPPED;
+    server->on_event(server, tcpx, ETCH_CONXEVT_STOPPED, 0, 0);
+    return result;
+}
+
+
+/**
+ * next_etch_tcpserver_id()
+ * return a unique ID used to identify a server instance
+ */
+unsigned next_etch_tcpserver_id()
+{
+    do { apr_atomic_inc32 ((volatile apr_uint32_t*) &tcpserver_id_farm);
+       } while(tcpserver_id_farm == 0); 
+
+    return tcpserver_id_farm;
+}
+
+
+/**
+ * etch_tcpsvr_dummy_connection()
+ * create a dummy client connection so as to unblock the accept thread, 
+ * in order that it can then recognize that it should exit, and do so.
+ * note that an invalid server address such as 0.0.0.0 will cause the connection
+ * attempt to fail, whereas it will not have caused the accept to fail. in such
+ * a case, the accept thread is left hanging, and a subsequent crash on service
+ * exit is likely. TODO both ends should validate IP addresses. etch_url does not.
+ */
+int etch_tcpsvr_dummy_connection (etch_tcp_connection* tcpx)
+{
+    apr_status_t apr_status = APR_SUCCESS;
+    apr_socket_t*   dummy = 0;
+    apr_sockaddr_t* addr  = 0;
+    int attempts = 0;
+    etch_connection* cx = &tcpx->cx;
+    const int MAXATTEMPTS = 8, DELAY_BETWEEN_ATTEMPTS_MS = 100;
+
+    apr_status = new_tcpsocket(&dummy, cx->aprpool);
+    if(apr_status != APR_SUCCESS) {
+        cx->on_event(tcpx, ETCH_CONXEVT_OPENERR, 3, (void*)(size_t)apr_status); 
+    }
+    else {
+        apr_status = apr_sockaddr_info_get(&addr, "127.0.0.1", APR_UNSPEC, cx->sockdata->port, 0, cx->aprpool);
+        if(apr_status != APR_SUCCESS) {
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not get addr info.");
+        }
+
+        while (1)
+        {
+            apr_status = apr_socket_connect (dummy, addr);
+            if(apr_status == APR_SUCCESS)
+                break;
+            
+            if (++attempts > MAXATTEMPTS)
+            {
+                cx->on_event (tcpx, ETCH_CONXEVT_OPENERR, 2, (void*)(size_t)apr_status); 
+                break;
+            }
+            else
+                etch_sleep(DELAY_BETWEEN_ATTEMPTS_MS);
+        }
+    }
+    return apr_status ? -1 : 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - - 
+ * tcp server :: i_sessionlistener
+ * - - - - - - - - - - - - - - - - - 
+ */
+
+/*
+ * pointers to these funtions are copied from the i_sessionlistener implementation
+ * at set_session() time. these stub implementations are provided as placeholders.
+ */
+
+
+
+
+
+
+
+etch_object* etch_tcpsvr_stub_session_query (void* obj, etch_query* query) 
+{
+    return NULL;
+}
+
+
+/* - - - - - - - - - - - - - - -
+ * tcpserver :: i_transport 
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etch_tcpsvr_get_session
+ * i_transport::get_session implementation.
+ * returns the i_session, whose thisx is a etch_session_listener*
+ */
+i_session* etch_tcpsvr_get_session(void* data) 
+{
+    etch_tcp_server* thisx = (etch_tcp_server*)data;
+    ETCH_ASSERT(is_etch_tcpserver(thisx));
+    return thisx->isession;
+}
+
+
+
+
+/**
+ * etch_tcpsvr_transport_control()
+ * i_transport::transport_control override.
+ * @param control event, sender relinquishes.
+ * @param value control value, sender relinquishes.
+ */
+int etch_tcpsvr_transport_control (void* data, etch_event* control, etch_object* value)
+{
+  etch_tcp_server* thisx = (etch_tcp_server*)data;
+    int  result = 0;
+    etch_connection* cx = NULL;
+    const int timeoutms = value? ((etch_int32*) value)->value: 0;
+    const int objclass  = control? ((etch_object*)control)->class_id: 0;
+    ETCH_ASSERT(is_etch_tcpserver(thisx));
+    cx = &thisx->cxlisten->cx;
+
+    switch(objclass)
+    {  
+       case CLASSID_CONTROL_START:
+
+            if (0 == (result = etch_tcpsvr_open(thisx, ETCH_CONX_NOT_RECONNECTING)))
+                result = etch_tcpsvr_start(thisx);
+
+            break; 
+           
+       case CLASSID_CONTROL_START_WAITUP:
+
+            /* point to the condition variable on the waiter. this is a semikludge;
+             * however we need to have a target for the up state before we do the 
+             * waitup, since the connect will complete before we get around to waitup,
+             * and it needs to be able to mark state as up. previously the state 
+             * variable cond_var was not set until the wait_up was invoked. in the 
+             * current design the cond_var is nulled out after a wait, in order to 
+             * reset wait state to not waiting, so we need to ensure it is populated 
+             * in advance of any need to set a wait condition to some state prior to 
+             * actually waiting.
+             * TODO: etch_wait was changed remove this
+             */
+            //etchconx_init_waitstate(cx);
+
+            /* open the connection, and wait for completion. caller blocks here.
+             * timeout is indicated via result code 1 = ETCH_TIMEOUT. SVR BREAK 002
+             */
+            if (0 == (result = etch_tcpsvr_open(thisx, ETCH_CONX_NOT_RECONNECTING)))
+                if (0 == (result = etch_tcpsvr_start(thisx)))
+                    result = etchconx_wait_up(cx, timeoutms);
+            break;  
+
+       case CLASSID_CONTROL_STOP:
+
+            result = etch_tcpsvr_close(thisx);
+            break;
+
+       case CLASSID_CONTROL_STOP_WAITDOWN:
+            /* note all comments above at case CLASSID_CONTROL_START_WAITUP */
+            //etchconx_init_waitstate(cx);
+
+            if (0 == (result = etch_tcpsvr_close(thisx)))
+                result = etchconx_wait_down(cx, timeoutms);
+
+            break;
+    }
+
+    if (control) 
+        etch_object_destroy(control);
+    if (value)   
+        etch_object_destroy(value);
+    return result;
+}
+
+
+/**
+ * etch_tcpsvr_transport_notify()
+ * i_transport::transport_notify override.
+ * @param evt, caller relinquishes.
+ */
+int etch_tcpsvr_transport_notify (void* data, etch_event* evt)
+{        
+    etch_tcp_server* thisx = (etch_tcp_server*)data;
+    ETCH_ASSERT(is_etch_tcpserver(thisx)); 
+    etch_object_destroy(evt);
+    return 0;  /* nothing to do */
+}
+
+
+/**
+ * etch_tcpsvr_transport_query()
+ * i_transport::transport_query override.
+ * @param query, caller relinquishes.
+ */
+etch_object* etch_tcpsvr_transport_query (void* data, etch_query* query) 
+{          
+    etch_tcp_server* thisx = (etch_tcp_server*)data;
+    ETCH_ASSERT(is_etch_tcpserver(thisx));
+    /* todo is this right? */
+    return thisx->itransport->transport_query(thisx->itransport, query);
+}
+
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_tdformat.c b/binding-c/runtime/c/src/main/transport/etch_tdformat.c
new file mode 100644
index 0000000..cef73e2
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_tdformat.c
@@ -0,0 +1,120 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_tdformat.c
+ * a factory used to abstract tagged data handler constructors
+ */
+#include "etch_tdformat.h" 
+#include "etch_objecttypes.h"
+#include <wchar.h>
+
+void etchtdf_init();
+int  etchtdf_name_to_id(wchar_t*);
+tagged_data_input*  etchtdf_defnewtdi (etch_value_factory*);
+tagged_data_output* etchtdf_defnewtdo (etch_value_factory*);
+
+const wchar_t* tdfname_binary = L"binary";
+const wchar_t* tdfname_xml    = L"xml";
+
+
+/*
+ * tagdata_format_factory()
+ * @param format_name name of the tagged data format, e.g., L"binary", 
+ * caller retains ownership of this string.
+ * @return a format factory (interface to tagged data constructors) for specified format.
+ * caller assumes ownership of this object.
+ */
+tagdata_format_factory* get_format_factory(wchar_t* format_name)
+{
+    tagdata_format_factory* ff = (tagdata_format_factory*) new_object
+        (sizeof(tagdata_format_factory), ETCHTYPEB_FORMATFACT, CLASSID_FORMATFACT);
+
+    ff->new_tagdata_input  = etchtdf_defnewtdi;
+    ff->new_tagdata_output = etchtdf_defnewtdo; 
+
+    switch(etchtdf_name_to_id(format_name))
+    {   case ETCH_TAGDATA_FORMAT_BINARY:
+             ((etch_object*)ff)->class_id = CLASSID_FORMATFACT_BINARY;       
+             ff->new_tagdata_input  = new_binary_tdi; 
+             ff->new_tagdata_output = new_binary_tdo; 
+             break;
+        case ETCH_TAGDATA_FORMAT_XML:
+             ((etch_object*)ff)->class_id = CLASSID_FORMATFACT_XML;
+             /* overrides will be plugged in here at such time as we have xml tdi/tdo */
+             break;
+        default: /* name not recognized */
+             break;
+    }
+
+    return ff;
+}
+
+
+/*
+ * etchtdf_init()
+ * static data lazy initializer 
+ */
+void etchtdf_init()
+{
+    if (is_tdf_initialized) return;
+    tdformat_names[ETCH_TAGDATA_FORMAT_BINARY] = tdfname_binary;
+    tdformat_names[ETCH_TAGDATA_FORMAT_XML]    = tdfname_xml;
+    is_tdf_initialized = TRUE;
+}
+
+ 
+/*
+ * etchtdf_name_to_id()
+ * translate name of tagdata format to format ID (index)
+ */
+int etchtdf_name_to_id(wchar_t* format_name)
+{
+    int i = 0;
+    etchtdf_init();
+    if (NULL == format_name) return -1;
+
+    for(; i < ETCH_TAGDATA_FORMAT_COUNT; i++)
+        if (0 == wcscmp(format_name, tdformat_names[i]))
+            return i;
+
+    return -1;
+}
+
+
+/*
+ * tdf_defnewtdi()
+ * default virtual new_tagdata_input()
+ */
+tagged_data_input* etchtdf_defnewtdi (etch_value_factory* vf)
+{
+    return NULL;
+} 
+
+
+/*
+ * tdf_defnewtdi()
+ * default virtual new_tagdata_output()
+ */
+tagged_data_output* etchtdf_defnewtdo (etch_value_factory* vf)
+{
+    return NULL;
+} 
+
+
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_transport.c b/binding-c/runtime/c/src/main/transport/etch_transport.c
new file mode 100644
index 0000000..f28bb47
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_transport.c
@@ -0,0 +1,1574 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_transport.c 
+ * common transport functionality
+ */
+
+#include "etch.h"
+#include "etch_runtime.h"
+#include "etch_plain_mailbox_manager.h"
+#include "etch_svcobj_masks.h"
+#include "etch_plain_mailbox.h"
+#include "etch_transport.h"
+#include "etch_packetizer.h"
+#include "etch_messagizer.h"
+#include "etch_tcp_server.h"
+#include "etch_tcp_connection.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+static const char* LOG_CATEGORY = "etch_transport";
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+typedef etch_plainmailboxmgr etch_mailbox_manager;
+
+
+int tcpdelsvc_init (etch_tcp_delivery_service*);
+int destroy_delivery_service_interface (void*);
+int destroy_delivery_service_via_interface(void*);
+int destroy_tcp_delivery_service(void*);
+int tcpdelsvc_begincall(i_delivery_service*, etch_message*, i_mailbox**);
+int tcpdelsvc_endcall  (i_delivery_service*, i_mailbox*, etch_type*, etch_object**);
+int tcpdelsvc_session_message (void*, etch_who*, etch_message*);
+int tcpdelsvc_session_control (void*, etch_event*, etch_object*);
+int tcpdelsvc_session_notify  (void*, etch_event*);
+etch_object* tcpdelsvc_session_query (void*, etch_query*);
+i_session* tcpdelsvc_get_session(void*);
+etch_object* tcpdelsvc_transport_query (void*, etch_query*); 
+int tcpdelsvc_transport_control(void*, etch_event*, etch_object*);
+int tcpdelsvc_transport_notify (void*, etch_event*);
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * delivery service
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/*
+ * new_etch_transport()
+ * etch_delivery_service constructor.
+ * @remarks this is the transport factory, implemented via a switch. 
+ * @param uri a uri string, caller relinquishes.
+ * @param params a transport parameter bundle, caller retains.
+ * @param conximpl optional pre-existing connection implementation, such as tcp_connection*.
+ * @return a delivery service interface. note that invoking the destructor on this interface
+ * destroys the delivery service implementation, as well as the interface.
+ */
+i_delivery_service* new_etch_transport (wchar_t* uri, etch_factory_params* params, void* conximpl)
+{
+    etch_url* url = new_url(uri); 
+
+    i_delivery_service* newds = new_etch_transport_a (url, params, conximpl);   
+    
+    etch_object_destroy(url);
+    return newds;    
+}
+
+
+/*
+ * new_etch_transport_a()
+ * etch_delivery_service constructor.
+ * @remarks this is the transport factory, implemented via a switch. 
+ * @param url an etch_url, caller retains.
+ * @param resources a resources map, caller retains.
+ * @return a delivery service interface. invoking the destructor on this interface
+ * destroys the delivery service implementation, as well as the interface.
+ */
+i_delivery_service* new_etch_transport_a (etch_url* url, etch_factory_params* params, void* conximpl)
+{
+    i_delivery_service* newds = NULL;
+
+    if (is_url_scheme_udp(url))
+    {    
+        /* not yet implemented */
+    }
+    #if(0)
+    else   /* handlers for other url schemes follow here eventually */  
+    if (is_url_scheme_foo(url))
+    {
+        /* ... */
+    }
+    #endif
+    else
+    {   /* url schemes http, tcp, default */
+        etch_tcp_delivery_service* tcpds = new_tcp_delivery_service (url, params, conximpl); 
+ 
+        if (tcpds)
+        {   newds = tcpds->ids; 
+            newds->thisx = tcpds;
+        } 
+    }
+    
+    return newds;    
+}
+
+
+/*
+ * new_delivery_service()
+ */
+etch_object* new_delivery_service (const int objsize, const unsigned short class_id)
+{
+    return new_object (objsize, ETCHTYPEB_DELIVERYSVC_IMPL, class_id);
+}    
+
+
+/*
+ * new_tcp_delivery_service()
+ * etch_tcp_delivery_service constructor 
+ * replaces java TcpTransportFactory.newTransport
+ * @param params server parameter bundle, caller retains. 
+ * &param tcpx if present, the already accepted client connection. 
+ * if present, caller retains.
+ */
+etch_tcp_delivery_service* new_tcp_delivery_service (etch_url* url, 
+    etch_factory_params* params, etch_tcp_connection* tcpconx)
+{
+    etch_resources* resources = NULL;
+    etch_packetizer* packetizer = NULL;
+    etch_messagizer* messagizer = NULL;
+    etch_mailbox_manager* mboxmgr = NULL;
+    etch_tcp_delivery_service* delsvc = NULL;  
+    const int is_tcpconx_owned = tcpconx == NULL;  
+    ETCH_ASSERT(params && params->in_resx); 
+    resources = params->in_resx;
+
+    do
+    {   /* as each next higher layer of the delivery service is instantiated, it
+         * is passed passed a transport interface to the previously-instantiated
+         * layer. in each such case, note that the new layer does not own memory 
+         * for the passed transport interface. 
+         */
+        if (NULL == tcpconx)  
+            tcpconx = new_tcp_connection (url, params->in_resx, NULL);  
+        
+        ETCH_ASSERT(tcpconx);
+        if (0 != init_etch_tcpconx_interfaces (tcpconx)) break;  
+         
+        packetizer = new_packetizer_a (tcpconx->itd, url, resources); 
+        if (NULL == packetizer) break;
+      
+        messagizer = new_messagizer_a (packetizer->transportpkt, url, resources);
+        if (NULL == messagizer) break;
+
+        mboxmgr = new_plain_mailbox_manager (messagizer->transportmsg, 
+            url->raw, resources, params->mblock);
+        if (NULL == mboxmgr) break;
+
+        delsvc = (etch_tcp_delivery_service*) new_delivery_service 
+          (sizeof(etch_tcp_delivery_service), CLASSID_TCP_DELIVERYSVC);
+
+        ((etch_object*)delsvc)->destroy = destroy_tcp_delivery_service;
+
+        /* set our transport to that of the next lower layer (mailbox manager) */
+        delsvc->transport  = mboxmgr->transportmsg;  
+        delsvc->transportx = mboxmgr->imanager;  /* todo can we lose this ref? */     
+
+        delsvc->mailboxmgr = mboxmgr;
+        delsvc->tcpconx    = tcpconx;
+        delsvc->wait_up    = tcpconx->cx.wait_up; /* connection up/down monitor */
+        delsvc->wait_down  = tcpconx->cx.wait_down; /* connection up/down monitor */
+        delsvc->rwlock     = params->mblock;     /* not owned */
+        delsvc->packetizer = packetizer;        /* todo can we lose these refs */
+        delsvc->messagizer = messagizer;
+        delsvc->resources  = resources;
+        delsvc->is_tcpconx_owned = is_tcpconx_owned;
+
+        tcpdelsvc_init (delsvc);  /* initialize the delivery service interface */
+
+    } while(0);
+
+    if (NULL == delsvc)
+    {
+      etch_object_destroy(tcpconx);
+      tcpconx = NULL;
+
+      etch_object_destroy(packetizer);
+      packetizer = NULL;
+
+      etch_object_destroy(messagizer);
+      messagizer = NULL;
+
+      etch_object_destroy(mboxmgr);
+      mboxmgr = NULL;
+
+    }
+
+    return delsvc;
+}
+
+/**
+ * tcpdelsvc_set_session()
+ * @param session the i_sessionmessage interface. caller retains ownership.
+ * this is generally called from the stub constructor.
+ */
+void tcpdelsvc_set_session (void* data, void* sessionData) 
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    i_sessionmessage* session = (i_sessionmessage*)sessionData;
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+    ETCH_ASSERT(is_etch_sessionmsg(session));
+    /* set delivery service session to be the passed (stub's) session */
+    tcpds->session = tcpds->ids->ism = session;
+}
+
+/**
+ * tcpdelsvc_transport_message()
+ * @param whoto recipient - caller retains this memory, can be null.
+ * @param message the message
+ * caller relinquishes this memory on success, retains on failure.
+ * @return 0 success, -1 error.
+ */
+int tcpdelsvc_transport_message (void* data, void* whoData, void* messageData)
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    etch_who* whoto = (etch_who*)whoData;
+    etch_message* msg = (etch_message*)messageData;
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+    i_transportmessage* dstransport  = tcpds->transport;
+    ETCH_ASSERT(is_etch_transportmsg(dstransport));
+
+    return dstransport->transport_message (dstransport->thisx, whoto, msg);
+}
+
+
+
+/**
+ * tcpdelsvc_init()
+ * initialize delivery service interface
+ */
+int tcpdelsvc_init (etch_tcp_delivery_service* delsvc)
+{   
+    i_session*   isession   = NULL;
+    i_transport* itransport = NULL;
+
+    i_delivery_service* ids = new_delivery_service_interface(NULL, NULL);
+    delsvc->ids = ids;
+
+    /* external transport and session */
+    ids->transport  = delsvc->transport;
+    ids->session    = delsvc->session;
+
+    ids->begin_call = delsvc->begin_call = (etch_delivsvc_begincall)tcpdelsvc_begincall;
+    ids->end_call   = delsvc->end_call   = (etch_delvisvc_endcall)tcpdelsvc_endcall;
+
+
+    /* - - - - - - - - - - - - - - -
+     * i_transportmessage (native)
+     * - - - - - - - - - - - - - - -
+     */
+    itransport = new_transport_interface (ids,
+        tcpdelsvc_transport_control,
+        tcpdelsvc_transport_notify,
+        tcpdelsvc_transport_query);
+
+    delsvc->transportmsg = new_transportmsg_interface (ids, 
+        tcpdelsvc_transport_message, 
+        itransport); /* transportmsg now owns itransport */
+
+    delsvc->transportmsg->set_session = tcpdelsvc_set_session;
+    delsvc->transportmsg->get_session = tcpdelsvc_get_session;
+
+    /* copy native transport back to interface */
+    ids->itm = delsvc->transportmsg;
+
+    /* copy i_transportmsg interface methods up to this object */
+    delsvc->transport_message = delsvc->transportmsg->transport_message;
+    delsvc->transport_control = itransport->transport_control;
+    delsvc->transport_notify  = itransport->transport_notify;
+    delsvc->transport_query   = itransport->transport_query;
+    delsvc->set_session       = itransport->set_session;
+    delsvc->get_session       = itransport->get_session;
+  
+
+    /* - - - - - - - - - - - - - - -
+     * i_sessionmessage (native)
+     * - - - - - - - - - - - - - - -
+     */
+    isession = new_session_interface (ids, 
+        tcpdelsvc_session_control,
+        tcpdelsvc_session_notify,
+        tcpdelsvc_session_query);
+
+    delsvc->sessionmsg  = new_sessionmsg_interface (ids, 
+        tcpdelsvc_session_message, 
+        isession); /* sessionmsg now owns isession */
+
+    /* copy native session back to interface */
+    ids->ism = delsvc->sessionmsg;
+
+    /* copy i_sessionmessage interface methods up to this object */
+    delsvc->session_message = delsvc->sessionmsg->session_message;
+    delsvc->session_control = isession->session_control;
+    delsvc->session_notify  = isession->session_notify;
+    delsvc->session_query   = isession->session_query;
+
+    /* finally set session of next lower layer (messagizer) to our session */
+    delsvc->transport->set_session (delsvc->transport->thisx, delsvc->sessionmsg);   
+
+    return 0;
+}
+
+
+/**
+ * new_delivery_service_interface()
+ * delivery service interface constructor
+ */
+i_delivery_service* new_delivery_service_interface
+    (i_sessionmessage* isessionmsg, i_transportmessage* itransportmsg)
+{
+    i_delivery_service* ids = (i_delivery_service*) new_object(sizeof(i_delivery_service), 
+        ETCHTYPEB_DELIVERYSVCINT, CLASSID_DELIVERYSVC);
+
+    /* this destructor destroys the parent implementation, 
+     * which in turn destroys this interface object */
+    ((etch_object*)ids)->destroy = destroy_delivery_service_via_interface;
+
+    ids->ism = isessionmsg;
+    ids->itm = itransportmsg;
+
+    return ids;
+}
+
+
+/**
+ * destroy_delivery_service_stub()
+ * invoked by i_deliveryservice destructor to destroy the stub via the session
+ * shared by the stub and delivery service, and finally destroy the session.
+ */
+int destroy_delivery_service_stub (void * data)
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    /* 1. the stub constructor created a session interface and set the 
+     * delivery service's session to that session, and set the delivery
+     * service's is_session_owned true.
+     * 2. the stub and delivery service therefore share the session interface.
+     * 3. the delivery service implementation object (e.g. tcp delivery service)
+     * also references that session, but of course does not own it. 
+     * 4. the session interface's thisx pointer is the stub object.
+     * 5. the delivery service owns the stub by contract.
+     * the delivery service implementation object's destructor invokes the
+     * delivery service interface destructor to destroy the session and stub.
+     * 6. the delivery service interface destructor destroys the stub by invoking 
+     * this method, which finds the stub via the thisx of the shared session. 
+     */
+    xxxx_either_stub* stubobj = NULL;   
+    if (!ids->session || !ids->is_session_owned) return -1;
+    
+    stubobj = ids->session->thisx;  /* stub is the session interface's thisx */
+    if (is_etch_stub(stubobj)) 
+        ((etch_object*)stubobj)->destroy(stubobj);
+    else  /* is there a use case for this */
+    {   assert(is_etch_sessionmsg(ids->session));  
+        etch_object_destroy(ids->session);
+    }
+
+    ids->session = NULL;  
+    return 0;
+}
+
+
+/**
+ * destroy_delivery_service_interface()
+ * i_delivery_service destructor 1.
+ */
+int destroy_delivery_service_interface(void* data)
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    if (NULL == ids) return -1;
+
+    if (!is_etchobj_static_content(ids))
+    {   
+        /* stub owns the ism, ds owns the stub: destroy stub and session */
+        destroy_delivery_service_stub(ids);  
+
+        /* stub does not own the itm: itm is that of the mailbox manager */
+        if (ids->itm && ids->is_transport_owned) {   
+            etch_object_destroy(ids->itm);
+            ids->itm = NULL;
+        }
+    }
+            
+    return destroy_objectex((etch_object*)ids);
+}
+
+
+/*
+ * destroy_delivery_service_via_interface()
+ * i_delivery_service destructor 2.
+ * this destructor will destroy the parent delivery service implementation, whose
+ * destructor will in turn destroy this interface object. this permits the object 
+ * creating the delivery service to hold a reference to the interface only, and to
+ * destroy the implementation and interface by invoking the interface's destructor.
+ */
+int destroy_delivery_service_via_interface(void* data)
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    etch_object* deliveryservice_implobj = ids? ids->thisx: NULL;
+
+    if (deliveryservice_implobj) /* etch_tcp_delivery_service, e.g. */
+        deliveryservice_implobj->destroy (deliveryservice_implobj);
+
+    return 0;
+}
+ 
+
+/**
+ * destroy_tcp_delivery_service()
+ * etch_tcp_delivery_service destructor
+ */
+int destroy_tcp_delivery_service (void* data)
+{
+  etch_tcp_delivery_service* thisx = (etch_tcp_delivery_service*)data;
+    const char* thistext = "delsvc dtor";
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx))
+    {         
+        /* ensure any threads referencing mailboxes (see mailbox.message())
+         * have run to completion before we start tearing it down. */                 
+        etchmbox_get_readlockex (thisx->rwlock, thistext);
+        etchmbox_release_readlockex (thisx->rwlock, thistext);
+
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "destroying packetizer ...\n");
+
+        etch_object_destroy(((etch_packetizer*)thisx->packetizer));
+        thisx->packetizer = NULL;
+
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "destroying messagizer ...\n");
+
+        etch_object_destroy(((etch_messagizer*)thisx->messagizer));
+        thisx->messagizer = NULL;
+
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "destroying mailbox manager ...\n");
+    
+        etch_object_destroy(((etch_mailbox_manager*)thisx->mailboxmgr));
+        thisx->mailboxmgr = NULL;
+
+        /* on server side, listen thread destroys tcpconx on exit. 
+         * on client side, tcpconx is destroyed here. */
+        if (thisx->is_tcpconx_owned){
+
+            etch_object_destroy(thisx->tcpconx);
+            thisx->tcpconx = NULL;
+        }
+
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "destroying delivery interface ...\n");
+        destroy_delivery_service_interface(thisx->ids);
+
+        etch_object_destroy(thisx->sessionmsg);
+        thisx->sessionmsg = NULL;
+
+        etch_object_destroy(thisx->transportmsg);
+        thisx->transportmsg = NULL;
+
+    }
+    return destroy_objectex((etch_object*)thisx);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * i_deliveryservice (i_sessionmessage, i_transportmessage)
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * get_etch_ds_impl()
+ * convenience method to verify i_delivery_service, and from it, 
+ * get, verify, and return the delivery service implementation object.
+ */
+etch_tcp_delivery_service* get_etch_ds_impl (i_delivery_service* ids) 
+{
+    etch_tcp_delivery_service* tcpds = NULL;
+    ETCH_ASSERT(is_etch_ideliverysvc(ids));
+    tcpds = ids->thisx;
+    ETCH_ASSERT(is_etch_deliverysvc(tcpds));
+    return tcpds;
+}
+
+
+ /**
+ * tcpdelsvc_begincall()
+ * i_deliveryservice :: begincall
+ * @param msg caller relinquishes on success, retains on failure
+ * @param out mailbox interface returned on success
+ * @return 0 success, or -1 failure. new mailbox return in out parameter.
+ */
+int tcpdelsvc_begincall (i_delivery_service* ids, etch_message* msg, i_mailbox** out)
+{
+    int result = 0;
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+    i_transportmessage* dstransport  = tcpds->transport;
+    ETCH_ASSERT(is_etch_transportmsg(dstransport));
+
+    /* transport is mailbox mgr pmboxmgr_transport_call(imbmgr) */
+    result = tcpds->transportx->transport_call (tcpds->transportx, NULL, msg, out);
+
+    return result;
+}
+
+
+/**
+ * tcpdelsvc_endcall() 
+ * read the response message, close its mailbox and return the result object.
+ * @param mbox the current mailbox (interface), caller retains.
+ * @param response_type type of the response message, caller retains.
+ * @param out pointer to caller's location to receive the message response object.
+ * @remarks if some exception condition occurred, the result object will not be an
+ * object of the expected result type, but rather will be an etch_mailbox_element
+ * object containing an exception. therefore, the result object should be tested
+ * with is_exception(resultobj) prior to expecting it to be of the expected type. 
+ * @return 0 success, -1 failure. a result object is returned via out parameter.
+ * the result object is the expected object type of the service function result,
+ * or if a response could not be read, the etch_mailbox_element object wrapping
+ * both the reply message object, and an exception object detailing the problem. 
+ * for example, if the service message is etch_int32* add(etch_int32*, etch_int32*),
+ * the result object will be an etch_int32 unless an exception occurred. 
+ */
+int tcpdelsvc_endcall (i_delivery_service* ids, i_mailbox* ibox, etch_type* response_type, etch_object** out)
+{
+    int result  = 0;
+    int timeout = 0;
+    etch_config_t*  config          = NULL;
+    int32           default_timeout = 0;
+    etch_object* result_obj = NULL;
+    etch_mailbox_element* mbe = NULL;
+    const char* thistext = "tcpdelsvc_endcall";
+    /* get the response message type's instance data */
+    etch_type_impl* typeinfo = response_type? (etch_type_impl*) response_type->impl: NULL;
+    ETCH_ASSERT(typeinfo && out);
+
+    etch_runtime_get_config(&config);
+    ETCH_ASSERT(config);
+
+    /* we do not default to wait forever in order that we can fail gracefully rather
+     * than hang the mailbox read. this behavior is essential for comprehensive testing. 
+     * if a type specifies a timeout of zero, we do not interpret this as ETCH_INFWAIT, 
+     * but rather we substitute a default timeout, which is configurable. 
+     * if a message type actually requires an abnormally lengthy wait, it will specify  
+     * some presumably large number of milliseconds as its timeout value. similarly,
+     * if we actually want to wait "forever" by default, we can configure a very large 
+     * timeout value which is effectively "forever".
+     */
+    etch_config_get_property_int(config, "etch.mailbox.timeout.read", &default_timeout);
+    //TODO: no timeout value
+    timeout = typeinfo->timeout > 0 ? typeinfo->timeout : default_timeout;
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "reading mailbox (wait %d) ...\n", timeout);
+
+    /* read reply message from mailbox, waiting for message to arrive if necessary */
+    result = ibox->read_withwait(ibox, timeout, &mbe);
+
+    if(mbe == NULL) {
+      result = 0;
+      *out = (etch_object*) new_etch_exception_from_errorcode(ETCH_ERROR);
+    }
+    /* mailbox read timed out or otherwise failed */
+    else if (is_etch_exception(mbe)) 
+    {   /* here we are returning an object of a type not expected by the service.
+         * this method's contract will specify that the app must test the returned
+         * object for an exception prior to "casting" it to the expected result 
+         * object type. another possibility is that we could have default  
+         * constructors for each response type.  
+         */
+        *out = (etch_object*) mbe;
+    }
+    /* find the result object expected in the reply message */  
+    else if (NULL == (result_obj = message_get (mbe->msg, typeinfo->response_field)))
+    {   
+        etch_object_destroy(mbe);
+        *out = NULL;
+        result = 0;
+    }
+    else 
+    {  /* we found the reply message result object. return this result object, 
+        * and destroy the message wrapper and the reply message along with it. 
+        * note that we must be careful destroying the message, since the message
+        * result object, that we intend to return to the application, is part of 
+        * the message and thus destroyed with the message unless steps are taken 
+        * to protect it. we could clone the result and return the clone, but
+        * that would presuppose that the object is cloneable, so instead we will 
+        * protect the object, destroy the message, and finally unprotect the object.
+        */
+       set_etchobj_static_all(result_obj);   /* protect result object */
+       etch_object_destroy(mbe);                    /* destroy message and wrapper */
+       clear_etchobj_static_all(result_obj); /* unprotect result object */
+       *out = result_obj;                    /* return result object */
+       // ETCH_LOG(LOG_CATEGORY, ETCH_LOG_XDEBUG, "mailbox result object type %d class %d\n", 
+       //          ((etch_object*)result_obj)->obj_type, ((etch_object*)result_obj)->class_id);
+       result = 0;
+    }
+
+    /* acquire mailbox read write lock to switch context back to the receive thread,
+     * which will continue at the return from the queue.put in mailbox.message().
+     * we have passed in a dedicated mutex in start_xxxx_client, intended to be used
+     * by client main thread and receive thread as a read/write lock. there should
+     * be a cleaner way to sync mailbox reads and writes from within the mailbox
+     * itself, we need to investigate. ideally we would sync all of mailbox.message()
+     * using its queue waiter's mutex; however at present all such waiter mutexes are
+     * non-recursive, and so we would need to do extensive re-testing if we were to
+     * change waiter mutexes to be nestable, assuming they would work at all that way.
+     * we should make this change asap however, since the way it is now, we don't wait
+     * for the mailbox write to do its fire_notify() before we read the mailbox.
+     * however the following lock at least ensures the fire_notify() happens prior to  
+     * closing the mailbox, which is the overriding consideration.
+     */
+    etchmbox_get_readlock (ibox->thisx, thistext);
+    etchmbox_release_readlock (ibox->thisx, thistext);
+
+    /* we're now done with the the mailbox so close it. */
+    ibox->close_read (ibox);  
+    return result;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - 
+ * i_deliveryservice :: i_sessionmessage (i_session)
+ * - - - - - - - - - - - - - - - - - - - - - - - - - 
+ */
+
+/* this is the delivery service interface implementation of i_sessionmessage,
+ * distinct from the transport.session's implementation of i_sessionmessage
+ * which is implemented externally and set via set_session().
+ */
+
+/**
+ * tcpdelsvc_session_message()
+ * @param whofrom caller retains, can be null.
+ * @param msg caller relinquishes
+ * @return 0 (message handled), or -1 (error, closed, or timeout)  
+ */
+int tcpdelsvc_session_message (void* data, etch_who* whofrom, etch_message* msg)
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+    i_sessionmessage* dssession = tcpds->session;
+    ETCH_ASSERT(is_etch_sessionmsg(dssession));
+
+    return dssession->session_message(dssession->thisx, whofrom, msg);
+}
+
+
+/**
+ * tcpdelsvc_session_control()
+ * delivery service interface implementation of i_session_message  
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+int tcpdelsvc_session_control (void* data, etch_event* control, etch_object* value)
+{
+  i_delivery_service* ids = (i_delivery_service*)data;
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+    i_sessionmessage* dssession = tcpds->session;
+    ETCH_ASSERT(is_etch_sessionmsg(dssession));
+
+    return dssession->session_control(dssession->thisx, control, value);
+}
+
+
+/**
+ * etch_tcpdelsvc_session_notify()
+ * @param evt event, caller relinquishes.
+ */
+int tcpdelsvc_session_notify (void* data, etch_event* evt)
+{
+  i_delivery_service* ids = (i_delivery_service*)data;
+    int result = -1, evtype = evt? evt->value: 0;
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+    i_sessionmessage* dssession = tcpds->session;
+    ETCH_ASSERT(is_etch_sessionmsg(dssession));
+
+    switch(evtype)
+    {
+        case ETCHEVT_SESSION_UP:
+            etch_wait_set(tcpds->wait_up, evtype);
+            break;
+        case ETCHEVT_SESSION_DOWN:
+            etch_wait_set(tcpds->wait_down, evtype);
+            break;
+    }
+
+    result = dssession->session_notify (dssession->thisx, evt);
+    return result;
+}
+
+/**
+ * etch_tcpdelsvc_session_query()
+ * @param query, caller relinquishes.
+ */
+etch_object* tcpdelsvc_session_query (void* data, etch_query* query) 
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+    i_sessionmessage* dssession = tcpds->session;
+    ETCH_ASSERT(is_etch_sessionmsg(dssession));
+
+    return dssession->session_query (dssession->thisx, query);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * i_deliveryservice :: i_transportmessage (i_transport)
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+
+/**
+ * tcpdelsvc_get_session()
+ * @return a reference to the delivery service i_sessionmessage interface.
+ * caller does not own this object.
+ */
+i_session* tcpdelsvc_get_session (void* data) 
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+
+    return (i_session*)tcpds->session;
+}
+
+
+
+
+/**
+ * tcpdelsvc_transport_control()
+ * @param control, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ * @remarks as it currently stands, the value object passed through these transport
+ * interfaces must be a cloneable object, either through being cloneable by default,
+ * such as the etch_primitive or etch_object derivatives (for example, etch_int32, 
+ * etch_string, etch_date, etch_event, etch_object, and others); or by virtue of
+ * having custom clone() functions assigned to them.
+ */
+int tcpdelsvc_transport_control (void* data, etch_event* control, etch_object* valobj)
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    int  result = 0;    
+    etch_connection* cx = NULL;
+    i_transportmessage* dstransport = NULL;
+    etch_tcp_delivery_service* tcpds = NULL;
+    const int objclass  = control? ((etch_object*)control)->class_id: 0;
+    const int timeoutms = control && (is_etch_int32(valobj))? ((etch_int32*)control)->value: 0;
+    ETCH_ASSERT(is_etch_ideliverysvc(ids) && objclass);
+
+    tcpds = get_etch_ds_impl(ids);  /* delivery service implementation */
+    ETCH_ASSERT(is_etch_deliverysvc(tcpds));
+    dstransport = tcpds->transport; /* delivery service transport (mailbox mgr) */
+    ETCH_ASSERT(is_etch_transportmsg(dstransport));
+    cx = &tcpds->tcpconx->cx;       /* underlying connection */
+
+    switch(objclass)  /* forward the transport event */
+    {           
+       case CLASSID_CONTROL_START_WAITUP:  
+            /* point to the condition variable on the waiter. the need to do this 
+             * is a semikludge; that is, having to set some state prior to calling
+             * waitup; however we can't have the function call preset the state
+             * because the absence of the state variable means "not waiting", and
+             * is tested for by the wait function. so we need to have a target for
+             * the "up" state before we do the waitup, since the connect will complete
+             * before we get around to asking for the waitup, and it needs to be able
+             * to mark state as up, thus we set that target below. previously the state 
+             * variable cond_var was not set until the wait_up was invoked. in the 
+             * current design the cond_var is nulled out after a wait, in order to 
+             * reset wait state to not waiting, so we need to ensure it is populated 
+             * in advance of any need to set a wait condition to some state, prior to 
+             * actually waiting.  
+             */
+            //etchconx_init_waitstate (cx);  /* see comment above */
+            ((etch_object*)control)->class_id = CLASSID_CONTROL_START; /* modify event to not wait */
+
+            result = dstransport->transport_control (dstransport->thisx, control, valobj);
+
+            if (0 == result)     
+                result = etchconx_wait_up (cx, timeoutms);
+
+            break; 
+
+       case CLASSID_CONTROL_STOP_WAITDOWN: 
+            //etchconx_init_waitstate (cx); /* see comment above */
+            ((etch_object*)control)->class_id = CLASSID_CONTROL_STOP; /* modify event to not wait */ 
+
+            result = dstransport->transport_control (dstransport->thisx, control, valobj);
+
+            if (0 == result)     
+                result = etchconx_wait_down (cx, timeoutms);
+
+            break;
+
+        case CLASSID_CONTROL_START:
+        case CLASSID_CONTROL_STOP:
+        default: /* event not of interest here so pass it on */
+
+            result = dstransport->transport_control (dstransport->thisx, control, valobj);
+    }
+
+    return result;
+}
+
+
+/**
+ * tcpdelsvc_transport_notify()
+ * @param evt, caller relinquishes.
+ */
+int tcpdelsvc_transport_notify (void* data, etch_event* evt)
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+
+    return tcpds->transport->transport_notify( tcpds->transport->thisx, evt);
+}
+
+
+/**
+ * tcpdelsvc_transport_query()
+ * i_transportmessage::transport_query override.
+ * @param query, caller relinquishes.
+ */
+etch_object* tcpdelsvc_transport_query (void* data, etch_query* query) 
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    int result = 0;
+    etch_object* resultobj  = NULL;
+    etch_connection* cx = NULL;
+    const int timeoutms = query? query->value: 0;
+    const int objclass  = query? ((etch_object*)query)->class_id: 0;
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+    i_transportmessage* dstransport  = tcpds->transport;
+    cx = &tcpds->tcpconx->cx;
+
+    switch(objclass)
+    {  
+       case CLASSID_QUERY_WAITUP:   
+            result = etchconx_wait_up(cx, timeoutms);
+            break;
+
+       case CLASSID_QUERY_WAITDOWN:  
+            result = etchconx_wait_down(cx, timeoutms);
+            break;
+
+        default:
+            resultobj = dstransport->transport_query (dstransport->thisx, query);
+            query = NULL; /* argument was relinquished */
+    }
+
+    if (query) 
+        etch_object_destroy(query);
+    return resultobj;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * etch_resources
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/*
+ * etch_transport_resources_init()
+ * @return transport resources map initialized with default items and values
+ */
+etch_resources* etch_transport_resources_init(etch_resources* resxmap) 
+{
+    const int SESSIONPOOL_INITSIZE = 4;
+
+    etch_resources* resources = resxmap? resxmap: new_etch_resources(0);
+
+    /* these threadpools are session thread managers, i.e. they manage 
+     * a pool of stub listener threads on either side. */ 
+    if (NULL == etch_resources_get (resources, ETCH_RESXKEY_POOLTYPE_QUEUED))  
+    {   /* until we implement a queued pool, we use a free pool */
+        etch_threadpool* threadpool 
+            = new_threadpool (ETCH_THREADPOOLTYPE_FREE, SESSIONPOOL_INITSIZE);
+
+        etch_resources_add (resources, (wchar_t*)ETCH_RESXKEY_POOLTYPE_QUEUED, 
+           (etch_object*) threadpool);
+    }
+
+    if (NULL == etch_resources_get (resources, ETCH_RESXKEY_POOLTYPE_FREE)) 
+    {                  
+        etch_threadpool* threadpool 
+            = new_threadpool (ETCH_THREADPOOLTYPE_FREE, SESSIONPOOL_INITSIZE);
+
+        etch_resources_add (resources, (wchar_t*)ETCH_RESXKEY_POOLTYPE_FREE, 
+           (etch_object*)threadpool);
+    }
+
+    if (NULL == etch_resources_get (resources, ETCH_RESXKEY_MSGIZER_FORMAT)) 
+    {                  
+        etch_resources_add (resources, (wchar_t*)ETCH_RESXKEY_MSGIZER_FORMAT, 
+           (etch_object*)new_stringw(ETCH_RESXVAL_XPORTFMT_BINARY));
+    }
+
+    return resources;
+}
+
+
+/*
+ * get_etch_transport_resources()
+ * @return transport resources map initialized with default items and values
+ */
+etch_resources* get_etch_transport_resources(etch_resources* resxmap)
+{
+    etch_resources* outresx = NULL;
+    ETCH_ASSERT(resxmap == NULL || is_etch_hashtable(resxmap));
+
+    outresx = etch_transport_resources_init(resxmap);
+
+    ETCH_ASSERT(outresx);
+    return outresx;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * server/client "factories"
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/*
+ * destroy_etch_clientsession()
+ * destructor for a server's client session's instance data.
+ */
+int destroy_etch_clientsession (void* data)
+{
+    etch_session* thisx = (etch_session*)data;
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx))
+    {              
+        
+        etch_object_destroy(thisx->ds);   
+        etch_object_destroy(thisx->server_stub);
+        etch_object_destroy(thisx->server);
+        etch_object_destroy(thisx->client);
+        /* note that we do not destroy the conximpl (accepted tcp connection) 
+         * here, the receive thread destroys it instead */
+
+        /* remove this entry from active sessions list.
+         * note that thisx.thisx is the serverparams hosting the sessions list */
+        remove_etch_session (thisx->thisx, thisx->session_id);
+    }
+            
+    return destroy_objectex((etch_object*)thisx);
+}
+
+
+/*
+ * new_etch_clientsession()
+ * constructor for session parameter bundle.
+ * this object wraps all of a server's per-session instance data.
+ */
+etch_session* new_etch_clientsession (void* host, etch_connection* cx)
+{
+    etch_session* newobj = (etch_session*) new_object(sizeof(etch_session),
+        ETCHTYPEB_CLIENT_SESSION, CLASSID_CLIENT_SESSION);
+
+    ((etch_object*)newobj)->destroy = destroy_etch_clientsession;
+    newobj->thisx = host;  /* etch_serverparams* */
+    newobj->cx = cx;
+    newobj->session_id = cx->conxid;  /* session key */
+
+    /* carrying the session instance data with the connection is not good design,
+     * however we need it in the receive loop listener threadproc which does not  
+     * see transport.h. when we figure another way to get the session's data 
+     * through to the listener thread, we should remove it from the connection, 
+     * since session data is at a much higher level than connection of course.
+     */
+    cx->session = (etch_object*) newobj;
+
+    return newobj;
+}
+
+
+/*
+ * get_etch_session()
+ * look up session instance data object matching specified session ID.
+ * @return index of entry, or -1 if not found. 
+ * array entry is returned via out parameter if specified.
+ */
+int get_etch_session (etch_server_factory* sf, const int session_id, etch_session** out)
+{
+    int  ndx = 0, retndx = -1;
+    etch_iterator iterator;
+    etch_session  *s = NULL;
+    ETCH_ASSERT(is_etch_factoryparams(sf));
+
+    etch_arraylist_getlock(sf->clientlist);
+	
+	set_iterator(&iterator, sf->clientlist, &sf->clientlist->iterable); 
+    while(iterator.has_next(&iterator))
+    {   if ((NULL != (s = iterator.current_value)) && (s->session_id == session_id))
+        {   if (out) *out = s;
+            retndx = ndx;
+            break;
+        } 
+        ndx++;
+        iterator.next(&iterator);  
+    }
+
+    etch_arraylist_rellock(sf->clientlist);
+
+    return retndx;
+}
+
+
+/*
+ * remove_etch_session()
+ * remove session instance data object matching specified session ID.
+ * does not destroy list item content but rather returns it for caller disposition.
+ * @return the removed object, or NULL if not found.
+ */
+etch_session* remove_etch_session (etch_server_factory* sf, const int session_id)
+{
+    etch_session* foundsession = NULL;
+    int whichndx = 0;
+
+    etch_arraylist_getlock(sf->clientlist);
+    whichndx = get_etch_session (sf, session_id, &foundsession);
+
+    if (whichndx >= 0) {
+        etch_arraylist_remove (sf->clientlist, whichndx, FALSE);
+    }
+    etch_arraylist_rellock(sf->clientlist);
+
+    return foundsession;
+}
+
+
+/*
+ * destroy_etch_client_factory()
+ * client params destructor. 
+ * destroys the ancillary objects attached to a remote server.
+ */
+int destroy_etch_client_factory (void* data)
+{
+  etch_client_factory* thisx = (etch_client_factory*)data;
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx))
+    {                     
+        if (thisx->iclient)                           /* destroy i_xxxx_client */
+        {
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "destroying client interface ...\n");
+
+            if(((etch_object*)thisx->iclient))
+                ((etch_object*)thisx->iclient)->destroy(((etch_object*)thisx->iclient));
+            thisx->iclient = NULL;
+        }
+
+        if (thisx->stub)                              /* destroy xxxx_client_stub */
+        {   
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "destroying stub ...\n");
+            if(((etch_object*)thisx->stub))
+                ((etch_object*)thisx->stub)->destroy(((etch_object*)thisx->stub));
+            thisx->stub = NULL;
+        } 
+
+        /* destroy i_delivery_service */
+        if (thisx->dsvc)
+        {
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "destroying delivery service ...\n");
+            if(thisx->dsvc)
+                etch_object_destroy(thisx->dsvc);
+            thisx->dsvc = NULL;
+
+        }
+
+        /* destroy etch_resources */
+        if (thisx->in_resx)
+        {   
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "destroying resources ...\n");
+            etch_object_destroy(thisx->in_resx);
+            thisx->in_resx = NULL;
+        }
+
+	    etch_object_destroy(thisx->mainpool);
+	    thisx->mainpool = NULL;
+
+        etch_mutex_destroy(thisx->rwlock);
+        thisx->rwlock = NULL;
+
+    }
+         
+    return destroy_objectex(((etch_object*)thisx)); 
+}
+
+
+/*
+ * new_client_factory()
+ * constructor for client parameter bundle.
+ */
+etch_client_factory* new_client_factory (etch_object* session, i_session* isession, main_client_create_func main_client_create) 
+{
+    etch_status_t status = ETCH_SUCCESS;
+    const int MAINPOOL_INITIAL_SIZE = 4;
+
+    etch_client_factory* cf = (etch_client_factory*) new_object 
+        (sizeof(etch_client_factory), ETCHTYPEB_FACTORYPARAMS, CLASSID_CLIENTFACTORY);
+
+    ((etch_object*)cf)->destroy    = destroy_etch_client_factory;
+
+    cf->new_client = main_client_create;
+
+    cf->mainpool   = new_threadpool (ETCH_THREADPOOLTYPE_FREE, MAINPOOL_INITIAL_SIZE);
+
+    // TODO: pool
+    status = etch_mutex_create(&cf->rwlock, ETCH_MUTEX_UNNESTED, NULL);
+    ETCH_ASSERT(status == ETCH_SUCCESS);
+
+    return cf;
+}
+
+
+/*
+ * destroy_etch_server_factory()
+ * server params destructor. 
+ */
+int destroy_etch_server_factory (void* data)
+{
+    etch_server_factory* thisx = (etch_server_factory*)data;
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx))
+    {                          
+      etch_object_destroy(thisx->clientlist);
+      thisx->clientlist = NULL;
+
+      etch_object_destroy(thisx->mainpool);
+      thisx->mainpool = NULL;
+
+      etch_object_destroy(thisx->subpool);
+      thisx->subpool = NULL;
+
+    etch_mutex_destroy(thisx->mblock);
+    thisx->mblock = NULL;
+
+    }
+            
+    return destroy_objectex((etch_object*)thisx);
+}
+
+
+/*
+ * new_server_factory()
+ * constructor for server parameter bundle.
+ * fyi invoked from this.new_etch_listener()
+ */
+etch_server_factory* new_server_factory (etch_object* session, i_session* isession,
+    helper_listener_create_func helper_listener_create, main_server_create_func main_server_create)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    const int MAINPOOL_INITIAL_SIZE = 4, SUBPOOL_INITIAL_SIZE = 4;
+
+    etch_server_factory* sf = (etch_server_factory*) new_object(sizeof(etch_server_factory), ETCHTYPEB_FACTORYPARAMS, CLASSID_SERVERFACTORY);
+    
+    ((etch_object*)sf)->destroy = destroy_etch_server_factory;
+
+    sf->clientlist = new_etch_arraylist_synchronized(ETCH_DEFSIZE, ETCH_DEFSIZE);
+    sf->clientlist->content_type = ETCHARRAYLIST_CONTENT_SIMPLE;
+    sf->clientlist->is_readonly = TRUE; /* array does not own its content */
+
+    sf->helper_new_listener = helper_listener_create;
+    sf->main_new_server     = main_server_create;
+    sf->session  = session;
+    sf->isession = isession;
+
+    sf->mainpool = new_threadpool (ETCH_THREADPOOLTYPE_FREE, MAINPOOL_INITIAL_SIZE);
+    sf->subpool  = new_threadpool (ETCH_THREADPOOLTYPE_FREE, SUBPOOL_INITIAL_SIZE);  
+
+    // TODO: pool
+    status = etch_mutex_create(&sf->mblock, ETCH_MUTEX_UNNESTED, NULL);
+    ETCH_ASSERT(status == ETCH_SUCCESS);
+
+    return sf;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * transport listener
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+
+/*
+ * tcpxfact_get_session()
+ * return session interface from the server factory bundle.
+ * validate and assert the i_sessionlistener object.
+ */
+i_session* tcpxfact_get_session (i_sessionlistener* lxr)
+{
+   i_session* session = NULL;
+   etch_server_factory* factory = NULL;
+   ETCH_ASSERT(is_etch_sessionlxr(lxr));
+   factory = lxr->server_params;
+   session = factory? factory->isession: NULL;
+   return session;
+}
+
+
+/*
+ * tcpxfact_session_control()
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+int tcpxfact_session_control (void* data, etch_event* control, etch_object* value)
+{           
+    i_sessionlistener* thisx = (i_sessionlistener*)data;
+    int result = -1;
+    i_session* session = tcpxfact_get_session (thisx);
+
+    if (session && session->session_control)  
+        result = session->session_control (session, control, value);
+    else 
+    {   
+        etch_object_destroy(control);
+        etch_object_destroy(value);
+    }
+
+    return result;
+}
+
+
+/*
+ * tcpxfact_session_notify()
+ * @param evt event, caller relinquishes.
+ */
+int tcpxfact_session_notify (void* data, etch_event* evt)
+{
+    i_sessionlistener* thisx = (i_sessionlistener*)data;
+    int result = -1;
+    i_session* session = tcpxfact_get_session (thisx);
+
+    if (session && session->session_notify)  
+        result = session->session_notify (session, evt);
+    else 
+        etch_object_destroy(evt);
+
+    return result;
+}
+
+
+/*
+ * tcpxfact_session_query()
+ * @param query caller relinquishes
+ */
+etch_object* tcpxfact_session_query (void* data, etch_query* query)
+{
+    i_sessionlistener* thisx = (i_sessionlistener*)data;
+    void* resultobj = NULL;
+    i_session* session = tcpxfact_get_session (thisx);
+
+    if (session && session->session_query)  
+        resultobj = session->session_query (session, query);
+    else 
+        etch_object_destroy(query);
+
+    return resultobj;
+}
+
+
+/*
+ * transport_thread_id()
+ * return thread_id for thread zero on the main pool of this listener.
+ */
+int transport_thread_id (i_sessionlistener* listener)
+{
+    etch_server_factory* sf = NULL; etch_thread* thread0 = NULL;
+    ETCH_ASSERT(listener && is_etch_serverparams(listener->server_params));
+    sf = (etch_server_factory*) listener->server_params;
+    ETCH_ASSERT(sf->mainpool);
+    thread0 = threadpool_thread (sf->mainpool, 0);
+    return thread0? thread0->params.etch_thread_id: 0;
+}
+
+
+/*
+ * transport_session_count()
+ * return count of outstanding client sessions for this server.
+ */
+int transport_session_count (i_sessionlistener* listener)
+{
+    etch_server_factory* sf = NULL;
+    if (NULL == listener || NULL == listener->server_params) return 0;
+    sf = listener->server_params;
+    if (NULL == sf || NULL == sf->clientlist) return 0;
+    return sf->clientlist->count;
+}
+
+ 
+/*
+ * tcpxfact_teardown_client_sessions()
+ * signal and wait for each session thread to exit, destroying each 
+ * thread, connection and session. tearing down the session destroys its
+ * delivery service, remote client, and stub. this is intended to be invoked 
+ * only at server shutdown, after the main (accept) thread has exited.
+ */
+int transport_teardown_client_sessions (i_sessionlistener* listener)
+{
+    etch_iterator iterator;
+    etch_session* session = NULL;
+    etch_server_factory* sf = listener->server_params;
+    set_iterator (&iterator, sf->clientlist, &sf->clientlist->iterable);
+
+    while(iterator.has_next(&iterator)) /* for each extant client session ... */
+    {   
+        
+        if (NULL != (session = iterator.current_value))  
+        {   
+            if (is_etch_connection(session->cx))
+            {
+                session->cx->is_started = FALSE;   /* mark connection stopped */
+
+                if (is_etch_thread(session->cx->thread)){   
+                    etch_join (session->cx->thread); /* BLOCK for thread exit */
+                }
+            }
+	        //etch_object_destroy(session->conximpl);
+    	    //session->conximpl = NULL;
+            //etch_object_destroy(session);               /* teardown this session */
+        } 
+
+        iterator.next(&iterator);  
+    }  
+
+    return 0;
+}
+
+
+/*
+ * etch_listener_waitfor_exit()
+ * block until accept listener thread exits.
+ */
+int etch_listener_waitfor_exit (i_sessionlistener* thisx)
+{
+    etch_server_factory* p = thisx->server_params;
+    const int result = threadpool_waitfor_all (p->mainpool, FALSE);
+    return result; 
+}
+
+
+/*
+ * tcpxfact_session_accepted()
+ * override for transport factory session_accepted()
+ * signature is typedef int (*etch_session_accepted) (void* thisx, void* socket);
+ * parallels java TcpTransportFactory.newListener.newSessionListener.sessionAccepted
+ * @param thisx the i_sessionlistener quasi interface
+ * @param socket an open accept raw socket, wrapped by etch_socket. caller relinquishes.
+ * in practice this is an apr socket wrapped by etch_socket.
+ * @return 0 success, -1 failure.
+ */
+int tcpxfact_session_accepted (void* data, void* connectionData)
+{
+    i_sessionlistener* thisx = (i_sessionlistener*)data;
+    etch_tcp_connection* tcpconx = (etch_tcp_connection*)connectionData;
+    int result = 0;
+    void* newstub = NULL;
+    etch_session* newsession = NULL;
+    etch_server_factory* params = NULL;
+    etch_connection* cx = &tcpconx->cx;
+    i_delivery_service* delivery_service = NULL;
+    const int session_id = cx->conxid;
+    ETCH_ASSERT(is_etch_sessionlxr(thisx));
+    ETCH_ASSERT(is_etch_tcpconnection(tcpconx));
+    params = (etch_server_factory*) thisx->server_params;
+    ETCH_ASSERT(params && params->helper_new_listener);
+
+    /* fyi java binding makes a copy of the generic resources here.  
+     * we instead will not use resources for client-specific map entries,
+     * but rather will use the parameter bundle. TODO allocate client-specific
+     * segment of parameter bundle.
+     */
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "creating client session %d ...\n", session_id);
+
+    /* instantiate delivery service */
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "creating delivery service ...\n");
+
+    delivery_service = new_etch_transport_a (thisx->url, thisx->server_params, tcpconx);  
+
+    if (NULL == delivery_service) 
+    {   ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "could not create delivery service\n");
+        return -1;
+    }
+
+    ETCH_ASSERT(delivery_service->itm && delivery_service->itm->transport_control);
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "delivery service created\n");
+
+    newsession = new_etch_clientsession (params, cx);
+    newsession->mainlistener = thisx;  /* session points back to accept listener */
+    newsession->ds = delivery_service;  
+    newsession->conximpl = (etch_object*) tcpconx;
+
+     /* CALL BACK to helper.xxx_helper_listener_create to create this 
+      * client's server side listener, server implementation, and stub.
+      */
+    newstub = params->helper_new_listener(params, newsession);
+    ETCH_ASSERT(is_etch_stub(newstub));
+
+    etch_arraylist_add (params->clientlist, newsession);  
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "client session %d created\n", session_id);
+
+    /* START this client's individual listener. since we have an accepted socket
+     * in hand, it is in effect already started.
+     */
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "starting client session %d ...\n", session_id);
+    result = delivery_service->itm->transport_control (delivery_service, 
+        new_etch_event(CLASSID_CONTROL_START, 0), NULL);
+
+    return result;
+}
+
+/*
+ * destroy_etch_listener()
+ * etch_listener destructor.
+ */
+int destroy_etch_listener (void* data)
+{
+    i_sessionlistener* thisx = (i_sessionlistener*)data;
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx)) {
+        etch_object_destroy(thisx->url);
+        thisx->url = NULL;
+
+        if (thisx->is_session_owned)
+            etch_free(thisx->isession);
+
+        if (thisx->is_transport_owned)
+            etch_free(thisx->itransport);
+
+        if (thisx->is_resources_owned)
+        {
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "destroying resources ...\n");
+            etch_object_destroy(thisx->resources);
+            thisx->resources = NULL;
+        }
+
+        if (thisx->thisx)
+        {   /* watch this spot: the i_sessionlistener and the etch_tcp_server 
+             * have mutual references. we must ensure that if we are to 
+             * destroy the etch_tcp_server via the i_sessionlistener, that the
+             * etch_tcp_server does not also destroy the i_sessionlistener. */
+            etch_tcp_server* srvobj = (etch_tcp_server*) thisx->thisx;
+            ETCH_ASSERT(is_etch_tcpserver(srvobj));
+            etch_object_destroy(srvobj);
+        }
+
+        if (thisx->server_params)  
+        {
+            etch_server_factory* sf = thisx->server_params;
+            ETCH_ASSERT(is_etch_serverparams(sf));
+            etch_object_destroy(sf);
+        }
+    }
+            
+    return destroy_objectex((etch_object*)thisx);
+}
+
+
+/*
+ * new_etch_listener()
+ * constructs a new transport listener used to construct server sessions.
+ * @param uri a uri string, caller relinquishes.
+ * @param resx a resources map, caller relinquishes. currently ALWAYS NULL.
+ * @param helper_new_server_funcptr pointer to the listener ctor in server helper.
+ * @param main_new_server_funcptr pointer to the server impl ctor in main. 
+ * @param get_xxxx_resources_funcptr helper new service resources callback.
+ * @return an i_sessionlistener interface. caller owns it. note that java binding 
+ * returns a transport interface, whereas c binding will instead extract the 
+ * transport interface from i_sessionlistener.itransport.
+ */
+i_sessionlistener* new_etch_listener (wchar_t* uri, etch_resources* resx, 
+    void* factory_thisx,
+    helper_listener_create_func helper_listener_create,
+    main_server_create_func main_server_create,
+    helper_resources_init_func helper_resources_init)
+{
+    etch_tcp_server* tcp_server = NULL;
+    etch_server_factory* params = NULL;
+    etch_url* url = new_url(uri);
+     
+    /* listener assumes the session interface of the server factory creator.
+     * this accomplishes the same thing as the session method implementations 
+     * found in java TcpTransportFactory.newListener().
+     */
+    i_session* isession = new_session_interface (NULL,  
+        tcpxfact_session_control, 
+        tcpxfact_session_notify, 
+        tcpxfact_session_query);
+   
+    /* create the listener interface, specifying the on_session_accepted
+     * callback to be invoked on each successful server accept in order
+     * to create a new server. relinquish isession to listener here. */
+    i_sessionlistener* listener = new_sessionlistener_interface (NULL, 
+        tcpxfact_session_accepted, isession);
+    
+    ((etch_object*)listener)->destroy   = destroy_etch_listener;
+    listener->wait_exit = etch_listener_waitfor_exit;
+    listener->url = url;        /* relinquished */
+
+    /* create server "factory", which is in the c binding a parameter   
+     * bundle which includes callbacks to the new server constructors */
+    params = new_server_factory ((etch_object*) listener, listener->isession, helper_listener_create, main_server_create);
+    params->thisx = factory_thisx;
+
+    /* instantiate generic resources and call back to specific helper for vf */
+    listener->is_resources_owned = TRUE;    
+    listener->resources = get_etch_transport_resources (resx);  /* resx null */
+    params->in_resx = listener->resources;  
+    params->in_uri  = uri;  
+    helper_resources_init(params);
+    listener->server_params = params;
+    /* fyi params delivery service is set later, in svr->on_session_accepted(), 
+       whose implementation is tcpxfact_session_accepted(), in this module */
+
+    /* create the tcp connection and acceptor SVR BREAK 001 */
+    tcp_server = new_tcp_server (url, params->mainpool, params->subpool, resx, listener);
+
+    if (NULL == tcp_server) {   
+        etch_object_destroy(listener);
+        return NULL;
+    }
+
+    /* listener [main] expects that i_sessionlistener.thisx is the server,
+     * e.g. an etch_tcp_server* */
+    listener->thisx = tcp_server; 
+    
+    /* copy server object's session virtuals to this object */
+    /* see java TcpTransportFactory.newListener() for session impls */
+    listener->session  = tcp_server->session;
+    listener->isession = tcp_server->isession;
+    listener->session_control = tcp_server->session_control;
+    listener->session_notify  = tcp_server->session_notify;
+    listener->session_query   = tcp_server->session_query;
+
+    /* set this listener object's transport to be the server connection's transport */
+    ETCH_ASSERT(tcp_server->itransport);
+    etch_free(listener->itransport);  /* TODO don't instantiate in the first place */
+    listener->itransport = tcp_server->itransport;
+    listener->transport_control = tcp_server->transport_control;
+    listener->transport_notify  = tcp_server->transport_notify;
+    listener->transport_query   = tcp_server->transport_query;
+    listener->set_session = tcp_server->set_session;
+    listener->get_session = tcp_server->get_session;
+    listener->is_transport_owned = FALSE;
+ 
+    return listener;  /* caller owns this object */  
+}
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_transport_data.c b/binding-c/runtime/c/src/main/transport/etch_transport_data.c
new file mode 100644
index 0000000..94c3a7f
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_transport_data.c
@@ -0,0 +1,86 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_transportdata.c
+ * i_transportdata interface
+ */
+
+#include "etch_transport_data.h"
+#include "etch_message.h"
+#include "etch_log.h"
+#include "etch_flexbuffer.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+
+/*
+ * destroy_transportdata()
+ * i_transportdata destructor
+ */
+int destroy_transportdata(void* data)
+{
+    i_transportdata* sm = (i_transportdata*)data;
+    if (NULL == sm) return -1;
+
+    if (!is_etchobj_static_content(sm))
+    {   etch_free(sm->itransport);
+    }
+
+    return destroy_objectex((etch_object*)sm);
+}
+
+/*
+ * etchtransportdata_def_transportdata()
+ * default virtual implementation  
+ * @param whoto caller retains
+ * @param buf caller retains 
+ */
+int etchtransportdata_def_transportdata (void* data, void* who, void* buffer)
+{
+      return -1;
+}
+
+/**
+ * new_transportdata_interface()
+ * i_transportdata constructor
+ * @param func i_transportdata::transport_data function override. 
+ * @param itransport transport interface virtual function overrides, 
+ * caller relinquishes ownership of this memory
+ */
+i_transportdata* new_transportdata_interface(void* thisx, etch_transport_data func, i_transport* itransport)  
+{
+    i_transportdata* newi = (i_transportdata*) new_object
+        (sizeof(i_transportdata), ETCHTYPEB_TRANSPORTDATA, CLASSID_TRANSPORTDATA);
+
+    ((etch_object*)newi)->clone   = clone_null;
+    ((etch_object*)newi)->destroy = destroy_transportdata;  
+
+    newi->transport_data = func? func: etchtransportdata_def_transportdata;
+
+    newi->itransport = itransport? itransport: new_default_transport_interface();
+    newi->transport_control = newi->itransport->transport_control; 
+    newi->transport_notify  = newi->itransport->transport_notify;
+    newi->transport_query   = newi->itransport->transport_query;
+    newi->get_session       = newi->itransport->get_session;
+    newi->set_session       = newi->itransport->set_session;
+
+    newi->thisx = thisx;
+
+    return newi;
+}
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_transport_message.c b/binding-c/runtime/c/src/main/transport/etch_transport_message.c
new file mode 100644
index 0000000..1640f87
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_transport_message.c
@@ -0,0 +1,92 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_transportmsg.c
+ * i_transportmessage interface
+ */
+
+#include "etch_transport_message.h"
+#include "etch_message.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+
+
+/*
+ * etch_msghandler_defmessage()
+ * default virtual implementation 
+ * @param sender cller retains
+ * @param msg  
+ */
+int etchtransportmsg_def_transportmessage (void* data, void* sender, void* msg)
+{
+      return -1;
+}
+
+/*
+ * destroy_transportmessage()
+ * i_transportmessage destructor
+ */
+int destroy_transportmessage(void* data)
+{
+  i_transportmessage* sm = (i_transportmessage*)data;
+    if (NULL == sm) return -1;
+
+    if (!is_etchobj_static_content(sm))
+    {   etch_free(sm->itransport);
+    }
+            
+    return destroy_objectex((etch_object*)sm);
+}
+
+/**
+ * new_transportmsg_interface()
+ * i_transportmessage constructor
+ * @param itransport transport interface virtual function overrides, 
+ * caller relinquishes ownership of this memory
+ * @param itransport transport interface virtual function overrides, 
+ * caller relinquishes ownership of this memory
+ */
+i_transportmessage* new_transportmsg_interface(void* thisx, 
+    etch_transport_message tm, i_transport* itransport)  
+{
+    i_transportmessage* newi = (i_transportmessage*) new_object
+        (sizeof(i_transportmessage), ETCHTYPEB_TRANSPORTMSG, CLASSID_TRANSPORTMSG);
+
+    ((etch_object*)newi)->clone   = clone_null;
+    ((etch_object*)newi)->destroy = destroy_transportmessage;  
+
+    newi->transport_message = tm? tm: etchtransportmsg_def_transportmessage;
+
+    newi->itransport = itransport? itransport: new_default_transport_interface();
+    newi->transport_control = newi->itransport->transport_control; 
+    newi->transport_notify  = newi->itransport->transport_notify;
+    newi->transport_query   = newi->itransport->transport_query;
+    newi->get_session       = newi->itransport->get_session;
+    newi->set_session       = newi->itransport->set_session;
+
+    newi->thisx = thisx;
+
+    return newi;
+}
+
+
+
+
diff --git a/binding-c/runtime/c/src/main/transport/etch_transport_packet.c b/binding-c/runtime/c/src/main/transport/etch_transport_packet.c
new file mode 100644
index 0000000..67bce3f
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_transport_packet.c
@@ -0,0 +1,99 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_transportpkt.c
+ * i_transportpacket interface
+ */
+
+#include "etch_transport_packet.h"
+#include "etch_message.h"
+#include "etch_flexbuffer.h"
+#include "etch_objecttypes.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+/*
+static const char* LOG_CATEGORY = "etch_transportpkg";
+*/
+#define ETCHPACKET_DEFHEADERSIZE 8
+
+int etchtransportpkt_def_transportpacket (void* tp, void* sender, void* buffer)
+{
+      return -1;
+}
+
+/*
+ * etchtransportpkt_def_headersize()
+ * default implementation of get_header_size() 
+ * @return size of packet header in bytes
+ */
+int etchtransportpkt_def_headersize (void* data)
+{
+    i_transportpacket* tp = (i_transportpacket*)data;
+    return tp->header_size;
+}
+
+
+/*
+ * destroy_transportpacket()
+ * i_transportpacket destructor
+ */
+int destroy_transportpacket(void* data)
+{
+    i_transportpacket* itp = (i_transportpacket*)data;
+    ETCH_ASSERT(is_etch_transportpkt(itp));
+
+    if (!is_etchobj_static_content(itp))
+    {   etch_free(itp->itransport);
+    }
+
+    return destroy_objectex((etch_object*) itp);
+}
+
+
+/**
+ * new_transportpkt_interface()
+ * i_transportpacket constructor
+ * @param tp transport_packet virtual function overrides, 
+ * @param itransport transport interface virtual function overrides, 
+ * caller relinquishes ownership of this memory
+ */
+i_transportpacket* new_transportpkt_interface(void* thisx, etch_transport_packet tp, i_transport* itransport)  
+{
+    i_transportpacket* newi = (i_transportpacket*) new_object
+        (sizeof(i_transportpacket), ETCHTYPEB_TRANSPORTPKT, CLASSID_TRANSPORTPKT);
+
+    ((etch_object*)newi)->clone   = clone_null;
+    ((etch_object*)newi)->destroy = destroy_transportpacket;
+    newi->thisx   = thisx;
+    newi->header_size = ETCHPACKET_DEFHEADERSIZE;
+
+    newi->transport_packet = tp? tp: etchtransportpkt_def_transportpacket;
+
+    newi->itransport = itransport? itransport: new_default_transport_interface(thisx);
+
+    newi->transport_control = newi->itransport->transport_control; 
+    newi->transport_notify  = newi->itransport->transport_notify;
+    newi->transport_query   = newi->itransport->transport_query;
+    newi->get_session       = newi->itransport->get_session;
+    newi->set_session       = newi->itransport->set_session;
+
+    newi->get_headersize    = etchtransportpkt_def_headersize;  
+
+    return newi;
+}
diff --git a/binding-c/runtime/c/src/main/transport/etch_url.c b/binding-c/runtime/c/src/main/transport/etch_url.c
new file mode 100644
index 0000000..acd8f75
--- /dev/null
+++ b/binding-c/runtime/c/src/main/transport/etch_url.c
@@ -0,0 +1,649 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * etch_url.c -- URL class, ported from etch java binding
+ * only methods needed for the c binding were ported.
+ */
+#include "etch_url.h"
+#include "etch_exception.h"
+#include "etch_map.h"
+#include "etch_log.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_mem.h"
+#include <wchar.h>
+
+int      etchurl_parse      (etch_url*, wchar_t*);
+int      etchurl_parseterms (etch_url*, wchar_t*);
+int      etchurl_parseparams(etch_url*, wchar_t*);
+void     etchurl_parsehost  (etch_url*, wchar_t*);
+wchar_t* etchurl_unescape   (etch_url*, wchar_t*);
+int      etchurl_is_emptystring(wchar_t*);
+etch_arraylist* new_etchurl_paramlist();
+etch_hashtable* new_etchurl_termmap();
+etch_set* new_etch_term_consolidator_set();
+
+
+/**
+ * destroy_url()
+ * etch_url destructor. 
+ */
+int destroy_url(void* data)
+{
+    etch_url* url = (etch_url*)data;
+    if (!is_etchobj_static_content(url))
+    {   if (url->raw)       etch_free(url->raw);
+        if (url->scheme)    etch_free(url->scheme);
+        if (url->user)      etch_free(url->user);
+        if (url->password)  etch_free(url->password);
+        if (url->fragment)  etch_free(url->fragment);
+        if (url->host)      etch_free(url->host);
+        if (url->uri)       etch_free(url->uri);
+
+        etch_object_destroy(url->params);
+        etch_object_destroy(url->terms);
+    }
+
+    return destroy_objectex((etch_object*)url);
+}
+
+
+/**
+ * new_url()
+ * etch_url constructor. 
+ * @param urlstring the raw url string. caller retains ownership.
+ */
+etch_url* new_url(wchar_t* urlstring) 
+{
+    etch_url* newurl = (etch_url*) new_object(sizeof(etch_url), ETCHTYPEB_URL, CLASSID_URL);
+
+    ((etch_object*)newurl)->destroy = destroy_url;  
+    ((etch_object*)newurl)->clone   = clone_null;   
+
+    newurl->raw = new_wchar(urlstring);
+    etchurl_parse(newurl, urlstring);
+ 
+    return newurl;
+}
+
+
+
+
+/**
+ * etchurl_get_params()
+ * @return an iterator over the URL parameters. caller owns and must destroy the iterator.
+ */
+etch_iterator* etchurl_get_params(etch_url* url)
+{
+    etch_iterator* iterator = url->params?
+        new_iterator(url->params, &url->params->iterable):
+        new_empty_iterator();
+
+    return iterator;
+}
+
+
+/**
+ * etchurl_paramcount()
+ * @return count of parameters present in the URL
+ */
+int etchurl_paramcount(etch_url* url)
+{
+    return url->params? url->params->count: 0;
+}
+
+
+/**
+ * etchurl_termcount()
+ * @return count of terms present in the URL
+ */
+int etchurl_termcount(etch_url* url)
+{
+    return etchmap_count(url->terms);
+}
+
+
+/**
+ * etchurl_parse()
+ * parse out a raw URL
+ */
+int etchurl_parse(etch_url* thisx, wchar_t* rawurl)
+{
+    wchar_t *q = 0, *p = 0, *urlcopy = 0, *ss = 0; 
+    int result = -1;
+    if (NULL == rawurl) return -1;
+    urlcopy = new_wchar(rawurl); p = urlcopy;
+
+    do
+    {   thisx->charcount = wcslen(p);
+        thisx->bytecount = sizeof(wchar_t) * thisx->charcount; /* minus nullterm */
+        if (0 == thisx->bytecount) break;
+   
+        /* scheme:[//[user[:password]@]host[:port]/]uri[;params][?terms][#frag] */
+        ss = wcsstr(p, L"//");
+        q  = wcschr(p, L':');
+
+        if (!ss || !q)   
+            thisx->scheme = new_wchar(ETCH_URL_DEFAULT_SCHEME);
+        else
+        if (q && (ss > q))
+        {  *q++ = L'\0';
+            thisx->scheme = etchurl_unescape(thisx, p); 
+            p = q;  
+        }
+        else break;
+
+        /* s is [//[user[:password]@]host[:port]/]uri[;params][?terms][#frag] */
+        if (NULL != (q = wcschr(p, L'#')))  
+        {  *q++ = L'\0';
+            thisx->fragment = etchurl_unescape(thisx, q); 
+        } 
+
+        /* [//[user[:password]@]host[:port]/]uri[;params][?terms] */
+        if (NULL != (q = wcschr(p, L'?')))  
+        {  *q++ = L'\0';
+            etchurl_parseterms(thisx, q); 
+        } 
+
+        /* [//[user[:password]@]host[:port]/]uri[;params] */
+        if (NULL != (q = wcschr(p, L';')))  
+        {  *q++ = L'\0';
+            etchurl_parseparams(thisx, q); 
+        } 
+
+        /* [//[user[:password]@]host[:port]/]uri */
+        if (p == wcsstr(p, L"//"))  /* begins with "//"? */   
+        {   p++; p++; 
+        }
+
+        /* [user[:password]@]host[:port]/]uri */
+        if (NULL != (q = wcschr(p, L'/'))) /* if slash found ... */
+        {   /* [user[:password]@]host[:port]/uri */                
+           *q++ = L'\0';
+            etchurl_parsehost(thisx, p);   
+            p = q;
+        }
+        else 
+        {   /* [user[:password]@]host[:port] */
+            etchurl_parsehost(thisx, p);   
+            *p = L'\0';  /* p now empty string */      
+        }   
+     
+        thisx->uri = etchurl_unescape(thisx, p);
+  
+        result = 0;
+
+    } while(0);
+
+    etch_free(urlcopy);
+    return result;
+}
+
+
+/**
+ * etchurl_parsepass()
+ */
+void etchurl_parsepass(etch_url* thisx, wchar_t* s)
+{
+    wchar_t *p = s, *q = 0;
+    /* user[:password] */
+
+    if  (NULL != (q = wcschr(p, L':'))) 
+    {    *q++ = L'\0';
+         thisx->password = etchurl_unescape(thisx, q);
+    }
+
+    thisx->user = etchurl_unescape(thisx, p);                
+}
+
+
+/**
+ * etchurl_parseport()
+ */
+void etchurl_parseport(etch_url* thisx, wchar_t* s)
+{
+    wchar_t *p = s, *q = 0, *a = 0;
+    /* host[:port] */
+
+    if  (NULL != (q = wcschr(p, L':'))) 
+    {    *q++ = L'\0';
+         a = etchurl_unescape(thisx, q);
+		 //thisx->port = _wtoi(a);
+#ifdef WIN32
+		thisx->port = _wtoi(a);
+#else
+		//TODO: check this
+		thisx->port = wcstol(a, NULL, 10);
+#endif
+		 
+         etch_free(a);
+    }
+
+    a = etchurl_unescape(thisx, p); 
+    thisx->host = a;   
+}
+
+
+/**
+ * etchurl_parsehost()
+ */
+void etchurl_parsehost(etch_url* thisx, wchar_t* s)
+{
+    wchar_t *p = s, *q = 0;
+
+    /* [user[:password]@]host[:port] */
+    if (NULL != (q = wcschr(p, L'@')))  
+    {  *q++ = L'\0'; 
+        etchurl_parsepass(thisx, p);
+        etchurl_parseport(thisx, q);
+    } 
+    else etchurl_parseport(thisx, p);     
+}
+
+
+/**
+ * etchurl_remove_term()
+ * remove term from term map, destroying term key string and returning term value object.
+ * @param key a raw string representing the key of the pair to be removed from the map.
+ * caller retains ownership of this string.
+ * @return the etch object value of the key/value pair removed from the map, or null.
+ * caller assumes ownership of this object.
+ */
+etch_object* etchurl_remove_term(etch_url* url, wchar_t* key)
+{
+    int result = 0;
+    etch_hashitem bucket, *removeditem = &bucket;
+    const int keylen = (int) wcslen(key) * sizeof(wchar_t);
+    memset(removeditem, 0, sizeof(etch_hashitem));
+
+    result = ((struct i_hashtable*)((etch_object*)url->terms)->vtab)->remove(url->terms->realtable, 
+									     key, keylen, url->terms, (void*)&removeditem);
+                               
+    etch_free(removeditem->key);    
+
+    return removeditem->value;
+}
+
+
+/**
+ * etchurl_add_term()
+ * @param termname a disposable string, caller relinquishes ownership
+ * @param termval  a disposable string, caller relinquishes ownership
+ * @return 0 or -1
+ */
+int etchurl_add_term(etch_url* url, wchar_t* termname, wchar_t* termval)
+{
+    int result = 0;
+    etch_string* newvalobj = new_stringw(termval);
+    etch_object* foundvalobj = etchmap_findxw (url->terms, termname, NULL);
+
+    /* zero is insertxw error return */
+    if (NULL == foundvalobj) {
+        result = etchmap_insertxw(url->terms, termname, newvalobj, FALSE)? 0: -1;
+    }
+    else
+    if(is_etch_set(foundvalobj)) {
+        /* -1 is set_add error return */
+        result = etchmap_set_add((etch_set*)foundvalobj, (etch_object*) newvalobj)? -1: 0;
+    }
+    else {
+        /* consolidate terms for this key */
+        etch_set* thisset = new_etch_term_consolidator_set();  
+        etch_object* removedvalobj = NULL;
+
+        etchmap_set_add (thisset, foundvalobj);
+        etchmap_set_add (thisset, (etch_object*) newvalobj);
+
+        removedvalobj = etchurl_remove_term(url, termname);  
+        ETCH_ASSERT(removedvalobj == foundvalobj); 
+ 
+        /* replace the single term with the new term consolidator set */
+        result = etchmap_insertxw (url->terms, termname, thisset, FALSE)? 0: -1;
+    }
+
+    etch_free(termname);
+    etch_free(termval);
+    return result;
+}
+
+
+/**
+ * etchurl_add_double_term()
+ * todo: remove this if we don't use it
+ */
+int etchurl_add_double_term(etch_url* url, wchar_t* termname, const double termval)
+{
+    wchar_t buf[128], *newstr = NULL;
+    memset(buf, 0, sizeof(buf));
+    etch_snwprintf(buf, 127, L"%f", termval);
+    newstr = new_wchar(buf); /* we relinquish newstr to etchurl_add_term() */
+    return etchurl_add_term(url, termname, newstr);
+}
+
+
+/**
+ * etchurl_add_integer_term()
+ */
+int etchurl_add_integer_term(etch_url* url, wchar_t* termname, const int termval)
+{
+    wchar_t buf[36], *newstr = NULL;
+    memset(buf, 0, sizeof(buf));
+#ifdef WIN32
+    _itow(termval, buf, 10);
+#else
+    etch_snwprintf(buf, sizeof(buf), L"%d", termval);
+	//swprintf(buf, L"%d", termval);
+#endif
+    newstr = new_wchar(buf); /* we relinquish newstr to etchurl_add_term() */
+    return etchurl_add_term(url, termname, newstr);
+}
+
+
+/**
+ * etchurl_add_param()
+ * @param param a disposable string, caller relinquishes 
+ */
+int etchurl_add_param(etch_url* url, wchar_t* param) 
+{
+    if (etchurl_is_emptystring(param)) 
+    {   etch_free(param);
+        return -1;
+    }
+
+    if (NULL == url->params)  /* lazy-allocate param map */
+        url->params = new_etchurl_paramlist(); 
+  
+    return etch_arraylist_add (url->params, new_stringw(param));
+}
+
+
+/**
+ * etchurl_unescape()
+ * @param s a string from which escapes are to be removed. caller retains ownership.
+ * @return a newly-allocated unescaped string for which caller assumes ownership.
+ */
+wchar_t* etchurl_unescape(etch_url* url, wchar_t* s)
+{
+    int n1, n2;
+    wchar_t *p = s, *q = 0, *newstr = 0, c0, c1, c2;
+    const size_t charlen = wcslen(s), bytecount = (charlen + 1) * sizeof(wchar_t);
+
+    newstr = etch_malloc(bytecount, ETCHTYPEB_STRING);
+    memset(newstr, 0, bytecount);
+    q = newstr;
+
+    while(*p)
+    {
+        switch(*p)
+        {   case L'%':  
+                 if (c1 = *++p) break;
+                 if (c2 = *++p) break;
+                 n1 = hexwchar_to_int(c1);
+                 n2 = hexwchar_to_int(c2);
+                 c0 = (n1 << 4) | n2;
+                 *q++ = c0;
+                 break;
+
+            case L'+': *q++ = L' '; break;
+
+            default:   *q++ = *p;
+        }
+        
+        if (*p) ++p;
+    }
+
+    return newstr; /* caller owns */ 
+}
+
+
+/**
+ * etchurl_parseterm()
+ * @param s, a url string. caller retains ownership, however the string is modified herein.
+ * s content is expected as name[=value] 
+ */
+int etchurl_parseterm(etch_url* url, wchar_t* s)
+{
+    wchar_t *p = s, *q = 0, *key = 0, *val = 0; 
+    if (etchurl_is_emptystring(s)) return 0;
+
+    if (NULL == url->terms)  /* lazy-allocate term map */
+        url->terms = new_etchurl_termmap();  
+
+    q = wcschr(p, L'=');
+    if (q) *q = L'\0';
+
+    key = etchurl_unescape(url, p);      /* acquire key memory */
+
+    if(q && !etchurl_is_emptystring(++q)) {
+        val = etchurl_unescape(url, q);  /* acquire val memory */
+        etchurl_add_term(url, key, val); /* relinquish key&val */
+    }
+    else {
+        /* relinquish key */
+        etchurl_add_term(url, key, new_wchar(L""));
+    }
+
+    return 0;  
+}
+
+
+/**
+ * etchurl_parseterms()
+ * @param s a string containing delimited URL terms.
+ * caller retains ownership of this string, however it is modified herein.
+ */
+int etchurl_parseterms(etch_url* url, wchar_t* s)
+{
+    wchar_t *p = s, *q = 0;
+
+    while(1)
+    {   if (NULL == (q = wcschr(p, L'&'))) break;
+        *q = L'\0';
+        etchurl_parseterm(url, p);
+        p = ++q;
+    }
+
+    etchurl_parseterm(url, p); 
+
+    return 0;  
+}
+
+
+/**
+ * etchurl_parseparams()
+ * @param s a string containing delimited URL parameters.
+ * caller retains ownership of this string, however it is modified herein.
+ */
+int etchurl_parseparams(etch_url* url, wchar_t* s)
+{
+    wchar_t *p = s, *q = 0, *a = 0;
+    if (etchurl_is_emptystring(s)) return 0;
+
+    while(1)
+    {   if (NULL == (q = wcschr(p, L';'))) break;
+        *q = L'\0';
+        a = etchurl_unescape(url, p);  /* acquire string a */
+        etchurl_add_param(url, a);  /* relinquish string a */
+        p = ++q;
+    }
+
+    if (!etchurl_is_emptystring(p))  /* clone final substring */
+        etchurl_add_param(url, new_wchar(p));  
+
+    return 0;  
+}
+
+
+/**
+ * etchurl_get_integer_term()
+ * returns integer value of specified query term in out parameter.
+ * @return 0 success, -1 not found or error.
+ */
+int etchurl_get_integer_term(etch_url* url, const wchar_t* termname, int* out)
+{
+    int  result = 0;
+    etch_string* foundobj = (etch_string*) etchurl_get_term(url, termname);
+    if (!foundobj || !is_etch_string(foundobj) || !foundobj->char_count) return -1;
+  
+#ifdef WIN32
+    result = _wtoi(foundobj->v.valw);
+#else
+	result = wcstol(foundobj->v.valw, NULL, 10);
+#endif
+
+    if(out) *out = result;
+     
+    return result;
+}
+
+
+/**
+ * etchurl_get_boolean_term()
+ * this is not yet functional: see etchurl_get_integer_term()
+ */
+boolean etchurl_get_boolean_term(etch_url* url, const wchar_t* termname, boolean* retval)
+{
+    int result = 0;
+    etch_object* foundobj = etchurl_get_term(url, termname);
+     
+    if  (is_etch_boolean(foundobj))
+         if (retval)
+            *retval = ((etch_boolean*) foundobj)->value;
+         else;
+    else result = -1;
+
+    return result;
+}
+
+
+/**
+ * etchurl_get_term()
+ * returns a *reference* to a wrapped URL term. caller does not own it.
+ */
+etch_object* etchurl_get_term(etch_url* url, const wchar_t* termname)
+{
+    etch_object* founditem = NULL;
+
+    if (url->terms)
+        founditem = etchmap_findxw (url->terms, (wchar_t*) termname, NULL);
+
+    return founditem;
+}
+
+
+/**
+ * etchurl_is_emptystring()
+ */
+int etchurl_is_emptystring(wchar_t* s)
+{
+    wchar_t* p = s;
+    size_t charlen = s? wcslen(s): 0;
+    if (0 == charlen) return TRUE;
+    while(*p++) if (*p != L' ') return FALSE;
+    return TRUE;
+}
+
+
+/* 
+ * etchurl_termmap_clear_handler()
+ * clear callback for term map.
+ */
+int etchurl_termmap_clear_handler (void* keyData, void* valueData)
+{
+    wchar_t* key = (wchar_t*)keyData;
+    etch_object* value = (etch_object*)valueData;
+    etch_free(key);  /* free string key */
+    etch_object_destroy(value); /* free etch object value */
+    return TRUE;
+}
+
+
+/* 
+ * etchurl_termset_clear_handler()
+ * clear callback for term consolidation set.
+ * since it is a set, it does not contains values, only keys which are etch objects
+ */
+int etchurl_termset_clear_handler (void* data, void* value)  
+{
+    etch_object* key = (etch_object*)data;
+    ETCH_ASSERT(key);
+    etch_object_destroy(key);  
+    return TRUE;
+}
+
+
+/* 
+ * new_etch_term_consolidator_set()
+ * constructor for a set configured appropriately for use as a term consolidator.
+ * since it is a set, it does not contains values, only keys which are etch objects.
+ * the new set is configured such that these objects are owned by the set 
+ * and will therefore be destroyed with the set.
+ */
+etch_set* new_etch_term_consolidator_set()
+{
+    etch_set* thisset = new_set(ETCH_URL_DEFSUBTERMS);
+    thisset->is_readonly_keys = FALSE;
+    thisset->freehook = etchurl_termset_clear_handler;
+    return thisset;
+}
+
+
+/*
+ * new_etch_urlparamlist()
+ * list of URL parameters. list entries are etch_string objects. the list is 
+ * configured such that these objects are destroyed when the list is cleared.
+ */
+etch_arraylist* new_etchurl_paramlist()
+{
+    etch_arraylist* list = new_etch_arraylist(ETCH_URL_DEFNUMPARMS, 0);
+    list->content_type   = ETCHARRAYLIST_CONTENT_OBJECT; 
+    list->content_obj_type = ETCHTYPEB_PRIMITIVE;
+    list->content_class_id = CLASSID_STRING;
+    list->is_readonly = FALSE;
+    return list;
+}
+
+
+/*
+ * new_etch_urltermmap() 
+ * map of URL term name/value pairs.
+ * map keys are raw strings. map values are etch objects, which will be either
+ * etch_string*, or etch_set*. such a set consolidates objects for a given key.
+ * the map is configured such that content keys and values are destroyed when  
+ * the map is destroyed.
+ */
+etch_hashtable* new_etchurl_termmap()
+{
+    etch_hashtable* terms   = new_hashtable(ETCH_URL_DEFNUMTERMS);
+    terms->content_type     = ETCHHASHTABLE_CONTENT_OBJECT; 
+    terms->content_obj_type = ETCHTYPEB_PRIMITIVE;
+    terms->content_class_id = CLASSID_ANY;
+    terms->is_readonly_keys = terms->is_readonly_values = FALSE;
+    terms->freehook = etchurl_termmap_clear_handler;  /* frees memory on clear */
+    return terms;
+}
+
+
+int is_url_scheme_http (etch_url* url) { return url && url->scheme && 0 == wcscmp(url->scheme, L"http"); }
+int is_url_scheme_tcp  (etch_url* url) { return url && url->scheme && 0 == wcscmp(url->scheme, L"tcp"); }
+int is_url_scheme_udp  (etch_url* url) { return url && url->scheme && 0 == wcscmp(url->scheme, L"udp");  }
+
+
+
+
diff --git a/binding-c/runtime/c/src/test/CUnit-Run.dtd b/binding-c/runtime/c/src/test/CUnit-Run.dtd
new file mode 100644
index 0000000..1e92a0a
--- /dev/null
+++ b/binding-c/runtime/c/src/test/CUnit-Run.dtd
@@ -0,0 +1,35 @@
+<!ELEMENT CUNIT_TEST_RUN_REPORT
+  (CUNIT_HEADER, CUNIT_RESULT_LISTING, CUNIT_RUN_SUMMARY, CUNIT_FOOTER)>
+
+<!ELEMENT CUNIT_HEADER EMPTY>
+
+<!ELEMENT CUNIT_RESULT_LISTING (CUNIT_RUN_SUITE*|CUNIT_RUN_GROUP*)>
+
+<!ELEMENT CUNIT_RUN_SUITE (CUNIT_RUN_SUITE_SUCCESS|CUNIT_RUN_SUITE_FAILURE)>
+  <!ELEMENT CUNIT_RUN_SUITE_SUCCESS (SUITE_NAME,CUNIT_RUN_TEST_RECORD*)>
+  <!ELEMENT CUNIT_RUN_SUITE_FAILURE (SUITE_NAME,FAILURE_REASON)>
+    <!ELEMENT SUITE_NAME (#PCDATA)>
+    <!ELEMENT FAILURE_REASON (#PCDATA)>
+
+<!ELEMENT CUNIT_RUN_GROUP (CUNIT_RUN_GROUP_SUCCESS|CUNIT_RUN_GROUP_FAILURE)>
+  <!ELEMENT CUNIT_RUN_GROUP_SUCCESS (GROUP_NAME,CUNIT_RUN_TEST_RECORD*)>
+  <!ELEMENT CUNIT_RUN_GROUP_FAILURE (GROUP_NAME,FAILURE_REASON)>
+    <!ELEMENT GROUP_NAME (#PCDATA)>
+
+<!ELEMENT CUNIT_RUN_TEST_RECORD (CUNIT_RUN_TEST_SUCCESS|CUNIT_RUN_TEST_FAILURE)>
+  <!ELEMENT CUNIT_RUN_TEST_SUCCESS (TEST_NAME)>
+  <!ELEMENT CUNIT_RUN_TEST_FAILURE (TEST_NAME, FILE_NAME, LINE_NUMBER, CONDITION)>
+    <!ELEMENT TEST_NAME (#PCDATA)>
+    <!ELEMENT FILE_NAME (#PCDATA)>
+    <!ELEMENT LINE_NUMBER (#PCDATA)>
+    <!ELEMENT CONDITION (#PCDATA)>
+
+<!ELEMENT CUNIT_RUN_SUMMARY (CUNIT_RUN_SUMMARY_RECORD*)>
+  <!ELEMENT CUNIT_RUN_SUMMARY_RECORD (TYPE, TOTAL, RUN, SUCCEEDED, FAILED)>
+    <!ELEMENT TYPE (#PCDATA)>
+    <!ELEMENT TOTAL (#PCDATA)>
+    <!ELEMENT RUN (#PCDATA)>
+    <!ELEMENT SUCCEEDED (#PCDATA)>
+    <!ELEMENT FAILED (#PCDATA)>
+
+<!ELEMENT CUNIT_FOOTER (#PCDATA)>
diff --git a/binding-c/runtime/c/src/test/CUnit-Run.xsl b/binding-c/runtime/c/src/test/CUnit-Run.xsl
new file mode 100644
index 0000000..74cb1e0
--- /dev/null
+++ b/binding-c/runtime/c/src/test/CUnit-Run.xsl
@@ -0,0 +1,152 @@
+<?xml version='1.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.
+
+-->
+
+<xsl:stylesheet
+	version="1.0"
+	xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+       
+	<xsl:template match="CUNIT_TEST_RUN_REPORT">
+		<html>
+	 	 	<head>
+	 	 		<title> CUnit - All Test Run Summary Report </title>
+	 	 	</head>
+		 	 	
+	 	 	<body bgcolor="#e0e0f0">
+	 	 		<xsl:apply-templates/>
+	 	 	</body>
+	 	 </html>
+	</xsl:template>
+	 	
+	<xsl:template match="CUNIT_HEADER">
+		<div align="center">
+			<h3> <b> CUnit - A Unit testing framework for C. </b>
+			<br/> <a href="http://cunit.sourceforge.net/"> http://cunit.sourceforge.net/ </a> </h3>
+		</div>	
+	</xsl:template>
+	 	
+	<xsl:template match="CUNIT_RESULT_LISTING">
+		<table cols="4" width="90%" align="center">
+			<tr>
+			<td width="25%"> </td>
+			<td width="25%"> </td>
+			<td width="25%"> </td>
+			<td width="25%"> </td>
+			</tr>
+			<xsl:apply-templates/>
+		</table>	
+	</xsl:template>
+	
+	<xsl:template match="CUNIT_RUN_SUITE">
+		<xsl:apply-templates/>
+	</xsl:template>
+	
+	<xsl:template match="SUITE_NAME">
+	</xsl:template>
+	
+	<xsl:template match="CUNIT_RUN_SUITE_SUCCESS">
+		<tr bgcolor="#f0e0f0">
+			<td colspan="4"> Running Suite <xsl:value-of select="SUITE_NAME"/> </td>
+		</tr>
+		<xsl:apply-templates/>
+	</xsl:template>
+	
+	<xsl:template match="CUNIT_RUN_GROUP">
+		<xsl:apply-templates/>
+	</xsl:template>
+	
+	<xsl:template match="CUNIT_RUN_GROUP_SUCCESS">
+		<tr bgcolor="#f0e0f0">
+			<td colspan="4"> Running Group <xsl:apply-templates/> </td>
+		</tr>
+	</xsl:template>
+	
+	<xsl:template match="CUNIT_RUN_TEST_RECORD">
+		<xsl:apply-templates/>
+	</xsl:template>
+	
+	<xsl:template match="CUNIT_RUN_TEST_SUCCESS">
+		<tr bgcolor="#e0f0d0">
+			<td> </td> <td colspan="2"> Running test <xsl:apply-templates/>... </td> <td bgcolor="#50ff50"> Passed </td>
+		</tr>	
+	</xsl:template>
+	
+	<xsl:template match="CUNIT_RUN_TEST_FAILURE">
+		<tr bgcolor="#e0f0d0">
+			<td> </td> <td colspan="2"> Running test <xsl:value-of select="TEST_NAME"/>... </td> <td bgcolor="#ff5050"> Failed </td>
+		</tr>
+		
+		<tr>
+			<td colspan="4" bgcolor="#ff9090">
+				<table width="100%"> 
+					<tr> <th width="15%"> File Name </th> <td width="50%" bgcolor="#e0eee0"> <xsl:value-of select="FILE_NAME"/> </td> <th width="20%"> Line Number </th> <td width="10%" bgcolor="#e0eee0"> <xsl:value-of select="LINE_NUMBER"/> </td>  </tr>
+					<tr> <th width="15%"> Condition </th> <td colspan="3" width="85%" bgcolor="#e0eee0"> <xsl:value-of select="CONDITION"/> </td> </tr>
+				</table>
+			</td>	
+		</tr>
+	</xsl:template>
+	
+	<xsl:template match="CUNIT_RUN_SUITE_FAILURE">
+		<tr>
+			<td colspan="3" bgcolor="#f0b0f0">Running Suite <xsl:value-of select="SUITE_NAME"/>... </td>
+			<td bgcolor="#ff7070"> <xsl:value-of select="FAILURE_REASON"/> </td>
+		</tr>	
+	</xsl:template>
+	
+	<xsl:template match="CUNIT_RUN_GROUP_FAILURE">
+		<tr>
+			<td colspan="3" bgcolor="#f0b0f0">Running Group <xsl:value-of select="GROUP_NAME"/>... </td>
+			<td bgcolor="#ff7070"> <xsl:value-of select="FAILURE_REASON"/> </td>
+		</tr>	
+	</xsl:template>
+	
+	<xsl:template match="CUNIT_RUN_SUMMARY">
+		<p/>
+		<table width="90%" rows="5" align="center">
+		<tr align="center" bgcolor="skyblue"> <th colspan="5"> Cumulative Summary for Run  </th> </tr>
+		<tr> 
+			<th width="20%" bgcolor="#ffffc0" align="center"> Type </th>
+			<th width="20%" bgcolor="#ffffc0" align="center"> Total </th>
+			<th width="20%" bgcolor="#ffffc0" align="center"> Run </th>
+			<th width="20%" bgcolor="#ffffc0" align="center"> Succeeded </th>
+			<th width="20%" bgcolor="#ffffc0" align="center"> Failed </th>
+		</tr>
+		<xsl:for-each select="CUNIT_RUN_SUMMARY_RECORD">
+			<tr align="center" bgcolor="lightgreen">
+				<td> <xsl:value-of select="TYPE" /> </td>
+				<td> <xsl:value-of select="TOTAL" /> </td>
+				<td> <xsl:value-of select="RUN" /> </td>
+				<td> <xsl:value-of select="SUCCEEDED" /> </td>
+				<td> <xsl:value-of select="FAILED" /> </td>
+			</tr>
+		</xsl:for-each>	
+		</table>
+	</xsl:template>
+	
+	<xsl:template match="CUNIT_FOOTER">
+		<p/>
+		<hr align="center" width="90%" color="red" />
+		<h5 align="center"> 
+	 		<xsl:apply-templates/>
+	 	</h5>
+	</xsl:template>
+ 	
+</xsl:stylesheet>
diff --git a/binding-c/runtime/c/src/test/common/test_arraylist.c b/binding-c/runtime/c/src/test/common/test_arraylist.c
new file mode 100644
index 0000000..8cedfc1
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_arraylist.c
@@ -0,0 +1,681 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_arraylist.c -- test etch_arraylist
+ */
+#include "etch_runtime.h"
+#include "etch_arraylist.h"
+#include "etch_thread.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define OBJSIG 0xbadf00d
+#define NUMITEMS 3
+#define ETCHTYPEA_TESTOBJ 0xff
+#define IS_DEBUG_CONSOLE FALSE
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    return etch_status;
+}
+
+static int clean_suite(void)
+{
+    return etch_runtime_shutdown();
+}
+
+typedef struct TESTOBJ
+{   int id;
+    int signature;
+} TESTOBJ;
+
+
+static TESTOBJ* objfactory(const int id)
+{ 
+   TESTOBJ* obj = etch_malloc(sizeof(TESTOBJ), ETCHTYPEA_TESTOBJ);
+   obj->id = id; obj->signature = OBJSIG;
+   return obj;
+}
+
+
+/**
+ * comparator callback for contains(), indexof(), functions
+ * typedef int (*etch_comparator) (void* myobj, void* otherobj);
+ */
+static int al_comparator(void* p, void* q)
+{   
+    int result = 0;
+    TESTOBJ* myobj = (TESTOBJ*)p, *othobj = (TESTOBJ*)q;
+    if (!myobj || !othobj) result = -2;
+    else if (myobj->signature != OBJSIG || othobj->signature != OBJSIG) result = -2;
+    else if (myobj->id < othobj->id) result = -1;
+    else if (myobj->id > othobj->id) result = 1;
+    else result = 0; /* equality */
+    return result;
+}
+
+
+/* 
+ * test new_arraylist()
+ */
+static void test_new_arraylist(void)
+{
+    const int TESTSIZE = 2048, TESTDELTA = 1024;
+
+    // check default size
+    etch_arraylist* list = new_etch_arraylist(0, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(list);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(list->base);
+    CU_ASSERT_EQUAL(list->count,0);
+    CU_ASSERT_EQUAL(list->size,  ETCHARRAYLIST_DEFSIZE * sizeof(void**));
+    CU_ASSERT_EQUAL(list->delta, ETCHARRAYLIST_DEFSIZE * sizeof(void**));
+
+    //free memory and ensure nothing remains allocated
+    etch_arraylist_destroy(list,TRUE);
+#ifdef ETCH_DEBUGALLOC
+    g_bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+#endif
+
+    // check custome size
+    list = new_etch_arraylist(TESTSIZE, TESTDELTA);
+    CU_ASSERT_EQUAL(list->count,0);
+    CU_ASSERT_EQUAL(list->size,  TESTSIZE  * sizeof(void**));
+    CU_ASSERT_EQUAL(list->delta, TESTDELTA * sizeof(void**));
+    memset(list->base, 0xff, list->size); /* try write to entire buffer */
+
+    // free memory; ensure nothing remains allocated
+    etch_arraylist_destroy(list,TRUE);
+#ifdef ETCH_DEBUGALLOC
+    g_bytes_allocated = etch_showmem(TRUE,FALSE);
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+    // start fresh for next test
+    memtable_clear();
+#endif
+}
+
+
+/* 
+ * test arraylist_add()
+ */
+static void test_add(void)
+{
+   TESTOBJ *x1, *x2;
+   etch_arraylist* list = new_etch_arraylist(8,0); 
+   CU_ASSERT_EQUAL(list->base[0],NULL);
+   CU_ASSERT_EQUAL(list->base[1],NULL);
+
+   etch_arraylist_add(list, x1 = objfactory(1));
+   CU_ASSERT_EQUAL(list->count,1);
+   CU_ASSERT_EQUAL(list->base[0], x1); /* ensure item's buffer slot OK */
+
+   etch_arraylist_add(list, x2 = objfactory(2));
+   CU_ASSERT_EQUAL(list->count,2);
+   CU_ASSERT_EQUAL(list->base[1], x2); /* ensure item's buffer slot OK */
+
+   // free memory including test objects
+   etch_arraylist_destroy(list,TRUE);
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(TRUE,IS_DEBUG_CONSOLE);
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test arraylist_destroy()
+ */
+static void test_destroy(void)
+{
+    CU_PASS("tested in all previous and subsequent tests"); 
+}
+
+/*
+ * test arraylist_count()
+ */
+static void test_count(void)
+{
+    TESTOBJ *x1, *x2;
+    etch_arraylist* list = new_etch_arraylist(8,0); 
+    CU_ASSERT_EQUAL(list->count,0);
+    CU_ASSERT_EQUAL(etch_arraylist_count(list),0);
+
+    etch_arraylist_add(list, x1 = objfactory(1));
+    CU_ASSERT_EQUAL(list->count,1);
+    CU_ASSERT_EQUAL(etch_arraylist_count(list),1);
+
+    etch_arraylist_add(list, x2 = objfactory(2));
+    CU_ASSERT_EQUAL(list->count,2);
+    CU_ASSERT_EQUAL(etch_arraylist_count(list),2);
+
+    // free memory including test objects
+    etch_arraylist_destroy(list,TRUE);
+ #ifdef ETCH_DEBUGALLOC
+    g_bytes_allocated = etch_showmem(TRUE,IS_DEBUG_CONSOLE);
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+    // start fresh for next test
+    memtable_clear();
+ #endif
+}
+
+/* 
+ * test arraylist_remove()
+ */
+static void test_remove_firstitem(void)
+{
+   TESTOBJ *x1, *x2;
+   etch_arraylist* list = new_etch_arraylist(8,0);
+
+   etch_arraylist_add(list, x1 = objfactory(1));   /* allocate and add test obj x1 */
+   etch_arraylist_add(list, x2 = objfactory(2));   /* allocate and add test obj x2 */
+
+   CU_ASSERT_EQUAL_FATAL(list->count,2);
+   CU_ASSERT_EQUAL(list->base[0], x1);
+   CU_ASSERT_EQUAL(list->base[1], x2);
+
+   //remove list[0] and free its x1 memory
+   etch_arraylist_remove(list,0,TRUE);
+
+   CU_ASSERT_EQUAL_FATAL(list->count,1);
+
+   // ensure TESTBOJ bytes were freed
+   // ensure item's buffer slot cleared
+   CU_ASSERT_EQUAL(list->base[1], NULL);
+
+   // ensure item 1 is now item 0
+   CU_ASSERT_EQUAL_FATAL(list->base[0], x2);
+   
+   // remove list[0] but don't free x2 memory
+   etch_arraylist_remove(list,0,FALSE);
+
+   CU_ASSERT_EQUAL(list->count,0); /* ensure no bytes were freed */
+
+    // ensure item's buffer slot cleared
+   CU_ASSERT_EQUAL(list->base[0], NULL);
+
+   /* finally free the last test object, which would have been freed in the
+    * prior arraylist_remove() had we not specified to not do so. Also if we
+    * did not free it here it would be freed in the memtable_clear() below.
+    */
+   etch_free(x2);
+
+   // destroy the arraylist
+   etch_arraylist_destroy(list,TRUE);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+/* 
+ * test arraylist_remove()
+ */
+static void test_remove_lastitem(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   etch_arraylist* list = new_etch_arraylist(8,0); 
+
+   etch_arraylist_add(list, x1 = objfactory(1));   /* allocate and add test obj x1 */
+   etch_arraylist_add(list, x2 = objfactory(2));   /* allocate and add test obj x2 */
+   etch_arraylist_add(list, x3 = objfactory(3));   /* allocate and add test obj x3 */
+   CU_ASSERT_EQUAL_FATAL(list->count,3);
+
+   CU_ASSERT_EQUAL(list->base[2], x3);
+
+   // remove list[2] and free its x3 memory
+   etch_arraylist_remove(list,2,TRUE);
+
+   CU_ASSERT_EQUAL(list->base[2], NULL); /* ensure item's buffer slot cleared */
+
+   CU_ASSERT_EQUAL_FATAL(list->base[0], x1);
+   CU_ASSERT_EQUAL_FATAL(list->base[1], x2);
+   
+   /* destroy the arraylist freeing the test object content as well */
+   etch_arraylist_destroy(list,TRUE); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+/*
+static void dumplist(etch_arraylist* list)
+{
+    int i=0; char c=0;
+    const int n = list->count;
+    printf("\ndumping list ...\n"); fflush(stdout);
+    for(; i < n; i++)
+    {   TESTOBJ* item = list->base[i];
+        printf("\n list[%d] %d\n", i, item->id); fflush(stdout);
+    }
+    
+    printf("\nany key ..."); while(!c) c = getchar(); printf("\n"); 
+}
+*/
+
+/* 
+ * removetest_comparator()
+ * comparator for test_remove() arraylist_indexof
+ * note that the test value is passed as an int not an object
+ */
+static int removetest_comparator(void* testvalue, void* listcontent)
+{
+    const int ivalue  = (int) (size_t) testvalue;
+    TESTOBJ*  listobj = (TESTOBJ*) listcontent;
+    int jvalue = listobj->id;
+    return ivalue < jvalue? -1: ivalue > jvalue? 1: 0;
+} 
+
+
+/* 
+ * test_remove()
+ * remove items 
+ */
+static void test_remove(void)
+{
+    const int numitems = 10;
+    int i=0, curritems = numitems;
+    etch_arraylist* list = new_etch_arraylist(64,0); 
+
+    for(; i < numitems; i++)
+        etch_arraylist_add(list, objfactory(i));
+        
+    #if IS_DEBUG_CONSOLE
+    dumplist(list);
+    #endif
+
+    for(i=2; i < numitems; i+=2)
+    {
+        /* remove the list content whose value is i */
+        const int index = etch_arraylist_indexof(list, (void*)(size_t) i, 0, removetest_comparator);
+        CU_ASSERT_NOT_EQUAL(index, -1);
+
+        if (index >= 0)
+        {
+            if (0 == etch_arraylist_remove(list, index, TRUE))
+                curritems--;
+            
+            #if IS_DEBUG_CONSOLE
+            dumplist(list);
+            #endif
+        }
+        else
+        {
+            #if IS_DEBUG_CONSOLE
+            printf("could not remove list content %d\n", i);
+            #endif
+        }
+
+        CU_ASSERT_EQUAL(list->count, curritems);
+    }
+
+    /* destroy the arraylist freeing the test object content as well */
+    etch_arraylist_destroy(list,TRUE); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test arraylist_insert()
+ */
+static void test_insert_first(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   etch_arraylist* list = new_etch_arraylist(8,0); 
+
+   etch_arraylist_add(list, x2 = objfactory(2));   /* allocate and add test obj x2 */
+   etch_arraylist_add(list, x3 = objfactory(3));   /* allocate and add test obj x3 */
+
+   /* insert test obj x1 into slot 0 */
+   etch_arraylist_insert(list, 0, x1 = objfactory(1)); 
+
+   CU_ASSERT_EQUAL_FATAL(list->count,3);
+   CU_ASSERT_EQUAL(list->base[0], x1);
+   CU_ASSERT_EQUAL(list->base[1], x2);    
+   CU_ASSERT_EQUAL(list->base[2], x3);   
+
+   /* destroy the arraylist freeing the test object content as well */
+   etch_arraylist_destroy(list,TRUE); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test arraylist_insert()
+ */
+static void test_insert_mid(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   etch_arraylist* list = new_etch_arraylist(8,0); 
+
+   etch_arraylist_add(list, x1 = objfactory(1));    
+   etch_arraylist_add(list, x3 = objfactory(3));    
+
+   /* insert test obj x1 into slot 1 */
+   etch_arraylist_insert(list, 1, x2 = objfactory(2)); 
+
+   CU_ASSERT_EQUAL_FATAL(list->count,3);
+   CU_ASSERT_EQUAL(list->base[0], x1);
+   CU_ASSERT_EQUAL(list->base[1], x2);    
+   CU_ASSERT_EQUAL(list->base[2], x3);   
+
+   /* destroy the arraylist freeing the test object content as well */
+   etch_arraylist_destroy(list,TRUE); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test arraylist_insert()
+ */
+static void test_insert_end(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   etch_arraylist* list = new_etch_arraylist(8,0); 
+
+   etch_arraylist_add(list, x1 = objfactory(1));    
+   etch_arraylist_add(list, x2 = objfactory(2));   
+
+   /* insert test obj x1 into slot 1 */
+   etch_arraylist_insert(list, 2, x3 = objfactory(3)); 
+
+   CU_ASSERT_EQUAL_FATAL(list->count,3);
+   CU_ASSERT_EQUAL(list->base[0], x1);
+   CU_ASSERT_EQUAL(list->base[1], x2);    
+   CU_ASSERT_EQUAL(list->base[2], x3);   
+
+   /* destroy the arraylist freeing the test object content as well */
+   etch_arraylist_destroy(list,TRUE); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test arraylist_containsp(), arraylist_contains()
+ */
+static void test_contains(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   int result = 0;
+   etch_arraylist* list = new_etch_arraylist(8,0); 
+
+   etch_arraylist_add(list, x1 = objfactory(1));    
+   etch_arraylist_add(list, x2 = objfactory(2));
+   etch_arraylist_add(list, x3 = objfactory(3)); 
+
+   result = etch_arraylist_containsp(list, x1, 0); 
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = etch_arraylist_containsp(list, x2, 0); 
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = etch_arraylist_containsp(list, x3, 0); 
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = etch_arraylist_containsp(list, x1, 1); /* start at index 1 */ 
+   CU_ASSERT_EQUAL(result, FALSE); 
+
+   result = etch_arraylist_contains(list, x1, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = etch_arraylist_contains(list, x2, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = etch_arraylist_contains(list, x3, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, TRUE); 
+
+   result = etch_arraylist_contains(list, x1, 2, al_comparator); /* start at index 2 */ 
+   CU_ASSERT_EQUAL(result, FALSE); 
+
+   /* destroy the arraylist freeing the test object content as well */
+   etch_arraylist_destroy(list,TRUE); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+/* 
+ * test arraylist_indexofp(), arraylist_indexof()
+ */
+static void test_indexof(void)
+{
+   TESTOBJ *x1, *x2, *x3;
+   int result = 0;
+   etch_arraylist* list = new_etch_arraylist(8,0); 
+   x3 = objfactory(3);
+
+   etch_arraylist_add(list, x1 = objfactory(1));    
+   etch_arraylist_add(list, x2 = objfactory(2));
+
+   result = etch_arraylist_indexofp(list, x1, 0); 
+   CU_ASSERT_EQUAL(result, 0); 
+
+   result = etch_arraylist_indexofp(list, x2, 0); 
+   CU_ASSERT_EQUAL(result, 1); 
+
+   result = etch_arraylist_indexofp(list, x3, 0); 
+   CU_ASSERT_EQUAL(result, -1);  /* not found */
+
+   result = etch_arraylist_indexofp(list, x1, 1); /* start at index 1 */ 
+   CU_ASSERT_EQUAL(result, -1); 
+
+   result = etch_arraylist_indexof(list, x1, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, 0); 
+
+   result = etch_arraylist_indexof(list, x2, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, 1); 
+
+   result = etch_arraylist_indexof(list, x3, 0, al_comparator);
+   CU_ASSERT_EQUAL(result, -1); 
+
+   result = etch_arraylist_indexof(list, x1, 1, al_comparator);   
+   CU_ASSERT_EQUAL(result, -1); 
+
+   etch_free(x3);
+
+   /* destroy the arraylist freeing the test object content as well */
+   etch_arraylist_destroy(list,TRUE); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test arraylist_get()
+ */
+static void test_get(void)
+{
+   TESTOBJ *x1, *x2, *x3, *x;
+   etch_arraylist* list = new_etch_arraylist(8,0); 
+
+   etch_arraylist_add(list, x1 = objfactory(1));    
+   etch_arraylist_add(list, x2 = objfactory(2));
+   etch_arraylist_add(list, x3 = objfactory(3));
+
+   x = etch_arraylist_get(list,0); 
+   CU_ASSERT_EQUAL(x, x1); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->signature, OBJSIG); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->id, 1); 
+
+   x = etch_arraylist_get(list,1); 
+   CU_ASSERT_EQUAL(x, x2); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->signature, OBJSIG); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->id, 2); 
+
+   x = etch_arraylist_get(list,2); 
+   CU_ASSERT_EQUAL(x, x3); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->signature, OBJSIG); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->id, 3); 
+
+   x = etch_arraylist_get(list,3); 
+   CU_ASSERT_EQUAL(x, NULL); 
+
+   /* destroy the arraylist freeing the test object content as well */
+   etch_arraylist_destroy(list,TRUE); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test arraylist_set()
+ */
+static void test_set(void)
+{
+   int result = 0;
+   TESTOBJ *x1, *x2, *x3, *x4, *x5;
+   etch_arraylist* list = new_etch_arraylist(8,0); 
+
+   etch_arraylist_add(list, x1 = objfactory(1));    
+   etch_arraylist_add(list, x2 = objfactory(2));
+   etch_arraylist_add(list, x3 = objfactory(3));
+
+   result = etch_arraylist_set(list, 0, x4 = objfactory(4)); 
+   CU_ASSERT_EQUAL(result,0); 
+   CU_ASSERT_EQUAL(list->base[0], x4); 
+
+   result = etch_arraylist_set(list, 2, x5 = objfactory(5)); 
+   CU_ASSERT_EQUAL(result,0); 
+   CU_ASSERT_EQUAL(list->base[2], x5); 
+
+   result = etch_arraylist_set(list, 3, x5); /* attempt replace beyond end of list */
+   CU_ASSERT_EQUAL(result,-1); 
+
+   /* destroy the arraylist without freeing the test object content */
+   etch_arraylist_destroy(list,FALSE); 
+
+   etch_free(x1); etch_free(x2); etch_free(x3); etch_free(x4); etch_free(x5); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test arraylist auto reallocation
+ */
+static void test_expand(void)
+{
+   const int INIT_MAX = 4;
+   TESTOBJ *x1, *x2, *x3, *x4, *x5, *x6, *x;
+   etch_arraylist* list = new_etch_arraylist(INIT_MAX,0); 
+
+   etch_arraylist_add(list, x1 = objfactory(1));
+   etch_arraylist_add(list, x2 = objfactory(2));
+   etch_arraylist_add(list, x3 = objfactory(3));
+   etch_arraylist_add(list, x4 = objfactory(4));
+   CU_ASSERT_EQUAL(list->size, INIT_MAX * sizeof(void**)); 
+
+   etch_arraylist_add(list, x5 = objfactory(5));
+   CU_ASSERT_EQUAL(list->size, INIT_MAX * sizeof(void**) * 2); 
+   etch_arraylist_add(list, x6 = objfactory(6));
+
+   x = etch_arraylist_get(list,4); 
+   CU_ASSERT_EQUAL(x, x5); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->signature, OBJSIG); 
+   CU_ASSERT_EQUAL(((TESTOBJ*)x)->id, 5); 
+   x = etch_arraylist_get(list,5); 
+   CU_ASSERT_EQUAL(x, x6); 
+
+   /* destroy the arraylist freeing the test object content as well */
+   etch_arraylist_destroy(list,TRUE); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+CU_pSuite test_arraylist_suite()
+{
+    CU_pSuite pSuite = CU_add_suite("suite_arraylist", init_suite, clean_suite);
+    CU_add_test(pSuite, "test new_arraylist()", test_new_arraylist); 
+    CU_add_test(pSuite, "test arraylist_add()", test_add);
+    CU_add_test(pSuite, "test arraylist_destroy()", test_destroy);
+    CU_add_test(pSuite, "test arraylist_count()", test_count);
+    CU_add_test(pSuite, "test arraylist_remove() first", test_remove_firstitem);
+    CU_add_test(pSuite, "test arraylist_remove() last", test_remove_lastitem);
+    CU_add_test(pSuite, "test arraylist_remove() mid", test_remove);
+    CU_add_test(pSuite, "test arraylist_insert() first", test_insert_first);
+    CU_add_test(pSuite, "test arraylist_insert() mid", test_insert_mid); 
+    CU_add_test(pSuite, "test arraylist_insert() end", test_insert_end);
+    CU_add_test(pSuite, "test arraylist_contains(), containsp", test_contains);  
+    CU_add_test(pSuite, "test arraylist_indexof(), indexofp", test_indexof);
+    CU_add_test(pSuite, "test arraylist_get()", test_get); 
+    CU_add_test(pSuite, "test arraylist set", test_set);
+    CU_add_test(pSuite, "test arraylist auto realloc", test_expand);
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_cache.c b/binding-c/runtime/c/src/test/common/test_cache.c
new file mode 100644
index 0000000..c8e64af
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_cache.c
@@ -0,0 +1,271 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_cache.c
+ * test the runtime object cache
+ * we can swap out cache back ends and this test should work the same regardless
+ */
+#include "etch_runtime.h"
+#include "etch_cache.h"
+#include "etch_arraylist.h"
+#include "etch_hash.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+
+#define IS_DEBUG_CONSOLE FALSE
+
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    return etch_runtime_initialize(NULL);
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+
+static int test_cache_freehook_func(void* key, void* value)
+{
+    //etch_free(key);
+    //if(value) {
+    //    etch_free(value);
+    //}
+    return 0;
+}
+
+/**
+ * This subtest instantiates various etch objects which cache some part of 
+ * themselves, and destroys the objects. At each step the test verifies that
+ * the cache contains the expected number of entries, e.g. if I create 
+ * multiple hashtables I should only have cached one hashtable vtable.
+ */
+static void test_multiple_items(void)
+{
+    int cache_start_count = 0, cache_current_count;
+    int result1 = 0, result2 = 0, result3 = 0;
+    etch_hashtable* myhashtab1 = NULL;
+    etch_hashtable* myhashtab2 = NULL;
+    etch_hashtable* myhashtab3 = NULL;
+    etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket;
+
+    wchar_t* wstr1 = L"abracadabra"; 
+    wchar_t* wstr2 = L"gilgamesh";
+    wchar_t* wstr3 = L"antidisestablishmentarianism";
+
+    const size_t numElements1 = wcslen(wstr1);
+    const size_t numElements2 = wcslen(wstr2);
+    const size_t numElements3 = wcslen(wstr3);
+
+    const size_t numBytes1 = sizeof(wchar_t) * numElements1;
+    const size_t numBytes2 = sizeof(wchar_t) * numElements2;
+    const size_t numBytes3 = sizeof(wchar_t) * numElements3;
+
+    size_t actlen1 = 0, actlen2 = 0, actlen3 = 0;
+    wchar_t *key1 = NULL, *key2 = NULL, *key3 = NULL;
+
+    // set freehook for cache
+    etch_cache_set_freehook(test_cache_freehook_func);
+
+    key1 = etch_malloc(numBytes1 + sizeof(wchar_t), 0);
+    key2 = etch_malloc(numBytes2 + sizeof(wchar_t), 0);
+    key3 = etch_malloc(numBytes3 + sizeof(wchar_t), 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key2);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(key3);
+
+    /* create one hashtable first, so in case we are tracking memory, we ensure that 
+     * the hashtable code module paths will already be cached. */
+    myhashtab1 = new_hashtable(16);
+ 
+    cache_start_count = etch_cache_count();
+        
+#if defined(WIN32) && !defined(_WIN32_WCE)
+	result1 = wcscpy_s(key1, numElements1+1, wstr1);  /* wcscpy_s param 2 must be */
+    result2 = wcscpy_s(key2, numElements2+1, wstr2);  /* number of characters + 1 */
+    result3 = wcscpy_s(key3, numElements3+1, wstr3);  
+#elif defined(_WIN32_WCE)
+	wcsncpy(key1, wstr1, numElements1);
+	wcsncpy(key2, wstr2, numElements2);
+	wcsncpy(key3, wstr3, numElements3);
+#else
+    result1 = wcscpy(key1, wstr1);
+    result2 = wcscpy(key2, wstr2);
+    result3 = wcscpy(key3, wstr3);  
+#endif
+    actlen1 = wcslen(key1);
+    actlen2 = wcslen(key2);
+    actlen3 = wcslen(key3);
+
+    myhashtab2 = new_hashtable(16);
+    myhashtab3 = new_hashtable(16);
+
+    /* we should not have cached any more hashtable vtables */
+    cache_current_count = etch_cache_count();
+    CU_ASSERT_EQUAL(cache_current_count, cache_start_count);
+
+    ((struct i_hashtable*)((etch_object*)myhashtab1)->vtab)->insert(myhashtab1->realtable, key1, (int)numBytes1, NULL,0,0,0);
+    ((struct i_hashtable*)((etch_object*)myhashtab2)->vtab)->insert(myhashtab2->realtable, key2, (int)numBytes2, NULL,0,0,0);
+    ((struct i_hashtable*)((etch_object*)myhashtab2)->vtab)->insert(myhashtab3->realtable, key3, (int)numBytes3, NULL,0,0,0);
+
+    /* TODO instantiate some other object here which uses the cache */
+
+    destroy_hashtable(myhashtab1, TRUE, TRUE);
+    destroy_hashtable(myhashtab2, TRUE, TRUE);
+    destroy_hashtable(myhashtab3, TRUE, TRUE);
+    /* note that key1 and key2 are now dangling pointers since we asked the
+     * hashtable to free keys and values memory
+     */
+    etch_free(key1);
+    etch_free(key2);
+    etch_free(key3);
+
+}
+
+
+/**
+ * test_intkeys()
+ * tests caching using integer keys as we might do for etchobjects such as vtables
+ */
+static void test_intkeys(void)
+{
+    int i, startsize, size;
+    const int STARTKEY = 0, ENDKEY = 512, KEYCOUNT = ENDKEY - STARTKEY;
+    char* teststring = "it works!";
+    char* item = etch_malloc(sizeof(teststring),0);
+    memcpy(item, teststring, sizeof(teststring)); 
+
+    // set freehook for cache
+    etch_cache_set_freehook(test_cache_freehook_func);
+
+    startsize = etch_cache_count();
+
+    for(i = STARTKEY; i < ENDKEY; i++)
+        etch_cache_add(i, item);
+
+    size = etch_cache_count();
+    CU_ASSERT_EQUAL(size, KEYCOUNT + startsize);
+
+    for(i = STARTKEY; i < ENDKEY; i++)
+        CU_ASSERT_PTR_NOT_NULL(etch_cache_find(i, 0));
+
+    for(i = STARTKEY; i < ENDKEY; i++)
+        CU_ASSERT_PTR_NOT_NULL(etch_cache_del(i));
+
+    size = etch_cache_count();
+    CU_ASSERT_EQUAL(size, startsize);
+
+    etch_free(item);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,0);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_intkeys()
+ * tests caching using string keys with no values, as we might do for source  
+ * file paths in the debug allocator  
+ */
+static void test_pathkeys(void)
+{
+    char* path1 = "..\\..\\foo\\bar\\file1.dat";
+    char* path2 = "..\\..\\foo\\bar\\file2.dat";
+    char* path3 = "c:\\the\\quick\\brown\\fox\\jumped\\over\\the\\lazy\\dog\\file3.dat";
+    unsigned hash1 = 0, hash2 = 0, hash3 = 0;
+    char* namefound = NULL;
+    etch_hashitem  hashbucket; 
+    etch_hashitem* thisitem = &hashbucket;
+    int result = 0; 
+    int len1 = (int)strlen(path1), len2 = (int)strlen(path2), len3 = (int)strlen(path3);
+ 
+    // set freehook for cache
+    etch_cache_set_freehook(test_cache_freehook_func);
+
+    hash1 = etch_cache_insertx (path1, NULL, FALSE);
+    hash2 = etch_cache_insertx (path2, NULL, FALSE);
+    hash3 = etch_cache_insertx (path3, NULL, FALSE);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    etch_cache_findx(path1, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    CU_ASSERT_EQUAL(hash1, thisitem->hash);
+    result = strncmp(path1, thisitem->key, len1);
+    CU_ASSERT_EQUAL(result,0);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    etch_cache_findx(path2, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    CU_ASSERT_EQUAL(hash2, thisitem->hash);
+    result = strncmp(path2, thisitem->key, len2);
+    CU_ASSERT_EQUAL(result,0);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    etch_cache_findx(path3, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    CU_ASSERT_EQUAL(hash3, thisitem->hash);
+    result = strncmp(path3, thisitem->key, len3);
+    CU_ASSERT_EQUAL(result,0);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    etch_cache_find_by_hash(hash1, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    result = strncmp(path1, thisitem->key, len1);
+    CU_ASSERT_EQUAL(result,0);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    etch_cache_find_by_hash(hash2, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    result = strncmp(path2, thisitem->key, len2);
+    CU_ASSERT_EQUAL(result,0);
+
+    memset(thisitem, 0, sizeof(etch_hashitem));
+    etch_cache_find_by_hash(hash3, &thisitem);
+    CU_ASSERT_PTR_NOT_NULL(thisitem->key);
+    result = strncmp(path3, thisitem->key, len3);
+    CU_ASSERT_EQUAL(result,0);
+}
+
+CU_pSuite test_cache_suite()
+{
+    CU_pSuite pSuite = CU_add_suite("etch_cache", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test path strings as keys", test_pathkeys);
+    CU_add_test(pSuite, "multiple of same object test", test_multiple_items); 
+    CU_add_test(pSuite, "integer cache key test", test_intkeys);
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_etch.c b/binding-c/runtime/c/src/test/common/test_etch.c
new file mode 100644
index 0000000..a0ca12c
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_etch.c
@@ -0,0 +1,76 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_etch.c -- test etch common
+ */
+#include "etch.h"
+
+#include <stdio.h>
+#include <wchar.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    return 0;
+}
+
+//**********************
+// START testcases here
+//**********************
+
+static void test_etch_datatypes(void)
+{
+    CU_ASSERT_EQUAL(sizeof(char), 1);
+    CU_ASSERT_EQUAL(sizeof(byte), 1);
+    CU_ASSERT_EQUAL(sizeof(int8), 1);
+    CU_ASSERT_EQUAL(sizeof(uint8), 1);
+    CU_ASSERT_EQUAL(sizeof(int16), 2);
+    CU_ASSERT_EQUAL(sizeof(uint16), 2);
+    CU_ASSERT_EQUAL(sizeof(int32), 4);
+    CU_ASSERT_EQUAL(sizeof(uint32), 4);
+    CU_ASSERT_EQUAL(sizeof(int64), 8);
+    CU_ASSERT_EQUAL(sizeof(uint64), 8);
+}
+
+//**********************
+// END testcases here
+//**********************
+
+CU_pSuite test_etch_suite()
+{
+    CU_pSuite ps = CU_add_suite("etch_suite", init_suite, clean_suite);  
+    CU_add_test(ps, "test etch_datatypes", test_etch_datatypes);
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_etch_config.c b/binding-c/runtime/c/src/test/common/test_etch_config.c
new file mode 100644
index 0000000..5d1470f
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_etch_config.c
@@ -0,0 +1,247 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_etch_config.c -- test etch config
+ */
+#include <stdio.h>
+#include <wchar.h>
+#include "CUnit.h"
+
+#include "etch_runtime.h"
+#include "etch_config.h"
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    return 0;
+}
+
+//**********************
+// START testcases here
+//**********************
+
+void test_etch_config_create_destroy(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    etch_config_t* config = NULL;
+    
+    etch_status = etch_config_create(&config);
+    CU_ASSERT_PTR_NOT_NULL(config);
+
+    etch_config_destroy(config);
+}
+/*
+static void test_etch_config_open(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    etch_config_t* config = NULL;
+
+    etch_status = etch_config_create(&config);
+    CU_ASSERT_PTR_NOT_NULL(config);
+
+    etch_status = etch_config_open(config, "C:\\etch_config.properties");
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_config_destroy(config);
+}
+*/
+static void test_etch_config_set_property(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    etch_config_t* config = NULL;
+    char* value = NULL;
+
+    etch_status = etch_config_create(&config);
+    CU_ASSERT_PTR_NOT_NULL(config);
+
+    etch_status = etch_config_clear(config);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_config_set_property(NULL, NULL, NULL);
+    CU_ASSERT_EQUAL(etch_status, ETCH_EINVAL);
+
+    etch_status = etch_config_set_property(config, NULL, NULL);
+    CU_ASSERT_EQUAL(etch_status, ETCH_EINVAL);
+
+    etch_status = etch_config_set_property(config, "test.property", NULL);
+    CU_ASSERT_EQUAL(etch_status, ETCH_EINVAL);
+
+    etch_status = etch_config_set_property(config, "test.property", "value");
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_config_set_property(config, "test.property", "new value");
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_config_get_property_string(config, "test.property", &value);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+    CU_ASSERT_EQUAL(strcmp(value, "new value"), 0);
+
+    // check resize
+    etch_status = etch_config_set_property(config, "test.property1", "value");
+    etch_status = etch_config_set_property(config, "test.property2", "value");
+    etch_status = etch_config_set_property(config, "test.property3", "value");
+    etch_status = etch_config_set_property(config, "test.property4", "value");
+    etch_status = etch_config_set_property(config, "test.property5", "value");
+    etch_status = etch_config_set_property(config, "test.property6", "value");
+    etch_status = etch_config_set_property(config, "test.property7", "value");
+    etch_status = etch_config_set_property(config, "test.property8", "value");
+    etch_status = etch_config_set_property(config, "test.property9", "value");
+    etch_status = etch_config_set_property(config, "test.property10", "value");
+    etch_status = etch_config_set_property(config, "test.property11", "value");
+    CU_ASSERT_EQUAL(etch_config_get_length(config), 12);
+    CU_ASSERT_EQUAL(etch_config_get_size(config), 20);
+
+    etch_config_destroy(config);
+}
+
+static void test_etch_config_get_property_string(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    etch_config_t* config = NULL;
+    char* value1 = NULL;
+
+    etch_status = etch_config_create(&config);
+    CU_ASSERT_PTR_NOT_NULL(config);
+
+    etch_status = etch_config_set_property(config, "test.property", "value");
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_config_get_property_string(config, NULL, &value1);
+    CU_ASSERT_EQUAL(etch_status, ETCH_EINVAL);
+
+    etch_status = etch_config_get_property_string(config, NULL, NULL);
+    CU_ASSERT_EQUAL(etch_status, ETCH_EINVAL);
+
+    etch_status = etch_config_get_property_string(config, "test.property", &value1);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+    CU_ASSERT_EQUAL(strcmp(value1, "value"), 0);
+
+    etch_status = etch_config_get_property_string(config, "test.property1", &value1);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+    CU_ASSERT_PTR_NULL(value1);
+
+    etch_config_destroy(config);
+}
+
+static void test_etch_config_get_property_int(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    etch_config_t* config = NULL;
+    int32 value1 = 0;
+
+    etch_status = etch_config_create(&config);
+    CU_ASSERT_PTR_NOT_NULL(config);
+
+    etch_status = etch_config_set_property(config, "test.property", "10");
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_config_set_property(config, "test.property1", "fdg");
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_config_get_property_int(config, NULL, &value1);
+    CU_ASSERT_EQUAL(etch_status, ETCH_EINVAL);
+
+    etch_status = etch_config_get_property_int(config, NULL, NULL);
+    CU_ASSERT_EQUAL(etch_status, ETCH_EINVAL);
+
+    etch_status = etch_config_get_property_int(config, "test.property", &value1);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+    CU_ASSERT_EQUAL(value1, 10);
+
+    etch_status = etch_config_get_property_int(config, "test.property1", &value1);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_config_get_property_int(config, "test.property1", &value1);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_config_destroy(config);
+}
+
+static void test_etch_config_get_property_by_index(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    etch_config_t* config = NULL;
+    char* value1 = NULL;
+
+    etch_status = etch_config_create(&config);
+    CU_ASSERT_PTR_NOT_NULL(config);
+
+    etch_status = etch_config_clear(config);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_config_set_property(config, "test.property", "value");
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_config_get_property_by_index(config, 0, &value1);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+    CU_ASSERT_PTR_NOT_NULL(value1);
+    if(value1 != NULL) {
+        CU_ASSERT_EQUAL(strcmp("value", value1), 0);
+    }
+
+    etch_config_destroy(config);
+}
+
+static void test_etch_config_has_property(void)
+{
+    int result = 0;
+
+    etch_status_t etch_status = ETCH_SUCCESS;
+    etch_config_t* config = NULL;
+
+    etch_status = etch_config_create(&config);
+    CU_ASSERT_PTR_NOT_NULL(config);
+
+    etch_status = etch_config_set_property(config, "test.property", "value");
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    result = etch_config_has_property(config, "test.property");
+    CU_ASSERT_EQUAL(result, 1);
+
+    result = etch_config_has_property(config, "test.property2");
+    CU_ASSERT_EQUAL(result, 0);
+
+    etch_config_destroy(config);
+}
+
+//**********************
+// END testcases here
+//**********************
+
+CU_pSuite test_etch_config_suite()
+{
+    CU_pSuite ps = CU_add_suite("etch_config", init_suite, clean_suite);  
+    CU_add_test(ps, "test etch_config_create_destroy", test_etch_config_create_destroy);
+    //CU_add_test(ps, "test etch_config_open", test_etch_config_open);
+    CU_add_test(ps, "test etch_config_set_property", test_etch_config_set_property);
+    CU_add_test(ps, "test etch_config_get_property_string", test_etch_config_get_property_string);
+    CU_add_test(ps, "test etch_config_get_property_int", test_etch_config_get_property_int);
+    CU_add_test(ps, "test etch_config_get_property_by_index", test_etch_config_get_property_by_index);
+    CU_add_test(ps, "test etch_config_has_property", test_etch_config_has_property);
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_etch_encoding.c b/binding-c/runtime/c/src/test/common/test_etch_encoding.c
new file mode 100644
index 0000000..ee44229
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_etch_encoding.c
@@ -0,0 +1,231 @@
+/* $Id$
+ *
+ * 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.
+ */
+
+/*
+ * test_encoding.c -- test etch encoding
+ */
+#include "etch_runtime.h"
+#include "etch_encoding.h"
+#include "etch_mem.h"
+
+#include "CUnit.h"
+#include <stdio.h>
+#include <wchar.h>
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+/*
+static void test_etch_encoding_unicode_to_utf8(void)
+{
+    int result = 0;
+    char* out = NULL;
+
+    result = etch_encoding_unicode_to_utf8(&out, L"U\u00A9");
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_NOT_NULL(out);
+    if(out != NULL)
+    {
+        CU_ASSERT_EQUAL(out[0], 'U');
+        CU_ASSERT_EQUAL(out[1], (char)0xc2);
+        CU_ASSERT_EQUAL(out[2], (char)0xa9);
+    }
+    if(out != NULL)
+    {
+        etch_free(out);
+        out = NULL;
+    }
+}
+
+static void test_etch_encoding_unicode_to_ansi(void)
+{
+    int result = 0;
+    char* out = NULL;
+
+    result = etch_encoding_unicode_to_ansi(&out, L"UNICODE String");
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_NOT_NULL(out);
+    CU_ASSERT_STRING_EQUAL(out, "UNICODE String");
+    if(out != NULL)
+    {
+        etch_free(out);
+        out = NULL;
+    }
+}
+
+static void test_etch_encoding_utf8_to_unicode(void)
+{
+    int result = 0;
+    char in[] = {'U', 0xc2, 0xa9, 0x00};
+    wchar_t* out = NULL;
+
+    result = etch_encoding_utf8_to_unicode(&out, in);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_NOT_NULL(out);
+    if(out != NULL)
+    {
+        CU_ASSERT_EQUAL(out[0], L'U');
+        CU_ASSERT_EQUAL(out[1], L'\u00A9');
+    }
+    if(out != NULL)
+    {
+        etch_free(out);
+        out = NULL;
+    }
+    if(out != NULL)
+    {
+        etch_free(out);
+        out = NULL;
+    }
+}
+
+static void test_etch_encoding_ansi_to_unicode(void)
+{
+    int result = 0;
+    wchar_t* out = NULL;
+
+    result = etch_encoding_ansi_to_unicode(&out, "UNICODE");
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_NOT_NULL(out);
+    CU_ASSERT_EQUAL(wcscmp(out, L"UNICODE"), 0);
+    if(out != NULL)
+    {
+        etch_free(out);
+        out = NULL;
+    }
+    if(out != NULL)
+    {
+        etch_free(out);
+        out = NULL;
+    }
+}
+
+static void test_etch_encoding_get_unicode_bytecount(void)
+{
+    size_t count1 = 0;
+    size_t count2 = 0;
+    wchar_t* str = L"UNICODE";
+    count1 = (wcslen(str) + 1) * sizeof(wchar_t);
+
+    count2 = etch_encoding_get_unicode_bytecount(str);
+    CU_ASSERT_EQUAL(count1, count2);
+
+}
+*/
+static void test_etch_encoding_transcode_ucs2_utf8(void)
+{
+
+  char* out = 0;
+  unsigned char outEncoding = ETCH_ENCODING_UTF8;
+  const char in[] = {'a', 0,
+                     'b', 0,
+                     'c', 0,
+                       0, 0};
+  unsigned char inEncoding = ETCH_ENCODING_UCS2;
+  unsigned int inByteCount = 4*2;
+  int outBytes;
+  // TODO: pool
+  CU_ASSERT_EQUAL(0, etch_encoding_transcode(&out, outEncoding, in, inEncoding, inByteCount, &outBytes, NULL));
+  CU_ASSERT(out != NULL);
+  if(out){
+      CU_ASSERT_EQUAL('a', out[0]);
+      CU_ASSERT_EQUAL('b', out[1]);
+      CU_ASSERT_EQUAL('c', out[2]);
+      CU_ASSERT_EQUAL(0,   out[3]);
+      CU_ASSERT_EQUAL(4, outBytes);
+      etch_free(out);
+  }
+}
+
+static void test_etch_encoding_transcode_ucs4_utf8(void)
+{
+
+  char* out = 0;
+  unsigned char outEncoding = ETCH_ENCODING_UTF8;
+  const char in[] = {'a', 0, 0, 0,
+                     'b', 0, 0, 0,
+                     'c', 0, 0, 0,
+                       0, 0, 0, 0};
+  unsigned char inEncoding = ETCH_ENCODING_UCS4;
+  unsigned int inByteCount = 4*4;
+  int outBytes;
+  // TODO: pool
+  CU_ASSERT_EQUAL(0, etch_encoding_transcode(&out, outEncoding, in, inEncoding, inByteCount, &outBytes, NULL));
+  CU_ASSERT(out != NULL);
+  if(out){
+      CU_ASSERT_EQUAL('a', out[0]);
+      CU_ASSERT_EQUAL('b', out[1]);
+      CU_ASSERT_EQUAL('c', out[2]);
+      CU_ASSERT_EQUAL(0,   out[3]);
+      CU_ASSERT_EQUAL(4, outBytes);
+      etch_free(out);
+  }
+}
+
+
+static void test_etch_encoding_transcode_wchar_utf8(void) {
+  char* out = 0;
+  unsigned char outEncoding = ETCH_ENCODING_UTF8;
+  wchar_t *in = L"abc";
+  // TODO: pool
+  CU_ASSERT_EQUAL(0, etch_encoding_transcode_wchar(&out, outEncoding, in, NULL));
+  CU_ASSERT(out != NULL);
+  if(out){
+      CU_ASSERT_EQUAL('a', out[0]);
+      CU_ASSERT_EQUAL('b', out[1]);
+      CU_ASSERT_EQUAL('c', out[2]);
+      CU_ASSERT_EQUAL(0,   out[3]);
+      etch_free(out);
+  }
+}
+
+CU_pSuite test_etch_encoding_suite(void)
+{
+    CU_pSuite ps = CU_add_suite("etch_encoding", init_suite, clean_suite);
+    /*
+    CU_add_test(ps, "test etch_encoding_unicode_to_utf8", test_etch_encoding_unicode_to_utf8);
+    CU_add_test(ps, "test etch_encoding_unicode_to_ansi", test_etch_encoding_unicode_to_ansi);
+    CU_add_test(ps, "test etch_encoding_utf8_to_unicode", test_etch_encoding_utf8_to_unicode);
+    CU_add_test(ps, "test etch_encoding_ansi_to_unicode", test_etch_encoding_ansi_to_unicode);
+    CU_add_test(ps, "test etch_encoding_get_unicode_bytecount", test_etch_encoding_get_unicode_bytecount);
+    */
+    CU_add_test(ps, "test etch_encoding_transcode_ucs2_utf8", test_etch_encoding_transcode_ucs2_utf8);
+    CU_add_test(ps, "test etch_encoding_transcode_ucs4_utf8", test_etch_encoding_transcode_ucs4_utf8);
+    CU_add_test(ps, "test etch_encoding_transcode_wchar_utf8", test_etch_encoding_transcode_wchar_utf8);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_etch_linked_list.c b/binding-c/runtime/c/src/test/common/test_etch_linked_list.c
new file mode 100644
index 0000000..bda8b92
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_etch_linked_list.c
@@ -0,0 +1,392 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_runtime.c -- test etch runtime
+ */
+#include "etch_runtime.h"
+#include "etch_linked_list.h"
+
+#include <stdio.h>
+#include <wchar.h>
+#include "CUnit.h"
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    return 0;
+}
+
+//**********************
+// START testcases here
+//**********************
+
+static void test_etch_linked_list_create_destroy(void)
+{
+    etch_status_t       status = ETCH_SUCCESS;
+    etch_linked_list_t* list   = NULL;
+
+    status = etch_linked_list_create(&list, 0);
+    CU_ASSERT_PTR_NOT_NULL(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    status = etch_linked_list_destroy(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+}
+
+static void test_etch_linked_list_add(void)
+{
+    etch_status_t       status = ETCH_SUCCESS;
+    etch_linked_list_t* list   = NULL;
+    char*               data   = "test_0";
+    uint32              count  = 0;
+    uint32              i      = 0;
+
+    status = etch_linked_list_add(NULL, NULL);
+    CU_ASSERT_EQUAL(status, ETCH_EINVAL);
+
+    status = etch_linked_list_create(&list, 0);
+    CU_ASSERT_PTR_NOT_NULL(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_add(list, data);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 1);
+
+    status = etch_linked_list_remove(list, data);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 0);
+
+    status = etch_linked_list_add(list, NULL);
+    CU_ASSERT_EQUAL(status, ETCH_EINVAL);
+
+    status = etch_linked_list_add(list, "test_1");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_add(list, "test_2");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_destroy(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_create(&list, ETCH_LINKED_LIST_DATA_FREE);
+    CU_ASSERT_PTR_NOT_NULL(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_add(list, etch_malloc(10, 0));
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_add(list, etch_malloc(20, 0));
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_destroy(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_create(&list, 0);
+    CU_ASSERT_PTR_NOT_NULL(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    for(i = 0; i < 1000; i++) {
+        status = etch_linked_list_add(list, data);
+        CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    }
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 1000);
+
+    for(i = 0; i < 1000; i++) {
+        status = etch_linked_list_remove(list, data);
+        CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    }
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 0);
+
+
+    status = etch_linked_list_destroy(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+}
+
+void test_etch_linked_list_count(void)
+{
+    etch_status_t       status = ETCH_SUCCESS;
+    etch_linked_list_t* list   = NULL;
+    uint32              count  = 0;
+
+    status = etch_linked_list_create(&list, 0);
+    CU_ASSERT_PTR_NOT_NULL(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 0);
+
+    status = etch_linked_list_add(list, "test_1");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 1);
+
+    status = etch_linked_list_destroy(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+}
+
+void test_etch_linked_list_contains(void)
+{
+    etch_status_t       status    = ETCH_SUCCESS;
+    etch_linked_list_t* list      = NULL;
+    uint32              contains  = 0;
+    char*               data      = "test_1";
+
+    status = etch_linked_list_create(&list, 0);
+    CU_ASSERT_PTR_NOT_NULL(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_add(list, "test_2");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_add(list, data);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    contains = etch_linked_list_contains(NULL, NULL);
+    CU_ASSERT_EQUAL(contains, 0);
+
+    contains = etch_linked_list_contains(list, NULL);
+    CU_ASSERT_EQUAL(contains, 0);
+
+    contains = etch_linked_list_contains(list, "test_3");
+    CU_ASSERT_EQUAL(contains, 0);
+
+    contains = etch_linked_list_contains(list, data);
+    CU_ASSERT_EQUAL(contains, 1);
+
+    status = etch_linked_list_destroy(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+}
+
+void test_etch_linked_list_insert(void)
+{
+    etch_status_t       status    = ETCH_SUCCESS;
+    etch_linked_list_t* list      = NULL;
+    uint32              count     = 0;
+
+    status = etch_linked_list_create(&list, 0);
+    CU_ASSERT_PTR_NOT_NULL(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_insert(list, 2, "test_1");
+    CU_ASSERT_EQUAL(status, ETCH_EOUTOFBOUNDS);
+
+    status = etch_linked_list_add(list, "test_2");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 1);
+
+    status = etch_linked_list_insert(list, 0, "test_3");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 2);
+
+    status = etch_linked_list_insert(list, 1, "test_4");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 3);
+
+    status = etch_linked_list_insert(list, 2, "test_4");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 4);
+
+    status = etch_linked_list_destroy(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+}
+
+void test_etch_linked_list_get(void)
+{
+    etch_status_t       status    = ETCH_SUCCESS;
+    etch_linked_list_t* list      = NULL;
+    uint32              count     = 0;
+    uint32              i         = 0;
+    char*               data      = NULL;
+
+    status = etch_linked_list_create(&list, 0);
+    CU_ASSERT_PTR_NOT_NULL(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_add(list, "test_0 added");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_insert(list, 0, "test_1 insert 0");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_insert(list, 1, "test_2 insert 1");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_insert(list, 2, "test_3 insert 2");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 4);
+
+    for(i = 0; i < count; i++) {
+      status = etch_linked_list_get(list, i, (void**)&data);
+        CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+        //printf("%s\n", data);
+    }
+
+    status = etch_linked_list_destroy(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+}
+
+void test_etch_linked_list_remove_at(void)
+{
+    etch_status_t       status    = ETCH_SUCCESS;
+    etch_linked_list_t* list      = NULL;
+    uint32              count     = 0;
+
+    status = etch_linked_list_create(&list, 0);
+    CU_ASSERT_PTR_NOT_NULL(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_add(list, "test_0 added");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_remove_at(list, 0);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 0);
+
+    status = etch_linked_list_add(list, "test_0 added");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    status = etch_linked_list_add(list, "test_1 added");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    status = etch_linked_list_add(list, "test_2 added");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 3);
+    status = etch_linked_list_remove_at(list, 1);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 2);
+
+    status = etch_linked_list_remove_at(list, 1);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 1);
+
+    status = etch_linked_list_remove_at(list, 0);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 0);
+
+    status = etch_linked_list_destroy(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    // check remove of last list element
+    status = etch_linked_list_create(&list, 0);
+    CU_ASSERT_PTR_NOT_NULL(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_add(list, "test_0 added");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    status = etch_linked_list_add(list, "test_1 added");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    status = etch_linked_list_add(list, "test_2 added");
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_linked_list_remove_at(list, 2);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 2);
+
+    status = etch_linked_list_remove_at(list, 1);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    status = etch_linked_list_remove_at(list, 0);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 0);
+
+    status = etch_linked_list_destroy(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+}
+
+void test_etch_linked_list_remove(void)
+{
+    etch_status_t       status    = ETCH_SUCCESS;
+    etch_linked_list_t* list      = NULL;
+    uint32              count     = 0;
+    char*               data      = NULL;
+
+    status = etch_linked_list_create(&list, 0);
+    CU_ASSERT_PTR_NOT_NULL(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    data = "test_0 added";
+
+    status = etch_linked_list_add(list, data);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 1);
+
+    status = etch_linked_list_remove(list, data);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    count = etch_linked_list_count(list);
+    CU_ASSERT_EQUAL(count, 0);
+
+    status = etch_linked_list_destroy(list);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+}
+
+//**********************
+// END testcases here
+//**********************
+
+/**
+ * main
+ */
+CU_pSuite test_etch_linked_list_suite()
+{
+    CU_pSuite ps = CU_add_suite("etch_runtime", init_suite, clean_suite);
+    
+    CU_add_test(ps, "test_etch_linked_list_create_destroy", test_etch_linked_list_create_destroy);
+    CU_add_test(ps, "test_etch_linked_list_add", test_etch_linked_list_add);
+    CU_add_test(ps, "test_etch_linked_list_count", test_etch_linked_list_count);
+    CU_add_test(ps, "test_etch_linked_list_contains", test_etch_linked_list_contains);
+    CU_add_test(ps, "test_etch_linked_list_insert", test_etch_linked_list_insert);
+    CU_add_test(ps, "test_etch_linked_list_get", test_etch_linked_list_get);
+    CU_add_test(ps, "test_etch_linked_list_remove_at", test_etch_linked_list_remove_at);
+    CU_add_test(ps, "test_etch_linked_list_remove", test_etch_linked_list_remove);
+
+    return ps;
+
+
+
+
+}
diff --git a/binding-c/runtime/c/src/test/common/test_etch_log.c b/binding-c/runtime/c/src/test/common/test_etch_log.c
new file mode 100644
index 0000000..b97abfe
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_etch_log.c
@@ -0,0 +1,146 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_runtime.c -- test etch runtime
+ */
+#include "etch_runtime.h"
+#include "etch_config.h"
+#include "etch_log.h"
+
+#include <stdio.h>
+#include <wchar.h>
+#include "CUnit.h"
+
+static const char* TEST_ETCH_LOG_CATEGORY = "test_etch_config";
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    return 0;
+}
+
+static etch_status_t etch_log_appender_test_create(void** appender, etch_config_t* config)
+{
+    *appender = NULL;
+    return ETCH_SUCCESS;
+}
+
+static etch_status_t etch_log_appender_test_open(void* appender)
+{
+    //printf("etch_log_appender_test_open\n");
+    return ETCH_SUCCESS;
+}
+
+static etch_status_t etch_log_appender_test_log(void* appender, etch_log_message_t* message)
+{
+    //printf("etch_log_appender_test_log\n");
+    return ETCH_SUCCESS;
+}
+
+static etch_status_t etch_log_appender_test_close(void* appender)
+{
+    //printf("etch_log_appender_test_close\n");
+    return ETCH_SUCCESS;
+}
+
+static etch_status_t etch_log_appender_test_destroy(void* appender)
+{
+    return ETCH_SUCCESS;
+}
+
+static struct etch_log_appender_desc etch_log_appender_test_desc = {
+    etch_log_appender_test_create,
+    etch_log_appender_test_open,
+    etch_log_appender_test_log,
+    etch_log_appender_test_close,
+    etch_log_appender_test_destroy
+};
+
+
+//**********************
+// START testcases here
+//**********************
+
+static void test_etch_log_register_appender(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    
+    etch_status = etch_log_register_appender("testappender", &etch_log_appender_test_desc);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+}
+
+static void test_etch_log_create_destroy(void)
+{
+    etch_status_t   etch_status = ETCH_SUCCESS;
+    etch_config_t*  config = NULL;
+    etch_log_t*     logger = NULL;
+
+    etch_status = etch_config_create(&config);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_log_create(&logger, config);
+    CU_ASSERT_PTR_NOT_NULL(logger);
+
+    etch_log_destroy(logger);
+    etch_config_destroy(config);
+}
+
+static void test_etch_log_log(void)
+{
+    etch_status_t   etch_status = ETCH_SUCCESS;
+    etch_config_t*  config = NULL;
+
+    etch_status = etch_config_create(&config);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_runtime_initialize(config);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    ETCH_LOG(TEST_ETCH_LOG_CATEGORY, ETCH_LOG_ERROR, "test log message");
+    ETCH_LOG(TEST_ETCH_LOG_CATEGORY, ETCH_LOG_XDEBUG, "test log message %s", "test1");
+    ETCH_LOG(TEST_ETCH_LOG_CATEGORY, ETCH_LOG_INFO, "test log message %s", "test2");
+
+    etch_runtime_shutdown();
+    etch_config_destroy(config);
+}
+
+//**********************
+// END testcases here
+//**********************
+
+CU_pSuite test_etch_log_suite()
+{
+    CU_pSuite ps = CU_add_suite("etch_log test suite", init_suite, clean_suite);
+    
+    CU_add_test(ps, "test etch_log_register_appender", test_etch_log_register_appender);
+    CU_add_test(ps, "test etch_log_create_destroy", test_etch_log_create_destroy);
+    CU_add_test(ps, "test etch_log_log", test_etch_log_log);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_etch_mutex.c b/binding-c/runtime/c/src/test/common/test_etch_mutex.c
new file mode 100644
index 0000000..fb049b8
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_etch_mutex.c
@@ -0,0 +1,151 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_mutex.c -- test etch mutex
+ */
+#include "etch_runtime.h"
+#include "etch_mutex.h"
+
+#include <stdio.h>
+#include <wchar.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+//**********************
+// START testcases here
+//**********************
+
+static void test_apr_mutex(void)
+{
+    apr_status_t        apr_status  = APR_SUCCESS;
+    apr_thread_mutex_t* apr_mutex   = NULL;
+
+    // test create, lock, unlock, destory
+    // create mutex
+    apr_status = apr_thread_mutex_create(&apr_mutex, APR_THREAD_MUTEX_NESTED, g_etch_main_pool);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+    // lock mutex
+    apr_status = apr_thread_mutex_lock(apr_mutex);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+    // unlock mutex
+    apr_status = apr_thread_mutex_unlock(apr_mutex);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+    // destroy mutex
+    apr_status = apr_thread_mutex_destroy(apr_mutex);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+    apr_mutex = NULL;
+
+
+    // test create, lock, lock, destory
+    // create mutex
+    apr_status = apr_thread_mutex_create(&apr_mutex, APR_THREAD_MUTEX_NESTED, g_etch_main_pool);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+    // lock mutex first time
+    apr_status = apr_thread_mutex_lock(apr_mutex);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+    // lock mutex second time
+    apr_status = apr_thread_mutex_lock(apr_mutex);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+    // unlock mutex second time
+    apr_status = apr_thread_mutex_unlock(apr_mutex);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+    apr_status = apr_thread_mutex_unlock(apr_mutex);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+    // destroy mutex
+    apr_status = apr_thread_mutex_destroy(apr_mutex);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+    if(apr_status != APR_SUCCESS) {
+        char buffer[1024];
+        apr_strerror(apr_status, buffer, 1024);
+        printf("error: %s\n", buffer);
+    }
+    apr_mutex = NULL;
+}
+
+static void test_etch_mutex_create_destory(void)
+{
+    etch_status_t status  = APR_SUCCESS;
+    etch_mutex_t* mutex   = NULL;
+
+    status = etch_mutex_create(&mutex, ETCH_MUTEX_UNNESTED, g_etch_main_pool);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_mutex_lock(mutex);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_mutex_trylock(mutex);
+    CU_ASSERT_EQUAL(status, ETCH_EBUSY);
+
+    status = etch_mutex_unlock(mutex);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_mutex_unlock(mutex);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_mutex_unlock(mutex);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_mutex_destroy(mutex);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+}
+
+//**********************
+// END testcases here
+//**********************
+
+/**
+ * main   
+ */
+CU_pSuite test_etch_mutex_suite()
+{
+    CU_pSuite ps = CU_add_suite("etch_mutex", init_suite, clean_suite);
+
+    CU_add_test(ps, "test apr_mutex", test_apr_mutex);
+    CU_add_test(ps, "test etch_mutex_create_destory", test_etch_mutex_create_destory);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_etch_runtime.c b/binding-c/runtime/c/src/test/common/test_etch_runtime.c
new file mode 100644
index 0000000..4cf2d32
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_etch_runtime.c
@@ -0,0 +1,198 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_runtime.c -- test etch runtime
+ */
+#include "etch_runtime.h"
+#include "etch_config.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include <wchar.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+static int init_suite(void)
+{
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    return 0;
+}
+
+//**********************
+// START testcases here
+//**********************
+
+static void test_etch_runtime_get_version(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    uint16        major       = 0;
+    uint16        minor       = 0;
+    uint16        revision    = 0;
+
+    // initialize runtime
+    etch_status = etch_runtime_get_version(NULL, NULL, NULL);
+    CU_ASSERT_EQUAL(etch_status, ETCH_EINVAL);
+
+    etch_status = etch_runtime_get_version(&major, &minor, &revision);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+}
+
+
+static void test_etch_runtime_initialize_shutdown(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    // initialize runtime
+    etch_status = etch_runtime_initialize(NULL);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+    // check apr pool
+    CU_ASSERT_PTR_NOT_NULL(g_etch_main_pool);
+    // shutdown runtime
+    etch_runtime_shutdown();
+    // check apr pool
+    CU_ASSERT_PTR_NULL(g_etch_main_pool);
+}
+
+static void test_etch_runtime_get_config(void)
+{
+    etch_status_t etch_status  = ETCH_SUCCESS;
+    etch_config_t *config      = NULL;
+    etch_config_t *configtemp  = NULL;
+
+    etch_status = etch_config_create(&config);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_runtime_initialize(config);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+
+    etch_status = etch_runtime_get_config(&configtemp);
+    CU_ASSERT_EQUAL(etch_status, ETCH_SUCCESS);
+    CU_ASSERT_PTR_NOT_NULL(configtemp);
+
+    // shutdown runtime
+    etch_runtime_shutdown();
+
+    etch_config_destroy(config);
+}
+
+static void test_etch_runtime_multiple_times(void)
+{
+    etch_status_t etch_status_runtime  = ETCH_SUCCESS;
+    etch_status_t etch_status_shutdown  = ETCH_SUCCESS;
+    int i=0;
+    
+    for (i=0; i<5; i++)
+    {
+        etch_status_runtime = etch_runtime_initialize(NULL);
+        CU_ASSERT_EQUAL(etch_status_runtime, ETCH_SUCCESS);
+
+        // shutdown runtime
+        etch_status_shutdown = etch_runtime_shutdown();
+        CU_ASSERT_EQUAL(etch_status_shutdown, ETCH_SUCCESS);
+    }
+}
+
+
+static void test_etch_runtime_config_multiple_times(void)
+{
+    etch_status_t etch_status_config  = ETCH_SUCCESS;
+    etch_status_t etch_status_runtime  = ETCH_SUCCESS;
+    etch_status_t etch_status_shutdown  = ETCH_SUCCESS;
+    etch_config_t *config;
+    etch_config_t *configtemp  = NULL;
+
+    int i=0;
+    
+    for (i=0; i<5; i++)
+    {
+        etch_status_config = etch_config_create(&config);
+        CU_ASSERT_EQUAL(etch_status_config, ETCH_SUCCESS);
+
+        etch_status_runtime = etch_runtime_initialize(config);
+        CU_ASSERT_EQUAL(etch_status_runtime, ETCH_SUCCESS);
+
+        etch_status_config = etch_runtime_get_config(&configtemp);
+        CU_ASSERT_EQUAL(etch_status_config, ETCH_SUCCESS);
+        CU_ASSERT_PTR_NOT_NULL(configtemp);
+
+        // shutdown runtime
+        etch_status_shutdown = etch_runtime_shutdown();
+        CU_ASSERT_EQUAL(etch_status_shutdown, ETCH_SUCCESS);
+
+        etch_status_config = etch_config_destroy(config);
+        CU_ASSERT_EQUAL(etch_status_config, ETCH_SUCCESS);
+    }
+}
+
+static void test_etch_runtime_initialize_shutdown_refcount(void)
+{
+    etch_status_t  status = ETCH_SUCCESS;
+
+    /* 1 initialisation */
+    status = etch_runtime_initialize(NULL);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    /* 2 initialisation */
+    status = etch_runtime_initialize(NULL);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    /* 3 initialisation */
+    status = etch_runtime_initialize(NULL);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+    
+    // check apr pool
+    CU_ASSERT_PTR_NOT_NULL(g_etch_main_pool);
+
+    /* 1 shutdown */
+    status = etch_runtime_shutdown();
+    /* 2 shutdown */
+    status = etch_runtime_shutdown();
+    /* 3 shutdown */
+    status = etch_runtime_shutdown();
+
+    // check apr pool
+    CU_ASSERT_PTR_NULL(g_etch_main_pool);
+}
+
+
+//**********************
+// END testcases here
+//**********************
+
+/**
+ * main
+ */
+CU_pSuite test_etch_runtime_suite(int argc, char** argv)
+{
+    CU_pSuite ps = CU_add_suite("etch_runtime", init_suite, clean_suite);
+    
+    CU_add_test(ps, "test_etch_runtime_get_version", test_etch_runtime_get_version);
+    CU_add_test(ps, "test_etch_runtime_initialize_shutdown", test_etch_runtime_initialize_shutdown);
+    CU_add_test(ps, "test_etch_runtime_get_config", test_etch_runtime_get_config);
+    CU_add_test(ps, "test_etch_runtime_multiple_times", test_etch_runtime_multiple_times);
+    CU_add_test(ps, "test_etch_runtime_config_multiple_times", test_etch_runtime_config_multiple_times);
+    CU_add_test(ps, "test_etch_runtime_initialize_shutdown_refcount", test_etch_runtime_initialize_shutdown_refcount);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_etch_thread.c b/binding-c/runtime/c/src/test/common/test_etch_thread.c
new file mode 100644
index 0000000..28ab28a
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_etch_thread.c
@@ -0,0 +1,85 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_etch_threadpool.c -- test etch threadpool
+ */
+#include "etch_runtime.h"
+#include "etch_thread2.h"
+#include "etch_mem.h"
+
+#include "CUnit.h"
+#include <stdio.h>
+#include <wchar.h>
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+//**********************
+// START testcases here
+//**********************
+
+static void test_etch_thread_create_destroy(void)
+{
+    //status = etch_thread_create(&thread, 
+
+
+
+    //status = etch_threadpool_create(&threadpool, ETCH_THREADPOOL_TYPE_FREE, 5);
+    //CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    //status = etch_threadpool_destroy(threadpool);
+    //CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+}
+
+//**********************
+// END testcases here
+//**********************
+
+/**
+ * main   
+ */
+CU_pSuite test_etch_thread_suite()
+{
+    CU_pSuite ps = CU_add_suite("etch_thread", init_suite, clean_suite);
+
+    CU_add_test(ps, "test etch_thread_create_destroy", test_etch_thread_create_destroy);
+    
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_etch_wait.c b/binding-c/runtime/c/src/test/common/test_etch_wait.c
new file mode 100644
index 0000000..fd22cc8
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_etch_wait.c
@@ -0,0 +1,167 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_etch_wait.c -- test etch wait
+ */
+#include "etch_runtime.h"
+#include "etch_wait.h"
+
+#include "apr_thread_proc.h"
+
+#include <stdio.h>
+#include <wchar.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+//**********************
+// START testcases here
+//**********************
+
+typedef struct apr_thread_data_t
+{
+    etch_wait_t* waiter;
+    uint16       mode;
+    uint16       rv;
+} apr_thread_data_t;
+
+static void* APR_THREAD_FUNC thread_func1(apr_thread_t *thd, void *data)
+{
+    apr_status_t       status;
+    apr_thread_data_t* thd_data = data;
+    clock_t            start    = 0;
+    clock_t            end      = 0;
+    clock_t            diff     = 0;
+
+    switch(thd_data->mode) {
+        case 0:
+            start = clock();
+            status = etch_wait_timedwait(thd_data->waiter, 4, 400);
+            CU_ASSERT_EQUAL(status, ETCH_ETIMEOUT);
+            end = clock();
+            diff = end - start;
+            break;
+        case 1:
+            start = clock();
+            status = etch_wait_timedwait(thd_data->waiter, 2, 500);
+            CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+            end = clock();
+            diff = end - start;
+            break;
+    }
+
+    apr_thread_exit(thd, 0);
+    return NULL;
+}
+
+static void test_etch_wait_create_destroy(void)
+{
+    etch_status_t status = ETCH_SUCCESS;
+    etch_wait_t*  waiter = NULL;
+
+    status = etch_wait_create(&waiter, g_etch_main_pool);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_wait_destroy(waiter);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+}
+
+static void test_etch_wait_timedwait(void)
+{
+    etch_status_t status     = ETCH_SUCCESS;
+    etch_wait_t*  waiter     = NULL;
+
+    
+    apr_status_t      apr_status;
+    apr_status_t      apr_thread_status;
+    apr_thread_data_t apr_thread_data;
+    apr_thread_t*     apr_thread = NULL;
+
+    status = etch_wait_create(&waiter, g_etch_main_pool);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_wait_timedwait(waiter, 2, 100);
+    CU_ASSERT_EQUAL(status, ETCH_ETIMEOUT);
+
+    // timeout / signal test
+    apr_thread_data.waiter = waiter;
+    apr_thread_data.mode   = 0;
+
+    apr_status = apr_thread_create(&apr_thread, NULL, thread_func1, &apr_thread_data, g_etch_main_pool);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+
+    apr_sleep(200);
+    etch_wait_set(waiter, 1);
+
+    apr_status = apr_thread_join(&apr_thread_status, apr_thread);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+
+    // timeout / signal test
+    apr_thread_data.waiter = waiter;
+    apr_thread_data.mode   = 1;
+
+    apr_status = apr_thread_create(&apr_thread, NULL, thread_func1, &apr_thread_data, g_etch_main_pool);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+    
+    etch_wait_set(waiter, 2);
+
+    apr_status = apr_thread_join(&apr_thread_status, apr_thread);
+    CU_ASSERT_EQUAL(apr_status, APR_SUCCESS);
+
+    status = etch_wait_destroy(waiter);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+}
+
+//**********************
+// END testcases here
+//**********************
+
+/**
+ * main   
+ */
+CU_pSuite test_etch_wait_suite()
+{
+    CU_pSuite ps = CU_add_suite("etch_wait", init_suite, clean_suite);
+
+    CU_add_test(ps, "test test_etch_wait_create_destroy", test_etch_wait_create_destroy);
+    CU_add_test(ps, "test test_etch_wait_timedwait", test_etch_wait_timedwait);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_etchobject.c b/binding-c/runtime/c/src/test/common/test_etchobject.c
new file mode 100644
index 0000000..d09231e
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_etchobject.c
@@ -0,0 +1,1056 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_etchobject.c.c -- test etch object inheritance and primitives
+ */
+#include "etch_runtime.h"
+#include "etch_object.h"
+#include "etch_objecttypes.h"
+#include "etch_nativearray.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+#include <wchar.h>
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/**
+ * class_a: base class
+ */
+typedef struct class_a
+{
+    etch_object object;
+
+    etch_string* a_string;
+     
+} class_a;
+
+
+/**
+ * class_a destructor
+ */
+static int destroy_class_a(void* data)
+{
+    class_a* thisp = (class_a*)data;
+    if (thisp->a_string)
+        etch_object_destroy(thisp->a_string);
+
+    destroy_object((etch_object*) thisp);
+    return 0;
+}
+
+/**
+ * class_a copy consttructor
+ */
+static void* clone_class_a(void* data)
+{
+    class_a* origobj = (class_a*)data;
+    class_a* newobj = (class_a*) new_object(sizeof(class_a), 413, 0);
+    memcpy(newobj, origobj, sizeof(etch_object));
+    newobj->a_string = (etch_string*)etch_object_clone_func(origobj->a_string);
+    return newobj; 
+}
+
+
+/**
+ * class_a constructor
+ */
+static class_a* new_class_a(const wchar_t* strval)
+{
+    class_a* newobj  = (class_a*) new_object(sizeof(class_a), 403, 0);
+    ((etch_object*)newobj)->destroy  = destroy_class_a;
+    ((etch_object*)newobj)->clone    = clone_class_a;
+    newobj->a_string = new_stringw(strval);
+    return newobj;
+}
+
+
+/**
+ * class_b: inherits from class_a
+ */
+typedef struct class_b
+{
+    etch_object object;
+
+    char* data; 
+    int   datasize;  
+
+} class_b;
+
+
+/**
+ * class_b destructor
+ */
+static int destroy_class_b(void* data)
+{
+    class_b* thisp = (class_b*)data;
+    etch_free(thisp->data);
+    destroy_object((etch_object*) thisp);
+    return 0;
+}
+
+
+/**
+ * class_b copy consttructor
+ */
+static void* clone_class_b(void* data)
+{
+    class_b* origobj = (class_b*)data;
+    class_b* newobj  = (class_b*) new_object(sizeof(class_b), 415, 0);
+    memcpy(newobj, origobj, sizeof(etch_object));
+
+    ((etch_object*)newobj)->parent = ((etch_object*)origobj)->parent? 
+        etch_object_clone_func(((etch_object*)origobj)->parent): 
+        (etch_object*)new_class_a(NULL);
+
+    if (origobj->data)
+    {
+        newobj->data     = etch_malloc(origobj->datasize, 412); 
+        newobj->datasize = origobj->datasize;
+        memcpy(newobj->data, origobj->data, origobj->datasize); 
+    }
+ 
+    return newobj;
+}
+
+
+/**
+ * class_b constructor
+ */
+static class_b* new_class_b(class_a* parent, const int datalen)
+{
+    class_b* newobj = (class_b*) new_object(sizeof(class_b), 404, 0);
+    ((etch_object*)newobj)->parent  = (etch_object*)(parent? parent: new_class_a(NULL));
+    ((etch_object*)newobj)->destroy = destroy_class_b;
+    ((etch_object*)newobj)->clone   = clone_class_b;
+    newobj->data    = etch_malloc(datalen, 402);
+    memset(newobj->data, 'x', datalen);
+    newobj->datasize = datalen;
+    return newobj;
+}
+
+
+/**
+ * class_c: inherits from class_b
+ */
+typedef struct class_c
+{
+    etch_object object;
+
+    int* intarray;
+    int  numitems;
+
+} class_c;
+
+
+/**
+ * class_c destructor
+ */
+static int destroy_class_c(void* data)
+{
+    class_c* thisp = (class_c*)data;
+    etch_free(thisp->intarray);
+    destroy_object((etch_object*) thisp);
+    return 0;
+}
+
+
+/**
+ * class_c copy consttructor
+ */
+static void* clone_class_c(void* data)
+{
+    class_c* origobj = (class_c*)data;
+    class_c* newobj  = (class_c*) new_object(sizeof(class_c), 410, 0);
+    memcpy(newobj, origobj, sizeof(etch_object));
+
+    if  (((etch_object*)origobj)->parent)
+         ((etch_object*)newobj)->parent = etch_object_clone_func(((etch_object*)origobj)->parent);
+    else ((etch_object*)newobj)->parent = (etch_object*)new_class_b(NULL, 0);
+
+    if (origobj->intarray)
+    {
+        newobj->intarray = etch_malloc(origobj->numitems * sizeof(int), 411);
+        newobj->numitems = origobj->numitems;
+        memcpy(newobj->intarray, origobj->intarray, origobj->numitems * sizeof(int)); 
+    }
+
+    return newobj; 
+}
+
+
+/**
+ * class_c constructor
+ */
+static class_c* new_class_c(class_b* parent)
+{
+    int i = 0;
+    class_c* newobj  = (class_c*) new_object(sizeof(class_b), 400, 0);
+    ((etch_object*)newobj)->parent   = (etch_object*)(parent? parent: new_class_b(NULL, 0));
+    ((etch_object*)newobj)->destroy  = destroy_class_c;
+    ((etch_object*)newobj)->clone    = clone_class_c;
+
+    newobj->numitems = 4;
+    newobj->intarray = etch_malloc(4 * sizeof(int), 401);
+    for(; i < 4; i++) newobj->intarray[i] = i;
+
+    return newobj;
+}
+
+
+/**
+ * test_inheritance()
+ * test that in scenario c inherits from b inherits from a,
+ * destroying c destroys b destroys a.
+ */
+static void test_inheritance(void)
+{
+    class_a* class_toplevel = NULL;
+    class_b* class_midlevel = NULL;
+    class_c* class_lowlevel = NULL;
+
+    class_toplevel = new_class_a(L"it works!");
+    class_midlevel = new_class_b(class_toplevel, 128);
+    class_lowlevel = new_class_c(class_midlevel);
+ 
+    /* any object destructor should recursively destroy() its superclasses */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(((etch_object*)class_lowlevel)->parent);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(((etch_object*)class_midlevel)->parent);
+    CU_ASSERT_PTR_NULL_FATAL(((etch_object*)class_toplevel)->parent);
+
+    etch_object_destroy(class_lowlevel);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_clone()
+ * test validity of cloned objects, also test construction of inherited object
+ * when the parent(s) implementation(s) is/are not specified.
+ * clones must be disposable, i.e. they must own all their memory
+ * including that of their superclasses, such that if c inherits from b 
+ * inherits from a, and I clone c giving c', and I then destroy c, then 
+ * I can subsequently destroy c' via normal channels.
+ */
+static void test_clone(void)
+{
+    class_c* class_lowlevel = NULL;
+    class_b* class_midlevel = NULL;
+    class_a* class_toplevel = NULL;
+
+    class_c* clone_lowlevel = NULL;
+    class_b* clone_midlevel = NULL;
+    class_a* clone_toplevel = NULL;
+
+    /* construct class c and all its superclasses */
+    class_lowlevel = new_class_c(NULL);
+
+    /* verify that superclasses were created */
+    class_midlevel = (class_b*) ((etch_object*)class_lowlevel)->parent;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(class_midlevel);
+    class_toplevel = (class_a*) ((etch_object*)class_midlevel)->parent;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(class_toplevel);
+    CU_ASSERT_PTR_NULL_FATAL(((etch_object*)class_toplevel)->parent);
+
+    /* clone class c and all its superclasses */
+    clone_lowlevel = (class_c*)etch_object_clone_func(class_lowlevel);
+
+    /* verify that superclasses were created */
+    clone_midlevel = (class_b*) ((etch_object*)clone_lowlevel)->parent;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(clone_midlevel);
+    clone_toplevel = (class_a*) ((etch_object*)clone_midlevel)->parent;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(clone_toplevel);
+    CU_ASSERT_PTR_NULL_FATAL(((etch_object*)clone_toplevel)->parent);
+
+    /* verify that superclass and data clones are not references to old memory */
+    CU_ASSERT_NOT_EQUAL_FATAL(class_midlevel, clone_midlevel);
+    CU_ASSERT_NOT_EQUAL_FATAL(class_toplevel, clone_toplevel);
+   
+    if (class_midlevel->data != 0 && clone_midlevel->data != 0)
+        CU_ASSERT_NOT_EQUAL_FATAL(class_midlevel->data, clone_midlevel->data);
+    if (class_toplevel->a_string != 0 && clone_toplevel->a_string != 0)
+        CU_ASSERT_NOT_EQUAL_FATAL(class_toplevel->a_string, clone_toplevel->a_string);
+
+    // clean data of clone_midlevel so we get no memory leaks
+    if(clone_midlevel->data) {
+        etch_free(clone_midlevel->data);
+    }
+
+    /* we don't need to do this for the test, but here we illustrate   
+     * the etch C way of accessing superclass data from a subclass, 
+     * which is to traverse the parent chain to the class you want, 
+     * and cast the parent* to that class, if it is not so cast already. 
+     */
+    clone_midlevel->datasize = 1024; 
+    clone_midlevel->data = etch_malloc(clone_midlevel->datasize, 419);
+    memset(clone_midlevel->data, '-',  clone_midlevel->datasize);
+ 
+    /* destroy class c with all its superclasses and associated instance data */
+    etch_object_destroy(class_lowlevel);
+
+    /* destroy class c clone and all its superclasses 
+     * if the clone of class_c had not properly cloned all its superclasses and 
+     * data, this would crash on attempt to free dangling pointer.
+     */
+    etch_object_destroy(clone_lowlevel);
+}
+
+
+static void test_primitive_byte(void)
+{
+    signed char v = 255;
+    etch_byte* newobj = new_byte(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(v, newobj->value);
+
+    etch_object_destroy(newobj); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+static void test_primitive_bool(void)
+{
+    etch_boolean* newobj = new_boolean(100);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value, TRUE); 
+
+    etch_object_destroy(newobj); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+static void test_primitive_int8(void)
+{
+    signed char v = -1;
+    etch_int8* newobj = new_int8(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v); 
+
+    etch_object_destroy(newobj); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+static void test_primitive_int16(void)
+{
+    short v = -1;
+    etch_int16* newobj = new_int16(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v); 
+
+    etch_object_destroy(newobj); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+static void test_primitive_int32(void)
+{
+    int v = 1 << 31;
+    etch_int32* newobj = new_int32(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v); 
+
+    etch_object_destroy(newobj); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+static void test_primitive_int64(void)
+{
+    int64 v = ((int64)(1)) << 63;
+    etch_int64* newobj = new_int64(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v);  
+
+    etch_object_destroy(newobj); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+static void test_primitive_float(void)
+{
+    float v = (float)(3.14159);
+    etch_float* newobj = new_float(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v); 
+
+    etch_object_destroy(newobj); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+static void test_primitive_double(void)
+{
+    double v = (1 << 31) + 3.14159;
+    etch_double* newobj = new_double(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(newobj->value,v); 
+
+    etch_object_destroy(newobj); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+static void test_primitive_string(void)
+{
+    wchar_t* v = L"it works!";
+    etch_string* newobj = new_stringw(v);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newobj); 
+    CU_ASSERT_EQUAL(wcscmp(v, newobj->v.valw), 0);
+    
+    etch_object_destroy(newobj); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/** 
+ * test_nativearray_ctordtor()
+ * test that we can create and destroy an etch_nativearray with all memory accounted for
+ */
+static void test_nativearray_ctordtor(void)
+{
+    etch_nativearray* bytearray_1x4 = new_etch_nativearray(CLASSID_ARRAY_BYTE, sizeof(byte), 1, 4, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(bytearray_1x4); 
+
+    etch_object_destroy(bytearray_1x4);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/** 
+ * test_nativearray_1x1x4()
+ * test that we can populate and access a 1-dimensional array of byte
+ */
+static void test_nativearray_1x1x4(void)
+{
+    int   i = 0, result = 0;
+    char  x[4] = {'a','b','c','d'}, thisx = 0;
+    const int numdimensions = 1, itemcount = 4;
+
+    etch_nativearray* a = new_etch_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, itemcount, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < itemcount; i++)     /* populate array */
+    {
+        result = a->put1(a, &x[i], i); /* insert value of i to ith slot */
+        CU_ASSERT_EQUAL(result, 0); 
+    }
+
+    for(i = 0; i < itemcount; i++)      /* read values out of array */
+    {
+        result = a->get1(a, &thisx, i); /* get value of ith slot into thisx */
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(x[i], thisx); 
+    }
+
+    etch_object_destroy(a);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/** 
+ * test_nativearray_1x4x4()
+ * test that we can populate and access a 1-dimensional array of int
+ */
+static void test_nativearray_1x4x4(void)
+{
+    int i = 0, j = 0, result = 0;
+    const int numdimensions = 1, itemcount = 4;
+
+    etch_nativearray* a = new_etch_nativearray 
+        (CLASSID_ARRAY_INT32, sizeof(int), numdimensions, itemcount, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < itemcount; i++)  /* populate array */
+    {
+        result = a->put1(a, &i, i); /* insert value of i to ith slot */
+        CU_ASSERT_EQUAL(result, 0); 
+    }
+
+    for(i = 0; i < itemcount; i++)  /* read values out of array */
+    {
+        result = a->get1(a, &j, i); /* get value of ith slot into j */
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(i, j); 
+    }
+
+    etch_object_destroy(a);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/** 
+ * test_nativearray_1xstruct()
+ * test that we can populate and access a 1-dimensional array of struct
+ */
+static void test_nativearray_1xstruct(void)
+{
+    int i = 0, result = 0;
+    const int numdimensions = 1, itemcount = 4;
+    struct x { int n; char c; };
+    struct x xgot  = {-1,'?'};
+    struct x xs[4] = { {0,'a'}, {1,'b'}, {2,'c'}, {3,'d'}, };
+
+    etch_nativearray* a = new_etch_nativearray 
+        (CLASSID_ARRAY_STRUCT, sizeof(struct x), numdimensions, itemcount, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < itemcount; i++)      /* populate array */
+    {
+        result = a->put1(a, &xs[i], i); /* insert xs[i] to ith slot */
+        CU_ASSERT_EQUAL(result, 0); 
+    }
+
+    for(i = 0; i < itemcount; i++)      /* read values out of array */
+    {
+        result = a->get1(a, &xgot, i);  /* get value of ith slot into xgot */
+        CU_ASSERT_EQUAL(result, 0); 
+        result = memcmp(&xgot, &xs[i], sizeof(struct x));
+        CU_ASSERT_EQUAL(result, 0); 
+    }
+
+    etch_object_destroy(a);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/** 
+ * test_nativearray_2x1x4()
+ * test that we can populate and access a 2-dimensional array of byte
+ */
+static void test_nativearray_2x1x4(void)
+{
+    int   i = 0, j = 0, result = 0;
+    char  x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+
+    /* note when creating arrays, the dimensions are specified in reverse,
+     * low-order dimension (dim0) first, e.g., for x[2][3][4], 
+     * dim0count is 4, dim1count is 3, dim2count is 2.
+     */
+    etch_nativearray* a = new_etch_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < dim1count; i++)         /* populate array */
+    {
+        for(j = 0; j < dim0count; j++)      
+        {                                  /* insert x[i][j] to array[i][j] */
+            result = a->put2(a, &x[i][j], i, j); 
+            CU_ASSERT_EQUAL(result, 0); 
+        }
+    }
+
+    for(i = 0; i < dim1count; i++)         /* read array */
+    {
+        for(j = 0; j < dim0count; j++)     /* read values out of array */
+        {                                  /* get array[i][j] into thisx */
+            result = a->get2(a, &thisx, i, j); 
+            CU_ASSERT_EQUAL(result, 0); 
+            CU_ASSERT_EQUAL(x[i][j], thisx); 
+        }
+    }
+
+    etch_object_destroy(a);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/** 
+ * test_nativearray_3xstruct()
+ * test that we can populate and access a 3-dimensional array of struct
+ */
+static void test_nativearray_3xstruct(void)
+{
+    int i = 0, j = 0, k = 0, result = 0;
+    struct x  { int n; char c; };
+    struct x  xgot  = {-1,'?'};
+    struct x *xthis = 0;
+
+    struct x xs[2][3][4] = 
+    {   
+      {      
+         {  
+            {0,'a'}, {1,'b'}, {2,'c'}, {3,'d'},  
+         },
+         {  
+            {0,'e'}, {1,'f'}, {2,'g'}, {3,'h'},  
+         },
+         {  
+            {0,'i'}, {1,'j'}, {2,'k'}, {3,'l'},  
+         },
+      },
+      {
+         {  
+            {0,'m'}, {1,'n'}, {2,'o'}, {3,'p'},  
+         },
+         {  
+            {0,'q'}, {1,'r'}, {2,'s'}, {3,'t'},  
+         },
+         {  
+            {0,'u'}, {1,'v'}, {2,'w'}, {3,'x'},  
+         },
+      },    
+    };
+
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+
+    etch_nativearray* a = new_etch_nativearray (CLASSID_ARRAY_STRUCT, sizeof(struct x), 
+        numdimensions, dim0count, dim1count, dim2count);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < dim2count; i++)   /* write array */       
+    {
+        for(j = 0; j < dim1count; j++)
+        {
+            for(k = 0; k < dim0count; k++)      
+            {                                   
+                result = a->put3(a, &xs[i][j][k], i, j, k); 
+                CU_ASSERT_EQUAL(result, 0); 
+            }
+        }
+    }
+
+    for(i = 0; i < dim2count; i++)     /* read array */
+    {
+        for(j = 0; j < dim1count; j++)
+        {
+            for(k = 0; k < dim0count; k++)      
+            {                                   
+                result = a->get3(a, &xgot, i, j, k);   
+                CU_ASSERT_EQUAL(result, 0); 
+                xthis = &xs[i][j][k];
+                result = memcmp(&xgot, xthis, sizeof(struct x));
+                CU_ASSERT_EQUAL(result, 0); 
+            }
+        }
+    }
+
+    etch_object_destroy(a);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/** 
+ * test_arrayfrom_2x1x4()
+ * test that we can access a static 2-dimensional array of byte.
+ * also validates that our array subscripting calculations match those of
+ * the C compiler, since we map and access an array mapped by the compiler.
+ * also validates that the etch_nativearray will not attempt to destroy
+ * the byte vector of an array created in this manner. 
+ */
+static void test_arrayfrom_2x1x4(void)
+{
+    int   i = 0, j = 0, result = 0;
+    char  x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+
+    etch_nativearray* a = new_etch_nativearray_from(&x, CLASSID_ARRAY_BYTE,  
+        sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    for(i = 0; i < dim1count; i++)         /* read array */
+    {
+        for(j = 0; j < dim0count; j++)     /* read values out of array */
+        {                                  /* get array[i][j] into thisx */
+            result = a->get2(a, &thisx, i, j); 
+            CU_ASSERT_EQUAL(result, 0); 
+            CU_ASSERT_EQUAL(x[i][j], thisx); 
+        }
+    }
+
+    etch_object_destroy(a);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/** 
+ * test_subarray()
+ * test that we can create a one-dimensional subarray from a 2-dimensional 
+ * array of byte, and that all memory is accounted for.
+ */
+static void test_subarray(void)
+{
+    int   i = 0, result = 0;
+    char  x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+    etch_nativearray *a0 = NULL, *a1 = NULL, *a2 = NULL;
+
+    etch_nativearray* a = new_etch_nativearray_from(&x, CLASSID_ARRAY_BYTE,  
+        sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+    a->content_obj_type = ETCHTYPEB_BYTE;
+    a->content_class_id = CLASSID_NONE; /* unwrapped content */
+
+    a0 = new_subarray(a, 0); /* test index 0 */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a0); 
+
+    CU_ASSERT_EQUAL(a0->is_content_owned, FALSE);
+    CU_ASSERT_EQUAL(a0->numdims,   a->numdims-1);
+    CU_ASSERT_EQUAL(a0->bytecount, a->bytecount/2);
+    CU_ASSERT_EQUAL(a0->itemsize,  a->itemsize);
+
+    CU_ASSERT_EQUAL(a0->content_obj_type, a->content_obj_type);
+    CU_ASSERT_EQUAL(a0->content_class_id, a->content_class_id);
+
+    /* recall that dimension and dimsize are stored low-order 
+     * dimension first, so dimension[0] and dimsize[0] are 
+     * the same for byte x[2][4] as for x[4] */
+    CU_ASSERT_EQUAL(a0->dimension[0], a->dimension[0]);  
+    CU_ASSERT_EQUAL(a0->dimsize[0],   a->dimsize[0]);  
+
+    for(i = 0; i < dim0count; i++)      
+    {                                  
+        result = a0->get1(a0, &thisx, i); 
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(x[0][i], thisx); 
+    }
+
+    a1 = new_subarray(a, 1); /* test index 1 */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a1); 
+
+    CU_ASSERT_EQUAL(a1->is_content_owned, FALSE);
+    CU_ASSERT_EQUAL(a1->numdims,   a->numdims-1);
+    CU_ASSERT_EQUAL(a1->bytecount, a->bytecount/2);
+    CU_ASSERT_EQUAL(a1->itemsize,  a->itemsize);
+
+    CU_ASSERT_EQUAL(a1->content_obj_type, a->content_obj_type);
+    CU_ASSERT_EQUAL(a1->content_class_id, a->content_class_id);
+
+    /* recall that dimension and dimsize are stored low-order 
+     * dimension first, so dimension[0] and dimsize[0] are 
+     * the same for byte x[2][4] as for x[4] */
+    CU_ASSERT_EQUAL(a1->dimension[0], a->dimension[0]);
+    CU_ASSERT_EQUAL(a1->dimsize[0],   a->dimsize[0]);
+
+    for(i = 0; i < dim0count; i++)      
+    {                                  
+        result = a1->get1(a1, &thisx, i); 
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(x[1][i], thisx); 
+    }
+
+    a2 = new_subarray(a, 2); /* test nonexistent index 2 */
+    CU_ASSERT_PTR_NULL(a2); 
+
+    etch_object_destroy(a1);
+    etch_object_destroy(a0);
+    etch_object_destroy(a);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * test_if_busted_subarray()
+ * this test is here to debug something that was either broken in subarray,
+ * or that was not broken, but rather the validator test using it was broken.
+ * verdict: subarray itemsize was broken, is fixed.
+ */
+static void test_if_busted_subarray(void)  
+{
+    short x[2][3][4] = 
+      { { { 1,1,1,1, }, { 1,1,1,1, }, { 1,-1,32767, -32768, }, },
+        { { 1,1,1,1, }, { 1,1,1,1, }, { 1,-1,0xfffe,0xffff, }, },
+      };
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+    int i=0, j=0, k=0;
+
+    etch_nativearray* a1 = new_etch_nativearray_from(&x, CLASSID_ARRAY_INT16,  
+         sizeof(short), numdimensions, dim0count, dim1count, dim2count);  
+    a1->content_obj_type = ETCHTYPEB_INT16;
+    a1->content_class_id = CLASSID_NONE; /* unwrapped */
+
+    for(i = 0; i < dim2count; i++)
+    {
+        etch_nativearray* a2 = (etch_nativearray*) etch_nativearray_get_element(a1, i); 
+        CU_ASSERT_EQUAL_FATAL(is_etch_nativearray(a2), TRUE);
+        CU_ASSERT_EQUAL_FATAL(a2->bytecount,   a1->bytecount/a1->dimension[2]);
+        CU_ASSERT_EQUAL_FATAL(a2->numdims,     a1->numdims-1);
+        CU_ASSERT_EQUAL_FATAL(a2->dimsize[0],  a1->dimsize[0]);  
+        CU_ASSERT_EQUAL_FATAL(a2->dimsize[1],  a1->dimsize[1]);
+        CU_ASSERT_EQUAL_FATAL(a2->dimension[0],a1->dimension[0]);
+        CU_ASSERT_EQUAL_FATAL(a2->dimension[1],a1->dimension[1]);
+        CU_ASSERT_EQUAL_FATAL(a2->dimension[1],dim1count);
+
+        for(j = 0; j < dim1count; j++)
+        {
+            etch_nativearray* a3 = (etch_nativearray*) etch_nativearray_get_element(a2, j); 
+            CU_ASSERT_EQUAL_FATAL(is_etch_nativearray(a3), TRUE);
+            CU_ASSERT_EQUAL_FATAL(a3->bytecount,   a2->bytecount/a2->dimension[1]);
+            CU_ASSERT_EQUAL_FATAL(a3->numdims,     a2->numdims-1);
+            CU_ASSERT_EQUAL_FATAL(a3->dimsize[0],  a2->dimsize[0]);
+            CU_ASSERT_EQUAL_FATAL(a3->dimension[0],a2->dimension[0]);
+            CU_ASSERT_EQUAL_FATAL(a3->dimension[0],dim0count);
+
+            for(k = 0; k < dim0count; k++)
+            {   
+                short n_expected = 0, n_actual = 0;
+                etch_int16* shortobj  = (etch_int16*) etch_nativearray_get_element(a3, k); 
+                CU_ASSERT_EQUAL_FATAL(is_etch_int16(shortobj), TRUE);
+                n_expected = x[i][j][k];
+                n_actual   = shortobj->value;
+                CU_ASSERT_EQUAL_FATAL(n_expected, n_actual);
+
+                etch_object_destroy(shortobj);
+            }
+
+            etch_object_destroy(a3);
+        } 
+
+        etch_object_destroy(a2);   
+    }
+
+    etch_object_destroy(a1);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/** 
+ * test_get_element()
+ * test that we can get element[i] of a native array, and that element
+ * is another native array, or a wrapped etch object the same type as
+ * the array's content_obj_type and possibly content_class_id.
+ */
+static void test_get_element(void)
+{
+    int   i = 0;
+    char  x[2][4] = { {'a','b','c','d'}, {'e','f','g','h'}, }, thisx = 0;
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+    etch_nativearray *a1  = NULL;
+    etch_object*   returnobj  = NULL;
+    etch_byte* retbyteobj = NULL;
+
+    etch_nativearray* a = new_etch_nativearray_from(&x, CLASSID_ARRAY_BYTE,  
+        sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+    a->content_obj_type = ETCHTYPEB_BYTE;
+    a->content_class_id = CLASSID_NONE; /* unwrapped content */
+
+    /* get element[1] from the array, expecting a byte[4] native array */
+    returnobj = etch_nativearray_get_element(a, 1); 
+
+    CU_ASSERT_EQUAL_FATAL(is_etch_nativearray(returnobj), TRUE);
+
+    a1 = (etch_nativearray*) returnobj;
+
+    CU_ASSERT_EQUAL(a1->is_content_owned, FALSE);
+    CU_ASSERT_EQUAL(a1->numdims,   a->numdims-1);
+    CU_ASSERT_EQUAL(a1->bytecount, a->bytecount/2);
+    CU_ASSERT_EQUAL(a1->itemsize,  a->itemsize);
+
+    CU_ASSERT_EQUAL(a1->content_obj_type, a->content_obj_type);
+    CU_ASSERT_EQUAL(a1->content_class_id, a->content_class_id);
+    CU_ASSERT_EQUAL(a1->dimension[0], a->dimension[0]);
+    CU_ASSERT_EQUAL(a1->dimsize[0],   a->dimsize[0]);
+
+    for(i = 0; i < dim0count; i++)      
+    {   
+        /* get element[i] from the subarray, expecting an etch_byte object */                               
+        returnobj = etch_nativearray_get_element(a1, i); 
+        CU_ASSERT_PTR_NOT_NULL_FATAL(returnobj); 
+        CU_ASSERT_EQUAL_FATAL(((etch_object*)returnobj)->class_id, CLASSID_PRIMITIVE_BYTE);
+
+        retbyteobj = (etch_byte*) returnobj; /* verify that wrapped byte */
+        thisx = retbyteobj->value;           /* matches original array */
+        CU_ASSERT_EQUAL(x[1][i], thisx); 
+
+        etch_object_destroy(retbyteobj);
+    }
+
+    etch_object_destroy(a1);
+    etch_object_destroy(a);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etchobject_suite()
+{
+    CU_pSuite ps = CU_add_suite("etchobject", init_suite, clean_suite);
+    
+    CU_add_test(ps, "test primitive byte",    test_primitive_byte); 
+    CU_add_test(ps, "test primitive boolean", test_primitive_bool); 
+    CU_add_test(ps, "test primitive int8",    test_primitive_int8); 
+    CU_add_test(ps, "test primitive int16",   test_primitive_int16); 
+    CU_add_test(ps, "test primitive int32",   test_primitive_int32); 
+    CU_add_test(ps, "test primitive int64",   test_primitive_int64); 
+    CU_add_test(ps, "test primitive float",   test_primitive_float); 
+    CU_add_test(ps, "test primitive double",  test_primitive_double); 
+    CU_add_test(ps, "test primitive string",  test_primitive_string); 
+
+    CU_add_test(ps, "test tri-level inheritance", test_inheritance); 
+    CU_add_test(ps, "test clone and auto-construct superclass", test_clone); 
+
+    CU_add_test(ps, "test native array ctor",  test_nativearray_ctordtor);
+    CU_add_test(ps, "test 1-dim byte array",   test_nativearray_1x1x4);
+    CU_add_test(ps, "test 1-dim int array",    test_nativearray_1x4x4);
+    CU_add_test(ps, "test 1-dim struct array", test_nativearray_1xstruct);
+    CU_add_test(ps, "test 2-dim byte array",   test_nativearray_2x1x4);
+    CU_add_test(ps, "test 3-dim struct array", test_nativearray_3xstruct);
+    CU_add_test(ps, "test static 2-dim byte array", test_arrayfrom_2x1x4);
+    CU_add_test(ps, "test subarray",           test_subarray);
+    CU_add_test(ps, "test get array element",  test_get_element);
+    CU_add_test(ps, "test 3-dim int16 subarray ", test_if_busted_subarray);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_flexbuf.c b/binding-c/runtime/c/src/test/common/test_flexbuf.c
new file mode 100644
index 0000000..abc8db3
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_flexbuf.c
@@ -0,0 +1,396 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+/*
+ * test_flexbuf.c
+ * test flex buffer
+ */
+#include "etch_runtime.h"
+#include "etch_flexbuffer.h"
+#include "etch_mem.h"
+
+#include <limits.h>
+#include <float.h>
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+static etch_flexbuffer* fbuf = 0;
+
+// TODO add testcases
+// test endianes big + little
+// test signed + unsigned values
+
+/**
+ * returns number of errors
+ */
+static int check_buf(etch_flexbuffer* buf, const int len, const int ndx, const int avl)
+{
+    int errors = 0, avail = (int) etch_flexbuf_avail(buf);
+    if (buf->datalen != len) errors++;
+    if (buf->index   != ndx) errors++;
+    if (avail        != avl) errors++;
+    return errors;
+}
+
+static void testCreateAndDestroy0(void)
+{
+    fbuf = new_flexbuffer(0);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    
+    CU_ASSERT(etch_flexbuf_avail(fbuf) == 0);
+    
+    destroy_etch_flexbuffer(fbuf);
+}
+
+static void testCreateAndDestroy1(void)
+{
+    fbuf = new_flexbuffer(-1);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    destroy_etch_flexbuffer(fbuf);
+
+    fbuf = new_flexbuffer(1);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    CU_ASSERT(etch_flexbuf_avail(fbuf) == 0);
+
+    destroy_etch_flexbuffer(fbuf);
+    
+    fbuf = new_flexbuffer(4*1024*1024+1);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    destroy_etch_flexbuffer(fbuf); /* takes NULL */
+}
+
+static void testCreateAndDestroy2(void)
+{
+    void *ptr = etch_malloc(1024, 0);
+    fbuf = etch_flexbuf_create_b(ptr, 1024, 0);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    CU_ASSERT(etch_flexbuf_avail(fbuf) == 0);
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+static void testCreateAndDestroy3(void)
+{
+    void *ptr = etch_malloc(1024, 0);
+    fbuf = etch_flexbuf_create_bi(ptr, 1024, 100, 0);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+    CU_ASSERT(etch_flexbuf_avail(fbuf) == 100);
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+static void testPutAndGet(void)
+{
+    byte test_bytes[] = "testbytes";
+    void *test_buffer = etch_malloc(128, 0);
+    size_t n;
+    int i;
+    etch_flexbuffer *efb2;
+
+    fbuf = new_flexbuffer(0);
+
+    etch_flexbuf_put(fbuf, test_bytes, 0, strlen((char*)test_bytes));
+
+    /* rewind the buffer */
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get(fbuf, test_buffer, 0, strlen((char*)test_bytes));
+    CU_ASSERT(memcmp(test_buffer, test_bytes, n) == 0);
+
+    /* test put byte */
+    etch_flexbuf_set_index(fbuf, 0);
+    for(i = 0; i < (int) strlen((char*)test_bytes); i++)
+        etch_flexbuf_put_byte(fbuf, test_bytes[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get(fbuf, test_buffer, 0, strlen((char*)test_bytes));
+    CU_ASSERT(memcmp(test_buffer, test_bytes, n) == 0);
+
+    /* test put from another buffer */
+    efb2 = new_flexbuffer(0);
+    etch_flexbuf_set_index(fbuf, 0);
+    etch_flexbuf_put_from(efb2, fbuf, n);
+
+    etch_flexbuf_set_index(efb2, 0);
+    n = etch_flexbuf_get(efb2, test_buffer, 0, strlen((char*)test_bytes));
+    CU_ASSERT(memcmp(test_buffer, test_bytes, n) == 0);
+
+    etch_free(test_buffer);
+    destroy_etch_flexbuffer(fbuf);
+    destroy_etch_flexbuffer(efb2);
+}
+
+static void testPutAndGetFully(void)
+{
+    byte test_bytes[] = "testbytes";
+    void *test_buffer = etch_malloc(128, 0);
+    size_t n;
+
+    fbuf = new_flexbuffer(0);
+
+    etch_flexbuf_put(fbuf, test_bytes, 0, strlen((char*)test_bytes));
+
+    /* rewind the buffer */
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get_fully(fbuf, test_buffer, strlen((char*)test_bytes));
+    CU_ASSERT(memcmp(test_buffer, test_bytes, n) == 0);
+
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get_fully(fbuf, test_buffer, 4);
+    CU_ASSERT(memcmp(test_buffer, test_bytes, 4) == 0);
+
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get_fully(fbuf, test_buffer, 32);
+	
+    CU_ASSERT(memcmp(test_buffer, test_bytes, (strlen((char*)test_bytes) < 32 ? strlen((char*)test_bytes): 32)) == 0);
+
+    etch_free(test_buffer);
+    destroy_etch_flexbuffer(fbuf);
+}
+
+
+static void testPutAndGetByte(void)
+{
+    byte test_bytes[] = "testbytes";
+    void *test_buffer = etch_malloc(128, 0);
+    size_t n;
+    int i;
+
+    fbuf = new_flexbuffer(0);
+
+    etch_flexbuf_set_index(fbuf, 0);
+    for(i = 0; i < (int)strlen((char*)test_bytes); i++)
+        etch_flexbuf_put_byte(fbuf, test_bytes[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+    n = etch_flexbuf_get(fbuf, test_buffer, 0, strlen((char*)test_bytes));
+    CU_ASSERT(memcmp(test_buffer, test_bytes, n) == 0);
+
+
+    etch_free(test_buffer);
+    destroy_etch_flexbuffer(fbuf);
+}
+
+static void testPutAndGetShort(void)
+{
+    short test_shorts[] = {SHRT_MIN, SHRT_MAX, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0x7FFF, \
+        0xFFFF, 0xFFFE, -8192, -4096, -2048, -1024, -512, -256, -128, -64, -32, -16, -8, -4, -2, -1};
+
+    int i, result; short value = 0;
+
+    fbuf = new_flexbuffer(0);
+
+    for(i = 0; i < sizeof(test_shorts)/sizeof(short); i++)
+        etch_flexbuf_put_short(fbuf, test_shorts[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+
+    for(i = 0; i < sizeof(test_shorts)/sizeof(short); i++)
+    {
+        result = etch_flexbuf_get_short(fbuf, &value);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(test_shorts[i], value); 
+    }   
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+
+static void testPutAndGetInt(void)
+{
+    int test_ints[] = {INT_MIN, INT_MAX, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0x7FFF, \
+        0xFFFF, 0xFFFFF, 0xFFFFFF, 0xFFFFFFF, 0xFFFFFFE,0x7FFFFFFF, 0xFFFFFFFF, 0xF7FFFFFF, 0xF6FFFFFF, \
+        0xF5FFFFFF, 0xF4FFFFFF, 0xF3FFFFFF, 0xF2FFFFFF, 0xF1FFFFFF, 0xF0FFFFFF, 0xFF0FFFFF, \
+        -8192, -4096, -2048, -1024, -512, -256, -128, -64, -32, -16, -8, -4, -2, -1};
+
+    int i;
+
+    fbuf = new_flexbuffer(0);
+
+    for(i = 0; i < sizeof(test_ints)/sizeof(int); i++)
+        etch_flexbuf_put_int(fbuf, test_ints[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+    for(i = 0; i < sizeof(test_ints)/sizeof(int); i++)
+    {   
+        int n = 0, m = test_ints[i], result;
+        result = etch_flexbuf_get_int(fbuf, &n);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(n,m); 
+    }   
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+
+static void testPutAndGetInt64(void)
+{
+    int64 test_int64s[] = {LONG_MIN, LONG_MAX, 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0x7FFF, \
+        0xFFFF, 0xFFFFF, 0xFFFFFF, 0xFFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF, 0xF7FFFFFF, 0xF6FFFFFF, 0x7FFFFFFFFFFFFFFFLL,\
+        0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFF0LL, 0xFFFFFFFFFFFFFF00LL, 0xFFFFFFFFFFFFF000LL, 0xFFFFFFFFFFFFF000LL, \
+        0xF5FFFFFF, 0xF4FFFFFF, 0xF3FFFFFF, 0xF2FFFFFF, 0xF1FFFFFF, 0xF0FFFFFF, 0xFF0FFFFF, \
+        -8192, -4096, -2048, -1024, -512, -256, -128, -64, -32, -16, -8, -4, -2, -1};
+
+    int i, result;
+
+    fbuf = new_flexbuffer(0);
+
+    for(i = 0; i < sizeof(test_int64s)/sizeof(int64); i++)
+        etch_flexbuf_put_long(fbuf, test_int64s[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+
+    for(i = 0; i < sizeof(test_int64s)/sizeof(int64); i++)
+    {   
+        int64 n = 0, m = test_int64s[i];
+        result = etch_flexbuf_get_long(fbuf, &n);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(n,m); 
+    }   
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+
+static void testPutAndGetFloat(void)
+{
+    float test_floats[] = {FLT_MIN, 0.0f, 1.1f, 2.2f, 4.4f, 8.8f, 16.16f, 32.32f, 64.64f, 128.128f, 256.256f, 512.512f,\
+        1024.1024f, 2048.2048f, 4096.4096f, 8192.8192f, FLT_MAX};
+
+    int i, result;
+
+    fbuf = new_flexbuffer(0);
+
+    for(i = 0; i < sizeof(test_floats)/sizeof(float); i++)
+        etch_flexbuf_put_float(fbuf, test_floats[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+
+    for(i = 0; i < sizeof(test_floats)/sizeof(float); i++)
+    {  
+        float x = 0.0; double diff; int is_equal;
+        const float y = test_floats[i];
+        result = etch_flexbuf_get_float(fbuf, &x);
+        CU_ASSERT_EQUAL(result, 0);
+        diff = (double) (y - x);
+        is_equal = fabs(diff) < 0.00001;
+        CU_ASSERT_EQUAL(is_equal, TRUE);
+    }
+            
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+static void testPutAndGetDouble(void)
+{
+    double test_doubles[] = {DBL_MIN, 0.0, 1.1, 2.2, 4.4, 8.8, 16.16, 32.32, 64.64, 128.128, 256.256, 512.512,\
+        1024.1024, 2048.2048, 4096.4096, 8192.8192, DBL_MAX};
+
+    int i, result;
+
+    fbuf = new_flexbuffer(0);
+
+    for(i = 0; i < sizeof(test_doubles)/sizeof(double); i++)
+        etch_flexbuf_put_double(fbuf, test_doubles[i]);    
+
+    etch_flexbuf_set_index(fbuf, 0);
+
+    for(i = 0; i < sizeof(test_doubles)/sizeof(double); i++)
+    {   
+        double x, y = test_doubles[i];
+        result = etch_flexbuf_get_double(fbuf, &x);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT(x == y);  
+    }  
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+static void testSetSize(void)
+{
+    etch_flexbuffer *fbuf = new_flexbuffer(0);
+
+    CU_ASSERT_EQUAL(0, etch_flexbuf_set_length(fbuf, 1024));
+    CU_ASSERT_EQUAL(0, check_buf(fbuf, 1024, 0, 1024));
+   
+    CU_ASSERT_EQUAL(0, etch_flexbuf_set_length(fbuf, 0));
+    CU_ASSERT_EQUAL(0, check_buf(fbuf, 0, 0, 0));
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+static void testCompact(void)
+{
+    int i;
+    etch_flexbuffer *fbuf = new_flexbuffer(128);
+
+    for(i = 0; i < 10; i++)
+        etch_flexbuf_put_short(fbuf, 1);
+
+    etch_flexbuf_set_index(fbuf, 0);
+    etch_flexbuf_compact(fbuf);
+    CU_ASSERT(fbuf->index ==0);
+    CU_ASSERT(etch_flexbuf_avail(fbuf) == (10*sizeof(short)));
+
+    destroy_etch_flexbuffer(fbuf);
+}
+
+
+//int _tmain(int argc, _TCHAR* argv[])
+CU_pSuite test_etch_flexbuf_suite()
+{
+    CU_pSuite ps = CU_add_suite("suite flexbuffer", init_suite, clean_suite);
+
+    CU_add_test(ps, "testCreateAndDestroy0", testCreateAndDestroy0);
+    CU_add_test(ps, "testCreateAndDestroy1", testCreateAndDestroy1);
+    CU_add_test(ps, "testCreateAndDestroy2", testCreateAndDestroy2);
+    CU_add_test(ps, "testCreateAndDestroy3", testCreateAndDestroy3);
+    CU_add_test(ps, "testPutAndGet", testPutAndGet);
+    CU_add_test(ps, "testPutAndGetFully", testPutAndGetFully);
+    CU_add_test(ps, "testPutAndGetByte", testPutAndGetByte);
+    CU_add_test(ps, "testPutAndGetShort", testPutAndGetShort);
+    CU_add_test(ps, "testPutAndGetInt", testPutAndGetInt);
+    CU_add_test(ps, "testPutAndGetInt64", testPutAndGetInt64);
+    CU_add_test(ps, "testPutAndGetFloat", testPutAndGetFloat);
+    CU_add_test(ps, "testPutAndGetFloat", testPutAndGetDouble);
+    CU_add_test(ps, "testSetSize", testSetSize);
+    CU_add_test(ps, "testCompact", testCompact);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_hashing.c b/binding-c/runtime/c/src/test/common/test_hashing.c
new file mode 100644
index 0000000..80e1d5b
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_hashing.c
@@ -0,0 +1,365 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_hashing.c 
+ * test hashing of various complex items and associated memory management 
+ */
+
+#include "etch_runtime.h"
+#include "etch_binary_tdi.h"  /* must be included second */
+#include "etch_binary_tdo.h"
+#include "etch_connection.h"
+#include "etch_id_name.h"
+#include "etch_field.h"
+#include "etch_type.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+// intern types
+static int g_is_automated_test;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * individual setup and teardown
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+static int this_test_setup()
+{
+    int result = -1;
+
+    do {
+        result = 0;
+
+    } while(0);
+
+    return result;
+}
+
+static int this_test_teardown()
+{    
+
+    return 0;
+}
+
+/**
+ * destroy_content_id_name()
+ * passed a content pointer out of the hashtable, interprets pointer as etch_id_name,
+ * frees the name string, and frees the etch_id_name shell.
+ */
+static int destroy_content_id_name(void* content)
+{
+    etch_id_name*  idname = (etch_id_name*) content;
+    return idname? etch_object_destroy(idname): -1;
+    return 0;
+}
+
+
+/**
+ * destroy_content_field()
+ */
+static int destroy_content_field(void* content)
+{
+    etch_field* field = (etch_field*) content;
+    return field? etch_object_destroy(field): -1;
+}
+
+
+/**
+ * destroy_content_type()
+ */
+static int destroy_content_type(void* content)
+{
+    etch_type* type = (etch_type*) content;
+    return type? etch_object_destroy(type): -1;
+}
+
+
+/**
+ * test_idname_as_key
+ * tests that we can use etch_id_name (and etch_field and etch_type, since they
+ * are etch_id_name typedefs), as hashkeys, and subsequently acccess the original
+ * objects, individually clean up the keys, and ask hashtable to clean up the values.
+ */
+static void test_idname_as_key_hashclean_values(void)
+{
+    etch_field*   my_field  = NULL;
+    etch_type*    my_type   = NULL;
+    etch_id_name* my_idname = NULL;
+
+    const int id_name_size = sizeof(etch_id_name);
+    const int field_size   = sizeof(etch_field);
+    const int type_size    = sizeof(etch_type);
+
+    etch_hashtable* myhashtab = NULL;  
+    etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket; 
+
+    wchar_t* name1 = L"name number one";  
+    wchar_t* name2 = L"nombre numero dos";
+    wchar_t* name3 = L"le troisieme nom";
+
+    const size_t numElements1 = wcslen(name1);
+    const size_t numElements2 = wcslen(name2);
+    const size_t numElements3 = wcslen(name3);
+
+    const size_t numBytes1 = sizeof(wchar_t) * numElements1;
+    const size_t numBytes2 = sizeof(wchar_t) * numElements2;
+    const size_t numBytes3 = sizeof(wchar_t) * numElements3;
+
+    void* value1 = NULL, *value2 = NULL, *value3 = NULL;
+
+    int result = 0, result1 = 0, result2 = 0, result3 = 0;
+    unsigned bytes_allocated = 0;
+
+    value1 = etch_malloc(numBytes1 + sizeof(wchar_t), 0);
+    value2 = etch_malloc(numBytes2 + sizeof(wchar_t), 0);
+    value3 = etch_malloc(numBytes3 + sizeof(wchar_t), 0);
+
+    wcscpy(value1, name1);
+    wcscpy(value2, name2);
+    wcscpy(value3, name3);
+
+    myhashtab = new_hashtable(16);  
+    myhashtab->is_readonly_keys   = TRUE;  /* keys will NOT be freed on destroy */
+    myhashtab->is_readonly_values = FALSE; /* values WILL be freed on destroy */
+    myhashtab->is_tracked_memory  = TRUE;  /* hashtable will use etch_free */
+   
+    my_idname = new_id_name(name1);
+    my_field  = new_field(name2);
+    my_type   = new_type(name3);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_idname);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_field);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_type);
+
+    /* ensure constructors populated the hash key */
+    CU_ASSERT_NOT_EQUAL_FATAL(((etch_object*)my_idname)->get_hashkey(my_idname),0);
+    CU_ASSERT_NOT_EQUAL_FATAL(((etch_object*)my_field)->get_hashkey(my_field),0);
+    CU_ASSERT_NOT_EQUAL_FATAL(((etch_object*)my_type)->get_hashkey(my_type),0);
+
+    /* ensure constructors populated the wire id */
+    CU_ASSERT_NOT_EQUAL_FATAL(my_idname->id,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_field->id,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_type->id,0);
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->inserth(myhashtab->realtable, my_idname, value1, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->inserth(myhashtab->realtable, my_field, value2, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->inserth(myhashtab->realtable, my_type, value3, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->findh(myhashtab->realtable, ((etch_object*)my_idname)->get_hashkey(my_idname), myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_id_name(myentry->key);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->findh(myhashtab->realtable, ((etch_object*)my_field)->hashkey, myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_field(myentry->key);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->findh(myhashtab->realtable, ((etch_object*)my_type)->hashkey, myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_type(myentry->key);
+    CU_ASSERT_EQUAL(result,0);
+
+    /** above we looked up each item and freed memory for the id_name, field, and type keys,
+     * but not for their values. when we created the map we specified is_readonly_keys, so the
+     * map destructor will free memory for the value content, but not for the key content. */
+    etch_object_destroy(myhashtab);
+
+}
+
+
+/**
+ * test_idname_as_key
+ * tests that we can use etch_id_name (and etch_field and etch_type, since they
+ * are etch_id_name typedefs), as hashkeys, and subsequently acccess the original
+ * objects and clean up both the keys and values.
+ */
+static void test_idname_as_key_hashclean_none(void)
+{
+    etch_field*   my_field  = NULL;
+    etch_type*    my_type   = NULL;
+    etch_id_name* my_idname = NULL;
+
+    const int id_name_size = sizeof(etch_id_name);
+    const int field_size   = sizeof(etch_field);
+    const int type_size    = sizeof(etch_type);
+
+    etch_hashtable* myhashtab = NULL;  
+    etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket; 
+
+    wchar_t* name1 = L"name number one";  
+    wchar_t* name2 = L"nombre numero dos";
+    wchar_t* name3 = L"le troisieme nom";
+
+    const size_t numElements1 = wcslen(name1);
+    const size_t numElements2 = wcslen(name2);
+    const size_t numElements3 = wcslen(name3);
+
+    const size_t numBytes1 = sizeof(wchar_t) * numElements1;
+    const size_t numBytes2 = sizeof(wchar_t) * numElements2;
+    const size_t numBytes3 = sizeof(wchar_t) * numElements3;
+    void* value1 = NULL, *value2 = NULL, *value3 = NULL;
+
+    size_t actlen1 = 0, actlen2 = 0, actlen3 = 0;
+    int result = 0, result1 = 0, result2 = 0, result3 = 0;
+    unsigned bytes_allocated = 0;
+
+    value1 = etch_malloc(numBytes1 + 2, 0);   
+    value2 = etch_malloc(numBytes2 + 2, 0);  
+    value3 = etch_malloc(numBytes3 + 2, 0);  
+    
+//	wcscpy_s(value1, numElements1+1, name1);   
+//    wcscpy_s(value2, numElements2+1, name2);   
+//    wcscpy_s(value3, numElements3+1, name3);   
+
+	wcscpy(value1, name1);   
+    wcscpy(value2, name2);   
+    wcscpy(value3, name3);   
+
+
+    actlen1 = wcslen(name1);  actlen2 = wcslen(name2); actlen3 = wcslen(name3);
+
+    myhashtab = new_hashtable(16);  
+    myhashtab->is_readonly_keys   = TRUE; /* keys will be freed on destroy  */
+    myhashtab->is_readonly_values = TRUE; /* values will be freed on destroy */
+    myhashtab->is_tracked_memory  = TRUE; /* hashtable will etch_free content */
+
+    /* here we are creating id_name, field, and type objects using names allocated
+     * on out local stack. therefore the cleanup parameters must be set to not free 
+     * memory for the name part, or we will crash. note that name is part of the 
+     * key structs, and is also the value of the hashed key/value pair, however 
+     * we etch_malloc'ed memory for the values and copied our stack strings into it,
+     * so we will want to free the value memory. we could ask the hashtable to do
+     * so but we'll do it manually here instead.
+     */
+    my_idname = new_id_name(name1);
+    my_field  = new_field(name2);
+    my_type   = new_type(name3);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_idname);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_field);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_type);
+
+   /* ensure constructors populated the hash key */
+    CU_ASSERT_NOT_EQUAL_FATAL(((etch_object*)my_idname)->hashkey,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(((etch_object*)my_field)->hashkey,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(((etch_object*)my_type)->hashkey,0);
+
+    /* ensure constructors populated the id (hash of name) */
+    CU_ASSERT_NOT_EQUAL_FATAL(my_idname->id,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_field->id,0);
+    CU_ASSERT_NOT_EQUAL_FATAL(my_type->id,0);
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->inserth(myhashtab->realtable, my_idname, value1, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->inserth(myhashtab->realtable, my_field, value2, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->inserth(myhashtab->realtable, my_type, value3, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->findh(myhashtab->realtable, ((etch_object*)my_idname)->hashkey, myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_id_name(myentry->key);  
+    CU_ASSERT_EQUAL(result,0);  
+    etch_free(myentry->value); 
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->findh(myhashtab->realtable, ((etch_object*)my_field)->hashkey, myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_field(myentry->key);  
+    CU_ASSERT_EQUAL(result,0); 
+    etch_free(myentry->value);  
+
+    result = ((struct i_hashtable*)((etch_object*)myhashtab)->vtab)->findh(myhashtab->realtable, ((etch_object*)my_type)->hashkey, myhashtab, &myentry);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL(myentry->key);
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+    result = destroy_content_type(myentry->key);  
+    CU_ASSERT_EQUAL(result,0); 
+    etch_free(myentry->value);  
+
+    etch_object_destroy(myhashtab);  /* hashtable was asked to not free any content */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_hashing_suite()
+{
+    CU_pSuite ps = CU_add_suite("suite_hashing", init_suite, clean_suite);
+
+    CU_add_test(ps, "test hash id_name etc - auto-cleanup values", test_idname_as_key_hashclean_values);
+    CU_add_test(ps, "test hash id_name etc - no auto-cleanup", test_idname_as_key_hashclean_none);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_hashtable.c b/binding-c/runtime/c/src/test/common/test_hashtable.c
new file mode 100644
index 0000000..10aecbb
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_hashtable.c
@@ -0,0 +1,1179 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_hashtable.c 
+ * tests the C implementation of etch hashtable.
+ * this hashtable implementation uses the public domain jenkins hashtable.
+ */
+#include "etch_runtime.h"
+#include "etch_hash.h"
+#include "etch_general.h"
+#include "etch_objecttypes.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define TESTDATAPATH "./jenktest.txt"
+#define MAXLINELEN 64
+#define DATASIZE    4
+#define DATAVALUE  "foo" 
+#define INITIAL_TABLE_SIZE 64
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+// intern types
+static int g_is_automated_test;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/**
+ * test_new_hashtable
+ * unit test for new_hashtable
+ */
+static void test_new_hashtable(void)
+{
+    /* new_hashtable always returns mimimal initial size if the input value is too small */
+    etch_hashtable* eht = new_hashtable(-1);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), ETCH_DEFAULT_HASHTABLE_SIZE);
+    etch_object_destroy(eht);
+
+    /* the hashtable size will be modified to previous power of 2 */
+    eht = new_hashtable(63);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);  /* size will be 3 2instead of 64 */
+    etch_object_destroy(eht);
+
+    /* good input case, the size is within boundary and power of 2 */
+    eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+    etch_object_destroy(eht);
+
+    /* the maximum initial size is MAX_INITIAL_HASHTABLE_SIZE */
+    eht = new_hashtable(MAX_INITIAL_HASHTABLE_SIZE+1);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), MAX_INITIAL_HASHTABLE_SIZE);
+    etch_object_destroy(eht);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+static void test_map(void)
+{
+	etch_hashtable* map = new_etch_map(0);
+
+	int count = 0;
+
+	etch_int32*  content1 = new_int32(1);
+	etch_string* content2 = new_stringa("Hallo");
+
+	etch_int32*  key1 = (etch_int32*)new_stringa("Hallo");
+	etch_string* key2 = (etch_string*)new_int32(1);
+
+	count = etchmap_count(map);
+	CU_ASSERT_TRUE(count == 0);
+
+	etchmap_add(map, key1, content1);
+	etchmap_add(map, key2, content2);
+
+	count = etchmap_count(map);
+	CU_ASSERT_TRUE(count == 2);
+
+	etchmap_del(map,key1);
+	etchmap_del(map,key2);
+
+	count = etchmap_count(map);
+	CU_ASSERT_TRUE(count == 0);
+
+	key1 = new_int32(2);
+	etchmap_add(map, key1, content1);
+	key1->value = 3;
+	etchmap_add(map, key1, content2);
+	
+	count = etchmap_count(map);
+	CU_ASSERT_TRUE(count == 1);
+}
+
+/**
+ * test_new_etch_hashtable
+ * unit test for new_etch_hashtable
+ */
+//void test_new_etch_hashtable(void)
+//{
+//    /* new_etch_hashtable does not have meat in it */
+//    etch_hashtable* eht = new_etch_hashtable();
+//    CU_ASSERT_PTR_NOT_NULL_FATAL(eht);
+//    CU_ASSERT_PTR_NULL(eht->realtable);
+//    CU_ASSERT_PTR_NULL(((etch_object*)eht)->vtab);
+//    etch_free(eht);
+//}
+
+/**
+ * test_destroy_hashtable
+ * unit test for destroy_hashtable
+ */
+//void test_destroy_hashtable(void)
+//{
+//    wchar_t *key = NULL, *val = NULL;
+//
+//    /* try to delete key and value but nothing in it */
+//    etch_hashtable* eht = new_etch_hashtable();
+//    destroy_hashtable(eht, TRUE, TRUE);
+//
+//    /* negative test with NULL hash table */
+//    destroy_hashtable(NULL, TRUE, TRUE);
+//
+//    /* TODO: add more cases to verify key/value deletion */
+//}
+
+/**
+ * test_jenkins_insert
+ * unit test for jenkins_insert
+ */
+static void test_jenkins_insert(void)
+{
+    int keylen = 0, vallen=0;
+    wchar_t key[100];
+
+    etch_hashtable* eht = new_hashtable(16);
+    
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+
+    etch_snwprintf(key, 100, L"key%d", 0);
+    keylen = (int)wcslen(key);
+    vallen = 3;
+    jenkins_insert(eht->realtable, key, (keylen+1)*sizeof(wchar_t), L"val", (vallen+1)*sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+    /* insert the same key value pair */
+    jenkins_insert(eht->realtable, key, (keylen+1)*sizeof(wchar_t), L"val", (vallen+1)*sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    /* insert the same key but different value */
+    jenkins_insert(eht->realtable, key, (keylen+1)*sizeof(wchar_t), L"va1", (vallen+1)*sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    /* insert different key but the same value */
+    etch_snwprintf(key, 100, L"key%d", 1);
+    jenkins_insert(eht->realtable, key, (keylen+1)*sizeof(wchar_t), L"val", (vallen+1)*sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* insert different key value pair */
+    etch_snwprintf(key, 100, L"key%d", 2);
+    jenkins_insert(eht->realtable, key, (keylen+1)*sizeof(wchar_t), L"va1", (vallen+1)*sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 3);
+
+    /* insert NULL key and value */
+    jenkins_insert(eht->realtable, NULL, 0, NULL, 0, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 3);
+
+    etch_object_destroy(eht);
+}
+
+/**
+ * test_jenkins_find
+ * unit test for jenkins_find
+ */
+static void test_jenkins_find(void)
+{
+    int result = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+    etch_hashitem* outentry;
+    etch_hashtable* eht = 0;
+
+    eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(key1, 100, L"key%d", 1);
+    etch_snwprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(val1, 100, L"val%d", 1);
+    etch_snwprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, (keylen + 1)*sizeof(wchar_t), val1, (vallen + 1)*sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    /* get first, first key = first key */
+    result = jenkins_find(eht->realtable, key2, keylen*2+2, 0, &outentry);
+    CU_ASSERT_EQUAL(result, -1);
+
+    jenkins_insert(eht->realtable, key2, keylen*2+2, val2, vallen*2+2, 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* get first, first key = first key */
+    result = jenkins_find(eht->realtable, key2, keylen*2+2, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry->key);
+
+    etch_object_destroy(eht);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_jenkins_findh
+ * unit test for jenkins_findh
+ */
+static void test_jenkins_findh(void)
+{
+    int result = 0, keylen = 0, vallen = 0, hash = 0, bytes_allocated = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+    etch_hashitem* outentry;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key   = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(key1, 100, L"key%d", 1);
+    etch_snwprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(val1, 100, L"val%d", 1);
+    etch_snwprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, (keylen + 1) * sizeof(wchar_t), val1, (vallen + 1) * sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+    jenkins_insert(eht->realtable, key2, (keylen + 1) * sizeof(wchar_t), val2, (vallen + 1) * sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* Find the second key */
+    result = jenkins_find(eht->realtable, key2, (keylen + 1) * sizeof(wchar_t), 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry->key);
+
+    etch_object_destroy(eht);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * etch_testobject  
+ * test object for test_jenkins_inserth
+ */
+typedef struct etch_testobject
+{
+    etch_object object;
+
+    char* hashvalue; 
+
+} etch_testobject; 
+
+
+ 
+/**
+ * test_inserth_get_hashkey
+ * object hashkey computation virtual for test_jenkins_inserth
+ * attempts to compute and set hashkey in object, returning hashkey so set, or zero.
+ */
+static int test_inserth_get_hashkey(etch_object* obj)
+{
+    char* hashitem = ((etch_testobject*)obj)->hashvalue;
+    if (NULL == hashitem) return 0;
+    return obj->hashkey = jenkins_hashx(hashitem, (int) strlen(hashitem), 0);
+}
+
+
+/**
+ * new_testobject  
+ * construct test object for test_jenkins_inserth
+ * illustrates that constructor should set the get_hashkey virtual.
+ */
+static etch_testobject* new_testobject(char* hashsource)
+{
+   etch_testobject* newobj = (etch_testobject*) new_object
+        (sizeof(etch_testobject), ETCHTYPEB_NONE, CLASSID_NONE);
+
+   newobj->hashvalue = hashsource;
+
+   ((etch_object*)newobj)->get_hashkey = test_inserth_get_hashkey;
+
+   ((etch_object*)newobj)->get_hashkey((etch_object*)newobj);
+
+   return newobj;
+}
+
+
+
+/**
+ * test_inserth_freehandler
+ * hashtable content memory management callback for test_jenkins_inserth
+ */
+static int test_inserth_freehandler(etch_object* key, etch_object* val)
+{
+    etch_object_destroy(key);
+    etch_object_destroy(val);
+    return 0;
+}
+
+
+/**
+ * test_jenkins_inserth
+ * unit test for jenkins_inserth
+ * this test was written before the etch etch_object* included a get_hashkey virtual
+ */
+static void test_jenkins_inserth(void)
+{
+    int result = 0; 
+    unsigned hash1 = 0, hash2 = 0;
+    etch_hashitem outentry, *outitem = &outentry; 
+    char *s1 = "abracadabra", *s2 =  "gilgamesh";
+    etch_testobject *key1, *key2;
+    etch_object *val1, *val2;
+    etch_hashtable* eht;
+    memset(outitem, 0, sizeof(etch_hashitem));   
+
+    key1 = new_testobject(s1);
+    key2 = new_testobject(s2);
+
+    val1 = new_object(sizeof(etch_object), ETCHTYPEB_NONE, CLASSID_NONE);
+    val2 = new_object(sizeof(etch_object), ETCHTYPEB_NONE, CLASSID_NONE);
+
+    eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(eht);
+
+    /* set hook to free all hashtable content when we destroy hashtable */
+    eht->freehook = test_inserth_freehandler;
+
+    CU_ASSERT_NOT_EQUAL_FATAL(((etch_object*)key1)->hashkey, 0); /* ensure test object ctor set hashkey */
+    CU_ASSERT_NOT_EQUAL_FATAL(((etch_object*)key2)->hashkey, 0);
+    /* recompute expected hashkeys and compare to effective hashkeys */
+    hash1 = jenkins_hashx(s1, (int) strlen(s1), 0);
+    hash2 = jenkins_hashx(s2, (int) strlen(s2), 0);
+    CU_ASSERT_EQUAL(hash1,((etch_object*)key1)->hashkey);
+    CU_ASSERT_EQUAL(hash2,((etch_object*)key2)->hashkey);
+
+    /* insert pairs to map using the pre-computed hashkeys */
+    result = jenkins_inserth(eht->realtable, key1, val1, NULL, NULL);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    result = jenkins_inserth(eht->realtable, key2, val2, NULL, NULL);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* look them up using expected hashkeys */
+    result = jenkins_findh(eht->realtable, hash1, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key1, outentry.key);
+
+    result = jenkins_findh(eht->realtable, hash2, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry.key);
+
+    etch_object_destroy(eht);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+ 
+/**
+ * default_get_hashkey
+ * object hashkey computation virtual for test_default_hashkey
+ * attempts to compute and set a hashkey in object, 
+ * for use when no dedicated override is supplied.
+ */
+static int default_get_hashkey(etch_object* obj)
+{
+    void* hashitem = obj;  /* we use the object address as hash source */
+    return obj->hashkey = jenkins_hashx((char*)&hashitem, sizeof(void*), 0);
+}
+
+
+/**
+ * new_default_object
+ * test object constructor for test_default_hashkey
+ * sets a default hashkey function and invokes it
+ */
+static etch_testobject* new_default_object()
+{
+   etch_testobject* newobj = (etch_testobject*) new_object
+        (sizeof(etch_testobject), ETCHTYPEB_NONE, CLASSID_NONE);
+
+   ((etch_object*)newobj)->get_hashkey = default_get_hashkey;
+
+   ((etch_object*)newobj)->get_hashkey((etch_object*)newobj);
+
+   return newobj;
+}
+
+
+/**
+ * test_default_hashkey
+ * unit test for hashing using the default hashkey function
+ * this test was written before the etch etch_object* included a get_hashkey virtual
+ */
+static void test_default_hashkey(void)
+{
+    int result = 0; 
+    unsigned hash1 = 0, hash2 = 0;
+    etch_hashitem outentry, *outitem = &outentry; 
+    etch_testobject *key1, *key2, *val1, *val2;
+    etch_hashtable* eht;
+    memset(outitem, 0, sizeof(etch_hashitem));   
+
+    key1 = new_default_object();
+    key2 = new_default_object();
+    CU_ASSERT_NOT_EQUAL_FATAL(((etch_object*)key1)->hashkey, 0); /* ensure test object ctor set hashkey */
+    CU_ASSERT_NOT_EQUAL_FATAL(((etch_object*)key2)->hashkey, 0);
+    val1 = new_default_object();
+    val2 = new_default_object();
+    eht = new_hashtable(32);
+    /* set hook to free all hashtable content when we destroy hashtable */
+    eht->freehook = test_inserth_freehandler;
+
+    /* insert pairs to map using the pre-computed hashkeys */
+    result = jenkins_inserth(eht->realtable, key1, val1, NULL, NULL);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    result = jenkins_inserth(eht->realtable, key2, val2, NULL, NULL);
+    CU_ASSERT_EQUAL(result,0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* look them up using effective hashkeys */
+    result = jenkins_findh(eht->realtable, ((etch_object*)key1)->hashkey, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key1, outentry.key);
+
+    result = jenkins_findh(eht->realtable, ((etch_object*)key2)->hashkey, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry.key);
+
+    /* compute expected hashkeys from addresses of key objects */
+    hash1 = jenkins_hashx((char*)&key1, sizeof(void*), 0);
+    hash2 = jenkins_hashx((char*)&key2, sizeof(void*), 0);
+
+    /* look them up using computed hashkeys */
+    result = jenkins_findh(eht->realtable, hash1, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key1, outentry.key);
+
+    result = jenkins_findh(eht->realtable, hash2, 0, &outitem);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry.key);
+
+    etch_object_destroy(eht);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_jenkins_first
+ * unit test for jenkins_first
+ */
+static void test_jenkins_first(void)
+{
+    int result = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+    etch_hashitem* outentry;
+    int ptrEqual;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(key1, 100, L"key%d", 1);
+    etch_snwprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(val1, 100, L"val%d", 1);
+    etch_snwprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, (keylen + 1) * sizeof(wchar_t), val1, (vallen + 1) * sizeof(wchar_t), 0, 0);
+    jenkins_insert(eht->realtable, key2, (keylen + 1) * sizeof(wchar_t), val2, (vallen + 1) * sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* get first, first key = first key */
+    result = jenkins_first(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    printf("jenkins_first: %ls=%ls\n", key1, (wchar_t*)outentry->key);
+    ptrEqual = key1 == (wchar_t*)outentry->key || 
+                key2 == (wchar_t*)outentry->key;
+    CU_ASSERT_TRUE(ptrEqual);
+
+    /* next is key2 */
+    result = jenkins_next(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    ptrEqual = key1 == (wchar_t*)outentry->key || 
+                key2 == (wchar_t*)outentry->key;
+    CU_ASSERT_TRUE(ptrEqual);
+
+    etch_object_destroy(eht);
+}
+
+
+/**
+ * test_jenkins_next
+ * unit test for jenkins_next
+ */
+static void test_jenkins_next(void)
+{
+    int result = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* key3 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+    wchar_t* val3 = 0;
+    etch_hashitem* outentry;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    key3 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(key1, 100, L"key%d", 1);
+    etch_snwprintf(key2, 100, L"key%d", 2);
+    etch_snwprintf(key3, 100, L"key%d", 3);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    val3 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(val1, 100, L"val%d", 1);
+    etch_snwprintf(val2, 100, L"val%d", 2);
+    etch_snwprintf(val3, 100, L"val%d", 3);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, (keylen+1)*sizeof(wchar_t), val1, (vallen+1)*sizeof(wchar_t), 0, 0);
+    jenkins_insert(eht->realtable, key2, (keylen+1)*sizeof(wchar_t), val2, (vallen+1)*sizeof(wchar_t), 0, 0);
+    jenkins_insert(eht->realtable, key3, (keylen+1)*sizeof(wchar_t), val3, (vallen+1)*sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 3);
+
+    result = jenkins_first(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+
+    result = jenkins_next(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+
+    result = jenkins_next(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+
+    result = jenkins_next(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, -1);
+
+    etch_object_destroy(eht);
+}
+
+
+/**
+ * test_jenkins_current
+ * unit test for jenkins_current
+ */
+static void test_jenkins_current(void)
+{
+    int result = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+    etch_hashitem* outentry;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    /* get current, no key */
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+    result = jenkins_current(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, -1);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(key1, 100, L"key%d", 1);
+    etch_snwprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(val1, 100, L"val%d", 1);
+    etch_snwprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, (keylen+1)*sizeof(wchar_t), val1, (vallen+1)*sizeof(wchar_t), 0, 0);
+    jenkins_insert(eht->realtable, key2, (keylen+1)*sizeof(wchar_t), val2, (vallen+1)*sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+
+    /* get current, current key = key2 */
+    result = jenkins_current(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry->key);
+
+    /* remove second entry */
+    result = jenkins_remove(eht->realtable, key2, (keylen+1)*sizeof(wchar_t), 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key2, outentry->key);
+
+    /* get current, current key = key1 */
+    result = jenkins_current(eht->realtable, 0, &outentry);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_PTR_EQUAL(key1, outentry->key);
+
+    etch_object_destroy(eht);
+}
+
+/**
+ * test_jenkins_remove
+ * unit test for jenkins_remove
+ */
+static void test_jenkins_remove(void)
+{
+    int count = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    //wchar_t* val2 = 0;
+    etch_hashitem* outentry;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(key1, 100, L"key%d", 1);
+    etch_snwprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    //val2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(val1, 100, L"val%d", 1);
+    //etch_snwprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    outentry = (etch_hashitem*)malloc(sizeof(etch_hashitem)); 
+    outentry->key   = malloc(sizeof(wchar_t) * 100);
+    outentry->value = malloc(sizeof(wchar_t) * 100);
+
+    jenkins_insert(eht->realtable, key1, (keylen+1)*sizeof(wchar_t), val1, (vallen+1)*sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+
+    /* remove wrong entry */
+    count = jenkins_remove(eht->realtable, key2, (keylen+1)*sizeof(wchar_t), 0, &outentry);
+    CU_ASSERT_EQUAL(count, -1);
+
+    /* remove the entry */
+    count = jenkins_remove(eht->realtable, key1,(keylen+1)*sizeof(wchar_t), 0, &outentry);
+    CU_ASSERT_EQUAL(count, 0);
+    CU_ASSERT_PTR_EQUAL(key1, outentry->key);
+
+    etch_object_destroy(eht);
+}
+
+
+/**
+ * test_jenkins_clear
+ * unit test for jenkins_clear
+ */
+static void test_jenkins_clear(void)
+{
+    int count = 0, keylen = 0, vallen = 0;
+    wchar_t* key1 = 0;
+    wchar_t* key2 = 0;
+    wchar_t* val1 = 0;
+    wchar_t* val2 = 0;
+
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+
+    key1 = malloc(sizeof(wchar_t) * 100);
+    key2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(key1, 100, L"key%d", 1);
+    etch_snwprintf(key2, 100, L"key%d", 2);
+    keylen = (int)wcslen(key1);
+
+    val1 = malloc(sizeof(wchar_t) * 100);
+    val2 = malloc(sizeof(wchar_t) * 100);
+    etch_snwprintf(val1, 100, L"val%d", 1);
+    etch_snwprintf(val2, 100, L"val%d", 2);
+    vallen = (int)wcslen(val1);
+
+    jenkins_insert(eht->realtable, key1, (keylen+1)*sizeof(wchar_t), val1, (vallen+1)*sizeof(wchar_t), 0, 0);
+    jenkins_insert(eht->realtable, key2, (keylen+1)*sizeof(wchar_t), val2, (vallen+1)*sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 2);
+    count = jenkins_clear(eht->realtable, TRUE, TRUE, 0, 0);
+    /* clear 2 key/val pair */
+    CU_ASSERT_EQUAL(count, 2);
+    CU_ASSERT_PTR_NOT_NULL(eht->realtable);
+
+    etch_object_destroy(eht);
+}
+
+
+/**
+ * test_jenkins_count
+ * unit test for jenkins_count
+ */
+static void test_jenkins_count(void)
+{
+    etch_hashtable* eht = new_hashtable(32);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+    jenkins_insert(eht->realtable, L"key", 4 * sizeof(wchar_t), L"val", 4 * sizeof(wchar_t), 0, 0);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 1);
+    etch_object_destroy(eht);
+}
+
+/**
+ * test_jenkins_size
+ * unit test for jenkins_size
+ */
+static void test_jenkins_size(void)
+{
+    int i = 0;
+    int keylen = 0;
+    wchar_t key[100];
+
+    etch_hashtable* eht = new_hashtable(16);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+    for (i=0; i<17; i++)
+    {
+        etch_snwprintf(key, 100, L"key%d", i);
+        keylen = (int)wcslen(key);
+        jenkins_insert(eht->realtable, key, (keylen + 1) * sizeof(wchar_t), L"val", 4 * sizeof(wchar_t), 0, 0);
+    }
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 32);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 17);
+    etch_object_destroy(eht);
+}
+
+/**
+ * test_jenkins_stats
+ * unit test for jenkins_stats
+ */
+static void test_jenkins_stats(void)
+{
+    
+}
+
+/**
+ * test_jenkins_hash
+ * unit test for jenkins_hash
+ */
+//void test_jenkins_hash(void)
+//{
+//    int hash = 0;
+//
+//    etch_hashtable* eht = new_etch_hashtable();
+//    CU_ASSERT_PTR_NOT_NULL(eht);
+//    CU_ASSERT_PTR_NULL(eht->realtable);
+//    /* realtable is NULL */
+//    hash = jenkins_hash(eht->realtable, "key", 3, 0, 0, 0);
+//    CU_ASSERT_EQUAL(hash, 0);
+//    destroy_hashtable(eht, TRUE, TRUE);
+//
+//    eht = new_hashtable(16);
+//    CU_ASSERT_PTR_NOT_NULL(eht);
+//    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+//    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+//    /* key is NULL */
+//    hash = jenkins_hash(eht->realtable, 0, 0, 0, 0, 0);
+//    CU_ASSERT_EQUAL(hash, 0);
+//    /* key length is 0 */
+//    hash = jenkins_hash(eht->realtable, "key", 0, 0, 0, 0);
+//    CU_ASSERT_EQUAL(hash, 0);
+//    /* key length is MAX_ETCHHASHKEY + 1 */
+//    hash = jenkins_hash(eht->realtable, "key", MAX_ETCHHASHKEY+1, 0, 0, 0);
+//    CU_ASSERT_EQUAL(hash, 0);
+//    /* get a good hash */
+//    hash = jenkins_hash(eht->realtable, "key", 3, 0, 0, 0);
+//    CU_ASSERT_NOT_EQUAL(hash, 0);
+//    /* hash should be the same is input arguments are the same */
+//    CU_ASSERT_EQUAL(hash, jenkins_hash(eht->realtable, "key", 3, 0, 0, 0));
+//    /* hash should be different if input arguments are different */
+//    CU_ASSERT_NOT_EQUAL(hash, jenkins_hash(eht->realtable, "kee", 3, 0, 0, 0));
+etch_object_destroy(eht);
+//}
+
+
+/**
+ * test_intkey
+ * test using a 32 bit int as a key
+ */
+#pragma warning (disable:4996)
+static void test_intkey(void)
+{
+  	etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket;
+    char* test_string = "it works"; 
+    unsigned int key = 12345, key2 = 11111, key3 = 11111;
+    int value_len = (int)strlen(test_string)+1; /* string length of value */
+    struct i_hashtable* vtab = NULL;
+    etch_hashtable* ht = new_hashtable(4);
+
+    /* our hash key is a 4-byte item, which we will use to contain the 
+       value of a 32 bit int.
+     */
+	char* pkey = malloc(sizeof(int));
+
+    /*  the string pval is our hash value */
+    char* pval = malloc(value_len);  
+    strcpy(pval, test_string); 
+
+    /* copy the int into our hash key.
+     */
+    memcpy(pkey, &key, sizeof(int));
+    vtab = (struct i_hashtable*)((etch_object*)ht)->vtab;
+    CU_ASSERT_EQUAL(vtab->insert(ht->realtable, pkey, sizeof(int), pval, value_len, 0, 0), 0);
+    CU_ASSERT_EQUAL(vtab->find  (ht->realtable, pkey, sizeof(int), NULL, &myentry), 0);
+    CU_ASSERT_EQUAL(vtab->find  (ht->realtable, &key, sizeof(int), NULL, &myentry), 0);
+
+    /* test two pointers to the same value.
+     */
+    CU_ASSERT_EQUAL(vtab->insert(ht->realtable, &key2, sizeof(int), pval, value_len, 0, 0), 0);
+    CU_ASSERT_EQUAL(vtab->find  (ht->realtable, &key3, sizeof(int), NULL, &myentry), 0);
+
+    destroy_hashtable(ht, FALSE, FALSE);
+    free(pkey);
+    free(pval);
+}
+
+
+/**
+ * test_jenkins_destroy
+ * unit test for jenkins_destroy
+ */
+//void test_jenkins_destroy(void)
+//{
+//    int result = 0;
+//
+//    etch_hashtable* eht = new_etch_hashtable();
+//    CU_ASSERT_PTR_NOT_NULL(eht);
+//    CU_ASSERT_PTR_NULL(eht->realtable);
+//    /* realtable is NULL */
+//    result = jenkins_destroy(eht->realtable, 0, 0);
+//    CU_ASSERT_EQUAL(result, -1);
+//
+//    eht = new_hashtable(16);
+//    CU_ASSERT_PTR_NOT_NULL(eht);
+//    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+//    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+//    /* realtable is not NULL */
+//    result = jenkins_destroy(eht->realtable, 0, 0);
+//    CU_ASSERT_EQUAL(result, 0);
+//}
+
+/**
+ * test_jenkins_create
+ * unit test for jenkins_create
+ */
+//void test_jenkins_create(void)
+//{
+//    int result = 0;
+//
+//    etch_hashtable* eht = new_etch_hashtable();
+//    CU_ASSERT_PTR_NOT_NULL(eht);
+//    CU_ASSERT_PTR_NULL(eht->realtable);
+//    /* realtable is NULL */
+//    result = jenkins_create(16, 0, eht->realtable);
+//    CU_ASSERT_EQUAL(result, -1);
+//    destroy_hashtable(eht, FALSE, FALSE);
+//
+//    eht = new_hashtable(16);
+//    CU_ASSERT_PTR_NOT_NULL(eht);
+//    CU_ASSERT_PTR_NOT_NULL(eht->realtable);
+//    /* realtable is NULL */
+//    result = jenkins_create(16, 0, eht->realtable);
+//    CU_ASSERT_EQUAL(result, 0);
+//    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+//    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+//    destroy_hashtable(eht, FALSE, FALSE);
+//}
+
+/**
+ * test_ctor_jenkins_hashtable
+ * unit test for ctor_jenkins_hashtable
+ */
+static void test_ctor_jenkins_hashtable(void)
+{
+    etch_hashtable* eht = ctor_jenkins_hashtable(16);
+    CU_ASSERT_PTR_NOT_NULL(eht);
+    CU_ASSERT_PTR_NOT_NULL(eht->realtable);
+    CU_ASSERT_PTR_NOT_NULL(((etch_object*)eht)->vtab);
+    CU_ASSERT_EQUAL(jenkins_size(eht->realtable, 0, 0), 16);
+    CU_ASSERT_EQUAL(jenkins_count(eht->realtable, 0, 0), 0);
+
+    destroy_hashtable(eht, FALSE, FALSE);
+}
+
+
+#pragma warning (disable:4996)
+
+/*
+ * test_key_pointer: test using a memory address as a hash key.
+ * return 1 if OK, zero if failed.
+ */
+static int test_key_pointer(etch_hashtable* ht)
+{
+	etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket;
+    char* test_string = "it works"; 
+    const int value_len = (int)strlen(test_string)+1; /* string length of value */
+    const int key_len = sizeof(char*); 
+
+    /* our hash key is a 4-byte item, which we will use to contain the 
+       value of a memory address.
+     */
+	char* pkey = malloc(key_len);
+
+    /* the value of the pval memory address is our hash key.
+     * the string pval is our hash value. Of course, our hash table stores pointers,
+     * not values, so the key is &pval, and the value is pval.
+     */
+    char* pval = malloc(value_len);  
+    strcpy(pval, test_string); 
+
+    /* copy the memory address into our hash key.
+     */
+    memcpy(pkey, &pval, sizeof(char*));
+
+    CU_ASSERT_EQUAL(((struct i_hashtable*)((etch_object*)ht)->vtab)->insert(ht->realtable, pkey, key_len, pval, value_len, 0, 0), 0);
+
+    CU_ASSERT_EQUAL(((struct i_hashtable*)((etch_object*)ht)->vtab)->find(ht->realtable, pkey, key_len, NULL, &myentry), 0);
+
+    CU_ASSERT_PTR_NOT_NULL(myentry->value);
+
+    /* This code demonstrates what we've done here. The key is the value of a
+     * char*, and the value is that same char*. So, indirectly dereferencing  
+     * the key must elicit the same result as dereferencing the value. 
+     */
+    CU_ASSERT_EQUAL(memcmp(myentry->key, &myentry->value, sizeof(char*)), 0);
+    
+    CU_ASSERT_EQUAL(strcmp(*(char**)myentry->key, (char*)myentry->value), 0);
+
+	return 1;
+}
+
+/**
+ * test_all
+ * unit test for various functions strung together
+ */
+static void test_combo(void)
+{
+    char  buf[MAXLINELEN];
+    char* pkey; void* pdata;
+    int   n, keylen, myincount=0, myhashcount=0, myfreecount=0;
+    etch_hashtable* myhash;
+    etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket;
+    unsigned hashed;
+    char  c = 0, *p;
+    FILE* f = 0;
+    p = "abracadabra"; n = (int)strlen(p); // Test the hash function
+    hashed = etchhash(p, n, 0);
+
+    f = fopen(TESTDATAPATH,"r");
+    CU_ASSERT_PTR_NOT_NULL_FATAL(f);
+
+    myhash = new_hashtable(INITIAL_TABLE_SIZE);  /* create hash table */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(myhash);
+
+    ((struct i_hashtable*)((etch_object*)myhash)->vtab)->stats(myhash->realtable, 0, 0); /* show table stats */
+    n = ((struct i_hashtable*)((etch_object*)myhash)->vtab)->size(myhash->realtable, 0, 0);
+    CU_ASSERT_EQUAL(n, INITIAL_TABLE_SIZE);
+  
+    while (fgets((char*)buf, MAXLINELEN, f))   /* read the testdata file line by line */ 
+    {
+        unsigned char* p = buf; while(*p++) if (*p <= 0x0d) *p = 0;       /* strip crlf */
+        keylen = (int)strlen(buf);   /* we use null termed key, but it is not necessary */ 
+        pkey   = malloc(keylen+1); strcpy(pkey, buf);    
+        pdata  = malloc(DATASIZE);  /* note that user allocates memory for key and data */
+        strcpy(pdata, DATAVALUE);   /* hashtable does not make copies of key or of data */
+                                    /* insert the new hashtable entry */          
+        if  (0 == ((struct i_hashtable*)((etch_object*)myhash)->vtab)->insert(myhash->realtable, pkey, keylen, pdata, DATASIZE, 0, 0))         
+        {    myincount++;           /* point at current entry in hashtable */
+             ((struct i_hashtable*)((etch_object*)myhash)->vtab)->current(myhash->realtable, 0, &myentry);  
+             CU_ASSERT_PTR_EQUAL(myentry->key, pkey); /* ensure items just inserted are there */
+             CU_ASSERT_PTR_EQUAL(myentry->value, pdata);
+        }
+        else                        /* insert failure - probably duplicate */
+        {    free(pkey);  
+             free(pdata);
+        }
+    }
+
+    fclose(f); f = 0;
+    ((struct i_hashtable*)((etch_object*)myhash)->vtab)->stats(myhash->realtable, 0, 0); /* show table stats */ 
+
+    pkey = "banana";  /* test a hashtable lookup */
+
+    CU_ASSERT_EQUAL(((struct i_hashtable*)((etch_object*)myhash)->vtab)->find(myhash->realtable, pkey, (int)strlen(pkey), NULL, &myentry), 0);
+    CU_ASSERT_EQUAL(strcmp(pkey, myentry->key), 0);
+
+    CU_ASSERT_EQUAL(((struct i_hashtable*)((etch_object*)myhash)->vtab)->first(myhash->realtable, NULL, &myentry), 0);
+    myhashcount = 1;
+
+    while(0 == ((struct i_hashtable*)((etch_object*)myhash)->vtab)->next(myhash->realtable, NULL, &myentry))          
+    {    
+        myhashcount++;
+    }
+
+    /* test using pointer as key, adding 0 or 1 to myhashcount */
+    myhashcount += test_key_pointer(myhash);
+
+    /* destroy hash table and all its contents (free key and data memory) */
+    myfreecount = ((struct i_hashtable*)((etch_object*)myhash)->vtab)->clear(myhash->realtable, TRUE, TRUE, 0, 0);
+
+    CU_ASSERT_EQUAL(myfreecount, myhashcount);
+}
+
+
+/**
+ * _tmain
+ * unit test entry point
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_hashtable_suite()
+{
+    CU_pSuite ps = CU_add_suite("suite_etchhash", init_suite, clean_suite);
+   
+    CU_add_test(ps, "new_hashtable", test_new_hashtable);
+    //CU_add_test(ps, "new_etch_hashtable", test_new_etch_hashtable);
+    //CU_add_test(ps, "destroy_hashtable", test_destroy_hashtable);
+    //CU_add_test(ps, "jenkins_hash", test_jenkins_hash);
+    CU_add_test(ps, "jenkins_find", test_jenkins_find);
+    CU_add_test(ps, "jenkins_findh", test_jenkins_findh);
+    CU_add_test(ps, "jenkins default key", test_default_hashkey);
+    CU_add_test(ps, "jenkins_first", test_jenkins_first);
+    CU_add_test(ps, "jenkins_next", test_jenkins_next);
+    CU_add_test(ps, "jenkins_current", test_jenkins_current);  
+    CU_add_test(ps, "jenkins_remove", test_jenkins_remove);  
+    CU_add_test(ps, "jenkins_clear", test_jenkins_clear);  
+    CU_add_test(ps, "jenkins_count", test_jenkins_count);  
+    CU_add_test(ps, "jenkins_size", test_jenkins_size);  
+    CU_add_test(ps, "jenkins_insert", test_jenkins_insert);  
+    CU_add_test(ps, "jenkins_inserth", test_jenkins_inserth);  
+    CU_add_test(ps, "jenkins_stats", test_jenkins_stats);  
+    //CU_add_test(ps, "jenkins_destroy", test_jenkins_destroy);  
+    //CU_add_test(ps, "jenkins_create", test_jenkins_create);  
+    CU_add_test(ps, "ctor_jenkins_hashtable", test_ctor_jenkins_hashtable);   
+    CU_add_test(ps, "test integer key", test_intkey);  
+    CU_add_test(ps, "test combinations", test_combo);    
+	CU_add_test(ps, "test map", test_map);    
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/common/test_iterator.c b/binding-c/runtime/c/src/test/common/test_iterator.c
new file mode 100644
index 0000000..e85c151
--- /dev/null
+++ b/binding-c/runtime/c/src/test/common/test_iterator.c
@@ -0,0 +1,335 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_iterator.c -- test etch_iterator over i_iterable classes
+ */
+#include "etch_runtime.h"
+#include "etch_arraylist.h"
+#include "etch_hash.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+#include <wchar.h>
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+static etch_arraylist* testlist;
+static etch_hashtable* testhash;
+
+/* 
+ * load_listdata_int()
+ * load testlist array with some etch_int32 objects
+ */
+static int load_listdata_int()
+{
+    int i = 0, numitems = 4;
+    etch_int32* newobj = NULL;
+    int ints[4] = { 1, 2, 3, 4 };
+
+    for(; i < numitems; i++)
+    {
+        newobj = new_int32(ints[i]);
+        etch_arraylist_add(testlist, newobj);
+    }
+
+    return numitems;
+}
+
+
+/* 
+ * new_listdata()
+ * create testlist array and load it up with data objects
+ */
+static int new_listdata(const int datatype)
+{
+    int count = 0;
+    testlist = new_etch_arraylist(0,0);  
+    testlist->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
+    count = load_listdata_int(); 
+    return count;
+}
+
+
+/* 
+ * destroy_listdata()
+ * destroy testlist array and content
+ */
+static void destroy_listdata()
+{
+    etch_arraylist_destroy(testlist, TRUE);
+}
+
+
+/* 
+ * load_hashdata_string()
+ * load testhash hashtable with some etch_string objects
+ */
+static int load_hashdata_string()
+{
+    int i = 0, numitems = 4, result = 0;
+    //wchar_t* testval = NULL;
+    void* key = NULL;
+    etch_string* newobj = NULL;
+    wchar_t* str0 = L"now ", *str1 = L"is  ", *str2 = L"the ", *str3 = L"time";
+    wchar_t* strings[4] = { str0, str1, str2, str3 };
+    const size_t bytelen = (wcslen(str0) + 1) * sizeof(wchar_t);
+
+    for(; i < numitems; i++)
+    {
+        //testval = etch_malloc(bytelen, 0);
+        //memcpy(testval, strings[i], bytelen);
+        newobj = new_stringw(strings[i]); 
+
+        key  = etch_malloc(bytelen, 0);
+        memcpy(key, strings[i], bytelen);
+
+        result = ((struct i_hashtable*)((etch_object*)testhash)->vtab)->insert(testhash->realtable, 
+                 key, (int)bytelen, newobj, 0, NULL, NULL);
+    }
+
+    return numitems;
+}
+
+
+/* 
+ * new_hashdata()
+ * create testhash hashtable and load it up with data objects
+ */
+static int new_hashdata(const int datatype)
+{
+    int count = 0;
+    testhash = new_hashtable(16);  
+    count = load_hashdata_string();
+    return count;
+}
+
+
+/* 
+ * destroy_hashdata()
+ * destroy testhash hashtable and content
+ */
+static void destroy_hashdata()
+{
+    destroy_hashtable(testhash, TRUE, TRUE);
+}
+
+
+/* 
+ * test_iterator_over_arraylist
+ */
+static void test_iterator_over_arraylist(void)
+{
+    etch_iterator* iterator = NULL; 
+    int testcount = 0, thiscount = 0;
+    testcount = new_listdata(0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(testlist);
+    CU_ASSERT_NOT_EQUAL(testlist->count, 0);
+
+    iterator = new_iterator(testlist, &testlist->iterable);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+    CU_ASSERT_EQUAL_FATAL(iterator->ordinal,1);
+
+    while(iterator->has_next(iterator))
+          thiscount += (iterator->next(iterator) == 0);  
+        
+    CU_ASSERT_EQUAL(thiscount, testcount-1);
+
+    etch_object_destroy(iterator);
+    destroy_listdata();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_iterator_over_hashtable
+ */
+static void test_iterator_over_hashtable(void)
+{
+    etch_iterator* iterator = NULL; 
+    int result = 0, thiscount = 0, testcount = 0;
+    testcount = new_hashdata(1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(testhash);
+    CU_ASSERT_NOT_EQUAL(((struct i_hashtable*)((etch_object*)testhash)->vtab)->count(testhash->realtable,0,0),0);
+#ifdef ETCH_DEBUGALLOC
+    startbytes = etch_showmem(0, FALSE); /* note testdata bytes */
+#endif
+
+    iterator = new_iterator(testhash, &testhash->iterable);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(iterator->current_key);
+    CU_ASSERT_EQUAL_FATAL(iterator->ordinal,1);
+    thiscount = 1;
+
+    while(iterator->has_next(iterator))
+    {
+        if (0 != (result = iterator->next(iterator))) break;  
+         
+        thiscount++;
+        CU_ASSERT_PTR_NOT_NULL(iterator->current_key);
+        CU_ASSERT_PTR_NOT_NULL(iterator->current_value);
+
+        #if IS_DEBUG_CONSOLE       
+        if  (iterator->current_value)
+             wprintf(L"value is %s\n",(wchar_t*)iterator->current_value);
+        else wprintf(L"value is null\n");           
+        #endif       
+    } 
+        
+    CU_ASSERT_EQUAL(testcount, thiscount);
+
+    etch_object_destroy(iterator);
+    destroy_hashdata();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   g_bytes_allocated -= startbytes;
+   CU_ASSERT_TRUE(g_bytes_allocated <= 0);  
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_stack_allocated_iterator
+ * iterator as automatic variable
+ */
+static void test_stack_allocated_iterator(void)
+{
+    etch_iterator iterator;
+    struct i_iterable* vtab = NULL;
+    int testcount = 0, thiscount = 0;
+    testcount = new_listdata(0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(testlist);
+    CU_ASSERT_NOT_EQUAL(testlist->count, 0);
+    
+
+    set_iterator(&iterator, testlist, &testlist->iterable);
+
+    CU_ASSERT_EQUAL_FATAL(iterator.ordinal,1);
+    vtab = (struct i_iterable*)iterator.object.vtab;
+    while(vtab->has_next(&iterator))
+          thiscount += (vtab->next(&iterator) == 0);  
+        
+    CU_ASSERT_EQUAL(thiscount, testcount-1);
+
+    destroy_listdata();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_reset_iterator
+ * test reinitalizing and reusing iterator
+ */
+static void test_reset_iterator(void)
+{
+    etch_iterator iterator;
+    struct i_iterable* vtab = NULL;
+    int testcount = 0, thiscount1 = 0, thiscount2 = 0;
+
+    testcount = new_listdata(0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(testlist);
+    CU_ASSERT_NOT_EQUAL(testlist->count, 0);
+
+    set_iterator(&iterator, testlist, &testlist->iterable);
+
+    CU_ASSERT_EQUAL(iterator.ordinal,1);
+    vtab = (struct i_iterable*)iterator.object.vtab;
+    while(vtab->has_next(&iterator))
+          thiscount1 += (vtab->next(&iterator) == 0);  
+        
+    CU_ASSERT_EQUAL(thiscount1, testcount-1);
+
+    set_iterator(&iterator, testlist, &testlist->iterable);
+    vtab = (struct i_iterable*)iterator.object.vtab;
+    CU_ASSERT_EQUAL(iterator.ordinal,1);
+
+    while(vtab->has_next(&iterator))
+          thiscount2 += (vtab->next(&iterator) == 0); 
+ 
+    CU_ASSERT_EQUAL(thiscount2, thiscount1);    
+
+    destroy_listdata();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_iterator_suite()
+{    
+    CU_pSuite pSuite = CU_add_suite("suite_iterator", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test forward iterator over arraylist",   test_iterator_over_arraylist);
+    CU_add_test(pSuite, "test forward iterator over hashtable",   test_iterator_over_hashtable);
+    CU_add_test(pSuite, "test stack allocated iterator",   test_stack_allocated_iterator);
+    CU_add_test(pSuite, "test reset iterator",   test_reset_iterator);
+
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/etch-c-test.vcproj b/binding-c/runtime/c/src/test/etch-c-test.vcproj
new file mode 100644
index 0000000..274c9ad
--- /dev/null
+++ b/binding-c/runtime/c/src/test/etch-c-test.vcproj
@@ -0,0 +1,518 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8,00"

+	Name="etch-c-test"

+	ProjectGUID="{64A36C3F-2BE4-4471-A291-C65BD8A9E6FE}"

+	RootNamespace="etchctest"

+	Keyword="Win32Proj"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="target/win32/$(ConfigurationName)"

+			IntermediateDirectory="target/win32/$(ConfigurationName)"

+			ConfigurationType="1"

+			InheritedPropertySheets=".\etch-c-test.vsprops"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="..\..\include;..\extern\jenkhash;&quot;$(APR)\include&quot;;&quot;$(APR_ICONV)\include&quot;;&quot;$(CUNIT)\CUnit\Headers&quot;"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="3"

+				UsePrecompiledHeader="0"

+				ProgramDataBaseFileName="$(IntDir)\etch-c-test.pdb"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="libapr-1.lib libapriconv-1.lib  libcunit.lib WS2_32.LIB Mswsock.lib"

+				LinkIncremental="2"

+				AdditionalLibraryDirectories="$(APR)\Debug;$(APR_ICONV)\Debug;$(CUNIT)\VC8\Release - Static Lib\"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="target/win32/$(ConfigurationName)"

+			IntermediateDirectory="target/win32/$(ConfigurationName)"

+			ConfigurationType="1"

+			InheritedPropertySheets=".\etch-c-test.vsprops"

+			CharacterSet="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				AdditionalIncludeDirectories="..\..\include;..\extern\jenkhash;&quot;$(APR)\include&quot;;&quot;$(APR_ICONV)\include&quot;;&quot;$(CUNIT)\CUnit\Headers&quot;"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"

+				RuntimeLibrary="2"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="libapr-1.lib libapriconv-1.lib  libcunit.lib WS2_32.LIB Mswsock.lib"

+				LinkIncremental="1"

+				AdditionalLibraryDirectories="$(APR)\Release;$(APR_ICONV)\Release;$(CUNIT)\VC8\Release - Static Lib\"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Debug Static|Win32"

+			OutputDirectory="target/win32/$(ConfigurationName)"

+			IntermediateDirectory="target/win32/$(ConfigurationName)"

+			ConfigurationType="1"

+			InheritedPropertySheets=".\etch-c-test.vsprops"

+			CharacterSet="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="..\..\include;..\extern\jenkhash;&quot;$(APR)\include\win32_x86&quot;;&quot;$(APR)\include&quot;;&quot;$(APR_ICONV)\include&quot;;&quot;$(CUNIT)\include&quot;"

+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;APR_DECLARE_STATIC;API_DECLARE_STATIC"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="3"

+				ProgramDataBaseFileName="$(IntDir)\etch-c-test.pdb"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalOptions="/NODEFAULTLIB:LIBCMT"

+				AdditionalDependencies="apr-1.lib apriconv-1.lib  cunit.lib WS2_32.LIB Mswsock.lib"

+				LinkIncremental="2"

+				AdditionalLibraryDirectories="&quot;$(APR)\lib\win32_x86_Debug&quot;;&quot;$(APR_ICONV)\lib\win32_x86_Debug&quot;;&quot;$(CUNIT)\lib\win32_x86_Debug&quot;"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release Static|Win32"

+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			InheritedPropertySheets=".\etch-c-test.vsprops"

+			CharacterSet="1"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"

+				RuntimeLibrary="2"

+				UsePrecompiledHeader="0"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				LinkIncremental="1"

+				GenerateDebugInformation="true"

+				SubSystem="1"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Quelldateien"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\main.c"

+				>

+			</File>

+			<File

+				RelativePath=".\test_all.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_arraylist.c"

+				>

+			</File>

+			<File

+				RelativePath=".\message\test_arrayvalue.c"

+				>

+			</File>

+			<File

+				RelativePath=".\message\test_binarytditdo.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_cache.c"

+				>

+			</File>

+			<File

+				RelativePath=".\message\test_defvalufact.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_etch.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_etch_config.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_etch_encoding.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_etch_linked_list.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_etch_log.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_etch_mutex.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_etch_runtime.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_etch_thread.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_etch_wait.c"

+				>

+			</File>

+			<File

+				RelativePath=".\internal\test_etchinternal_single_linked_list.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_etchobject.c"

+				>

+			</File>

+			<File

+				RelativePath=".\message\test_field.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_flexbuf.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_hashing.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_hashtable.c"

+				>

+			</File>

+			<File

+				RelativePath=".\message\test_idname.c"

+				>

+			</File>

+			<File

+				RelativePath=".\common\test_iterator.c"

+				>

+			</File>

+			<File

+				RelativePath=".\transport\test_mailboxmgr.c"

+				>

+			</File>

+			<File

+				RelativePath=".\message\test_message.c"

+				>

+			</File>

+			<File

+				RelativePath=".\transport\test_messagizer.c"

+				>

+			</File>

+			<File

+				RelativePath=".\transport\test_packetizer.c"

+				>

+			</File>

+			<File

+				RelativePath=".\transport\test_plainmailbox.c"

+				>

+			</File>

+			<File

+				RelativePath=".\transport\test_queue.c"

+				>

+			</File>

+			<File

+				RelativePath=".\support\test_remote.c"

+				>

+			</File>

+			<File

+				RelativePath=".\message\test_structvalue.c"

+				>

+			</File>

+			<File

+				RelativePath=".\support\test_stub.c"

+				>

+			</File>

+			<File

+				RelativePath=".\transport\test_tcpconn.c"

+				>

+			</File>

+			<File

+				RelativePath=".\transport\test_threadpool.c"

+				>

+			</File>

+			<File

+				RelativePath=".\transport\test_transport.c"

+				>

+			</File>

+			<File

+				RelativePath=".\message\test_type.c"

+				>

+			</File>

+			<File

+				RelativePath=".\transport\test_url.c"

+				>

+			</File>

+			<File

+				RelativePath=".\message\test_validator.c"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Headerdateien"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath=".\test_all.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Ressourcendateien"

+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"

+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"

+			>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/binding-c/runtime/c/src/test/etch-c-test.vsprops b/binding-c/runtime/c/src/test/etch-c-test.vsprops
new file mode 100644
index 0000000..9512adc
--- /dev/null
+++ b/binding-c/runtime/c/src/test/etch-c-test.vsprops
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioPropertySheet

+	ProjectType="Visual C++"

+	Version="8.00"

+	Name="etch-c-test"

+	>

+	<Tool

+		Name="VCLinkerTool"

+		AdditionalLibraryDirectories=""

+	/>

+	<UserMacro

+		Name="APR"

+		Value="$(SolutionDir)src\extern\apr\apr"

+		PerformEnvironmentSet="true"

+	/>

+	<UserMacro

+		Name="APR_ICONV"

+		Value="$(SolutionDir)src\extern\apr\apr-iconv"

+		PerformEnvironmentSet="true"

+	/>

+	<UserMacro

+		Name="CUNIT"

+		Value="$(SolutionDir)src\extern\cunit"

+		PerformEnvironmentSet="true"

+	/>

+	<UserMacro

+		Name="VLD"

+		Value="$(SolutionDir)src\extern\vld"

+		PerformEnvironmentSet="true"

+	/>

+</VisualStudioPropertySheet>

diff --git a/binding-c/runtime/c/src/test/internal/test_etchinternal_single_linked_list.c b/binding-c/runtime/c/src/test/internal/test_etchinternal_single_linked_list.c
new file mode 100644
index 0000000..7d4bce9
--- /dev/null
+++ b/binding-c/runtime/c/src/test/internal/test_etchinternal_single_linked_list.c
@@ -0,0 +1,51 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "CUnit.h"
+#include "etchinternal_single_linked_list.h"
+
+static int intFinder(void* data, void* toFind) {
+  int iToFind = (int)toFind;
+  int intData = *((int*)data);
+  return iToFind == intData;
+}
+
+static void testFind() {
+  etchinternal_single_linked_list* l = etchinternal_single_linked_list_create();
+
+  int v = 1;
+  etchinternal_single_linked_list_add(l, &v, sizeof(v));
+  v = 2;
+  etchinternal_single_linked_list_add(l, &v, sizeof(v));
+
+  CU_ASSERT_EQUAL(1, etchinternal_single_linked_list_find(l, intFinder, (void*)1) != 0);
+  CU_ASSERT_EQUAL(1, etchinternal_single_linked_list_find(l, intFinder, (void*)2) != 0);
+  CU_ASSERT_EQUAL(0, etchinternal_single_linked_list_find(l, intFinder, (void*)3) != 0);
+
+  etchinternal_single_linked_list_destroy(l);
+}
+
+CU_pSuite test_etchinternal_single_linked_list()
+{
+  CU_pSuite pSuite = CU_add_suite("etchinternal_single_linked_list", 0, 0);
+  CU_add_test(pSuite, "testFind()", testFind); 
+  return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/jenktest.txt b/binding-c/runtime/c/src/test/jenktest.txt
new file mode 100644
index 0000000..1183597
--- /dev/null
+++ b/binding-c/runtime/c/src/test/jenktest.txt
@@ -0,0 +1,58 @@
+apple
+banana
+banter
+baseball
+blueberry
+brown
+browser
+camera
+can
+cantaloupe
+cherry
+cinnamon
+clear
+dash
+date
+distance
+ever
+ewe
+eye
+fig
+grape
+her
+lake
+leaf
+leave
+lemon
+lever
+lime
+mellon
+mango
+math
+music
+netscape
+never
+orange
+pear
+pepper
+politics
+psychedelic
+psychology
+salt
+science
+sift
+signals
+softball
+spice
+stupid
+swear
+syntax
+strawberry
+tangerine
+towel
+turn
+washcloth
+watermelon
+will
+words
+yellow
diff --git a/binding-c/runtime/c/src/test/main.c b/binding-c/runtime/c/src/test/main.c
new file mode 100644
index 0000000..2df5364
--- /dev/null
+++ b/binding-c/runtime/c/src/test/main.c
@@ -0,0 +1,109 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifdef _VLD_H_
+#include "vld.h"
+#endif
+
+#include "test_all.h"
+#include <stdlib.h>
+#include <string.h>
+#include "CUnit.h"
+#include "Basic.h"
+#include "Automated.h"
+#include "Console.h"
+#include <stdio.h>
+#include <apr.h>
+#include "apr_time.h"
+
+void run_console(int argc, char** args) {
+    CU_console_run_tests();
+}
+
+void run_automatic(int argc, char** args) {
+  CU_set_output_filename("alltests");
+  CU_automated_run_tests();
+}
+
+void run_selected(int argc, char** args) {
+  int i;
+  CU_pTestRegistry reg;
+  CU_pSuite suiteToRun;
+  reg = CU_get_registry();
+  for (i=1; i<argc; i++) {
+    if (args[i][0] != '-') {
+      suiteToRun = CU_get_suite_by_name(args[i], reg);
+      if (suiteToRun) {
+        CU_basic_set_mode(CU_BRM_VERBOSE);
+        CU_basic_run_suite(suiteToRun);
+      } else {
+        printf("suite '%s' not found\n", args[i]);
+      }
+    }
+  }
+}
+
+void run_default(int arg, char** args) {
+  char c;
+  CU_basic_set_mode(CU_BRM_VERBOSE);
+  CU_basic_run_tests();
+
+  printf("press <enter> to exit.");
+  scanf("%c", &c);
+}
+
+void (*runner)(int argc, char** args);
+
+void parseOptions(int argc, char** args) {
+  runner = run_default;
+  if (argc >= 2) {
+    char* parameter = args[1];
+    if (strcmp(parameter, "-c") == 0) {
+	runner = run_console;
+    } else if (strcmp(parameter, "-a") == 0) {
+	runner = run_automatic;
+    } else if (strcmp(parameter, "-s") == 0) {
+	runner = run_selected;
+    }
+  }
+}
+
+int main(int argc, char** argv) {
+    int i=0;
+    CU_ErrorCode rv = 0;
+
+    parseOptions(argc, argv);
+
+    if (CUE_SUCCESS != CU_initialize_registry()) {
+        return 1;
+    }
+
+    while (etch_testlist[i] != 0) {
+      (void)etch_testlist[i++]();
+    }
+
+    runner(argc, argv);
+
+    CU_cleanup_registry();
+    rv = CU_get_error();
+
+    return rv;
+}
diff --git a/binding-c/runtime/c/src/test/message/test_arrayvalue.c b/binding-c/runtime/c/src/test/message/test_arrayvalue.c
new file mode 100644
index 0000000..bea11bf
--- /dev/null
+++ b/binding-c/runtime/c/src/test/message/test_arrayvalue.c
@@ -0,0 +1,1746 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_arrayvalue.c -- test etch_arrayvalue object
+ */
+#include "etch_runtime.h"
+#include "etch_tagdata_inp.h"
+#include "etch_arrayval.h"
+#include "etch_exception.h"
+#include "etch_nativearray.h"
+#include "etch_objecttypes.h"
+#include "etch_mem.h"
+#include <wchar.h>
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+#define OBJTYPE_FAKETDI_IMPL ETCHTYPEB_INSTANCEDATA
+#define CLASSID_FAKETDI_IMPL 0xf0
+#define OBJTYPE_FAKETDO_IMPL ETCHTYPEB_INSTANCEDATA
+#define CLASSID_FAKETDO_IMPL 0xf1
+#define OBJTYPE_FAKETDI_VTABLE 0x88
+#define OBJTYPE_FAKETDO_VTABLE 0x89
+
+#define EXCPTEST_UNCHECKED_STATICTEXT 1
+#define EXCPTEST_CHECKED_COPYTEXT     2
+#define EXCPTEST_CHECKED_STATICTEXT   3
+
+#define IS_DEBUG_CONSOLE FALSE  /* TRUE to display test diagnostics */
+
+static etch_arraylist* testdata;
+static int g_which_exception_test;
+
+
+#if(0)
+
+/**
+ * fake_tdi_impl
+ * instance data for a TDI implementation
+ */
+typedef struct fake_tdi_impl
+{
+    etch_object object;
+
+    int index;
+    byte started, done, ended;
+    etch_arrayvalue* arrray;
+
+} fake_tdi_impl;
+
+
+/**
+ * fake_tdo_impl
+ * instance data for a TDO implementation
+ */
+typedef struct fake_tdo_impl
+{
+    etch_object object;
+
+    byte started, ended;
+    etch_arraylist* list;   
+    etch_arrayvalue* arrray;
+
+} fake_tdo_impl;
+
+
+/**
+ * destroy_fake_tdi_impl
+ * memory cleanup handler for fake_tdi_impl
+ */
+static int destroy_fake_tdi_impl(fake_tdi_impl* impl)
+{
+    int result = verify_object((etch_object*)impl, OBJTYPE_FAKETDI_IMPL, CLASSID_FAKETDI_IMPL, NULL);
+    if (result == -1) return -1; /* object passed was not expected object */
+
+    etch_object_destroy(impl->arrray); 
+
+    etch_free(impl);    
+    return 0;
+}
+
+
+/**
+ * destroy_fake_tdo_impl
+ * memory cleanup handler for fake_tdo_impl
+ */
+static int destroy_fake_tdo_impl(fake_tdo_impl* impl)
+{
+    etch_destructor destroy = NULL;
+    int result = verify_object((etch_object*)impl, OBJTYPE_FAKETDO_IMPL, CLASSID_FAKETDO_IMPL, NULL);
+    if (result == -1) return -1; /* object passed was not expected object */
+
+    impl->list->is_readonly = TRUE;
+    etch_object_destroy(impl->list);     /* destroy list, but not content */
+
+    impl->arrray->list->is_readonly = FALSE;
+    etch_object_destroy(impl->arrray); /* destroy arravalue and content */
+
+    etch_free(impl);    
+    return 0;
+}
+
+
+/**
+ * new_fake_tdi_impl()
+ * constructor for TDI implementation instance data
+ */
+static fake_tdi_impl* new_fake_tdi_impl()
+{
+    fake_tdi_impl* data = (fake_tdi_impl*) new_object
+        (sizeof(fake_tdi_impl), ETCHTYPEB_INSTANCEDATA, CLASSID_FAKETDI_IMPL);
+
+    data->destroy = destroy_fake_tdi_impl;
+    
+    return data;
+}
+
+
+/**
+ * new_fake_tdo_impl()
+ * constructor for TDO implementation instance data
+ */
+static fake_tdo_impl* new_fake_tdo_impl()
+{
+    fake_tdo_impl* data = (fake_tdo_impl*) new_object
+        (sizeof(fake_tdo_impl), ETCHTYPEB_INSTANCEDATA, CLASSID_FAKETDO_IMPL);
+ 
+    data->destroy = destroy_fake_tdo_impl;
+    
+    return data;
+}
+
+
+static enum etch_classid CLASSID_VTABLE_FAKETDI = CLASSID_DYNAMIC_START + 0x0;  
+static enum etch_classid CLASSID_VTABLE_FAKETDO = CLASSID_DYNAMIC_START + 0x1;
+
+
+/**
+ * faketdi_start_array() overrides tdi_start_array()
+ * Starts reading an array from the stream.
+ * @return the array that we are reading.
+ * @throws IOException if there is a problem with the stream.
+ */
+static etch_arrayvalue* faketdi_start_array(tagged_data_input* tdi)
+{
+    int result = 0;
+    fake_tdi_impl* data = NULL;
+    etch_arrayvalue* newarrayval = NULL;
+    const int DIM_ZERO = 0, READONLY = TRUE, DEFSIZE = 0, DEFDELTA = 0;
+    byte fake_typecode = 0;
+    etch_type* fake_structtype = NULL;
+    
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
+
+    data = (fake_tdi_impl*) tdi->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = data->destroy(NULL); /* ensure we can call instance data destructor */
+    CU_ASSERT_EQUAL(result,-1);
+
+    CU_ASSERT_EQUAL(data->started,FALSE);
+    CU_ASSERT_EQUAL(data->done,FALSE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+
+    data->started = TRUE;
+    data->index = 0;
+
+    /* create instance array */
+    newarrayval = new_arrayvalue 
+        (fake_typecode, fake_structtype, DIM_ZERO, DEFSIZE, DEFDELTA, READONLY); 
+
+    data->arrray = newarrayval;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->arrray);
+
+    return data->arrray;
+}
+
+
+/**
+ * faketdo_start_array() overrides tdo_start_array()
+ */
+static etch_arrayvalue* faketdo_start_array(tagged_data_output* tdo, etch_arrayvalue* thisp)
+{
+    int result = 0;
+    fake_tdo_impl* data = NULL;
+  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
+
+    data = (fake_tdo_impl*) tdo->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = data->destroy(NULL); /* ensure we can call into instance data destructor */
+    CU_ASSERT_EQUAL(result,-1);
+
+    CU_ASSERT_EQUAL(data->started,FALSE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+
+    data->arrray = thisp;
+    data->list = new_arrayvalue_arraylist();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->arrray);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->list);
+
+    data->started = TRUE;
+    return data->arrray;
+}
+
+
+/**
+ * faketdi_read_array_element() overrides tdi_read_array_element()
+ */
+static int faketdi_read_array_element(tagged_data_input* tdi, ETCH_ARRAY_ELEMENT** out_ae)   
+{
+    int result = 0;
+    fake_tdi_impl* data = NULL;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
+
+    data = (fake_tdi_impl*) tdi->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->done,FALSE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+
+	if (data->index < (int)testdata->count)
+	{   
+		*out_ae = arraylist_get(testdata, data->index++);
+		return TRUE;
+	}
+	
+	data->done = TRUE;
+	return FALSE;
+}
+
+
+/**
+ * faketdo_write_array_element() overrides tdi_read_array_element()
+ */
+static int faketdo_write_array_element(tagged_data_output* tdo, etch_object* newitem)   
+{
+    int result = 0;
+    fake_tdo_impl* data = NULL;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
+
+    data = (fake_tdo_impl*) tdo->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->list);  
+
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+   
+	result = arraylist_add(data->list, newitem);
+	return 0;
+}
+
+
+/**
+ * faketdi_end_array() overrides tdi_end_array()
+ * Ends an array that we are reading.
+ * @param array the array that we read.
+ * @throws IOException if there is a problem with the stream.
+ */
+static int faketdi_end_array(tagged_data_input* tdi, etch_arrayvalue* av)
+{
+    int result = 0;
+    fake_tdi_impl* data = NULL;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
+
+    data = (fake_tdi_impl*) tdi->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->arrray); 
+ 
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->done,TRUE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+    CU_ASSERT_EQUAL(data->arrray,av);
+			
+	data->ended = TRUE;
+    return 0;
+}
+
+
+/**
+ * faketdo_end_array() overrides tdo_end_array()
+ */
+static int faketdo_end_array(tagged_data_output* tdo, etch_arrayvalue* av)
+{
+    int result = 0;
+    fake_tdo_impl* data = NULL;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
+
+    data = (fake_tdo_impl*) tdo->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->list); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->arrray); 
+ 
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+    CU_ASSERT_EQUAL(data->arrray,av);
+			
+	data->ended = TRUE;
+    return 0;
+}
+
+
+/**
+ * faketdi_close() port from java test
+ * also tested here is that we can call base methods on a derived object. we invoke 
+ * the TDI destructor here, which is an overide of the etchobject destructor.
+ * the TDI destructor walks the vtable chain to its parent, and invokes the parent
+ * destructor to destroy etchobject content such as any exception, and finally
+ * the object itself.
+ */
+static void faketdi_close(tagged_data_input* tdi)  
+{
+    etch_object_destroy(tdi); /* destroy object */
+}
+
+
+/**
+ * faketdo_close() port from java test
+ */
+static void faketdo_close(tagged_data_output* tdo)  
+{
+    etch_object_destroy(tdo); /* destroy object */
+}
+
+
+/**
+ * new_fake_tdi()
+ * constructor for TDI implementation  
+ */
+static tagged_data_input* new_fake_tdi()
+{
+    tagged_data_input* faketdi = NULL;
+    i_tagged_data_input*  vtab = NULL;
+    const unsigned short CLASS_ID = CLASSID_VTABLE_FAKETDI;
+
+    faketdi = new_tagged_data_input();
+   
+    vtab = cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+    if(!vtab)  
+    {   
+        vtab = new_vtable(NULL, sizeof(i_tagged_data_input), CLASS_ID);
+   
+        /* override three i_tagged_data_input methods */
+        vtab->start_array = faketdi_start_array;
+        vtab->end_array   = faketdi_end_array;
+        vtab->read_array_element = faketdi_read_array_element;
+
+        ((etch_object*)vtab)->vtab = faketdi->vtab; /* chain parent vtable to override vtab */
+
+        cache_insert(vtab->hashkey, vtab, FALSE);
+    } 
+
+    CU_ASSERT_EQUAL_FATAL(((etch_object*)vtab)->class_id, CLASSID_VTABLE_FAKETDI);
+
+    ((etch_object*)faketdi)->vtab = vtab;  /* set override vtab */
+
+    faketdi->impl = (etch_object*) new_fake_tdi_impl(); /* instantiate tdi instance data */
+
+    switch(g_which_exception_test)
+    {   case EXCPTEST_UNCHECKED_STATICTEXT: 
+             etch_throw((etch_object*)faketdi, EXCPTYPE_NULLPTR, NULL, 0);  
+             break;   
+        case EXCPTEST_CHECKED_COPYTEXT:   
+             etch_throw((etch_object*)faketdi, EXCPTYPE_CHECKED_BOGUS, L"copied text", ETCHEXCP_COPYTEXT | ETCHEXCP_FREETEXT);  
+             break; 
+        case EXCPTEST_CHECKED_STATICTEXT:   
+             etch_throw((etch_object*)faketdi, EXCPTYPE_CHECKED_BOGUS, local_excp_text, ETCHEXCP_STATICTEXT);  
+             break;       
+    }
+
+    return faketdi;
+}
+
+
+/**
+ * new_fake_tdo()
+ * constructor for TDO implementation  
+ */
+static tagged_data_output* new_fake_tdo()
+{
+    tagged_data_output* faketdo = NULL;
+    i_tagged_data_output*  vtab = NULL;
+    const unsigned short CLASS_ID = CLASSID_VTABLE_FAKETDO;
+
+    faketdo = new_tagged_data_output();
+     
+    vtab = cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+    if(!vtab)  
+    {   vtab = new_vtable(NULL, sizeof(i_tagged_data_input), CLASS_ID);
+     
+        /* override three i_tagged_data_output methods */
+        vtab->start_array = faketdo_start_array;
+        vtab->end_array   = faketdo_end_array;
+        vtab->write_array_element = faketdo_write_array_element;
+
+        ((etch_object*)vtab)->vtab = faketdo->vtab; /* chain parent vtab to override vtab */
+    
+        cache_insert(vtab->hashkey, vtab, FALSE);
+    } 
+
+    CU_ASSERT_EQUAL_FATAL(((etch_object*)vtab)->class_id, CLASSID_VTABLE_FAKETDO);
+
+    ((etch_object*)faketdo)->vtab = vtab; /* set override vtab */
+
+    faketdo->impl = (etch_object*) new_fake_tdo_impl(); /* instantiate tdo instance data */
+
+    return faketdo;
+}
+
+#endif /* if(0) */
+
+
+/* 
+ * load_testdata_string()
+ * load testdata array with some ETCH_STRING objects
+ */
+static int load_testdata_string()
+{
+    int i = 0, numitems = 4;
+    etch_string* newobj = NULL;
+    wchar_t* str0 = L"now ", *str1 = L"is  ", *str2 = L"the ", *str3 = L"time";
+    wchar_t* strings[4] = { str0, str1, str2, str3 };
+
+    for(; i < numitems; i++)
+    {
+        /* new_etch_string copies parameter string */        
+        newobj = new_stringw(strings[i]);  
+        etch_arraylist_add(testdata, newobj);
+    }
+
+    return numitems;
+}
+
+
+/* 
+ * load_testdata_int()
+ * load testdata array with some ETCH_INT objects
+ */
+static int load_testdata_int()
+{
+    int i = 0, numitems = 4;
+    etch_int32* newobj = NULL;
+    int ints[4] = { 1, 2, 3, 4 };
+
+    for(; i < numitems; i++)
+    {
+        newobj = new_int32(ints[i]);
+        etch_arraylist_add(testdata, newobj);
+    }
+
+    return numitems;
+}
+
+
+/* 
+ * new_testdata()
+ * create testdata array and load it up with data objects
+ */
+static int new_testdata(const int datatype)
+{
+    int count = 0;
+    g_which_exception_test = 0;
+    testdata = new_etch_arraylist(0,0);  
+    testdata->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
+ 
+    switch(datatype)
+    { case 1: count = load_testdata_int();    break;
+      case 2: count = load_testdata_string(); break;
+      default: return -1;
+    }
+  
+    return count;
+}
+
+
+/* 
+ * destroy_testdata()
+ * destroy testdata array and content
+ */
+static void destroy_testdata()
+{
+    etch_arraylist_destroy(testdata, TRUE);
+}
+
+
+#if 0
+/* 
+ * compare_lists()
+ * compares testdata list with the arrayvalue's list
+ * returns boolean indicating equal or not
+ */
+static int compare_lists(etch_arrayvalue* av)
+{
+    int testcount = 0, i = 0, eqcount = 0;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av->list);
+
+    testcount = av->list->count; 
+    CU_ASSERT_EQUAL(testcount, testdata->count);
+    if (testcount != testdata->count) return FALSE;
+
+    for(; i < (const int) testcount; i++)     
+        if (etch_arraylist_get(testdata, i) == etch_arraylist_get(av->list, i))
+            eqcount++;  
+
+    CU_ASSERT_EQUAL(testcount, eqcount);     
+    return testcount == eqcount;
+}
+#endif
+
+#if(0)
+
+/* 
+ * run_read_test
+ * create an array value to read current test data
+ * and verify that content matches test data
+ */
+static void run_read_test()
+{
+    int result = 0;
+    tagged_data_input* tdi = NULL;
+    etch_arrayvalue* av = NULL;
+
+    tdi = new_fake_tdi();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);
+    CU_ASSERT_FALSE_FATAL(is_exception(tdi));
+    CU_ASSERT_EQUAL_FATAL(get_result(tdi),0);
+
+    /* create array value, reading from test values */
+    av = arrayvalue_read(tdi);
+
+    result = compare_lists(av);
+    CU_ASSERT_EQUAL(result, TRUE);
+
+    /* clean up TDI */
+    faketdi_close(tdi);
+
+    /* destroy testdata list and content */
+    testdata->destroy(testdata);
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE); /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */   
+}
+
+
+/* 
+ * run_write_test
+ * create an array value to write current test data
+ * and verify that content matches test data
+ */
+static void run_write_test()
+{
+    int result = 0, i = 0;
+    etch_arrayvalue* arrayval = NULL;
+    tagged_data_output* tdo = NULL;
+    const int DIM_ZERO = 0, NOT_READONLY = FALSE, DEFSIZE = 0, DEFDELTA = 0;
+    etch_type* fake_structtype = NULL;
+    byte  fake_typecode = 0;
+    void* thisitem = NULL;
+                                         
+    arrayval = new_arrayvalue /* create array value instance */
+        (fake_typecode, fake_structtype, DIM_ZERO, DEFSIZE, DEFDELTA, NOT_READONLY);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(arrayval);
+    CU_ASSERT_FALSE_FATAL(is_exception(arrayval));
+    CU_ASSERT_EQUAL_FATAL(get_result(arrayval),0);
+
+    for(; i < (const int) testdata->count; i++)
+    {     
+        thisitem = arraylist_get(testdata, i);
+        result = arrayvalue_add(arrayval, (ETCH_ARRAY_ELEMENT*) thisitem);
+        CU_ASSERT_EQUAL(result,0);
+    }
+
+    tdo = new_fake_tdo();
+
+    result = arrayvalue_write(arrayval, tdo);
+    CU_ASSERT_EQUAL(result,0);
+
+    faketdo_close(tdo);
+
+    /* destroy testdata list but not content */
+    arraylist_destroy(testdata, FALSE);  
+
+    g_bytes_allocated = etch_showmem(0, IS_DEBUG_CONSOLE);  /* verify all memory freed */
+    CU_ASSERT_EQUAL(g_bytes_allocated, 0);  
+    memtable_clear();  /* start fresh for next test */   
+}
+
+#endif /* #if(0) */
+
+
+/* 
+ * run_exception_test
+ *  
+ */
+static void run_exception_test(const int whichtest)
+{
+    /* global marker asks components to throw exceptions */
+    g_which_exception_test = whichtest; 
+
+    #if(0)
+    /* create a bogus TDI inheriting from tagged data input */
+    tdi = new_fake_tdi();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);
+
+    do 
+    {   switch(whichtest)
+        {   case EXCPTEST_UNCHECKED_STATICTEXT:
+            case EXCPTEST_CHECKED_COPYTEXT:
+            case EXCPTEST_CHECKED_STATICTEXT:
+            {   CU_ASSERT_TRUE_FATAL(is_exception(tdi));
+                #if IS_DEBUG_CONSOLE 
+                wprintf(L"\ncaught %s exception\n", tdi->result->exception->excptext);          
+                #endif   
+                break;          
+            }
+        }
+        if (is_exception(tdi)) break;
+
+        /* create array value, reading from test values */
+        av = arrayvalue_read(tdi);
+        /* if av is NULL we would throw an exception here */
+
+        result = compare_lists(av);
+        CU_ASSERT_EQUAL(result, TRUE); 
+
+    } while(0);  
+
+    /* clean up TDI */
+    faketdi_close(tdi);
+
+    #endif
+
+    /* destroy testdata list and content */
+    etch_object_destroy(testdata);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+#if(0)
+
+/* 
+ * read_test_integer
+ */
+static void read_test_integer(void)
+{
+    int itemcount = 0;
+    if ((itemcount = new_testdata(1)) > 0)
+        run_read_test(); 
+}
+
+
+/* 
+ * write_test_integer
+ */
+static void write_test_integer(void)
+{
+    int itemcount = 0;
+    if ((itemcount = new_testdata(1)) > 0)
+        run_write_test(); 
+}
+
+
+/* 
+ * read_test_string
+ */
+static void read_test_string(void)
+{
+    int itemcount = 0;
+    if ((itemcount = new_testdata(2)) > 0)
+        run_read_test(); 
+}
+
+
+/* 
+ * write_test_string
+ */
+static void write_test_string(void)
+{
+    int itemcount = 0;
+    if ((itemcount = new_testdata(2)) > 0)
+        run_write_test(); 
+}
+
+#endif /* #if(0) */
+
+
+/* 
+ * exception_test_1
+ */
+static void exception_test_1(void)
+{
+    int itemcount = 0;
+    if ((itemcount = new_testdata(1)) > 0)
+        run_exception_test(EXCPTEST_UNCHECKED_STATICTEXT); 
+}
+
+
+/* 
+ * exception_test_2
+ */
+static void exception_test_2(void)
+{
+    int itemcount = 0;
+    if ((itemcount = new_testdata(1)) > 0)
+        run_exception_test(EXCPTEST_CHECKED_COPYTEXT); 
+}
+
+
+/* 
+ * exception_test_3
+ */
+static void exception_test_3(void)
+{
+    int itemcount = 0;
+    if ((itemcount = new_testdata(1)) > 0)
+        run_exception_test(EXCPTEST_CHECKED_STATICTEXT); 
+}
+
+
+/* 
+ * test_iterator_over_arraylist
+ */
+static void test_iterator_over_arraylist(void)
+{
+    etch_iterator* iterator = NULL; 
+    int testcount = 0;
+    struct i_iterable* vtab = NULL;
+
+    new_testdata(1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(testdata);
+    CU_ASSERT_NOT_EQUAL(testdata->count, 0);
+
+    iterator = new_iterator(testdata, &testdata->iterable);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+    CU_ASSERT_EQUAL_FATAL(iterator->ordinal,1);
+    testcount = 1;
+    
+    vtab = (struct i_iterable*)((etch_object*)iterator)->vtab;
+    
+    while(vtab->has_next(iterator))
+          testcount += vtab->next(iterator) == 0;  
+        
+    CU_ASSERT_EQUAL(testcount, testdata->count);
+
+    destroy_iterator(iterator);
+    destroy_testdata();
+}
+
+
+/* 
+ * test_create_from_1
+ * create arrayvalue from single-dimensioned byte nativearray and verify
+ */
+static void test_create_from_1(void)
+{
+    etch_arrayvalue* av = NULL;
+    etch_byte* thisitem = NULL;
+    int   i = 0, result = 0;
+    byte  fake_typecode = 0xff;
+    char  x[4] = {'a','b','c','d'};
+    const int numdimensions = 1, itemcount = 4;
+
+    etch_nativearray* a = new_etch_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, itemcount, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type = ETCHTYPEB_BYTE; /* array content is type byte */
+    a->content_class_id = CLASSID_NONE;   /* array content is unwrapped (default) */
+
+    for(i = 0; i < itemcount; i++) /* populate native array from test data */
+        CU_ASSERT_EQUAL(0, result = a->put1(a, &x[i], i)); 
+
+    /* populate arrayvalue from native array */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, itemcount, 0, FALSE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+    CU_ASSERT_EQUAL(arrayvalue_count(av), itemcount);
+
+    /* assert that arrayvalue content matches test data */
+    for(i=0; i < itemcount; i++)
+    {     
+        thisitem = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+        CU_ASSERT_EQUAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_PRIMITIVE);
+        CU_ASSERT_EQUAL(((etch_object*)thisitem)->class_id, CLASSID_PRIMITIVE_BYTE);
+        CU_ASSERT_EQUAL(thisitem->value, x[i]);
+    }
+
+    etch_object_destroy(av);  /* destroy array value and content */
+}
+
+
+/* 
+ * test_create_from_2
+ * create arrayvalue from single-dimensioned int nativearray and verify
+ */
+static void test_create_from_2(void)
+{
+    etch_arrayvalue* av  = NULL;
+    etch_int32* thisitem = NULL;
+    int   i = 0, result  = 0;
+    byte  fake_typecode  = 0xff;
+    int   n[4] = {10,11,12,13};
+    const int numdimensions = 1, itemcount = 4;
+
+    etch_nativearray* a = new_etch_nativearray 
+        (CLASSID_ARRAY_INT32, sizeof(int), numdimensions, itemcount, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type = ETCHTYPEB_INT32; /* array content is type int */
+    a->content_class_id = CLASSID_NONE;   /* array content is unwrapped (default) */
+
+    for(i = 0; i < itemcount; i++) /* populate native array from test data */
+        CU_ASSERT_EQUAL(0, result = a->put1(a, &n[i], i));
+ 
+    /* populate arrayvalue from native array */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, itemcount, 0, FALSE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+    CU_ASSERT_EQUAL(arrayvalue_count(av), itemcount);
+
+    /* assert that arrayvalue content matches test data */
+    for(i=0; i < itemcount; i++)
+    {     
+        thisitem = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+        CU_ASSERT_EQUAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_PRIMITIVE);
+        CU_ASSERT_EQUAL(((etch_object*)thisitem)->class_id, CLASSID_PRIMITIVE_INT32);
+        CU_ASSERT_EQUAL(thisitem->value, n[i]);
+    }
+
+    etch_object_destroy(av);  /* destroy array value and content */
+}
+
+
+/* 
+ * test_create_from_3
+ * create arrayvalue from single-dimensioned long long nativearray and verify
+ */
+static void test_create_from_3(void)
+{
+    etch_arrayvalue* av  = NULL;
+    etch_int64* thisitem = NULL;
+    int   i = 0, result  = 0;
+    byte  fake_typecode  = 0xff;
+    int64 n[5] = {-2, -1, 0 , 1, 2};
+    const int numdimensions = 1, itemcount = 5;
+
+    etch_nativearray* a = new_etch_nativearray 
+        (CLASSID_ARRAY_INT64, sizeof(int64), numdimensions, itemcount, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type = ETCHTYPEB_INT64; /* array content is type int64 */
+    a->content_class_id = CLASSID_NONE;   /* array content is unwrapped (default) */
+
+    for(i = 0; i < itemcount; i++) /* populate native array from test data */
+        CU_ASSERT_EQUAL(0, result = a->put1(a, &n[i], i));
+ 
+    /* populate arrayvalue from native array */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, itemcount, 0, FALSE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+    CU_ASSERT_EQUAL(arrayvalue_count(av), itemcount);
+
+    /* assert that arrayvalue content matches test data */
+    for(i=0; i < itemcount; i++)
+    {     
+        thisitem = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+        CU_ASSERT_EQUAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_PRIMITIVE);
+        CU_ASSERT_EQUAL(((etch_object*)thisitem)->class_id, CLASSID_PRIMITIVE_INT64);
+        CU_ASSERT_EQUAL(thisitem->value, n[i]);
+    }
+
+    etch_object_destroy(av);  /* destroy array value and content */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_create_from_4
+ * create arrayvalue from single-dimensioned double nativearray and verify
+ */
+static void test_create_from_4(void)
+{
+    etch_arrayvalue* av   = NULL;
+    etch_double* thisitem = NULL;
+    int    i = 0, result  = 0;
+    byte   fake_typecode  = 0xff;
+    double f[3] = {-1000.0, 3.14149, 65536.0};
+    const int numdimensions = 1, itemcount = 3;
+
+    etch_nativearray* a = new_etch_nativearray 
+        (CLASSID_ARRAY_DOUBLE, sizeof(int64), numdimensions, itemcount, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type = ETCHTYPEB_IEEE64; /* array content is type double */
+    a->content_class_id = CLASSID_NONE;   /* array content is unwrapped (default) */
+
+    for(i = 0; i < itemcount; i++) /* populate native array from test data */
+        CU_ASSERT_EQUAL(0, result = a->put1(a, &f[i], i));
+ 
+    /* populate arrayvalue from native array */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, itemcount, 0, FALSE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+    CU_ASSERT_EQUAL(arrayvalue_count(av), itemcount);
+
+    /* assert that arrayvalue content matches test data */
+    for(i=0; i < itemcount; i++)
+    {     
+        thisitem = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+        CU_ASSERT_EQUAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_PRIMITIVE);
+        CU_ASSERT_EQUAL(((etch_object*)thisitem)->class_id, CLASSID_PRIMITIVE_DOUBLE);
+        CU_ASSERT_DOUBLE_EQUAL(thisitem->value, f[i], 0.01);
+    }
+
+    etch_object_destroy(av);  /* destroy array value and content */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_create_from_5
+ * create arrayvalue from single-dimensioned string nativearray and verify
+ */
+static void test_create_from_5(void)
+{
+    etch_arrayvalue* av   = NULL;
+    etch_string* thisitem = NULL;
+    int   i = 0, result   = 0;
+    byte  fake_typecode   = 0xff;
+    wchar_t* c[3] = {L"hey", L"it", L"works!"};
+    //char* c[3] = {"hey", "it", "works!"};
+    const int numdimensions = 1, itemcount = 3;
+
+    etch_nativearray* a = new_etch_nativearray 
+        (CLASSID_ARRAY_STRING, sizeof(void*), numdimensions, itemcount, 0, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type = ETCHTYPEB_STRING; /* array content is type string */
+    a->content_class_id = CLASSID_NONE;    /* array content is unwrapped (default) */
+    a->is_content_owned = FALSE;
+
+    for(i = 0; i < itemcount; i++) /* populate native array from test data */
+        CU_ASSERT_EQUAL(0, result = a->put1(a, &c[i], i));
+ 
+    /* populate arrayvalue from native array */
+    printf("tot1\n");
+    av = new_arrayvalue_from(a, fake_typecode, NULL, itemcount, 0, FALSE);
+    printf("tot2\n");
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+    CU_ASSERT_EQUAL(arrayvalue_count(av), itemcount);
+
+    /* assert that arrayvalue content matches test data */
+    for(i=0; i < itemcount; i++)
+    {     
+        thisitem = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+        CU_ASSERT_EQUAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_PRIMITIVE);
+        CU_ASSERT_EQUAL(((etch_object*)thisitem)->class_id, CLASSID_STRING);
+        CU_ASSERT_NSTRING_EQUAL(thisitem->v.value, c[i], wcslen(c[i]));
+        //CU_ASSERT_NSTRING_EQUAL(thisitem->v.value, c[i], strlen(c[i]));
+    }
+
+    etch_object_destroy(av);  /* destroy array value and content */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_create_from_10
+ * create arrayvalue from two-dimensioned byte nativearray and verify
+ */
+static void test_create_from_10(void)
+{
+    etch_arrayvalue* av = NULL;
+    etch_arrayvalue* subav = NULL;
+    etch_byte*       thisitem = NULL;
+    int   i = 0, j = 0, result = 0;
+    byte  fake_typecode = 0xff;
+    char  x[2][4] = {  {'a','b','c','d',},  {'e', 'f', 'g', 'h',},  };
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+
+    etch_nativearray* a = new_etch_nativearray 
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type = ETCHTYPEB_BYTE; /* array content is type byte */
+    a->content_class_id = CLASSID_NONE;   /* array content is unwrapped (default) */
+
+    for(i = 0; i < dim1count; i++)
+        for(j = 0; j < dim0count; j++) /* populate native array from test data */
+            CU_ASSERT_EQUAL(0, result = a->put2(a, &x[i][j], i, j)); 
+
+    /* populate arrayvalue from native array. we tell the arrayvalue to take  
+     * ownership of the native array. result is a 2-dimensional arrayvalue,
+     * which is represented as an arrayvalue of arrayvalues
+     */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, 32, 0, FALSE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+    CU_ASSERT_EQUAL(av->dim, numdimensions); 
+    CU_ASSERT_EQUAL(arrayvalue_count(av), dim1count); 
+
+    /* assert that arrayvalue content matches test data */
+    for(i = 0; i < dim1count; i++)
+    {
+        subav = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(subav); 
+        CU_ASSERT_EQUAL(((etch_object*)subav)->obj_type, ETCHTYPEB_ARRAYVAL);
+        CU_ASSERT_EQUAL(arrayvalue_count(subav), dim0count);
+
+        for(j = 0; j < dim0count; j++)
+        {     
+            byte expected_value = x[i][j];
+            thisitem = arrayvalue_get(subav, j);
+            CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+            CU_ASSERT_EQUAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_PRIMITIVE);
+            CU_ASSERT_EQUAL(((etch_object*)thisitem)->class_id, CLASSID_PRIMITIVE_BYTE);
+            CU_ASSERT_EQUAL(thisitem->value, expected_value);
+        }
+    }
+
+    /* destroy array value and content. memory includes the sub-arrayvalues,
+     * the native array from above, and the sub-native arrays */
+    etch_object_destroy(av);  
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_create_from_11
+ * create arrayvalue from two-dimensioned int16 nativearray and verify
+ */
+static void test_create_from_11(void)
+{
+    etch_arrayvalue* av = NULL;
+    etch_arrayvalue* subav = NULL;
+    etch_int16*      thisitem = NULL;
+    int   i = 0, j = 0, result = 0;
+    byte  fake_typecode = 0xff;
+    short n[2][4] = { { 100,101,102,103, },  { 0xeffc,0xeffd,0xeffe,0xefff },  };
+    const int numdimensions = 2, dim0count = 4, dim1count = 2;
+
+    etch_nativearray* a = new_etch_nativearray 
+        (CLASSID_ARRAY_INT16, sizeof(short), numdimensions, dim0count, dim1count, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type = ETCHTYPEB_INT16; /* array content is type short int */
+    a->content_class_id = CLASSID_NONE;   /* array content is unwrapped (default) */
+
+    for(i = 0; i < dim1count; i++)
+        for(j = 0; j < dim0count; j++) /* populate native array from test data */
+            CU_ASSERT_EQUAL(0, result = a->put2(a, &n[i][j], i, j)); 
+
+    /* populate arrayvalue from native array. we tell the arrayvalue to take  
+     * ownership of the native array. result is a 2-dimensional arrayvalue,
+     * which is represented as an arrayvalue of arrayvalues
+     */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, 32, 0, FALSE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+    CU_ASSERT_EQUAL(av->dim, numdimensions); 
+    CU_ASSERT_EQUAL(arrayvalue_count(av), dim1count); 
+
+    /* assert that arrayvalue content matches test data */
+    for(i = 0; i < dim1count; i++)
+    {
+        subav = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(subav); 
+        CU_ASSERT_EQUAL(((etch_object*)subav)->obj_type, ETCHTYPEB_ARRAYVAL);
+        CU_ASSERT_EQUAL(arrayvalue_count(subav), dim0count);
+
+        for(j = 0; j < dim0count; j++)
+        {     
+            short expected_value = n[i][j];
+            thisitem = arrayvalue_get(subav, j);
+            CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+            CU_ASSERT_EQUAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_PRIMITIVE);
+            CU_ASSERT_EQUAL(((etch_object*)thisitem)->class_id, CLASSID_PRIMITIVE_INT16);
+            CU_ASSERT_EQUAL(thisitem->value, expected_value);
+        }
+    }
+
+    /* destroy array value and content. memory includes the sub-arrayvalues,
+     * the native array from above, and the sub-native arrays */
+    etch_object_destroy(av);  
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_create_from_12
+ * create arrayvalue from two-dimensioned string nativearray and verify
+ */
+static void test_create_from_12(void)
+{
+    etch_arrayvalue* av = NULL;
+    etch_arrayvalue* subav = NULL;
+    etch_string*     thisitem = NULL;
+    const int DEFSIZE=0, DEFDELTA=0; 
+    int   i = 0, j = 0, result = 0;
+    byte  fake_typecode = 0xff;
+
+    wchar_t* x[6][4] 
+      = { { L"I think that I", L"shall never see,", L"A poem as lovely", L"as a tree.", }, 
+          { L"She knows not what", L"the curse may be,", L"And so she weaveth", L"steadily,", }, 
+          { L"And little other", L"care hath she,", L"The Lady of Shalott", L".", }, 
+          { L"And therefore I have sailed", L"the seas, and come", L"To the holy city", L"of Byzantium.", },
+          { L"Once out of nature", L"I shall never take", L"My bodily form", L" from any natural thing,", }, 
+          { L"But such a form", L"as Grecian goldsmiths make", L"Of hammered gold ", L"and gold enameling", }, 
+       };
+
+    const int numdimensions = 2, dim0count = 4, dim1count = 6;
+
+    #if(0) /* create empty native array and populate it item by item */
+
+    etch_nativearray* a = new_etch_nativearray (CLASSID_ARRAY_STRING, 
+        sizeof(void*), numdimensions, dim0count, dim1count, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type = ETCHTYPEB_STRING; /* array content is type string */
+    a->content_class_id = CLASSID_NONE;   /* array content is unwrapped (default) */
+
+    for(i = 0; i < dim1count; i++)
+    for(j = 0; j < dim0count; j++)  /* populate native array from test data */
+        CU_ASSERT_EQUAL(0, result = a->put2(a, &x[i][j], i, j)); 
+
+    #else /* create native array from static array */
+
+    etch_nativearray* a = new_etch_nativearray_from(&x, CLASSID_ARRAY_STRING, 
+        sizeof(void*), numdimensions, dim0count, dim1count, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type = ETCHTYPEB_STRING; /* array content is type string */
+    a->content_class_id = CLASSID_NONE;     /* array content is unwrapped (default) */
+
+    #endif 
+
+    for(j = 0; j < dim0count; j++)       
+    {   wchar_t* thisx = 0, *thatx = x[i][j];          
+        result = a->get2(a, &thisx, i, j); 
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_PTR_NOT_NULL_FATAL(thisx); 
+        result = wcscmp(thisx, thatx);
+        CU_ASSERT_EQUAL(result,0); 
+    }   
+
+    /* populate arrayvalue from native array. we tell the arrayvalue to take  
+     * ownership of the native array. result is a 2-dimensional arrayvalue,
+     * which is represented as an arrayvalue of arrayvalues
+     */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, DEFSIZE, DEFDELTA, FALSE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+    CU_ASSERT_EQUAL(av->dim, numdimensions); 
+    CU_ASSERT_EQUAL(result = arrayvalue_count(av), dim1count); 
+
+    /* assert that arrayvalue content matches test data */
+    for(i = 0; i < dim1count; i++)
+    {
+        subav = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(subav); 
+        CU_ASSERT_EQUAL(((etch_object*)subav)->obj_type, ETCHTYPEB_ARRAYVAL);
+        CU_ASSERT_EQUAL(result = arrayvalue_count(subav), dim0count);
+
+        for(j = 0; j < dim0count; j++)
+        {     
+            wchar_t* expected_value = x[i][j];
+            thisitem = arrayvalue_get(subav, j);
+            CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+            CU_ASSERT_EQUAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_PRIMITIVE);
+            CU_ASSERT_EQUAL(((etch_object*)thisitem)->class_id, CLASSID_STRING);
+            result = wcscmp(expected_value, thisitem->v.value);
+            CU_ASSERT_EQUAL(result, 0);
+        }
+    }
+
+    /* destroy array value and content. memory includes the sub-arrayvalues,
+     * the native array from above, and the sub-native arrays */
+    etch_object_destroy(av);  
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_create_from_13
+ * create arrayvalue from two-dimensioned object nativearray and verify
+ */
+static void test_create_from_13(void)
+{
+    etch_nativearray* a = NULL;
+    etch_arrayvalue* av = NULL;
+    etch_arrayvalue* subav = NULL;
+    etch_object* thisitem = NULL;
+    const int DEFSIZE=0, DEFDELTA=0; 
+    int   i = 0, j = 0, result = 0, count = 0;
+    byte  fake_typecode = 0xff;
+
+    etch_object* x[2][3] = { { NULL, NULL, NULL, }, { NULL, NULL, NULL, }, };
+
+    const int numdimensions = 2, dim0count = 3, dim1count = 2;
+
+    for(i = 0; i < dim1count; i++)  /* populate array of objects */
+    for(j = 0; j < dim0count; j++)
+    {   etch_object* thisobj = new_object(sizeof(etch_object), ETCHTYPEB_ETCHOBJECT,CLASSID_NONE);
+        thisobj->hashkey = ++count;     /* usurp hashkey for this test */
+        x[i][j] = thisobj;
+    }
+
+    /* create an etch_nativearray from the above array of objects. 
+     * native array owns its data and so since the data are etch objects
+     * the native array will destroy them at such time as arrayvalue
+     * destroys the native array, the objects likewise destroying their
+     * own content (that content being the etch_malloc'ed memory, above).
+     */
+    a = new_etch_nativearray_from(&x, CLASSID_ARRAY_OBJECT, 
+        sizeof(void*), numdimensions, dim0count, dim1count, 0);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type = ETCHTYPEB_ETCHOBJECT; /* array content is type object */
+    a->content_class_id = CLASSID_OBJECT;       /* array content is wrapped */
+
+    for(i = 0; i < dim1count; i++)   /* assert that native array content */
+    for(j = 0; j < dim0count; j++)   /* when read back, is as expected */    
+    {   etch_object* thisx = 0, *thatx = x[i][j];          
+        result = a->get2(a, &thisx, i, j); 
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_PTR_NOT_NULL_FATAL(thisx); 
+        CU_ASSERT_PTR_EQUAL_FATAL(thisx, thatx);  
+    }   
+
+    /* populate arrayvalue from native array. we tell the arrayvalue to take  
+     * ownership of the native array. result is a 2-dimensional arrayvalue,
+     * which is represented as an arrayvalue of arrayvalues
+     */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, DEFSIZE, DEFDELTA, FALSE);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+    CU_ASSERT_EQUAL(av->dim, numdimensions); 
+    CU_ASSERT_EQUAL(result = arrayvalue_count(av), dim1count); 
+
+    /* assert that arrayvalue content matches test data */
+    for(i = 0; i < dim1count; i++)
+    {
+        subav = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(subav); 
+        CU_ASSERT_EQUAL(((etch_object*)subav)->obj_type, ETCHTYPEB_ARRAYVAL);
+        CU_ASSERT_EQUAL(result = arrayvalue_count(subav), dim0count);
+
+        for(j = 0; j < dim0count; j++)
+        {     
+            etch_object* expected_object = x[i][j];
+            thisitem = arrayvalue_get(subav, j);
+            CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+            CU_ASSERT_EQUAL_FATAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_ETCHOBJECT);
+            // TODO this is CLASSID_ANY (zero) not CLASSID_OBJECT - verify that this is as expected
+            // CU_ASSERT_EQUAL_FATAL(((etch_object*)thisitem)->class_id, CLASSID_OBJECT);
+            CU_ASSERT_EQUAL(thisitem->hashkey, expected_object->hashkey);
+        }
+    }
+
+    /* destroy array value and content. memory freed includes sub-arrayvalues,
+     * the native array and test objects from above, and the sub-arrays */
+    etch_object_destroy(av);  
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_create_from_21
+ * create arrayvalue from three-dimensioned byte nativearray and verify
+ */
+static void test_create_from_21(void)
+{
+    etch_arrayvalue* av = NULL;
+    etch_arrayvalue* subav1 = NULL;
+    etch_arrayvalue* subav2 = NULL;
+    etch_byte* thisitem = NULL;
+    int   i = 0, j = 0, k = 0, result = 0;
+    const int DEFSIZE=0, DEFDELTA=0; 
+    byte  fake_typecode = 0xff;
+
+    char x[2][3][4] 
+      = { { {'a','b','c','d',},             
+            {'e','f','g','h',}, 
+            {'i','j','k','l',}, 
+          },
+          { {'m','n','o','p',},             
+            {'q','r','s','t',}, 
+            {'u','v','w','x',}, 
+          },
+        };
+
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+
+    #if(0)
+    etch_nativearray* a = new_etch_nativearray   /* construct empty native array */
+        (CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type = ETCHTYPEB_BYTE; /* array content is type byte */
+    a->content_class_id = CLASSID_NONE;   /* array content is unwrapped (default) */
+
+    for(i = 0; i < dim2count; i++) /* populate native array iteratively */
+    for(j = 0; j < dim1count; j++) 
+    for(k = 0; k < dim0count; k++) 
+        CU_ASSERT_EQUAL(0, result = a->put3(a, &x[i][j][k], i, j, k)); 
+    #else
+    /* populate native arrary from static test data array */
+
+    etch_nativearray* a = new_etch_nativearray_from(&x, CLASSID_ARRAY_BYTE, 
+        sizeof(byte), numdimensions, dim0count, dim1count, dim2count);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+    a->content_obj_type = ETCHTYPEB_BYTE; /* array content is type byte */
+    a->content_class_id = CLASSID_NONE;   /* array content is unwrapped */
+
+    #endif
+
+    /* populate arrayvalue from native array. we tell the arrayvalue to take  
+     * ownership of the native array. result is a 3-dimensional arrayvalue,
+     * which is represented as an arrayvalue of arrayvalues of arrayvalues.
+     */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, DEFSIZE, DEFDELTA, FALSE);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+    CU_ASSERT_EQUAL(av->dim, numdimensions); 
+    CU_ASSERT_EQUAL(arrayvalue_count(av), dim2count); 
+
+    /* assert that arrayvalue content matches test data */
+    for(i = 0; i < dim2count; i++)
+    {
+        subav1 = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(subav1); 
+        CU_ASSERT_EQUAL(((etch_object*)subav1)->obj_type, ETCHTYPEB_ARRAYVAL);
+        CU_ASSERT_EQUAL(result = arrayvalue_count(subav1), dim1count);
+
+        for(j = 0; j < dim1count; j++)
+        {     
+            subav2 = arrayvalue_get(subav1, j);
+            CU_ASSERT_PTR_NOT_NULL_FATAL(subav2); 
+            CU_ASSERT_EQUAL(((etch_object*)subav2)->obj_type, ETCHTYPEB_ARRAYVAL);
+            CU_ASSERT_EQUAL(result = arrayvalue_count(subav2), dim0count);
+
+            for(k = 0; k < dim0count; k++)
+            {     
+                byte expected_value = x[i][j][k];
+                thisitem = arrayvalue_get(subav2, k);
+                CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+                CU_ASSERT_EQUAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_PRIMITIVE);
+                CU_ASSERT_EQUAL(((etch_object*)thisitem)->class_id, CLASSID_PRIMITIVE_BYTE);
+                CU_ASSERT_EQUAL(((etch_byte*)thisitem)->value, expected_value);
+            }
+        }
+    }
+
+    /* destroy array value and content. memory freed includes the native array 
+     * constructed above, the arrayvalue, its sub-arrayvalues and their sub-
+     * native arrays, and any disposable native array content. 
+     */ 
+    etch_object_destroy(av);  
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_arrayvalue_to_nativearray_10
+ * create create native byte[] array from arrayvalue
+ */
+static void test_arrayvalue_to_nativearray_10(void)
+{
+    etch_arrayvalue* av = NULL;
+    int   i = 0, result = 0;
+    byte  fake_typecode = 0xff;
+    char  x[4] = {'a','b','c','d'};
+    const int numdimensions = 1, itemcount = 4;
+    etch_nativearray* old_nativearray_dangling_ref = NULL;
+
+    etch_nativearray* a = new_etch_nativearray(CLASSID_ARRAY_BYTE, sizeof(byte), numdimensions, itemcount, 0, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+
+    a->content_obj_type  = ETCHTYPEB_BYTE; /* array content is type byte */
+    a->content_class_id  = CLASSID_NONE;   /* array content is unwrapped (default) */
+
+    for(i = 0; i < itemcount; i++) /* populate native array from test data */
+        CU_ASSERT_EQUAL(0, result = a->put1(a, &x[i], i)); 
+
+    /* populate arrayvalue from native array */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, itemcount, 0, FALSE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+    CU_ASSERT_EQUAL(arrayvalue_count(av), itemcount);
+
+    for(i=0; i < itemcount; i++)
+    {     
+        etch_byte* thisitem = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+        CU_ASSERT_EQUAL(thisitem->value, x[i]);
+    }
+
+    /* this will be a dangling pointer after we arrayvalue_to_nativearray() */
+    old_nativearray_dangling_ref = av->natarray;
+
+    /* convert new arrayvalue back to a nativearray. the embedded nativearray 
+     * we created above, is destroyed in the process, and replaced with a new
+     * nativearray, whose content should of course be identical to the old. 
+     */
+    result = arrayvalue_to_nativearray(av); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL (av->natarray); 
+    CU_ASSERT_PTR_NOT_EQUAL_FATAL(av->natarray, old_nativearray_dangling_ref); 
+    CU_ASSERT_EQUAL_FATAL(result,itemcount);  /* returns items inserted count */
+
+    /* get items one at a time from the arrayvalue's new native array,
+     * and compare to expected value from the test data above.
+     */
+    for(i = 0; i < itemcount; i++)  
+    {
+        byte c2=0, c1 = x[i];
+        result = av->natarray->get1(av->natarray, &c2, i);
+        CU_ASSERT_EQUAL(result,0);
+        CU_ASSERT_EQUAL(c1, c2); 
+    }
+
+    etch_object_destroy(av);  /* destroy array value and content */
+}
+
+
+/* 
+ * test_arrayvalue_to_nativearray_20
+ * create create native string[][] array from arrayvalue
+ */
+static void test_arrayvalue_to_nativearray_20(void)
+{
+    etch_arrayvalue* av = NULL;
+    etch_arrayvalue* subav = NULL;
+    etch_string*     thisitem = NULL;
+    byte  fake_typecode = 0xff;
+    const int numdimensions = 2, dim0count = 4, dim1count = 6;
+    const int DEFSIZE=0, DEFDELTA=0; 
+    int   i = 0, j = 0, result = 0;
+    etch_nativearray* old_nativearray_dangling_ref = NULL;
+
+    wchar_t* x[6][4] 
+      = { { L"I think that I", L"shall never see,", L"A poem as lovely", L"as a tree.", }, 
+          { L"She knows not what", L"the curse may be,", L"And so she weaveth", L"steadily,", }, 
+          { L"And little other", L"care hath she,", L"The Lady of Shalott", L".", }, 
+          { L"And therefore I have sailed", L"the seas, and come", L"To the holy city", L"of Byzantium.", },
+          { L"Once out of nature", L"I shall never take", L"My bodily form", L" from any natural thing,", }, 
+          { L"But such a form", L"as Grecian goldsmiths make", L"Of hammered gold ", L"and gold enameling", }, 
+       };
+
+    etch_nativearray* a = new_etch_nativearray_from(&x, CLASSID_ARRAY_STRING, 
+        sizeof(void*), numdimensions, dim0count, dim1count, 0);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+    a->content_obj_type = ETCHTYPEB_STRING; /* content is type string */
+    a->content_class_id = CLASSID_UNWRAPPED;     /* content is unwrapped (default) */
+
+    /* populate arrayvalue from native array as in earlier test */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, DEFSIZE, DEFDELTA, FALSE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+
+    /* this will be a dangling pointer after we arrayvalue_to_nativearray() */
+    old_nativearray_dangling_ref = av->natarray;
+
+    /* convert new arrayvalue back to a nativearray. the embedded nativearray 
+     * we created above, is destroyed in the process, and replaced with a new
+     * nativearray, whose content should of course be identical to the old. 
+     */
+    result = arrayvalue_to_nativearray(av); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL (av->natarray); 
+    CU_ASSERT_PTR_NOT_EQUAL_FATAL(av->natarray, old_nativearray_dangling_ref); 
+    CU_ASSERT_EQUAL_FATAL(result, dim0count * dim1count);   
+  
+    /* get items one at a time from the arrayvalue's new native array,
+     * and compare to expected value from the test data above.
+     */
+    for(i = 0; i < dim1count; i++)
+    {
+        subav = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(subav); 
+        CU_ASSERT_EQUAL(((etch_object*)subav)->obj_type, ETCHTYPEB_ARRAYVAL);
+        CU_ASSERT_EQUAL(result = arrayvalue_count(subav), dim0count);
+
+        for(j = 0; j < dim0count; j++)
+        {     
+            wchar_t* expected_value = x[i][j];
+            thisitem = arrayvalue_get(subav, j);
+            CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+            CU_ASSERT_EQUAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_PRIMITIVE);
+            CU_ASSERT_EQUAL(((etch_object*)thisitem)->class_id, CLASSID_STRING);
+            result = wcscmp(expected_value, thisitem->v.value);
+            CU_ASSERT_EQUAL(result, 0);
+        }
+    }
+
+    etch_object_destroy(av);  /* destroy array value and content */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_arrayvalue_to_nativearray_30
+ * create create native byte[][][] array from arrayvalue
+ */
+static void test_arrayvalue_to_nativearray_30(void)
+{
+    etch_arrayvalue* av = NULL;
+    etch_arrayvalue* subav1 = NULL;
+    etch_arrayvalue* subav2 = NULL;
+    etch_byte* thisitem = NULL;
+    byte  fake_typecode = 0xff;
+    int   i = 0, j = 0, k = 0, result = 0;
+    const int DEFSIZE=0, DEFDELTA=0; 
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+    etch_nativearray* old_nativearray_dangling_ref = NULL;
+
+    char x[2][3][4] 
+      = { { {'a','b','c','d',},             
+            {'e','f','g','h',}, 
+            {'i','j','k','l',}, 
+          },
+          { {'m','n','o','p',},             
+            {'q','r','s','t',}, 
+            {'u','v','w','x',}, 
+          },
+        };
+
+    etch_nativearray* a = new_etch_nativearray_from(&x, CLASSID_ARRAY_BYTE, 
+        sizeof(byte), numdimensions, dim0count, dim1count, dim2count);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(a); 
+    a->content_obj_type = ETCHTYPEB_BYTE; /* content is type byte */
+    a->content_class_id = CLASSID_NONE;   /* content is unwrapped */
+
+    /* populate arrayvalue from native array. we tell the arrayvalue to take  
+     * ownership of the native array. result is a 3-dimensional arrayvalue,
+     * which is represented as an arrayvalue of arrayvalues of arrayvalues.
+     */
+    av = new_arrayvalue_from(a, fake_typecode, NULL, DEFSIZE, DEFDELTA, FALSE);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(av);
+ 
+    /* this will be a dangling pointer after we arrayvalue_to_nativearray() */
+    old_nativearray_dangling_ref = av->natarray;
+
+    /* convert new arrayvalue back to a nativearray. the embedded nativearray 
+     * we created above, is destroyed in the process, and replaced with a new
+     * nativearray, whose content should of course be identical to the old. 
+     */
+    result = arrayvalue_to_nativearray(av); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL (av->natarray); 
+    CU_ASSERT_PTR_NOT_EQUAL_FATAL(av->natarray, old_nativearray_dangling_ref); 
+    CU_ASSERT_EQUAL_FATAL(result, dim0count * dim1count * dim2count);   
+  
+    /* get items one at a time from the arrayvalue's new native array,
+     * and compare to expected value from the test data above.
+     */
+    for(i = 0; i < dim2count; i++)
+    {
+        subav1 = arrayvalue_get(av, i);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(subav1); 
+        CU_ASSERT_EQUAL(((etch_object*)subav1)->obj_type, ETCHTYPEB_ARRAYVAL);
+        CU_ASSERT_EQUAL(result = arrayvalue_count(subav1), dim1count);
+
+        for(j = 0; j < dim1count; j++)
+        {     
+            subav2 = arrayvalue_get(subav1, j);
+            CU_ASSERT_PTR_NOT_NULL_FATAL(subav2); 
+            CU_ASSERT_EQUAL(((etch_object*)subav2)->obj_type, ETCHTYPEB_ARRAYVAL);
+            CU_ASSERT_EQUAL(result = arrayvalue_count(subav2), dim0count);
+
+            for(k = 0; k < dim0count; k++)
+            {     
+                byte expected_value = x[i][j][k];
+                thisitem = arrayvalue_get(subav2, k);
+                CU_ASSERT_PTR_NOT_NULL_FATAL(thisitem); 
+                CU_ASSERT_EQUAL(((etch_object*)thisitem)->obj_type, ETCHTYPEB_PRIMITIVE);
+                CU_ASSERT_EQUAL(((etch_object*)thisitem)->class_id, CLASSID_PRIMITIVE_BYTE);
+                CU_ASSERT_EQUAL(((etch_byte*)thisitem)->value, expected_value);
+            }
+        }
+    }
+
+    etch_object_destroy(av);  /* destroy array value and content */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_arrayvalue_suite()
+{    
+    CU_pSuite pSuite = CU_add_suite("suite_arrayvalue", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test iterator over arraylist",   test_iterator_over_arraylist);
+    #if(0)
+    CU_add_test(pSuite, "test array value read ints",     read_test_integer);
+    CU_add_test(pSuite, "test array value read strings",  read_test_string);
+    CU_add_test(pSuite, "test array value write ints",    write_test_integer);
+    CU_add_test(pSuite, "test array value write strings", write_test_string);
+    #endif
+    CU_add_test(pSuite, "test predefined exception",      exception_test_1);
+    CU_add_test(pSuite, "test copy text exception",       exception_test_2);
+    CU_add_test(pSuite, "test global text exception",     exception_test_3);
+    CU_add_test(pSuite, "test create from byte[]",        test_create_from_1);
+    CU_add_test(pSuite, "test create from int[]",         test_create_from_2);
+    CU_add_test(pSuite, "test create from int64[]",       test_create_from_3);
+    CU_add_test(pSuite, "test create from double[]",      test_create_from_4);
+    CU_add_test(pSuite, "test create from string[]",      test_create_from_5);
+    CU_add_test(pSuite, "test create from byte[][]",      test_create_from_10);
+    CU_add_test(pSuite, "test create from short[][]",     test_create_from_11);
+    CU_add_test(pSuite, "test create from string[][]",    test_create_from_12);
+    CU_add_test(pSuite, "test create from object[][]",    test_create_from_13);
+    CU_add_test(pSuite, "test create from byte[][][]",    test_create_from_21);
+    CU_add_test(pSuite, "test arrayvalue to byte[]",      test_arrayvalue_to_nativearray_10);
+    CU_add_test(pSuite, "test arrayvalue to string[][]",  test_arrayvalue_to_nativearray_20);
+    CU_add_test(pSuite, "test arrayvalue to byte[][][]",  test_arrayvalue_to_nativearray_30);
+
+    return pSuite; 
+}
diff --git a/binding-c/runtime/c/src/test/message/test_binarytditdo.c b/binding-c/runtime/c/src/test/message/test_binarytditdo.c
new file mode 100644
index 0000000..352966e
--- /dev/null
+++ b/binding-c/runtime/c/src/test/message/test_binarytditdo.c
@@ -0,0 +1,2457 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_binarytditdo.c 
+ * test binary input and output
+ */
+
+#include "etch_runtime.h"
+#include "etch_binary_tdi.h"
+#include "etch_binary_tdo.h"
+#include "etch_connection.h"
+#include "etch_default_value_factory.h"
+#include "etch_binary_tdo.h"
+#include "etch_binary_tdi.h"
+#include "etch_messagizer.h"
+#include "etch_resources.h"
+#include "etch_nativearray.h"
+#include "etch_arrayval.h"
+#include "etch_thread.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_map.h"
+#include "etch_log.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - 
+ * unit test support
+ * - - - - - - - - - - - - - -
+ */
+
+static etch_type*  mt_footype;
+static etch_field* mf_fookey;
+static int objcount, arraycount; 
+static unsigned short CLASSID_MY_IMPL_TP;
+
+
+static void this_test_setup()
+{
+    mt_footype = new_static_type(L"footype");
+    mf_fookey  = new_static_field(L"foofield");
+}
+
+static void this_test_teardown()
+{
+    destroy_static_type(mt_footype);
+    destroy_static_field(mf_fookey);
+}
+
+#if 0
+/**
+ * etch_system_nanotime()
+ * operating system specific implementation of java System.nanotime().
+ */
+static int64 etch_system_nanotime()
+{
+    int64 result = 0;
+
+#ifdef WIN32
+    LARGE_INTEGER li;
+    QueryPerformanceCounter(&li);
+    result = li.QuadPart;
+#else
+     #warning etch_system_nanotime have to be checked, we need a nanotime function
+    //TODO check this
+    struct timeval time;
+    gettimeofday(&time, NULL);
+    result = time.tv_usec * 1000;
+#endif
+
+    return result;
+}
+#endif
+
+static signed char* get_test_bytes(signed char minval, int n)
+{
+    int i = 0;
+    signed char* vals = malloc(n * sizeof(char));
+    while(n--) vals[i++] = minval++;
+    return vals;
+}
+
+
+static short* get_test_shorts(short minval, int n)
+{
+    int i = 0;
+    short* vals = malloc(n * sizeof(short));
+    while(n--) vals[i++] = minval++;
+    return vals;
+}
+
+
+static int* get_test_ints(int* out)
+{
+    int n = 65536+2+2, k = 65536+2, i = 0;
+    int minval = ETCHTYPE_MIN_INT16 - 1;
+    int*  vals = malloc(n * sizeof(int));
+    while(k--) vals[i++] = minval++;
+    vals[i++] = ETCHTYPE_MIN_INT32;
+    vals[i++] = ETCHTYPE_MAX_INT32;
+    *out = n;
+    return vals;
+}
+
+
+static int64* get_test_longs(int* out)
+{
+    int n = 65536+2+6, k = 65536+2, i = 0;
+    int minval  = ETCHTYPE_MIN_INT16 - 1;
+    int64* vals = malloc(n * sizeof(int64));
+    while(k--) vals[i++] = minval++;
+    vals[i++] = ETCHTYPE_MIN_INT32;
+    vals[i++] = ETCHTYPE_MAX_INT32;
+    vals[i++] = (int64) ETCHTYPE_MIN_INT32 - 1;
+    vals[i++] = (int64) ETCHTYPE_MAX_INT32 + 1;
+    vals[i++] = ETCHTYPE_MIN_INT64;
+    vals[i++] = ETCHTYPE_MAX_INT64;
+    *out = n;
+    return vals;
+}
+
+
+#if 0
+/**
+ * do_perftest
+ * measure performance of messagizer.transport_message()
+ */
+static void do_perftest(char* name, const int iter, etch_messagizer* messagizer, 
+    etch_message* msg, const int n)
+{
+    int64 t0, t1;
+    double dtime, drate;
+    int i = 0, result = 0;
+    etch_who* whofrom = NULL;
+
+    /* ensure message will not be destroyed by transport_message 
+     * since we invoke transport_message multiple times here */
+    unsigned char save_msg_staticflag = ((etch_object*)msg)->is_static;
+    set_etchobj_static_all(msg); 
+    printf("\n");
+
+    t0 = etch_system_nanotime();
+
+    for(; i < n; i++)
+        result = messagizer->transport_message(messagizer, whofrom, msg);
+
+    t1 = etch_system_nanotime();
+
+    dtime = (t1 - t0) / (double) 1000000000;
+    drate = (double) n / dtime;
+
+    printf("%s iteration %d time %7.3f count %d rate %7.3f\n", name, iter, dtime, n, drate);
+
+    ((etch_object*)msg)->is_static = save_msg_staticflag;
+}
+#endif
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ * my_impl_transportpacket (i_transportpacket implementation) 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * my_impl_transportpacket
+ * test object implementing i_transportpacket
+ */
+typedef struct my_impl_transportpacket
+{
+    etch_object object;
+
+    /* i_transportpacket interface and methods, plus original destructor
+     * which becomes replaced with a custom destructor to destroy this
+     * object. this is the model for destroying an interface wrapper object
+     * when we do not save and pass around a pointer to the wrapper, but rather
+     * a pointer to the interface. the interface in question, i_transportpacket
+     * in this case, contains a pointer to the wrapper object, in this case a
+     * my_impl_transportpacket*. when the interface is instantiated, its original 
+     * destructor is saved, and is replaced with a destructor which invokes
+     * the wrapper's destructor. the wrapper destructor must then know to 
+     * invoke the interface's original destructor when destroying the interface.
+     */
+    i_transportpacket* ixp;           /* owned */ 
+    etch_object_destructor destroy_transportpacket;  /* i_transportpacket original destructor */
+    etch_transport_packet transport_packet;        /* transport_packet() */
+    etch_transport_packet_headersize  header_size; /* header_size() */
+
+    i_sessionpacket* session;         /* not owned */
+
+} my_impl_transportpacket;
+
+
+/**
+ * destroy_my_impl_transportpacket()
+ * my_impl_transportpacket destructor
+ */
+static int destroy_my_impl_transportpacket(void* transport_package)
+{
+    my_impl_transportpacket* thisx = (my_impl_transportpacket*)transport_package;
+
+    if (!is_etchobj_static_content(thisx))
+    {       /* invoke original i_transportpacket destructor */
+        if (thisx->ixp && thisx->destroy_transportpacket)   
+            thisx->destroy_transportpacket(thisx->ixp);
+    }
+
+   return destroy_objectex((etch_object*) thisx);
+}
+
+
+/**
+ * impl_transport_packet()
+ * my_impl_transportpacket::transport_packet
+ * @param whoto caller retains, can be null
+ * @param fbuf caller retains
+ */
+static int impl_transport_packet (void* data, void* whoto, void* fbuf)
+{
+    return 0;
+}
+
+
+/**
+ * my_transport_control()
+ * my_impl_transportpacket::itransport::transport_control 
+ */
+static int my_transport_control (void* data, etch_object* control, etch_object* value)
+{
+    return 0;
+}
+
+
+/**
+ * my_transport_notify()
+ * my_impl_transportpacket::itransport::transport_notify 
+ */
+static int my_transport_notify (i_transportpacket* itp, etch_object* evt)
+{
+    return 0;
+}
+
+
+/**
+ * my_transport_query()
+ * my_impl_transportpacket::itransport::transport_query 
+ */
+static etch_object* my_transport_query (i_transportpacket* itp, etch_object* query) 
+{
+    return NULL;
+}
+
+
+/**
+ * my_transport_get_session()
+ * my_impl_transportpacket::itransport::get_session 
+ */
+static i_sessionpacket* my_transport_get_session(i_transportpacket* itp)
+{
+    my_impl_transportpacket* mytp = itp->thisx; 
+    return mytp->session;
+}
+
+
+/**
+ * my_transport_set_session()
+ * my_impl_transportpacket::itransport::set_session
+ */
+static void my_transport_set_session(i_transportpacket* itp, i_sessionpacket* session)
+{   
+    my_impl_transportpacket* mytp = itp->thisx; 
+    mytp->session = session;
+}
+
+
+/*
+ * destroy_my_transportpacket()
+ * i_transportpacket destructor
+ * this destructor will destroy its parent (my_impl_transportpacket), 
+ * which will in turn destroy this object.
+ */
+static int destroy_my_transportpacket(void* data)
+{
+    i_transportpacket* itp = (i_transportpacket*)data;
+    my_impl_transportpacket* mytp = NULL;
+    if (NULL == itp) return -1;
+
+    mytp = itp->thisx;  
+
+    etch_object_destroy(mytp);
+
+    return 0;
+}
+
+/**
+ * new_my_impl_transportpacket()
+ * my_impl_transportpacket constructor
+ */
+static my_impl_transportpacket* new_my_impl_transportpacket()
+{
+    i_transportpacket* itp  = NULL;
+    i_transport* itransport = NULL;
+    /* this is a model for dynamic class ID assigment */
+    unsigned short class_id = CLASSID_MY_IMPL_TP? CLASSID_MY_IMPL_TP: 
+        (CLASSID_MY_IMPL_TP = get_dynamic_classid());
+
+    my_impl_transportpacket* mytp = (my_impl_transportpacket*) new_object
+      (sizeof(my_impl_transportpacket), ETCHTYPEB_TRANSPORTPKT, class_id);
+
+    ((etch_object*)mytp)->destroy = destroy_my_impl_transportpacket;
+
+    itransport = new_transport_interface_ex(mytp,
+        (etch_transport_control)     my_transport_control, 
+        (etch_transport_notify)      my_transport_notify, 
+        (etch_transport_query)       my_transport_query,
+        (etch_transport_get_session) my_transport_get_session, 
+        (etch_transport_set_session) my_transport_set_session);
+
+    itp = new_transportpkt_interface(mytp, impl_transport_packet, itransport);
+
+    /* save off i_transportpacket destructor */
+    mytp->destroy_transportpacket = ((etch_object*)itp)->destroy;
+
+    /* replace i_transportpacket destructor with one which will destroy this object */
+    ((etch_object*)itp)->destroy = destroy_my_transportpacket;
+
+    /* g_my_transportpacket will get set to this interface */
+    mytp->ixp = itp;  
+
+    return mytp;
+}
+
+
+
+/* - - - - - - - - - - - - - - 
+ * unit tests
+ * - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_constructor_0
+ * verify that memory is freed as expected
+ */
+static void test_constructor_0(void)
+{
+    binary_tagged_data_output* tdo = new_binary_tagdata_output(NULL, NULL);
+
+    etch_object_destroy(tdo);
+
+    etchvf_free_builtins(); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_constructor_1
+ * verify that memory is freed as expected
+ */
+static void test_constructor_1(void)
+{
+
+    default_value_factory*  vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    binary_tagged_data_output* tdo          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    tdo = new_binary_tagdata_output((etch_value_factory*) vf, NULL);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    etch_object_destroy(tdo);
+
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_constructor_2
+ * verify that memory is freed as expected
+ */
+static void test_constructor_2(void)
+{
+    default_value_factory*  vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    binary_tagged_data_output* tdo          = NULL;
+    etch_flexbuffer*        fbuf            = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    fbuf = new_flexbuffer(0);
+    CU_ASSERT_PTR_NOT_NULL(fbuf);
+
+    /* since we pass in vf and buf, we retain ownership */
+    tdo = new_binary_tagdata_output((etch_value_factory*)vf, fbuf);
+    CU_ASSERT_PTR_NOT_NULL(tdo);
+
+    etch_object_destroy(fbuf);
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    etch_object_destroy(tdo);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_check_value()
+ */
+static void test_check_value(void)
+{
+    int  i = 0;
+    signed char typecode = 0;
+    binary_tagged_data_output* tdo = new_binary_tagdata_output(NULL, NULL);
+
+    do  /* check byte values */
+    {   signed char *testbytes = get_test_bytes(ETCHTYPE_MIN_BYTE, 256), c = 0;
+        etch_byte* byteobj = new_byte(0);
+
+        for(i = 0; i < 256; i++)
+        {
+            byteobj->value = c = testbytes[i];
+            typecode = etchtagdata_check_value((etch_object*) byteobj);
+
+            if (is_inrange_tiny_for_signed_chars(c)) 
+               { CU_ASSERT_EQUAL(typecode, c);  }
+            else
+               { CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_BYTE); }
+        }
+
+        free(testbytes);
+        etch_object_destroy(byteobj);
+
+    } while(0);
+
+    do  /* check short values */
+    {   short *testshorts = get_test_shorts(ETCHTYPE_MIN_INT16, 65536), n = 0;
+        etch_int16* shortobj = new_int16(0);
+
+        for(i = 0; i < 65536; i++)
+        {                             
+            shortobj->value = n = testshorts[i];
+            typecode = etchtagdata_check_value((etch_object*) shortobj);
+
+            if (is_inrange_tiny(n)) 
+               { CU_ASSERT_EQUAL(typecode, (signed char) n);  }
+            else
+            if (is_inrange_byte(n))
+               { CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_BYTE); }
+            else
+               { CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_SHORT); }
+        }
+
+        free(testshorts);
+        etch_object_destroy(shortobj);
+
+    } while(0);
+
+    do  /* check int values */
+    {   int intcount = 0, *testints = get_test_ints(&intcount), n = 0;
+        etch_int32* intobj = new_int32(0);
+
+        for(i = 0; i < intcount; i++)
+        {                             
+            intobj->value = n = testints[i];
+            typecode = etchtagdata_check_value((etch_object*) intobj);
+
+            if (is_inrange_tiny(n)) 
+               { CU_ASSERT_EQUAL(typecode, (signed char) n);  }
+            else
+            if (is_inrange_byte(n))
+               { CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_BYTE); }
+            else
+            if (is_inrange_int16(n))
+               { CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_SHORT); }
+            else
+               { CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_INT); }
+        }
+
+        free(testints);
+        etch_object_destroy(intobj);
+
+    } while(0);
+
+    do  /* check long values */
+    {   int   longcount = 0;
+        int64 *testlongs = get_test_longs(&longcount), n = 0;
+        etch_int64* longobj = new_int64(0);
+
+        for(i = 0; i < longcount; i++)
+        {                             
+            longobj->value = n = testlongs[i];
+            typecode = etchtagdata_check_value((etch_object*) longobj);
+
+            if (is_inrange_tiny(n)) 
+               { CU_ASSERT_EQUAL(typecode, (signed char) n);  }
+            else
+            if (is_inrange_byte(n))
+               { CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_BYTE); }
+            else
+            if (is_inrange_int16(n))
+               { CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_SHORT); }
+            else
+            if (is_inrange_int32(n))
+               { CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_INT); }
+            else
+               { CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_LONG); }
+        }
+
+        free(testlongs);
+        etch_object_destroy(longobj);
+
+    } while(0);
+
+    typecode = etchtagdata_check_value(NULL);
+    CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_NULL);
+
+    do {  /* check boolean values */
+        etch_boolean* boolobj = new_boolean(FALSE);
+        typecode = etchtagdata_check_value((etch_object*)boolobj);
+        CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE);
+        boolobj->value = TRUE;
+        typecode = etchtagdata_check_value((etch_object*)boolobj);
+        CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE);
+        etch_object_destroy(boolobj);
+    } while(0);
+
+    do {  /* check ieee values */
+    etch_float* floatobj = new_float((float) 3.14159);
+    etch_double* doubobj = new_double(3.14159);
+    typecode = etchtagdata_check_value((etch_object*)floatobj);
+    CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_FLOAT);
+    typecode = etchtagdata_check_value((etch_object*)doubobj);
+    CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_DOUBLE);
+    etch_object_destroy(floatobj);
+    etch_object_destroy(doubobj);
+    } while(0);
+
+    do {  /* check bytes */
+    etch_nativearray* bytearray = new_etch_nativearray(CLASSID_ARRAY_BYTE, sizeof(byte), 1, 4, 0, 0);  
+    etch_arrayvalue*  arrayvalu = new_arrayvalue(ETCH_XTRNL_TYPECODE_BYTES, NULL, 1, 0, 0, 0, 0);
+    arrayvalu->content_obj_type = ETCHTYPEB_BYTE; 
+    typecode = etchtagdata_check_value((etch_object*)bytearray);
+    CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_BYTES);
+    typecode = etchtagdata_check_value((etch_object*)arrayvalu);
+    CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_BYTES);
+    etch_object_destroy(bytearray);
+    etch_object_destroy(arrayvalu);
+    } while(0);
+
+    do {  /* check string */
+    etch_string* strempty = new_stringw(L"");
+    etch_string* strother = new_stringw(L"x");
+    typecode = etchtagdata_check_value((etch_object*)strempty);
+    CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_EMPTY_STRING);
+    typecode = etchtagdata_check_value((etch_object*)strother);
+    CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_STRING);
+    etch_object_destroy(strempty);
+    etch_object_destroy(strother);
+    } while(0);
+
+    do {  /* check custom */
+    etch_type* newtype = new_type(L"unknown");
+    etch_date* newdate = new_date();
+    etch_structvalue* sv = new_structvalue(newtype, 0);
+    typecode = etchtagdata_check_value((etch_object*)sv);
+    CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_CUSTOM); 
+    typecode = etchtagdata_check_value((etch_object*)newdate);
+    CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_CUSTOM); 
+    etch_object_destroy(newdate);
+    etch_object_destroy(newtype);
+    etch_object_destroy(sv);
+    } while(0);
+
+    do {  /* check end of data marker */
+    etch_object* eodobj = etchtagdata_new_eodmarker(FALSE);  
+    typecode = etchtagdata_check_value((etch_object*)eodobj);
+    CU_ASSERT_EQUAL(typecode, (signed char) ETCH_XTRNL_TYPECODE_NONE); 
+    etch_object_destroy(eodobj);
+    } while(0);
+
+    etch_object_destroy(tdo);
+
+    etchvf_free_builtins(); 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * message_to_bytes()
+ * return the encoded bytes for a message.
+ * caller relinquishes msg, assumes returned bytes.
+ */
+static byte* message_to_bytes(default_value_factory* vf, etch_message* msg, size_t* out)
+{
+    size_t bufcount = 0;
+    byte* msgbytes = NULL;
+
+    etch_flexbuffer* fbuf = new_flexbuffer(ETCH_DEFSIZE);
+    binary_tagged_data_output* tdo = new_binary_tagdata_output(msg->vf, fbuf);
+
+    if (0 == ((struct i_tagged_data_output*)((etch_object*)tdo)->vtab)->write_message((tagged_data_output*) tdo, msg, fbuf))
+    {
+        etch_flexbuf_set_index(fbuf, 0);
+        msgbytes = etch_flexbuf_get_all(fbuf, &bufcount); 
+    }
+                                                                        
+    etch_object_destroy(fbuf);
+    etch_object_destroy(tdo);
+    etch_object_destroy(msg);
+             
+    if (out) *out = bufcount;
+    return msgbytes;
+}
+
+
+/**
+ * bytes_to_message()
+ * return the message constructed from the supplied bytes.
+ * caller relinquishes bytes, assumes returned message.
+ */
+static etch_message* bytes_to_message(default_value_factory* vf, byte* bytes, const size_t bytecount)   
+{           
+    etch_flexbuffer* fbuf = new_flexbuffer_from(bytes, bytecount, bytecount, 0);
+
+    binary_tagged_data_input* tdi = new_binary_tagdata_input((etch_value_factory*) vf);
+
+    etch_message* msg = bintdi_read_message((tagged_data_input*) tdi, fbuf);
+
+    etch_object_destroy(tdi);
+    etch_object_destroy(fbuf);  /* flexbuf destroys bytes */
+    return msg;
+}
+
+
+/**
+ * is_equal_objects()
+ * currently we don't have a convenient way to determine if objects are equal,
+ * primarily because the default hashkey is generated from object address, and
+ * we have to date omitted the equality function from out object definition.
+ * it remains to be seen whether we need a general equality test, in practice
+ * we may only need it for certain high level objects. so we'll wing it for now.
+ */
+static int is_equal_objects(etch_object* a, etch_object* b)
+{
+    if ((((etch_object*)a)->obj_type == b->obj_type) && (((etch_object*)a)->class_id == b->class_id)) 
+        return TRUE;
+
+    /* todo: tests for array type and content comparison here */
+
+    return FALSE;
+}
+
+
+/*
+ * show_value() - debug display for do_tdo_tdi_test()
+ */
+static void show_value(etch_object* obj)
+{
+    #if IS_DEBUG_CONSOLE
+
+    char x[2] = {0,0};
+
+    if (is_etch_byte(obj))  
+    {   x[0] = ((etch_byte*)obj)->value;
+        printf("  >>> '%s'\n", x);  
+    }
+    else 
+    if (is_etch_arrayvalue(obj))
+    {   etch_arrayvalue* av = (etch_arrayvalue*) obj;
+        const int dim = av->dim;
+        const int count = av->list->count;
+        printf("$$$ array dim %d count %d\n", dim, count);  
+    }
+    fflush(stdout);
+
+    #endif
+}
+
+
+/*
+ * do_tdo_tdi_test()
+*/
+static etch_object* do_tdo_tdi_test(default_value_factory* vf, etch_object* thisobj, etch_validator* vtor)
+{
+    etch_message* thismsg = NULL, *resultmsg = NULL;
+    etch_hashitem x, *thisitem = &x; 
+    etch_object* returnobj = NULL;
+    byte*  msgbytes  = NULL;
+    size_t bytecount = 0;
+    int    result = 0;
+    memset(thisitem, 0, sizeof(thisitem));
+    show_value(thisobj); 
+
+    etchtype_clear_validator(mt_footype, mf_fookey);
+    result = etchtype_put_validator (mt_footype, clone_field(mf_fookey), (etch_object*) vtor);
+    CU_ASSERT_EQUAL(result, 0);
+    /* protect caller's object so that temporary owners in this test can't destroy it */
+    set_etchobj_static_all(thisobj); 
+
+    thismsg = new_message(mt_footype, ETCH_DEFSIZE, (etch_value_factory*) vf);
+
+    result  = message_put(thismsg, clone_field(mf_fookey), thisobj);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    /* serialize thismsg. relinquish thismsg, assume msgbytes */
+    msgbytes = message_to_bytes(vf, thismsg, &bytecount); 
+    CU_ASSERT_PTR_NOT_NULL(msgbytes);
+    CU_ASSERT_NOT_EQUAL(bytecount, 0);
+
+    /* deserialize msgbytes. relinquish msgbytes, assume resultmsg */
+    resultmsg = bytes_to_message(vf, msgbytes, bytecount);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(resultmsg);
+
+    result = structvalue_is_type(resultmsg->sv, mt_footype);
+    CU_ASSERT_EQUAL(result, TRUE);
+
+    result = message_size(resultmsg);
+    CU_ASSERT_EQUAL(result, 1);
+
+    result = etchmap_map_find(resultmsg->sv->items, (etch_object*) mf_fookey, &thisitem);
+    CU_ASSERT_EQUAL(result, 0);
+
+    /* we verified that the deserialized message contains caller's reconstituted object.
+     * we want to return that object to caller so that it can be compared with the
+     * original object; however before we return, we are going to destroy the message, 
+     * and since the message owns its content, it will destroy the object we intend to
+     * return, so we remove the object from the message before we destroy the message.
+     * this call frees all hashtable memory associated with this key/value pair except
+     * except for the value object itself, including the key.
+     */
+    if (result == 0)
+        returnobj = message_remove(resultmsg, mf_fookey);
+
+    etch_object_destroy(resultmsg);
+    clear_etchobj_static_all(thisobj); /* unprotect caller's object protected above */  
+    return returnobj;
+}
+
+
+/**
+ * do_recursive_test()
+ * recurse input object creating message from all content from scalar up to top level
+ * enclosing array. serialize and deserialize each message and verify that deserialized
+ * object matches original.
+ */
+static void do_recursive_test(default_value_factory* vf, etch_object* obj, etch_validator* vtor)
+{
+    etch_object* thisobj = obj, *reconstituted_obj = NULL; 
+
+    if (is_etch_arrayvalue(thisobj)) 
+    {
+        etch_iterator iterator;        
+        arrayvalue_set_iterator((etch_arrayvalue*) thisobj, &iterator); 
+
+        while(iterator.has_next(&iterator))
+        {
+            etch_object* subobj = iterator.current_value;
+
+            do_recursive_test(vf, subobj, vtor->element_validator(vtor)); 
+
+            iterator.next(&iterator);
+        }
+    }
+    /* printf("\n(%05d. type %d class %d)\n", ++objcount, ((etch_object*)obj)->obj_type, ((etch_object*)obj)->class_id); fflush(stdout); */
+   
+    reconstituted_obj = do_tdo_tdi_test(vf, thisobj, vtor);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(reconstituted_obj);
+    CU_ASSERT_EQUAL(is_equal_objects(thisobj, reconstituted_obj), TRUE);     
+    etch_object_destroy(reconstituted_obj);
+}
+
+#ifdef _WIN32
+#pragma message ( "test_byte_array_out_in deactivated" )
+#else
+#warning "test_byte_array_out_in deactivated"
+#endif
+
+#if 0
+/**
+ * test_byte_array_out_in()
+ * test serialization and subsequent deserialization of a byte array
+ */
+static void test_byte_array_out_in(void)
+{
+    const int NUMDIMS = 2;
+    char  x[2][3] = { {'a','b','c', }, {'d','e','f', }, };
+    default_value_factory*  vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    etch_nativearray*       natarray        = NULL;
+    etch_arrayvalue*        arrayval        = NULL;
+    etch_arrayvalue* reconstituted_arrayval = NULL;
+    etch_validator*         validator       = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    natarray  = new_etch_nativearray_from(x, CLASSID_ARRAY_BYTE, sizeof(byte), NUMDIMS, 3, 2, 0);
+    arrayval  = new_arrayvalue_from(natarray, ETCH_XTRNL_TYPECODE_BYTES, NULL, 2, 0, FALSE);
+    validator = etchvtor_byte_get(NUMDIMS);
+
+    this_test_setup();
+    ((struct i_value_factory*)((etch_object*)vf)->vtab)->add_type(vf, mt_footype); /* the type we are testing with */
+    objcount = arraycount = 0; /* initialize global counters */
+
+    /* test serialization and deserialization of the array object as a whole. 
+     * we are returned an object which is the reconstituted array after it has
+     * been serialized and subsequently deserialized */
+    reconstituted_arrayval = (etch_arrayvalue*) do_tdo_tdi_test
+        (vf, (etch_object*) arrayval, validator);
+
+    CU_ASSERT_EQUAL_FATAL(is_etch_arrayvalue(reconstituted_arrayval), TRUE);
+
+    /* recursively test serialization and deserialization of all the components 
+     * of the array object, including the array itself, subarrays, and scalars,
+     * as per the java version of this test. this really ensures that we have 
+     * all our memory management ducks in a row. */
+
+    do_recursive_test (vf, (etch_object*) arrayval, validator);
+
+    etch_object_destroy(arrayval);
+    etch_object_destroy(reconstituted_arrayval);
+   
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    this_test_teardown();
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+#endif
+
+/**
+ * test_bool_array_out_in()
+ * test serialization and subsequent deserialization of a boolean array
+ */
+static void test_bool_array_out_in(void)
+{
+    const int NUMDIMS = 2;
+    boolean x[2][3] = { { TRUE, FALSE, TRUE, }, { FALSE, TRUE, FALSE, }, };
+    default_value_factory*  vf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    etch_nativearray*       natarray        = NULL;
+    etch_arrayvalue*        arrayval        = NULL;
+    etch_arrayvalue* reconstituted_arrayval = NULL;
+    etch_validator*         validator       = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    natarray  = new_etch_nativearray_from(x, CLASSID_ARRAY_BOOL, sizeof(boolean), NUMDIMS, 3, 2, 0);
+    arrayval  = new_arrayvalue_from(natarray, ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE, NULL, 2, 0, FALSE);
+    validator = etchvtor_boolean_get(NUMDIMS);
+
+    this_test_setup();
+    ((struct i_value_factory*)((etch_object*)vf)->vtab)->add_type(vf, mt_footype); /* the type we are testing with */
+    objcount = arraycount = 0; /* initialize global counters */
+
+    /* test serialization and deserialization of the array object as a whole. 
+     * we are returned an object which is the reconstituted array after it has
+     * been serialized and subsequently deserialized */
+    reconstituted_arrayval = (etch_arrayvalue*) do_tdo_tdi_test(vf, (etch_object*) arrayval, validator);
+
+    CU_ASSERT_EQUAL_FATAL(is_etch_arrayvalue(reconstituted_arrayval), TRUE);
+
+    /* recursively test serialization and deserialization of all the components 
+     * of the array object, including the array itself, subarrays, and scalars,
+     * as per the java version of this test. this really ensures that we have 
+     * all our memory management ducks in a row. */
+
+    do_recursive_test (vf, (etch_object*) arrayval, validator);
+
+    etch_object_destroy(arrayval);
+    etch_object_destroy(reconstituted_arrayval);
+   
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    this_test_teardown();
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_short_array_out_in()
+ * test serialization and subsequent deserialization of a short integer array
+ */
+static void test_short_array_out_in(void)
+{
+    const int NUMDIMS = 2;
+    short x[2][3] = { { 0, 1, 2, }, { -1, -32768, 32767, }, };
+    default_value_factory*  vf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    etch_nativearray*       natarray        = NULL;
+    etch_arrayvalue*        arrayval        = NULL;
+    etch_arrayvalue* reconstituted_arrayval = NULL;
+    etch_validator*         validator       = NULL;
+
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    natarray  = new_etch_nativearray_from(x, CLASSID_ARRAY_INT16, sizeof(short), NUMDIMS, 3, 2, 0);
+    arrayval  = new_arrayvalue_from(natarray, ETCH_XTRNL_TYPECODE_SHORT, NULL, 2, 0, FALSE);
+    validator = etchvtor_int16_get(NUMDIMS);
+
+    this_test_setup();
+    ((struct i_value_factory*)((etch_object*)vf)->vtab)->add_type(vf, mt_footype); /* the type we are testing with */
+    objcount = arraycount = 0; /* initialize global counters */
+
+    /* test serialization and deserialization of the array object as a whole. 
+     * we are returned an object which is the reconstituted array after it has
+     * been serialized and subsequently deserialized */
+    reconstituted_arrayval = (etch_arrayvalue*) do_tdo_tdi_test(vf, (etch_object*) arrayval, validator);
+
+    CU_ASSERT_EQUAL_FATAL(is_etch_arrayvalue(reconstituted_arrayval), TRUE);
+
+    /* recursively test serialization and deserialization of all the components 
+     * of the array object, including the array itself, subarrays, and scalars,
+     * as per the java version of this test. this really ensures that we have 
+     * all our memory management ducks in a row. */
+
+    do_recursive_test (vf, (etch_object*) arrayval, validator);
+
+    etch_object_destroy(arrayval);
+    etch_object_destroy(reconstituted_arrayval);
+    
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    this_test_teardown();
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_int_array_out_in()
+ * test serialization and subsequent deserialization of an int array
+ */
+static void test_int_array_out_in(void)
+{
+    const int NUMDIMS = 2;
+    int x[2][3] = { { 0, 1, 2, }, { -1, ETCHTYPE_MIN_INT32, ETCHTYPE_MAX_INT32, }, };
+    default_value_factory*  vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    etch_nativearray*       natarray        = NULL;
+    etch_arrayvalue*        arrayval        = NULL;
+    etch_arrayvalue* reconstituted_arrayval = NULL;
+    etch_validator*         validator       = NULL;
+
+    
+     typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    natarray  = new_etch_nativearray_from(x, CLASSID_ARRAY_INT32, sizeof(int), NUMDIMS, 3, 2, 0);
+    arrayval  = new_arrayvalue_from(natarray, ETCH_XTRNL_TYPECODE_INT, NULL, 2, 0, FALSE);
+    validator = etchvtor_int32_get(NUMDIMS);
+
+    this_test_setup();
+    ((struct i_value_factory*)((etch_object*)vf)->vtab)->add_type(vf, mt_footype); /* the type we are testing with */
+    objcount = arraycount = 0; /* initialize global counters */
+
+    /* test serialization and deserialization of the array object as a whole. 
+     * we are returned an object which is the reconstituted array after it has
+     * been serialized and subsequently deserialized */
+    reconstituted_arrayval = (etch_arrayvalue*) do_tdo_tdi_test(vf, (etch_object*) arrayval, validator);
+
+    CU_ASSERT_EQUAL_FATAL(is_etch_arrayvalue(reconstituted_arrayval), TRUE);
+
+    /* recursively test serialization and deserialization of all the components 
+     * of the array object, including the array itself, subarrays, and scalars,
+     * as per the java version of this test. this really ensures that we have 
+     * all our memory management ducks in a row. */
+
+    do_recursive_test (vf, (etch_object*) arrayval, validator);
+
+    etch_object_destroy(arrayval);
+    etch_object_destroy(reconstituted_arrayval);
+   
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    this_test_teardown();
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_long_array_out_in()
+ * test serialization and subsequent deserialization of a long array
+ */
+static void test_long_array_out_in(void)
+{
+    const int NUMDIMS = 2;
+    int64 x[2][3] = { { 0, 1, 2, }, { -1, ETCHTYPE_MIN_INT64, ETCHTYPE_MAX_INT64, }, };
+    default_value_factory*  vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    etch_nativearray*       natarray        = NULL;
+    etch_arrayvalue*        arrayval        = NULL;
+    etch_arrayvalue* reconstituted_arrayval = NULL;
+    etch_validator*         validator       = NULL;
+    
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    natarray  = new_etch_nativearray_from(x, CLASSID_ARRAY_INT64, sizeof(int64), NUMDIMS, 3, 2, 0);
+    arrayval  = new_arrayvalue_from(natarray, ETCH_XTRNL_TYPECODE_LONG, NULL, 2, 0, FALSE);
+    validator = etchvtor_int64_get(NUMDIMS);
+
+    this_test_setup();
+    ((struct i_value_factory*)((etch_object*)vf)->vtab)->add_type(vf, mt_footype); /* the type we are testing with */
+    objcount = arraycount = 0; /* initialize global counters */
+
+    /* test serialization and deserialization of the array object as a whole. 
+     * we are returned an object which is the reconstituted array after it has
+     * been serialized and subsequently deserialized */
+    reconstituted_arrayval = (etch_arrayvalue*) do_tdo_tdi_test(vf, (etch_object*) arrayval, validator);
+
+    CU_ASSERT_EQUAL_FATAL(is_etch_arrayvalue(reconstituted_arrayval), TRUE);
+
+    /* recursively test serialization and deserialization of all the components 
+     * of the array object, including the array itself, subarrays, and scalars,
+     * as per the java version of this test. this really ensures that we have 
+     * all our memory management ducks in a row. */
+
+    do_recursive_test (vf, (etch_object*) arrayval, validator);
+
+    etch_object_destroy(arrayval);
+    etch_object_destroy(reconstituted_arrayval);
+   
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    this_test_teardown();
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_float_array_out_in()
+ * test serialization and subsequent deserialization of a float array
+ */
+static void test_float_array_out_in(void)
+{
+    const int NUMDIMS = 2;
+    float x[2][3] = { { 0.0, 1.0, 2.0, }, { -1.0, ETCHTYPE_MIN_FLOAT, ETCHTYPE_MAX_FLOAT, }, };
+    default_value_factory*  vf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    etch_nativearray*       natarray        = NULL;
+    etch_arrayvalue*        arrayval        = NULL;
+    etch_arrayvalue* reconstituted_arrayval = NULL;
+    etch_validator*         validator       = NULL;
+
+     typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    natarray  = new_etch_nativearray_from(x, CLASSID_ARRAY_FLOAT, sizeof(float), NUMDIMS, 3, 2, 0);
+    arrayval  = new_arrayvalue_from(natarray, ETCH_XTRNL_TYPECODE_FLOAT, NULL, 2, 0, FALSE);
+    validator = etchvtor_float_get(NUMDIMS);
+
+    this_test_setup();
+    ((struct i_value_factory*)((etch_object*)vf)->vtab)->add_type(vf, mt_footype); /* the type we are testing with */
+    objcount = arraycount = 0; /* initialize global counters */
+
+    /* test serialization and deserialization of the array object as a whole. 
+     * we are returned an object which is the reconstituted array after it has
+     * been serialized and subsequently deserialized */
+    reconstituted_arrayval = (etch_arrayvalue*) do_tdo_tdi_test(vf, (etch_object*) arrayval, validator);
+
+    CU_ASSERT_EQUAL_FATAL(is_etch_arrayvalue(reconstituted_arrayval), TRUE);
+
+    /* recursively test serialization and deserialization of all the components 
+     * of the array object, including the array itself, subarrays, and scalars,
+     * as per the java version of this test. this really ensures that we have 
+     * all our memory management ducks in a row. */
+
+    do_recursive_test (vf, (etch_object*) arrayval, validator);
+
+    etch_object_destroy(arrayval);
+    etch_object_destroy(reconstituted_arrayval);
+   
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    this_test_teardown();
+    
+    // TODO: cleanup statics
+    // etchvf_free_builtins()
+
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_double_array_out_in()
+ * test serialization and subsequent deserialization of a double array
+ */
+static void test_double_array_out_in(void)
+{
+    const int NUMDIMS = 2;
+    double x[2][3] = { { 0.0, 1.0, 2.0, }, { -1.0, ETCHTYPE_MIN_DOUBLE, ETCHTYPE_MAX_DOUBLE, }, };
+    default_value_factory*  vf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    etch_nativearray*       natarray        = NULL;
+    etch_arrayvalue*        arrayval        = NULL;
+    etch_arrayvalue* reconstituted_arrayval = NULL;
+    etch_validator*         validator       = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    natarray  = new_etch_nativearray_from(x, CLASSID_ARRAY_DOUBLE, sizeof(double), NUMDIMS, 3, 2, 0);
+    arrayval  = new_arrayvalue_from(natarray, ETCH_XTRNL_TYPECODE_DOUBLE, NULL, 2, 0, FALSE);
+    validator = etchvtor_double_get(NUMDIMS);
+
+    this_test_setup();
+    ((struct i_value_factory*)((etch_object*)vf)->vtab)->add_type(vf, mt_footype); /* the type we are testing with */
+    objcount = arraycount = 0; /* initialize global counters */
+
+    /* test serialization and deserialization of the array object as a whole. 
+     * we are returned an object which is the reconstituted array after it has
+     * been serialized and subsequently deserialized */
+    reconstituted_arrayval = (etch_arrayvalue*) do_tdo_tdi_test(vf, (etch_object*) arrayval, validator);
+
+    CU_ASSERT_EQUAL_FATAL(is_etch_arrayvalue(reconstituted_arrayval), TRUE);
+
+    /* recursively test serialization and deserialization of all the components 
+     * of the array object, including the array itself, subarrays, and scalars,
+     * as per the java version of this test. this really ensures that we have 
+     * all our memory management ducks in a row. */
+
+    do_recursive_test (vf, (etch_object*) arrayval, validator);
+
+    etch_object_destroy(arrayval);
+    etch_object_destroy(reconstituted_arrayval);
+   
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    this_test_teardown();
+    
+    // TODO: cleanup statics
+    // etchvf_free_builtins()
+
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+static etch_string* ns(int n) 
+{ 
+    wchar_t buf[32]; etch_snwprintf(buf, 32, L"%d", (size_t) n);
+    return new_stringw(buf);
+}
+
+
+/**
+ * test_string_array_out_in()
+ * test serialization and subsequent deserialization of a string array
+ */
+static void test_string_array_out_in(void)
+{
+    const int NUMDIMS = 2;
+    etch_string* x[2][3] = { { ns(0), ns(1), ns(2), }, { ns(3), ns(4), ns(5), }, };
+    default_value_factory*  vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    etch_nativearray*       natarray        = NULL;
+    etch_arrayvalue*        arrayval        = NULL;
+    etch_arrayvalue* reconstituted_arrayval = NULL;
+    etch_validator*         validator       = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+
+    natarray  = new_etch_nativearray_from(x, CLASSID_ARRAY_STRING, sizeof(void*), NUMDIMS, 3, 2, 0);
+    arrayval  = new_arrayvalue_from(natarray, ETCH_XTRNL_TYPECODE_STRING, NULL, 2, 0, FALSE);
+    validator = etchvtor_string_get(NUMDIMS);
+
+    this_test_setup();
+    ((struct i_value_factory*)((etch_object*)vf)->vtab)->add_type(vf, mt_footype); /* the type we are testing with */
+    objcount = arraycount = 0; /* initialize global counters */
+
+    /* test serialization and deserialization of the array object as a whole. 
+     * we are returned an object which is the reconstituted array after it has
+     * been serialized and subsequently deserialized */
+    reconstituted_arrayval = (etch_arrayvalue*) do_tdo_tdi_test(vf, (etch_object*) arrayval, validator);
+
+    CU_ASSERT_EQUAL_FATAL(is_etch_arrayvalue(reconstituted_arrayval), TRUE);
+
+    /* recursively test serialization and deserialization of all the components 
+     * of the array object, including the array itself, subarrays, and scalars,
+     * as per the java version of this test. this really ensures that we have 
+     * all our memory management ducks in a row. */
+
+    do_recursive_test (vf, (etch_object*) arrayval, validator);
+
+    etch_object_destroy(arrayval);
+    etch_object_destroy(reconstituted_arrayval);
+   
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    this_test_teardown();
+    
+    // TODO: cleanup statics
+    // etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+#ifdef _WIN32
+#pragma message ( "test_add_perf deactivated" )
+#else
+#warning "test_add_perf deactivated"
+#endif
+
+#if 0
+/**
+ * test_add_perf()
+ * test performance of add(x,y) message serialization and delivery
+ */
+static void test_add_perf(void)
+{
+    int result = 0;
+    etch_who* whofrom = NULL;
+    etch_message* msg = NULL;
+    etch_messagizer* messagizer = NULL;
+    i_transportpacket* my_packetsource = NULL;
+    my_impl_transportpacket* my_impl_packetsource = NULL;
+    default_value_factory*  vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    etch_type*  addtype = NULL;
+    etch_field* xfield  = NULL;
+     etch_field* yfield = NULL;
+     etch_resources* resx = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+    
+    resx = new_etch_resources(ETCH_RESOURCES_DEFSIZE);
+
+    addtype = new_type(L"add");
+    xfield  = new_field(L"x");
+    yfield  = new_field(L"y");
+
+    etchtype_put_validator(addtype, clone_field(xfield), (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(addtype, clone_field(yfield), (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(addtype, clone_field(builtins._mf__message_id), (etch_object*) etchvtor_int64_get(0));
+
+    msg = new_message(addtype, ETCH_DEFSIZE, (etch_value_factory*) vf);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(msg);
+    message_put(msg, clone_field(xfield), (etch_object*) new_int32(1));  /* relinquish all content */
+    message_put(msg, clone_field(yfield), (etch_object*) new_int32(2));
+    message_put(msg, clone_field(builtins._mf__message_id), (etch_object*) new_int64(0x0123456789abcdefLL));   
+
+    /* we relinquish vf to the resources destructor here */
+    etch_resources_add(resx, ETCH_RESXKEY_MSGIZER_VALUFACT, (etch_object*) vf); 
+
+    /* instantiate object which implements i_transportpacket and extract its interface.
+     * the interface's destructor is coded to destroy its instantiating object. */
+    my_impl_packetsource = new_my_impl_transportpacket();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_impl_packetsource);
+    my_packetsource = my_impl_packetsource->ixp; /* extract interface */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(my_packetsource); 
+
+    messagizer = new_messagizer(my_packetsource, L"foo:?Messagizer.format=binary", resx);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(messagizer);  
+
+    /* we need to continue to use the message in this test, so since the message's
+     * destructor will be called by messagizer.transport_message(), mark the message
+     * static such that it is protected from destruction.
+     */
+    set_etchobj_static_all(msg); 
+
+    /* we ordinarily relinquish msg on success, retain it on failure;  
+     * however here we have retained it regardless, since we marked it  
+     * static above, thus disabling its destructor. 
+     */
+    result = messagizer->transport_message(messagizer, whofrom, msg);
+    CU_ASSERT_EQUAL(result, 0);  
+
+    if (0 == result)
+    {   int i = 0;
+        const int n = 900973; /* this code is ported from the java test */
+
+        for(i = 0; i < 3; i++)
+            do_perftest("test_add_perf", i, messagizer, msg, n);
+    }
+
+    clear_etchobj_static_all(msg);  /* clear static state so we can destroy it now */
+    etch_object_destroy(msg);
+
+    etch_object_destroy(xfield);
+    etch_object_destroy(yfield);
+    etch_object_destroy(addtype);
+
+    etch_object_destroy(resx);  /* content is destroyed also (vf in this case) */
+    etch_object_destroy(messagizer);
+    etch_object_destroy(my_packetsource); /* destroys my_impl_transportpacket also */
+    
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+#endif
+
+/**
+ * get_bytearray()
+ * support for test_value_to_bytes().
+ * return an etch_nativearray wrapping the supplied static byte* array.
+ */
+static etch_nativearray* get_bytearray(byte* bytes, const int bytecount)
+{ 
+    etch_nativearray* na = new_etch_nativearray_from(bytes, CLASSID_ARRAY_BYTE, sizeof(byte), 1, bytecount, 0, 0);  
+    na->content_obj_type = ETCHTYPEB_BYTES;
+    na->content_class_id = CLASSID_NONE; /* unwrapped */
+    return na;
+}
+
+ 
+ /**
+ * assert_value_to_bytes()
+ * support for test_value_to_bytes() -- serialize value object, and assert 
+ * that the serialized bytes match the supplied expected byte array.
+ */
+static int assert_value_to_bytes(etch_object* value, etch_nativearray* expected_bytes, etch_value_factory* vf)
+{
+    byte* buf = NULL;
+    int  bytecount = 0, i = 0, result = 0, errs = 0;
+    etch_flexbuffer* fbuf = new_flexbuffer(ETCH_DEFSIZE);
+    etch_validator*  vtor = etchvtor_object_get(0);
+
+    binary_tagged_data_output* tdo = new_binary_tagdata_output(vf, fbuf);
+
+    /* serialize the specified value object to the buffer fbuf */
+    result = bintdo_write_value(tdo, vtor, value);
+    CU_ASSERT_EQUAL(result, 0);
+    if (0 != result) errs++;
+
+    if (0 == result)
+    {
+        fbuf->index = 0; /* get the serialized bytes to a new buffer */
+        buf = etch_flexbuf_get_all(fbuf, (size_t*) &bytecount); 
+
+	printf("%d <-> %d\n", bytecount, (int)expected_bytes->bytecount);
+        CU_ASSERT_EQUAL(bytecount, expected_bytes->bytecount);
+        if (bytecount != expected_bytes->bytecount) errs++;
+
+        if (bytecount == expected_bytes->bytecount)
+        {   /* verify that serialized bytes match expected bytes  */
+            for(i = 0; i < bytecount; i++)
+            {   signed char a = buf[i], b = 0;
+                expected_bytes->get1(expected_bytes, &b, i);
+                result = ((int) a == (int) b);
+                CU_ASSERT_EQUAL(result, TRUE);
+                if (!result) 
+                    errs++;
+            }
+        }
+    }
+
+    /* free memory */
+    etch_object_destroy(value);
+    etch_object_destroy(expected_bytes);
+    etch_object_destroy(tdo);
+    etch_object_destroy(fbuf);
+    etch_free(buf);
+
+    return errs? -1: 0;
+}
+
+
+/**
+ * test_single_value_to_bytes()
+ * test that various value objects serialized by the tdo match hard-coded expected byte arrays
+ */
+static void test_single_value_to_bytes(void)
+{
+    int  result = 0;
+    etch_value_factory*  vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = (etch_value_factory*)new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+    
+    do  /* NULL */
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_NULL }; 
+        result = assert_value_to_bytes(NULL, get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do  /* boolean primitive objects */
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE }; 
+        result = assert_value_to_bytes((etch_object*) new_boolean(FALSE), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do 
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE }; 
+        result = assert_value_to_bytes((etch_object*) new_boolean(TRUE), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do  /* some tiny integers */
+    {   signed char a[] = { 0 }; 
+        result = assert_value_to_bytes((etch_object*) new_byte(0), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do   
+    {   signed char a[] = { 1 }; 
+        result = assert_value_to_bytes((etch_object*) new_byte(1), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do   
+    {   signed char a[] = { -1 }; 
+        result = assert_value_to_bytes((etch_object*) new_byte(-1), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do  /* non-tinyint byte */
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_BYTE, -100 }; 
+        result = assert_value_to_bytes((etch_object*) new_byte(-100), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do  /* some short integers */
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_SHORT, 39, 16 }; 
+        result = assert_value_to_bytes((etch_object*) new_int16(10000), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do   
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_SHORT, -40, -16 }; 
+        result = assert_value_to_bytes((etch_object*) new_int16(-10000), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do  /* 32-bit integers */
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_INT, 59, -102, -54, 0 }; 
+        result = assert_value_to_bytes((etch_object*) new_int32(1000000000), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do   
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_INT, -60, 101, 54, 0 }; 
+        result = assert_value_to_bytes((etch_object*) new_int32(-1000000000), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do  /* long integers */
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_LONG, 13, -32, -74, -77, -89, 100, 0, 0 }; 
+        result = assert_value_to_bytes((etch_object*) new_int64(1000000000000000000LL), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do   
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_LONG, -14, 31, 73, 76, 88, -100, 0, 0 }; 
+        result = assert_value_to_bytes((etch_object*) new_int64(-1000000000000000000LL), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do  /* float */
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_FLOAT, 70, 64, -28, 0 }; 
+        result = assert_value_to_bytes((etch_object*) new_float(12345.0), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    do  /* double */
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_DOUBLE, 64, -42, -24, 0, 0, 0, 0, 0 }; 
+        result = assert_value_to_bytes((etch_object*) new_double(23456.0), get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+    } while(0);
+
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_boolean_array_value_to_bytes()
+ * test that various value objects serialized by the tdo match hard-coded expected byte arrays
+ */
+static void test_boolean_array_value_to_bytes(void)
+{
+    int  result = 0;
+    etch_value_factory*     vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = (etch_value_factory*)new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    do  /* boolean[] */
+    {   const int NUMDIMS1 = 1, ITEMCOUNT = 2;
+
+        signed char a[] =
+        { ETCH_XTRNL_TYPECODE_ARRAY, /* array type */
+          ETCH_XTRNL_TYPECODE_BOOLEAN_CONTENT, /* array content type */
+          NUMDIMS1,  /* dimensions count */
+          ITEMCOUNT, /* count of content items following */
+          ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE,   /* item[0] */
+          ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE,  /* item[1] */
+          ETCH_XTRNL_TYPECODE_NONE /* eod mark */
+        }; 
+
+        etch_arrayvalue* av = new_arrayvalue(ETCH_XTRNL_TYPECODE_BOOLEAN_CONTENT, 
+            NULL, NUMDIMS1, ITEMCOUNT, 0, FALSE, FALSE);
+
+        arrayvalue_add(av, (etch_object*) new_boolean(TRUE));
+        arrayvalue_add(av, (etch_object*) new_boolean(FALSE));
+ 
+        result = assert_value_to_bytes((etch_object*) av, get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+    
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_byte_array_value_to_bytes()
+ * test that various value objects serialized by the tdo match hard-coded expected byte arrays
+ */
+static void test_byte_array_value_to_bytes(void)
+{
+    int  result = 0;
+    etch_value_factory*     vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = (etch_value_factory*)new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    do  /* byte[] */
+    {   const int ITEMCOUNT = 3;
+        signed char content[] = { 1, 2, 3 };
+
+        signed char a[] =  /* byte vector is a special case, not an array type */
+        { ETCH_XTRNL_TYPECODE_BYTES, /* array content type */
+          ITEMCOUNT,  /* count of items following */
+          1,   /* item[0] */
+          2,   /* item[1] */
+          3    /* item[2] */
+        }; 
+
+        etch_nativearray* expected = get_bytearray((byte*)a, sizeof(a));
+
+        /* memory management notes: here we create a nativearray na from static
+         * content. new_etch_nativearray_from() defaults nativearray.is_content_owned   
+         * to false, so when the nativearray na is destroyed, it will not attempt 
+         * to free memory for the static content bytes. we then create an arrayvalue 
+         * from nativearray na, specifying FALSE for parameter 6, is_readonly. the  
+         * arrayvalue destructor will as a result destroy the content nativearray, 
+         * which will in turn *not* destroy its content bytearray. finally, we   
+         * relinquish the arrayvalue to assert_value_to_bytes(), which calls the 
+         * arrayvalue destructor, causing the above to occur.
+         */
+        etch_nativearray* na = new_etch_nativearray_from(content, CLASSID_ARRAY_BYTE, sizeof(byte), 1, ITEMCOUNT, 0, 0); 
+        etch_arrayvalue*  av = new_arrayvalue_from(na, ETCH_XTRNL_TYPECODE_BYTE, NULL, ITEMCOUNT, 0, FALSE);
+      
+        result = assert_value_to_bytes((etch_object*) av, expected, vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+
+    do  /* byte[][] */
+    {   
+        #define NUMDIMS2   2
+        #define ITEMCOUNT2 2
+        #define ITEMCOUNT3 3
+        signed char content[NUMDIMS2][ITEMCOUNT3] = { { 1, 2, 3, }, { 4, 5, 6, }, };
+
+        signed char a[] =    /* array[2] of byte vectors */
+        { ETCH_XTRNL_TYPECODE_ARRAY, /* value type array */    
+          ETCH_XTRNL_TYPECODE_BYTE,  /* array content type */  
+          NUMDIMS2,                  /* dimensions count */
+          ITEMCOUNT2,                /* item count in dim[1] */
+	      ETCH_XTRNL_TYPECODE_BYTES, /* byte vector follows */
+          ITEMCOUNT3,                /* count of items following */
+          1,                         /* item[0][0] */
+          2,                         /* item[0][1] */
+          3,                         /* item[0][2] */          
+	      ETCH_XTRNL_TYPECODE_BYTES, /* byte vector follows */
+          ITEMCOUNT3,                /* count of items following */
+          4,                         /* item[1][0] */
+          5,                         /* item[1][1] */
+          6,                         /* item[1][2] */             
+          ETCH_XTRNL_TYPECODE_NONE   /* eod mark */
+        }; 
+
+        etch_nativearray* expected = get_bytearray((byte*)a, sizeof(a));
+
+        /* memory management notes: here we create a nativearray na from static
+         * content. new_etch_nativearray_from() defaults nativearray.is_content_owned   
+         * to false, so when the nativearray na is destroyed, it will not attempt 
+         * to free memory for the static content bytes. we then create an arrayvalue 
+         * from nativearray na, specifying FALSE for parameter 6, is_readonly. the  
+         * arrayvalue destructor will as a result destroy the content nativearray, 
+         * which will in turn *not* destroy its content bytearray. finally, we   
+         * relinquish the arrayvalue to assert_value_to_bytes(), which calls the 
+         * arrayvalue destructor, causing the above to occur.
+         */
+        etch_nativearray* na = new_etch_nativearray_from(content, CLASSID_ARRAY_BYTE, 
+            sizeof(byte), NUMDIMS2, ITEMCOUNT3, ITEMCOUNT2, 0); 
+
+        /* note here that the arrayvalue content type (ETCH_XTRNL_TYPECODE_BYTE)
+         * is the content type serialized, so it must be the same as a[1].
+         * the serialized type of arrays of byte vectors is BYTE, as defined by the 
+         * tagged data spec, and not BYTES, which one might expect
+         */
+        etch_arrayvalue*  av = new_arrayvalue_from(na, ETCH_XTRNL_TYPECODE_BYTE, 
+            NULL, ETCH_DEFSIZE, 0, FALSE);
+      
+        result = assert_value_to_bytes((etch_object*) av, expected, vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_short_array_value_to_bytes()
+ * test that various value objects serialized by the tdo match hard-coded expected byte arrays
+ */
+static void test_short_array_value_to_bytes(void)
+{
+    int  result = 0;
+    etch_value_factory*     vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = (etch_value_factory*)new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    do  /* short[] */
+    {   const int NUMDIMS1 = 1, ITEMCOUNT = 3;
+
+        signed char a[] =
+        { ETCH_XTRNL_TYPECODE_ARRAY, /* array type */
+          ETCH_XTRNL_TYPECODE_SHORT, /* array content type */
+          NUMDIMS1,  /* dimensions count */
+          ITEMCOUNT, /* count of content items following */
+          1,   /* item[0] */
+          2,   /* item[1] */
+          3,   /* item[2] */
+          ETCH_XTRNL_TYPECODE_NONE  /* eod mark */
+        }; 
+
+        etch_arrayvalue* av = new_arrayvalue(ETCH_XTRNL_TYPECODE_SHORT, 
+            NULL, NUMDIMS1, ITEMCOUNT, 0, FALSE, FALSE);
+
+        arrayvalue_add(av, (etch_object*) new_int16(1));
+        arrayvalue_add(av, (etch_object*) new_int16(2));
+        arrayvalue_add(av, (etch_object*) new_int16(3));
+ 
+        result = assert_value_to_bytes((etch_object*) av, get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_int_array_value_to_bytes()
+ * test that various value objects serialized by the tdo match hard-coded expected byte arrays
+ */
+static void test_int_array_value_to_bytes(void)
+{
+    int  result = 0;
+    etch_value_factory*     vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = (etch_value_factory*)new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+
+    do  /* short[] */
+    {   const int NUMDIMS1 = 1, ITEMCOUNT = 3;
+
+        signed char a[] =
+        { ETCH_XTRNL_TYPECODE_ARRAY, /* array type */
+          ETCH_XTRNL_TYPECODE_INT,   /* array content type */
+          NUMDIMS1,  /* dimensions count */
+          ITEMCOUNT, /* count of content items following */
+          1,   /* item[0] */
+          2,   /* item[1] */
+          3,   /* item[2] */
+          ETCH_XTRNL_TYPECODE_NONE  /* eod mark */
+        }; 
+
+        etch_arrayvalue* av = new_arrayvalue(ETCH_XTRNL_TYPECODE_INT, 
+            NULL, NUMDIMS1, ITEMCOUNT, 0, FALSE, FALSE);
+
+        arrayvalue_add(av, (etch_object*) new_int32(1));
+        arrayvalue_add(av, (etch_object*) new_int32(2));
+        arrayvalue_add(av, (etch_object*) new_int32(3));
+ 
+        result = assert_value_to_bytes((etch_object*) av, get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins() 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_long_array_value_to_bytes()
+ * test that various value objects serialized by the tdo match hard-coded expected byte arrays
+ */
+static void test_long_array_value_to_bytes(void)
+{
+    int  result = 0;
+    etch_value_factory*     vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = (etch_value_factory*)new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    do  /* short[] */
+    {   const int NUMDIMS1 = 1, ITEMCOUNT = 3;
+
+        signed char a[] =
+        { ETCH_XTRNL_TYPECODE_ARRAY, /* array type */
+          ETCH_XTRNL_TYPECODE_LONG,  /* array content type */
+          NUMDIMS1,  /* dimensions count */
+          ITEMCOUNT, /* count of content items following */
+          1,   /* item[0] */
+          2,   /* item[1] */
+          3,   /* item[2] */
+          ETCH_XTRNL_TYPECODE_NONE  /* eod mark */
+        }; 
+
+        etch_arrayvalue* av = new_arrayvalue(ETCH_XTRNL_TYPECODE_LONG, 
+            NULL, NUMDIMS1, ITEMCOUNT, 0, FALSE, FALSE);
+
+        arrayvalue_add(av, (etch_object*) new_int64(1));
+        arrayvalue_add(av, (etch_object*) new_int64(2));
+        arrayvalue_add(av, (etch_object*) new_int64(3));
+ 
+        result = assert_value_to_bytes((etch_object*) av, get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins() 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_float_array_value_to_bytes()
+ * test that various value objects serialized by the tdo match hard-coded expected byte arrays
+ */
+static void test_float_array_value_to_bytes(void)
+{
+    int  result = 0;
+    etch_value_factory*     vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = (etch_value_factory*)new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+
+    do  /* short[] */
+    {   const int NUMDIMS1 = 1, ITEMCOUNT = 3;
+
+        signed char a[] =
+        { ETCH_XTRNL_TYPECODE_ARRAY, /* array type */
+          ETCH_XTRNL_TYPECODE_FLOAT, /* array content type */
+          NUMDIMS1,  /* dimensions count */
+          ITEMCOUNT, /* count of content items following */
+          ETCH_XTRNL_TYPECODE_FLOAT, 63,-128, 0, 0,   /* item[0] */
+          ETCH_XTRNL_TYPECODE_FLOAT, 64,   0, 0, 0,   /* item[1] */
+          ETCH_XTRNL_TYPECODE_FLOAT, 64,  64, 0, 0,   /* item[2] */
+          ETCH_XTRNL_TYPECODE_NONE  /* eod mark */
+        }; 
+
+        etch_arrayvalue* av = new_arrayvalue(ETCH_XTRNL_TYPECODE_FLOAT, 
+            NULL, NUMDIMS1, ITEMCOUNT, 0, FALSE, FALSE);
+
+        arrayvalue_add(av, (etch_object*) new_float(1.0));
+        arrayvalue_add(av, (etch_object*) new_float(2.0));
+        arrayvalue_add(av, (etch_object*) new_float(3.0));
+ 
+        result = assert_value_to_bytes((etch_object*) av, get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins() 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_double_array_value_to_bytes()
+ * test that various value objects serialized by the tdo match hard-coded expected byte arrays
+ */
+static void test_double_array_value_to_bytes(void)
+{
+    int  result = 0;
+    etch_value_factory*     vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = (etch_value_factory*)new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    do  /* short[] */
+    {   const int NUMDIMS1 = 1, ITEMCOUNT = 3;
+
+        signed char a[] =
+        { ETCH_XTRNL_TYPECODE_ARRAY, /* array type */
+          ETCH_XTRNL_TYPECODE_DOUBLE, /* array content type */
+          NUMDIMS1,  /* dimensions count */
+          ITEMCOUNT, /* count of content items following */
+          ETCH_XTRNL_TYPECODE_DOUBLE, 63,-16, 0, 0,  0, 0, 0, 0,  /* item[0] */
+          ETCH_XTRNL_TYPECODE_DOUBLE, 64,  0, 0, 0,  0, 0, 0, 0,  /* item[1] */
+          ETCH_XTRNL_TYPECODE_DOUBLE, 64,  8, 0, 0,  0, 0, 0, 0,  /* item[2] */
+          ETCH_XTRNL_TYPECODE_NONE  /* eod mark */
+        }; 
+
+        etch_arrayvalue* av = new_arrayvalue(ETCH_XTRNL_TYPECODE_DOUBLE, 
+            NULL, NUMDIMS1, ITEMCOUNT, 0, FALSE, FALSE);
+
+        arrayvalue_add(av, (etch_object*) new_double(1.0));
+        arrayvalue_add(av, (etch_object*) new_double(2.0));
+        arrayvalue_add(av, (etch_object*) new_double(3.0));
+ 
+        result = assert_value_to_bytes((etch_object*)av, get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins() 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_string_values_to_bytes()
+ * test that various value objects serialized by the tdo match hard-coded expected byte arrays
+ */
+static void test_string_values_to_bytes(void)
+{
+    int  result = 0;
+    etch_value_factory*     vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = (etch_value_factory*)new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    printf("1\n");
+    
+    do
+    {   signed char a[] = { ETCH_XTRNL_TYPECODE_EMPTY_STRING }; 
+
+        result = assert_value_to_bytes((etch_object*) new_stringw(L""), 
+            get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+
+    printf("2\n");
+
+    do  /* string */
+    {   /* note here that our test object is a unicode string, while our expected byte 
+         * array encodes an array of 8-bit characters. this is because we carry all
+         * strings internally as unicode, but the tdo converts strings to the configured 
+         * wire encoding format, which is utf-8 at this writing. 
+         */ 
+        const int STRLEN = 3;
+        signed char a[] = { ETCH_XTRNL_TYPECODE_STRING, STRLEN, 97, 98, 99 }; 
+
+        result = assert_value_to_bytes((etch_object*) new_stringw(L"abc"), 
+            get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+    printf("3\n");
+
+    do  /* string[] */
+    {   const int NUMDIMS1 = 1, ITEMCOUNT = 3, STRLEN1 = 1;
+
+        signed char a[] =
+        { ETCH_XTRNL_TYPECODE_ARRAY,  /* array type */
+          ETCH_XTRNL_TYPECODE_STRING, /* array content type */
+          NUMDIMS1,  /* dimensions count */
+          ITEMCOUNT, /* count of content items following */
+          ETCH_XTRNL_TYPECODE_STRING, STRLEN1, 97,  /* item[0] */
+          ETCH_XTRNL_TYPECODE_EMPTY_STRING,         /* item[1] */
+          ETCH_XTRNL_TYPECODE_STRING, STRLEN1, 99,  /* item[2] */
+          ETCH_XTRNL_TYPECODE_NONE    /* eod mark */
+        }; 
+
+        etch_arrayvalue* av = new_arrayvalue(ETCH_XTRNL_TYPECODE_STRING, 
+            NULL, NUMDIMS1, ITEMCOUNT, 0, FALSE, FALSE);
+
+        arrayvalue_add(av, (etch_object*) new_stringw(L"a"));
+        arrayvalue_add(av, (etch_object*) new_stringw(L""));
+        arrayvalue_add(av, (etch_object*) new_stringw(L"c"));
+ 
+        result = assert_value_to_bytes((etch_object*)av, get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+    printf("4\n");
+
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins() 
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_date_values_to_bytes()
+ * test that various value objects serialized by the tdo match hard-coded expected byte arrays
+ */
+static void test_date_values_to_bytes(void)
+{
+    int  result = 0;
+    etch_value_factory*     vf              = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    vf = (etch_value_factory*)new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    do  /* date */
+    {   const int64 BOGUSDATEVAL = 1234567890;
+
+        signed char a[] = 
+        { ETCH_XTRNL_TYPECODE_CUSTOM,   /* indicates struct follows */
+          ETCH_XTRNL_TYPECODE_INT, 43, 57, 107, -52, /* _mt__etch_datetime type id */
+          1,                            /* struct member count */
+          ETCH_XTRNL_TYPECODE_INT, 102, 0,  26,  64, /* "dateTime" field id */
+          ETCH_XTRNL_TYPECODE_INT, 73, -106, 2, -46, /* serialized 1234567890 */
+          ETCH_XTRNL_TYPECODE_NONE      /* eod mark */
+        }; 
+
+        etch_date* testdate = new_date();
+        testdate->value = (time_t) BOGUSDATEVAL;
+
+        result = assert_value_to_bytes((etch_object*)testdate, get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+
+    do  /* date[] */
+    {   const int NUMDIMS1 = 1, ITEMCOUNT1 = 1; 
+        const int64 BOGUSDATEVAL1 = 1234567890LL;
+        const int64 BOGUSDATEVAL2 = 2345678901LL;
+
+        signed char a[] =
+        { ETCH_XTRNL_TYPECODE_ARRAY,  /* array type */
+          ETCH_XTRNL_TYPECODE_CUSTOM, /* array content type */
+          ETCH_XTRNL_TYPECODE_INT, 43, 57, 107, -52, /* "custom struct type" _mt__etch_datetime */
+          NUMDIMS1,   /* array dimensions */
+          ITEMCOUNT2, /* count of array content items following */  
+
+          ETCH_XTRNL_TYPECODE_CUSTOM, /* start array member[0] */
+          ETCH_XTRNL_TYPECODE_INT, 43, 57, 107, -52, /* struct type _mt__etch_datetime */
+          ITEMCOUNT1,                 /* struct item count */
+          ETCH_XTRNL_TYPECODE_INT, 102, 0,  26,  64, /* "dateTime" field id */
+          ETCH_XTRNL_TYPECODE_INT, 73, -106, 2, -46, /* serialized 1234567890 */     
+          ETCH_XTRNL_TYPECODE_NONE,   /* eod mark for struct - end of array member[0] */
+
+          ETCH_XTRNL_TYPECODE_CUSTOM, /* start array member[1] */
+          ETCH_XTRNL_TYPECODE_INT, 43, 57, 107, -52, /* struct type _mt__etch_datetime */
+          ITEMCOUNT1,                 /* struct item count */
+          ETCH_XTRNL_TYPECODE_INT, 102, 0,  26,  64, /* "dateTime" field id */
+          ETCH_XTRNL_TYPECODE_LONG,  0, 0, 0, 0,  -117, -48, 56, 53, /* serialized 2345678901 */     
+          ETCH_XTRNL_TYPECODE_NONE,   /* eod mark for struct - end of array member[1] */
+
+          ETCH_XTRNL_TYPECODE_NONE,   /* eod mark for array */
+        }; 
+
+        etch_arrayvalue* av = NULL;
+        etch_type* my_custom_struct_type = builtins._mt__etch_datetime;
+
+        etch_date* date1 = new_date();
+        etch_date* date2 = new_date();
+        date1->value = BOGUSDATEVAL1;
+        date2->value = BOGUSDATEVAL2;
+
+        av = new_arrayvalue(ETCH_XTRNL_TYPECODE_CUSTOM, 
+             my_custom_struct_type, NUMDIMS1, ITEMCOUNT2, 0, FALSE, FALSE);
+
+        arrayvalue_add(av, (etch_object*) date1);
+        arrayvalue_add(av, (etch_object*) date2);
+ 
+        result = assert_value_to_bytes((etch_object*) av, get_bytearray((byte*)a, sizeof(a)), vf);
+        CU_ASSERT_EQUAL(result,0);
+
+    } while(0);
+
+    // destroy vf
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_binarytdit_suite()
+{
+    CU_pSuite ps = CU_add_suite("bintditdo test suite", init_suite, clean_suite);
+
+    CU_add_test(ps, "test constructor 0", test_constructor_0);
+    CU_add_test(ps, "test constructor 1", test_constructor_1);
+    CU_add_test(ps, "test constructor 2", test_constructor_2);
+    CU_add_test(ps, "test check value",   test_check_value);
+     
+	//TODO implement this test's functionality again!!!
+    //CU_add_test(ps, "test byte[][] out and back in",   test_byte_array_out_in);
+    CU_add_test(ps, "test bool[][] out and back in",   test_bool_array_out_in);
+    CU_add_test(ps, "test short[][] out and back in",  test_short_array_out_in);
+
+    CU_add_test(ps, "test int[][] out and back in",    test_int_array_out_in);
+    CU_add_test(ps, "test long[][] out and back in",   test_long_array_out_in);
+    CU_add_test(ps, "test float[][] out and back in",  test_float_array_out_in);
+    CU_add_test(ps, "test double[][] out and back in", test_double_array_out_in);
+    CU_add_test(ps, "test string[][] out and back in", test_string_array_out_in);
+//    CU_add_test(ps, "test add perf", test_add_perf);
+
+    CU_add_test(ps, "test single values to bytes", test_single_value_to_bytes);
+    CU_add_test(ps, "test bool array to bytes",    test_boolean_array_value_to_bytes);
+    CU_add_test(ps, "test byte arrays to bytes",   test_byte_array_value_to_bytes);
+    CU_add_test(ps, "test short array to bytes",   test_short_array_value_to_bytes);
+    CU_add_test(ps, "test int array to bytes",     test_int_array_value_to_bytes);
+    CU_add_test(ps, "test long array to bytes",    test_long_array_value_to_bytes);
+    CU_add_test(ps, "test float array to bytes",   test_float_array_value_to_bytes);
+    CU_add_test(ps, "test double array to bytes",  test_double_array_value_to_bytes);
+    CU_add_test(ps, "test string values to bytes", test_string_values_to_bytes);
+    CU_add_test(ps, "test date values to bytes",   test_date_values_to_bytes);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/message/test_defvalufact.c b/binding-c/runtime/c/src/test/message/test_defvalufact.c
new file mode 100644
index 0000000..f5ea464
--- /dev/null
+++ b/binding-c/runtime/c/src/test/message/test_defvalufact.c
@@ -0,0 +1,2041 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_defvalufact.c 
+ * test default impl of value factory
+ */
+#include "etch_runtime.h"
+#include "etch_validator.h"  /* must be included second */
+#include "etch_tagged_data.h"
+#include "etch_map.h"
+#include "etch_log.h"
+#include "etch_id_name.h"
+#include "etch_default_value_factory.h"
+#include "etch_arrayval.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+#include "etch_nativearray.h"
+#include "etch_serializer.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+#include <wchar.h>
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - 
+ * unit test support
+ * - - - - - - - - - - - - - -
+ */
+
+/**
+ * do_test_type_field
+ */
+static int do_test_type_field(default_value_factory* vf, etch_type* type, etch_field* key, etch_object* value)
+{
+    etch_message* msg = new_message(type, 1, (etch_value_factory*)vf);
+
+    const int result = message_put(msg, key, value);
+
+    etch_object_destroy(msg);
+
+    return result; 
+}
+
+
+/* - - - - - - - - - - - - - - 
+ * unit tests
+ * - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_constructor
+ * tests that all objects instatiated with a value factory such as builtin types 
+ * and associated validators, are freed as expected. 
+ */
+static void test_constructor(void)
+{
+    vf_idname_map*          typemap = NULL;
+    class_to_type_map*      c2tmap  = NULL;
+    default_value_factory*  vf      = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(vf);
+
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_builtin_types()
+ * test that the vf contains all expected default types
+ */
+static void test_builtin_types(void)
+{
+    int errs = 0;
+    vf_idname_map*          typemap = NULL;
+    class_to_type_map*      c2tmap  = NULL;
+    default_value_factory*  vf      = NULL;
+    struct i_value_factory* vtab    = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+    vtab = (struct i_value_factory*)((etch_object*)vf)->vtab;
+    if (NULL == vtab->get_type_by_name(vf, builtins._mt__etch_auth_exception->name))
+        errs++; 
+    if (NULL == vtab->get_type_by_name(vf, builtins._mt__etch_datetime->name))
+        errs++; 
+    if (NULL == vtab->get_type_by_name(vf, builtins._mt__etch_list->name))
+        errs++; 
+    if (NULL == vtab->get_type_by_name(vf, builtins._mt__etch_map->name))
+        errs++; 
+    if (NULL == vtab->get_type_by_name(vf, builtins._mt__etch_runtime_exception->name))
+        errs++; 
+    if (NULL == vtab->get_type_by_name(vf, builtins._mt__etch_set->name))
+        errs++; 
+    if (NULL == vtab->get_type_by_name(vf, builtins._mt__exception->name))
+        errs++; 
+
+    CU_ASSERT_EQUAL(errs, 0);  
+
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_add_type_a()
+ * test that a type can be added and its memory automatically freed.
+ */
+static void test_add_type_a(void)
+{
+    vf_idname_map*          typemap  = NULL;
+    class_to_type_map*      c2tmap   = NULL;
+    default_value_factory*  dvf      = NULL;
+    etch_type*              newtype  = NULL;
+    etch_type*              efftype  = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    newtype = new_static_type(L"testtype");
+    efftype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->add_type(dvf, newtype);  /* not owned by vf */
+    CU_ASSERT_PTR_EQUAL(newtype, efftype);
+
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    destroy_static_type(efftype); /* since not owned by vf */
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_add_type_b()
+ * test that a duplicate type is rejected as expected.
+ */
+static void test_add_type_b(void)
+{
+    vf_idname_map*          typemap  = NULL;
+    class_to_type_map*      c2tmap   = NULL;
+    default_value_factory*  dvf      = NULL;
+    wchar_t* samestring              = L"sametype";
+    etch_type*              newtype1 = NULL;
+    etch_type*              newtype2 = NULL;
+    etch_type*              efftype  = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    newtype1 = new_static_type(samestring);
+    newtype2 = new_static_type(samestring);
+
+    efftype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->add_type(dvf, newtype1);  /* not owned by vf */
+    CU_ASSERT_PTR_EQUAL(efftype, newtype1);
+
+    /* when try to add a duplicate, vf returns original and destroys duplicate */
+    efftype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->add_type(dvf, newtype2);  
+    CU_ASSERT_PTR_EQUAL(efftype, newtype1);
+
+
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    /* detroy newtype1 since not owned by vf */
+    destroy_static_type(newtype1);
+    /* don't destroy newtype2 since vf destroyed it */
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_add_type_c()
+ * test that a duplicate of a builtin type is handled as expected.
+ */
+static void test_add_type_c(void)
+{
+    vf_idname_map*          typemap  = NULL;
+    class_to_type_map*      c2tmap   = NULL;
+    default_value_factory*  dvf      = NULL;
+    etch_type*              duptype  = NULL;
+    etch_type*              efftype  = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+    
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    duptype = new_type(str_etch_runtime_exception);
+
+    /* when try to add a duplicate, vf returns original and destroys duplicate */
+    efftype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->add_type(dvf, duptype);
+    CU_ASSERT_PTR_EQUAL(efftype, builtins._mt__etch_runtime_exception);
+
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_get_type_by_id()
+ * test that a type can be retrived by its id, and memory accounted for.
+ */
+static void test_get_type_by_id(void)
+{
+    vf_idname_map*          typemap  = NULL;
+    class_to_type_map*      c2tmap   = NULL;
+    default_value_factory*  dvf      = NULL;
+   /* note that a *reference* is returned (not disposable), not a copy. */
+    unsigned saved_id = 0;
+    etch_type*              newtype   = NULL;
+    etch_type*              foundtype = NULL;
+    
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    newtype  = new_type(L"testtype");
+    saved_id = newtype->id;
+    ((struct i_value_factory*)((etch_object*)dvf)->vtab)->add_type(dvf, newtype);
+
+    foundtype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_id(dvf, saved_id);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(foundtype);
+    CU_ASSERT_EQUAL(saved_id, foundtype->id);
+
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    etch_object_destroy(newtype);   /* vf now owns its nonstatic user types */
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_get_type_by_name()
+ * test that a type can be retrived by its name, and memory accounted for.
+ */
+static void test_get_type_by_name(void)
+{
+    vf_idname_map*          typemap  = NULL;
+    class_to_type_map*      c2tmap   = NULL;
+    default_value_factory*  dvf      = NULL;
+    /* note that a *reference* is returned (not disposable), not a copy. */
+    etch_type*              newtype   = NULL;
+    etch_type*              foundtype = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    newtype = new_type(L"testtype");
+    ((struct i_value_factory*)((etch_object*)dvf)->vtab)->add_type(dvf, newtype);
+
+    foundtype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_name(dvf, L"testtype");
+    CU_ASSERT_PTR_NOT_NULL_FATAL(foundtype);
+
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    etch_object_destroy(newtype);   /* vf now owns its nonstatic user types */
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_get_types()
+ * test that all types can be retrived as a list, and memory accounted for.
+ */
+static void test_get_types(void)
+{
+    int  result;
+    vf_idname_map*      typemap    = NULL;
+    class_to_type_map*  c2tmap     = NULL;
+    default_value_factory*  dvf    = NULL;
+    etch_hashtable*     map        = NULL;
+    etch_iterator       iterator;
+    etch_arraylist*     typeslist  = NULL;
+    etch_hashitem       hashbucket;
+    etch_hashitem*      thisitem   =  &hashbucket;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    // get type map
+    map = dvf->types;
+    // get type list
+    typeslist = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_types(dvf);
+
+    set_iterator(&iterator, typeslist, &typeslist->iterable);
+
+    while(iterator.has_next(&iterator))
+    {
+        /* we're iterating the arraylist, so we're looking at the value,
+         * which of course was the hashtable key */
+        etch_type* thistype = (etch_type*) iterator.current_value;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(thistype); 
+
+        /* map.remove() sends us back the key and value if we ask for it. so we 
+         * are using remove both to look up the type, and to remove it so we can
+         * verify that the list content is one to one with the types map */
+        result = ((struct i_hashtable*)((etch_object*)map)->vtab)->removeh
+	  (map->realtable, ((etch_object*)thistype)->get_hashkey(thistype), map, (void**)&thisitem);
+        CU_ASSERT_EQUAL(result, 0); 
+
+        result = etchmap_count(map);
+        iterator.next(&iterator);
+    }
+
+    /* assert that list contnent and map content were the same */
+    result = etchmap_count(map);
+    CU_ASSERT_EQUAL(result, 0);
+
+    /* the list is marked to not free content, which is what we want, however
+     * if would not make a difference if it were not, since the types are refs
+     * to the builtin types, thus marked static, and so were the list to invoke
+     * destructors on its content, the destructor would take no action.
+     */
+    etch_object_destroy(typeslist);
+
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_authxcp_fields()
+ * test that auth exception type is configured as expected
+ */
+static void test_authxcp_fields(void)
+{
+    int result = 0;
+    vf_idname_map*      typemap    = NULL;
+    class_to_type_map*  c2tmap     = NULL;
+    default_value_factory*  dvf     = NULL;
+    etch_type*              msgtype = NULL;
+    etch_field*             msgkey1 = NULL;
+    etch_field*             msgkey2 = NULL;
+    etch_object*                val_good = NULL;
+    etch_object*                val_unxp = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    /* apparently the purpose of this test, ported from java test, is to test that
+     * the authxcp type has a _mf_msg field, and that if we then make a message
+     * of type authxcp and put to it a string value keyed by _mf_msg, that it
+     * validates OK. i.e., the _mf_msg field of a authxcp should be a string.
+     */
+    msgtype  = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_name(dvf, str_etch_auth_exception); 
+    msgkey1  = clone_field(builtins._mf_msg); 
+    msgkey2  = clone_field(builtins._mf_msg); 
+    val_good = (etch_object*) new_stringw(L"dlrow olleh");
+    val_unxp = (etch_object*) new_int32(0);
+
+    result = do_test_type_field(dvf, msgtype, msgkey1, val_good);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    result = do_test_type_field(dvf, msgtype, msgkey2, val_unxp);
+    CU_ASSERT_EQUAL(result, -1); /* type validation should fail */  
+
+
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+} 
+
+
+/**
+ * test_rtxcp_fields()
+ * test that runtime exception type is configured as expected
+ */
+static void test_rtxcp_fields(void)
+{
+    int result = 0;
+    vf_idname_map*      typemap    = NULL;
+    class_to_type_map*  c2tmap     = NULL;
+    default_value_factory*  dvf     = NULL;
+    etch_type*              msgtype = NULL;
+    etch_field*             msgkey1 = NULL;
+    etch_field*             msgkey2 = NULL;
+    etch_object*                val_good = NULL;
+    etch_object*                val_unxp = NULL;
+    
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    msgtype  = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_name(dvf, str_etch_runtime_exception); 
+    msgkey1  = clone_field(builtins._mf_msg); 
+    msgkey2  = clone_field(builtins._mf_msg); 
+    val_good = (etch_object*) new_stringw(L"dlrow olleh");
+    val_unxp = (etch_object*) new_int32(0);
+
+    result = do_test_type_field(dvf, msgtype, msgkey1, val_good);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    result = do_test_type_field(dvf, msgtype, msgkey2, val_unxp);
+    CU_ASSERT_EQUAL(result, -1); /* type validation should fail */  
+
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+} 
+
+
+/**
+ * test_exception_fields()
+ * test that exception type is configured as expected
+ */
+static void test_exception_fields(void)
+{
+    int result = 0;
+    vf_idname_map*      typemap        = NULL;
+    class_to_type_map*  c2tmap         = NULL;
+    default_value_factory*  dvf        = NULL;
+    etch_type*              msgtype    = NULL;
+    etch_field*             key_result = NULL;
+    etch_field*             key_msg_id = NULL;
+    etch_field*             key_inrepto = NULL;
+    etch_object*                val_rtexp   = NULL;
+    etch_object*                val_long1   = NULL;
+    etch_object*                val_long2   = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    msgtype     = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_name(dvf, str_exception); 
+    key_result  = clone_field(builtins._mf_result); 
+    key_msg_id  = clone_field(builtins._mf__message_id); 
+    key_inrepto = clone_field(builtins._mf__in_reply_to); 
+    val_rtexp   = (etch_object*) new_etch_exception_from_errorcode(ETCH_ERROR);
+    val_long1   = (etch_object*) new_int64(123);
+    val_long2   = (etch_object*) new_int64(456);
+
+    result = do_test_type_field(dvf, msgtype, key_result, val_rtexp);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    result = do_test_type_field(dvf, msgtype, key_msg_id, val_long1);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    result = do_test_type_field(dvf, msgtype, key_inrepto, val_long2);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+} 
+
+
+/**
+ * test_get_string_encoding()
+ */
+static void test_get_string_encoding(void)
+{
+    vf_idname_map*          typemap    = NULL;
+    class_to_type_map*      c2tmap     = NULL;
+    default_value_factory*  dvf        = NULL;
+    wchar_t*                encoding   = NULL; 
+    etch_string*            newstring  = NULL;
+    int  result;
+    int etch_encoding;
+    char* teststring                   = "8 bit characters";
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    /* note that a reference to a raw string is returned */
+    encoding = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_string_encoding(dvf);
+
+    result = wcscmp(encoding, L"utf-8");
+    CU_ASSERT_EQUAL(result, 0);
+
+    etch_encoding = get_etch_string_encoding((etch_value_factory*)dvf);
+
+    newstring = new_string("8 bit characters", etch_encoding);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newstring);
+    result = strcmp(newstring->v.valc, teststring);
+    CU_ASSERT_EQUAL(result, 0);  
+    
+    etch_object_destroy(newstring);
+
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+} 
+
+
+/**
+ * test_add_mixin()
+ */
+static void test_add_mixin(void)
+{
+    int result = 0;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    
+    default_value_factory*  mixvf1_vf       = NULL;
+    vf_idname_map*          mixvf1_typemap  = NULL;
+    class_to_type_map*      mixvf1_c2tmap   = NULL;
+    
+    default_value_factory*  mixvf2_vf      = NULL;
+    vf_idname_map*          mixvf2_typemap  = NULL;
+    class_to_type_map*      mixvf2_c2tmap   = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    // init statics
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    mixvf1_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(mixvf1_typemap);
+    mixvf1_c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(mixvf1_c2tmap);
+    // init statics
+    defvf_initialize_static(mixvf1_typemap, mixvf1_c2tmap);
+    mixvf1_vf = new_default_value_factory(mixvf1_typemap, mixvf1_c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(mixvf1_vf);
+
+    mixvf2_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(mixvf2_typemap);
+    mixvf2_c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(mixvf2_c2tmap);
+    // init statics
+    defvf_initialize_static(mixvf2_typemap, mixvf2_c2tmap);
+    mixvf2_vf = new_default_value_factory(mixvf2_typemap, mixvf2_c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(mixvf2_vf);
+
+    result = defvf_add_mixin(dvf, (etch_value_factory*) mixvf1_vf);
+    CU_ASSERT_EQUAL(result, 0);  
+    result = defvf_add_mixin(dvf, (etch_value_factory*) mixvf2_vf);
+    CU_ASSERT_EQUAL(result, 0);  
+ 
+    result = dvf->mixins->count;
+    CU_ASSERT_EQUAL(result, 2);  
+
+    // destroy dvf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    // destroy mixvf1_vf
+    etch_object_destroy(mixvf1_vf);
+    etch_object_destroy(mixvf1_c2tmap);
+    etch_object_destroy(mixvf1_typemap);
+
+    // destroy mixvf2_vf
+    etch_object_destroy(mixvf2_vf);
+    etch_object_destroy(mixvf2_c2tmap);
+    etch_object_destroy(mixvf2_typemap);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_mixin_recursion
+ * exercise the various vf apis which are mixin-recursive
+ */
+static void test_mixin_recursion(void)
+{
+    int result = 0;
+    etch_type* rettype = NULL;
+    wchar_t* str_foo = L"foo", *str_bar = L"bar", *str_bogus = L"wtf";
+    etch_type* newtype1 = NULL;
+    etch_type* newtype2 = NULL;
+
+
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    default_value_factory*  mixin1_dvf      = NULL;
+    vf_idname_map*          mixin1_typemap  = NULL;
+    class_to_type_map*      mixin1_c2tmap   = NULL;
+
+    default_value_factory*  mixin2_dvf      = NULL;
+    vf_idname_map*          mixin2_typemap  = NULL;
+    class_to_type_map*      mixin2_c2tmap   = NULL;
+
+    // main vf
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    // mixin1 vf
+    mixin1_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(mixin1_typemap);
+    mixin1_c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(mixin1_c2tmap);
+    defvf_initialize_static(mixin1_typemap, mixin1_c2tmap);
+    mixin1_dvf = new_default_value_factory(mixin1_typemap, mixin1_c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(mixin1_dvf);
+
+    // mixin2 vf
+    mixin2_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(mixin2_typemap);
+    mixin2_c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(mixin2_c2tmap);
+    defvf_initialize_static(mixin2_typemap, mixin2_c2tmap);
+    mixin2_dvf = new_default_value_factory(mixin2_typemap, mixin2_c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(mixin2_dvf);
+
+    newtype1 = new_static_type(str_foo);
+    newtype2 = new_static_type(str_bar);
+    
+    rettype =  ((struct i_value_factory*)((etch_object*)mixin1_dvf)->vtab)->add_type(mixin1_dvf, newtype1);
+    CU_ASSERT_PTR_EQUAL_FATAL(rettype, newtype1);
+
+    rettype = ((struct i_value_factory*)((etch_object*)mixin2_dvf)->vtab)->add_type(mixin2_dvf, newtype2);
+    CU_ASSERT_PTR_EQUAL_FATAL(rettype, newtype2);
+
+    result = defvf_add_mixin(dvf, (etch_value_factory*) mixin1_dvf);
+    CU_ASSERT_EQUAL(result, 0);  
+    result = defvf_add_mixin(dvf, (etch_value_factory*) mixin2_dvf);
+    CU_ASSERT_EQUAL(result, 0);  
+
+    result = defvf_add_mixin(mixin1_dvf, (etch_value_factory*) mixin2_dvf);
+    CU_ASSERT_EQUAL(result, 0);
+
+    rettype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_name(dvf, str_exception);
+    CU_ASSERT_PTR_NOT_NULL(rettype);  /* builtin type */
+
+    rettype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_name(mixin1_dvf, str_exception);
+    CU_ASSERT_PTR_NOT_NULL(rettype);  /* builtin type */
+
+    rettype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_name(mixin2_dvf, str_exception);
+    CU_ASSERT_PTR_NOT_NULL(rettype);  /* builtin type */
+
+    /* mixin recursive by-name lookup */
+    rettype = ((struct i_value_factory*)((etch_object*)mixin1_dvf)->vtab)->get_type_by_name(mixin1_dvf, str_bar);
+    CU_ASSERT_PTR_NOT_NULL(rettype);  /* via mixvf1 mixin 1 */
+
+    rettype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_name(dvf, str_foo);
+    CU_ASSERT_PTR_NOT_NULL(rettype);  /* via vf mixin 1 */ 
+
+    rettype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_name(dvf, str_bar);
+    CU_ASSERT_PTR_NOT_NULL(rettype);  /* via vf mixin 2 */ 
+
+    /* mixin recursive by-id lookup */
+    rettype = ((struct i_value_factory*)((etch_object*)mixin1_dvf)->vtab)->get_type_by_id(mixin1_dvf, newtype2->id);
+    CU_ASSERT_PTR_NOT_NULL(rettype);  /* via mixvf1 mixin 1 */
+
+    rettype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_id(dvf, newtype1->id);
+    CU_ASSERT_PTR_NOT_NULL(rettype);  /* via vf mixin 1 */ 
+
+    rettype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_id(dvf, newtype2->id);
+    CU_ASSERT_PTR_NOT_NULL(rettype);  /* via vf mixin 2 */ 
+
+    /* negative tests will recurse all mixins */
+    rettype =  ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_name(mixin1_dvf, str_bogus);
+    CU_ASSERT_PTR_NULL(rettype);
+
+    rettype = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_type_by_id(dvf, compute_id_name_id_from_widename(str_bogus));
+    CU_ASSERT_PTR_NULL(rettype);  /* via vf mixin 1 */  
+
+    // destroy mixvf2_vf
+    etch_object_destroy(mixin2_dvf);
+    etch_object_destroy(mixin2_c2tmap);
+    etch_object_destroy(mixin2_typemap);
+
+    // destroy mixvf1_vf
+    etch_object_destroy(mixin1_dvf);
+    etch_object_destroy(mixin1_c2tmap);
+    etch_object_destroy(mixin1_typemap);
+
+    // destroy mixvf2_vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    destroy_static_type(newtype1);
+    destroy_static_type(newtype2);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_custom_struct_type
+ *  
+ */
+static void test_custom_struct_type(void)
+{
+    int result = 0;
+    etch_type* rettype = NULL;
+    wchar_t *str_vf0 = L"vf0", *str_vf1 = L"vf1", *str_vf2 = L"vf2";
+    
+    default_value_factory*  vf0             = NULL;
+    vf_idname_map*          vf0_typemap     = NULL;
+    class_to_type_map*      vf0_c2tmap      = NULL;
+
+    default_value_factory*  vf1             = NULL;
+    vf_idname_map*          vf1_typemap     = NULL;
+    class_to_type_map*      vf1_c2tmap      = NULL;
+
+    default_value_factory*  vf2             = NULL;
+    vf_idname_map*          vf2_typemap     = NULL;
+    class_to_type_map*      vf2_c2tmap      = NULL;
+
+    etch_type* cstype0 = new_static_type(str_vf0);
+    etch_type* cstype1 = new_static_type(str_vf1);
+    etch_type* cstype2 = new_static_type(str_vf2);
+
+    const unsigned short ETCHTYPE_CSCLASS0 = 0xe0, CLASSID_CSCLASS0 = 0xf0;
+    const unsigned short ETCHTYPE_CSCLASS1 = 0xe1, CLASSID_CSCLASS1 = 0xf1;
+    const unsigned short ETCHTYPE_CSCLASS2 = 0xe2, CLASSID_CSCLASS2 = 0xf2;
+    const unsigned short ETCHTYPE_CSBOGUS  = 0xe3, CLASSID_BOGUS    = 0xf3;
+
+    const unsigned csclass0 = ETCHMAKECLASS(ETCHTYPE_CSCLASS0, CLASSID_CSCLASS0);
+    const unsigned csclass1 = ETCHMAKECLASS(ETCHTYPE_CSCLASS1, CLASSID_CSCLASS1);
+    const unsigned csclass2 = ETCHMAKECLASS(ETCHTYPE_CSCLASS2, CLASSID_CSCLASS2);
+    const unsigned csbogus  = ETCHMAKECLASS(ETCHTYPE_CSBOGUS,  CLASSID_BOGUS);
+
+    vf0_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(vf0_typemap);
+    vf0_c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(vf0_c2tmap);
+    defvf_initialize_static(vf0_typemap, vf0_c2tmap);
+    vf0 = new_default_value_factory(vf0_typemap, vf0_c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf0);
+    result = class_to_type_map_put(vf0->class_to_type, csclass0, cstype0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    vf1_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(vf1_typemap);
+    vf1_c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(vf1_c2tmap);
+    defvf_initialize_static(vf1_typemap, vf1_c2tmap);
+    vf1 = new_default_value_factory(vf1_typemap, vf1_c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf1);
+    result = class_to_type_map_put(vf1->class_to_type, csclass1, cstype1);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    vf2_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(vf2_typemap);
+    vf2_c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(vf2_c2tmap);
+    defvf_initialize_static(vf2_typemap, vf2_c2tmap);
+    vf2 = new_default_value_factory(vf2_typemap, vf2_c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf2);
+    result = class_to_type_map_put(vf2->class_to_type, csclass2, cstype2);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = defvf_add_mixin(vf0, (etch_value_factory*) vf1);
+    CU_ASSERT_EQUAL(result, 0);
+    result = defvf_add_mixin(vf0, (etch_value_factory*) vf2);
+    CU_ASSERT_EQUAL(result, 0);
+
+    result = defvf_add_mixin(vf1, (etch_value_factory*) vf2);
+    CU_ASSERT_EQUAL(result, 0);  
+
+    rettype = ((struct i_value_factory*)((etch_object*)vf0)->vtab)->get_custom_struct_type(vf0, csclass0);
+    CU_ASSERT_PTR_EQUAL(rettype, cstype0);  
+
+    /* recurse mixed-in vfs for custom types */
+    rettype = ((struct i_value_factory*)((etch_object*)vf0)->vtab)->get_custom_struct_type(vf0, csclass1);
+    CU_ASSERT_PTR_EQUAL(rettype, cstype1); 
+  
+    rettype = ((struct i_value_factory*)((etch_object*)vf0)->vtab)->get_custom_struct_type(vf0, csclass2);
+     CU_ASSERT_PTR_EQUAL(rettype, cstype2); 
+
+    /* negative test will recurse all mixins */
+    rettype = ((struct i_value_factory*)((etch_object*)vf0)->vtab)->get_custom_struct_type(vf0, csbogus);
+    CU_ASSERT_PTR_NULL(rettype);   
+
+    // destroy vf2
+    etch_object_destroy(vf2);
+    etch_object_destroy(vf2_c2tmap);
+    etch_object_destroy(vf2_typemap);
+
+    // destroy vf1
+    etch_object_destroy(vf1);
+    etch_object_destroy(vf1_c2tmap);
+    etch_object_destroy(vf1_typemap);
+
+    // destroy vf0
+    etch_object_destroy(vf0);
+    etch_object_destroy(vf0_c2tmap);
+    etch_object_destroy(vf0_typemap);
+
+    destroy_static_type(cstype0);
+    destroy_static_type(cstype1);
+    destroy_static_type(cstype2);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_get_set_message_id()
+ */
+static void test_get_set_message_id(void)
+{
+    int result = 0;
+    int64 idvalue = 12345;
+    etch_type* newtype = new_static_type(L"testtype");
+    etch_int64* idobj  = new_int64(idvalue), *retobj = NULL;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+     etch_message*          msg             = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    msg = new_message(newtype, ETCH_DEFSIZE, (etch_value_factory*) dvf);
+
+    etchtype_put_validator(newtype, builtins._mf__message_id, (etch_object*) etchvtor_int64_get(0));
+    
+    result = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->set_message_id(dvf, msg, idobj);  /* we no longer own idobj */
+    CU_ASSERT_EQUAL_FATAL(result,0);  /* ensure idobj validates ok */
+
+    /* we get back a reference to the ID object, not a copy */
+    retobj = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_message_id(dvf, msg); 
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(retobj); 
+    CU_ASSERT_EQUAL(retobj->value, idvalue); 
+
+    etch_object_destroy(msg);
+    
+    // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    destroy_static_type(newtype);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_get_set_in_reply_to()
+ */
+static void test_get_set_in_reply_to(void)
+{
+    int result = 0;
+    int64 idvalue = 12345;
+    etch_type* newtype = new_static_type(L"testtype");
+    etch_int64* idobj  = new_int64(idvalue), *retobj = NULL;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    etch_message*           msg             = NULL;
+    
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    msg = new_message(newtype, ETCH_DEFSIZE, (etch_value_factory*) dvf);
+
+    etchtype_put_validator(newtype, builtins._mf__in_reply_to, (etch_object*) etchvtor_int64_get(0));
+    
+    result = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->set_in_reply_to(dvf, msg, idobj);
+    CU_ASSERT_EQUAL_FATAL(result,0);  /* ensure idobj validates ok */
+
+    /* we get back a reference to the ID, not a copy */
+    retobj = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->get_in_reply_to(dvf, msg); 
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(retobj); 
+    CU_ASSERT_EQUAL(retobj->value, idvalue); 
+
+    etch_object_destroy(msg);
+    
+    // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    destroy_static_type(newtype);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_export_custom_value_exception()
+ * export an etch_exception
+ */
+static void test_export_custom_value_exception(void)
+{
+    int result = 0;
+    etch_structvalue* sv = NULL;
+    etch_serializer* impexhelper = NULL;
+    etch_string* exported_stringobj = NULL;
+    etch_exception* nullptr_exception = NULL;
+    wchar_t* exception_string_out = NULL;
+
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    nullptr_exception = new_etch_exception_from_errorcode(ETCH_EINVAL); 
+
+    /* retain ownership of nullptr_exception, assume ownership of returned struct */
+    sv = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->export_custom_value(dvf, (etch_object*) nullptr_exception);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+    /* we could hard code the struct key for the test, but to be thorough
+     * let's get it programmatically. we get the import-export helper for 
+     * the type of object we are exporting (exception). from the helper
+     * will get the key for the expected string export value, which should
+     * be an etch_field of name "msg" */
+    impexhelper = etchtype_get_impexphelper(builtins._mt__exception);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+    /* get reference to exported object from struct, expected to be an 
+     * etch_string wrapping an ascii string which is the exception text.
+     * the exception text will contain the instance text specified above,
+     * specifically it should be "null pointer exception dlr0w 0ll3h" */
+    exported_stringobj = (etch_string*) structvalue_get(sv, impexhelper->field); 
+    result = is_etch_string(exported_stringobj);
+    CU_ASSERT_EQUAL_FATAL(result,TRUE); 
+
+    exception_string_out = exported_stringobj->v.valw;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(exception_string_out);
+
+    etch_object_destroy(sv);
+
+    // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_import_custom_value_exception()
+ * import an etch exception type
+ */
+static void test_import_custom_value_exception(void)
+{
+    etch_structvalue* sv = NULL;
+    etch_exception* inexcp = NULL;
+    etch_serializer* impexhelper = NULL;
+    char *outtext     =  "null pointer exception fubar";
+    wchar_t *expected = L"null pointer exception fubar", *intext = NULL;
+    int result = 0;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+    
+    impexhelper = etchtype_get_impexphelper(builtins._mt__exception);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+    sv = new_structvalue(builtins._mt__exception, 1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+    result = structvalue_put(sv, clone_field(impexhelper->field), 
+        (etch_object*) new_string(outtext, ETCH_ENCODING_UTF8));
+    CU_ASSERT_EQUAL_FATAL(result,0); 
+
+    /* relinquish ownership of struct, assume ownership of inexcp */
+    /* todo need to serialize exception type perhaps, in order to be able to
+     * re-instantiate an exception as a null pointer exception for example */
+    inexcp = (etch_exception*) ((struct i_value_factory*)((etch_object*)dvf)->vtab)->import_custom_value(dvf, sv);
+    CU_ASSERT_EQUAL_FATAL(is_etch_exception(inexcp), TRUE); 
+
+    intext = etch_exception_get_message(inexcp)->v.valw;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(intext); 
+    result = wcscmp(intext, expected);
+    CU_ASSERT_EQUAL(result,0);  
+
+    etch_object_destroy(inexcp);
+    
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_export_custom_value_runtime_exception()
+ * export an etch_runtime_exception
+ */
+static void test_export_custom_value_runtime_exception(void)
+{
+    int result = 0;
+    etch_structvalue* sv = NULL;
+    etch_serializer* impexhelper = NULL;
+    etch_string* exported_stringobj = NULL;
+    etch_exception* runtime_exception = NULL;
+    wchar_t* exception_string_out = NULL;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    runtime_exception = new_etch_exception_from_errorcode(ETCH_ERROR); 
+
+    /* retain ownership of runtime_exception, assume ownership of returned struct */
+    sv = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->export_custom_value(dvf, (etch_object*) runtime_exception);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+    /* see comments at this spot in test_export_custom_value_exception */
+    impexhelper = etchtype_get_impexphelper(builtins._mt__etch_runtime_exception);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+    /* get reference to exported object from struct, expected to be an 
+     * etch_string wrapping an ascii string which is the exception text.
+     * the exception text will contain the instance text specified above,
+     * specifically it should be "etch runtime exception tey rabuf ew era" */
+    exported_stringobj = (etch_string*) structvalue_get(sv, impexhelper->field); 
+    result = is_etch_string(exported_stringobj);
+    CU_ASSERT_EQUAL_FATAL(result,TRUE); 
+
+    exception_string_out = exported_stringobj->v.valw;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(exception_string_out);
+
+    
+    etch_object_destroy(sv);
+    
+    // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_import_custom_value_runtime_exception()
+ * import an etch rutime exception type
+ */
+static void test_import_custom_value_runtime_exception(void)
+{
+    etch_structvalue* sv = NULL;
+    etch_exception* inexcp = NULL;
+    etch_serializer* impexhelper = NULL;
+    char *outtext     =  "etch runtime exception fubar";
+    wchar_t *expected = L"etch runtime exception fubar", *intext = NULL;
+    int result = 0;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    
+        typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    impexhelper = etchtype_get_impexphelper(builtins._mt__etch_runtime_exception);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+    sv = new_structvalue(builtins._mt__etch_runtime_exception, 1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+    result = structvalue_put(sv, clone_field(impexhelper->field), 
+        (etch_object*) new_string(outtext, ETCH_ENCODING_UTF8));
+    CU_ASSERT_EQUAL_FATAL(result,0); 
+
+    /* relinquish ownership of struct, assume ownership of inexcp */
+    inexcp = (etch_exception*) ((struct i_value_factory*)((etch_object*)dvf)->vtab)->import_custom_value(dvf, sv);
+    CU_ASSERT_EQUAL_FATAL(is_etch_exception(inexcp), TRUE); 
+
+    intext = etch_exception_get_message(inexcp)->v.valw;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(intext); 
+    result = wcscmp(intext, expected);
+    CU_ASSERT_EQUAL(result,0);  
+
+    etch_object_destroy(inexcp);
+    // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_export_custom_value_list()
+ * export an etch list type
+ */
+static void test_export_custom_value_list(void)
+{
+    int result = 0;
+    etch_structvalue* sv = NULL;
+    etch_arraylist*  outlist = NULL;
+    etch_nativearray*  explist = NULL;
+	etch_int32* content = NULL;
+    etch_serializer* impexhelper = NULL;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    outlist = new_etch_arraylist(0,0);
+    outlist->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
+    outlist->is_readonly  = FALSE;
+    outlist->content_obj_type = ETCHTYPEB_PRIMITIVE;
+    outlist->content_class_id = CLASSID_PRIMITIVE_INT32;
+    etch_arraylist_add(outlist, new_int32(1));
+    etch_arraylist_add(outlist, new_int32(2));
+
+    /* retain ownership of outlist, assume ownership of returned struct */
+    sv = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->export_custom_value(dvf, (etch_object*) outlist);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+    /* see comments at this spot in test_export_custom_value_exception() */
+    impexhelper = etchtype_get_impexphelper(builtins._mt__etch_list);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+	explist = (etch_nativearray*) structvalue_get(sv, impexhelper->field); 
+
+    result  = is_etch_nativearray(explist);
+    CU_ASSERT_EQUAL_FATAL(result,TRUE); 
+    CU_ASSERT_EQUAL(explist->dimension[0],2);
+
+	explist->get1(explist, &content, 0);
+	CU_ASSERT_EQUAL_FATAL(is_etch_int32(content), TRUE);
+	CU_ASSERT_EQUAL(content->value, 1);
+	content = NULL;
+    explist->get1(explist, &content, 1);
+	CU_ASSERT_EQUAL_FATAL(is_etch_int32(content), TRUE);
+	CU_ASSERT_EQUAL(content->value, 2);
+
+    etch_object_destroy(outlist);
+    etch_object_destroy(sv);
+
+   // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_import_custom_value_list()
+ * import an etch list type
+ */
+static void test_import_custom_value_list(void)
+{
+    etch_iterator iterator;
+    etch_structvalue* sv = NULL;
+    etch_arraylist* inlist = NULL;
+    etch_arrayvalue* outlist = NULL;
+    etch_serializer* impexhelper = NULL;
+    int result = 0;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    
+        typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    impexhelper = etchtype_get_impexphelper(builtins._mt__etch_list);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+    sv = new_structvalue(builtins._mt__etch_list, 1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+	outlist  = new_arrayvalue_default();
+	arrayvalue_add(outlist, (ETCH_ARRAY_ELEMENT*)new_int32(1));
+	arrayvalue_add(outlist, (ETCH_ARRAY_ELEMENT*)new_int32(2));
+
+    result = structvalue_put(sv, clone_field(impexhelper->field), (etch_object*) outlist);
+    CU_ASSERT_EQUAL_FATAL(result,0); 
+
+    /* relinquish ownership of struct and outlist, assume ownership of inlist */
+    inlist = (etch_arraylist*) ((struct i_value_factory*)((etch_object*)dvf)->vtab)->import_custom_value(dvf, sv);
+    CU_ASSERT_EQUAL_FATAL(is_etch_arraylist(inlist), TRUE); 
+
+    set_iterator(&iterator, inlist, &inlist->iterable);
+
+    /* verify that imported list content is same as original */
+    while(iterator.has_next(&iterator))
+    {  
+       etch_int32* intobj = iterator.current_value;
+       CU_ASSERT_EQUAL_FATAL(is_etch_int32(intobj), TRUE);
+       switch(intobj->value) { case 1: case 2: break; default: result = -1; }       
+       CU_ASSERT_NOT_EQUAL(result, -1);  
+       iterator.next(&iterator); 
+    }
+
+    etch_object_destroy(inlist);
+   // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_export_custom_value_map()
+ * export an etch map type
+ */
+static void test_export_custom_value_map(void)
+{
+    etch_structvalue* sv = NULL;
+    etch_hashtable*  outmap = NULL;
+    etch_nativearray* explist = NULL;
+	etch_int32* icontent = NULL;
+	etch_string* scontent = NULL;
+    etch_serializer* impexhelper = NULL;
+    int  result = 0, outmapcount = 0;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    outmap = new_etch_map(0);  /* etch_map is an object-to-object hashtable */
+    etchmap_map_add (outmap, (etch_object*) new_string("1", ETCH_ENCODING_ASCII), (etch_object*) new_int32(1));
+    etchmap_map_add (outmap, (etch_object*) new_string("2", ETCH_ENCODING_ASCII), (etch_object*) new_int32(2)); 
+    outmapcount = etchmap_count(outmap);
+    CU_ASSERT_EQUAL_FATAL(outmapcount, 2);
+
+    /* retain ownership of outmap, assume ownership of returned struct */
+    sv = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->export_custom_value(dvf, (etch_object*) outmap);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+    /* see comments at this spot in test_export_custom_value_exception() */
+    impexhelper = etchtype_get_impexphelper(builtins._mt__etch_map);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+	explist = (etch_nativearray*) structvalue_get(sv, impexhelper->field); 
+
+    result  = is_etch_nativearray(explist);
+    CU_ASSERT_EQUAL_FATAL(result,TRUE); 
+    CU_ASSERT_EQUAL(explist->dimension[0],4);
+
+	explist->get1(explist, &scontent, 0);
+	CU_ASSERT_EQUAL_FATAL(is_etch_string(scontent), TRUE);
+	icontent = NULL;
+	scontent = NULL;
+    explist->get1(explist, &icontent, 1);
+	CU_ASSERT_EQUAL_FATAL(is_etch_int32(icontent), TRUE);
+	CU_ASSERT_EQUAL(icontent->value, 1);
+	icontent = NULL;
+	scontent = NULL;
+
+
+	explist->get1(explist, &scontent, 2);
+	CU_ASSERT_EQUAL_FATAL(is_etch_string(scontent), TRUE);
+	icontent = NULL;
+	scontent = NULL;
+    explist->get1(explist, &icontent, 3);
+	CU_ASSERT_EQUAL_FATAL(is_etch_int32(icontent), TRUE);
+	CU_ASSERT_EQUAL(icontent->value, 2);
+	icontent = NULL;
+	scontent = NULL;
+
+    etch_object_destroy(outmap);
+    etch_object_destroy(sv);
+
+   // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins(
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_import_custom_value_map()
+ * import an etch map type
+ */
+static void test_import_custom_value_map(void)
+{
+    etch_iterator iterator;
+    etch_structvalue* sv = NULL;
+    etch_hashtable* inmap = NULL;
+    etch_arrayvalue* outlist = NULL;
+    etch_serializer* impexhelper = NULL;
+    int  result = 0;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    impexhelper = etchtype_get_impexphelper(builtins._mt__etch_map);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+    sv = new_structvalue(builtins._mt__etch_map, 1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+	outlist  = new_arrayvalue_default();
+	arrayvalue_add(outlist, (ETCH_ARRAY_ELEMENT*)new_string("1", ETCH_ENCODING_ASCII));
+	arrayvalue_add(outlist, (ETCH_ARRAY_ELEMENT*)new_int32(1));
+	arrayvalue_add(outlist, (ETCH_ARRAY_ELEMENT*)new_string("2", ETCH_ENCODING_ASCII));
+	arrayvalue_add(outlist, (ETCH_ARRAY_ELEMENT*)new_int32(2));
+
+    result = structvalue_put(sv, clone_field(impexhelper->field), (etch_object*) outlist);
+    CU_ASSERT_EQUAL_FATAL(result,0); 
+
+    /* relinquish ownership of struct and outlist, assume ownership of inmap */
+    inmap = (etch_hashtable*) ((struct i_value_factory*)((etch_object*)dvf)->vtab)->import_custom_value(dvf, sv);
+    CU_ASSERT_EQUAL_FATAL(is_etch_hashtable(inmap), TRUE); 
+
+    set_iterator(&iterator, inmap, &inmap->iterable);
+
+    /* verify that imported map content is same as original */
+    while(iterator.has_next(&iterator))
+    {  
+       etch_string* keyobj = iterator.current_key;
+       etch_int32*  valobj = iterator.current_value;
+       CU_ASSERT_EQUAL_FATAL(is_etch_string(keyobj), TRUE);
+       CU_ASSERT_EQUAL_FATAL(is_etch_int32(valobj), TRUE);
+       switch(valobj->value) { case 1: case 2: break; default: result = -1; }       
+       CU_ASSERT_NOT_EQUAL(result, -1); 
+ 
+       iterator.next(&iterator); 
+    }
+    
+    etch_object_destroy(inmap);  
+
+    // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+/**
+ * test_export_custom_value_set()
+ * export an etch set type
+ */
+static void test_export_custom_value_set(void)
+{
+    etch_structvalue* sv = NULL;
+	etch_string* content = NULL;
+    etch_hashtable*  outset = NULL;
+    etch_nativearray*  explist = NULL;
+    etch_serializer* impexhelper = NULL;
+    int  result = 0, outsetcount = 0;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    outset = new_etch_set(0);  /* etch_set is an object-to-null hashtable */
+    etchmap_set_add (outset, (etch_object*) new_string("1", ETCH_ENCODING_ASCII));
+    etchmap_set_add (outset, (etch_object*) new_string("2", ETCH_ENCODING_ASCII)); 
+    outsetcount = etchmap_count(outset);
+    CU_ASSERT_EQUAL_FATAL(outsetcount, 2); 
+
+    /* retain ownership of outset, assume ownership of returned struct */
+    sv = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->export_custom_value(dvf, (etch_object*) outset);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+    /* see comments at this spot in test_export_custom_value_exception() */
+    impexhelper = etchtype_get_impexphelper(builtins._mt__etch_set);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+	explist = (etch_nativearray*) structvalue_get(sv, impexhelper->field); 
+
+    result  = is_etch_nativearray(explist);
+    CU_ASSERT_EQUAL_FATAL(result,TRUE); 
+    CU_ASSERT_EQUAL(explist->dimension[0],2);
+
+	explist->get1(explist, &content, 0);
+	CU_ASSERT_EQUAL_FATAL(is_etch_string(content), TRUE);
+	content = NULL;
+	explist->get1(explist, &content, 1);
+	CU_ASSERT_EQUAL_FATAL(is_etch_string(content), TRUE);
+	content = NULL;
+
+    etch_object_destroy(outset);
+    etch_object_destroy(sv);
+
+    // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_import_custom_value_set()
+ * import an etch set type
+ */
+static void test_import_custom_value_set(void)
+{
+    etch_iterator iterator;
+    etch_structvalue* sv = NULL;
+    etch_hashtable* inset = NULL;
+    etch_arrayvalue* outlist = NULL;
+    etch_serializer* impexhelper = NULL;
+    int  result = 0;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    impexhelper = etchtype_get_impexphelper(builtins._mt__etch_set);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+    sv = new_structvalue(builtins._mt__etch_set, 1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+	outlist  = new_arrayvalue_default();
+	arrayvalue_add(outlist, (ETCH_ARRAY_ELEMENT*)new_string("1", ETCH_ENCODING_ASCII));
+	arrayvalue_add(outlist, (ETCH_ARRAY_ELEMENT*)new_string("2", ETCH_ENCODING_ASCII));
+
+    result = structvalue_put(sv, clone_field(impexhelper->field), (etch_object*) outlist);
+    CU_ASSERT_EQUAL_FATAL(result,0); 
+
+    /* relinquish ownership of struct and outlist, assume ownership of inset */
+    inset = (etch_hashtable*) ((struct i_value_factory*)((etch_object*)dvf)->vtab)->import_custom_value(dvf, sv);
+    CU_ASSERT_EQUAL_FATAL(is_etch_set(inset), TRUE); 
+
+    set_iterator(&iterator, inset, &inset->iterable);
+
+    /* verify that imported map content is same as original */
+    while(iterator.has_next(&iterator))
+    {  
+       etch_string* setobj = iterator.current_key;
+       CU_ASSERT_EQUAL(is_etch_string(setobj), TRUE);
+       CU_ASSERT_PTR_NULL(iterator.current_value);
+       iterator.next(&iterator); 
+    }
+
+    etch_object_destroy(inset);
+    // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_export_custom_value_date()
+ * export an etch date type
+ */
+static void test_export_custom_value_date(void)
+{
+    etch_date*  outdate  = NULL;
+    etch_int64* expdate  = NULL;
+    etch_structvalue* sv = NULL;
+    etch_serializer* impexhelper = NULL;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    outdate = new_date();
+
+    /* retain ownership of outdate, assume ownership of returned struct */
+    sv = ((struct i_value_factory*)((etch_object*)dvf)->vtab)->export_custom_value(dvf, (etch_object*) outdate);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+    /* see comments at this spot in test_export_custom_value_exception() */
+    impexhelper = etchtype_get_impexphelper(builtins._mt__etch_datetime);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+    /* get reference to exported etch_int64 object from struct */
+    expdate = (etch_int64*) structvalue_get(sv, impexhelper->field); 
+    CU_ASSERT_EQUAL_FATAL(is_etch_int64(expdate), TRUE); 
+
+    etch_object_destroy(outdate);
+    etch_object_destroy(sv);
+    // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_import_custom_value_date()
+ * import an etch date type
+ */
+static void test_import_custom_value_date(void)
+{
+    etch_date*  indate = NULL;
+    etch_structvalue* sv = NULL;
+    etch_serializer* impexhelper = NULL;
+    time_t outtime, intime;
+    int result = 0;
+    default_value_factory*  dvf             = NULL;
+    vf_idname_map*          typemap         = NULL;
+    class_to_type_map*      c2tmap          = NULL;
+    
+     typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);  
+    defvf_initialize_static(typemap, c2tmap);
+    dvf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(dvf);
+
+    time(&outtime);
+
+    impexhelper = etchtype_get_impexphelper(builtins._mt__etch_datetime);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impexhelper); 
+
+    sv = new_structvalue(builtins._mt__etch_datetime, 1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+
+    result = structvalue_put(sv, clone_field(impexhelper->field), (etch_object*) new_int64(outtime));
+    CU_ASSERT_EQUAL_FATAL(result,0); 
+
+    /* relinquish ownership of struct, assume ownership of indate */
+    indate = (etch_date*) ((struct i_value_factory*)((etch_object*)dvf)->vtab)->import_custom_value(dvf, sv);
+    CU_ASSERT_EQUAL_FATAL(is_etch_date(indate), TRUE); 
+
+    intime = (time_t) indate->value;
+    CU_ASSERT_EQUAL(intime, outtime); 
+
+    etch_object_destroy(indate);
+    // destroy vf
+    etch_object_destroy(dvf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+    
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_defvaluefact_suite()
+{    
+    CU_pSuite pSuite = CU_add_suite("suite_defvf", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test constructor", test_constructor); 
+    CU_add_test(pSuite, "test builtins",  test_builtin_types);  
+    CU_add_test(pSuite, "test add type a",  test_add_type_a); 
+    CU_add_test(pSuite, "test add type b",  test_add_type_b); 
+    CU_add_test(pSuite, "test add type c",  test_add_type_c);  
+    CU_add_test(pSuite, "test get type by id", test_get_type_by_id);  
+    CU_add_test(pSuite, "test get type by name", test_get_type_by_name); 
+    CU_add_test(pSuite, "test get all types", test_get_types); 
+    CU_add_test(pSuite, "test auth excp fields",  test_authxcp_fields); 
+    CU_add_test(pSuite, "test runtime excp fields", test_rtxcp_fields);
+    CU_add_test(pSuite, "test get_set_message_id",  test_get_set_message_id); 
+    CU_add_test(pSuite, "test get_set_in_reply_to", test_get_set_in_reply_to);  
+    CU_add_test(pSuite, "test exception fields",  test_exception_fields);
+    CU_add_test(pSuite, "test get encoding", test_get_string_encoding); 
+
+    CU_add_test(pSuite, "test add mixin", test_add_mixin); 
+    CU_add_test(pSuite, "test mixin recursion", test_mixin_recursion); 
+    CU_add_test(pSuite, "test custom struct type", test_custom_struct_type); 
+                                                                   
+    CU_add_test(pSuite, "test export custom (exception)", test_export_custom_value_exception); 
+    CU_add_test(pSuite, "test export custom (runtime)", test_export_custom_value_runtime_exception); 
+    CU_add_test(pSuite, "test export custom (list)", test_export_custom_value_list);
+    CU_add_test(pSuite, "test export custom (map)",  test_export_custom_value_map);
+    CU_add_test(pSuite, "test export custom (set)",  test_export_custom_value_set);
+    CU_add_test(pSuite, "test export custom (date)", test_export_custom_value_date);
+
+    CU_add_test(pSuite, "test import custom (exception)", test_import_custom_value_exception); 
+    CU_add_test(pSuite, "test import custom (runtime)", test_import_custom_value_runtime_exception); 
+    CU_add_test(pSuite, "test import custom (list)", test_import_custom_value_list); 
+    CU_add_test(pSuite, "test import custom (map)",  test_import_custom_value_map); 
+    CU_add_test(pSuite, "test import custom (set)",  test_import_custom_value_set); 
+    CU_add_test(pSuite, "test import custom (date)", test_import_custom_value_date); 
+
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/message/test_field.c b/binding-c/runtime/c/src/test/message/test_field.c
new file mode 100644
index 0000000..e7ffdbd
--- /dev/null
+++ b/binding-c/runtime/c/src/test/message/test_field.c
@@ -0,0 +1,207 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_field.c 
+ * tests the C implementation of the etch_field object.
+ */
+#include "etch_runtime.h"
+#include "etch_field.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+#include <wchar.h>
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+
+/**
+ * test_field
+ */
+static void test_field(void)
+{
+    int alloc_a = 0, alloc_b = 0, result = 0;
+    etch_field *field1 = NULL, *field2 = NULL;
+
+    const wchar_t* nametext1 = L"abracadabra";
+
+    const wchar_t* nametext2 = L"gilgamesh";
+
+#ifdef ETCH_DEBUGALLOC
+    alloc_a  = etch_showmem(0, FALSE);
+#endif
+    field1 = new_field(NULL);
+    
+#ifdef ETCH_DEBUGALLOC
+   alloc_b  = etch_showmem(0, FALSE);
+#endif
+
+    CU_ASSERT_PTR_NULL(field1);
+    CU_ASSERT_EQUAL(alloc_a, alloc_b); 
+
+    field1 = new_field(nametext1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(field1);
+    CU_ASSERT_TRUE(is_good_field(field1));
+
+    field2 = new_field(nametext1);
+    CU_ASSERT_TRUE(is_equal_fields(field1, field2));
+    result = memcmp(field1->name, field2->name, field1->namebytelen);
+    CU_ASSERT_EQUAL(result,0);
+
+    destroy_field(field1);
+    destroy_field(field2);
+
+#ifdef ETCH_DEBUGALLOC
+    alloc_a = etch_showmem(0, FALSE);
+    CU_ASSERT_EQUAL(alloc_a, alloc_b); 
+#endif
+
+    field1 = new_field(nametext1);
+    field2 = new_field(nametext2);
+
+    CU_ASSERT_FALSE(is_equal_fields(field1, field2));
+
+    destroy_field(field1);
+    destroy_field(field2);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_inheritance
+ * test that etch_field's inheritance list is as expected
+ */
+static void test_inheritance(void)
+{
+    int  ndx = 0, parentcount = 0;
+    etchparentinfo* parentinfo = NULL;
+    const wchar_t* nametext1 = L"abracadabra";
+    
+    etch_field *field1 = new_field(nametext1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(field1);
+
+    while(1)
+    { parentinfo = get_next_etch_parent((etch_object*)field1, ndx++);
+      if (NULL == parentinfo) break;
+      parentcount++; 
+      #if IS_DEBUG_CONSOLE 
+      printf("parent %d type %d class %d\n", parentcount, ((etch_object*)parentinfo)->obj_type, ((etch_object*)parentinfo)->class_id);
+      #endif
+    }  
+
+    CU_ASSERT_EQUAL(parentcount, 2); /* field derives from both id_name and object */
+
+    destroy_field(field1);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_field_hashfunc
+ * Unit test field_hashfunc
+ */
+static void test_field_hashfunc(void)
+{
+    unsigned hash1 = 0, hash2 = 0;
+    etch_field *field1 = NULL, *field2 = NULL;
+
+    const wchar_t* nametext1 = L"abracadabra";
+    const size_t   numelts1  = wcslen(nametext1);
+    const size_t   numbytes1 = sizeof(wchar_t) * ( numelts1 + 1 );
+
+    const wchar_t* nametext2 = L"gilgamesh";
+    const size_t   numelts2  = wcslen(nametext2);
+    const size_t   numbytes2 = sizeof(wchar_t) * ( numelts2 + 1 );
+ 
+    hash1 = compute_field_id_from_widename(nametext1);
+    hash2 = compute_field_id_from_widename(nametext2);
+
+    CU_ASSERT_NOT_EQUAL(hash1, hash2);
+
+    field1 = new_field(nametext1);
+    field2 = new_field(nametext2);
+    CU_ASSERT_EQUAL(field1->namebytelen, numbytes1);
+    CU_ASSERT_EQUAL(field2->namebytelen, numbytes2);
+    CU_ASSERT_EQUAL(field1->id, hash1);
+    CU_ASSERT_EQUAL(field2->id, hash2);
+
+    destroy_field(field1);
+    destroy_field(field2);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_field_suite()
+//int main(int argc, char** argv[])
+{    
+    CU_pSuite pSuite = CU_add_suite("etch_field tests", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test etch_field constructors/destructors", test_field);  
+    CU_add_test(pSuite, "test etch_field hashing", test_field_hashfunc); 
+    CU_add_test(pSuite, "test etch_field inheritance", test_inheritance);   
+
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/message/test_idname.c b/binding-c/runtime/c/src/test/message/test_idname.c
new file mode 100644
index 0000000..07422c9
--- /dev/null
+++ b/binding-c/runtime/c/src/test/message/test_idname.c
@@ -0,0 +1,165 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_id_name.c 
+ * tests the C implementation of the etch_id_name object.
+ */
+#include "etch_runtime.h"
+#include "etch_id_name.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+#include <wchar.h>
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+
+/**
+ * test_id_name
+ */
+static void test_id_name(void)
+{
+    int result = 0;
+    etch_id_name *id_name1 = NULL, *id_name2 = NULL;
+
+    const wchar_t* nametext1 = L"abracadabra";
+
+    const wchar_t* nametext2 = L"gilgamesh";
+
+#ifdef ETCH_DEBUGALLOC
+    alloc_a  = etch_showmem(0, FALSE);
+#endif
+    id_name1 = new_id_name(NULL);
+    CU_ASSERT_PTR_NULL(id_name1);
+
+#ifdef ETCH_DEBUGALLOC
+    alloc_b  = etch_showmem(0, FALSE);
+    CU_ASSERT_EQUAL(alloc_a, alloc_b); 
+#endif
+
+    id_name1 = new_id_name(nametext1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(id_name1);
+    CU_ASSERT_TRUE(is_good_id_name(id_name1));
+
+    id_name2 = new_id_name(nametext1);
+    CU_ASSERT_TRUE(is_equal_id_names(id_name1, id_name2));
+    result = memcmp(id_name1->name, id_name2->name, id_name1->namebytelen);
+    CU_ASSERT_EQUAL(result,0);
+
+    destroy_id_name(id_name1);
+    destroy_id_name(id_name2);
+
+#ifdef ETCH_DEBUGALLOC
+    alloc_a = etch_showmem(0, FALSE);
+    CU_ASSERT_EQUAL(alloc_a, alloc_b); 
+#endif
+
+    id_name1 = new_id_name(nametext1);
+    id_name2 = new_id_name(nametext2);
+
+    CU_ASSERT_FALSE(is_equal_id_names(id_name1, id_name2));
+
+    destroy_id_name(id_name1);
+    destroy_id_name(id_name2);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_id_name_hashfunc
+ * Unit test id_name_hashfunc
+ */
+static void test_id_name_hashfunc(void)
+{
+    unsigned hash1 = 0, hash2 = 0;
+    etch_id_name *id_name1 = NULL, *id_name2 = NULL;
+
+    const wchar_t* nametext1 = L"abracadabra";
+    const size_t   numelts1  = wcslen(nametext1);
+    const size_t   numbytes1 = sizeof(wchar_t) * ( numelts1 + 1 );
+
+    const wchar_t* nametext2 = L"gilgamesh";
+    const size_t   numelts2  = wcslen(nametext2);
+    const size_t   numbytes2 = sizeof(wchar_t) * ( numelts2 + 1 );
+ 
+    hash1 = compute_id_name_id_from_widename(nametext1);
+    hash2 = compute_id_name_id_from_widename(nametext2);
+
+    CU_ASSERT_NOT_EQUAL(hash1, hash2);
+
+    id_name1 = new_id_name(nametext1);
+    id_name2 = new_id_name(nametext2);
+    CU_ASSERT_EQUAL(id_name1->namebytelen, numbytes1);
+    CU_ASSERT_EQUAL(id_name2->namebytelen, numbytes2);
+    CU_ASSERT_EQUAL(id_name1->id, hash1);
+    CU_ASSERT_EQUAL(id_name2->id, hash2);
+
+    destroy_id_name(id_name1);
+    destroy_id_name(id_name2);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_idname_suite()
+{    
+    CU_pSuite pSuite = CU_add_suite("suite_id_name", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test etch_id_name constructors/destructors", test_id_name);  
+    CU_add_test(pSuite, "test etch_id_name hashing", test_id_name_hashfunc);  
+
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/message/test_message.c b/binding-c/runtime/c/src/test/message/test_message.c
new file mode 100644
index 0000000..20c11e8
--- /dev/null
+++ b/binding-c/runtime/c/src/test/message/test_message.c
@@ -0,0 +1,1241 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_message.c -- test etch_message object
+ */
+#include "etch_runtime.h"
+#include "etch_connection.h"
+#include "etch_encoding.h"
+#include "etch_thread.h"
+#include "etch_log.h"
+#include "etch_message.h"
+#include "etch_objecttypes.h"
+#include "etch_exception.h"
+#include "etch_cache.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * individual setup and teardown
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+#if(0)
+#define OBJTYPE_FAKETDI_IMPL ETCHTYPEB_INSTANCEDATA
+#define CLASSID_FAKETDI_IMPL 0xf0
+#define OBJTYPE_FAKETDO_IMPL ETCHTYPEB_INSTANCEDATA
+#define CLASSID_FAKETDO_IMPL   0xf1
+#define OBJTYPE_FAKETDI_VTABLE 0x88
+#define OBJTYPE_FAKETDO_VTABLE 0x89
+#define CLASSID_FAKETDI 0xf6
+#define CLASSID_FAKETDO 0xf7
+#endif
+
+#define OBJTYPE_FAKEVF_IMPL ETCHTYPEB_INSTANCEDATA
+#define CLASSID_FAKEVF_IMPL    0xf2
+#define OBJTYPE_FAKEVF_VTABLE  0x90
+#define OBJTYPE_FAKEVF_IMPL ETCHTYPEB_INSTANCEDATA
+#define OBJTYPE_FAKEVF ETCHTYPEB_VALUEFACTORY
+#define CLASSID_FAKEVF  0xf5
+
+#define EXCPTEST_UNCHECKED_STATICTEXT 1
+#define EXCPTEST_CHECKED_COPYTEXT     2
+#define EXCPTEST_CHECKED_STATICTEXT   3
+
+
+typedef struct testitems
+{
+    etch_type*  mt1;
+    etch_type*  mt2;
+    etch_type*  rmt;
+    etch_field* mf1;
+    etch_field* mf2;
+    etch_field* mf3;
+    etch_field* mf4;
+
+    etch_string* s1;
+    etch_string* s2;
+    etch_int32*  n1;
+    etch_int32*  n2;
+    etch_int64*  l1;
+    etch_int64*  l2;
+
+    etch_field *mf_bool_d0_1;   
+    etch_field *mf_bool_d0_2;   
+    etch_field *mf_bool_d1_1;   
+    etch_field *mf_bool_d1_2;  
+
+    etch_field *mf_int32_d0_1;  
+    etch_field *mf_int32_d0_2;  
+    etch_field *mf_int32_d1_1;  
+    etch_field *mf_int32_d1_2;  
+
+    etch_field *mf_str_d0_1;   
+    etch_field *mf_str_d0_2;   
+    etch_field *mf_str_d1_1;  
+    etch_field *mf_str_d1_2;  
+
+    etch_field *mf_message_id;
+    etch_field *mf_in_reply_to; 
+
+    etch_hashtable* items;
+
+} testitems;
+
+enum objtyp {
+	ETCHTYPE_VTABLE_FAKETDI = 0xfa,
+	ETCHTYPE_VTABLE_FAKETDO = 0xfb,
+	ETCHTYPE_VTABLE_FAKEVF  = 0xfc
+};
+
+
+/* = = = = = = = = = = = = = = =
+ * VALUE FACTORY IMPLEMENTATION
+ * = = = = = = = = = = = = = = =
+ */
+
+/**
+ * fake_vf_impl
+ * instance data for a value factory implementation
+ */
+typedef struct fake_vf_impl
+{
+    etch_object object;
+
+    etch_field* mf_message_id;
+    etch_field* mf_in_reply_to;
+
+} fake_vf_impl;
+
+
+/**
+ * destroy_fake_vf_impl
+ * destructor for fake_vf_impl
+ */
+static int destroy_fake_vf_impl(void* data)
+{
+  fake_vf_impl* impl = (fake_vf_impl*)data;
+    int result = verify_object((etch_object*)impl, OBJTYPE_FAKEVF_IMPL, CLASSID_FAKEVF_IMPL, 0);
+    if (result == -1) return -1; /* object passed was not expected object */
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impl->mf_message_id);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impl->mf_in_reply_to); 
+
+    etch_object_destroy(impl->mf_message_id);
+    etch_object_destroy(impl->mf_in_reply_to);
+
+    etch_free(impl); 
+    return 0;
+}
+
+
+/**
+ * new_fake_vf_impl()
+ * constructor for TDI implementation instance data
+ */
+static fake_vf_impl* new_fake_vf_impl(testitems* items)
+{
+    fake_vf_impl* data = etch_malloc(sizeof(fake_vf_impl), ETCHTYPEB_INSTANCEDATA);
+    memset(data, 0, sizeof(fake_vf_impl));
+    ((etch_object*)data)->obj_type = OBJTYPE_FAKEVF_IMPL;
+    ((etch_object*)data)->class_id = CLASSID_FAKEVF_IMPL;
+
+    data->mf_message_id  = (etch_field*)etch_object_clone_func(items->mf_message_id);
+    data->mf_in_reply_to = (etch_field*)etch_object_clone_func(items->mf_in_reply_to);
+ 
+    ((etch_object*)data)->destroy = destroy_fake_vf_impl;
+    return data;
+}
+
+
+/*  
+ * value factory virtual function overrides
+ */
+
+/**
+ * fvf_get_message_id() -- valuefactory.get_message_id() implementation.
+ * @return non-disposable reference to id object, or null if not found.
+ */
+static etch_int64* fvf_get_message_id (void* vfData, etch_message* msg)
+{
+    etch_value_factory* vf = (etch_value_factory*)vfData;
+    etch_int64* id = NULL;
+    fake_vf_impl* data = (fake_vf_impl*) vf->impl;
+
+    id = (etch_int64*) message_get(msg, data->mf_message_id);
+
+    /* return (etch_int64*) verifyx((etch_object*) id, 0, 
+       CLASSID_PRIMITIVE_INT64, EXCPTYPE_INTERNALERR); */
+
+    return id;
+}
+
+
+/**
+ * fvf_set_message_id() -- valuefactory.set_message_id() implementation.
+ */
+static int fvf_set_message_id (void* vfData, etch_message* msg, etch_int64* id)
+{
+    etch_value_factory* vf = (etch_value_factory*)vfData;
+    fake_vf_impl* data  = (fake_vf_impl*) vf->impl;
+    etch_field* keycopy = (etch_field*)etch_object_clone_func(data->mf_message_id);
+
+    const int result = message_put(msg, keycopy, (etch_object*) id);  
+    return result;
+}
+
+
+/**
+ * fvf_get_in_reply_to() -- valuefactory.get_in_reply_to() implementation.
+ */
+static etch_int64* fvf_get_in_reply_to (void* vfData, etch_message* msg)
+{
+    etch_value_factory* vf = (etch_value_factory*)vfData;
+    etch_int64* id = NULL;
+    fake_vf_impl* data = (fake_vf_impl*) vf->impl;
+
+    id = (etch_int64*) message_get(msg, data->mf_in_reply_to);
+
+    return id;
+}
+
+
+/**
+ * fvf_set_in_reply_to() -- valuefactory.set_message_id() implementation.
+ */
+static int fvf_set_in_reply_to (void* vfData, etch_message* msg, etch_int64* id)
+{
+    etch_value_factory* vf = (etch_value_factory*)vfData;
+    fake_vf_impl* data  = (fake_vf_impl*) vf->impl;
+    etch_field* keycopy = clone_field(data->mf_in_reply_to);
+
+    /* FYI this copy of the key is put to etch_message* sent message, and gets   
+     * freed in msg.destroy(), message owns memory other than vf and type 
+     */
+    return message_put(msg, keycopy, (etch_object*) id);  
+}
+
+/*  
+ * value factory constructors/destructors
+ */
+
+
+#if 0
+/**
+ * fakevf_close() ala java test
+ */
+static void fakevf_close(etch_value_factory* vf)  
+{
+    etch_object_destroy(vf);  
+}
+#endif
+
+#define CLASSID_FAKE_VALUEFACTORY 200
+
+/**
+ * new_fake_value_factory()
+ * constructor for value factory implementation  
+ */
+static etch_value_factory* new_fake_value_factory(testitems* items)  
+{
+    etch_value_factory* fakevf = NULL;
+    i_value_factory* vtab = NULL;
+    const int VTABSIZE = sizeof(i_value_factory);
+    const unsigned short CLASS_ID = CLASSID_FAKE_VALUEFACTORY;
+   
+    fakevf = new_value_factory(0);
+   
+    vtab = etch_cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+    if(!vtab)  
+    {    
+        vtab = new_vtable(((etch_object*)fakevf)->vtab, VTABSIZE, CLASS_ID);
+
+        /* override four i_value_factory methods */
+        vtab->get_message_id  = fvf_get_message_id;
+        vtab->set_message_id  = fvf_set_message_id;
+        vtab->get_in_reply_to = fvf_get_in_reply_to;
+        vtab->set_in_reply_to = fvf_set_in_reply_to;      
+
+        ((etch_object*)vtab)->vtab = (vtabmask*)((etch_object*)fakevf)->vtab;  /* chain vtabs */
+        etch_cache_insert(((etch_object*)vtab)->hashkey, vtab, 0);  
+    } 
+
+    CU_ASSERT_EQUAL_FATAL(((etch_object*)vtab)->class_id, CLASS_ID);
+
+    ((etch_object*)fakevf)->vtab = (vtabmask*)vtab;  /* set override vtab */
+
+    fakevf->impl = (etch_object*) new_fake_vf_impl(items); /* create vf instance data */
+
+    return fakevf;
+}
+
+
+#if(0)
+
+/* = = = = = = = = = =    
+ * TDI IMPLEMENTATION
+ * = = = = = = = = = =     
+ */
+
+/**
+ * fake_tdi_impl
+ * instance data for a TDI implementation
+ */
+typedef struct fake_tdi_impl
+{
+    etch_object object;
+
+    etch_type*    tdi_type;
+    etch_message* xmessage;
+    etch_iterator iterator;  
+    etch_value_factory* vf;
+    testitems*    testdata;
+    byte started, done, ended, is_owned_message;
+
+} fake_tdi_impl;
+
+
+
+/**
+ * destroy_fake_tdi_impl
+ * memory cleanup handler for fake_tdi_impl
+ */
+static int destroy_fake_tdi_impl(void* data)
+{
+  fake_tdi_impl* impl = (fake_tdi_impl*)data;
+    etch_destructor destroy = NULL;
+    int result = verify_object((etch_object*)impl, OBJTYPE_FAKETDI_IMPL, CLASSID_FAKETDI_IMPL, 0);
+    if (result == -1) return -1; /* object passed was not expected object */
+
+    /* type is a reference, it does not belong to the tdi. message is created  
+     * in the tdi, but ownership is assumed to transfer to the caller when  
+     * message_read returns. if this is not the case then is_owned_message 
+     * must have been set elsewhere.
+     */
+    if (impl->is_owned_message) 
+    {   /* not the default case, see comment above */
+        CU_ASSERT_PTR_NOT_NULL_FATAL(impl->xmessage);  
+        etch_object_destroy(impl->xmessage);  
+    }
+ 
+    etch_free(impl); 
+    return 0;
+}
+
+
+/**
+ * new_fake_tdi_impl()
+ * constructor for TDI implementation instance data
+ */
+static fake_tdi_impl* new_fake_tdi_impl(etch_value_factory* vf, etch_type* static_type, testitems* testdata)
+{
+    fake_tdi_impl* data = (fake_tdi_impl*) 
+        new_object(sizeof(fake_tdi_impl), ETCHTYPEB_INSTANCEDATA, CLASSID_FAKETDI_IMPL);
+
+    /* value factory and type are references, memory not owned by tdi */
+    data->tdi_type = static_type;     
+    data->vf = vf;  
+    data->testdata = testdata;
+
+    data->destroy = destroy_fake_tdi_impl;        
+    return data;
+}
+
+
+/**
+ * faketdi_start_message() overrides tdi_start_message()
+ */
+static etch_message* faketdi_start_message(tagged_data_input* tdi) 
+{
+    int result = 0;
+    fake_tdi_impl* tdidata = NULL;
+    etch_message* newmessage = NULL;
+    etch_value_factory* vf = NULL;
+    const int READONLY = TRUE, DEFSIZE = 0, DEFDELTA = 0;
+    
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
+
+    tdidata = (fake_tdi_impl*) tdi->impl; /* validate instance data */
+    result  = verify_object((etch_object*)tdidata, OBJTYPE_FAKETDI_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdidata->vf);
+
+    etch_object_destroy(NULL); /* ensure we can call into instance destructor */
+    CU_ASSERT_EQUAL(result,-1);
+
+    CU_ASSERT_EQUAL(tdidata->started,FALSE);
+    CU_ASSERT_EQUAL(tdidata->done,FALSE);
+    CU_ASSERT_EQUAL(tdidata->ended,FALSE);
+
+    tdidata->started = TRUE;
+
+    /* create a message (struct) to receive the elements read. a message owns all  
+     * its memory except the value factory and type (note that the vf might need 
+     * to be refcounted for that reason, to ensure that if the service shuts down 
+     * while a message is in the pipeline, a vf is not destroyed prior to a message
+     * which references it). the type is passed through to the underlying struct. 
+     * a struct owns all its memory except type, so it is assigned a reference to 
+     * the tdi's type, which is an object global to the service. ownership of the 
+     * struct, and by extension the messsage, memory, is assumed to be passed to 
+     * the caller when this function returns. if instead it was desired that the 
+     * tdi own the message and hence the struct, an indicator of such and an 
+     * associated message dtor call, would need to be coded in the tdi and tdi 
+     * destructor implementation.
+     */
+    newmessage = new_message (tdidata->tdi_type, 0, tdidata->vf);  
+
+    tdidata->xmessage = newmessage;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdidata->xmessage);
+    
+    set_iterator(&tdidata->iterator, /* establish iterator on the input data */
+        tdidata->testdata->items, &tdidata->testdata->items->iterable);
+
+    /* while an empty dataset is valid in the general case, 
+     * this test assumes that input is non-empty */
+    result = tdidata->iterator.has_next(&tdidata->iterator); 
+    CU_ASSERT_EQUAL(result,TRUE);
+
+    return newmessage;
+}
+
+ 
+/**
+ * faketdi_read_struct_element() overrides tdi_read_struct_element()
+ */
+static int faketdi_read_struct_element(tagged_data_input* tdi, etch_struct_element* out_se)   
+{
+    int result = 0;
+    fake_tdi_impl* data = NULL;
+    etch_iterator* iterator = NULL;
+    etch_destructor destroy = NULL;    
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(out_se);
+
+    data = (fake_tdi_impl*) tdi->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+  
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->done,FALSE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+    iterator = &data->iterator;
+
+	if (iterator->has_next(iterator)) 
+	{   
+        CU_ASSERT_EQUAL_FATAL(result,0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(iterator->current_key);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(iterator->current_value);
+
+    	out_se->key   = (etch_field*) iterator->current_key;
+        out_se->value = (etch_object*)    iterator->current_value;
+
+        iterator->next(iterator);
+		return TRUE;
+	}
+	
+	data->done = TRUE;
+	return FALSE;
+}
+
+
+/**
+ * faketdi_end_message() overrides tdi_end_struct()
+ */
+static etch_message* faketdi_end_message(tagged_data_input* tdi, etch_message* msg) 
+{
+    int result = 0;
+    fake_tdi_impl* data = NULL;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
+
+    data = (fake_tdi_impl*) tdi->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    CU_ASSERT_EQUAL_FATAL(data->xmessage, msg); 
+
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->done,TRUE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+    			
+	data->ended = TRUE;
+    return msg;
+}
+
+
+/**
+ * faketdi_close() ala java test
+ * also tested here is that we can call base methods on a derived object. we invoke 
+ * the TDI destructor here, which is an overide of the etchobject destructor.
+ * the TDI destructor walks the vtable chain to its parent, and invokes the parent
+ * destructor to destroy etchobject content such as any exception, and finally
+ * the object itself.
+ */
+static void faketdi_close(tagged_data_input* tdi)  
+{
+    etch_object_destroy(tdi);  
+}
+
+
+/**
+ * new_fake_tdi()
+ * constructor for TDI implementation  
+ */
+static tagged_data_input* new_fake_tdi(etch_type* static_type, etch_value_factory* vfobj, testitems* data)  
+{
+    tagged_data_input* faketdi = NULL;
+    i_tagged_data_input* vtab  = NULL;
+    const unsigned short CLASS_ID = CLASSID_FAKETDI;
+    CU_ASSERT_EQUAL_FATAL(is_good_type(static_type),TRUE);
+   
+    faketdi = new_tagged_data_input();
+
+    vtab = cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+    if(!vtab)  
+    {    
+        vtab = new_vtable(((etch_object*)faketdi)->vtab, sizeof(i_tagged_data_input), CLASS_ID);
+
+        /* override three i_tagged_data_input methods */
+        vtab->start_message       = faketdi_start_message;  
+        vtab->end_message         = faketdi_end_message;    
+        vtab->read_struct_element = faketdi_read_struct_element;
+
+        ((etch_object*)vtab)->vtab = faketdi->vtab;      /* chain parent vtab to override vtab */
+        cache_insert(vtab->hashkey, vtab, FALSE);
+    } 
+
+    CU_ASSERT_EQUAL_FATAL(((etch_object*)vtab)->class_id, CLASS_ID);
+
+    ((etch_object*)faketdi)->vtab = vtab;  /* set override vtab */
+
+    faketdi->impl = (etch_object*) 
+        new_fake_tdi_impl(vfobj, static_type, data); /* create TDI instance data */
+
+    switch(g_which_exception_test)
+    {   case EXCPTEST_UNCHECKED_STATICTEXT: 
+             etch_throw((etch_object*) faketdi, EXCPTYPE_NULLPTR, NULL, 0);  
+             break;   
+        case EXCPTEST_CHECKED_COPYTEXT:   
+             etch_throw((etch_object*) faketdi, EXCPTYPE_CHECKED_BOGUS, L"copied text", ETCHEXCP_COPYTEXT | ETCHEXCP_FREETEXT);  
+             break; 
+        case EXCPTEST_CHECKED_STATICTEXT:   
+             etch_throw((etch_object*) faketdi, EXCPTYPE_CHECKED_BOGUS, local_excp_text, ETCHEXCP_STATICTEXT);  
+             break;       
+    }
+
+    return faketdi;
+}
+
+
+/* = = = = = = = = = = 
+ * TDO IMPLEMENTATION
+ * = = = = = = = = = = 
+ */
+
+/**
+ * fake_tdo_impl
+ * instance data for a TDO implementation
+ */
+typedef struct fake_tdo_impl
+{
+    etch_object object;
+
+    byte started, ended, closed;
+    etch_message* xmessage;  /* reference */
+    etch_hashtable* fakeout; /* fake output sink */  
+
+} fake_tdo_impl;
+
+
+/**
+ * destroy_fake_tdo_impl
+ * memory cleanup handler for fake_tdo_impl
+ * we do not destroy the message and underlying struct, this is a reference. 
+ */
+static int destroy_fake_tdo_impl(void* data)
+{
+  fake_tdo_impl* impl = (fake_tdo_impl*)data;
+    etch_destructor destroy = NULL;
+    int result = verify_object((etch_object*)impl, OBJTYPE_FAKETDO_IMPL, CLASSID_FAKETDO_IMPL, NULL);
+    if (result == -1) return -1; /* object passed was not expected object */
+
+    /* destroy the fake output sink, in this case a map. we do not want the map to
+     * destroy its content because the message owns that content, and we did not
+     * in this case give the output sink copies of that content. 
+    */
+    etch_object_destroy(impl->fakeout); 
+
+    etch_free(impl);    
+    return 0;
+}
+
+
+/**
+ * new_fake_tdo_impl()
+ * constructor for TDO implementation instance data
+ */
+static fake_tdo_impl* new_fake_tdo_impl(etch_message* msg)
+{
+    fake_tdo_impl* data = (fake_tdo_impl*) 
+        new_object(sizeof(fake_tdo_impl), ETCHTYPEB_INSTANCEDATA, CLASSID_FAKETDO_IMPL);
+
+    data->xmessage = msg; /* reference, not owned */
+
+    data->destroy = destroy_fake_tdo_impl;    
+    return data;
+}
+
+
+/**
+ * faketdo_start_message() overrides tdo_start_message()
+ */
+static etch_message* faketdo_start_message(tagged_data_output* tdo, etch_message* msg)  
+{
+    int result = 0;
+    fake_tdo_impl* data = NULL;
+    etch_destructor destructor = NULL;
+  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
+
+    data = (fake_tdo_impl*) tdo->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, (void**) &destructor);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    
+    etch_object_destroy(NULL); /* ensure we can call instance destructor */
+    CU_ASSERT_EQUAL(result,-1);
+
+    CU_ASSERT_EQUAL(data->started,FALSE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+
+    CU_ASSERT_EQUAL_FATAL(msg, data->xmessage);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->fakeout); 
+
+    data->started = TRUE;    
+    return msg;
+}
+
+
+/**
+ * faketdo_write_struct_element() overrides tdo_write_struct_element()
+ */
+static int faketdo_write_struct_element(tagged_data_output* tdo, etch_field* key, etch_object* val)  
+{
+    int result = 0;
+    fake_tdo_impl*  data  = NULL;
+    etch_hashtable* fakeout = NULL;
+  	etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket;
+  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo);  /* validate parameters */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(val);
+
+    result = is_good_field(key);
+    CU_ASSERT_EQUAL_FATAL(result,TRUE);
+
+    data = (fake_tdo_impl*) tdo->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    fakeout = data->fakeout;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(fakeout);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(fakeout->realtable);  
+
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->ended, FALSE);
+    CU_ASSERT_EQUAL(data->closed,FALSE);
+
+    /* do the write to the fake output */ 
+    result = ((etch_object*)fakeout)->vtab->insert(fakeout->realtable, key, HASHSIZE_FIELD, val, 0, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    /* verify the write by accessing the item just written */
+    result = ((etch_object*)fakeout)->vtab->find(fakeout->realtable, key, HASHSIZE_FIELD, 0, &myentry);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    CU_ASSERT_EQUAL_FATAL(myentry->key, (void*)key);
+    CU_ASSERT_EQUAL_FATAL(myentry->value, val);
+    
+	return 0;
+}
+
+
+/**
+ * faketdo_end_message() overrides tdo_end_message()
+ */
+static etch_message* faketdo_end_message(tagged_data_output* tdo, etch_message* msg)
+{
+    int result = 0;
+    fake_tdo_impl* data = NULL;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
+
+    data = (fake_tdo_impl*)  tdo->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->xmessage); 
+ 
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+    CU_ASSERT_EQUAL(data->closed,FALSE);
+    CU_ASSERT_EQUAL(data->xmessage, msg);
+			
+	data->ended = TRUE;
+    return msg;
+}
+
+
+/**
+ * faketdo_close() ala java test
+ */
+static void faketdo_close(tagged_data_output* tdo)  
+{
+    etch_object_destroy(tdo); 
+}
+
+
+/**
+ * new_fake_tdo()
+ * constructor for TDO implementation  
+ */
+static tagged_data_output* new_fake_tdo(etch_message* msg)  
+{
+    tagged_data_output* faketdo = NULL;
+    i_tagged_data_output*  vtab = NULL;
+    fake_tdo_impl* impl = NULL;
+    const unsigned short CLASS_ID = CLASSID_FAKETDO;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(msg);
+
+    faketdo = new_tagged_data_output();     
+
+    vtab = cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+    if(!vtab)  
+    {   
+        vtab = new_vtable(((etch_object*)faketdo)->vtab, sizeof(i_tagged_data_output), CLASS_ID);
+
+        /* override three i_tagged_data_output methods */
+        vtab->start_message        = faketdo_start_message;
+        vtab->end_message          = faketdo_end_message;
+        vtab->write_struct_element = faketdo_write_struct_element;
+
+        ((etch_object*)vtab)->vtab = faketdo->vtab;       /* chain parent vtab */
+    
+        cache_insert(vtab->hashkey, vtab, FALSE);
+    } 
+
+    CU_ASSERT_EQUAL_FATAL(((etch_object*)vtab)->class_id, CLASS_ID);
+
+    ((etch_object*)faketdo)->vtab = vtab;  /* set override vtab */
+
+    impl = new_fake_tdo_impl(msg);  /* construct TDO instance data */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impl); 
+            
+    impl->fakeout = new_hashtable(16); /* instantiate fake output target */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impl->fakeout);
+    impl->fakeout->content_type = ETCHHASHTABLE_CONTENT_OBJECT;
+
+    faketdo->impl = (etch_object*) impl;
+
+    return faketdo; 
+}
+
+#endif /* #if(0) */
+
+
+/* = = = = = = = = = = 
+ * TEST DATA  
+ * = = = = = = = = = = 
+ */
+
+/* 
+ * testdata_clear_handler()
+ * memory callback on testdata clear
+ */
+static int testdata_clear_handler (void* key, void* value)  
+{
+    return TRUE; /* indicate free handled */
+}
+
+/* 
+ * new_testitems()
+ * instantiate and return types and fields used in tests
+ */
+static testitems* new_testitems()
+{
+    testitems* items = etch_malloc(sizeof(struct testitems), 0);
+    items->mt1 = new_type(L"mt1");
+    items->mt2 = new_type(L"mt2");
+    items->rmt = new_type(L"rmt");
+    items->mf1 = new_field(L"x");
+    items->mf2 = new_field(L"y");
+    items->mf3 = new_field(L"s1");
+    items->mf4 = new_field(L"s2");
+
+    items->s1 = new_stringw(L"string1");
+    items->s2 = new_stringw(L"string2");
+    items->n1 = new_int32(1);
+    items->n2 = new_int32(2);
+    items->l1 = new_int64(12345);
+    items->l2 = new_int64(54321);
+
+    items->mf_bool_d0_1  = new_field(L"f1");
+    items->mf_bool_d0_2  = new_field(L"f2");
+    items->mf_bool_d1_1  = new_field(L"f3");
+    items->mf_bool_d1_2  = new_field(L"f4");
+
+    items->mf_int32_d0_1 = new_field(L"f5");
+    items->mf_int32_d0_2 = new_field(L"f6");
+    items->mf_int32_d1_1 = new_field(L"f7");
+    items->mf_int32_d1_2 = new_field(L"f8");
+
+    items->mf_str_d0_1   = new_field(L"f9");
+    items->mf_str_d0_2   = new_field(L"fa");
+    items->mf_str_d1_1   = new_field(L"fb");
+    items->mf_str_d1_2   = new_field(L"fc");
+
+    items->mf_message_id  = new_field(L"_messageId"); 
+    items->mf_in_reply_to = new_field(L"_inReplyTo"); 
+ 
+    etchtype_put_validator(items->mt1, clone_field(items->mf_message_id), (etch_object*) etchvtor_int64_get(0));
+    etchtype_put_validator(items->mt1, clone_field(items->mf1), (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(items->mt1, clone_field(items->mf2), (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(items->mt1, clone_field(items->mf3), (etch_object*) etchvtor_string_get(0));
+    etchtype_put_validator(items->mt1, clone_field(items->mf4), (etch_object*) etchvtor_string_get(0));
+
+    etchtype_put_validator(items->rmt, clone_field(items->mf_message_id), (etch_object*) etchvtor_int64_get(0));
+    etchtype_put_validator(items->rmt, clone_field(items->mf_in_reply_to),(etch_object*) etchvtor_int64_get(0));
+
+    #if(0)
+    etchtype_put_validator(items->mt1, items->mf_bool_d0_1->clone(items->mf_bool_d0_1), (etch_object*) etchvtor_boolean_get(0));
+    etchtype_put_validator(items->mt1, items->mf_bool_d0_2->clone(items->mf_bool_d0_2), (etch_object*) etchvtor_boolean_get(0));
+
+    etchtype_put_validator(items->mt1, items->mf_bool_d1_1->clone(items->mf_bool_d1_1), (etch_object*) etchvtor_boolean_get(1));
+    etchtype_put_validator(items->mt1, items->mf_bool_d1_2->clone(items->mf_bool_d1_2), (etch_object*) etchvtor_boolean_get(1));
+
+    etchtype_put_validator(items->mt1, items->mf_int32_d0_1->clone(items->mf_int32_d0_1), (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(items->mt1, items->mf_int32_d0_2->clone(items->mf_int32_d0_2), (etch_object*) etchvtor_int32_get(0));
+
+    etchtype_put_validator(items->mt1, items->mf_int32_d1_1->clone(items->mf_int32_d1_1), (etch_object*) etchvtor_int32_get(1));
+    etchtype_put_validator(items->mt1, items->mf_int32_d1_2->clone(items->mf_int32_d1_2), (etch_object*) etchvtor_int32_get(1));
+
+    etchtype_put_validator(items->mt1, items->mf_str_d0_1->clone(items->mf_str_d0_1), (etch_object*) etchvtor_string_get(0));
+    etchtype_put_validator(items->mt1, items->mf_str_d0_2->clone(items->mf_str_d0_2), (etch_object*) etchvtor_string_get(0));
+
+    etchtype_put_validator(items->mt1, items->mf_str_d1_1->clone(items->mf_str_d1_1), (etch_object*) etchvtor_string_get(1));
+    etchtype_put_validator(items->mt1, items->mf_str_d1_2->clone(items->mf_str_d1_2), (etch_object*) etchvtor_string_get(1));
+    #endif
+
+    items->items = new_hashtable(0);
+    items->items->is_readonly_keys   = FALSE;
+    items->items->is_readonly_values = FALSE; 
+    items->items->is_tracked_memory  = TRUE;
+    items->items->content_type = ETCHHASHTABLE_CONTENT_OBJECT;
+    items->items->freehook = testdata_clear_handler;
+    return items;
+}
+
+/* 
+ * destroy_testitems()
+ * free memory for test data
+ */
+static void destroy_testitems(testitems* items)
+{
+    etch_object_destroy(items->mt1);
+    etch_object_destroy(items->mt2);
+    etch_object_destroy(items->rmt);
+    etch_object_destroy(items->mf1);
+    etch_object_destroy(items->mf2); 
+    etch_object_destroy(items->mf3);
+    etch_object_destroy(items->mf4);
+
+    etch_object_destroy(items->s1); 
+    etch_object_destroy(items->s2); 
+    etch_object_destroy(items->n1); 
+    etch_object_destroy(items->n2); 
+    etch_object_destroy(items->l1); 
+    etch_object_destroy(items->l2); 
+
+    etch_object_destroy (items->mf_message_id); 
+    etch_object_destroy(items->mf_in_reply_to);
+
+    etch_object_destroy(items->mf_bool_d0_1);   
+    etch_object_destroy(items->mf_bool_d0_2);   
+    etch_object_destroy(items->mf_bool_d1_1);  
+    etch_object_destroy(items->mf_bool_d1_2);   
+
+    etch_object_destroy(items->mf_int32_d0_1); 
+    etch_object_destroy(items->mf_int32_d0_2);  
+    etch_object_destroy(items->mf_int32_d1_1);  
+    etch_object_destroy(items->mf_int32_d1_2);  
+
+    etch_object_destroy(items->mf_str_d0_1);    
+    etch_object_destroy(items->mf_str_d0_2);    
+    etch_object_destroy(items->mf_str_d1_1);    
+    etch_object_destroy(items->mf_str_d1_2);   
+
+    etchvtor_clear_cache(); /* free all cached validators */
+
+    destroy_hashtable(items->items, FALSE, FALSE);
+
+    etch_free(items);   
+}
+
+
+#if 0
+/* 
+ * compare_lists()
+ * compares specified message content with content of some other map.
+ * returns boolean indicating equal or not.
+ */
+static int compare_lists(etch_message* msg, etch_hashtable* otherdata)  
+{
+    int thiscount = 0, fakecount = 0, result = 0;
+    etch_structvalue* svx = NULL;
+    etch_iterator  iterator;
+  	etch_hashitem  hashbucket;
+    etch_hashitem* sventry = &hashbucket;
+
+    svx = msg->sv;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(svx);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(svx->items);
+
+    thiscount = ((struct i_hashtable*)((etch_object*)svx->items)->vtab)->count(svx->items->realtable,0,0); 
+    fakecount = ((struct i_hashtable*)((etch_object*)otherdata)->vtab)->count(otherdata->realtable,0,0); 
+    CU_ASSERT_EQUAL(fakecount, thiscount);
+    if (fakecount != thiscount) return FALSE;
+
+    set_iterator(&iterator, otherdata, &otherdata->iterable);
+
+    while(((struct i_iterable*)iterator.object.vtab)->has_next(&iterator) && result == 0)
+    {
+        result = ((struct i_hashtable*)((etch_object*)svx->items)->vtab)->findh
+            (svx->items->realtable, ((etch_object*)iterator.current_key)->hashkey, 
+	     otherdata, (void**)&sventry);
+        CU_ASSERT_EQUAL(iterator.current_value, sventry->value);
+
+        ((struct i_iterable*)iterator.object.vtab)->next(&iterator);
+    }
+
+    return TRUE;
+}
+
+#endif
+
+#if 0
+/* 
+ * hashtable_clear_handler()
+ * override callback from hashtable during clear()
+ */
+static int hashtable_clear_handler (void* key, void* value)  
+{
+    /* prior to calling clear() on any hashtable htab, set: 
+     *    htab.callback = hashtable_clear_handler; 
+     * and the hashtable will call back here for each item in the table,
+     * replacing any such handler installed. return FALSE to have the hashtable 
+     * proceed as it would with a handler. save off the existing handler and call 
+     * it, to proceed as if you had not replaced the handler. return TRUE to  
+     * indicate you handled the free and the hashtable should not attempt to free 
+     * memory for key and/or value, if in fact it would have done so otherwise. 
+     * note that structs always set such a callback on their backing store
+     * in order to free key and value allocations.
+     */
+    return FALSE;
+}
+
+#endif
+/* = = = = = = = = = = 
+ * TESTS   
+ * = = = = = = = = = = 
+ */
+
+/* 
+ * run_iterator_test()
+ * iterate over test collection, inserting pairs to specified message.
+ * iterate over message, veriying that content matches test collection.
+ */
+static int run_iterator_test(etch_message* msg, testitems* data)
+{
+    etch_iterator* iterator  = NULL;
+    int msgcount = 0, testcount = 0, result = 0;
+
+    iterator = new_iterator(data->items, &data->items->iterable);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+    CU_ASSERT_EQUAL(iterator->ordinal,1);
+
+    while(iterator->has_next(iterator))
+    {
+        testcount++;
+
+        result = message_put(msg, iterator->current_key, iterator->current_value);
+
+        CU_ASSERT_EQUAL(result,0);
+        
+        iterator->next(iterator);
+    }
+    
+    set_iterator(iterator, msg->sv->items, &msg->sv->items->iterable);
+    CU_ASSERT_EQUAL(iterator->ordinal,1);
+
+    while(iterator->has_next(iterator))
+    {
+        msgcount++;
+        iterator->next(iterator);
+    }
+
+    CU_ASSERT_EQUAL(testcount, msgcount);
+    etch_object_destroy(iterator);
+    return msgcount;
+}
+
+
+/* 
+ * iterator_test()
+ */
+static void iterator_test(void)
+{
+    int result = 0;
+    testitems* data = NULL;
+    etch_hashtable* map = NULL;
+    etch_message*   msg = NULL;
+    etch_value_factory* vf = NULL; 
+
+    etch_string *sval1 = NULL, *sval2 = NULL;
+    etch_int32  *ival1 = NULL, *ival2 = NULL;
+    etch_field  *skey1 = NULL, *skey2 = NULL;
+    etch_field  *ikey1 = NULL, *ikey2 = NULL;
+
+    data = new_testitems();
+    map  = data->items;
+
+    /* a message owns all its memory except the value factory and type, so we'll
+     * make copies of all the testdata keys and values to be inserted into it */
+    ikey1 = (etch_field*)etch_object_clone_func(data->mf1); 
+    ikey2 = (etch_field*)etch_object_clone_func(data->mf2);
+    skey1 = (etch_field*)etch_object_clone_func(data->mf3); 
+    skey2 = (etch_field*)etch_object_clone_func(data->mf4);
+
+    sval1 = (etch_string*)etch_object_clone_func(data->s1);  
+    sval2 = (etch_string*)etch_object_clone_func(data->s2);
+    ival1 = (etch_int32*)etch_object_clone_func(data->n1);  
+    ival2 = (etch_int32*)etch_object_clone_func(data->n2);
+
+    /* insert cloned fields and values to the test input collection */
+    ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth(map->realtable, ikey1, ival1, map, 0);
+    ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth(map->realtable, ikey2, ival2, map, 0);
+    ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth(map->realtable, skey1, sval1, map, 0);
+    ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth(map->realtable, skey2, sval2, map, 0);
+   
+    vf = new_fake_value_factory(data);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(vf);
+    CU_ASSERT_FALSE_FATAL(is_etch_exception(vf));
+
+    /* a message owns its memory except vf and type, so we give it global type */
+    msg = new_message (data->mt1, 0, vf);  
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(msg);
+    CU_ASSERT_FALSE_FATAL(is_etch_exception(msg));
+    
+    result = run_iterator_test(msg, data);
+    CU_ASSERT_EQUAL(result,4);  /* 4 items in message */
+
+    etch_object_destroy(msg);
+    etch_object_destroy(vf); 
+  
+    destroy_testitems(data);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+/* 
+ * reply_test
+ * test message.reply 
+ */
+static void reply_test(void)
+{
+    int result = 0;
+    etch_message* msg = NULL; 
+    etch_message* newmsg = NULL;
+    etch_type* replytype = NULL;
+    etch_value_factory* vf = NULL;
+    etch_int64* id_original = NULL;
+    etch_int64* id_replied_to = NULL;
+    int64 val_origid = 0, val_replyid = 0;
+    testitems* data = new_testitems();
+
+    id_original = data->l1;
+
+    vf = new_fake_value_factory(data);
+    
+    msg = new_message (data->mt1, 0, vf);  /* message owns neither arg */
+
+    result = message_set_id(msg, (etch_int64*)etch_object_clone_func(id_original));  
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    replytype = data->rmt;    /* again, a message does not own a type */ 
+
+    newmsg = message_reply (msg, replytype);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(newmsg);
+    CU_ASSERT_FALSE_FATAL(is_etch_exception(newmsg));
+
+    result = is_equal_types(data->rmt, newmsg->sv->struct_type);
+    CU_ASSERT_TRUE(result);
+    CU_ASSERT_EQUAL(vf, newmsg->vf);
+
+    id_replied_to = message_get_in_reply_to(newmsg);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(id_replied_to);
+    CU_ASSERT_FALSE_FATAL(is_etch_exception(id_replied_to));
+
+    val_origid  = id_original->value;
+    val_replyid = id_replied_to->value;   
+    CU_ASSERT_EQUAL(val_origid, val_replyid);
+
+    etch_object_destroy(newmsg);
+    etch_object_destroy(msg);  
+    etch_object_destroy(vf);   
+    destroy_testitems(data);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+#if 0
+/* 
+ * run_exception_test
+ * execute an individual exception test 
+ */
+static void run_exception_test(const int whichtest)
+{
+    etch_type* static_type = NULL;
+    etch_value_factory* vf = NULL;
+    testitems* data = new_testitems();
+
+    static_type = new_type(L"type1");
+    vf = new_fake_value_factory(data);
+
+    #if(0)
+    /* create a bogus TDI inheriting from tagged data input */
+    tdi = new_fake_tdi(static_type, vf, NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);
+
+    switch(whichtest)
+    {   case EXCPTEST_UNCHECKED_STATICTEXT:
+        case EXCPTEST_CHECKED_COPYTEXT:
+        case EXCPTEST_CHECKED_STATICTEXT:
+        {   CU_ASSERT_TRUE_FATAL(is_exception(tdi));
+            #if IS_DEBUG_CONSOLE 
+            wprintf(L"\ncaught %s exception on tdi\n", tdi->result->exception->excptext);          
+            #endif   
+        }
+    }
+
+    msg = message_read(NULL); /* pass NULL for TDI */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(msg);
+    CU_ASSERT_TRUE(is_exception(msg));
+    excp = get_exception(msg);
+    CU_ASSERT_EQUAL(excp->excptype, EXCPTYPE_ILLEGALARG);
+    #if IS_DEBUG_CONSOLE 
+    wprintf(L"\ncaught %s exception on message\n", msg->result->exception->excptext);          
+    #endif   
+
+    /* free TDI */
+    faketdi_close(tdi);
+
+    /* free struct, it is just a shell with no content other than the exception */
+    etch_object_destroy(msg);
+
+    #endif
+
+    etch_object_destroy(vf);
+
+    destroy_testitems(data);
+    etch_object_destroy(static_type);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+#endif
+
+
+
+/**
+ * main   
+ */
+//int _tmain(int argc, _TCHAR* argv[])
+CU_pSuite test_etch_message_suite()
+{    
+    CU_pSuite pSuite = CU_add_suite("suite_message", init_suite, clean_suite);
+    CU_add_test(pSuite, "test iterator over message", iterator_test);  
+    CU_add_test(pSuite, "message reply test", reply_test); 
+
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/message/test_structvalue.c b/binding-c/runtime/c/src/test/message/test_structvalue.c
new file mode 100644
index 0000000..6a1cac1
--- /dev/null
+++ b/binding-c/runtime/c/src/test/message/test_structvalue.c
@@ -0,0 +1,1045 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_structvalue.c -- test etch_structvalue object
+ */
+
+#include "etch_runtime.h"
+#include "etch_connection.h"
+#include "etch_encoding.h"
+#include "etch_log.h"
+#include "etch_structval.h"
+#include "etch_nativearray.h"
+#include "etch_objecttypes.h"
+#include "etch_exception.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * individual setup and teardown
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+static etch_type *mt1, *mt2;
+
+static etch_field *mf_bool_d0_1;   
+static etch_field *mf_bool_d0_2;   
+static etch_field *mf_bool_d1_1;   
+static etch_field *mf_bool_d1_2;  
+
+static etch_field *mf_int32_d0_1;  
+static etch_field *mf_int32_d0_2;  
+static etch_field *mf_int32_d1_1;  
+static etch_field *mf_int32_d1_2;  
+
+static etch_field *mf_str_d0_1;   
+static etch_field *mf_str_d0_2;   
+static etch_field *mf_str_d1_1;  
+static etch_field *mf_str_d1_2;  
+
+static etch_hashtable* testdata;  
+
+static int g_which_exception_test;
+
+#if(0)
+#define OBJTYPE_FAKETDI_IMPL ETCHTYPEB_INSTANCEDATA
+#define CLASSID_FAKETDI_IMPL 0xf0
+#define OBJTYPE_FAKETDO_IMPL ETCHTYPEB_INSTANCEDATA
+#define CLASSID_FAKETDO_IMPL 0xf1
+#define OBJTYPE_FAKETDI_VTABLE 0x88
+#define OBJTYPE_FAKETDO_VTABLE 0x89
+#define CLASSID_FAKETDI 0xf6
+#define CLASSID_FAKETDO 0xf7
+#endif
+
+#define EXCPTEST_UNCHECKED_STATICTEXT 1
+#define EXCPTEST_CHECKED_COPYTEXT     2
+#define EXCPTEST_CHECKED_STATICTEXT   3
+
+
+#if(0)
+
+/**
+ * fake_tdi_impl
+ * instance data for a TDI implementation
+ */
+typedef struct fake_tdi_impl
+{
+    etch_object object;
+
+    etch_type* tdi_type;
+    byte started, done, ended, is_owned_struct;
+    etch_structvalue* xstruct;
+    etch_iterator iterator;  
+
+} fake_tdi_impl;
+
+
+/**
+ * fake_tdo_impl
+ * instance data for a TDO implementation
+ */
+typedef struct fake_tdo_impl
+{
+    etch_object object;
+
+    byte started, ended, closed;
+    etch_structvalue* xstruct;
+    etch_hashtable* fakeout; /* fake output stream */  
+
+} fake_tdo_impl;
+
+
+/**
+ * fake_tdi_impl_destroy_handler
+ * memory cleanup handler for fake_tdi_impl
+ */
+static int destroy_fake_tdi_impl(fake_tdi_impl* impl)
+{
+    etch_destructor destroy = NULL;
+    int result = verify_object((etch_object*)impl, OBJTYPE_FAKETDI_IMPL, CLASSID_FAKETDI_IMPL, NULL);
+    if (result == -1) return -1; /* object passed was not expected object */
+
+    /* type is a refrence, it does  not belong to the tdi. struct is created  
+     * in the tdi, but ownership is assumed to transfer to the caller when  
+     * structvalue_read returns. if this is not the case then is_owned_struct 
+     * must have been set elsewhere
+     */
+    if (impl->is_owned_struct) 
+    {   /* not the default case, see comment above */
+        CU_ASSERT_PTR_NOT_NULL_FATAL(impl->xstruct);  
+        etch_object_destroy(impl->xstruct);  
+    }
+ 
+    etch_free(impl); 
+   
+    return 0;
+}
+
+
+/**
+ * fake_tdo_impl_destroy_handler
+ * memory cleanup handler for fake_tdo_impl
+ */
+static int destroy_fake_tdo_impl(fake_tdo_impl* impl)
+{
+    etch_destructor destroy = NULL;
+    int result = verify_object((etch_object*)impl, OBJTYPE_FAKETDO_IMPL, CLASSID_FAKETDO_IMPL, NULL);
+    if (result == -1) return -1; /* object passed was not expected object */
+
+    /* destroy the fake output receptor, in this case a hashtable. we don't want the
+     * hashtable to destroy its content because its content is references to someone
+     * else's content, in this case the host struct value. 
+    */
+    destroy_hashtable(impl->fakeout, FALSE, FALSE); 
+
+    /* we do not destroy the struct value, this is merely a reference */ 
+    /* impl->((etch_object*)xstruct)->vtab->destroy(impl->xstruct); */
+
+    etch_free(impl);    
+    return 0;
+}
+
+
+/**
+ * new_fake_tdi_impl()
+ * constructor for TDI implementation instance data
+ */
+static fake_tdi_impl* new_fake_tdi_impl(etch_type* static_type)
+{
+   fake_tdi_impl* data = (fake_tdi_impl*) 
+        new_object(sizeof(fake_tdi_impl), ETCHTYPEB_INSTANCEDATA, CLASSID_FAKETDI_IMPL);
+
+   /* assign type - this is a reference, it is not our memory */
+    data->tdi_type = static_type;       
+
+    /* set destructor */
+    data->destroy = destroy_fake_tdi_impl;
+    return data;
+}
+
+
+/**
+ * new_fake_tdo_impl()
+ * constructor for TDO implementation instance data
+ */
+static fake_tdo_impl* new_fake_tdo_impl(etch_structvalue* sv)
+{
+    fake_tdo_impl* data = (fake_tdo_impl*) 
+         new_object(sizeof(fake_tdo_impl), ETCHTYPEB_INSTANCEDATA, CLASSID_FAKETDO_IMPL);
+
+    data->xstruct  = sv;
+
+    /* set destructor */
+    data->destroy = destroy_fake_tdo_impl;    
+    return data;
+}
+
+
+enum objtyp ETCHTYPE_VTABLE_FAKETDI = 0xf0;
+enum objtyp ETCHTYPE_VTABLE_FAKETDO = 0xf1;
+
+
+/**
+ * faketdi_start_struct() overrides tdi_start_struct()
+ */
+static etch_structvalue* faketdi_start_struct(tagged_data_input* tdi) 
+{
+    int result = 0;
+    fake_tdi_impl* data = NULL;
+    etch_structvalue* newstructval = NULL;
+    const int READONLY = TRUE, DEFSIZE = 0, DEFDELTA = 0;
+    
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
+
+    data = (fake_tdi_impl*) tdi->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    result = etch_object_destroy(NULL); /* ensure we can call into instance data destructor */
+    CU_ASSERT_EQUAL(result,-1);
+
+    CU_ASSERT_EQUAL(data->started,FALSE);
+    CU_ASSERT_EQUAL(data->done,FALSE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+
+    data->started = TRUE;
+
+    /* create a struct to receive the elements read. a struct owns all its memory
+     * so we give it a copy of the tdi's type. ownership of the struct is assumed
+     * to be passed to the caller when this function returns. if instead it was
+     * desired that the tdi own the struct, data.is_owned_struct would have to
+     * be set subsequently elsewhere. 
+     * note that sv no longer owns type, so we no longer clone the type
+     */
+    newstructval = new_structvalue (data->tdi_type, 0);  
+
+    data->xstruct = newstructval;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->xstruct);
+
+    /* establish iterator on the fake input data */
+    set_iterator(&data->iterator, testdata, &testdata->iterable);
+
+    /* while an empty dataset is valid in the general case, 
+     * this test assumes that input is non-empty */
+    result = data->iterator.vtab->has_next(&data->iterator); 
+    CU_ASSERT_EQUAL(result,TRUE);
+
+    return data->xstruct;
+}
+
+
+/**
+ * faketdo_start_struct() overrides tdo_start_struct()
+ */
+static int faketdo_start_struct(tagged_data_output* tdo, etch_structvalue* structval)  
+{
+    int result = 0;
+    fake_tdo_impl* data = NULL;
+  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
+
+    data = (fake_tdo_impl*) tdo->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    
+    result = data->destroy(NULL); /* ensure we can call instance data destructor */
+    CU_ASSERT_EQUAL(result,-1);
+
+    CU_ASSERT_EQUAL(data->started,FALSE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+
+    CU_ASSERT_EQUAL_FATAL(structval, data->xstruct);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->fakeout); 
+
+    data->started = TRUE;    
+    return 0;
+}
+
+
+
+/**
+ * faketdo_write_struct_element() overrides tdo_write_struct_element()
+ */
+static int faketdo_write_struct_element(tagged_data_output* tdo, etch_field* key, etch_object* val)  
+{
+    int result = 0;
+    fake_tdo_impl*  data  = NULL;
+    etch_hashtable* fakeout = NULL;
+  	etch_hashitem   hashbucket;
+    etch_hashitem*  myentry = &hashbucket;
+  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo);  /* validate parameters */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(val);
+
+    result = is_good_field(key);
+    CU_ASSERT_EQUAL_FATAL(result,TRUE);
+
+    data = (fake_tdo_impl*) tdo->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    fakeout = data->fakeout;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(fakeout);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(fakeout->realtable);  
+
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->ended, FALSE);
+    CU_ASSERT_EQUAL(data->closed,FALSE);
+
+    /* do the write to the fake output */ 
+    result = ((etch_object*)fakeout)->vtab->insert(fakeout->realtable, key, HASHSIZE_FIELD, val, 0, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+
+    /* verify the write by accessing the item just written */
+    result = ((etch_object*)fakeout)->vtab->find(fakeout->realtable, key, HASHSIZE_FIELD, 0, &myentry);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    CU_ASSERT_EQUAL_FATAL(myentry->key, (void*)key);
+    CU_ASSERT_EQUAL_FATAL(myentry->value, val);
+    
+	return 0;
+}
+
+ 
+/**
+ * faketdi_read_struct_element() overrides tdi_read_struct_element()
+ */
+static int faketdi_read_struct_element(tagged_data_input* tdi, etch_struct_element* out_se)   
+{
+    int result = 0;
+    fake_tdi_impl* data = NULL;
+    etch_iterator* iterator = NULL;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(out_se);
+
+    data = (fake_tdi_impl*) tdi->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+  
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->done,FALSE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+    iterator = &data->iterator;
+
+	if (iterator->has_next(iterator)) 
+	{   
+        CU_ASSERT_EQUAL_FATAL(result,0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(iterator->current_key);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(iterator->current_value);
+
+    	out_se->key   = (etch_field*) iterator->current_key;
+        out_se->value = (etch_object*)    iterator->current_value;
+
+        iterator->next(iterator);
+		return TRUE;
+	}
+	
+	data->done = TRUE;
+	return FALSE;
+}
+
+
+/**
+ * faketdi_end_struct() overrides tdi_end_struct()
+ */
+static int faketdi_end_struct(tagged_data_input* tdi, etch_structvalue* sv)   
+{
+    int result = 0;
+    fake_tdi_impl* data = NULL;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi->impl);
+
+    data = (fake_tdi_impl*) tdi->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDI_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->xstruct); 
+ 
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->done,TRUE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+    CU_ASSERT_EQUAL(data->xstruct,sv);
+			
+	data->ended = TRUE;
+    return 0;
+}
+
+
+/**
+ * faketdo_end_struct() overrides tdo_end_struct()
+ */
+static int faketdo_end_struct(tagged_data_output* tdo, struct etch_structvalue* sv) 
+{
+    int result = 0;
+    fake_tdo_impl* data = NULL;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdo->impl);
+
+    data = (fake_tdo_impl*) tdo->impl; /* validate instance data */
+    result = verify_object((etch_object*)data, OBJTYPE_FAKETDO_IMPL, 0, 0);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(data->xstruct); 
+ 
+    CU_ASSERT_EQUAL(data->started,TRUE);
+    CU_ASSERT_EQUAL(data->ended,FALSE);
+    CU_ASSERT_EQUAL(data->closed,FALSE);
+    CU_ASSERT_EQUAL(data->xstruct, sv);
+			
+	data->ended = TRUE;
+    return 0;
+}
+
+
+/**
+ * faketdi_close() ala java test
+ * also tested here is that we can call base methods on a derived object. we invoke 
+ * the TDI destructor here, which is an overide of the etchobject destructor.
+ * the TDI destructor walks the vtable chain to its parent, and invokes the parent
+ * destructor to destroy etchobject content such as any exception, and finally
+ * the object itself.
+ */
+static void faketdi_close(tagged_data_input* tdi)  
+{
+    tdi->destroy(tdi);  
+}
+
+
+/**
+ * faketdo_close() ala java test
+ */
+static void faketdo_close(tagged_data_output* tdo)  
+{
+    tdo->destroy(tdo);  
+}
+
+
+/**
+ * new_fake_tdi()
+ * constructor for TDI implementation  
+ */
+static tagged_data_input* new_fake_tdi(etch_type* static_type)  
+{
+    tagged_data_input* faketdi = NULL;
+    i_tagged_data_input* vtab  = NULL;
+    const unsigned short CLASS_ID = CLASSID_FAKETDI;
+    CU_ASSERT_EQUAL_FATAL(is_good_type(static_type),TRUE);
+   
+    faketdi = new_tagged_data_input();
+
+    vtab = cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+    if(!vtab)  
+    {    
+        vtab = new_vtable(((etch_object*)faketdi)->vtab, sizeof(i_tagged_data_input), CLASS_ID);
+
+        /* override three i_tagged_data_input methods */
+        vtab->start_struct = faketdi_start_struct;  
+        vtab->end_struct   = faketdi_end_struct;    
+        vtab->read_struct_element = faketdi_read_struct_element;
+
+        ((etch_object*)vtab)->vtab = faketdi->vtab;      /* chain parent vtab to override vtab */
+        cache_insert(vtab->hashkey, vtab, FALSE);
+    } 
+
+    CU_ASSERT_EQUAL_FATAL(((etch_object*)vtab)->class_id, CLASS_ID);
+
+    ((etch_object*)faketdi)->vtab = vtab;  /* set override vtab */
+
+    faketdi->impl = (etch_object*) 
+        new_fake_tdi_impl(static_type); /* create TDI instance data */
+
+    switch(g_which_exception_test)
+    {   case EXCPTEST_UNCHECKED_STATICTEXT: 
+             etch_throw((etch_object*) faketdi, EXCPTYPE_NULLPTR, NULL, 0);  
+             break;   
+        case EXCPTEST_CHECKED_COPYTEXT:   
+             etch_throw((etch_object*) faketdi, EXCPTYPE_CHECKED_BOGUS, L"copied text", ETCHEXCP_COPYTEXT | ETCHEXCP_FREETEXT);  
+             break; 
+        case EXCPTEST_CHECKED_STATICTEXT:   
+             etch_throw((etch_object*) faketdi, EXCPTYPE_CHECKED_BOGUS, local_excp_text, ETCHEXCP_STATICTEXT);  
+             break;       
+    }
+
+    return faketdi;
+}
+
+
+
+/**
+ * new_fake_tdo()
+ * constructor for TDO implementation  
+ */
+static tagged_data_output* new_fake_tdo(etch_structvalue* sv)  
+{
+    tagged_data_output* faketdo = NULL;
+    i_tagged_data_output*  vtab = NULL;
+    fake_tdo_impl* impl = NULL;
+    const unsigned short CLASS_ID = CLASSID_FAKETDO;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv);
+
+    faketdo = new_tagged_data_output();     
+
+    vtab = cache_find(get_vtable_cachehkey(CLASS_ID), 0);
+
+    if(!vtab)  
+    {   
+        vtab = new_vtable(((etch_object*)faketdo)->vtab, sizeof(i_tagged_data_output), CLASS_ID);
+
+        /* override three i_tagged_data_output methods */
+        vtab->start_struct = faketdo_start_struct;
+        vtab->end_struct   = faketdo_end_struct;
+        vtab->write_struct_element = faketdo_write_struct_element;
+
+        ((etch_object*)vtab)->vtab = faketdo->vtab;  /* chain parent vtab to override vtab */
+    
+        cache_insert(vtab->hashkey, vtab, FALSE);
+    } 
+
+    CU_ASSERT_EQUAL_FATAL(((etch_object*)vtab)->class_id, CLASS_ID);
+
+    ((etch_object*)faketdo)->vtab = vtab;         /* set override vtab */
+
+    impl = new_fake_tdo_impl(sv); /* set TDO instance data */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impl); 
+                  
+    impl->fakeout = new_hashtable(16); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(impl->fakeout);
+    impl->fakeout->is_readonly_keys  = impl->fakeout->is_readonly_values = FALSE;
+    impl->fakeout->is_tracked_memory = TRUE;
+    impl->fakeout->content_type = ETCHHASHTABLE_CONTENT_OBJECT;
+
+    faketdo->impl = (etch_object*) impl;
+
+    return faketdo;
+}
+
+#endif /* #if(0) */
+
+
+/* 
+ * load_testdata_string()
+ * load testdata map with some ETCH_STRING objects
+ */
+static int load_testdata_string()   
+{
+    int i = 0, numitems = 4, result = 0;
+    etch_field* newkey  = NULL;
+    etch_string* newobj = NULL;
+    wchar_t* str0 = L"now ", *str1 = L"is  ", *str2 = L"the ", *str3 = L"time";
+    wchar_t* strings[4] = { str0, str1, str2, str3 };
+
+    for(; i < numitems; i++)
+    {
+        newkey  = new_field(strings[i]);      /* testdata map CAN free keys */
+        newobj  = new_stringw(strings[i]);
+        result  = ((struct i_hashtable*)((etch_object*)testdata)->vtab)->inserth(testdata->realtable, newkey, newobj, 0, 0);
+    }
+
+    return numitems;
+}
+
+
+/* 
+ * load_testdata_int()
+ * load testdata array with some ETCH_INT objects
+ */
+static int load_testdata_int()   
+{
+    const int numitems = 4;
+    int i = 0, result = 0;
+    etch_field* newkey = NULL;
+    etch_int32* newobj = NULL;
+    wchar_t* str0 = L"fld1", *str1 = L"fld2", *str2 = L"fld3", *str3 = L"fld4";
+    wchar_t* keys[4] = { str0, str1, str2, str3 };
+    int ints[4] = { 1, 2, 3, 4 };
+
+    for(; i < numitems; i++)
+    {
+        newkey = new_field(keys[i]);
+        newobj = new_int32(ints[i]);  /* testdata table can free both keys and values */
+        result = ((struct i_hashtable*)((etch_object*)testdata)->vtab)->inserth(testdata->realtable, newkey, newobj, 0, 0);
+    }
+
+    return numitems;
+}
+
+
+/* 
+ * testdata_clear_handler()
+ * memory callback on testdata clear
+ */
+static int testdata_clear_handler (void* keyData, void* valueData)  
+{
+    etch_object_destroy((etch_object*)keyData);
+    etch_object_destroy((etch_object*)valueData);
+    return TRUE;
+}
+
+
+/* 
+ * new_testdata()
+ * create testdata map and load it up with data objects
+ */
+static int new_testdata(const int datatype)   
+{
+    int count = 0;
+    #if IS_DEBUG_CONSOLE
+    etch_iterator iterator;
+    #endif
+    g_which_exception_test = 0;
+    testdata = new_hashtable(0); 
+    testdata->is_readonly_keys   = FALSE;
+    testdata->is_readonly_values = FALSE; 
+    testdata->is_tracked_memory  = TRUE;
+    testdata->content_type = ETCHHASHTABLE_CONTENT_OBJECT;
+    testdata->freehook = testdata_clear_handler;
+ 
+    switch(datatype)
+    { case 1: count = load_testdata_int();    break;
+      case 2: count = load_testdata_string(); break;
+      default: return -1;
+    }
+
+    #if IS_DEBUG_CONSOLE
+    printf("\n");
+    #pragma warning (disable:4313)
+    set_iterator(&iterator, testdata, &testdata->iterable);
+
+    while(iterator.vtab->has_next(&iterator))
+    {
+        printf("testdata %08x %08x\n", iterator.current_key, iterator.current_value);
+        iterator.vtab->next(&iterator);
+    }
+    printf("\n");
+    #endif
+
+    mt1 = new_type(L"one"); 
+    mt2 = new_type(L"two");
+
+    mf_bool_d0_1  = new_field(L"f1");
+    mf_bool_d0_2  = new_field(L"f2");
+    mf_bool_d1_1  = new_field(L"f3");
+    mf_bool_d1_2  = new_field(L"f4");
+
+    mf_int32_d0_1 = new_field(L"f5");
+    mf_int32_d0_2 = new_field(L"f6");
+    mf_int32_d1_1 = new_field(L"f7");
+    mf_int32_d1_2 = new_field(L"f8");
+
+    mf_str_d0_1   = new_field(L"f9");
+    mf_str_d0_2   = new_field(L"fa");
+    mf_str_d1_1   = new_field(L"fb");
+    mf_str_d1_2   = new_field(L"fc");
+
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_bool_d0_1), (etch_object*) etchvtor_boolean_get(0));
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_bool_d0_2), (etch_object*) etchvtor_boolean_get(0));
+
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_bool_d1_1), (etch_object*) etchvtor_boolean_get(1));
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_bool_d1_2), (etch_object*) etchvtor_boolean_get(1));
+
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_int32_d0_1), (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_int32_d0_2), (etch_object*) etchvtor_int32_get(0));
+
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_int32_d1_1), (etch_object*) etchvtor_int32_get(1));
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_int32_d1_2), (etch_object*) etchvtor_int32_get(1));
+
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_str_d0_1), (etch_object*) etchvtor_string_get(0));
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_str_d0_2), (etch_object*) etchvtor_string_get(0));
+
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_str_d1_1), (etch_object*) etchvtor_string_get(1));
+    etchtype_put_validator(mt1, (etch_field*)etch_object_clone_func(mf_str_d1_2), (etch_object*) etchvtor_string_get(1));
+ 
+    return count;
+}
+
+/* 
+ * destroy_testdata()
+ * destroy testdata map and content
+ */
+static void destroy_testdata()  
+{
+    destroy_hashtable(testdata, TRUE, TRUE);
+
+    etch_object_destroy(mt1);  
+    etch_object_destroy(mt2);  
+
+    destroy_field(mf_bool_d0_1);
+    destroy_field(mf_bool_d0_2);
+    destroy_field(mf_bool_d1_1);
+    destroy_field(mf_bool_d1_2);
+    destroy_field(mf_int32_d0_1);
+    destroy_field(mf_int32_d0_2);
+    destroy_field(mf_int32_d1_1);
+    destroy_field(mf_int32_d1_2);
+    destroy_field(mf_str_d0_1);
+    destroy_field(mf_str_d0_2);
+    destroy_field(mf_str_d1_1);
+    destroy_field(mf_str_d1_2);
+
+    etchvtor_clear_cache(); /* free all cached validators */
+}
+
+#if 0
+
+/* 
+ * compare_lists()
+ * compares testdata content with specified struct content.
+ * returns boolean indicating equal or not.
+ */
+static int compare_lists(etch_structvalue* svx)  
+{
+    int thiscount = 0, testcount = 0, result = 0;
+    etch_iterator  iterator;
+  	etch_hashitem  hashbucket;
+    etch_hashitem* sventry = &hashbucket;
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(svx);  
+    CU_ASSERT_PTR_NOT_NULL_FATAL(svx->items);
+
+    thiscount = ((struct i_hashtable*)((etch_object*)svx->items)->vtab)->count(svx->items->realtable,0,0); 
+    testcount = ((struct i_hashtable*)((etch_object*)testdata)->vtab)->count(testdata->realtable,0,0); 
+    CU_ASSERT_EQUAL(testcount, thiscount);
+    if (testcount != thiscount) return FALSE;
+
+    set_iterator(&iterator, testdata, &testdata->iterable);
+
+    while(iterator.has_next(&iterator) && result == 0)
+    {
+        result = ((struct i_hashtable*)((etch_object*)svx->items)->vtab)->findh
+	  (svx->items->realtable, ((etch_object*)iterator.current_key)->hashkey, testdata, (void**)&sventry);
+
+        CU_ASSERT_EQUAL(iterator.current_value, sventry->value);
+
+        iterator.next(&iterator);
+    }
+
+    return TRUE;
+}
+
+
+/* 
+ * hashtable_clear_handler()
+ * override callback from hashtable during clear()
+ */
+static int hashtable_clear_handler (void* key, void* value)  
+{
+    /* prior to calling clear() on any hashtable htab, set: 
+     *    htab.callback = hashtable_clear_handler; 
+     * and the hashtable will call back here for each item in the table,
+     * replacing any such handler installed. return FALSE to have the hashtable 
+     * proceed as it would with a handler. save off the existing handler and call 
+     * it, to proceed as if you had not replaced the handler. return TRUE to  
+     * indicate you handled the free and the hashtable should not attempt to free 
+     * memory for key and/or value, if in fact it would have done so otherwise. 
+     * note that structvalue always sets such a callback on its backing store
+     * in order to free key and value allocations.
+     */
+    return FALSE;
+}
+
+/* 
+ * hashtable_do_nada_handler()
+ * override callback from hashtable during clear()
+ * this callback does nothing and returns TRUE, so no content memory is freed.
+ */
+static int hashtable_do_nada_handler (void* key, void* value)  
+{
+    return TRUE;
+}
+#endif
+
+/* 
+ * run_iterator_test
+ * test struct value iterator
+ */
+static void run_iterator_test(void)
+{
+    int result = 0, count = 0;
+    etch_iterator iterator;
+    etch_int32* int_obj_1 = NULL;
+    etch_int32* int_obj_2 = NULL;
+    etch_nativearray* int_array_1 = NULL;
+    etch_nativearray* int_array_2 = NULL;
+    etch_structvalue* sv = NULL;
+    etch_field* fldkey   = NULL;
+
+    new_testdata(1); /* instantiate types and fields we use here */
+
+    /* memory for field keys and object values is given to the struct to manage. 
+     * once a key and value are "put" to the struct, we give up responsibility
+     * for freeing them. therefore when we put an object to the struct, we clone 
+     * a type to use as the key. note that when we assign the struct a type, 
+     * however, we do not relinquish ownership of the memory for that etch_type.
+     * this is because types are global to the service in the binding, 
+     * and are freed only at service shutdown.
+     */
+ 
+    int_obj_1 = new_int32(123);  
+    int_obj_2 = new_int32(234);  
+
+    int_array_1 = new_etch_nativearray(CLASSID_ARRAY_INT32, sizeof(int), 1, 3, 0, 0);
+    int_array_2 = new_etch_nativearray(CLASSID_ARRAY_INT32, sizeof(int), 1, 5, 0, 0);
+
+    sv = new_structvalue(mt1, 0);   
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv); 
+    result = is_etch_exception(sv);
+    CU_ASSERT_EQUAL(result, FALSE); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv->items);
+
+    /* if structvalue has ETCH_STRUCTVAL_VALIDATE_ON_PUT compiled,
+     * these structvalue.put()s will be validated. */     
+
+    fldkey = clone_field(mf_int32_d0_1);
+    result = structvalue_put(sv, fldkey, (etch_object*) int_obj_1);
+    CU_ASSERT_EQUAL(result, 0);
+
+    set_iterator(&iterator, sv->items, &sv->items->iterable);
+    CU_ASSERT_EQUAL(iterator.has_next(&iterator), TRUE);
+
+    fldkey = clone_field(mf_int32_d0_2); 
+    result = structvalue_put(sv, fldkey, (etch_object*) int_obj_2);
+    CU_ASSERT_EQUAL(result, 0);
+
+    set_iterator(&iterator, sv->items, &sv->items->iterable);
+    CU_ASSERT_TRUE(iterator.has_next(&iterator));
+
+    iterator.next(&iterator);
+    CU_ASSERT_TRUE(iterator.has_next(&iterator));
+
+    iterator.next(&iterator);
+    CU_ASSERT_FALSE(iterator.has_next(&iterator));
+
+    fldkey = clone_field(mf_int32_d1_1); 
+    result = structvalue_put(sv, fldkey, (etch_object*) int_array_1);
+    CU_ASSERT_EQUAL(result, 0);
+
+    fldkey = clone_field(mf_int32_d1_2); 
+    result = structvalue_put(sv, fldkey, (etch_object*) int_array_2);
+    CU_ASSERT_EQUAL(result, 0);
+
+    set_iterator(&iterator, sv->items, &sv->items->iterable);
+
+    while(iterator.has_next(&iterator))
+    { count++;
+      iterator.next(&iterator);
+    }
+    CU_ASSERT_EQUAL(count,4);
+
+
+    /* free memory for struct and its instance data and content */
+    etch_object_destroy(sv); 
+    destroy_testdata();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * run_exception_test
+ *  
+ */
+static void run_exception_test(const int whichtest)
+{
+    etch_type* static_type = NULL;
+    static_type = new_type(L"type1");
+
+    #if(0)
+
+    /* create a bogus TDI inheriting from tagged data input */
+    tdi = new_fake_tdi(static_type);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tdi);
+
+    switch(whichtest)
+    {   case EXCPTEST_UNCHECKED_STATICTEXT:
+        case EXCPTEST_CHECKED_COPYTEXT:
+        case EXCPTEST_CHECKED_STATICTEXT:
+        {   CU_ASSERT_TRUE_FATAL(is_exception(tdi));
+            #if IS_DEBUG_CONSOLE 
+            wprintf(L"\ncaught %s exception on tdi\n", tdiobj->result->exception->excptext);          
+            #endif   
+        }
+    }
+
+    sv = structvalue_read(NULL); /* pass NULL for TDI */
+    CU_ASSERT_PTR_NOT_NULL_FATAL(sv);
+    CU_ASSERT_TRUE(is_exception(tdi));
+    excp = get_exception(sv);
+    CU_ASSERT_EQUAL(excp->excptype, EXCPTYPE_ILLEGALARG);
+    #if IS_DEBUG_CONSOLE 
+    wprintf(L"\ncaught %s exception on sv\n", svobj->result->exception->excptext);          
+    #endif   
+
+    /* free TDI */
+    faketdi_close(tdi);
+
+    /* free struct, it is just a shell with no content other than the exception */
+    etch_object_destroy(sv);
+
+    #endif
+
+    /* destroy the type allocated above.
+     * in most tests we would NOT do this since the struct would own it after we
+     * created the struct. however we passed a null tdi parameter above to the 
+     * method which would have created the struct. the type which would have
+     * been assigned to the struct was in the tdi that we did not pass. The tdi
+     * will not destroy its type. however note that in the real world this 
+     * situation would not occur. all types would be global, and we will always
+     * create a copy of the type for the struct. see faketdi_start_struct() for
+     * an example, note that it clones the type for the new struct.  
+     */
+    etch_object_destroy(static_type);
+
+    /* destroy testdata list and content */
+    destroy_testdata();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_iterator_over_hashtable
+ */
+static void test_iterator_over_hashtable(void)
+{
+    etch_iterator* iterator = NULL; 
+    int testcount = 0, thiscount = 0;
+    struct i_iterable* vtab = NULL;
+    new_testdata(1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(testdata);
+    testcount = ((struct i_hashtable*)((etch_object*)testdata)->vtab)->count(testdata->realtable, 0, 0);
+    CU_ASSERT_NOT_EQUAL(testcount, 0);
+
+    iterator = new_iterator(testdata, &testdata->iterable);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+    CU_ASSERT_EQUAL_FATAL(iterator->ordinal,1);
+    thiscount = 1;
+    vtab = (i_iterable*)((etch_object*)iterator)->vtab;
+    while(vtab->has_next(iterator))
+          thiscount += (vtab->next(iterator) == 0);  
+        
+    CU_ASSERT_EQUAL(testcount, thiscount);
+
+    destroy_iterator(iterator);
+    destroy_testdata();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+#if 0
+/* 
+ * exception_test_1
+ */
+static void exception_test_1(void)
+{
+    int itemcount = 0;
+    if ((itemcount = new_testdata(1)) > 0)
+        run_exception_test(EXCPTEST_UNCHECKED_STATICTEXT); 
+}
+#endif
+
+/* 
+ * exception_test_2
+ */
+static void exception_test_2(void)
+{
+    int itemcount = 0;
+    if ((itemcount = new_testdata(1)) > 0)
+        run_exception_test(EXCPTEST_CHECKED_COPYTEXT); 
+}
+
+#if 0
+
+/* 
+ * exception_test_3
+ */
+static void exception_test_3(void)
+{
+    int itemcount = 0;
+    if ((itemcount = new_testdata(1)) > 0)
+        run_exception_test(EXCPTEST_CHECKED_STATICTEXT); 
+}
+
+#endif
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_structvalue_suite()
+{    
+    CU_pSuite pSuite = CU_add_suite("suite_structvalue", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test iterator over hashtable", test_iterator_over_hashtable);
+    CU_add_test(pSuite, "test structvalue iterator", run_iterator_test);
+    CU_add_test(pSuite, "test sv exceptions", exception_test_2);
+
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/message/test_type.c b/binding-c/runtime/c/src/test/message/test_type.c
new file mode 100644
index 0000000..c52b020
--- /dev/null
+++ b/binding-c/runtime/c/src/test/message/test_type.c
@@ -0,0 +1,698 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_type.c 
+ * test etch_type
+ */
+
+#include "etch_runtime.h"
+#include "etch_type.h"
+#include "etch_validator.h"
+#include "etch_field.h"
+#include "etch_objecttypes.h"
+#include "etch_serializer.h"
+#include "etch_arraylist.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+#include "Basic.h"
+#include "Automated.h"
+#include <wchar.h>
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    //this_teardown();
+    etch_runtime_shutdown();
+    return 0;
+}
+
+int this_setup()
+{
+    return 0;
+}
+
+/*
+ * test_type
+ */
+static void test_type(void)
+{
+    int result = 0;
+    etch_type *type1 = NULL, *type2 = NULL;
+
+    const wchar_t* nametext1 = L"abracadabra";
+
+    const wchar_t* nametext2 = L"gilgamesh";
+    
+#ifdef ETCH_DEBUGALLOC
+    alloc_a = etch_showmem(0, FALSE);
+#endif
+    type1   = new_type(NULL);
+    CU_ASSERT_PTR_NULL(type1);
+
+#ifdef ETCH_DEBUGALLOC
+    alloc_b = etch_showmem(0, FALSE);
+    CU_ASSERT_EQUAL(alloc_a, alloc_b); 
+#endif
+
+    type1   = new_type(nametext1);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(type1);
+    CU_ASSERT_TRUE(is_good_type(type1));
+
+    type2   = new_type(nametext1);
+    CU_ASSERT_TRUE(is_equal_types(type1, type2));
+    result = memcmp(type1->name, type2->name, type1->namebytelen);
+    CU_ASSERT_EQUAL(result,0);
+
+    etch_object_destroy(type1);
+    etch_object_destroy(type2);
+
+#ifdef ETCH_DEBUGALLOC
+    alloc_a = etch_showmem(0, FALSE);
+    CU_ASSERT_EQUAL(alloc_a, alloc_b); 
+#endif
+
+    type1 = new_type(nametext1);
+    type2 = new_type(nametext2);
+
+    CU_ASSERT_FALSE(is_equal_types(type1, type2));
+
+    etch_object_destroy(type1);
+    etch_object_destroy(type2);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_type_hashfunc
+ * test wire hashing function
+ */
+static void test_type_hashfunc(void)
+{
+    unsigned hash1 = 0, hash2 = 0;
+    etch_type *type1 = NULL, *type2 = NULL;
+
+    const wchar_t* nametext1 = L"abracadabra";
+    const size_t   numelts1  = wcslen(nametext1);
+    const size_t   numbytes1 = sizeof(wchar_t) * ( numelts1 + 1 );
+
+    const wchar_t* nametext2 = L"gilgamesh";
+    const size_t   numelts2  = wcslen(nametext2);
+    const size_t   numbytes2 = sizeof(wchar_t) * ( numelts2 + 1 );
+ 
+    hash1 = compute_type_id_from_widename(nametext1);
+    hash2 = compute_type_id_from_widename(nametext2);
+
+    CU_ASSERT_NOT_EQUAL(hash1, hash2);
+
+    type1 = new_type(nametext1);
+    type2 = new_type(nametext2);
+    CU_ASSERT_EQUAL(type1->namebytelen, numbytes1);
+    CU_ASSERT_EQUAL(type2->namebytelen, numbytes2);
+    CU_ASSERT_EQUAL(type1->id, hash1);
+    CU_ASSERT_EQUAL(type2->id, hash2);
+
+    etch_object_destroy(type1);
+    etch_object_destroy(type2);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * function pointers used by test_getset()
+ */
+static int bogus_stubhelper (void* stub, void* delsvc, void* obj, void* whofrom, void* msg) { return 0; }
+
+
+
+/**
+ * test_getset
+ * test mutators
+ */
+static void test_getset(void)
+{
+    unsigned int this_class  = 0, old_class = 0;
+    unsigned char   cur_flag = 0, old_flag = 0;
+    unsigned int cur_timeout = 0, old_timeout = 0;
+    opaque_stubhelper cur_helper = NULL, old_helper = NULL;
+    etch_serializer *cur_impexphelper, *old_impexphelper;
+    etch_type *type1 = new_type(L"abracadabra");
+    etch_type *type2 = new_type(L"gilgamesh"), *cur_type = NULL, *old_type  = NULL;
+    etch_field *fld1 = new_field(L"field1"),  *cur_field = NULL, *old_field = NULL;
+    etch_serializer* impxhelp1 = (etch_serializer*) new_object(sizeof(etch_object), ETCHTYPEB_ETCHOBJECT, CLASSID_NONE);
+    const unsigned int TEST_CLASS = (ETCHTYPEB_PRIMITIVE << 16) | CLASSID_PRIMITIVE_INT32;
+
+    /* component type */
+    this_class = etchtype_get_component_type(type1);
+    CU_ASSERT_EQUAL(this_class, 0);
+
+    old_class = etchtype_set_component_type(type1, TEST_CLASS);
+    CU_ASSERT_EQUAL(old_class, 0);
+
+    this_class = etchtype_get_component_type(type1);
+    CU_ASSERT_EQUAL(this_class, TEST_CLASS);
+
+    old_class = etchtype_set_component_type(type1, 0);
+    CU_ASSERT_EQUAL(old_class, TEST_CLASS);
+
+    /* timeout */
+    cur_timeout = etchtype_get_timeout(type1);
+    CU_ASSERT_EQUAL(cur_timeout, 0);
+
+    old_timeout = etchtype_set_timeout(type1, 1000);
+    CU_ASSERT_EQUAL(old_timeout, 0);
+
+    cur_timeout = etchtype_get_timeout(type1);
+    CU_ASSERT_EQUAL(cur_timeout, 1000);
+
+    old_timeout = etchtype_set_timeout(type1, 0);
+    CU_ASSERT_EQUAL(old_timeout, 1000);
+
+    /* result type */
+    cur_type = etchtype_get_result_type(type1);
+    CU_ASSERT_PTR_EQUAL(cur_type, NULL);
+
+    old_type = etchtype_set_result_type(type1, type2);
+    CU_ASSERT_PTR_EQUAL(old_type, NULL);
+
+    cur_type = etchtype_get_result_type(type1);
+    CU_ASSERT_PTR_EQUAL(cur_type, type2);
+
+    old_type = etchtype_set_result_type(type1, NULL);
+    CU_ASSERT_PTR_EQUAL(old_type, type2);
+
+    /* super type */
+    cur_type = etchtype_get_super_type(type1);
+    CU_ASSERT_PTR_EQUAL(cur_type, NULL);
+
+    old_type = etchtype_set_super_type(type1, type2);
+    CU_ASSERT_PTR_EQUAL(old_type, NULL);
+
+    cur_type = etchtype_get_super_type(type1);
+    CU_ASSERT_PTR_EQUAL(cur_type, type2);
+
+    old_type = etchtype_set_super_type(type1, NULL);
+    CU_ASSERT_PTR_EQUAL(old_type, type2);
+
+    /* response field */
+    cur_field = etchtype_get_response_field(type1);
+    CU_ASSERT_PTR_EQUAL(cur_field, NULL);
+
+    old_field = etchtype_set_response_field(type1, type2);
+    CU_ASSERT_PTR_EQUAL(old_field, NULL);
+
+    cur_field = etchtype_get_response_field(type1);
+    CU_ASSERT_PTR_EQUAL(cur_field, type2);
+
+    old_field = etchtype_set_response_field(type1, NULL);
+    CU_ASSERT_PTR_EQUAL(old_field, type2);
+
+    /* run validators */
+    cur_flag = etchtype_get_run_validators(type1);
+    CU_ASSERT_EQUAL(cur_flag, FALSE);
+
+    old_flag = etchtype_set_run_validators(type1, TRUE);
+    CU_ASSERT_EQUAL(old_flag, FALSE);
+
+    cur_flag = etchtype_get_run_validators(type1);
+    CU_ASSERT_EQUAL(cur_flag, TRUE);
+
+    old_flag = etchtype_set_run_validators(type1,FALSE);
+    CU_ASSERT_EQUAL(old_flag, TRUE);
+
+    /* stub helper */
+    cur_helper = etchtype_get_type_stubhelper(type1);
+    CU_ASSERT_PTR_EQUAL(cur_helper, NULL);
+
+    old_helper = etchtype_set_type_stubhelper(type1, bogus_stubhelper);
+    CU_ASSERT_PTR_EQUAL(old_helper, NULL);
+
+    old_helper = etchtype_get_type_stubhelper(type1);
+    CU_ASSERT_PTR_EQUAL(old_helper, bogus_stubhelper);
+
+    old_helper = etchtype_set_type_stubhelper(type1, NULL);
+    CU_ASSERT_PTR_EQUAL(old_helper, bogus_stubhelper);
+
+    /* import/export helper */      
+    cur_impexphelper = etchtype_get_impexphelper(type1);
+    CU_ASSERT_PTR_EQUAL(cur_impexphelper, NULL);
+
+    old_impexphelper = etchtype_set_impexphelper(type1, impxhelp1);
+    CU_ASSERT_PTR_EQUAL(old_impexphelper, NULL);
+
+    cur_impexphelper = etchtype_get_impexphelper(type1);
+    CU_ASSERT_PTR_EQUAL(cur_impexphelper, impxhelp1);
+
+    old_impexphelper = etchtype_set_impexphelper(type1, NULL);
+    CU_ASSERT_PTR_EQUAL(old_impexphelper, impxhelp1);
+
+
+    etch_object_destroy(fld1);
+    etch_object_destroy(type2);
+    etch_object_destroy(type1);
+    etch_object_destroy(impxhelp1);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_assignable()
+ * test is_assignable_from()
+ */
+static void test_assignable(void)
+{
+    int result = 0;
+    const unsigned short TEST_SUPERCLASS_ID = 0xffff;
+    etch_type* type1 = new_type(L"type1");
+    etch_type* type2 = new_type(L"type2");
+    ((etch_object*)type1)->class_id  = TEST_SUPERCLASS_ID;
+    etchtype_set_super_type(type2, type1);
+
+    result = etchtype_is_assignable_from(type1, type2);
+    CU_ASSERT_EQUAL(result, TRUE); 
+
+    result = etchtype_is_assignable_from(type2, type1);
+    CU_ASSERT_EQUAL(result, FALSE); 
+
+    result = etchtype_is_assignable_from(type2, NULL);
+    CU_ASSERT_EQUAL(result, FALSE); 
+
+    result = etchtype_is_assignable_from(NULL, type1);
+    CU_ASSERT_EQUAL(result, FALSE); 
+
+    etch_object_destroy(type1);
+    etch_object_destroy(type2);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_validators_access
+ * test put and get validators
+ */
+static void test_validators_access(void)
+{
+    etch_iterator iterator;
+    etch_field* vtor1_key = new_field(L"vtor1");
+    etch_field* vtor2_key = new_field(L"vtor2");
+    etch_field* bogus_key = new_field(L"bogus");
+    etch_type *type1 = new_type(L"abracadabra");
+    etch_type *typev = new_type(L"struct"); /* struct validator type */
+    etch_validator* vtor1 = etchvtor_int32_get(0);
+    etch_validator* vtor2 = etchvtor_struct_get(typev, 0);
+    etch_validator* vtor_return = NULL;
+
+    int result = etchtype_put_validator(type1, (etch_field*)etch_object_clone_func(vtor1_key), (etch_object*) vtor1);
+    CU_ASSERT_EQUAL(result, 0);
+
+    vtor_return = (etch_validator*) etchtype_get_validator_by_name(type1, vtor1_key->name);
+    CU_ASSERT_PTR_NOT_NULL(vtor_return);   
+    CU_ASSERT_PTR_EQUAL(vtor_return, vtor1);
+
+    vtor_return = (etch_validator*) etchtype_get_validator_by_id(type1, vtor1_key->id);
+    CU_ASSERT_PTR_NOT_NULL(vtor_return);
+    CU_ASSERT_PTR_EQUAL(vtor_return, vtor1);
+
+    result = etchtype_put_validator(type1, (etch_field*)etch_object_clone_func(vtor2_key), (etch_object*) vtor2);
+    CU_ASSERT_EQUAL(result, 0);
+
+    result = etchtype_validators_count(type1);
+    CU_ASSERT_EQUAL(result, 2);
+
+    vtor_return = (etch_validator*) etchtype_get_validator_by_name(type1, vtor1_key->name);
+    CU_ASSERT_PTR_NOT_NULL(vtor_return);
+    CU_ASSERT_PTR_EQUAL(vtor_return, vtor1);
+
+    vtor_return = (etch_validator*) etchtype_get_validator_by_id(type1, vtor1_key->id);
+    CU_ASSERT_PTR_NOT_NULL(vtor_return);
+    CU_ASSERT_PTR_EQUAL(vtor_return, vtor1);
+
+    vtor_return = (etch_validator*) etchtype_get_validator_by_name(type1, vtor2_key->name);
+    CU_ASSERT_PTR_NOT_NULL(vtor_return);
+    CU_ASSERT_PTR_EQUAL(vtor_return, vtor2);
+
+    vtor_return = (etch_validator*) etchtype_get_validator_by_id(type1, vtor2_key->id);
+    CU_ASSERT_PTR_NOT_NULL(vtor_return);
+    CU_ASSERT_PTR_EQUAL(vtor_return, vtor2);
+
+    /* iterate over the validators map */
+    result = etchtype_set_validators_iterator(type1, &iterator);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    while(iterator.has_next(&iterator))
+    {   
+        const etch_validator* this_vtor = (etch_validator*) iterator.current_value;
+
+        if  (this_vtor == vtor1)
+             result = TRUE;
+        else
+        if  (this_vtor == vtor2)
+             result = TRUE; 
+        else result = FALSE;  
+             
+        CU_ASSERT_EQUAL_FATAL(result, TRUE);
+
+        iterator.next(&iterator);
+    }
+
+    /* etchtype_clear_validators() is superfluous here, destruction of the type
+     * has the same result, however we may as well test it */
+    result = etchtype_clear_validators(type1);
+    CU_ASSERT_EQUAL(result, 2); /* result of clear is cleared count */
+
+    result = etchtype_validators_count(type1);
+    CU_ASSERT_EQUAL(result, 0);
+
+    /* etchtype_put_validator() was given clones of these fields as validator 
+     * keys, which were freed during etchtype_clear_validators. this is the model
+     * to use in the binding, i.e. clone a static etch_field for put_validator().
+     */
+    etch_object_destroy(vtor1_key);
+    etch_object_destroy(vtor2_key);
+    etch_object_destroy(bogus_key);
+
+    /* vtor1 will not have been freed during etchtype_clear_validators(), 
+     * since it is a cached validator. likewise, calling its destructor  
+     * would have no effect, etchtype_clear_validators() has already tried.
+     * etchvtor_clear_cache() will free it and any other cached validators.
+     * vtor2 will however have been freed during etchtype_clear_validators(),  
+     * since a struct validator is not one of the cached validator types. 
+     * in any case, we don't need to be concerned here about which validators
+     * are cached and which are not, since etchtype_clear_validators() will
+     * free the uncached ones, and etchvtor_clear_cache() the cached ones.
+     */ 
+    etch_object_destroy(typev);
+    etch_object_destroy(type1);
+    etchvtor_clear_cache(); /* destroy cached validators (vtor1 in this case) */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_fields_access
+ */
+static void test_fields_access(void)
+{
+    etch_iterator iterator;
+    etch_field* field1 = new_field(L"field1");
+    etch_field* field2 = new_field(L"field2");
+    etch_field* field3 = new_field(L"field3");
+    etch_field* fieldx = new_field(L"fieldx");
+    etch_field* field_return = NULL;
+    etch_field* field_clone  = NULL;
+    etch_arraylist* list_return = NULL;
+    etch_type *type1 = new_type(L"abracadabra");
+    const int EXPECTED_FIELDS_COUNT = 3;
+    int result = 0, newfield_id = 0;
+
+    field_clone = (etch_field*)etch_object_clone_func(field1);
+    field_return = etchtype_add_field(type1, field_clone);
+    CU_ASSERT_PTR_NOT_NULL(field_return);
+    CU_ASSERT_PTR_EQUAL(field_return, field_clone);
+
+    /* ensure that trying to add a duplicate field returns the existing field.
+     * note that the new clone is destroyed by etchtype_add_field when it 
+     * determines that the supplied field can't be added */
+    field_return = etchtype_add_field(type1, (etch_field*)etch_object_clone_func(field1));
+    CU_ASSERT_PTR_NOT_NULL(field_return);
+    CU_ASSERT_PTR_EQUAL(field_return, field_clone);
+
+    /* add a couple more fields */
+    field_clone = (etch_field*)etch_object_clone_func(field2);
+    field_return = etchtype_add_field(type1, field_clone);
+    CU_ASSERT_PTR_NOT_NULL(field_return);
+    CU_ASSERT_PTR_EQUAL(field_return, field_clone);
+
+    field_clone = (etch_field*)etch_object_clone_func(field3);
+    field_return = etchtype_add_field(type1, field_clone);
+    CU_ASSERT_PTR_NOT_NULL(field_return);
+    CU_ASSERT_PTR_EQUAL(field_return, field_clone);
+
+    result = etchtype_fields_count(type1);
+    CU_ASSERT_EQUAL(result, EXPECTED_FIELDS_COUNT);
+
+    /* test accessors */
+    field_return = etchtype_get_field_by_name(type1, field1->name);
+    CU_ASSERT_PTR_NOT_NULL(field_return);
+    CU_ASSERT_EQUAL(is_equal_fields(field_return, field1), TRUE);
+
+    field_return = etchtype_get_field_by_id(type1, field1->id);
+    CU_ASSERT_PTR_NOT_NULL(field_return);
+    CU_ASSERT_EQUAL(is_equal_fields(field_return, field1), TRUE);
+
+    field_return = etchtype_get_field_by_name(type1, field2->name);
+    CU_ASSERT_PTR_NOT_NULL(field_return);
+    CU_ASSERT_EQUAL(is_equal_fields(field_return, field2), TRUE);
+
+    field_return = etchtype_get_field_by_id(type1, field2->id);
+    CU_ASSERT_PTR_NOT_NULL(field_return);
+    CU_ASSERT_EQUAL(is_equal_fields(field_return, field2), TRUE);
+
+    field_return = etchtype_get_field_by_name(type1, field3->name);
+    CU_ASSERT_PTR_NOT_NULL(field_return);
+    CU_ASSERT_EQUAL(is_equal_fields(field_return, field3), TRUE);
+
+    field_return = etchtype_get_field_by_id(type1, field3->id);
+    CU_ASSERT_PTR_NOT_NULL(field_return);
+    CU_ASSERT_EQUAL(is_equal_fields(field_return, field3), TRUE);
+
+    /* test that a "get" of an unrecognized field name, adds a new field
+     * with that name. this is consistent with the java binding */
+    field_return = etchtype_get_field_by_name(type1, fieldx->name);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(field_return);  
+    result = etchtype_fields_count(type1);
+    CU_ASSERT_EQUAL(result, EXPECTED_FIELDS_COUNT+1);
+    newfield_id = field_return->id;
+
+    /* iterate over the type's fieldmap */
+    result = etchtype_set_fields_iterator(type1, &iterator);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    while(iterator.has_next(&iterator))
+    {   
+        const unsigned this_id = ((etch_field*)iterator.current_key)->id;
+
+        if  (this_id == field1->id)
+             result = TRUE;
+        else
+        if  (this_id == field2->id)
+             result = TRUE; 
+        else
+        if  (this_id == field3->id)
+             result = TRUE; 
+        else
+        if  (this_id == newfield_id)
+             result = TRUE; 
+        else result = FALSE; 
+              
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        iterator.next(&iterator);
+    }
+
+    /* get a list of all the type's fields. 
+     * we own the returned list, which does not own its content */
+    list_return = (etch_arraylist*) etchtype_get_fields(type1);
+
+    CU_ASSERT_EQUAL_FATAL(is_etch_arraylist(list_return), TRUE);
+    CU_ASSERT_EQUAL(list_return->count, EXPECTED_FIELDS_COUNT+1);
+
+    /* iterate over the list of fields */
+    set_iterator(&iterator, list_return, &list_return->iterable);
+
+    while(iterator.has_next(&iterator))
+    {   
+        const unsigned this_id = ((etch_field*)iterator.current_value)->id;
+
+        if  (this_id == field1->id)
+             result = TRUE;
+        else
+        if  (this_id == field2->id)
+             result = TRUE; 
+        else
+        if  (this_id == field3->id)
+             result = TRUE; 
+        else
+        if  (this_id == newfield_id)
+             result = TRUE; 
+        else result = FALSE;  
+          
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        iterator.next(&iterator);
+    }
+
+    etch_object_destroy(list_return);
+    etch_object_destroy(field1);
+    etch_object_destroy(field2);
+    etch_object_destroy(field3);
+    etch_object_destroy(fieldx);
+    etch_object_destroy(type1);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_validators_chained
+ * test memory mangement of chained validators
+ */
+static void test_validators_chained(void)
+{
+    etch_field* vtor1_key = new_field(L"vtor1");
+    etch_field* vtor2_key = new_field(L"vtor2");
+    etch_type *structtype = new_type(L"struct"); /* struct validator type */
+    etch_validator* vtor1 = etchvtor_int32_get(0);
+    etch_validator* vtor2 = etchvtor_int16_get(0);
+    etch_validator* vtor3 = etchvtor_byte_get(0);
+    etch_validator* vtor4 = etchvtor_int32_get(0);
+    etch_validator* vtor5 = etchvtor_struct_get(structtype, 0);
+    etch_validator* vtor6 = etchvtor_struct_get(structtype, 0);
+    etch_validator* vtor7 = etchvtor_struct_get(structtype, 0);
+    etch_validator* vtor8 = etchvtor_string_get(0);
+    etch_type *type1 = new_type(L"abracadabra");
+
+    /* test 3 validators with the same key. when a validator is put to a type
+     * and the type already has one or more validators with the specified key, 
+     * the new validator is chained to the existing validator */
+    int result = etchtype_put_validator(type1, (etch_field*)etch_object_clone_func(vtor1_key), (etch_object*) vtor1);
+    CU_ASSERT_EQUAL(result, 0);
+
+    result = etchtype_put_validator(type1, (etch_field*)etch_object_clone_func(vtor1_key), (etch_object*) vtor2);
+
+    result = etchtype_put_validator(type1, (etch_field*)etch_object_clone_func(vtor1_key), (etch_object*) vtor3);
+
+    /* etchtype_clear_validators is needed here, since we want to begin 
+     * a new test with the type emptied of validators.
+     */
+    etchtype_clear_validators(type1); 
+
+     /* test 3 validators with the same key, and 2 validators with another key.
+      * note that the c binding convention is to always get a "fresh" validator 
+      * when we add a validator to a type, even though the get will return the 
+      * same object when the validator type we get is cached. */
+
+     result = etchtype_put_validator(type1, (etch_field*)etch_object_clone_func(vtor1_key), (etch_object*) vtor4);
+     result = etchtype_put_validator(type1, (etch_field*)etch_object_clone_func(vtor1_key), (etch_object*) vtor5);
+     result = etchtype_put_validator(type1, (etch_field*)etch_object_clone_func(vtor1_key), (etch_object*) vtor6);
+
+     result = etchtype_put_validator(type1, (etch_field*)etch_object_clone_func(vtor2_key), (etch_object*) vtor7);
+     result = etchtype_put_validator(type1, (etch_field*)etch_object_clone_func(vtor2_key), (etch_object*) vtor8);
+
+    /* etchtype_clear_validators is superfluous here, so we test not doing it. 
+     * when we destroy type1 below, the destructor for the type's instance data 
+     * object destroys the type's hashtables, which causes the hashtables to 
+     * first clear their content, as etchtype_clear_validators() would do.
+     */
+    /* etchtype_clear_validators(type1); */
+
+    /* etchtype_put_validator() was given clones of these fields as validator 
+     * keys, which were freed during etchtype_clear_validators. this is the model
+     * to use in the binding, i.e. clone a static etch_field for put_validator().
+     */
+    etch_object_destroy(vtor1_key);
+    etch_object_destroy(vtor2_key);
+
+    etch_object_destroy(structtype); 
+
+    /* the destroy() of type1 clears the type's fields and validators maps,
+     * which causes the fields, validator field keys, and non-cached validators,
+     * to be destroyed.
+     */
+    etch_object_destroy(type1);
+    etchvtor_clear_cache(); /* destroy any singleton cached validators */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_type_suite()
+{    
+    CU_pSuite ps = CU_add_suite("type test suite", init_suite, clean_suite);
+
+    CU_add_test(ps, "test etch_type constructors/destructors", test_type);  
+    CU_add_test(ps, "test etch_type hashing", test_type_hashfunc); 
+    CU_add_test(ps, "test getters/setters", test_getset);  
+    CU_add_test(ps, "test assignability", test_assignable);  
+    CU_add_test(ps, "test validators access", test_validators_access);  
+    CU_add_test(ps, "test fields access", test_fields_access);  
+    CU_add_test(ps, "test chained validators", test_validators_chained);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/message/test_validator.c b/binding-c/runtime/c/src/test/message/test_validator.c
new file mode 100644
index 0000000..cc20df1
--- /dev/null
+++ b/binding-c/runtime/c/src/test/message/test_validator.c
@@ -0,0 +1,1515 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_validator.c
+ * test etch_validator
+ */
+#include "etch_runtime.h"
+#include "etch_validator.h"
+#include "etch_tagged_data.h"
+#include "etch_nativearray.h"
+#include "etch_structval.h"
+#include "etch_objecttypes.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+#include "Basic.h"
+#include "Automated.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+static etch_type*    testtype;
+static etch_boolean* objbool_false;
+static etch_boolean* objbool_true;
+static etch_byte*    objbyte_one;
+static etch_int16*   objshort_two;
+static etch_int32*   objint_three;
+static etch_int64*   objlong_four;
+static etch_float*   objfloat_five;
+static etch_double*  objdouble_six;
+static etch_string*  objstring_abc;
+static etch_object*  objobject_null;
+static etch_nativearray* arraydim1;
+static etch_nativearray* arraydim2;
+static etch_nativearray* arraydim3;
+
+
+static void create_testobjects()
+{
+    testtype = new_type(L"abc");
+    objbool_false  = new_boolean(FALSE);
+    objbool_true   = new_boolean(TRUE);
+    objbyte_one    = new_byte(1);
+    objshort_two   = new_int16(2);
+    objint_three   = new_int32(3);
+    objlong_four   = new_int64(4);
+    objfloat_five  = new_float(5.0);
+    objdouble_six  = new_double(6.0);
+    objstring_abc  = new_stringw(L"abc");
+    objobject_null = (etch_object*) new_primitive(sizeof(etch_object), CLASSID_NONE);
+    arraydim1  = new_etch_nativearray(CLASSID_ARRAY_BOOL, 1, 1, 4, 0, 0);
+    arraydim2  = new_etch_nativearray(CLASSID_ARRAY_BOOL, 1, 2, 4, 3, 0);
+    arraydim3  = new_etch_nativearray(CLASSID_ARRAY_BOOL, 1, 3, 4, 3, 2);
+}
+
+
+static void destroy_testobjects()
+{
+    etch_object_destroy(testtype); testtype = NULL;
+    etch_object_destroy(objbool_false); objbool_false = NULL;
+    etch_object_destroy(objbool_true);  objbool_true  = NULL;
+    etch_object_destroy(objbyte_one);   objbyte_one   = NULL;
+    etch_object_destroy(objshort_two);  objshort_two  = NULL;
+    etch_object_destroy(objint_three);  objint_three  = NULL;
+    etch_object_destroy(objlong_four);  objlong_four  = NULL;
+    etch_object_destroy(objfloat_five); objfloat_five = NULL;
+    etch_object_destroy(objdouble_six); objdouble_six = NULL;
+    etch_object_destroy(objstring_abc); objstring_abc = NULL;
+    etch_object_destroy(objobject_null);objobject_null= NULL;
+    etch_object_destroy(arraydim1);  arraydim1 = NULL;
+    etch_object_destroy(arraydim2);  arraydim2 = NULL;
+    etch_object_destroy(arraydim3);  arraydim3 = NULL;
+}
+
+
+/**
+ * do_boolean_test()
+ * common test template for the boolean validator tests
+ */
+static void do_boolean_test(int dims, char* name, byte in_typecode, 
+    unsigned short validated_class_id, etch_object* objgood, etch_object* objbad)
+{
+    int result = 0; 
+    byte out_typecode = 0;
+    etch_validator* vtor = etchvtor_boolean_get(dims);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(vtor);
+    CU_ASSERT_EQUAL(vtor->numdimensions, dims); 
+    CU_ASSERT_EQUAL(validated_class_id, vtor->expected_class_id); 
+    CU_ASSERT_STRING_EQUAL(name, vtor->description);
+
+    result = vtor->validate(vtor, objgood);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = vtor->validate(vtor, objbad);
+    CU_ASSERT_EQUAL(result,-1);
+    if (result != -1)
+        result = 1;
+
+    result = vtor->check_value(vtor, objgood, &out_typecode);
+    CU_ASSERT_EQUAL(result, 0);   
+    CU_ASSERT_EQUAL(in_typecode, out_typecode);   
+
+    result = vtor->check_value(vtor, objbad, &out_typecode);
+    CU_ASSERT_EQUAL(result, -1);  
+
+    CU_ASSERT_EQUAL(vtor->is_cached, TRUE);
+    etch_object_destroy(vtor); /* test that vtor is cached */
+    CU_ASSERT_EQUAL(result, -1);  /* and cannot be destroyed */ 
+}
+
+
+/**
+ * test_boolean_validator()
+ */
+static void test_boolean_validator(void)  
+{
+    char* strbool0 = "bool[0]"; 
+    create_testobjects();
+
+	do_boolean_test(0, "bool[0]", ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE, 
+        CLASSID_PRIMITIVE_BOOL, (etch_object*) objbool_false, (etch_object*) objbyte_one);
+
+	do_boolean_test(0, "bool[0]", ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE, 
+        CLASSID_PRIMITIVE_BOOL, (etch_object*) objbool_true, (etch_object*) objshort_two);
+
+	do_boolean_test(0, "bool[0]", ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE, 
+        CLASSID_PRIMITIVE_BOOL, (etch_object*) objbool_true, (etch_object*) objint_three);
+
+	do_boolean_test(0, strbool0, ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE, 
+        CLASSID_PRIMITIVE_BOOL, (etch_object*) objbool_true, (etch_object*) objlong_four);
+
+	do_boolean_test(0, strbool0, ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE, 
+        CLASSID_PRIMITIVE_BOOL, (etch_object*) objbool_true, (etch_object*) objfloat_five);
+
+	do_boolean_test(0, strbool0, ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE, 
+        CLASSID_PRIMITIVE_BOOL, (etch_object*) objbool_true, (etch_object*) objdouble_six);
+
+	do_boolean_test(0, strbool0, ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE, 
+        CLASSID_PRIMITIVE_BOOL, (etch_object*) objbool_true, (etch_object*) objstring_abc);
+
+	do_boolean_test(0, strbool0, ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE, 
+        CLASSID_PRIMITIVE_BOOL, (etch_object*) objbool_true, objobject_null);
+
+	do_boolean_test(1, "bool[1]", ETCH_XTRNL_TYPECODE_ARRAY,
+        CLASSID_ARRAY_BOOL, (etch_object*) arraydim1, (etch_object*) objbool_true);
+
+	do_boolean_test(2, "bool[2]", ETCH_XTRNL_TYPECODE_ARRAY,
+        CLASSID_ARRAY_BOOL, (etch_object*) arraydim2, (etch_object*) arraydim1);
+
+	do_boolean_test(3, "bool[3]", ETCH_XTRNL_TYPECODE_ARRAY,
+        CLASSID_ARRAY_BOOL, (etch_object*) arraydim3, (etch_object*) arraydim2);
+
+    destroy_testobjects(); 
+    etchvtor_clear_cache();  /* destroy cached validators */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * do_recursive_test()
+ * run a validate on an anonymous object. if the object is a nativearray, 
+ * this method is invoked recursively until the array elements are validated.
+ * the caller relinquishes ownership of valobj to this method.
+ */
+static void do_recursive_test(etch_validator* vtor, const int dims, byte* typecodes, etch_object* valobj)
+{
+    int  result = 0;
+    signed char expected_typecode = 0, validated_typecode = 0;
+    //++debug_count;
+    //if (debug_count == 0x28)
+    //    result = 0; // debugger target    
+
+    result = vtor->validate(vtor, (etch_object*) valobj);
+    CU_ASSERT_EQUAL(result, 0);
+
+    expected_typecode = typecodes[dims];
+    result = vtor->check_value(vtor, (etch_object*) valobj, (unsigned char*)&validated_typecode);
+    CU_ASSERT_EQUAL(result,0);
+    if  (expected_typecode == validated_typecode)
+         result = TRUE;  
+    else result = FALSE;  // debugger target 
+    CU_ASSERT_EQUAL(result, TRUE);
+
+    if  (dims)
+    {   /* if validating an array, iterate the array and recursively validate 
+         * each array element, which could itself be an array. todo -- this
+         * is coded for nativearray, we may need to generalize to arrayvalue
+         */
+        int itemcount = 0, i = 0;
+        etch_nativearray* a = NULL;
+        etch_validator* element_vtor = vtor->element_validator(vtor);
+        CU_ASSERT_EQUAL_FATAL(is_etch_nativearray(valobj), TRUE);
+
+        a = (etch_nativearray*) valobj; 
+        itemcount = (int) a->dimension[dims-1];
+
+        for(; i < (const int) itemcount; i++)
+        {
+            etch_object* subobj = etch_nativearray_get_element(a, i); 
+
+            CU_ASSERT_PTR_NOT_NULL_FATAL(subobj);
+             
+            do_recursive_test(element_vtor, dims-1, typecodes, subobj);
+
+        } 
+
+        etch_object_destroy(valobj);
+    }
+    
+}
+
+
+/*
+ * test_array_boolean()
+ * test validator on arrays of boolean using the recursive test
+ */
+static void test_array_boolean(void)  
+{
+    const int numdimensions = 2, dim0count = 3, dim1count = 2;
+    boolean x1[2][3] = { { FALSE,FALSE,FALSE,}, { FALSE,FALSE,FALSE,}, };
+    boolean x2[2][3] = { { TRUE, TRUE, TRUE, }, { TRUE, TRUE, TRUE, }, };
+    byte typecodz[3] = { ETCH_XTRNL_TYPECODE_BOOLEAN_FALSE, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+    etch_nativearray* a1 = NULL, *a2 = NULL;
+
+    /* test validate boolean array x1/a1 */
+    etch_validator* vtor = etchvtor_boolean_get(numdimensions);
+
+	
+    a1 = new_etch_nativearray_from(&x1, CLASSID_ARRAY_BOOL,  
+        sizeof(boolean), numdimensions, dim0count, dim1count, 0);  
+	a1->is_content_owned = FALSE;
+    /* fyi we relinquish ownership of array a1 here */
+    do_recursive_test(vtor, numdimensions, typecodz, (etch_object*) a1);
+
+    /* test validate boolean array x2/a2 */
+    typecodz[0] = ETCH_XTRNL_TYPECODE_BOOLEAN_TRUE; 
+    vtor = etchvtor_boolean_get(numdimensions); 
+
+    a2 = new_etch_nativearray_from(&x2, CLASSID_ARRAY_BOOL,  
+        sizeof(boolean), numdimensions, dim0count, dim1count, 0);  
+
+	a2->is_content_owned = FALSE;
+    /* fyi we relinquish ownership of array a2 here */
+    do_recursive_test(vtor, numdimensions, typecodz, (etch_object*) a2);
+
+    /* done */
+    etchvtor_clear_cache();  /* destroy cached validator */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * test_array_byte()
+ * test validator on arrays of byte using the recursive test
+ */
+static void test_array_byte(void)  
+{
+    const int numdimensions = 2, dim0count = 3, dim1count = 2;
+    byte x1[2][3] = { { 'a',  'b',  'c', }, { 'd',  'e',  'f',}, };
+    byte x2[2][3] = { { ETCHTYPE_MIN_BYTE,0xff,0},{ ETCHTYPE_MAX_BYTE,0xff,0, }, };
+    byte typecodz[3] = { ETCH_XTRNL_TYPECODE_BYTE, 
+        ETCH_XTRNL_TYPECODE_BYTES, ETCH_XTRNL_TYPECODE_ARRAY };
+    etch_nativearray* a1 = NULL, *a2 = NULL;
+
+    /* test validate byte array x1/a1 */
+    etch_validator* vtor = etchvtor_byte_get(numdimensions);
+
+    a1 = new_etch_nativearray_from(&x1, CLASSID_ARRAY_BYTE,  
+        sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    /* fyi we relinquish ownership of array a1 here */
+    do_recursive_test(vtor, numdimensions, typecodz, (etch_object*) a1);
+
+    /* test validate byte array x2/a2 */
+    vtor = etchvtor_byte_get(numdimensions); 
+
+    a2 = new_etch_nativearray_from(&x2, CLASSID_ARRAY_BYTE,  
+        sizeof(byte), numdimensions, dim0count, dim1count, 0);  
+
+    /* fyi we relinquish ownership of array a2 here */
+    do_recursive_test(vtor, numdimensions, typecodz, (etch_object*) a2);
+
+    /* done */
+    etchvtor_clear_cache();  /* destroy cached validator */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * test_array_int16()
+ * test validator on arrays of short using the recursive test
+ */
+static void test_array_int16(void)  
+{
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+    etch_nativearray* a = NULL;
+
+    short x1[2][3][4] = 
+      { { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+        { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+      };
+    short x2[2][3][4] = 
+      { { { 1,1,1,1, }, { 1,1,1,1, }, { 1,1,1,1, }, },
+        { { 1,1,1,1, }, { 1,1,1,1, }, { 1,1,1,1, }, },
+      };
+    short x3[2][3][4] = 
+      { { { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, },
+        { { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, },
+      };
+    short x4[2][3][4] = 
+      { { { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+        },
+        { { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+        },
+      };
+    short x5[2][3][4] = 
+      { { { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+        },
+        { { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+        },
+      };
+    short x6[2][3][4] = 
+      { { { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+        },
+        { { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+        },
+      };
+    short x7[2][3][4] = 
+      { { { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+        },
+        { { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+        },
+      };
+
+    byte typecodz1[4] = { ETCH_XTRNL_TYPECODE_BYTE, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+    byte typecodz2[4] = { ETCH_XTRNL_TYPECODE_SHORT, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+    etch_validator* vtor = etchvtor_int16_get(numdimensions); /* vtor for all tests */
+
+    /* test validate short array x1/tc1 (1-byte shorts) */
+    a = new_etch_nativearray_from(&x1, CLASSID_ARRAY_INT16,  
+         sizeof(short), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate short array x2/tc1 (1-byte shorts) */
+    a = new_etch_nativearray_from(&x2, CLASSID_ARRAY_INT16,  
+           sizeof(short), numdimensions, dim0count, dim1count, dim2count);  
+ 
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+   /* test validate short array x3/tc1 (1-byte shorts) */
+    a = new_etch_nativearray_from(&x3, CLASSID_ARRAY_INT16,  
+           sizeof(short), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate short array x4/tc1 (1-byte shorts) */
+    a = new_etch_nativearray_from(&x4, CLASSID_ARRAY_INT16,  
+           sizeof(short), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate short array x5/tc1 (1-byte shorts) */
+    a = new_etch_nativearray_from(&x5, CLASSID_ARRAY_INT16,  
+           sizeof(short), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate short array x6/tc2 (2-byte shorts) */
+    a = new_etch_nativearray_from(&x6, CLASSID_ARRAY_INT16,  
+           sizeof(short), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz2, (etch_object*) a);
+
+
+    /* test validate short array x7/tc2 (2-byte shorts) */
+    a = new_etch_nativearray_from(&x7, CLASSID_ARRAY_INT16,  
+           sizeof(short), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz2, (etch_object*) a);
+
+
+    /* done */
+    etchvtor_clear_cache();  /* destroy cached validator */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * test_array_int32()
+ * test validator on arrays of int using the recursive test
+ */
+static void test_array_int32(void)  
+{
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+    etch_nativearray* a = NULL;
+
+    int x1[2][3][4] = 
+      { { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+        { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+      };
+    int x2[2][3][4] = 
+      { { { 1,1,1,1, }, { 1,1,1,1, }, { 1,1,1,1, }, },
+        { { 1,1,1,1, }, { 1,1,1,1, }, { 1,1,1,1, }, },
+      };
+    int x3[2][3][4] = 
+      { { { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, },
+        { { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, },
+      };
+    int x4[2][3][4] = 
+      { { { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+        },
+        { { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+        },
+      };
+    int x5[2][3][4] = 
+      { { { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+        },
+        { { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+        },
+      };
+    int x6[2][3][4] = 
+      { { { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+        },
+        { { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+        },
+      };
+    int x7[2][3][4] = 
+      { { { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+        },
+        { { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+        },
+      };
+
+    byte typecodz1[4] = { ETCH_XTRNL_TYPECODE_BYTE, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+    byte typecodz2[4] = { ETCH_XTRNL_TYPECODE_SHORT, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+
+    /* test validate int array x1/tc1 (1-byte ints) */
+    etch_validator* vtor = etchvtor_int32_get(numdimensions);  /* allocates object */
+
+    a = new_etch_nativearray_from(&x1, CLASSID_ARRAY_INT32,  
+         sizeof(int), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate int array x2/tc1 (1-byte ints) */
+    vtor = etchvtor_int32_get(numdimensions);  /* gets cached object */
+
+    a = new_etch_nativearray_from(&x2, CLASSID_ARRAY_INT32,  
+           sizeof(int), numdimensions, dim0count, dim1count, dim2count);  
+ 
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate int array x3/tc1 (1-byte ints) */
+    a = new_etch_nativearray_from(&x3, CLASSID_ARRAY_INT32,  
+           sizeof(int), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate int array x4/tc1 (1-byte ints) */
+    a = new_etch_nativearray_from(&x4, CLASSID_ARRAY_INT32,  
+           sizeof(int), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate int array x5/tc1 (1-byte ints) */
+    a = new_etch_nativearray_from(&x5, CLASSID_ARRAY_INT32,  
+           sizeof(int), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate int array x6/tc2 (2-byte ints) */
+    a = new_etch_nativearray_from(&x6, CLASSID_ARRAY_INT32,  
+           sizeof(int), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz2, (etch_object*) a);
+
+
+    /* test validate int array x7/tc2 (2-byte ints) */
+    a = new_etch_nativearray_from(&x7, CLASSID_ARRAY_INT32,  
+           sizeof(int), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz2, (etch_object*) a);
+
+
+    /* test validate int array x8/tc4 (4-byte ints) */
+    a = new_etch_nativearray_from(&x6, CLASSID_ARRAY_INT32,  
+           sizeof(int), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz2, (etch_object*) a);
+
+
+    /* test validate int array x9/tc4 (4-byte ints) */
+    a = new_etch_nativearray_from(&x7, CLASSID_ARRAY_INT32,  
+           sizeof(int), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz2, (etch_object*) a);
+
+
+    /* done */
+    etchvtor_clear_cache();  /* destroy cached validator */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * test_array_int64()
+ * test validator on arrays of long long using the recursive test
+ */
+static void test_array_int64(void)  
+{
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+    etch_nativearray* a = NULL;
+
+    int64 x1[2][3][4] = 
+      { { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+        { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+      };
+    int64 x2[2][3][4] = 
+      { { { 1,1,1,1, }, { 1,1,1,1, }, { 1,1,1,1, }, },
+        { { 1,1,1,1, }, { 1,1,1,1, }, { 1,1,1,1, }, },
+      };
+    int64 x3[2][3][4] = 
+      { { { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, },
+        { { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, },
+      };
+    int64 x4[2][3][4] = 
+      { { { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+        },
+        { { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+          { ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE,ETCHTYPE_MAX_BYTE, }, 
+        },
+      };
+    int64 x5[2][3][4] = 
+      { { { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+        },
+        { { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+          { ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE,ETCHTYPE_MIN_BYTE, }, 
+        },
+      };
+    int64 x6[2][3][4] = 
+      { { { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+        },
+        { { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+          { ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16,ETCHTYPE_MAX_INT16, }, 
+        },
+      };
+    int64 x7[2][3][4] = 
+      { { { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+        },
+        { { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+          { ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16,ETCHTYPE_MIN_INT16, }, 
+        },
+      };
+    int64 x8[2][3][4] = 
+      { { { ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32, }, 
+          { ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32, }, 
+          { ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32, }, 
+        },
+        { { ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32, }, 
+          { ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32, }, 
+          { ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32,ETCHTYPE_MAX_INT32, }, 
+        },
+      };
+    int64 x9[2][3][4] = 
+      { { { ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32, }, 
+          { ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32, }, 
+          { ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32, }, 
+        },
+        { { ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32, }, 
+          { ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32, }, 
+          { ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32,ETCHTYPE_MIN_INT32, }, 
+        },
+      };
+    int64 x10[2][3][4] = 
+      { { { ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64, }, 
+          { ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64, }, 
+          { ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64, }, 
+        },
+        { { ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64, }, 
+          { ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64, }, 
+          { ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64,ETCHTYPE_MAX_INT64, }, 
+        },
+      };
+    int64 x11[2][3][4] = 
+      { { { ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64, }, 
+          { ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64, }, 
+          { ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64, }, 
+        },
+        { { ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64, }, 
+          { ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64, }, 
+          { ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64,ETCHTYPE_MIN_INT64, }, 
+        },
+      };
+
+    byte typecodz1[4] = { ETCH_XTRNL_TYPECODE_BYTE, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+    byte typecodz2[4] = { ETCH_XTRNL_TYPECODE_SHORT, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+    byte typecodz4[4] = { ETCH_XTRNL_TYPECODE_INT, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+    byte typecodz8[4] = { ETCH_XTRNL_TYPECODE_LONG, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+    /* test validate int array x1/tc1 (1-byte ints) */
+    etch_validator* vtor = etchvtor_int64_get(numdimensions);  /* allocates object */
+
+    a = new_etch_nativearray_from(&x1, CLASSID_ARRAY_INT64,  
+         sizeof(int64), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate int64 array x2/tc1 (1-byte longs) */
+    vtor = etchvtor_int64_get(numdimensions);  /* gets cached object */
+
+    a = new_etch_nativearray_from(&x2, CLASSID_ARRAY_INT64,  
+           sizeof(int64), numdimensions, dim0count, dim1count, dim2count);  
+ 
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate int64 array x3/tc1 (1-byte longs) */
+    a = new_etch_nativearray_from(&x3, CLASSID_ARRAY_INT64,  
+           sizeof(int64), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate int64 array x4/tc1 (1-byte longs) */
+    a = new_etch_nativearray_from(&x4, CLASSID_ARRAY_INT64,  
+           sizeof(int64), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate int64 array x5/tc1 (1-byte longs) */
+    a = new_etch_nativearray_from(&x5, CLASSID_ARRAY_INT64,  
+           sizeof(int64), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate int64 array x6/tc2 (2-byte longs) */
+    a = new_etch_nativearray_from(&x6, CLASSID_ARRAY_INT64,  
+           sizeof(int64), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz2, (etch_object*) a);
+
+
+    /* test validate int64 array x7/tc2 (2-byte longs) */
+    a = new_etch_nativearray_from(&x7, CLASSID_ARRAY_INT64,  
+           sizeof(int64), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz2, (etch_object*) a);
+
+
+    /* test validate int64 array x8/tc4 (4-byte longs) */
+    a = new_etch_nativearray_from(&x8, CLASSID_ARRAY_INT64,  
+           sizeof(int64), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz4, (etch_object*) a);
+
+
+    /* test validate int64 array x9/tc4 (4-byte longs) */
+    a = new_etch_nativearray_from(&x9, CLASSID_ARRAY_INT64,  
+           sizeof(int64), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz4, (etch_object*) a);
+
+
+    /* test validate int64 array x10/tc8 (8-byte longs) */
+    a = new_etch_nativearray_from(&x10, CLASSID_ARRAY_INT64,  
+           sizeof(int64), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz8, (etch_object*) a);
+
+
+    /* test validate int64 array x11/tc8 (8-byte longs) */
+    a = new_etch_nativearray_from(&x11, CLASSID_ARRAY_INT64,  
+           sizeof(int64), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz8, (etch_object*) a);
+
+
+    /* done */
+    etchvtor_clear_cache();  /* destroy cached validator */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * test_array_float()
+ * test validator on arrays of float using the recursive test
+ */
+static void test_array_float(void)  
+{
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+    etch_nativearray* a = NULL;
+
+    float x1[2][3][4] = 
+      { { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+        { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+      };
+    float x2[2][3][4] = 
+      { { { 1,1,1,1, }, { 1,1,1,1, }, { 1,1,1,1, }, },
+        { { 1,1,1,1, }, { 1,1,1,1, }, { 1,1,1,1, }, },
+      };
+    float x3[2][3][4] = 
+      { { { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, },
+        { { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, },
+      };
+    float x4[2][3][4] = 
+      { { { ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT, }, 
+          { ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT, }, 
+          { ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT, }, 
+        },
+        { { ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT, }, 
+          { ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT, }, 
+          { ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT,ETCHTYPE_MAX_FLOAT, }, 
+        },
+      };
+    float x5[2][3][4] = 
+      { { { ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT, }, 
+          { ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT, }, 
+          { ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT, }, 
+        },
+        { { ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT, }, 
+          { ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT, }, 
+          { ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT,ETCHTYPE_MIN_FLOAT, }, 
+        },
+      };
+
+    byte typecodz1[4] = { ETCH_XTRNL_TYPECODE_FLOAT, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+    etch_validator* vtor = etchvtor_float_get(numdimensions); /* vtor for all tests */
+
+    /* test validate float array x1/tc1 (1-byte floats) */
+    a = new_etch_nativearray_from(&x1, CLASSID_ARRAY_FLOAT,  
+         sizeof(float), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate float array x2/tc1 (1-byte floats) */
+    a = new_etch_nativearray_from(&x2, CLASSID_ARRAY_FLOAT,  
+           sizeof(float), numdimensions, dim0count, dim1count, dim2count);  
+ 
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+   /* test validate float array x3/tc1 (1-byte floats) */
+    a = new_etch_nativearray_from(&x3, CLASSID_ARRAY_FLOAT,  
+           sizeof(float), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate float array x4/tc1 (1-byte floats) */
+    a = new_etch_nativearray_from(&x4, CLASSID_ARRAY_FLOAT,  
+           sizeof(float), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate float array x5/tc1 (1-byte floats) */
+    a = new_etch_nativearray_from(&x5, CLASSID_ARRAY_FLOAT,  
+           sizeof(float), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* done */
+    etchvtor_clear_cache();  /* destroy cached validator */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * test_array_double()
+ * test validator on arrays of double using the recursive test
+ */
+static void test_array_double(void)  
+{
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+    etch_nativearray* a = NULL;
+
+    double x1[2][3][4] = 
+      { { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+        { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+      };
+    double x2[2][3][4] = 
+      { { { 1,1,1,1, }, { 1,1,1,1, }, { 1,1,1,1, }, },
+        { { 1,1,1,1, }, { 1,1,1,1, }, { 1,1,1,1, }, },
+      };
+    double x3[2][3][4] = 
+      { { { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, },
+        { { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, { -1,-1,-1,-1, }, },
+      };
+    double x4[2][3][4] = 
+      { { { ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE, }, 
+          { ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE, }, 
+          { ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE, }, 
+        },
+        { { ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE, }, 
+          { ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE, }, 
+          { ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE,ETCHTYPE_MAX_DOUBLE, }, 
+        },
+      };
+    double x5[2][3][4] = 
+      { { { ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE, }, 
+          { ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE, }, 
+          { ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE, }, 
+        },
+        { { ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE, }, 
+          { ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE, }, 
+          { ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE,ETCHTYPE_MIN_DOUBLE, }, 
+        },
+      };
+
+    byte typecodz1[4] = { ETCH_XTRNL_TYPECODE_DOUBLE, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+    etch_validator* vtor = etchvtor_double_get(numdimensions); /* vtor for all tests */
+
+    /* test validate double array x1/tc1 (1-byte doubles) */
+    a = new_etch_nativearray_from(&x1, CLASSID_ARRAY_DOUBLE,  
+         sizeof(double), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate double array x2/tc1 (1-byte doubles) */
+    a = new_etch_nativearray_from(&x2, CLASSID_ARRAY_DOUBLE,  
+           sizeof(double), numdimensions, dim0count, dim1count, dim2count);  
+ 
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+   /* test validate double array x3/tc1 (1-byte doubles) */
+    a = new_etch_nativearray_from(&x3, CLASSID_ARRAY_DOUBLE,  
+           sizeof(double), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate double array x4/tc1 (1-byte doubles) */
+    a = new_etch_nativearray_from(&x4, CLASSID_ARRAY_DOUBLE,  
+           sizeof(double), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate double array x5/tc1 (1-byte doubles) */
+    a = new_etch_nativearray_from(&x5, CLASSID_ARRAY_DOUBLE,  
+           sizeof(double), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* done */
+    etchvtor_clear_cache();  /* destroy cached validator */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * test_array_string()
+ * test validator on arrays of etch_string* using the recursive test
+ */
+static void test_array_string(void)  
+{
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+    etch_nativearray* a = NULL;
+    int i = 0, j = 0, k = 0;
+    const wchar_t* emptystring = L"";
+    const wchar_t* nonemptystring = L"abc";
+
+    etch_string* x1[2][3][4] = 
+      { { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+        { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+      };
+
+    etch_string* x2[2][3][4] = 
+      { { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+        { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+      };
+
+    byte typecodz1[4] = { ETCH_XTRNL_TYPECODE_EMPTY_STRING, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+    byte typecodz2[4] = { ETCH_XTRNL_TYPECODE_STRING,
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY };
+
+    etch_validator* vtor = etchvtor_string_get(numdimensions); /* vtor for all tests */
+
+    for(i=0; i < dim2count; i++) /* populate test data arrays */
+    for(j=0; j < dim1count; j++)  
+    for(k=0; k < dim0count; k++)  
+    {
+        x1[i][j][k] = new_stringw(emptystring);
+        x2[i][j][k] = new_stringw(nonemptystring);
+    }
+
+    /* test validate etch_string* array x1/tc1 (empty string) */
+    a = new_etch_nativearray_from(&x1, CLASSID_ARRAY_STRING,  
+         sizeof(etch_string*), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz1, (etch_object*) a);
+
+
+    /* test validate etch_string* array x2/tc2 (nonempty string) */
+    a = new_etch_nativearray_from(&x2, CLASSID_ARRAY_STRING,  
+         sizeof(etch_string*), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz2, (etch_object*) a);
+
+
+    /* done */
+    etchvtor_clear_cache();  /* destroy cached validator */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * test_array_object()
+ * test validator on arrays of etch_object* using the recursive test
+ */
+static void test_array_object(void)  
+{
+    const int numdimensions = 3, dim0count = 4, dim1count = 3, dim2count = 2;
+    etch_nativearray* a = NULL;
+    etch_object* obj = NULL;
+    int i = 0, j = 0, k = 0;
+    int sequence = 0;
+
+    etch_object* x1[2][3][4] = 
+      { { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+        { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+      };
+
+    etch_object* x2[2][3][4] = 
+      { { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+        { { 0,0,0,0, }, { 0,0,0,0, }, { 0,0,0,0, }, },
+      };
+
+    byte typecodz[4] = { ETCH_XTRNL_TYPECODE_ANY, 
+        ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY, ETCH_XTRNL_TYPECODE_ARRAY};
+
+    etch_validator* vtor = etchvtor_object_get(numdimensions); /* vtor for all tests */
+
+    for(i=0; i < dim2count; i++) /* populate test data arrays */
+    for(j=0; j < dim1count; j++)  
+    for(k=0; k < dim0count; k++)  
+    {
+        sequence = i*j*k; 
+        obj = (etch_object*)new_int32(sequence);
+        x1[i][j][k] = obj;
+
+        obj = (etch_object*)&sequence;
+        x2[i][j][k] = obj;
+    }
+
+    /* test validate etch_object* array x1/tc (object owning object content) */
+    a = new_etch_nativearray_from(&x1, CLASSID_ARRAY_OBJECT,  
+         sizeof(etch_object*), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz, (etch_object*) a);
+
+
+    /* test validate etch_object* array x2/tc (object not owning its content) */
+    a = new_etch_nativearray_from(&x2, CLASSID_ARRAY_OBJECT,  
+         sizeof(etch_object*), numdimensions, dim0count, dim1count, dim2count);  
+
+    do_recursive_test(vtor, numdimensions, typecodz, (etch_object*) a);
+
+
+    /* done */
+    etchvtor_clear_cache();  /* destroy cached validator */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+
+/**
+ * do_struct_element_vtor_test()
+ * common test template for the structvalue element_validator tests
+ */
+static void do_struct_element_vtor_test(int testdims, char* name, unsigned short expected_class_id, etch_type* thistype)
+{
+    etch_validator* vtor = etchvtor_struct_get(thistype, testdims);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(vtor); 
+    CU_ASSERT_EQUAL(vtor->numdimensions, testdims); 
+    CU_ASSERT_EQUAL(vtor->expected_class_id, expected_class_id); 
+    CU_ASSERT_STRING_EQUAL(vtor->description, name); 
+    CU_ASSERT_EQUAL(is_equal_types(vtor->struct_type, thistype), TRUE);
+
+    /* validator destructor is benign if validator is marked cached
+     * however a struct validator is not cached */
+    etch_object_destroy(vtor);
+}
+
+
+/**
+ * test_struct_element_validator()
+ */
+static void test_struct_element_validator(void)  
+{
+    etch_type* typeabc = new_type(L"abc");
+
+    do_struct_element_vtor_test(0, "struct_abc[0]", CLASSID_STRUCTVALUE,  typeabc);
+    do_struct_element_vtor_test(1, "struct_abc[1]", CLASSID_ARRAY_OBJECT, typeabc);
+    do_struct_element_vtor_test(2, "struct_abc[2]", CLASSID_ARRAY_OBJECT, typeabc);
+    do_struct_element_vtor_test(3, "struct_abc[3]", CLASSID_ARRAY_OBJECT, typeabc);
+
+    etch_object_destroy(typeabc);
+    etchvtor_clear_cache();    /* not needed since struct validator not cached  */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * do_struct_goodvalue_test()
+ */
+static void do_struct_goodvalue_test(int testdims, const byte expected_typecode, 
+     etch_object* value, etch_type* thistype, const int is_expected_newobject)
+{
+    int result = 0;
+    byte validated_typecode = 0;
+    etch_object* validated_value = NULL;
+
+    etch_validator* vtor = etchvtor_struct_get(thistype, testdims);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(vtor); 
+
+    result = vtor->check_value(vtor, value, &validated_typecode);
+    CU_ASSERT_EQUAL_FATAL(result,0); 
+    CU_ASSERT_EQUAL(validated_typecode, expected_typecode); 
+
+    result = vtor->validate(vtor, value);
+    CU_ASSERT_EQUAL_FATAL(result,0); 
+
+    validated_value = vtor->validate_value(vtor, value);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(validated_value); 
+
+    if  (is_expected_newobject)
+    {
+         CU_ASSERT_PTR_NOT_EQUAL_FATAL(value, validated_value);
+    }
+    else CU_ASSERT_PTR_EQUAL_FATAL(value, validated_value);
+
+    /* validated_value can return the same object as paassed, or a different
+     * object. for example when we expect etch_byte but validate against an
+     * etch_int32, we would pass an etch_int32 and get back an etch_byte.  
+     * in the real world, we would replace the passed value with the validated
+     * value; however in this test the caller is not prepared to handle this
+     * situation, so we free the new object, and let caller free the original */
+    if (validated_value != value)
+        etch_object_destroy(validated_value);       
+
+    /* validator destructor is benign if validator is marked cached
+     * however a struct validator is not cached */
+    etch_object_destroy(vtor);      
+}
+
+
+
+/**
+ * do_struct_badvalue_test()
+ */
+static void do_struct_badvalue_test(int testdims, etch_object* value, etch_type* thistype)
+{
+    int result = 0;
+    byte validated_typecode = 0;
+    etch_object* validated_value = NULL;
+
+    etch_validator* vtor = etchvtor_struct_get(thistype, testdims);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(vtor); 
+
+    result = vtor->check_value(vtor, value, &validated_typecode);
+    CU_ASSERT_EQUAL_FATAL(result,-1); 
+
+    result = vtor->validate(vtor, value);
+    CU_ASSERT_EQUAL_FATAL(result,-1); 
+
+    validated_value = vtor->validate_value(vtor, value);
+    CU_ASSERT_PTR_NULL_FATAL(validated_value); 
+
+    if (validated_value && validated_value != value)
+        etch_object_destroy(validated_value);       
+
+    /* validator destructor is benign if validator is marked cached
+     * however a struct validator is not cached */
+    etch_object_destroy(vtor);      
+}
+
+
+/**
+ * test_struct_good_values()
+ */
+static void test_struct_good_values(void)  
+{
+    etch_type* typeabc = new_type(L"abc");
+    etch_nativearray* array_of_struct = NULL;
+    const int NUMDIMS0 = 0, NUMDIMS1 = 1, NUMDIMS2 = 2, DIMSIZE4 = 4;
+
+    etch_structvalue* sv = new_structvalue(typeabc, 0);
+    do_struct_goodvalue_test(NUMDIMS0, ETCH_XTRNL_TYPECODE_CUSTOM, (etch_object*) sv, typeabc, FALSE);
+
+    /* following tests create an empty array of structvalue objects */
+    array_of_struct = new_etch_nativearray_of(((etch_object*)sv)->obj_type, ((etch_object*)sv)->class_id, NUMDIMS1, DIMSIZE4, 0, 0);
+    do_struct_goodvalue_test(NUMDIMS1, ETCH_XTRNL_TYPECODE_ARRAY, (etch_object*) array_of_struct, typeabc, FALSE);
+    etch_object_destroy(array_of_struct);
+
+    array_of_struct = new_etch_nativearray_of(((etch_object*)sv)->obj_type, ((etch_object*)sv)->class_id, NUMDIMS2, DIMSIZE4, DIMSIZE4, 0);
+    do_struct_goodvalue_test(NUMDIMS2, ETCH_XTRNL_TYPECODE_ARRAY, (etch_object*) array_of_struct, typeabc, FALSE);
+    etch_object_destroy(array_of_struct);
+
+    etch_object_destroy(sv);          
+    etch_object_destroy(typeabc); /* in practice this would have been a static type */
+    etchvtor_clear_cache();    /* not needed since struct validator not cached  */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_struct_bad_values()  
+ */
+static void test_struct_bad_values(void)  
+{
+    etch_type* type_expected = new_type(L"abc");
+    etch_type* type_unexpect = new_type(L"def");
+    etch_nativearray* array_of_struct = NULL;
+    const int NUMDIMS0 = 0, NUMDIMS1 = 1, NUMDIMS2 = 2, NUMDIMS3 = 3, DIMSIZE4 = 4;
+
+    etch_structvalue* sv = new_structvalue(type_expected, 0);
+    etch_structvalue* svbogus = new_structvalue(type_unexpect, 0);
+    etch_int32*  intobj  = new_int32(1);
+    etch_object* objobj  = (etch_object*)intobj;
+
+    do_struct_badvalue_test(0, (etch_object*) intobj, type_expected);
+    do_struct_badvalue_test(0, objobj,  type_expected);
+    do_struct_badvalue_test(0, (etch_object*) svbogus, type_expected);
+    do_struct_badvalue_test(0, (etch_object*) sv, type_unexpect);
+
+    do_struct_badvalue_test(1, (etch_object*) intobj, type_expected);
+    do_struct_badvalue_test(1, objobj, type_expected);
+    do_struct_badvalue_test(1, (etch_object*) svbogus, type_expected);
+    do_struct_badvalue_test(1, (etch_object*) sv, type_unexpect);
+
+    /* following tests create an empty array of structvalue objects */
+    array_of_struct = new_etch_nativearray_of(((etch_object*)sv)->obj_type, ((etch_object*)sv)->class_id, NUMDIMS1, DIMSIZE4, 0, 0);
+    do_struct_badvalue_test(NUMDIMS0, (etch_object*) array_of_struct, type_expected);
+    etch_object_destroy(array_of_struct);
+
+    array_of_struct = new_etch_nativearray_of(((etch_object*)sv)->obj_type, ((etch_object*)sv)->class_id, NUMDIMS2, DIMSIZE4, DIMSIZE4, 0);
+    do_struct_badvalue_test(NUMDIMS1, (etch_object*) array_of_struct, type_expected);
+    do_struct_badvalue_test(NUMDIMS0, (etch_object*) array_of_struct, type_expected);
+    etch_object_destroy(array_of_struct);
+
+    array_of_struct = new_etch_nativearray_of(((etch_object*)sv)->obj_type, ((etch_object*)sv)->class_id, NUMDIMS3, DIMSIZE4, DIMSIZE4, DIMSIZE4);
+    do_struct_badvalue_test(NUMDIMS2, (etch_object*) array_of_struct, type_expected);
+    do_struct_badvalue_test(NUMDIMS1, (etch_object*) array_of_struct, type_expected);
+    do_struct_badvalue_test(NUMDIMS0, (etch_object*) array_of_struct, type_expected);
+    etch_object_destroy(array_of_struct);
+  
+    etch_object_destroy(objobj);
+    etch_object_destroy(sv);   
+    etch_object_destroy(svbogus);       
+    etch_object_destroy(type_expected); /* in real world these are static types */
+    etch_object_destroy(type_unexpect);  
+    etchvtor_clear_cache();  /* however struct validator is not cached */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_combo_validator_1()
+ */
+static void test_combo_validator_1(void)  
+{
+    int result = 0; 
+    etch_validator *vtor1 = 0, *vtor2 = 0, *vtor3 = 0;
+    create_testobjects();
+
+    /* one cached validator */
+    vtor1  = etchvtor_boolean_get(0);
+    vtor2  = NULL;
+    vtor3  = new_combo_validator(vtor1, vtor2);
+    result = is_etch_combo_validator(vtor3);
+    CU_ASSERT_EQUAL_FATAL(result, TRUE);
+    result = vtor3->validate(vtor3, (etch_object*) objbool_true);
+    CU_ASSERT_EQUAL(result,0);
+    etch_object_destroy(vtor3);
+
+    /* one cached validator */
+    vtor1  = NULL;
+    vtor2  = etchvtor_boolean_get(0);
+    vtor3  = new_combo_validator(vtor1, vtor2);
+    result = vtor3->validate(vtor3, (etch_object*) objbool_true);
+    CU_ASSERT_EQUAL(result,0);
+    etch_object_destroy(vtor3);
+
+    /* two cached validators */
+    vtor1  = etchvtor_boolean_get(0);
+    vtor2  = etchvtor_int32_get(0);
+    vtor3  = new_combo_validator(vtor1, vtor2);
+    result = vtor3->validate(vtor3, (etch_object*) objint_three);
+    CU_ASSERT_EQUAL(result,0);
+    etch_object_destroy(vtor3);
+
+    destroy_testobjects(); 
+    etchvtor_clear_cache();  /* destroy cached validators */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_combo_validator_2()
+ */
+static void test_combo_validator_2(void)  
+{
+    int result = 0; 
+    etch_validator *vtor1 = 0, *vtor2 = 0, *vtor3 = 0, *vtor4 = 0, *vtor5 = 0;
+    create_testobjects();
+
+    /* chain 1 of cached validators and combos */
+    vtor1  = etchvtor_boolean_get(0);
+    vtor2  = etchvtor_boolean_get(0);
+    vtor3  = new_combo_validator(vtor1, vtor2);
+    vtor4  = etchvtor_boolean_get(0);
+    vtor5  = new_combo_validator(vtor4, vtor3);
+    result = vtor5->validate(vtor5, (etch_object*) objbool_true);
+    CU_ASSERT_EQUAL(result,0);
+    etch_object_destroy(vtor5);
+
+    /* chain 2 of cached validators and combos */
+    vtor1  = etchvtor_boolean_get(0);
+    vtor2  = etchvtor_boolean_get(0);
+    vtor3  = new_combo_validator(vtor1, vtor2);
+    vtor4  = etchvtor_boolean_get(0);
+    vtor5  = new_combo_validator(vtor3, vtor4);
+    result = vtor5->validate(vtor5, (etch_object*) objbool_true);
+    CU_ASSERT_EQUAL(result,0);
+    etch_object_destroy(vtor5);
+
+    destroy_testobjects(); 
+    etchvtor_clear_cache();  /* destroy cached validators */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_combo_validator_3()
+ */
+static void test_combo_validator_3(void)  
+{
+    int result = 0; 
+    etch_validator *vtor1 = 0, *vtor2 = 0, *vtor3 = 0, *vtor4 = 0, *vtor5 = 0;
+    create_testobjects();
+
+    /* chain 1 of cached and non-cached validators and combos */
+    vtor1  = etchvtor_boolean_get(0);
+    vtor2  = etchvtor_int32_get(0);
+    vtor3  = new_combo_validator(vtor1, vtor2);
+    vtor4  = etchvtor_struct_get(testtype, 0);
+    vtor5  = new_combo_validator(vtor4, vtor3);
+    result = vtor5->validate(vtor5, (etch_object*) objint_three);
+    CU_ASSERT_EQUAL(result, 0); 
+    etch_object_destroy(vtor5);
+
+    /* chain 2 of cached and non-cached validators and combos */
+    vtor1  = etchvtor_int32_get(0);
+    vtor2  = etchvtor_boolean_get(0);
+    vtor3  = new_combo_validator(vtor1, vtor2);
+    vtor4  = etchvtor_struct_get(testtype, 0);  
+    vtor5  = new_combo_validator(vtor3, vtor4);
+    result = vtor5->validate(vtor5, (etch_object*) objint_three);
+    CU_ASSERT_EQUAL(result, 0);
+    etch_object_destroy(vtor5);
+
+    destroy_testobjects(); 
+    etchvtor_clear_cache();  /* destroy cached validators */
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_validator_suite()
+{
+    CU_pSuite ps = CU_add_suite("validator test suite", init_suite, clean_suite);
+
+    CU_add_test(ps, "test boolean validator", test_boolean_validator);
+    CU_add_test(ps, "test validate boolean arrays", test_array_boolean);
+    CU_add_test(ps, "test validate byte arrays", test_array_byte);
+    CU_add_test(ps, "test validate int16 arrays", test_array_int16);
+    CU_add_test(ps, "test validate int32 arrays", test_array_int32);
+    CU_add_test(ps, "test validate int64 arrays", test_array_int64);
+    CU_add_test(ps, "test validate float arrays", test_array_float);
+    CU_add_test(ps, "test validate double arrays", test_array_double);
+    CU_add_test(ps, "test validate etch_string* arrays", test_array_string);
+    CU_add_test(ps, "test validate etch_object* arrays", test_array_object);
+    CU_add_test(ps, "test struct element validator", test_struct_element_validator);   
+    CU_add_test(ps, "test struct good values", test_struct_good_values); 
+    CU_add_test(ps, "test struct bad values",  test_struct_bad_values);  
+    CU_add_test(ps, "test combo validator 1",  test_combo_validator_1); 
+    CU_add_test(ps, "test combo validator 2",  test_combo_validator_2); 
+    CU_add_test(ps, "test combo validator 3",  test_combo_validator_3);         
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/support/test_remote.c b/binding-c/runtime/c/src/test/support/test_remote.c
new file mode 100644
index 0000000..99bd47b
--- /dev/null
+++ b/binding-c/runtime/c/src/test/support/test_remote.c
@@ -0,0 +1,1180 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_remote.c
+ * test remote, delivery service, etc.
+ */
+
+#include "etch_runtime.h"
+#include "etch_svcobj_masks.h"
+#include "etch_transport.h"  
+#include "etch_thread.h"
+#include "etch_stub.h"
+#include "etch_remote.h"
+#include "etch_default_value_factory.h"
+#include "etch_plain_mailbox.h"
+#include "etch_plain_mailbox_manager.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_map.h"
+#include "etch_log.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#ifdef _WIN32
+#pragma message ( "this testsuite is not active" )
+#else
+#warning "this testsuite is not active"
+#endif
+
+#define IS_DEBUG_CONSOLE FALSE
+
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+#if 0
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * unit test support
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+#define THISTEST_WHO_VALUE 0x5151
+
+#define TEST_MSGID  0x1001
+#define TEST_QDELAYMS 1000
+#define TEST_MBOX_LIFETIME_UNTIL_CLOSE 0
+#define TEST_LIFETIME_ONE_SECOND 1000
+#define TEST_MAXMSGS_ONE 1
+
+static unsigned short CLASSID_MY_VF;
+static unsigned short CLASSID_MY_VF_VTAB;
+static unsigned short CLASSID_MY_VF_IMPL;
+static unsigned short CLASSID_MY_REMOTEIMPL;
+static unsigned short CLASSID_MY_IMPLBASE;
+static unsigned short CLASSID_MY_REMOTEBASE;
+static unsigned short CLASSID_MY_RESULT;
+ 
+typedef enum whats
+{ TRANSPORT_MESSAGE = 1, TRANSPORT_QUERY, TRANSPORT_CONTROL, TRANSPORT_NOTIFY,
+  BEGIN_CALL, END_CALL
+} whats;
+
+static etch_resources*         g_my_resources;
+static default_value_factory*  g_my_vf;
+static etch_plainmailbox*      g_my_mbox; 
+static i_mailbox*              g_my_ibox; 
+static etch_plainmailboxmgr*   g_my_mboxmgr;           
+static i_delivery_service*     g_my_ds;
+static etch_type*              g_mt_foo;
+static etch_type*              g_mt_bar;
+
+static etch_who*               gds_who;
+static int64                   gds_messageid;
+static int                     gds_what;
+static int                     gds_rtypeid;
+static int                     gds_eventval;
+static int                     gds_queryval;
+static int                     gds_controlval;
+static int                     gds_valueval;
+
+static i_delivery_service* new_my_delivery_service();
+static int my_pmboxmgr_session_notify (etch_plainmailboxmgr*, etch_event*);
+static default_value_factory* new_fake_valuefactory();
+static char* LOGSRC = "TEST";
+
+
+/**
+ * new_my_resources()
+ * resources map constructor
+ */
+static etch_resources* new_my_resources(void* valuefactory)
+{   
+    etch_resources* resx = get_etch_transport_resources(NULL);
+    etch_resources_add(resx, ETCH_RESXKEY_MSGIZER_VALUFACT, valuefactory); 
+    return resx;
+}
+
+
+/**
+ * setup_this_test()
+ * set up an individual unit test
+ */
+static int setup_this_test()
+{
+    CLASSID_MY_VF      = get_dynamic_classid();
+    CLASSID_MY_VF_VTAB = get_dynamic_classid();
+    CLASSID_MY_VF_IMPL = get_dynamic_classid();
+    #if(IS_DEBUG_CONSOLE)
+    printf("\n");
+    #endif
+
+    g_mt_foo = new_static_type(L"foo");
+    g_mt_bar = new_static_type(L"bar");
+
+    g_my_vf = new_fake_valuefactory();  
+    set_etchobj_static_all(g_my_vf);   /* so resources map will not destroy */ 
+
+    /* get resources map populated with transport resources such as thread pools */
+    g_my_resources = new_my_resources(g_my_vf);
+
+    g_my_ds = new_my_delivery_service ();
+
+    /* the ids itm object belongs to the ds transport which is the mailbox manager */
+    g_my_mboxmgr = g_my_ds->transport->thisx;
+    CU_ASSERT_FATAL(is_etch_mailboxmgr(g_my_mboxmgr));
+
+    /* register a new mailbox with the manager */
+    g_my_mbox = new_mailbox (g_my_mboxmgr->imanager, TEST_MSGID, 
+       TEST_QDELAYMS, TEST_MBOX_LIFETIME_UNTIL_CLOSE, TEST_MAXMSGS_ONE);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_mbox);
+    g_my_ibox = g_my_mbox->imailbox;
+    g_my_mboxmgr->session_notify = my_pmboxmgr_session_notify;
+
+    return 0;
+}
+
+
+/**
+ * teardown_this_test()
+ * tear down an individual unit test
+ */
+static void teardown_this_test()
+{ 
+    if (g_my_mboxmgr)
+        if (g_my_mbox)
+            etch_object_destroy(g_my_mbox);
+
+    if (g_my_resources)  
+    {   /* we did a set_etchobj_static_all() on the g_my_vf value factory  
+         * and as a result the map will not destroy it. if we had not done
+         * so, the vf would have been destroyed with the resources map. */
+        etch_object_destroy(g_my_resources);   
+    }
+
+    if (g_my_vf) 
+    {   /* we clear the set_etchobj_static_all() on the g_my_vf value factory  
+         * and as a result we can then destroy it */
+        clear_etchobj_static_all(g_my_vf);
+        etch_object_destroy(g_my_vf);
+    }
+
+    etch_object_destroy(g_my_ds);
+
+    destroy_static_type(g_mt_foo);
+    destroy_static_type(g_mt_bar);
+
+    gds_what  = 0;
+    gds_who   = NULL;
+    g_my_vf   = NULL;
+    g_my_ds   = NULL;
+    g_my_mbox = NULL;
+    g_my_ibox = NULL;
+    g_my_mboxmgr = NULL;  
+
+    g_mt_foo = g_mt_bar = NULL;
+    gds_eventval= gds_queryval = gds_controlval = gds_valueval = 0;
+    g_my_resources = NULL;
+    gds_messageid = 0;  
+    gds_rtypeid = 0;
+
+    etchvf_free_builtins(); 
+}
+
+/* - - - - - - - - - -
+ * mailbox manager
+ * - - - - - - - - - - 
+ */
+
+static int my_pmboxmgr_session_notify (etch_plainmailboxmgr* mgr, etch_event* evt)
+{
+    switch(evt->value)
+    {   case ETCHEVT_SESSION_DOWN: pmboxmgr_unregister_all(mgr);
+    }
+    //    ETCHOBJ_DESTROY();
+    etch_object_destroy(evt);
+    evt = NULL;
+
+    return 0;
+}
+
+
+/* - - - - - - - - - -
+ * remote object
+ * - - - - - - - - - - 
+ */
+
+/**
+ * my_remoteobj
+ * xxxx_remote_either
+ * this represents for this test what would be a service remote_server or remote_client in practice.
+ */
+typedef struct my_remoteobj
+{
+    etch_object object;
+
+    i_xxxx_either* xxxx_either_base;  /* owned server or client */
+    xxxx_remote*   remote_base;       /* owned */
+    void*          either_factory;    /* owned */
+    default_value_factory*  vf;       /* owned by base */
+
+    /* note that the transport interface is accessed via the remote_base */ 
+
+} my_remoteobj;
+
+
+
+/* - - - - - - - - - -
+ * value factory
+ * - - - - - - - - - - 
+ */
+
+/**
+ * my_valufactory_impl
+ * value factory instance data object
+ */
+typedef struct my_valufactory_impl
+{
+    etch_object object;
+
+} my_valufactory_impl;
+
+
+/**
+ * destroy_my_valufactory_impl()
+ * destructor for inheriting value factory instance data
+ */
+static int destroy_my_valufactory_impl(my_valufactory_impl* impl)
+{
+    if (NULL == impl) return -1;
+
+    if (!is_etchobj_static_content(impl))
+    {
+        /* no custom types to destroy - they are global for this test */
+    }
+
+    return destroy_objectex((etch_object*) impl);
+}
+
+
+/**
+ * new_my_valufactory_impl()
+ * constructor for our value factory's instance data
+ */
+static my_valufactory_impl* new_my_valufactory_impl()
+{
+    unsigned short class_id = CLASSID_MY_VF_IMPL? CLASSID_MY_VF_IMPL: 
+        (CLASSID_MY_VF_IMPL = get_dynamic_classid());
+
+    my_valufactory_impl* impl = (my_valufactory_impl*) new_object
+        (sizeof(my_valufactory_impl), ETCHTYPEB_VALUEFACTIMP, class_id);
+
+    ((etch_object*)impl)->destroy = destroy_my_valufactory_impl;
+
+    return impl;
+}
+
+
+/**
+ * new_fake_valuefactory()
+ */
+static default_value_factory* new_fake_valuefactory()
+{
+    my_valufactory_impl* impl = NULL;
+    etchparentinfo* inheritlist = NULL;
+    const unsigned short classid_vf = get_dynamic_classid_unique(&CLASSID_MY_VF);
+    const unsigned short classid_vf_vtab = get_dynamic_classid_unique(&CLASSID_MY_VF_VTAB);
+
+    g_my_vf = new_default_value_factory(NULL, NULL);
+
+   /* ensure parent type keys exist in the (one-based) inheritance list. 
+    * parent class of our custom vf is default_value_factory.
+    * inheritance list is used by validators and object assignment logic.
+    */
+    inheritlist = get_vtab_inheritance_list((etch_object*)g_my_vf, 2, 1, classid_vf_vtab);
+    inheritlist[1].obj_type = ETCHTYPEB_VALUEFACTORY;  
+    inheritlist[1].class_id = CLASSID_VALUEFACTORY;  /* parent class */
+    ((etch_object*)g_my_vf)->class_id = classid_vf;  /* our class */
+
+    /* instantiate the custom vf's instance data and assign it to the vf. 
+     * the impl comprises all data specific to the inheriting class, including 
+     * data and methods if any. the default value factory destructor will call 
+     * the destructor on the vf's impl object.
+     */  
+    impl = new_my_valufactory_impl();
+    g_my_vf->impl = (etch_object*) impl;
+    ((struct i_value_factory*)((etch_object*)g_my_vf)->vtab)->add_type(g_my_vf, g_mt_foo);
+    ((struct i_value_factory*)((etch_object*)g_my_vf)->vtab)->add_type(g_my_vf, g_mt_bar);
+
+    /* set msgid validator so we can set and retrieve message IDs */
+    etchtype_put_validator(g_mt_foo, builtins._mf__message_id, (etch_object*) etchvtor_int64_get(0));
+    etchtype_put_validator(g_mt_bar, builtins._mf__message_id, (etch_object*) etchvtor_int64_get(0));
+
+    return g_my_vf;
+}
+
+
+/* - - - - - - - - - -
+ * delivery service
+ * - - - - - - - - - - 
+ */
+
+/**
+ * myds_begincall()
+ * override for i_delivery_service.begin_call().
+ * typedef int (*etch_delivsvc_begincall)(void* thisx, etch_message*, void** out);  
+ * @param msg caller relinquishes on success, retains on failure
+ * @param out mailbox interface returned on success
+ * @return 0 success, or -1 failure. new mailbox return in out parameter.
+ */
+static int myds_begincall (i_delivery_service* thisx, etch_message* msg, void** out)
+{
+    etch_int64* msgid = NULL;        
+    assert(out);
+    *out = g_my_ibox;
+    gds_what = BEGIN_CALL;
+    msgid = message_get_id(msg);  
+    gds_messageid = msgid? msgid->value: 0;
+    etch_object_destroy(msg);
+    msg = NULL;
+
+    return 0;
+}
+
+
+/**
+ * myds_endcall()
+ * override for i_delivery_service.end_call().
+ * typedef int (*etch_delvisvc_endcall)(void* thisx, i_mailbox*, etch_type*, void** out); 
+ * message response received. close mailbox and return response.
+ * @param mbox the current mailbox (interface), caller retains.
+ * @param response_type type of the response message, caller retains.
+ * @param out pointer to caller's location to receive the message response object.
+ * @return 0 success, -1 failure. response object returned via out parameter.
+ * @remarks assumed that the reply message and its wrapper are destroyed with the mailbox.
+ */
+static int myds_endcall (i_delivery_service* thisx, i_mailbox* mbox, etch_type* rtype, void** out)
+{
+    etch_int32* resultobj = new_int32(CLASSID_MY_RESULT);
+    ((etch_object*)resultobj)->class_id = CLASSID_MY_RESULT;
+    gds_what = END_CALL;
+    gds_rtypeid = rtype->id;
+    assert(out);
+    *out = resultobj; 
+    return 0;
+}
+
+
+/* - - - - - - - - - - - - - - - - -  
+ * delivery service i_sessionmessage  
+ * - - - - - - - - - - - - - - - - -  
+ */
+
+/* this is the i_delivery_service implementation of i_sessionmessage,
+ * distinct from the transport.session's implementation of i_sessionmessage
+ * which is implemented externally and set via set_session().
+ */
+
+/**
+ * myds_session_message()
+ * override for i_delivery_service.ism.session_message().
+ * @param whofrom caller retains, can be null.
+ * @param msg caller relinquishes
+ * @return 0 (message handled), or -1 (error, closed, or timeout)  
+ */
+static int myds_session_message (etch_tcp_delivery_service* thisx, etch_who* whofrom, etch_message* msg)
+{
+  etch_object_destroy(msg);
+  msg = NULL;
+
+    return -1;
+}
+
+
+/**
+ * myds_session_control()
+ * override for i_delivery_service.ism.session_control().  
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+static int myds_session_control (etch_tcp_delivery_service* thisx, etch_event* control, etch_object* value)
+{
+    etch_object_destroy(control);
+    control = NULL;
+
+    etch_object_destroy(value);
+    value = NULL;
+
+    return -1;
+}
+
+
+/**
+ * myds_session_notify()
+ * override for i_delivery_service.ism.session_notify().
+ * @param evt event, caller relinquishes.
+ */
+static int myds_session_notify (etch_tcp_delivery_service* thisx, etch_event* evt)
+{
+    etch_object_destroy(evt);
+    evt = NULL;
+
+    return -1;
+}
+
+
+/**
+ * myds_session_query()
+ * override for i_delivery_service.ism.session_query().
+ * @param query, caller relinquishes.
+ */
+static etch_object* myds_session_query (void* data, etch_query* query) 
+{
+    etch_tcp_delivery_service* thisx = (etch_tcp_delivery_service*)data;
+
+    etch_object_destroy(query);
+    query = NULL;
+    return NULL;
+}
+
+
+/* - - - - - - - - - - - - - - - - - -   
+ * delivery service i_transportmessage  
+ * - - - - - - - - - - - - - - - - - -   
+ */
+
+/**
+ * myds_transport_message()
+ * override for i_delivery_service.itm.transport_message().
+ * @param whoto recipient - caller retains 
+ * @param message caller relinquishes on success, retains on failure.  
+ * @return 0 success, -1 error.
+ */
+static int myds_transport_message (etch_tcp_delivery_service* thisx, etch_who* whoto, etch_message* msg)
+{  
+    etch_int64* msgid = NULL;        
+    gds_what = TRANSPORT_MESSAGE;
+    gds_who  = whoto;    
+    msgid = message_get_id(msg);  
+    gds_messageid = msgid? msgid->value: 0;
+    etch_object_destroy(msg);
+    msg = NULL;
+
+    return 0;
+}
+
+
+/**
+ * myds_transport_control()
+ * override for i_delivery_service.itm.transport_control()
+ * @param control caller relinquishes.
+ * @param value caller relinquishes.
+ */
+static int myds_transport_control (void* data, etch_event* control, etch_object* value)
+{
+    etch_tcp_delivery_service* thisx = (etch_tcp_delivery_service*)data;
+    etch_int32* i = NULL;
+    assert(control);
+    gds_what = TRANSPORT_CONTROL;
+    gds_controlval = control->value;
+    i = (etch_int32*)value;
+    gds_valueval   = i? i->value: -1;
+    etch_object_destroy(control);
+    control = NULL;
+
+    etch_object_destroy(value);
+    value = NULL;
+
+    return 0;
+}
+
+
+/**
+ * myds_transport_notify()
+ * override for i_delivery_service.itm.transport_notify()
+ * i_transportmessage::transport_notify override.
+ * @param evt, caller relinquishes.
+ */
+static int myds_transport_notify (etch_tcp_delivery_service* thisx, etch_event* evt)
+{
+    assert(evt);
+    gds_what = TRANSPORT_NOTIFY;
+    gds_eventval = evt->value;
+    etch_object_destroy(evt);
+    return 0;
+}
+
+
+/**
+ * myds_transport_query()
+ * override for i_delivery_service.itm.transport_query()
+ * i_transportmessage::transport_query override.
+ * @param query, caller relinquishes.
+ */
+static etch_object* myds_transport_query (etch_tcp_delivery_service* thisx, etch_query* query) 
+{
+    etch_int32* resultobj = new_int32(CLASSID_MY_RESULT);
+    ((etch_object*)resultobj)->class_id = CLASSID_MY_RESULT;
+    gds_what = TRANSPORT_QUERY;
+    gds_queryval = query->value;
+    etch_object_destroy(query);
+    return (etch_object*) resultobj;
+}
+
+/**
+ * myds_get_session()
+ * override for i_delivery_service.itm.get_session()
+ * i_transportmessage::get_session override.
+ */
+static struct i_sessionmessage* myds_get_session (void* data) 
+{
+    etch_tcp_delivery_service* thisx = (etch_tcp_delivery_service*)data;
+    assert(FALSE);
+    return NULL;
+}
+
+
+/**
+ * myds_set_session()
+ * override for i_delivery_service.itm.set_session()
+ * i_transportmessage::set_session override.
+ */
+static void myds_set_session (etch_tcp_delivery_service* thisx, i_sessionmessage* newsession) 
+{
+    assert(FALSE);
+}
+
+
+/* - - - - - - - - - - - - - - -    
+ * delivery service construction
+ * - - - - - - - - - - - - - - -    
+ */
+
+/**
+ * new_my_delivery_service()
+ */
+static i_delivery_service* new_my_delivery_service()
+{
+    etch_tcp_connection* nullconnection = NULL;
+    etch_tcp_delivery_service* delsvc = NULL;
+    i_sessionmessage*   ism = NULL;
+    i_transportmessage* itm = NULL;
+    etch_client_factory* impl_factory = new_client_factory (NULL, NULL, NULL);
+
+    i_delivery_service* ids = new_etch_transport(L"http://www.cisco.com:9999/cuae", 
+        (etch_factory_params*) impl_factory, nullconnection); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(ids);
+
+    delsvc = ids->thisx;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(delsvc);
+    CU_ASSERT_EQUAL_FATAL(is_etch_deliverysvc(delsvc), TRUE);
+
+    ism = ids->ism;
+    itm = ids->itm; 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(ism);
+    CU_ASSERT_EQUAL_FATAL(is_etch_sessionmsg(ism), TRUE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(itm);
+    CU_ASSERT_EQUAL_FATAL(is_etch_transportmsg(itm), TRUE);
+
+    /* override delivery service i_sessionmessage to implementations herein */
+    ids->begin_call      = delsvc->begin_call      = myds_begincall;
+    ids->end_call        = delsvc->end_call        = myds_endcall;
+    ism->session_message = delsvc->session_message = myds_session_message;
+    ism->session_control = delsvc->session_control = myds_session_control;
+    ism->session_notify  = delsvc->session_notify  = myds_session_notify;
+    ism->session_query   = delsvc->session_query   = myds_session_query;
+
+    /* override delivery service i_transportmessage to implementations herein.
+     * note that we swap out the virtuals, but the not the itm object, which
+     * is the ds transport, which is the mailbox manager's itm. the mailbox
+     * manager owns it and will destroy it when destroyed during destruction  
+     * of the delivery service.
+     */
+    itm->transport_message = delsvc->transport_message = myds_transport_message;
+    itm->transport_control = delsvc->transport_control = myds_transport_control;
+    itm->transport_notify  = delsvc->transport_notify  = myds_transport_notify;
+    itm->transport_query   = delsvc->transport_query   = myds_transport_query;
+    itm->get_session       = delsvc->get_session       = myds_get_session;
+    itm->set_session       = delsvc->set_session       = myds_set_session;
+
+    return ids;
+}
+
+
+/* - - - - - - - - - - - - - - - - -  
+ * remote androgynous object 
+ * - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * destroy_my_remoteobj()
+ * destructor for our remote object
+ */
+static int destroy_my_remoteobj(my_remoteobj* thisx)
+{
+  etch_object_destroy(thisx->xxxx_either_base);
+  thisx->xxxx_either_base = NULL;
+
+  etch_object_destroy(thisx->remote_base);
+  thisx->remote_base = NULL;
+
+    return destroy_objectex((etch_object*) thisx);
+}
+
+/**
+ * destroy_my_clientorserver_impl()
+ * destructor for our remoteobj.xxxx_either_base
+ */
+static int destroy_my_clientorserver_impl(i_xxxx_either* thisx)
+{
+    etch_free(thisx->iobjsession);
+    return destroy_objectex((etch_object*) thisx);
+}
+
+
+/**
+ * new_my_clientorserver_impl()
+ * instatiate my_remoteobj.xxxx_either_base
+ */
+static i_xxxx_either* new_my_clientorserver_impl(my_remoteobj* thisx)
+{
+    i_xxxx_either* either_base = (i_xxxx_either*) new_object (sizeof(i_xxxx_either), 
+        ETCHTYPEB_EXESERVERBASE, get_dynamic_classid_unique(&CLASSID_MY_IMPLBASE));
+
+    ((etch_object*)either_base)->destroy = destroy_my_clientorserver_impl;
+
+    either_base->thisx = (etch_object*) thisx;
+    
+    {   /* populate as much of xxxx_either_impl as we need */
+        i_objsession* ios = new_default_objsession_interface (thisx);
+        either_base->iobjsession = ios;
+        either_base->_session_control = ios->_session_control; 
+        either_base->_session_notify  = ios->_session_notify; 
+        either_base->_session_query   = ios->_session_query; 
+    }
+
+    return either_base;
+}
+
+
+/**
+ * new_my_remote_base
+ * instantiates remote base.  
+ * @param ids delivery service -- caller retains.
+ * @param vf default value factory -- caller retains. 
+ * @param ixxxx service interface -- caller retains.
+ */
+static xxxx_remote* new_my_remote_base (void* thisx, 
+    i_delivery_service* ids, etch_value_factory* vf, etch_object* ixxxx)
+{
+    xxxx_remote* remote = new_etch_remote_base (thisx, ETCH_DEFSIZE, 
+        get_dynamic_classid_unique(&CLASSID_MY_REMOTEBASE), ids, vf, ixxxx);
+ 
+    return remote;
+}
+
+
+/**
+ * new_my_remote_client_or_server()
+ * instatiate and return an implementing object for the remote base.
+ */
+static my_remoteobj* new_my_remote_client_or_server (void* thisx, i_delivery_service* ids, etch_value_factory* vf)
+{
+    /* for these tests it doesn't matter whether we use obj_type of client or server */
+    my_remoteobj* remoteobj = (my_remoteobj*) new_object (sizeof(my_remoteobj), 
+        ETCHTYPEB_REMOTESERVER, get_dynamic_classid_unique(&CLASSID_MY_REMOTEIMPL)); 
+
+    ((etch_object*)remoteobj)->destroy = destroy_my_remoteobj;
+    remoteobj->remote_base = new_my_remote_base (remoteobj, ids, vf, NULL);
+    remoteobj->xxxx_either_base = new_my_clientorserver_impl(remoteobj);
+
+    return remoteobj;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - -
+ * unit tests
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_setup()
+ * test instantiation and teardown of test components such as delivery service,
+ * value factory, etc.
+ */
+static void test_setup(void)
+{
+    setup_this_test();
+
+    do
+    {  
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_new_message()
+ */
+static void test_new_message(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0;   
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf);  
+
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through etchremote_new_message() */
+        etch_message* newmsg = remote->new_message(remote, g_mt_foo);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(newmsg);
+
+        result = is_equal_types(message_type(newmsg), g_mt_foo);
+        CU_ASSERT_EQUAL(result, TRUE);  
+
+        CU_ASSERT_PTR_EQUAL(newmsg->vf, g_my_vf);
+
+        etch_object_destroy(newmsg);
+        etch_object_destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_send()
+ */
+static void test_send(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, MSGIDVAL = 54321; 
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+ 
+        etch_remote*  remote = myremote->remote_base;
+        etch_message* newmsg = remote->new_message (myremote->remote_base, g_mt_foo);
+        message_set_id (newmsg, new_int64(MSGIDVAL));
+
+        /* this call goes through delivery service.transport_message,
+         * which we overrode to myds_transport_message() above.
+         */
+        result = remote->send (remote, newmsg);  /* send message */
+
+        CU_ASSERT_EQUAL(result, 0);  
+        CU_ASSERT_EQUAL(TRANSPORT_MESSAGE, gds_what);
+        CU_ASSERT_EQUAL(gds_messageid, MSGIDVAL);
+
+        if (0 != result) /* message was relinquished on send() success */
+	    {
+	        etch_object_destroy(newmsg);
+	        newmsg = NULL;
+
+	    }
+
+        ((etch_object*)myremote)->destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_begincall()
+ */
+static void test_begincall(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, MSGIDVAL = 65432; 
+        i_mailbox* outmbox = NULL;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+  
+        etch_remote*  remote = myremote->remote_base;
+        etch_message* newmsg = remote->new_message (myremote->remote_base, g_mt_foo);
+        message_set_id (newmsg, new_int64(MSGIDVAL));
+
+        /* this call goes through delivery service.begin_call,
+         * which we overrode to myds_begincall() above.
+         */
+        result = remote->begin_call (remote, newmsg, &outmbox);
+
+        CU_ASSERT_EQUAL(result, 0);  
+        CU_ASSERT_EQUAL(BEGIN_CALL, gds_what);
+        CU_ASSERT_EQUAL(gds_messageid, MSGIDVAL);
+        CU_ASSERT_PTR_EQUAL(g_my_ibox, outmbox);
+
+        if (0 != result) /* message was relinquished on begin_call() success */
+	    {
+    	    etch_object_destroy(newmsg);
+	        newmsg = NULL;
+	    }
+
+        etch_object_destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_endcall()
+ */
+static void test_endcall(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0;
+        etch_object* resultobj = NULL;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+  
+        etch_remote*  remote = myremote->remote_base;
+    
+        /* this call goes through delivery service.end_call,
+         * which we overrode to myds_endcall() above.
+         */
+        result = remote->end_call (remote, g_my_ibox, g_mt_bar, &resultobj);
+
+        CU_ASSERT_EQUAL(result, 0);  
+        CU_ASSERT_EQUAL(END_CALL, gds_what);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(resultobj);
+        CU_ASSERT_EQUAL(((etch_object*)resultobj)->class_id, CLASSID_MY_RESULT); 
+        CU_ASSERT_EQUAL(g_mt_bar->id, gds_rtypeid); 
+        
+	    etch_object_destroy(resultobj);
+	    resultobj = NULL;
+
+
+        etch_object_destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_query()
+ */
+static void test_transport_query(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0, THISQUERYVAL = 76543;
+        etch_object* resultobj = NULL;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through delivery service.transport_query,
+         * which we overrode to myds_transport_query() above.
+         */
+        resultobj = remote->transport_query (remote, new_etch_query(0, THISQUERYVAL));
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(resultobj); 
+        CU_ASSERT_EQUAL(((etch_object*)resultobj)->class_id, CLASSID_MY_RESULT); 
+        CU_ASSERT_EQUAL(TRANSPORT_QUERY, gds_what);
+
+	    etch_object_destroy(resultobj);
+	    resultobj = NULL;
+
+        etch_object_destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_control()
+ */
+static void test_transport_control(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0, THISCTLVAL = 87654, THISVALVAL = 98765;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through delivery service.transport_control,
+         * which we overrode to myds_transport_control() above.
+         */
+        result = remote->transport_control (remote, new_etch_control(0, THISCTLVAL), new_int32(THISVALVAL));
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(TRANSPORT_CONTROL, gds_what);
+        CU_ASSERT_EQUAL(gds_controlval, THISCTLVAL);
+        CU_ASSERT_EQUAL(gds_valueval, THISVALVAL);
+
+        etch_object_destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_notify()
+ */
+static void test_transport_notify(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0, THISEVTVAL = 45678;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through delivery service.transport_notify,
+         * which we overrode to myds_transport_notify() above.
+         */
+        result = remote->transport_notify (remote, new_etch_event(0, THISEVTVAL));
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(TRANSPORT_NOTIFY, gds_what);
+        CU_ASSERT_EQUAL(gds_eventval, THISEVTVAL);
+
+        etch_object_destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_start_waitup()
+ */
+static void test_start_waitup(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0, THISWAITMS = 3000;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through delivery service.transport_control,
+         * which we overrode to myds_transport_control() in our ds constuctor 
+         * above. so we're not testing an actual connection waitup, we're testing
+         * that the call reaches delivery service.transport_control(), and that
+         * we can override delivery service.transport_control() at will.
+         */
+
+        result = remote->start_waitup(remote, ETCH_NOWAIT);
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(TRANSPORT_CONTROL, gds_what);
+        CU_ASSERT_EQUAL(gds_controlval, ETCH_NOWAIT);  
+
+        result = remote->start_waitup(remote, THISWAITMS);
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(gds_controlval, THISWAITMS);       
+
+        etch_object_destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_stop_waitdown()
+ */
+static void test_stop_waitdown(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, resultval = 0, THISWAITMS = 3000;
+
+        my_remoteobj* myremote = new_my_remote_client_or_server (NULL, 
+            g_my_ds, (etch_value_factory*) g_my_vf); 
+        etch_remote*  remote = myremote->remote_base;
+
+        /* this call goes through delivery service.transport_control,
+         * which we overrode to myds_transport_control() in our ds constuctor 
+         * above. so we're not testing an actual connection waitdown, we're testing
+         * that the call reaches delivery service.transport_control(), and that
+         * we can override delivery service.transport_control() at will.
+         */
+
+        result = remote->stop_waitdown(remote, ETCH_NOWAIT);
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(TRANSPORT_CONTROL, gds_what);
+        CU_ASSERT_EQUAL(gds_controlval, ETCH_NOWAIT);  
+
+        result = remote->stop_waitdown(remote, THISWAITMS);
+
+        CU_ASSERT_EQUAL(result, 0); 
+        CU_ASSERT_EQUAL(gds_controlval, THISWAITMS);       
+
+        etch_object_destroy(myremote);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+#endif
+
+CU_pSuite test_etch_remote_suite()
+{
+    CU_pSuite ps = CU_add_suite("remote base test suite", init_suite, clean_suite);
+        
+    // THESE TESTS ARE BROKEN
+    // TODO first fix the stub tests per java tests, then redo these tests similarly.
+    //CU_add_test(ps, "test test setup and teardown", test_setup);
+    //CU_add_test(ps, "test remote.new_message", test_new_message);
+    //CU_add_test(ps, "test remote.send", test_send);
+    //CU_add_test(ps, "test remote.begin_call", test_begincall);
+    //CU_add_test(ps, "test remote.end_call", test_endcall);
+    //CU_add_test(ps, "test remote.transport_query", test_transport_query);
+    //CU_add_test(ps, "test remote.transport_control", test_transport_control);
+    //CU_add_test(ps, "test remote.transport_notify", test_transport_notify);
+    //CU_add_test(ps, "test remote.start_waitup", test_start_waitup);
+    //CU_add_test(ps, "test remote.stop_waitdown", test_stop_waitdown);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/support/test_stub.c b/binding-c/runtime/c/src/test/support/test_stub.c
new file mode 100644
index 0000000..e24ffa7
--- /dev/null
+++ b/binding-c/runtime/c/src/test/support/test_stub.c
@@ -0,0 +1,1358 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_stub.c
+ * test stub, delivery service, etc.
+ */
+
+
+#include "etch_runtime.h"
+#include "etch_svcobj_masks.h"
+#include "etch_transport.h"  
+#include "etch_thread.h"
+#include "etch_object.h"
+#include "etch_stub.h"
+#include "etch_default_value_factory.h"
+#include "etch_plain_mailbox_manager.h"
+#include "etch_transport.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_map.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+#ifdef _WIN32
+#pragma message ( "this testsuite is not active" )
+#else
+#warning "this testsuite is not active"
+#endif
+
+#if 0
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * unit test support
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+#define THISTEST_WHO_VALUE 0x5151
+
+static unsigned short CLASSID_MY_VF;
+static unsigned short CLASSID_MY_VF_VTAB;
+static unsigned short CLASSID_MY_VF_IMPL;
+static unsigned short CLASSID_MY_IMPLOBJ;
+static unsigned short CLASSID_MY_IMPLBASE;
+
+static default_value_factory* new_fake_valuefactory();
+static etch_server_factory* new_my_stubparams(xxxx_either_impl*, etch_threadpool* qp, etch_threadpool* fp);
+
+static i_delivery_service* new_my_delivery_service();
+static etch_thread* thistest_proxy_threadpool_run (etch_threadpool*, etch_threadproc, void*);
+static char* LOGSRC = "TEST";
+ 
+typedef enum whats
+{ TRANSPORT_MESSAGE = 1, TRANSPORT_QUERY, TRANSPORT_CONTROL, TRANSPORT_NOTIFY,
+  SESSION_QUERY, SESSION_CONTROL, SESSION_NOTIFY, HOWDY,
+} whats;
+
+static etch_resources*         g_my_resources;
+static default_value_factory*  g_my_vf;
+static i_delivery_service*     g_my_ds;
+static i_delivery_service*     g_my_transport; /* alias for g_my_ds */
+static etch_tcp_delivery_service* g_my_dsimpl;
+static i_xxxx_either*          g_my_iserver;
+static etch_threadpool*        g_qpool;
+static etch_threadpool*        g_fpool;
+static etch_who*               g_who;
+static etch_type*              g_mt_howdy;
+static etch_type*              g_mt_nogood;
+static etch_server_factory*    g_stubparams; 
+static int                     g_is_run_on_queued_pool;
+static int                     g_is_run_on_free_pool;
+static int                     g_stub_errors;
+static etch_run                g_real_fpool_run;  /* saved threadpool run procs */
+static etch_run                g_real_qpool_run;
+
+static etch_who*               gds_who;
+static etch_message*           gds_message;   
+static etch_int32*             gds_query_result;
+static int                     gds_what;
+static int                     gds_eventval;
+static int                     gds_queryval;
+static int                     gds_controlval;
+static int                     gds_valueval;
+
+static etch_who*               gsv_who;
+static etch_message*           gsv_message;   
+static etch_int32*             gsv_query_result;
+static i_delivery_service*     gsv_ds;
+static int                     gsv_what;
+static int                     gsv_eventval;    
+static int                     gsv_queryval;
+static int                     gsv_controlval;
+static int                     gsv_valueval;
+
+
+/**
+ * new_my_resources()
+ * resources map constructor
+ */
+static etch_resources* new_my_resources(void* valuefactory)
+{   
+    etch_resources* resx = get_etch_transport_resources(NULL);
+    etch_resources_add(resx, ETCH_RESXKEY_MSGIZER_VALUFACT, valuefactory); 
+
+    g_qpool = (etch_threadpool*) etch_resources_get (resx, ETCH_RESXKEY_POOLTYPE_QUEUED); 
+    g_real_qpool_run = g_qpool->run; /* save the real run procedure */
+    g_qpool->run = thistest_proxy_threadpool_run; /* intercept the queued pool run */
+
+    g_fpool = (etch_threadpool*) etch_resources_get (resx, ETCH_RESXKEY_POOLTYPE_FREE); 
+    g_real_fpool_run = g_fpool->run; /* save the real run procedure */
+    g_fpool->run = thistest_proxy_threadpool_run; /* intercept the free pool run */
+
+    return resx;
+}
+
+
+/**
+ * setup_this_test()
+ * set up an individual unit test
+ */
+static int setup_this_test()
+{
+    CLASSID_MY_VF      = get_dynamic_classid();
+    CLASSID_MY_VF_VTAB = get_dynamic_classid();
+    CLASSID_MY_VF_IMPL = get_dynamic_classid();
+    #if(IS_DEBUG_CONSOLE)
+    printf("\n");
+    #endif
+
+    g_my_vf = new_fake_valuefactory();  
+    set_etchobj_static_all(g_my_vf);   /* so resources map will not destroy */ 
+ 
+    /* get resources map populated with transport resources such as thread pools */
+    g_my_resources = new_my_resources(g_my_vf);
+
+    //g_my_ds = new_my_delivery_service ();
+    //g_my_transport = g_my_ds; /* alias */
+   
+    g_who = new_who(new_int32(THISTEST_WHO_VALUE));
+    gds_query_result = new_int32(1);
+    gsv_query_result = new_int32(2);
+        
+    //g_my_dsimpl = g_my_ds->thisx;
+    //assert(is_etch_deliverysvc(g_my_dsimpl));
+    //assert(is_etch_sessionmsg(g_my_dsimpl->sessionmsg));
+
+    return 0;
+}
+
+
+/**
+ * setup_this_stub()
+ * setup for stub
+ */
+static int setup_this_stub(xxxx_either_impl* implobj, unsigned char stubtype, 
+    etch_threadpool* qp, etch_threadpool* fp) 
+{  
+    new_my_stubparams(implobj, qp, fp);  
+ 
+    g_my_ds = new_my_delivery_service ();
+    g_my_transport = g_my_ds; /* alias */
+   
+    g_my_dsimpl = g_my_ds->thisx;
+    assert(is_etch_deliverysvc(g_my_dsimpl));
+    assert(is_etch_sessionmsg(g_my_dsimpl->sessionmsg));
+
+    return 0;
+}
+
+
+/**
+ * teardown_this_test()
+ * tear down an individual unit test
+ */
+static void teardown_this_test()
+{ 
+    if (g_my_resources)  
+    {   /* we did a set_etchobj_static_all() on the g_my_vf value factory  
+         * and as a result the map will not destroy it. if we had not done
+         * so, the vf would have been destroyed with the resources map. */
+        etch_object_destroy(g_my_resources);   
+    }
+
+    if (g_my_vf) 
+    {   /* we clear the set_etchobj_static_all() on the g_my_vf value factory  
+         * and as a result we can then destroy it */
+        clear_etchobj_static_all(g_my_vf);
+        etch_object_destroy(g_my_vf);
+    }
+
+    etch_object_destroy(g_my_ds);
+    
+    etch_free(g_stubparams);
+    etch_free(g_my_iserver);
+
+    etch_object_destroy(g_who);
+    etch_object_destroy(gds_message);
+    etch_object_destroy(gds_query_result);
+
+    gds_what  = 0;
+    gds_who   = NULL;
+    g_my_vf   = NULL;
+    g_my_ds   = NULL;
+    g_who     = NULL;
+    g_is_run_on_queued_pool = g_is_run_on_free_pool = g_stub_errors = 0;
+    g_mt_howdy  = g_mt_nogood = NULL;
+    gds_message = NULL;
+    gds_eventval= gds_queryval = gds_controlval = gds_valueval = 0;
+    gds_query_result = NULL;
+    g_my_resources = NULL;
+
+    etch_object_destroy(gsv_message);
+    etch_object_destroy(gsv_query_result);
+
+    gsv_what  = 0;
+    gsv_who   = NULL;
+    gsv_ds    = NULL;
+    gsv_message = NULL;
+    gsv_eventval= gsv_queryval = gsv_controlval = gsv_valueval = 0;
+    g_my_transport = NULL;
+    gsv_query_result = NULL;
+
+    etchvf_free_builtins(); 
+}
+
+
+/* - - - - - - - - - -
+ * stub implementor
+ * - - - - - - - - - - 
+ */
+
+/**
+ * my_implob
+ * xxxx_either_impl with an extra method.
+ * this represents for this test what would be an impl_server or impl_client in practice.
+ */
+typedef struct my_implobj
+{
+    etch_object object;
+
+    i_xxxx_either*  either_base;  /* owned */
+    etch_object*        ixxxx;        /* not owned */
+    xxxx_remote_either* either;   /* not owned */
+
+    int (*destroyex) (void*);  /* user memory destructor */
+
+    /* - - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;  /* owned by base */
+    /* fyi: iobjsession->thisx is my_implobj* */
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - - - - - - - -
+     * custom instance data and methods  
+     * - - - - - - - - - - - - - - - - -
+     */
+
+    int (*howdy) (struct my_implobj*, i_delivery_service*, etch_who*, etch_message*);
+
+} my_implobj;
+
+
+
+/* - - - - - - - - - -
+ * value factory
+ * - - - - - - - - - - 
+ */
+
+/**
+ * my_valufactory_impl
+ * value factory instance data object
+ */
+typedef struct my_valufactory_impl
+{
+    etch_object object;
+
+	etch_type*      mt_howdy;
+    etch_type*      mt_nogood;
+
+} my_valufactory_impl;
+
+
+/**
+ * destroy_my_valufactory_impl()
+ * destructor for inheriting value factory instance data
+ */
+static int destroy_my_valufactory_impl(void* data)
+{
+    my_valufactory_impl* impl = (my_valufactory_impl*)data;
+    if (NULL == impl) return -1;
+
+    if (!is_etchobj_static_content(impl))
+    {
+        destroy_static_type(impl->mt_howdy);
+        destroy_static_type(impl->mt_nogood);
+    }
+
+    return destroy_objectex((etch_object*) impl);
+}
+
+
+/**
+ * new_my_valufactory_impl()
+ * constructor for our value factory's instance data
+ */
+static my_valufactory_impl* new_my_valufactory_impl()
+{
+    unsigned short class_id = CLASSID_MY_VF_IMPL? CLASSID_MY_VF_IMPL: 
+        (CLASSID_MY_VF_IMPL = get_dynamic_classid());
+
+    my_valufactory_impl* impl = (my_valufactory_impl*) new_object
+        (sizeof(my_valufactory_impl), ETCHTYPEB_VALUEFACTIMP, class_id);
+
+    ((etch_object*)impl)->destroy = destroy_my_valufactory_impl;
+
+    impl->mt_howdy  = new_static_type(L"howdy");
+    impl->mt_nogood = new_static_type(L"nogood");
+    g_mt_howdy  = impl->mt_howdy;
+    g_mt_nogood = impl->mt_nogood;
+
+    return impl;
+}
+
+
+/**
+ * new_fake_valuefactory()
+ */
+static default_value_factory* new_fake_valuefactory()
+{
+    my_valufactory_impl* impl = NULL;
+    etchparentinfo* inheritlist = NULL;
+    const unsigned short classid_vf = get_dynamic_classid_unique(&CLASSID_MY_VF);
+    const unsigned short classid_vf_vtab = get_dynamic_classid_unique(&CLASSID_MY_VF_VTAB);
+
+    g_my_vf = new_default_value_factory(NULL, NULL);
+
+   /* ensure parent type keys exist in the (one-based) inheritance list. 
+    * parent class of our custom vf is default_value_factory.
+    * inheritance list is used by validators and object assignment logic.
+    */
+    inheritlist = get_vtab_inheritance_list((etch_object*)g_my_vf, 2, 1, classid_vf_vtab);
+    inheritlist[1].obj_type = ETCHTYPEB_VALUEFACTORY;  
+    inheritlist[1].class_id = CLASSID_VALUEFACTORY;  /* parent class */
+    ((etch_object*)g_my_vf)->class_id = classid_vf;  /* our class */
+
+    /* instantiate the custom vf's instance data and assign it to the vf. 
+     * the impl comprises all data specific to the inheriting class, including 
+     * data and methods if any. the default value factory destructor will call 
+     * the destructor on the vf's impl object.
+     */  
+    impl = new_my_valufactory_impl();
+    g_my_vf->impl = (etch_object*) impl;
+    ((struct i_value_factory*)((etch_object*)g_my_vf)->vtab)->add_type(g_my_vf, impl->mt_howdy);
+    ((struct i_value_factory*)((etch_object*)g_my_vf)->vtab)->add_type(g_my_vf, impl->mt_nogood);
+
+    return g_my_vf;
+}
+
+
+/* - - - - - - - - - -
+ * delivery service
+ * - - - - - - - - - - 
+ */
+
+/**
+ * myds_begincall()
+ * typedef int (*etch_delivsvc_begincall)(void* thisx, etch_message*, void** out);  
+ * @param msg caller relinquishes on success, retains on failure
+ * @param out mailbox interface returned on success
+ * @return 0 success, or -1 failure. new mailbox return in out parameter.
+ */
+static int myds_begincall (void *data, etch_message* msg, void** out)
+{
+    assert(out);
+    *out = NULL;
+    return -1;
+}
+
+
+/**
+ * myds_endcall()
+ * typedef int (*etch_delvisvc_endcall)(void* thisx, i_mailbox*, etch_type*, void** out); 
+ * message response received. close mailbox and return response.
+ * @param mbox the current mailbox (interface), caller retains.
+ * @param response_type type of the response message, caller retains.
+ * @param out pointer to caller's location to receive the message response object.
+ * @return 0 success, -1 failure. response object returned via out parameter.
+ * @remarks assumed that the reply message and its wrapper are destroyed with the mailbox.
+ */
+static int myds_endcall (void* data, i_mailbox* mbox, etch_type* rtype, void** out)
+{
+    assert(out);
+    *out = NULL;
+    return -1;
+}
+
+/* - - - - - - - - - - - - - - - - -  
+ * delivery service i_sessionmessage  
+ * - - - - - - - - - - - - - - - - -  
+ */
+
+/* this is the delivery service interface implementation of i_sessionmessage,
+ * distinct from the transport.session's implementation of i_sessionmessage
+ * which is implemented externally and set via set_session().
+ */
+
+/**
+ * myds_session_message()
+ * @param whofrom caller retains, can be null.
+ * @param msg caller relinquishes
+ * @return 0 (message handled), or -1 (error, closed, or timeout)  
+ */
+static int myds_session_message (void* data, etch_who* whofrom, etch_message* msg)
+{
+    etch_object_destroy(msg);
+    msg = NULL;
+
+    return 0;
+}
+
+
+/**
+ * myds_session_control()
+ * delivery service interface implementation of i_session_message  
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ */
+static int myds_session_control (void* data, etch_event* control, etch_object* value)
+{
+  etch_object_destroy(control);
+  control = NULL;
+
+  etch_object_destroy(value);
+  value = NULL;
+
+    return 0;
+}
+
+
+/**
+ * myds_session_notify()
+ * @param evt event, caller relinquishes.
+ */
+static int myds_session_notify (void* data, etch_event* evt)
+{
+  etch_object_destroy(evt);
+  evt = NULL;
+
+  return 0;
+}
+
+
+/**
+ * myds_session_query()
+ * @param query, caller relinquishes.
+ */
+static etch_object* myds_session_query(void* data, etch_query* query) 
+{
+  etch_object_destroy(query);
+  query = NULL;
+
+  return NULL;
+}
+
+
+/* - - - - - - - - - - - - - - - - - -   
+ * delivery service i_transportmessage  
+ * - - - - - - - - - - - - - - - - - -   
+ */
+
+/**
+ * myds_transport_message()
+ * @param whoto recipient - caller retains 
+ * @param message caller relinquishes on success, retains on failure.  
+ * @return 0 success, -1 error.
+ */
+static int myds_transport_message(void* data, void* whoData, void* messageData)
+{  
+    gds_what = TRANSPORT_MESSAGE;
+    gds_who  = (etch_who*)whoData;
+    etch_object_destroy((etch_message*)messageData);
+
+    return 0;
+}
+
+
+/**
+ * myds_transport_control()
+ * @param control caller relinquishes.
+ * @param value caller relinquishes.
+ */
+static int myds_transport_control (void* data, etch_event* control, etch_object* valueData)
+{
+  etch_int32* value = (etch_int32*)valueData;
+    gds_what = TRANSPORT_CONTROL;
+    gds_controlval = control->value;   
+    gds_valueval   = value->value;                                                        
+    return 0;
+}
+
+
+/**
+ * myds_transport_notify()
+ * i_transportmessage::transport_notify override.
+ * @param evt, caller relinquishes.
+ */
+static int myds_transport_notify (void* data, etch_event* evt)
+{
+    gds_what  = TRANSPORT_NOTIFY;
+    gds_eventval = evt->value;
+    return 0;
+}
+
+
+/**
+ * myds_transport_query()
+ * i_transportmessage::transport_query override.
+ * @param query, caller relinquishes.
+ */
+static etch_object* myds_transport_query (void* data, etch_query* query) 
+{
+    gds_what  = TRANSPORT_QUERY;
+    gds_queryval = query->value;
+    return 0;
+}
+
+/**
+ * myds_get_session()
+ * i_transportmessage::get_session override.
+ */
+static i_session* myds_get_session (void* data) 
+{
+    etch_tcp_delivery_service* thisx = (etch_tcp_delivery_service*)data;
+    return (i_session*)thisx->session;
+}
+
+
+/**
+ * myds_set_session()
+ * i_transportmessage::set_session override.
+ */
+static void myds_set_session (void* data, void* param) 
+{
+    i_delivery_service* ids = (i_delivery_service*)data;
+    i_sessionmessage* newsession = (i_sessionmessage*)param;
+    /* we override methods in the ids itm. the itm object belongs to the ds transport,
+     * which is the mailbox manager. we need to ensure in the real world that the ds
+     * set_session() takes care of housekeeping similarly to this override.
+     */
+    etch_tcp_delivery_service* tcpds = get_etch_ds_impl(ids);
+    assert(is_etch_sessionmsg(newsession));
+    assert(tcpds->session == ids->session);
+    if (tcpds->session) 
+    {   assert(is_etch_sessionmsg(tcpds->session));
+        etch_object_destroy(tcpds->session);
+    }
+    
+    /* replace delivery service impl's sessionmsng with stub's sesssionmsg */
+    tcpds->session = ids->session = newsession;     
+    assert(is_etch_sessionmsg(tcpds->session));  
+
+    /* we say that the ds owns the session, since even though the session belongs 
+     * to the stub, the ds is expected to destroy the stub, and thus the session 
+     * interface along with it. 
+     */
+    ids->is_session_owned = TRUE;
+}
+
+
+/* - - - - - - - - - - - - - - -    
+ * delivery service construction
+ * - - - - - - - - - - - - - - -    
+ */
+
+/**
+ * new_my_delivery_service()
+ */
+static i_delivery_service* new_my_delivery_service()
+{
+    etch_tcp_connection* nullconnection = NULL;
+    etch_tcp_delivery_service* delsvc = NULL;
+    i_sessionmessage*    ism = NULL;
+    i_transportmessage*  itm = NULL;
+
+    i_delivery_service* ids = new_etch_transport(L"http://www.cisco.com:9999/cuae", 
+        (etch_factory_params*) g_stubparams, nullconnection); 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(ids);
+
+    delsvc = ids->thisx;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(delsvc);
+    CU_ASSERT_EQUAL_FATAL(is_etch_deliverysvc(delsvc), TRUE);
+
+    ism = ids->ism;
+    itm = ids->itm; 
+    CU_ASSERT_PTR_NOT_NULL_FATAL(ism);
+    CU_ASSERT_EQUAL_FATAL(is_etch_sessionmsg(ism), TRUE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(itm);
+    CU_ASSERT_EQUAL_FATAL(is_etch_transportmsg(itm), TRUE);
+
+    /* override delivery service i_sessionmessage to implementations herein */
+    ids->begin_call      = delsvc->begin_call      = myds_begincall;
+    ids->end_call        = delsvc->end_call        = myds_endcall;
+    ism->session_message = delsvc->session_message = myds_session_message;
+    ism->session_control = delsvc->session_control = myds_session_control;
+    ism->session_notify  = delsvc->session_notify  = myds_session_notify;
+    ism->session_query   = delsvc->session_query   = myds_session_query;
+
+    /* override delivery service i_transportmessage to implementations herein.
+     * note that we swap out the virtuals, but the not the itm object, which
+     * is the ds transport, which is the mailbox manager's itm. the mailbox
+     * manager owns it and will destroy it when destroyed during destruction  
+     * of the delivery service.
+     */
+    itm->transport_message = delsvc->transport_message = myds_transport_message;
+    itm->transport_control = delsvc->transport_control = myds_transport_control;
+    itm->transport_notify  = delsvc->transport_notify  = myds_transport_notify;
+    itm->transport_query   = delsvc->transport_query   = myds_transport_query;
+    itm->get_session       = delsvc->get_session       = myds_get_session;
+    itm->set_session       = delsvc->set_session       = myds_set_session;
+
+    return ids;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - -
+ * stub's implementing object
+ * - - - - - - - - - - - - - - - - - - -
+ */
+
+/* a stub's object is in practice a server implementation, masked by xxxx_either_impl, 
+ * such as perf_server_impl. the obj_type will be ETCHTYPEB_EXESERVERIMPL -   
+ * which is the type get_session_callbacks_from() recognizes to identify the obj as  
+ * implementing i_objsession. constructors assigning ETCHTYPEB_EXESERVERIMPL are 
+ * new_perf_remote_server() and init_perf_server_impl().
+ * stub.obj becomes this object. the delivery service session is set to the stub.
+ */
+
+#if(0)
+
+CLIENT SIDE
+perf_helper.new_remote_server()
+  remote_server = new_perf_remote_server (NULL, deliverysvc, vf);
+  i_perf_client* myclient = p->client = p->new_client(remote_server);
+  perf_client_stub* client_stub = new_perf_client_stub (p);
+     newstub->stub_base = new_stub (implobj, stubtype, ids, qp, fp);
+        /* set ds session to be stub's i_sessionmessage */
+        ids->itm->set_session (ids->itm, stubbase->isession);
+        /* copy stub implementor's i_objsession to the stub */
+        stubbase->impl_callbacks = etchstub_get_session_callbacks_from (implobj); 
+#endif
+
+
+/* - - - - - - - - - - -
+ * implobj i_objsession 
+ * - - - - - - - - - - - 
+ */
+
+/**
+ * mysv_session_control()
+ * remote server i_objsession._session_control()
+ * @param control event, caller relinquishes.
+ * @param value control value, caller relinquishes.
+ * assuming we return a zero result to etchstub_session_control(), 
+ * etchstub_session_control() assumes the control and value objects have been   
+ * assumed by this method, so we destroy them accordingly.
+ */
+static int mysv_session_control (void* data, etch_event* control, etch_object* param)
+{
+    etch_int32* value = (etch_int32*)param;
+    if (control)
+    {   gsv_controlval = control->value;
+        etch_object_destroy(control);
+    }
+    if (value)
+    {   gsv_valueval = value->value;
+        etch_object_destroy(value);
+    }
+    gsv_what = SESSION_CONTROL;
+    return 0;
+}
+
+
+/**
+ * mysv_session_notify()
+ * remote server i_objsession._session_notify()
+ * @param evt event, caller relinquishes.
+ * assuming we return a zero result to etchstub_session_notify(), 
+ * etchstub_session_notify() assumes the event object has been   
+ * assumed by this method, so we destroy it accordingly.
+ */
+static int mysv_session_notify (void* data, etch_event* evt)
+{
+    if (evt)
+    {   gsv_eventval = evt->value;
+        etch_object_destroy(evt);
+    }
+    gsv_what  = SESSION_NOTIFY;
+    return 0;
+}
+
+
+/**
+ * mysv_session_query()
+ * remote server i_objsession._session_query()
+ * @param query, caller relinquishes. 
+ * assuming we return a non-null result object to etchstub_session_query(), 
+ * etchstub_session_query() assumes the query object has been assumed by 
+ * this method, so we destroy it accordingly.
+ */
+static etch_int32* mysv_session_query (void* data, etch_query* query) 
+{
+    if (query)
+    {   gsv_queryval = query->value;
+        etch_free(query);
+    }
+    gsv_what = SESSION_QUERY;
+    return gsv_query_result;
+}
+
+
+/* - - - - - - - - - - - - - - - - -  
+ * implementing object constructor
+ * - - - - - - - - - - - - - - - - -  
+ */
+
+/**
+ * mysv_howdy
+ * implementation of my_implobj.howdy().
+ */
+static int mysv_howdy (my_implobj* thisx, i_delivery_service* ids, etch_who* who, etch_message* msg)
+{
+    gsv_what = HOWDY;
+    gsv_ds   = ids;
+    gsv_who  = who;
+    gsv_message = msg;
+    return 0;
+}
+
+
+/**
+ * destroy_my_implobj()
+ * destructor for our fake stub impl object
+ */
+static int destroy_my_implobj(void* data)
+{
+    my_implobj* thisx = (my_implobj*)data;
+    etch_free(thisx->either_base->iobjsession);
+    etch_object_destroy(thisx->either_base);
+    thisx->either_base = NULL;
+
+    return destroy_objectex((etch_object*) thisx);
+}
+
+
+/**
+ * new_my_implobj()
+ * instatiate and return an implementing object for the test stub.
+ * the only requisite of the stub's implementing object vis a vis this test,
+ * is that it implement the i_objsession interface. the stub makes this
+ * determination in etchstub_get_session_callbacks_from().
+ */
+static my_implobj* new_my_implobj()
+{
+    i_objsession* ios = NULL;
+
+    /* for the test it doesn't matter whether we use obj_type of client or server,
+     * it needs to be one or the other so etchstub_get_session_callbacks_from() 
+     * will be able to extract its objession interface. in pratice the implementing
+     * object would be either a client implementation or a server implementation,
+     * however the test uses only the session interfaces so the object is androgynous.
+     */
+    my_implobj* implobj = (my_implobj*) new_object (sizeof(my_implobj), 
+        ETCHTYPEB_EXECLIENTIMPL, get_dynamic_classid_unique(&CLASSID_MY_IMPLOBJ)); 
+
+    implobj->either_base = (i_xxxx_either*) new_object (sizeof(i_xxxx_either), 
+        ETCHTYPEB_EXECLIENTBASE, get_dynamic_classid_unique(&CLASSID_MY_IMPLBASE));
+
+    /* populate as much of i_xxxx_either as we need */
+    ((etch_object*)implobj)->destroy = destroy_my_implobj;
+    implobj->either_base->thisx = (etch_object*) implobj;  
+    ios = new_default_objsession_interface (implobj);
+    implobj->either_base->iobjsession = ios;
+    implobj->either_base->_session_control = ios->_session_control = mysv_session_control;
+    implobj->either_base->_session_notify  = ios->_session_notify  = mysv_session_notify;
+    implobj->either_base->_session_query   = ios->_session_query   = mysv_session_query;
+ 
+    /* populate as much of xxxx_either_impl as we need */
+    implobj->iobjsession = ios;
+    implobj->_session_control = ios->_session_control; 
+    implobj->_session_notify  = ios->_session_notify; 
+    implobj->_session_query   = ios->_session_query; 
+
+    implobj->howdy = mysv_howdy; /* custom method */
+    return implobj;
+}
+
+
+/* - - - - - - - - - - -
+ * thread pool override 
+ * - - - - - - - - - - -
+ */
+
+/**
+ * thistest_proxy_run()
+ * intercept of thread pool's run() which susequently calls the real run()
+ */
+static etch_thread* thistest_proxy_threadpool_run (etch_threadpool* pool, etch_threadproc threadproc, void* threaddata)
+{    
+    switch(pool->pooltype)
+    { 
+        case ETCH_THREADPOOLTYPE_FREE:
+             g_is_run_on_free_pool = TRUE;
+             return g_real_fpool_run (pool, threadproc, threaddata);
+
+        case ETCH_THREADPOOLTYPE_QUEUED:
+             g_is_run_on_queued_pool = TRUE;
+             return g_real_qpool_run (pool, threadproc, threaddata);
+    }
+
+    return NULL;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - -
+ * stub 
+ * - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * stubhelper_howdy()
+ * stub helper (execution logic) for the mt_howdy message type. such methods    
+ * conform to typedef opaque_stubhelper and are defined with the stub, and
+ * attached to the type in the stub implementation constructor. 
+ */
+static int mystub_run_howdy (void* stub, i_delivery_service* ds, i_xxxx_either* obj, etch_who* whofrom, etch_message* msg)
+{
+    int result = 0;
+    my_implobj* implobj = NULL;
+    if (NULL == obj || NULL == obj->thisx)
+    {   /* we can't use cunit macros away from the main thread, so we log errors instead */
+        ETCH_LOG(LOGSRC, ETCH_LOG_ERROR, "stub helper object null pointer\n"); 
+        g_stub_errors++;
+        return -1;
+    }
+
+    implobj = (my_implobj*) obj->thisx;
+
+    if (((etch_object*)implobj)->class_id != CLASSID_MY_IMPLOBJ)
+    {   ETCH_LOG(LOGSRC, ETCH_LOG_ERROR, "unexpected stub helper object type\n"); 
+        g_stub_errors++;
+        return -1;
+    }
+
+    /* execute implemented service method */
+    result = implobj->howdy (implobj, ds, whofrom, msg);   
+
+    if (0 != result)
+    {   ETCH_LOG(LOGSRC, ETCH_LOG_ERROR, "service method implementation failed\n"); 
+        g_stub_errors++;
+        return -1;
+    }
+
+    return result;
+}
+
+
+/**
+ * new_my_stubparams()
+ * the stub carries around an etch_server_factory parameter bundle, which
+ * contains not only the server "factories" (virtual constructors, not used
+ * in these tests), but also various other parameters needed by methods which
+ * see the stub, and which a real-world stub would not have access to globally. 
+ * one such parameter is the "server", masked by i_xxxx_either, from which the 
+ * stub helper exepcts to extract the stub implementation object. we therefore
+ * must instantiate one of these objects for the purposes of this test.
+ */
+static etch_server_factory* new_my_stubparams(xxxx_either_impl* implobj, etch_threadpool* qp, etch_threadpool* fp)
+{
+    g_stubparams = new_server_factory (NULL, NULL, NULL, NULL);  
+    g_stubparams->fpool = fp;
+    g_stubparams->qpool = qp;
+    // g_stubparams->in_delsvc = g_my_ds;
+    g_stubparams->in_resx = g_my_resources;    
+    g_stubparams->in_valufact = (etch_value_factory*) g_my_vf;
+    /* params->server is an i_xxxx_server, expected by the stub helper
+     * (mystub_run_howdy in this case) */    
+    g_my_iserver = etch_malloc(sizeof(i_xxxx_either), 0);
+    memset(g_my_iserver, 0, sizeof(i_xxxx_either));
+    g_my_iserver->thisx  = (etch_object*) implobj; 
+    // g_stubparams->server = g_my_iserver;
+    return g_stubparams;
+}
+ 
+
+/**
+ * new_stub()
+ * etch_stub (stub base) constructor. 
+ * since we are testing only the stub base, we don't have access to the value 
+ * factory through it, and so will instead use our global value factory to access 
+ * the howdy message type and then set its stub helper to the above.
+ */
+static etch_stub* new_mystub (xxxx_either_impl* implobj, unsigned char stubtype, 
+    i_delivery_service* ids, etch_threadpool* qp, etch_threadpool* fp) 
+// TODO REMOVE DS FROM THIS API
+{
+    etch_stub* stubbase = NULL;
+    xxxx_either_stub* stubimpl = NULL;
+    i_xxxx_either* stubimplobj = implobj->either_base;
+
+    setup_this_stub(implobj, stubtype, qp, fp);
+    assert(is_etch_sessionmsg(g_my_dsimpl->sessionmsg));
+
+    // stub base is instatiated in new_stubimpl_init()
+    // stubbase = new_stub (implobj, stubtype, g_my_ds, qp, fp);
+
+    stubimpl = new_stubimpl_init (stubimplobj, sizeof(xxxx_either_stub), 
+        stubtype, NULL, g_my_ds, qp, fp, g_stubparams);
+
+    stubbase = stubimpl->stub_base;
+    stubbase->is_implobj_owned = TRUE; /* let stubbase destroy its implobj */
+ 
+    assert(is_etch_sessionmsg(g_my_dsimpl->sessionmsg));
+
+    /* fyi new_stub() has copied the objesession interface from implobj thusly:   
+     * stubbase->impl_callbacks = etchstub_get_session_callbacks_from (implobj); 
+     */
+
+    /* instantiate parameter bundle to provide stubbase helper arguments */
+    // stubbase->params = new_my_stubparams(implobj, qp, fp);   
+    // stubbase->params->stubbase = stubbase;   
+
+    /* these tests call the stubbase's session_message(), session_notify, etc. 
+     * note that the stubbase's i_sessionmessage implementations, which are
+     * etchstub_session_message, etchstub_session_notify(), etc., invoke the
+     * objsession callbacks as set per comment immediately above. 
+     * of particular note is etchstub_session_message, which gets the type
+     * from the message, gets the stubbase "helper" (run procedure) from the message
+     * type, checks the type's async mode, and runs the proc inline or on a thread
+     * accordingly.
+     */
+    etchtype_set_type_stubhelper (g_mt_howdy, mystub_run_howdy);
+    stubbase->session_message = myds_session_message;
+
+    return stubbase;
+}
+
+
+
+/* - - - - - - - - - - - - - - - - - - - - -
+ * unit tests
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_setup()
+ */
+static void test_setup(void)
+{
+    setup_this_test();
+
+    do
+    {   
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_message_1()
+ * test a stub runner run on main thread 
+ */
+static void test_session_message_1(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0;   
+        etch_message* newmsg = NULL;
+        my_implobj* my_session = new_my_implobj (); /* should we move this to setup? */
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_CLIENT, g_my_ds, g_qpool, g_fpool);  
+
+        etchtype_set_async_mode (g_mt_howdy, ETCH_ASYNCMODE_NONE);
+
+        newmsg = new_message (g_mt_howdy, ETCH_DEFSIZE, (etch_value_factory*) g_my_vf);
+
+        /* fyi the default stub->session_message is etchstub_session_message(), 
+         * which we do not override. this method gets the type from the message,
+         * get's the stub helper proc from the type, checks the type's async mode,
+         * and runs the stub helper proc inline or on a thread accordingly.
+         */
+
+        /* todo in some places we pass session_message a delivery service, 
+         * but here we pass the stub. wtf? find the discrepancy and fix it. 
+         * ds can get the stub via its ism.thisx. stub can get ds via stub.params.
+         */
+        result = stub->session_message (stub, g_who, newmsg);
+ 
+        CU_ASSERT_EQUAL(result, 0);  /* 0 indicates message handled */
+        CU_ASSERT_EQUAL(g_stub_errors, 0);  
+        CU_ASSERT_EQUAL(HOWDY, gsv_what); 
+        CU_ASSERT_EQUAL(g_my_transport, gsv_ds);  
+        CU_ASSERT_EQUAL(g_who, gsv_who); 
+        CU_ASSERT_EQUAL(newmsg, gsv_message); 
+        CU_ASSERT_EQUAL(g_is_run_on_queued_pool, FALSE);
+        CU_ASSERT_EQUAL(g_is_run_on_free_pool, FALSE);    
+       
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_message_2()
+ * test a stub runner run on queued thread pool 
+ */
+static void test_session_message_2(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0;   
+        etch_message* newmsg = NULL;
+        my_implobj* my_session = new_my_implobj (); /* should we move this to setup? */
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_CLIENT, g_my_ds, g_qpool, g_fpool);  
+
+        etchtype_set_async_mode (g_mt_howdy, ETCH_ASYNCMODE_QUEUED);
+
+        newmsg = new_message (g_mt_howdy, ETCH_DEFSIZE, (etch_value_factory*) g_my_vf);
+
+        /* fyi the default stub->session_message is etchstub_session_message(), 
+         * which we do not override. this method gets the type from the message,
+         * get's the stub helper proc from the type, checks the type's async mode,
+         * and runs the stub helper proc inline or on a thread accordingly.
+         */
+        result = stub->session_message (stub, g_who, newmsg);
+ 
+        CU_ASSERT_EQUAL(result, 0);  /* 0 indicates message handled */
+        CU_ASSERT_EQUAL(g_stub_errors, 0);  
+        CU_ASSERT_EQUAL(HOWDY, gsv_what); 
+        CU_ASSERT_EQUAL(g_my_transport, gsv_ds);  
+        CU_ASSERT_EQUAL(g_who, gsv_who); 
+        CU_ASSERT_EQUAL(newmsg, gsv_message); 
+
+        /* if we don't implement a queued pool, a free pool was substituted */
+        #if ETCH_HAS_QUEUED_THREADPOOL
+        CU_ASSERT_EQUAL(g_is_run_on_queued_pool, TRUE);
+        CU_ASSERT_EQUAL(g_is_run_on_free_pool, FALSE);  
+        #else
+        CU_ASSERT_EQUAL(g_is_run_on_free_pool, TRUE);  
+        #endif
+       
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_message_3()
+ * test a stub runner run on free thread pool 
+ */
+static void test_session_message_3(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0;   
+        etch_message* newmsg = NULL;
+        my_implobj* my_session = new_my_implobj (); /* should we move this to setup? */
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_CLIENT, g_my_ds, g_qpool, g_fpool);  
+
+        etchtype_set_async_mode (g_mt_howdy, ETCH_ASYNCMODE_FREE);
+
+        newmsg = new_message (g_mt_howdy, ETCH_DEFSIZE, (etch_value_factory*) g_my_vf);
+
+        /* fyi the default stub->session_message is etchstub_session_message(), 
+         * which we do not override. this method gets the type from the message,
+         * get's the stub helper proc from the type, checks the type's async mode,
+         * and runs the stub helper proc inline or on a thread accordingly.
+         */
+        result = stub->session_message (stub, g_who, newmsg);
+ 
+        CU_ASSERT_EQUAL(result, 0);  /* 0 indicates message handled */
+        CU_ASSERT_EQUAL(g_stub_errors, 0);  
+        CU_ASSERT_EQUAL(HOWDY, gsv_what); 
+        CU_ASSERT_EQUAL(g_my_transport, gsv_ds);  
+        CU_ASSERT_EQUAL(g_who, gsv_who); 
+        CU_ASSERT_EQUAL(newmsg, gsv_message); 
+        CU_ASSERT_EQUAL(g_is_run_on_queued_pool, FALSE);
+        CU_ASSERT_EQUAL(g_is_run_on_free_pool, TRUE);  
+       
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_message_4()
+ * test sending a message whose type has no stub runner
+ */
+static void test_session_message_4(void)
+{
+    setup_this_test();
+
+    do 
+    {   int result = 0, was_msg_handled = 0;   
+        etch_message* newmsg = NULL;
+        my_implobj* my_session = new_my_implobj (); /* should we move this to setup? */
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_CLIENT, g_my_ds, g_qpool, g_fpool);  
+
+        newmsg = new_message (g_mt_nogood, ETCH_DEFSIZE, (etch_value_factory*) g_my_vf);
+
+        /* fyi the default stub->session_message is etchstub_session_message(), 
+         * which we do not override. this method gets the type from the message,
+         * get's the stub helper proc from the type, checks the type's async mode,
+         * and runs the stub helper proc inline or on a thread accordingly.
+         */
+        result = stub->session_message (stub, g_who, newmsg);
+
+        was_msg_handled = (0 == result);
+        CU_ASSERT_EQUAL(was_msg_handled, FALSE);   
+        CU_ASSERT_EQUAL(gsv_what, 0); 
+        CU_ASSERT_PTR_NULL(gsv_ds);  
+        CU_ASSERT_PTR_NULL(gsv_who); 
+        CU_ASSERT_PTR_NULL(gsv_message); 
+
+        /* fyi messages are not relinquished on failure 
+         * since caller may want to reroute the message on failure */
+        if (!was_msg_handled)
+            etch_object_destroy(newmsg);
+       
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_query()
+ */
+static void test_session_query(void)
+{
+    setup_this_test();
+
+    do 
+    {   const int THISQUERYVAL = 12345;
+        etch_object* resultobj = NULL;
+        my_implobj* my_session = new_my_implobj ();  
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_SERVER, g_my_ds, g_qpool, g_fpool);  
+
+        resultobj = stub->session_query (stub, new_etch_query(0, THISQUERYVAL));
+
+        CU_ASSERT_PTR_NOT_NULL(resultobj); 
+        CU_ASSERT_PTR_EQUAL(resultobj, gsv_query_result); 
+        CU_ASSERT_EQUAL(SESSION_QUERY, gsv_what);
+        CU_ASSERT_EQUAL(THISQUERYVAL, gsv_queryval);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_control()
+ */
+static void test_session_control(void)
+{
+    setup_this_test();
+
+    do 
+    {   const int THISCONTROLVAL = 12345, THISVALUEVAL = 54321;
+        int result = 0;
+        my_implobj* my_session = new_my_implobj ();  
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_SERVER, g_my_ds, g_qpool, g_fpool);  
+
+        result = stub->session_control (stub, new_etch_control(0, THISCONTROLVAL), new_int32(THISVALUEVAL));
+
+        CU_ASSERT_EQUAL(result,0); 
+        CU_ASSERT_EQUAL(SESSION_CONTROL, gsv_what);
+        CU_ASSERT_EQUAL(THISCONTROLVAL, gsv_controlval);
+        CU_ASSERT_EQUAL(THISVALUEVAL, gsv_valueval);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_notify()
+ */
+static void test_session_notify(void)
+{
+    setup_this_test();
+
+    do 
+    {   const int THISNOTIFYVAL = 12345;
+        int result = 0;
+        my_implobj* my_session = new_my_implobj ();  
+
+        etch_stub* stub = new_mystub ((xxxx_either_impl*) my_session, 
+            ETCH_STUBTYPE_SERVER, g_my_ds, g_qpool, g_fpool);  
+
+        result = stub->session_notify (stub, new_etch_event (0, THISNOTIFYVAL));
+
+        CU_ASSERT_EQUAL(result,0); 
+        CU_ASSERT_EQUAL(SESSION_NOTIFY, gsv_what);
+        CU_ASSERT_EQUAL(THISNOTIFYVAL, gsv_eventval);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+#endif
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_stub_suite()
+{
+    CU_pSuite ps =  CU_add_suite("stub base test suite", init_suite, clean_suite);
+
+    // THESE TESTS ARE BROKEN
+    // TODO go back to java test and reimplement these tests
+    //CU_add_test(ps, "test test setup and teardown", test_setup);
+    //CU_add_test(ps, "test send message main thread", test_session_message_1);
+    //CU_add_test(ps, "test send message queued pool", test_session_message_2);
+    //CU_add_test(ps, "test send message freepool", test_session_message_3);
+    //CU_add_test(ps, "test send message no good", test_session_message_4);   
+    //CU_add_test(ps, "test session query", test_session_query); 
+    //CU_add_test(ps, "test session control", test_session_control); 
+    //CU_add_test(ps, "test session notify", test_session_notify); 
+    
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/test.c b/binding-c/runtime/c/src/test/test.c
new file mode 100644
index 0000000..18b2b7a
--- /dev/null
+++ b/binding-c/runtime/c/src/test/test.c
@@ -0,0 +1,31 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main() {
+  void* t = malloc(0);
+  printf("%x\n", t);
+  printf("%d\n", strlen(0));
+    
+}
diff --git a/binding-c/runtime/c/src/test/test_all.c b/binding-c/runtime/c/src/test/test_all.c
new file mode 100644
index 0000000..fed3fea
--- /dev/null
+++ b/binding-c/runtime/c/src/test/test_all.c
@@ -0,0 +1,102 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "test_all.h"
+
+CU_pSuite test_etchinternal_single_linked_list();
+CU_pSuite test_arraylist_suite();
+CU_pSuite test_cache_suite();
+CU_pSuite test_etch_arrayvalue_suite();
+CU_pSuite test_etch_binarytdit_suite();
+CU_pSuite test_etch_config_suite();
+CU_pSuite test_etch_defvaluefact_suite();
+CU_pSuite test_etch_encoding_suite();
+CU_pSuite test_etch_field_suite();
+CU_pSuite test_etch_flexbuf_suite();
+CU_pSuite test_etch_hashing_suite();
+CU_pSuite test_etch_hashtable_suite();
+CU_pSuite test_etch_idname_suite();
+CU_pSuite test_etch_iterator_suite();
+CU_pSuite test_etch_log_suite();
+CU_pSuite test_etch_mailboxmgr_suite();
+CU_pSuite test_etch_message_suite();
+CU_pSuite test_etch_messagizer_suite();
+CU_pSuite test_etch_mutex_suite();
+CU_pSuite test_etch_packetizer_suite();
+CU_pSuite test_etch_plainmailbox_suite();
+CU_pSuite test_etch_queue();
+CU_pSuite test_etch_remote_suite();
+CU_pSuite test_etch_runtime_suite();
+CU_pSuite test_etch_structvalue_suite();
+CU_pSuite test_etch_stub_suite();
+CU_pSuite test_etch_suite();
+CU_pSuite test_etch_tcpconn_suite();
+CU_pSuite test_etch_thread_suite();
+CU_pSuite test_etch_threadpool_suite();
+CU_pSuite test_etch_transport_suite();
+CU_pSuite test_etch_type_suite();
+CU_pSuite test_etch_url_suite();
+CU_pSuite test_etch_validator_suite();
+CU_pSuite test_etch_wait_suite();
+CU_pSuite test_etchobject_suite();
+CU_pSuite test_etch_linked_list_suite();
+
+suite_creator etch_testlist[] = {
+    test_etch_tcpconn_suite,
+	test_etch_linked_list_suite,
+    test_etchinternal_single_linked_list,
+    test_arraylist_suite,
+    test_cache_suite,
+    test_etch_arrayvalue_suite,
+    test_etch_binarytdit_suite,
+    test_etch_config_suite,
+    test_etch_defvaluefact_suite,
+    test_etch_encoding_suite,
+    test_etch_field_suite,
+    test_etch_flexbuf_suite,
+    test_etch_hashing_suite,
+    test_etch_hashtable_suite,
+    test_etch_idname_suite,
+    test_etch_iterator_suite,
+    test_etch_log_suite,
+    test_etch_message_suite,
+    test_etch_messagizer_suite,
+    test_etch_mutex_suite,
+    test_etch_packetizer_suite,
+    test_etch_queue,
+    test_etch_remote_suite,
+    test_etch_runtime_suite,
+    test_etch_structvalue_suite,
+    test_etch_stub_suite,
+    test_etch_suite,
+    test_etch_thread_suite,
+    test_etch_threadpool_suite,
+    test_etch_transport_suite,
+    test_etch_type_suite,
+    test_etch_url_suite,
+    test_etch_validator_suite,
+    test_etchobject_suite,
+    test_etch_wait_suite,
+    test_etch_mailboxmgr_suite,
+    test_etch_plainmailbox_suite,
+    0
+};
+
diff --git a/binding-c/runtime/c/src/test/test_all.h b/binding-c/runtime/c/src/test/test_all.h
new file mode 100644
index 0000000..39d0ab8
--- /dev/null
+++ b/binding-c/runtime/c/src/test/test_all.h
@@ -0,0 +1,31 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#ifndef _TEST_ALL_H_
+#define _TEST_ALL_H_
+
+#include "CUnit.h"
+
+typedef CU_pSuite (*suite_creator)();
+
+extern suite_creator etch_testlist[];
+
+#endif
diff --git a/binding-c/runtime/c/src/test/transport/test_mailboxmgr.c b/binding-c/runtime/c/src/test/transport/test_mailboxmgr.c
new file mode 100644
index 0000000..e6a4af1
--- /dev/null
+++ b/binding-c/runtime/c/src/test/transport/test_mailboxmgr.c
@@ -0,0 +1,1770 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_mailboxmgr.c 
+ */
+#include "etch_runtime.h"
+#include "etch_plain_mailbox.h"  
+#include "etch_plain_mailbox_manager.h"
+#include "etch_transport_message.h"
+#include "etch_default_value_factory.h"
+#include "etch_map.h"
+#include "etch_log.h"
+#include "etch_exception.h"
+#include "etch_simpletimer.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_object.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - 
+ * unit test support
+ * - - - - - - - - - - - - - -
+ */
+
+
+typedef enum etch_what
+{ WHAT_NONE, 
+  SESSION_MESSAGE,   SESSION_QUERY,   SESSION_CONTROL,   SESSION_NOTIFY,
+  TRANSPORT_MESSAGE, TRANSPORT_QUERY, TRANSPORT_CONTROL, TRANSPORT_NOTIFY,
+} etch_what;
+
+
+static etch_plainmailboxmgr*  g_manager;
+static i_sessionmessage*      g_my_session;
+static i_transportmessage*    g_my_transport; 
+static etch_who*              g_who1;
+static etch_type*             g_type1;
+static etch_mutex*            g_rwlock;
+static default_value_factory* g_vf;
+static vf_idname_map*         g_typemap;
+static class_to_type_map*     g_c2tmap;
+
+static int g_is_unregistered;  
+static int g_mailbox_status;
+
+static unsigned short CLASSID_MY_IMPL_TP;
+static unsigned short CLASSID_MY_IMPL_SM;
+#define OBJTYPE_MY_IMPL_TM 0x5170
+#define OBJTYPE_MY_IMPL_SM 0x5171
+
+#define is_my_impl_tm(x) (x && ((etch_object*)x)->obj_type == OBJTYPE_MY_IMPL_TM) 
+#define is_my_impl_sm(x) (x && ((etch_object*)x)->obj_type == OBJTYPE_MY_IMPL_SM) 
+
+typedef struct my_impl_transportmessage my_impl_transportmessage;
+typedef struct my_impl_sessionmessage   my_impl_sessionmessage;
+
+static my_impl_transportmessage* new_my_impl_transportmessage();
+static my_impl_sessionmessage*   new_my_impl_sessionmessage();
+
+
+#if 0
+/**
+ * mymboxmgr_unregister()
+ * override for mailbox manager unregister
+ */
+static int mymboxmgr_unregister (i_mailbox_manager* imgr, i_mailbox* mbox)
+{
+    g_is_unregistered = TRUE;
+    return 0;
+}
+
+
+/**
+ * mymboxmgr_redeliver()
+ * override for mailbox manager redeliver
+ */
+static int mymboxmgr_redeliver (i_mailbox_manager* imgr, etch_who* whofrom, etch_message* msg)
+{
+    return 0;
+} 
+
+
+/**
+ * my_mailbox_notify()
+ * override for mailbox notify
+ */
+static int my_mailbox_notify (etch_plainmailbox* mbox, i_mailbox* mb, etch_object* state, const int is_closed) 
+{
+    g_mailbox = mb;
+    g_mailbox_state = state;
+    g_mailbox_status = TRUE;
+    g_mailbox_isclosed = is_closed;
+    return 0;
+}
+
+static int is_equal_who(etch_who* who1, etch_who* who2)
+{
+    int n1 = 0, n2 = 0;
+    if (!who1 || !who2) return FALSE;
+    if (((etch_object*)who1)->class_id != CLASSID_WHO || ((etch_object*)who2)->class_id != CLASSID_WHO) return FALSE;
+    if (!who1->value  || !who2->value) return FALSE;
+    if (!is_etch_int32(who1->value) || !is_etch_int32(who2->value)) return FALSE;
+    n1 = ((etch_int32*)who1->value)->value;
+    n2 = ((etch_int32*)who2->value)->value;
+    return n1 == n2;
+}
+#endif
+
+
+/**
+ * new_add_message
+ * convenience method to create a message of type "add"
+ */
+static etch_message* new_add_message()
+{
+    /* this call gets the "add" type from the value factory's types map.  
+     * if the type is not present, one is created and added to the map. the vf's 
+     * types map contains all builtin types, plus user types such as this. when  
+     * the vf is destroyed, its types map is destroyed (if we let the vf create  
+     * its own map at construction time rather than supplying a map to the vf
+     * constructor). when a types map is destroyed, it "destroys" its types.
+     * however builtin types are marked static and so the type destructor will
+     * take no action. user types are not so marked and so will be destroyed
+     * at that time.
+     */
+    etch_type* mt_add = etchtypemap_get_by_name(g_vf->types, L"add");
+    etch_message* newmsg = new_message(mt_add, ETCH_DEFSIZE, (etch_value_factory*) g_vf);
+    etchtype_put_validator(mt_add, clone_field(builtins._mf__message_id), (etch_object*) etchvtor_int64_get(0)); 
+    return newmsg;
+}
+
+
+/**
+ * get_add_result_type
+ */
+static etch_type* get_add_result_type()
+{
+    etch_type* mt_add_result = etchtypemap_get_by_name(g_vf->types, L"add_result");
+    etchtype_put_validator(mt_add_result, clone_field(builtins._mf__message_id), (etch_object*) etchvtor_int64_get(0)); 
+    etchtype_put_validator(mt_add_result, clone_field(builtins._mf__in_reply_to),(etch_object*) etchvtor_int64_get(0));  
+    return mt_add_result;
+}
+
+
+/**
+ * new_add_result_message
+ * convenience method to create a message of type "add_result"
+ */
+static etch_message* new_add_result_message()
+{
+    /* this call gets the "add_result" type from the value factory's types map.  
+     * if the type is not present, one is created and added to the map. the vf's 
+     * types map contains all builtin types, plus user types such as this. when  
+     * the vf is destroyed, its types map is destroyed (if we let the vf create  
+     * its own map at construction time rather than supplying a map to the vf
+     * constructor). when a types map is destroyed, it "destroys" its types.
+     * however builtin types are marked static and so the type destructor will
+     * take no action. user types are not so marked and so will be destroyed
+     * at that time.
+     */
+    etch_type* mt_add_result = get_add_result_type();
+    etch_message* newmsg = new_message(mt_add_result, ETCH_DEFSIZE, (etch_value_factory*) g_vf);
+    return newmsg;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ * my_impl_transportmessage (i_transportmessage implementation) 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * my_impl_transportmessage
+ * test object implementing i_transportmessage
+ */
+//typedef struct my_impl_transportmessage
+struct my_impl_transportmessage
+{
+    unsigned int hashkey;  
+    unsigned short  obj_type; 
+    unsigned short  class_id;
+    struct etch_object* vtab;  
+    int  (*destroy)(void*);
+    void*(*clone)  (void*); 
+    obj_gethashkey  get_hashkey;
+    struct etch_object* parent;
+    etchresult*     result;
+    unsigned int    refcount;
+    unsigned int    length;
+    unsigned char   is_null;
+    unsigned char   is_copy;
+    unsigned char   is_static;
+    unsigned char   reserved;
+
+    /* i_transportmessage interface and methods, plus original destructor
+     * which becomes replaced with a custom destructor to destroy this
+     * object. this is the model for destroying an interface wrapper object
+     * when we do not save and pass around a pointer to the wrapper, but rather
+     * a pointer to the interface. the interface in question, i_transportmessage
+     * in this case, contains a pointer to the wrapper object, in this case a
+     * my_impl_transportmessage*. when the interface is instantiated, its original 
+     * destructor is saved, and is replaced with a destructor which invokes
+     * the wrapper's destructor. the wrapper destructor must then know to 
+     * invoke the interface's original destructor when destroying the interface.
+     */
+    i_transportmessage* ixm;       /* owned */ 
+    etch_object_destructor destroy_transportmessage;  /* i_transportmessage original destructor */
+    etch_transport_message transport_message;   /* transport_message() */
+
+    i_sessionmessage* session;    /* not owned */
+
+    etch_who*       recipient;    /* not owned */
+    etch_message*   msg;          /* not owned */ 
+    etch_what       what;         
+    size_t          bufcount;  
+    char*           buf;          /* owned */    
+    etch_object*    query;        /* owned */
+    etch_object*    query_result; /* owned */
+    etch_object*    control;      /* owned */
+    etch_object*    value;        /* owned */
+    etch_object*    eventx;       /* owned */
+};
+//} my_impl_transportmessage;
+
+
+/**
+ * destroy_my_impl_transportmessage()
+ * my_impl_transportmessage destructor
+ */
+static int destroy_my_impl_transportmessage (void* data)
+{
+  my_impl_transportmessage* thisx = (my_impl_transportmessage*)data;
+    if (!is_etchobj_static_content(thisx))
+    {       /* invoke original i_transportmessage destructor */
+        if (thisx->ixm && thisx->destroy_transportmessage)   
+            thisx->destroy_transportmessage(thisx->ixm);
+
+        if (thisx->buf)
+            etch_free(thisx->buf);
+
+        
+        etch_object_destroy(thisx->query);
+        etch_object_destroy(thisx->query_result);
+        etch_object_destroy(thisx->control);
+        etch_object_destroy(thisx->value);
+        etch_object_destroy(thisx->eventx);
+    }
+
+   return destroy_objectex((etch_object*) thisx);
+}
+
+
+/**
+ * impl_transport_message()
+ * my_impl_transportmessage::transport_message
+ * @param whoto caller retains, can be null
+ * @param fbuf caller retains
+ */
+static int impl_transport_message (void* data, void* who, void* messageData)
+{
+    my_impl_transportmessage* mytm = (my_impl_transportmessage*)data;
+    etch_who* whoto = (etch_who*)who;
+    etch_message* msg = (etch_message*)messageData;
+
+    CU_ASSERT_FATAL(is_my_impl_tm(mytm));
+    mytm->what = TRANSPORT_MESSAGE;
+    mytm->recipient = whoto;
+    mytm->msg = msg;
+    return 0;
+}
+
+
+/**
+ * my_transport_control()
+ * my_impl_transportmessage::itransport::transport_control 
+ */
+static int my_transport_control (my_impl_transportmessage* mytm, etch_object* control, etch_object* value)
+{
+    CU_ASSERT_FATAL(is_my_impl_tm(mytm));
+    mytm->what    = TRANSPORT_CONTROL;
+    mytm->control = control;
+    mytm->value   = value;
+    return 0;
+}
+
+
+/**
+ * my_transport_notify()
+ * my_impl_transportmessage::itransport::transport_notify 
+ */
+static int my_transport_notify (my_impl_transportmessage* mytm, etch_object* evt)
+{
+    CU_ASSERT_FATAL(is_my_impl_tm(mytm));
+    mytm->what   = TRANSPORT_NOTIFY;
+    mytm->eventx = evt;
+    return 0;
+}
+
+
+/**
+ * my_transport_query()
+ * my_impl_transportmessage::itransport::transport_query 
+ */
+static etch_object* my_transport_query (my_impl_transportmessage* mytm, etch_object* query) 
+{
+    etch_object* resultobj = NULL;
+    CU_ASSERT_FATAL(is_my_impl_tm(mytm));
+    resultobj   = mytm->query_result; /* set artificially in test */
+    mytm->what  = TRANSPORT_QUERY;
+    mytm->query = query;
+    mytm->query_result = NULL;
+    return (etch_object*) resultobj;  /* caller owns */
+}
+
+
+/**
+ * my_transport_get_session()
+ * my_impl_transportmessage::itransport::get_session 
+ */
+static i_sessionmessage* my_transport_get_session(my_impl_transportmessage* mytm)
+{
+    CU_ASSERT_FATAL(is_my_impl_tm(mytm));
+    return mytm->session;
+}
+
+
+/**
+ * my_transport_set_session()
+ * my_impl_transportmessage::itransport::set_session
+ */
+static void my_transport_set_session (my_impl_transportmessage* mytm, i_sessionmessage* session)
+{   
+    CU_ASSERT_FATAL(is_my_impl_tm(mytm));
+    mytm->session = session;
+}
+
+
+/*
+ * destroy_my_transportmessage()
+ * i_transportmessage destructor
+ * this destructor will destroy its parent (my_impl_transportmessage), 
+ * which will in turn destroy this object.
+ */
+static int destroy_my_transportmessage (void* data)
+{
+  i_transportmessage* itm = (i_transportmessage*)data;
+    my_impl_transportmessage* mytp = NULL;
+    if (NULL == itm) return -1;
+
+    mytp = itm->thisx;  
+
+    etch_object_destroy(mytp);
+
+    return 0;
+}
+
+
+/**
+ * new_my_impl_transportmessage()
+ * my_impl_transportmessage constructor
+ */
+static my_impl_transportmessage* new_my_impl_transportmessage()
+{
+    i_transportmessage* itp  = NULL;
+    i_transport* itransport = NULL;
+    /* this is a model for dynamic class ID assigment */
+    unsigned short class_id = CLASSID_MY_IMPL_TP? CLASSID_MY_IMPL_TP: (CLASSID_MY_IMPL_TP = get_dynamic_classid());
+
+    my_impl_transportmessage* mytp = (my_impl_transportmessage*) new_object
+        (sizeof(my_impl_transportmessage), OBJTYPE_MY_IMPL_TM, class_id);
+
+    mytp->destroy = destroy_my_impl_transportmessage;
+
+    itransport = new_transport_interface_ex(mytp,
+        (etch_transport_control)     my_transport_control, 
+        (etch_transport_notify)      my_transport_notify, 
+        (etch_transport_query)       my_transport_query,
+        (etch_transport_get_session) my_transport_get_session, 
+        (etch_transport_set_session) my_transport_set_session);
+
+    itp = new_transportmsg_interface(mytp, impl_transport_message, itransport);
+
+    /* save off i_transportmessage destructor */
+    mytp->destroy_transportmessage = ((etch_object*)itp)->destroy;
+
+    /* replace i_transportmessage destructor with one which will destroy this object */
+    ((etch_object*)itp)->destroy = destroy_my_transportmessage;
+
+    /* g_my_transport is set to this interface */
+    mytp->ixm = itp;  
+
+    return mytp;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ * my_impl_sessionmessage (i_sessionmessage implementation) 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * my_impl_sessionmessage
+ * test object implementing i_sessionmessage
+ */
+struct my_impl_sessionmessage
+{
+    etch_object object;
+
+    /*
+     * i_sessionmessage interface and methods, plus original destructor
+     * which becomes replaced with a custom destructor to destroy this
+     * object. this is the model for destroying an interface wrapper object
+     * when we do not save and pass around a pointer to the wrapper, but rather
+     * a pointer to the interface. the interface in question, i_sessionmessage
+     * in this case, contains a pointer to the wrapper object, in this case a
+     * my_impl_sessionmessage*. when the interface is instantiated, its original 
+     * destructor is saved, and is replaced with a destructor which invokes
+     * the wrapper's destructor. the wrapper destructor must then know to 
+     * invoke the interface's original destructor when destroying the interface.
+     */
+    i_sessionmessage* ism;          /* owned */
+    etch_object_destructor destroy_sessionmessage; /* i_sessionmessage original destructor */
+    etch_session_message session_message;  /* session_message() method */
+
+    etch_what       what;
+    etch_who*       sender;         /* not owned */
+    etch_message*   msg;            /* not owned */
+    int             is_msg_handled;
+    etch_object*    query;          /* owned */
+    etch_object*    query_result;   /* owned */
+    etch_object*    control;        /* owned */
+    etch_object*    value;          /* owned */
+    etch_object*    eventx;         /* owned */
+};
+//} my_impl_sessionmessage;
+
+
+
+/**
+ * destroy_my_impl_sessionmessage()
+ * my_impl_sessionmessage destructor
+ */
+static int destroy_my_impl_sessionmessage(void* data)
+{
+  my_impl_sessionmessage* thisx = (my_impl_sessionmessage*)data;
+    if (!is_etchobj_static_content(thisx))
+    {       /* invoke original i_sessionmessage destructor */
+        if (thisx->ism && thisx->destroy_sessionmessage)
+            thisx->destroy_sessionmessage(thisx->ism);
+
+        /* these are objects which would be destroyed in the binding 
+         * by the last method to touch them */
+        etch_object_destroy(thisx->msg);
+
+        etch_object_destroy(thisx->query);
+
+        etch_object_destroy(thisx->query_result);
+
+        etch_object_destroy(thisx->control);
+
+        etch_object_destroy(thisx->value);
+
+        etch_object_destroy(thisx->eventx);
+    }
+
+   return destroy_objectex((etch_object*) thisx);
+}
+
+
+/**
+ * impl_session_message()
+ * my_impl_sessionmessage::ism::session_message.
+ * @param whofrom caller retains, can be null.
+ * @param msg caller abandons
+ */
+static int impl_session_message (void* data, etch_who* whofrom, etch_message* msg)
+{
+    my_impl_sessionmessage* mysm = (my_impl_sessionmessage*)data;
+
+    CU_ASSERT_FATAL(is_my_impl_sm(mysm));
+    mysm->what = SESSION_MESSAGE;
+
+    /* in this emulation we are the session consuming a message. if successful, 
+     * (i.e., the message is handled), the binding will eventually destroy the 
+     * message (the caller relinquishes message memory), and the who object.
+     * if not successful (message not handled) the caller retains message and 
+     * who memory in order to forward the message and who somewhere else
+     * (as an unwanted message). so we model that here: if the message is not 
+     * handled (a manual switch in these tests), we do not save references to
+     * the messaqe and who for cleanup, because the unwanted message, containing
+     * these objects, will be cleaned up instead. 
+     */
+    if (mysm->is_msg_handled)
+    {   
+        mysm->msg = msg;
+        mysm->sender = whofrom;
+        return 0;
+    }
+    
+    mysm->msg = NULL;
+    mysm->sender = NULL;
+    return -1;
+}
+
+
+/**
+ * my_session_control()
+ * my_impl_sessionmessage::ism::isession::session_control 
+ * control and value are always abandoned by caller so mysm must clean them up.
+ */
+static int my_session_control (my_impl_sessionmessage* mysm, etch_object* control, etch_object* value)
+{
+    CU_ASSERT_FATAL(is_my_impl_sm(mysm));
+    mysm->what    = SESSION_CONTROL;
+    mysm->control = control;
+    mysm->value   = value;
+    return 0;
+}
+
+
+/**
+ * my_session_notify()
+ * my_impl_sessionmessage::ism::isession::session_notify 
+ * evt is always abandoned by caller so mysm must clean it up.
+ */
+static int my_session_notify (my_impl_sessionmessage* mysm, etch_object* evt)
+{
+    CU_ASSERT_FATAL(is_my_impl_sm(mysm));
+    mysm->what   = SESSION_NOTIFY;
+    mysm->eventx = evt;
+    return 0;
+}
+
+
+/**
+ * my_session_query()
+ * my_impl_sessionmessage::ism::isession::session_query 
+ * query is always abandoned by caller so mysm must clean it up.
+ */
+static etch_object* my_session_query (my_impl_sessionmessage* mysm, etch_object* query) 
+{
+    etch_object* resultobj = NULL;
+    CU_ASSERT_FATAL(is_my_impl_sm(mysm));
+    resultobj   = mysm->query_result; /* artifically set in test */
+    mysm->what  = SESSION_QUERY;
+    mysm->query = query;
+    mysm->query_result = NULL;
+    return (etch_object*) resultobj; /* caller owns */
+}
+
+
+/*
+ * destroy_my_sessionmessage()
+ * i_sessionmessage destructor
+ * this destructor will destroy its parent (my_impl_sessionmessage), 
+ * which will in turn destroy this object.
+ */
+static int destroy_my_sessionmessage(void* data)
+{
+  i_sessionmessage* ism = (i_sessionmessage*)data;
+    my_impl_sessionmessage* mysm = NULL;
+    if (NULL == ism) return -1;
+
+    mysm = ism->thisx;  
+
+    etch_object_destroy(mysm);
+
+    return 0;
+}
+
+
+/**
+ * new_my_impl_sessionmessage()
+ * my_impl_sessionmessage constructor
+ */
+static my_impl_sessionmessage* new_my_impl_sessionmessage()
+{
+    i_sessionmessage* ism  = NULL;
+    i_session* isession = NULL;
+    /* this is a model for dynamic class ID assigment */
+    unsigned short class_id = CLASSID_MY_IMPL_SM? CLASSID_MY_IMPL_SM: 
+        (CLASSID_MY_IMPL_SM = get_dynamic_classid());
+
+    my_impl_sessionmessage* mysm = (my_impl_sessionmessage*) new_object
+      (sizeof(my_impl_sessionmessage), OBJTYPE_MY_IMPL_SM, class_id);
+
+    ((etch_object*)mysm)->destroy = destroy_my_impl_sessionmessage;
+
+    isession = new_session_interface(mysm,
+        (etch_session_control)     my_session_control, 
+        (etch_session_notify)      my_session_notify, 
+        (etch_session_query)       my_session_query);
+
+    ism = new_sessionmsg_interface(mysm, impl_session_message, isession);
+
+    /* save off i_sessionmessage destructor */
+    mysm->destroy_sessionmessage = ((etch_object*)ism)->destroy;
+
+    /* custom destructor will destroy the my_impl_sessionmessage */
+    ((etch_object*)ism)->destroy = destroy_my_sessionmessage;
+
+    /* g_my_session will get set to this interface */
+    mysm->ism = ism;  
+
+    return mysm;
+}
+
+
+/* - - - - - - - - - - - - - - - 
+ * setup/teardown for each test
+ * - - - - - - - - - - - - - - -
+ */
+
+/**
+ * setup_this_test()
+ * set up an individual unit test
+ */
+static int setup_this_test()
+{
+    my_impl_transportmessage* mytm_impl = NULL;
+    my_impl_sessionmessage*   mysm_impl = NULL;
+
+    g_who1   = new_who(new_int32(1));
+    g_type1  = new_type(L"type1");
+
+    g_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(g_typemap);
+    g_c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(g_c2tmap);  
+    defvf_initialize_static(g_typemap, g_c2tmap);
+    g_vf = new_default_value_factory(g_typemap, g_c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(g_vf);
+
+    // TODO: pool
+    etch_mutex_create(&g_rwlock, ETCH_MUTEX_UNNESTED, NULL);
+
+    etchtype_put_validator(g_type1, clone_field(builtins._mf__message_id), (etch_object*) etchvtor_int64_get(0));
+
+    /* we instantiate a wrapper x which implements and instantiates i_transportmessage.
+     * the instantiation of i_transportmessage will contain a pointer to x.
+     * our global reference g_my_transport is a pointer to the interface.
+     * the purpose of this excercise is that, in the real binding we can pass
+     * around the interface, whose methods can be then invoked without knowing
+     * anything about the wrapper. when we want to reference the wrapper x, 
+     * it is (my_impl_transportmessage) g_my_transport->thisx. 
+     */
+    mytm_impl = new_my_impl_transportmessage();
+    g_my_transport = mytm_impl->ixm;
+
+    mysm_impl = new_my_impl_sessionmessage();
+    g_my_session = mysm_impl->ism;
+
+    g_manager = new_plain_mailbox_manager (g_my_transport, NULL, NULL, g_rwlock); 
+    g_manager->set_session (g_manager, g_my_session);  
+    
+    return g_manager? 0: -1;
+}
+
+
+/**
+ * teardown_this_test()
+ * tear down an individual unit test
+ */
+static void teardown_this_test()
+{
+    etch_object_destroy(g_who1);
+    g_who1 = NULL;
+
+    etch_object_destroy(g_type1);
+    g_type1 = NULL;
+
+    etch_object_destroy(g_vf);
+    g_vf = NULL;
+
+    etch_object_destroy(g_c2tmap);
+    g_c2tmap = NULL;
+
+    etch_object_destroy(g_typemap);
+    g_typemap = NULL;
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+    etch_object_destroy(g_manager);
+    g_manager = NULL;
+
+    etch_mutex_destroy(g_rwlock);
+    g_rwlock = NULL;
+
+    etch_object_destroy(g_my_transport);
+    g_my_transport = NULL;
+
+    etch_object_destroy(g_my_session);
+    g_my_session = NULL;
+
+    g_is_unregistered = g_mailbox_status = 0;
+    etchvf_free_builtins(); 
+}
+
+
+/* - - - - - - - - - - - - - - 
+ * unit tests 
+ * - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_test_setup()
+ * run test setup and teardown and verify all memory accounted for.
+ */
+static void test_test_setup(void)
+{
+    int result = setup_this_test();
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_constructor()
+ */
+static void test_constructor(void)
+{
+    setup_this_test();
+
+    do
+    {  etch_object* session = 0;
+       CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_transport);  /* g_my_transport->thisx = my_impl_transportmessage */
+      
+       session = (etch_object*)g_my_transport->get_session (g_my_transport->thisx);
+       CU_ASSERT(is_etch_sessionmsg(session));
+       CU_ASSERT(is_etch_sessionmsg(g_manager->session));
+       /* used to work, no longer is the case, why are these no longer the same? */
+       // CU_ASSERT_PTR_EQUAL(g_manager->session, session);
+
+       CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_session);
+       CU_ASSERT_PTR_EQUAL(g_my_session, g_manager->get_session (g_manager));
+
+       CU_ASSERT_PTR_EQUAL(g_my_transport, g_manager->transport);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+
+/**
+ * test_session_query
+ */
+static void test_session_query(void)
+{
+    setup_this_test();
+
+    do
+    {   const int MY_QUERY_CLASSID = 0x111, MY_RESULT_CLASSID = 0x112;
+        etch_object* myqueryobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_QUERY_CLASSID);
+        etch_object* myresultob = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_RESULT_CLASSID);
+        etch_object* query_result = NULL;
+        my_impl_sessionmessage* my_sessionimpl = g_my_session->thisx;  
+        my_sessionimpl->query_result = myresultob;
+
+        query_result = g_manager->session_query(g_manager, (etch_query*)myqueryobj);
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(query_result);
+        CU_ASSERT_EQUAL(my_sessionimpl->what, SESSION_QUERY);
+        CU_ASSERT_PTR_EQUAL(my_sessionimpl->query, myqueryobj);
+        CU_ASSERT_PTR_EQUAL(myresultob, query_result);
+        etch_object_destroy(myresultob);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_control
+ */
+static void test_session_control(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0, MY_CONTROL_CLASSID = 0x111, MY_VALUE_CLASSID = 0x112;
+        etch_object* mycontrolobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_CONTROL_CLASSID);
+        etch_object* myvalueobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_VALUE_CLASSID);
+        my_impl_sessionmessage* my_sessionimpl = g_my_session->thisx;  
+
+        result = g_manager->session_control(g_manager, (etch_event*)mycontrolobj, myvalueobj);
+
+        CU_ASSERT_EQUAL(result,0);
+        CU_ASSERT_EQUAL(my_sessionimpl->what, SESSION_CONTROL);
+        CU_ASSERT_PTR_EQUAL(my_sessionimpl->control, mycontrolobj);
+        CU_ASSERT_PTR_EQUAL(my_sessionimpl->value, myvalueobj);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_notify
+ */
+static void test_session_notify(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0, MY_EVENT_CLASSID = 0x111;
+        etch_object* myeventobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_EVENT_CLASSID);
+        my_impl_sessionmessage* my_sessionimpl = g_my_session->thisx;  
+
+        result = g_manager->session_notify(g_manager, (etch_event*)myeventobj);
+
+        CU_ASSERT_EQUAL(result,0);
+        CU_ASSERT_EQUAL(my_sessionimpl->what, SESSION_NOTIFY);
+        CU_ASSERT_PTR_EQUAL(my_sessionimpl->eventx, myeventobj);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_query
+ */
+static void test_transport_query(void)
+{
+    setup_this_test();
+
+    do
+    {   const int MY_QUERY_CLASSID = 0x111, MY_RESULT_CLASSID = 0x112;
+        etch_object* myqueryobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_QUERY_CLASSID);
+        etch_object* myresultob = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_RESULT_CLASSID);
+        etch_object* query_result = NULL;
+        my_impl_transportmessage* my_transportimpl = g_my_transport->thisx;  
+        my_transportimpl->query_result = myresultob;
+
+        query_result = g_manager->transport_query(g_manager, (etch_query*)myqueryobj);
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(query_result);
+        CU_ASSERT_EQUAL(my_transportimpl->what, TRANSPORT_QUERY);
+        CU_ASSERT_PTR_EQUAL(my_transportimpl->query, myqueryobj);
+        CU_ASSERT_PTR_EQUAL(myresultob, query_result);
+        etch_object_destroy(myresultob);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_control
+ */
+static void test_transport_control(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0, MY_CONTROL_CLASSID = 0x111, MY_VALUE_CLASSID = 0x112;
+        etch_object* mycontrolobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_CONTROL_CLASSID);
+        etch_object* myvalueobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_VALUE_CLASSID);
+        my_impl_transportmessage* my_transportimpl = g_my_transport->thisx;  
+
+        result = g_manager->transport_control(g_manager, (etch_event*)mycontrolobj, myvalueobj);
+        CU_ASSERT_EQUAL(result,0);
+        CU_ASSERT_EQUAL(my_transportimpl->what, TRANSPORT_CONTROL);
+        CU_ASSERT_PTR_EQUAL(my_transportimpl->control, mycontrolobj);
+        CU_ASSERT_PTR_EQUAL(my_transportimpl->value, myvalueobj);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_notify
+ */
+static void test_transport_notify(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0, MY_EVENT_CLASSID = 0x111;
+        etch_object* myeventobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_EVENT_CLASSID);
+        my_impl_transportmessage* my_transportimpl = g_my_transport->thisx;  
+
+        result = g_manager->transport_notify(g_manager, (etch_event*)myeventobj);
+        CU_ASSERT_EQUAL(result,0);
+        CU_ASSERT_EQUAL(my_transportimpl->what, TRANSPORT_NOTIFY);
+        CU_ASSERT_PTR_EQUAL(my_transportimpl->eventx, myeventobj);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_message_1()
+ */
+static void test_transport_message_1(void)
+{
+    setup_this_test();
+
+    do
+    {   int  result = 0;
+        i_mailbox* mailbox = NULL;
+        etch_message* addmsg = NULL;
+        etch_int64* addmsg_id = NULL, *addmsg_inreplyto = NULL;
+
+        my_impl_transportmessage* my_transport_impl = (my_impl_transportmessage*) g_my_transport->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport_impl);
+        CU_ASSERT_EQUAL(my_transport_impl->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport_impl->recipient);
+        CU_ASSERT_PTR_NULL(my_transport_impl->msg);
+
+        addmsg = new_add_message();
+        CU_ASSERT_PTR_NOT_NULL_FATAL(addmsg);
+        
+        addmsg_id = message_get_id(addmsg);
+        CU_ASSERT_PTR_NULL(addmsg_id);
+        addmsg_inreplyto = message_get_in_reply_to(addmsg);
+        CU_ASSERT_PTR_NULL(addmsg_inreplyto);
+
+        result = g_manager->transport_message(g_manager, g_who1, addmsg);
+
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(my_transport_impl->what, TRANSPORT_MESSAGE);
+        CU_ASSERT_EQUAL(my_transport_impl->recipient, g_who1);
+        CU_ASSERT_PTR_EQUAL(my_transport_impl->msg, addmsg);
+
+        addmsg_id = message_get_id(addmsg);
+        CU_ASSERT_PTR_NOT_NULL(addmsg_id);
+        addmsg_inreplyto = message_get_in_reply_to(addmsg);
+        CU_ASSERT_PTR_NULL(addmsg_inreplyto);
+
+        mailbox = pmboxmgr_get_mailbox(g_manager, addmsg_id);
+        CU_ASSERT_PTR_NULL(mailbox);
+
+        /* transport does not own the message so we destroy it here.
+         * a real world transport does not have state such as message, however
+         * if the transport is always the message terminal within this test suite
+         * we can destroy the message in the my_impl_transportmessage destructor,
+         * modeling the real world passing on of the message by the transport.
+         */
+        etch_object_destroy(addmsg);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_message_2()
+ */
+static void test_transport_message_2(void)
+{
+    setup_this_test();
+
+    do
+    {   int  result = 0;
+        const int THISTESTID = 1;
+        i_mailbox* mailbox = NULL;
+        etch_message* add_resultmsg = NULL;
+        etch_int64* add_resultmsg_id = NULL, *add_resultmsg_inreplyto = NULL;
+
+        my_impl_transportmessage* my_transport_impl = (my_impl_transportmessage*) g_my_transport->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport_impl);
+        CU_ASSERT_EQUAL(my_transport_impl->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport_impl->recipient);
+        CU_ASSERT_PTR_NULL(my_transport_impl->msg);
+
+        add_resultmsg = new_add_result_message();
+        CU_ASSERT_PTR_NOT_NULL_FATAL(add_resultmsg);
+        
+        add_resultmsg_id = message_get_id(add_resultmsg);
+        CU_ASSERT_PTR_NULL(add_resultmsg_id);
+        add_resultmsg_inreplyto = message_get_in_reply_to(add_resultmsg);
+        CU_ASSERT_PTR_NULL(add_resultmsg_inreplyto);
+
+        result = message_set_in_reply_to(add_resultmsg, new_int64(THISTESTID));
+        CU_ASSERT_EQUAL(result, 0);
+
+        result = g_manager->transport_message(g_manager, g_who1, add_resultmsg);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(my_transport_impl->what, TRANSPORT_MESSAGE);
+        CU_ASSERT_EQUAL(my_transport_impl->recipient, g_who1);
+        CU_ASSERT_PTR_EQUAL(my_transport_impl->msg, add_resultmsg);
+
+        add_resultmsg_id = message_get_id(add_resultmsg);
+        CU_ASSERT_PTR_NOT_NULL(add_resultmsg_id);
+        add_resultmsg_inreplyto = message_get_in_reply_to(add_resultmsg);
+        CU_ASSERT_PTR_NOT_NULL(add_resultmsg_inreplyto);
+        if (add_resultmsg_inreplyto)
+        {   CU_ASSERT_EQUAL(add_resultmsg_inreplyto->value, THISTESTID);
+        }
+
+        mailbox = pmboxmgr_get_mailbox(g_manager, add_resultmsg_id);
+        CU_ASSERT_PTR_NULL(mailbox);
+
+        /* transport does not own the message so we destroy it here.
+         * a real world transport does not have state such as message, however
+         * if the transport is always the message terminal within this test suite
+         * we can destroy the message in the my_impl_transportmessage destructor,
+         * modeling the real world passing on of the message by the transport.
+         */
+        etch_object_destroy(add_resultmsg);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+ 
+/**
+ * test_transport_message_3()
+ * test attempt to send message that has already been sent
+ */
+static void test_transport_message_3(void)
+{
+    setup_this_test();
+
+    do
+    {   int  result = 0;
+        const int THISTESTID = 1;
+        etch_message* addmsg = NULL;
+        etch_int64* addmsg_id = NULL;
+
+        my_impl_transportmessage* my_transport_impl = (my_impl_transportmessage*) g_my_transport->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport_impl);
+        CU_ASSERT_EQUAL(my_transport_impl->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport_impl->recipient);
+        CU_ASSERT_PTR_NULL(my_transport_impl->msg);
+
+        addmsg = new_add_message();
+        CU_ASSERT_PTR_NOT_NULL_FATAL(addmsg);
+        
+        addmsg_id = message_get_id(addmsg);
+        CU_ASSERT_PTR_NULL(addmsg_id);
+        result = message_set_id(addmsg, new_int64(THISTESTID));
+        CU_ASSERT_EQUAL(result, 0);
+        addmsg_id = message_get_id(addmsg);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(addmsg_id);
+
+        result = g_manager->transport_message(g_manager, g_who1, addmsg);
+        CU_ASSERT_EQUAL(result, -1); /* should fail as already sent */
+
+        etch_object_destroy(addmsg);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_call_1()
+ * test sending a call message, then close mailbox for read
+ */
+static void test_transport_call_1(void)
+{
+    setup_this_test();
+
+    do
+    {   int  result = 0;
+        etch_message* addmsg = NULL;
+        etch_plainmailbox* my_mbox_impl = NULL;
+        i_mailbox *mailbox = NULL, *got_mailbox = NULL;
+        etch_int64* addmsg_id = NULL, *addmsg_inreplyto = NULL;
+
+        my_impl_transportmessage* my_transport_impl = (my_impl_transportmessage*) g_my_transport->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport_impl);
+        CU_ASSERT_EQUAL(my_transport_impl->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport_impl->recipient);
+        CU_ASSERT_PTR_NULL(my_transport_impl->msg);
+
+        g_manager->session_notify (g_manager, new_etch_event(0, ETCHEVT_SESSION_UP));
+
+        addmsg = new_add_message();
+        CU_ASSERT_PTR_NOT_NULL_FATAL(addmsg);
+
+        result = g_manager->transport_call (g_manager->imanager, g_who1,addmsg, &mailbox); 
+
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mailbox);
+
+        CU_ASSERT_EQUAL(my_transport_impl->what, TRANSPORT_MESSAGE);
+        CU_ASSERT_EQUAL(my_transport_impl->recipient, g_who1);
+        CU_ASSERT_PTR_EQUAL(my_transport_impl->msg, addmsg);
+
+        result = pmboxmgr_size(g_manager);
+        CU_ASSERT_EQUAL(result, 1);
+
+        addmsg_id = message_get_id(addmsg);
+        CU_ASSERT_PTR_NOT_NULL(addmsg_id);
+        addmsg_inreplyto = message_get_in_reply_to(addmsg);
+        CU_ASSERT_PTR_NULL(addmsg_inreplyto);
+
+        got_mailbox = pmboxmgr_get_mailbox(g_manager, addmsg_id);
+        CU_ASSERT_PTR_NOT_NULL(got_mailbox);
+        CU_ASSERT_PTR_EQUAL(mailbox, got_mailbox);
+
+        mailbox->close_read (mailbox);
+
+        result = pmboxmgr_size(g_manager);
+        CU_ASSERT_EQUAL(result, 0);
+
+        got_mailbox = pmboxmgr_get_mailbox(g_manager, addmsg_id);
+        CU_ASSERT_PTR_NULL(got_mailbox);
+
+        /* in practice the last entity to handle the message would destroy it */
+        etch_object_destroy(addmsg);
+
+        /* it is not yet determined whether the mailbox manager should destroy an
+         * unregistered mailbox - for now it does not, so we destroy it now. */
+        my_mbox_impl = mailbox->thisx;  /* get implementation from interface */
+        etch_object_destroy(my_mbox_impl);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_call_2()
+ * test sending a call message, then close mailbox for delivery
+ */
+static void test_transport_call_2(void)
+{
+    setup_this_test();
+
+    do
+    {   int  result = 0;
+        etch_message* addmsg = NULL;
+        etch_plainmailbox* my_mbox_impl = NULL;
+        i_mailbox *mailbox = NULL, *got_mailbox = NULL;
+        etch_int64* addmsg_id = NULL, *addmsg_inreplyto = NULL;
+
+        my_impl_transportmessage* my_transport_impl = (my_impl_transportmessage*) g_my_transport->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport_impl);
+        CU_ASSERT_EQUAL(my_transport_impl->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport_impl->recipient);
+        CU_ASSERT_PTR_NULL(my_transport_impl->msg);
+
+        g_manager->session_notify(g_manager, new_etch_event(0, ETCHEVT_SESSION_UP));
+
+        addmsg = new_add_message();
+        CU_ASSERT_PTR_NOT_NULL_FATAL(addmsg);
+
+        result = g_manager->transport_call(g_manager->imanager, g_who1,addmsg, &mailbox); 
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mailbox);
+
+        CU_ASSERT_EQUAL(my_transport_impl->what, TRANSPORT_MESSAGE);
+        CU_ASSERT_EQUAL(my_transport_impl->recipient, g_who1);
+        CU_ASSERT_PTR_EQUAL(my_transport_impl->msg, addmsg);
+
+        result = pmboxmgr_size(g_manager);
+        CU_ASSERT_EQUAL(result, 1);
+
+        addmsg_id = message_get_id(addmsg);
+        CU_ASSERT_PTR_NOT_NULL(addmsg_id);
+        addmsg_inreplyto = message_get_in_reply_to(addmsg);
+        CU_ASSERT_PTR_NULL(addmsg_inreplyto);
+
+        got_mailbox = pmboxmgr_get_mailbox(g_manager, addmsg_id);
+        CU_ASSERT_PTR_NOT_NULL(got_mailbox);
+        CU_ASSERT_PTR_EQUAL(mailbox, got_mailbox);
+
+        mailbox->close_delivery(mailbox);
+
+        result = pmboxmgr_size(g_manager);
+        CU_ASSERT_EQUAL(result, 0);
+
+        got_mailbox = pmboxmgr_get_mailbox(g_manager, addmsg_id);
+        CU_ASSERT_PTR_NULL(got_mailbox);
+
+        /* in practice the last entity to handle the message would destroy it */
+        etch_object_destroy(addmsg);
+
+        /* it is not yet determined whether the mailbox manager should destroy an
+         * unregistered mailbox - for now it does not, so we destroy it now. */
+        my_mbox_impl = mailbox->thisx;  /* get implementation from interface */
+        etch_object_destroy(my_mbox_impl);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+   
+/**
+ * test_transport_call_3()
+ * test attempt to send a call message that has already been sent
+ */
+static void test_transport_call_3(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0;
+        i_mailbox* mailbox = NULL;
+        etch_int64* addmsg_id = NULL;
+
+        etch_message* addmsg = new_add_message();
+        CU_ASSERT_PTR_NOT_NULL_FATAL(addmsg);
+        result = message_set_id(addmsg, new_int64(1));  /* set ID essentially marking message sent */
+        CU_ASSERT_EQUAL(result, 0);
+
+        result = g_manager->transport_call(g_manager->imanager, g_who1, addmsg, &mailbox); 
+        CU_ASSERT_NOT_EQUAL(result, 0);  /* result should indicate error, already sent */
+
+        CU_ASSERT_PTR_NULL(mailbox); /* no mailbox should have been created */
+        result = pmboxmgr_size(g_manager);
+        CU_ASSERT_EQUAL(result, 0);
+
+        addmsg_id = message_get_id(addmsg);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(addmsg_id);
+        mailbox = pmboxmgr_get_mailbox(g_manager, addmsg_id);
+        CU_ASSERT_PTR_NULL(mailbox); /* no mailbox should have been created */
+
+        etch_object_destroy(addmsg);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+    
+/**
+ * test_transport_call_4()
+ * test attempt to send a call message that is marked as a reply message
+ */
+static void test_transport_call_4(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0;
+        etch_message* addresultmsg = new_add_result_message();
+        CU_ASSERT_PTR_NOT_NULL_FATAL(addresultmsg);
+        result = message_set_in_reply_to(addresultmsg, new_int64(1));  /* set in reply to ID */
+        CU_ASSERT_EQUAL(result, 0);
+
+        result = g_manager->transport_call(g_manager->imanager, g_who1, addresultmsg, NULL); 
+        CU_ASSERT_NOT_EQUAL(result, 0);  /* result should indicate error, message is a reply */
+
+        result = pmboxmgr_size(g_manager); /* no mailbox should have been created */
+        CU_ASSERT_EQUAL(result, 0);
+
+        etch_object_destroy(addresultmsg);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+  
+/**
+ * test_session_message_1
+ * test reply to a message without a reply to ID
+ */
+void test_session_message_1(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0;
+        etch_message* addmsg = NULL;
+
+        my_impl_sessionmessage* my_sessionimpl = g_my_session->thisx;    
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_sessionimpl);
+        CU_ASSERT_EQUAL(my_sessionimpl->what, 0);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->sender);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->msg);
+         
+        addmsg = new_add_message();
+        CU_ASSERT_PTR_NOT_NULL_FATAL(addmsg);
+
+        my_sessionimpl->is_msg_handled = TRUE;
+                 
+        /* we pass impl rather than interface here - is this right */  
+        /* on success we relinquish ownership of the message to the session */
+                        
+        result = g_manager->session_message(g_manager, g_who1, addmsg);
+
+        CU_ASSERT_EQUAL(result, 0);  /* result should indicate message was handled */
+
+        CU_ASSERT_EQUAL(my_sessionimpl->what, SESSION_MESSAGE);
+        CU_ASSERT_PTR_EQUAL(my_sessionimpl->sender, g_who1);
+        CU_ASSERT_PTR_EQUAL(my_sessionimpl->msg, addmsg);         
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_message_2
+ * test reply to a message without a reply to ID
+ */
+static void test_session_message_2(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0;
+        etch_message* addmsg = NULL;
+
+        my_impl_sessionmessage* my_sessionimpl = g_my_session->thisx;    
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_sessionimpl);
+        CU_ASSERT_EQUAL(my_sessionimpl->what, 0);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->sender);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->msg);
+         
+        addmsg = new_add_message();
+        CU_ASSERT_PTR_NOT_NULL_FATAL(addmsg);
+
+        my_sessionimpl->is_msg_handled = FALSE;  /* the difference from test 1 */
+                 
+        /* we pass impl rather than interface here - is this right */  
+        /* on failure we retain ownership of the message */  
+                      
+        result = g_manager->session_message (g_manager, g_who1, addmsg);
+
+        CU_ASSERT_NOT_EQUAL_FATAL(result, 0);  /* result should indicate message not handled */
+
+        etch_object_destroy(addmsg); /* since session error we still own the message */
+
+        CU_ASSERT_EQUAL(my_sessionimpl->what, SESSION_MESSAGE);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->sender);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->msg);         
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_message_3
+ * test message having reply to ID not matching any mailbox
+ */
+static void test_session_message_3(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0;
+        my_impl_sessionmessage* my_sessionimpl = g_my_session->thisx;    
+
+        etch_message* addresultmsg = new_add_result_message();
+        /* no mailbox should be found for this reply to ID */
+        message_set_in_reply_to(addresultmsg, new_int64(1));   
+             
+        my_sessionimpl->is_msg_handled = TRUE;   
+                 
+        /* we pass impl rather than interface here - is this right */  
+        /* on failure we retain ownership of the message */                        
+        result = g_manager->session_message(g_manager, g_who1, addresultmsg);
+        CU_ASSERT_NOT_EQUAL_FATAL(result, 0);  /* result should indicate message not handled */
+
+        etch_object_destroy(addresultmsg); /* since session error we still own the message */
+
+        CU_ASSERT_EQUAL(my_sessionimpl->what, 0);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->sender);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->msg);         
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_message_5
+ * test message having reply to ID matching an open mailbox
+ */
+static void test_session_message_5(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0;
+        etch_int64* msgid = NULL;
+        etch_type* mt_add_result = NULL;
+        etch_mailbox_element* thiselt = NULL;
+        etch_plainmailbox* my_mbox_impl = NULL;
+        i_mailbox* mailbox = NULL, *got_mailbox = NULL;
+        my_impl_sessionmessage* my_sessionimpl = g_my_session->thisx;  
+        my_impl_transportmessage* my_transport_impl = g_my_transport->thisx;  
+
+        etch_message *replymsg = NULL, *addmsg = new_add_message();
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_sessionimpl);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport_impl);
+
+        g_manager->session_notify(g_manager, new_etch_event(0, ETCHEVT_SESSION_UP));
+
+        result = g_manager->transport_call(g_manager->imanager, g_who1, addmsg, &mailbox); 
+        CU_ASSERT_EQUAL(result, 0);  
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mailbox);
+             
+        CU_ASSERT_EQUAL(my_transport_impl->what, TRANSPORT_MESSAGE);
+        CU_ASSERT_PTR_EQUAL(my_transport_impl->recipient, g_who1);
+        CU_ASSERT_PTR_EQUAL(my_transport_impl->msg, addmsg);
+
+        result = pmboxmgr_size(g_manager);
+        CU_ASSERT_EQUAL(result, 1);
+ 
+        msgid = message_get_id(addmsg);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(msgid);
+        got_mailbox = pmboxmgr_get_mailbox(g_manager, msgid);
+        CU_ASSERT_PTR_EQUAL(got_mailbox, mailbox);
+
+        /* as of now our custom types are not compiled statically. perhaps this will change,
+         * or perhaps we'll simply continue to do it this way in the C binding. */
+        mt_add_result = get_add_result_type();
+
+        /* construct a reply message */
+        replymsg = message_reply(addmsg, mt_add_result);
+        result = is_etch_exception(replymsg);
+        CU_ASSERT_EQUAL_FATAL(result, FALSE);
+        my_sessionimpl->what = WHAT_NONE;
+
+        /* we pass impl rather than interface here - is this right */
+        /* post reply message to mailbox */  
+        /* on success we relinquish ownership of the reply message */                        
+        result = g_manager->session_message(g_manager, g_who1, replymsg);
+        CU_ASSERT_EQUAL_FATAL(result, 0);  /* result should indicate message handled */
+
+        CU_ASSERT_EQUAL(my_sessionimpl->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->sender);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->msg);
+
+        /* pop reply message from the mailbox */
+        result = mailbox->read(mailbox, &thiselt); 
+        CU_ASSERT_EQUAL_FATAL(result, 0);   
+        CU_ASSERT_PTR_EQUAL(thiselt->whofrom, g_who1);
+        CU_ASSERT_PTR_EQUAL(thiselt->msg, replymsg);
+        etch_object_destroy(thiselt);   /* we read it, we own it */
+        replymsg = NULL;  /* thiselt destructor destroyed replymsg */
+
+        result = pmboxmgr_size(g_manager);
+        CU_ASSERT_EQUAL(result, 1);  /* expect one mailbox */
+
+        result = mailbox->close_read(mailbox);
+        CU_ASSERT_EQUAL(result, 0);
+
+        result = pmboxmgr_size(g_manager); /* after close, expect zero mailboxes */
+        CU_ASSERT_EQUAL(result, 0);
+
+        /* in practice the last entity to handle the message would destroy it */
+        etch_object_destroy(addmsg);
+
+        /* it is not yet determined whether the mailbox manager should destroy an
+         * unregistered mailbox - for now it does not, so we destroy it now. */
+        my_mbox_impl = mailbox->thisx;  /* get implementation from interface */
+        etch_object_destroy(my_mbox_impl);    
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_message_6
+ * reply via closed mailbox
+ */
+static void test_session_message_6(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0;
+        etch_int64* msgid = NULL;
+        etch_type* mt_add_result = NULL;
+        etch_plainmailbox* my_mbox_impl = NULL;
+        i_mailbox* mailbox = NULL, *got_mailbox = NULL;
+        my_impl_sessionmessage* my_sessionimpl = g_my_session->thisx;  
+        my_impl_transportmessage* my_transport_impl = g_my_transport->thisx;  
+
+        etch_message *replymsg = NULL, *addmsg = new_add_message();
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_sessionimpl);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport_impl);
+
+        g_manager->session_notify(g_manager, new_etch_event(0, ETCHEVT_SESSION_UP));
+
+        result = g_manager->transport_call(g_manager->imanager, g_who1, addmsg, &mailbox); 
+        CU_ASSERT_EQUAL(result, 0);  
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mailbox);
+             
+        CU_ASSERT_EQUAL(my_transport_impl->what, TRANSPORT_MESSAGE);
+        CU_ASSERT_PTR_EQUAL(my_transport_impl->recipient, g_who1);
+        CU_ASSERT_PTR_EQUAL(my_transport_impl->msg, addmsg);
+
+        result = pmboxmgr_size(g_manager);
+        CU_ASSERT_EQUAL(result, 1);
+ 
+        msgid = message_get_id(addmsg);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(msgid);
+        got_mailbox = pmboxmgr_get_mailbox(g_manager, msgid);
+        CU_ASSERT_PTR_EQUAL(got_mailbox, mailbox);
+
+        result = mailbox->close_read(mailbox);
+        CU_ASSERT_EQUAL(result, 0);
+
+        result = pmboxmgr_size(g_manager);
+        CU_ASSERT_EQUAL(result, 0);   
+
+        /* construct a reply message */
+        mt_add_result = get_add_result_type();
+        replymsg = message_reply(addmsg, mt_add_result);
+        result = is_etch_exception(replymsg);
+        CU_ASSERT_EQUAL_FATAL(result, FALSE);
+        my_sessionimpl->what = WHAT_NONE;
+
+        /* we pass impl rather than interface here - is this right */
+        /* on failure we retain ownership of the reply message */                        
+        result = g_manager->session_message(g_manager, g_who1, replymsg);
+        CU_ASSERT_NOT_EQUAL_FATAL(result, 0);  /* result should indicate message not handled */
+        etch_object_destroy(replymsg); replymsg = NULL;
+
+        CU_ASSERT_EQUAL(my_sessionimpl->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->sender);
+        CU_ASSERT_PTR_NULL(my_sessionimpl->msg);
+
+        /* in practice the last entity to handle the message would destroy it */
+        etch_object_destroy(addmsg);
+
+        /* it is not yet determined whether the mailbox manager should destroy an
+         * unregistered mailbox - for now it does not, so we destroy it now. */
+        my_mbox_impl = mailbox->thisx;  /* get implementation from interface */
+        etch_object_destroy(my_mbox_impl);    
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_mailboxmgr_suite()
+{    
+    CU_pSuite pSuite = CU_add_suite("mailbox manager test suite", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test test setup",  test_test_setup); 
+    CU_add_test(pSuite, "test constructor", test_constructor);
+
+    CU_add_test(pSuite, "test transport query",   test_transport_query);
+    CU_add_test(pSuite, "test transport control", test_transport_control);
+    CU_add_test(pSuite, "test transport notify",  test_transport_notify);
+
+    CU_add_test(pSuite, "test session query",     test_session_query);
+    CU_add_test(pSuite, "test session control",   test_session_control);
+    CU_add_test(pSuite, "test session notify",    test_session_notify);
+
+    CU_add_test(pSuite, "test transport message 1", test_transport_message_1);
+    CU_add_test(pSuite, "test transport message 2", test_transport_message_2);
+    CU_add_test(pSuite, "test transport message 3", test_transport_message_3);
+
+    CU_add_test(pSuite, "test transport call 1",  test_transport_call_1); 
+    CU_add_test(pSuite, "test transport call 2",  test_transport_call_2);         
+    CU_add_test(pSuite, "test transport call 3",  test_transport_call_3);         
+    CU_add_test(pSuite, "test transport call 4",  test_transport_call_4); 
+  
+    CU_add_test(pSuite, "test session message 1", test_session_message_1);
+    CU_add_test(pSuite, "test session message 2", test_session_message_2);
+    CU_add_test(pSuite, "test session message 3", test_session_message_3);
+    CU_add_test(pSuite, "test session message 5", test_session_message_5);
+    CU_add_test(pSuite, "test session message 6", test_session_message_6);
+
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/transport/test_messagizer.c b/binding-c/runtime/c/src/test/transport/test_messagizer.c
new file mode 100644
index 0000000..5525b73
--- /dev/null
+++ b/binding-c/runtime/c/src/test/transport/test_messagizer.c
@@ -0,0 +1,1762 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_messagizer.c 
+ */
+#include "etch_runtime.h"
+#include "etch_messagizer.h"  
+#include "etch_default_value_factory.h"
+#include "etch_thread.h"
+#include "etch_map.h"
+#include "etch_log.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - 
+ * unit test support
+ * - - - - - - - - - - - - - -
+ */
+typedef struct test_value_factory test_value_factory;
+
+static etch_messagizer*        g_my_messagizer;
+static i_transportpacket*      g_my_transportpacket;
+static i_sessionmessage*       g_my_sessionmessage; 
+static etch_flexbuffer*        g_flexbuffer;
+static etch_resources*         g_my_resources;
+static vf_idname_map*          g_type_map;
+static class_to_type_map*      g_class_to_type_map;
+static etch_who*               g_who;
+static default_value_factory*  g_my_vf;
+static test_value_factory*     g_my_test_vf;
+static int g_which_valuefactory;
+
+static unsigned short CLASSID_MY_VF;
+static unsigned short CLASSID_MY_VF_VTAB;
+static unsigned short CLASSID_MY_VF_IMPL;
+static unsigned short CLASSID_MY_IMPL_TP;
+static unsigned short CLASSID_MY_IMPL_SM;
+#define OBJTYPE_MY_IMPL_TP 0x5170
+#define OBJTYPE_MY_IMPL_SM 0x5171
+
+#define is_my_impl_tp(x) (x && ((etch_object*)x)->obj_type == OBJTYPE_MY_IMPL_TP) 
+#define is_my_impl_sm(x) (x && ((etch_object*)x)->obj_type == OBJTYPE_MY_IMPL_SM) 
+
+#define THISTEST_HEADERSIZE 8
+#define TAGDATA_VERSION     3
+#define TYPECODE_EOD_MARK   (-127)
+#define THISTEST_WHO_VALUE 0x5151
+#define WHICHVF_TESTVF 1
+#define WHICHVF_MYVF   2
+#define FAKEID_TYPE_ADD         1 
+#define FAKEID_TYPE_ADD_RESULT  2 
+#define FAKEID_FIELD_X          3 
+#define FAKEID_FIELD_Y          4
+#define FAKEID_FIELD_RESULT     5
+
+static default_value_factory* get_current_valuefactory()
+{
+    if (g_my_test_vf) return (default_value_factory*) g_my_test_vf;
+    if (g_my_vf)      return g_my_vf;  
+    return NULL; 
+}
+
+typedef enum etch_what
+{ WHAT_NONE, 
+  TRANSPORT_PACKET, TRANSPORT_QUERY, TRANSPORT_CONTROL, TRANSPORT_NOTIFY,
+  SESSION_MESSAGE,  SESSION_QUERY,   SESSION_CONTROL,   SESSION_NOTIFY
+} etch_what;
+
+
+static int is_equal_who(etch_who* who1, etch_who* who2)
+{
+    int n1 = 0, n2 = 0;
+    if (!who1 || !who2) return FALSE;
+    if (((etch_object*)who1)->class_id != CLASSID_WHO || ((etch_object*)who2)->class_id != CLASSID_WHO) return FALSE;
+    if (!who1->value  || !who2->value) return FALSE;
+    if (!is_etch_int32(who1->value) || !is_etch_int32(who2->value)) return FALSE;
+    n1 = ((etch_int32*)who1->value)->value;
+    n2 = ((etch_int32*)who2->value)->value;
+    return n1 == n2;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ * my_impl_transportpacket (i_transportpacket implementation) 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * my_impl_transportpacket
+ * test object implementing i_transportpacket
+ */
+typedef struct my_impl_transportpacket
+{
+    etch_object object;
+
+    /* i_transportpacket interface and methods, plus original destructor
+     * which becomes replaced with a custom destructor to destroy this
+     * object. this is the model for destroying an interface wrapper object
+     * when we do not save and pass around a pointer to the wrapper, but rather
+     * a pointer to the interface. the interface in question, i_transportpacket
+     * in this case, contains a pointer to the wrapper object, in this case a
+     * my_impl_transportpacket*. when the interface is instantiated, its original 
+     * destructor is saved, and is replaced with a destructor which invokes
+     * the wrapper's destructor. the wrapper destructor must then know to 
+     * invoke the interface's original destructor when destroying the interface.
+     */
+    i_transportpacket* ixp;       /* owned */ 
+    etch_object_destructor destroy_transportpacket;  /* i_transportpacket original destructor */
+    etch_transport_packet transport_packet;        /* transport_packet() */
+    etch_transport_packet_headersize  header_size; /* header_size() */
+
+    i_sessionpacket* session;     /* not owned */
+
+    etch_who*       recipient;    /* not owned */
+    etch_what       what;          
+    size_t          bufcount;  
+    char*           buf;          /* owned */    
+    etch_object*    query;        /* owned */
+    etch_object*    query_result; /* owned */
+    etch_object*    control;      /* owned */
+    etch_object*    value;        /* owned */
+    etch_object*    eventx;       /* owned */
+
+} my_impl_transportpacket;
+
+
+/**
+ * destroy_my_impl_transportpacket()
+ * my_impl_transportpacket destructor
+ */
+static int destroy_my_impl_transportpacket(void* data)
+{
+    my_impl_transportpacket* thisx = (my_impl_transportpacket*)data;
+    assert(is_my_impl_tp(thisx));
+
+    if (!is_etchobj_static_content(thisx))
+    {       /* invoke original i_transportpacket destructor */
+        if (thisx->ixp && thisx->destroy_transportpacket)   
+            thisx->destroy_transportpacket(thisx->ixp);
+
+        if (thisx->buf)
+            etch_free(thisx->buf);
+
+        
+        etch_object_destroy(thisx->query);
+        etch_object_destroy(thisx->query_result);
+        etch_object_destroy(thisx->control);
+        etch_object_destroy(thisx->value);
+        etch_object_destroy(thisx->eventx);
+    }
+
+   return destroy_objectex((etch_object*) thisx);
+}
+
+
+/**
+ * impl_transport_packet()
+ * my_impl_transportpacket::transport_packet
+ * @param whoto caller retains, can be null
+ * @param fbuf caller retains
+ */
+static int impl_transport_packet (my_impl_transportpacket* mytp, etch_who* whoto, etch_flexbuffer* fbuf)
+{
+    CU_ASSERT_FATAL(is_my_impl_tp(mytp));
+    mytp->what      = TRANSPORT_PACKET;
+    mytp->recipient = whoto;   
+    /* retrieve the packet data. don't skip over header (0 is skip bytes) */
+    mytp->buf = (char*)etch_flexbuf_get_allfrom(fbuf, 0, &mytp->bufcount); 
+    return 0;
+}
+
+
+/**
+ * my_transport_control()
+ * my_impl_transportpacket::itransport::transport_control 
+ */
+static int my_transport_control (my_impl_transportpacket* mytp, etch_object* control, etch_object* value)
+{
+    CU_ASSERT_FATAL(is_my_impl_tp(mytp));
+    mytp->what    = TRANSPORT_CONTROL;
+    mytp->control = control;
+    mytp->value   = value;
+    return 0;
+}
+
+
+/**
+ * my_transport_notify()
+ * my_impl_transportpacket::itransport::transport_notify 
+ */
+static int my_transport_notify (my_impl_transportpacket* mytp, etch_object* evt)
+{
+    CU_ASSERT_FATAL(is_my_impl_tp(mytp)); 
+    mytp->what   = TRANSPORT_NOTIFY;
+    mytp->eventx = evt;
+    return 0;
+}
+
+
+/**
+ * my_transport_query()
+ * my_impl_transportpacket::itransport::transport_query 
+ */
+static etch_object* my_transport_query (my_impl_transportpacket* mytp, etch_object* query) 
+{
+    etch_object* resultobj = NULL;
+    CU_ASSERT_FATAL(is_my_impl_tp(mytp));
+    resultobj = mytp->query_result; /* set artificially in test */
+    mytp->what  = TRANSPORT_QUERY;
+    mytp->query = query;
+    mytp->query_result = NULL;
+    return (etch_object*) resultobj;  /* caller owns */
+}
+
+
+/**
+ * my_transport_get_session()
+ * my_impl_transportpacket::itransport::get_session 
+ */
+static i_sessionpacket* my_transport_get_session(my_impl_transportpacket* mytp)
+{
+    CU_ASSERT_FATAL(is_my_impl_tp(mytp));
+    return mytp->session;
+}
+
+
+/**
+ * my_transport_set_session()
+ * my_impl_transportpacket::itransport::set_session
+ */
+static void my_transport_set_session(my_impl_transportpacket* mytp, i_sessionpacket* session)
+{   
+    CU_ASSERT_FATAL(is_my_impl_tp(mytp));
+    CU_ASSERT_FATAL(is_etch_sessionpacket(session));
+    mytp->session = session;
+}
+
+
+/*
+ * destroy_my_transportpacket()
+ * i_transportpacket destructor
+ * this destructor will destroy its parent (my_impl_transportpacket), 
+ * which will in turn destroy this object.
+ */
+static int destroy_my_transportpacket(void* data)
+{
+    i_transportpacket* itp = (i_transportpacket*)data;
+    my_impl_transportpacket* mytp = NULL;
+    assert(is_etch_transportpkt(itp));
+
+    mytp = itp->thisx;  
+    assert(is_my_impl_tp(mytp));
+
+    etch_object_destroy(mytp);
+
+    return 0;
+}
+
+
+/**
+ * new_my_impl_transportpacket()
+ * my_impl_transportpacket constructor
+ */
+static my_impl_transportpacket* new_my_impl_transportpacket()
+{
+    i_transportpacket* itp  = NULL;
+    i_transport* itransport = NULL;
+    /* this is a model for dynamic class ID assigment */
+    unsigned short class_id = get_dynamic_classid_unique(&CLASSID_MY_IMPL_TP);
+
+    my_impl_transportpacket* mytp = (my_impl_transportpacket*) new_object
+      (sizeof(my_impl_transportpacket), OBJTYPE_MY_IMPL_TP, class_id);
+
+    ((etch_object*)mytp)->destroy = destroy_my_impl_transportpacket;
+
+    itransport = new_transport_interface_ex(mytp,
+        (etch_transport_control)     my_transport_control, 
+        (etch_transport_notify)      my_transport_notify, 
+        (etch_transport_query)       my_transport_query,
+        (etch_transport_get_session) my_transport_get_session, 
+        (etch_transport_set_session) my_transport_set_session);
+
+    itp = new_transportpkt_interface(mytp, (void*)impl_transport_packet, itransport);
+
+    /* default header_size() will return this value so no need to override */
+    itp->header_size = THISTEST_HEADERSIZE; 
+
+    /* save off i_transportpacket destructor */
+    mytp->destroy_transportpacket = ((etch_object*)itp)->destroy;
+
+    /* replace i_transportpacket destructor with one which will destroy this object */
+    ((etch_object*)itp)->destroy = destroy_my_transportpacket;
+
+    /* g_my_transportpacket will get set to this interface */
+    mytp->ixp = itp;  
+
+    return mytp;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ * my_impl_sessionmessage (i_sessionmessage implementation) 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * my_impl_sessionmessage
+ * test object implementing i_sessionmessage
+ */
+typedef struct my_impl_sessionmessage
+{
+    etch_object object;
+    /*
+     * i_sessionmessage interface and methods, plus original destructor
+     * which becomes replaced with a custom destructor to destroy this
+     * object. this is the model for destroying an interface wrapper object
+     * when we do not save and pass around a pointer to the wrapper, but rather
+     * a pointer to the interface. the interface in question, i_sessionmessage
+     * in this case, contains a pointer to the wrapper object, in this case a
+     * my_impl_sessionmessage*. when the interface is instantiated, its original 
+     * destructor is saved, and is replaced with a destructor which invokes
+     * the wrapper's destructor. the wrapper destructor must then know to 
+     * invoke the interface's original destructor when destroying the interface.
+     */
+    i_sessionmessage* ism;          /* owned */
+    etch_object_destructor destroy_sessionmessage; /* i_sessionmessage original destructor */
+    etch_session_message session_message;  /* session_message() method */
+
+    etch_what       what;
+    etch_who*       sender;         /* not owned */
+    etch_message*   msg;            /* not owned */
+    int             is_msg_handled;
+    etch_object*    query;          /* owned */
+    etch_object*    query_result;   /* owned */
+    etch_object*    control;        /* owned */
+    etch_object*    value;          /* owned */
+    etch_object*    eventx;         /* owned */
+
+    i_sessionpacket* session;
+
+} my_impl_sessionmessage;
+
+
+
+/**
+ * destroy_my_impl_sessionmessage()
+ * my_impl_sessionmessage destructor
+ */
+static int destroy_my_impl_sessionmessage(void* data)
+{
+    
+    my_impl_sessionmessage* thisx = (my_impl_sessionmessage*)data;
+    if (!is_etchobj_static_content(thisx))
+    {       /* invoke original i_sessionmessage destructor */
+        if (thisx->ism && thisx->destroy_sessionmessage)
+            thisx->destroy_sessionmessage(thisx->ism);
+
+        /* these are objects which would be destroyed in the binding 
+         * by the last method to touch them */
+        etch_object_destroy(thisx->msg);
+
+        etch_object_destroy(thisx->query);
+
+        etch_object_destroy(thisx->query_result);
+
+        etch_object_destroy(thisx->control);
+
+        etch_object_destroy(thisx->value);
+
+        etch_object_destroy(thisx->eventx);
+    }
+
+   return destroy_objectex((etch_object*) thisx);
+}
+
+
+/**
+ * impl_session_message()
+ * my_impl_sessionmessage::ism::session_message.
+ * @param whofrom caller retains, can be null.
+ * @param msg caller abandons
+ */
+static int impl_session_message (my_impl_sessionmessage* mysm, etch_who* whofrom, etch_message* msg)
+{
+    CU_ASSERT_FATAL(is_my_impl_sm(mysm));
+    mysm->what = SESSION_MESSAGE;
+
+    /* in this emulation we are the session consuming a message. if successful, 
+     * (i.e., the message is handled), the binding will eventually destroy the 
+     * message (the caller relinquishes message memory), and the who object.
+     * if not successful (message not handled) the caller retains message and 
+     * who memory in order to forward the message and who somewhere else
+     * (as an unwanted message). so we model that here: if the message is not 
+     * handled (a manual switch in these tests), we do not save references to
+     * the messaqe and who for cleanup, because the unwanted message, containing
+     * these objects, will be cleaned up instead. 
+     */
+    if (mysm->is_msg_handled)
+    {   
+        mysm->msg = msg;
+        mysm->sender = whofrom;
+        return 0;
+    }
+    
+    mysm->msg = NULL;
+    mysm->sender = NULL;
+    return -1;
+}
+
+
+/**
+ * my_session_control()
+ * my_impl_sessionmessage::ism::isession::session_control 
+ * control and value are always abandoned by caller so mysm must clean them up.
+ */
+static int my_session_control (my_impl_sessionmessage* mysm, etch_object* control, etch_object* value)
+{
+    CU_ASSERT_FATAL(is_my_impl_sm(mysm));
+    mysm->what    = SESSION_CONTROL;
+    mysm->control = control;
+    mysm->value   = value;
+    return 0;
+}
+
+
+/**
+ * my_session_notify()
+ * my_impl_sessionmessage::ism::isession::session_notify 
+ * evt is always abandoned by caller so mysm must clean it up.
+ */
+static int my_session_notify (my_impl_sessionmessage* mysm, etch_object* evt)
+{
+    CU_ASSERT_FATAL(is_my_impl_sm(mysm));
+    mysm->what   = SESSION_NOTIFY;
+    mysm->eventx = evt;
+    return 0;
+}
+
+
+/**
+ * my_session_query()
+ * my_impl_sessionmessage::ism::isession::session_query 
+ * query is always abandoned by caller so mysm must clean it up.
+ */
+static etch_object* my_session_query (my_impl_sessionmessage* mysm, etch_object* query) 
+{
+    etch_object* resultobj = NULL;
+    CU_ASSERT_FATAL(is_my_impl_sm(mysm));
+    resultobj   = mysm->query_result; /* artifically set in test */
+    mysm->what  = SESSION_QUERY;
+    mysm->query = query;
+    mysm->query_result = NULL;
+    return (etch_object*) resultobj; /* caller owns */
+}
+
+
+/*
+ * destroy_my_sessionmessage()
+ * i_sessionmessage destructor
+ * this destructor will destroy its parent (my_impl_sessionmessage), 
+ * which will in turn destroy this object.
+ */
+static int destroy_my_sessionmessage(void* data)
+{
+    i_sessionmessage* ism = (i_sessionmessage*)data;
+    my_impl_sessionmessage* mysm = NULL;
+    if (NULL == ism) return -1;
+
+    mysm = ism->thisx;  
+
+    etch_object_destroy(mysm);
+
+    return 0;
+}
+
+
+/**
+ * new_my_impl_sessionmessage()
+ * my_impl_sessionmessage constructor
+ */
+static my_impl_sessionmessage* new_my_impl_sessionmessage()
+{
+    i_sessionmessage* ism  = NULL;
+    i_session* isession = NULL;
+    /* this is a model for dynamic class ID assigment */
+    unsigned short class_id = CLASSID_MY_IMPL_SM? CLASSID_MY_IMPL_SM: 
+        (CLASSID_MY_IMPL_SM = get_dynamic_classid());
+
+    my_impl_sessionmessage* mysm = (my_impl_sessionmessage*) new_object
+      (sizeof(my_impl_sessionmessage), OBJTYPE_MY_IMPL_SM, class_id);
+
+    ((etch_object*)mysm)->destroy = destroy_my_impl_sessionmessage;
+
+    isession = new_session_interface(mysm,
+        (etch_session_control)     my_session_control, 
+        (etch_session_notify)      my_session_notify, 
+        (etch_session_query)       my_session_query);
+
+    ism = new_sessionmsg_interface(mysm, (void*)impl_session_message, isession);
+
+    /* save off i_sessionmessage destructor */
+    mysm->destroy_sessionmessage = ((etch_object*)ism)->destroy;
+
+    /* custom destructor will destroy the my_impl_sessionmessage */
+    ((etch_object*)ism)->destroy = destroy_my_sessionmessage;
+
+    /* g_my_sessionmessage will get set to this interface */
+    mysm->ism = ism;  
+
+    return mysm;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ * test value factories
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * test_value_factory
+ * value factory version 1
+ * this version uses inherited data coded into the object, as opposed to 
+ * instantiating an impl object to contain inherited data and methods.
+ */
+//typedef struct test_value_factory
+struct test_value_factory
+{
+    etch_object object;
+    /* - - - - - - - - - - - - - 
+     * default value factory  
+     * - - - - - - - - - - - - - 
+     */
+    etch_object* impl;
+
+    class_to_type_map* class_to_type;
+    vf_idname_map*  types;  
+    etch_arraylist* mixins;
+  
+    unsigned char is_own_types;
+    unsigned char is_own_class_to_type;
+
+    /* - - - - - - - - - - - - - 
+     * test value factory  
+     * - - - - - - - - - - - - - 
+     */
+    etch_type*    mt_add;
+    etch_type*    mt_add_result;
+    etch_field*   mf_x;
+    etch_field*   mf_y;
+    etch_field*   mf_result;
+};
+//} test_value_factory;
+
+
+/**
+ * destroy_test_value_factory()
+ * destructor for value factory version 1 
+ */
+static int destroy_test_value_factory(void* data)
+{
+    test_value_factory* vf = (test_value_factory*)data;
+    if (NULL == vf) return -1;
+
+    if (!is_etchobj_static_content(vf))
+    {
+ 	    destroy_static_type(vf->mt_add);
+        destroy_static_type(vf->mt_add_result);
+        destroy_static_field(vf->mf_x); 
+        destroy_static_field(vf->mf_y); 
+        destroy_static_field(vf->mf_result);  
+    }
+
+    return destroy_default_value_factory((default_value_factory*) vf);
+}
+
+
+/**
+ * new_test_valuefactory()
+ * constructor for value factory version 1 inheriting from default_value_factory
+ */
+static test_value_factory* new_test_valuefactory()
+{
+    etchparentinfo* inheritlist = NULL;
+    test_value_factory* vf = NULL;
+
+    g_type_map = new_vf_types_collection(ETCH_DEFSIZE);
+    /* since we explicitly instantiate a type map, and since we explicitly destroy
+     * the test's custom types, we want the type maps destructor to not destroy
+     * the map content. overriding the map's content clear callback is one way 
+     * to do this. */
+    g_type_map->freehook = etch_noop_clear_handler;  
+    g_class_to_type_map  = new_class_to_type_map(ETCH_DEFSIZE);
+
+    /* instantiate the new value factory.  
+     * this vf does NOT own its type maps since we supply them here. 
+     * however if we wanted to abandon ownership, we could set the   
+     * vf.is_own_types and vf.is_own_class_to_type flags here.
+     */
+    // init typemap and class to type map
+    defvf_initialize_static(g_type_map, g_class_to_type_map);
+    vf = (test_value_factory*) new_default_value_factory_ex(sizeof(test_value_factory), g_type_map, g_class_to_type_map);
+
+    ((etch_object*)vf)->destroy = destroy_test_value_factory;
+
+   /* ensure parent type keys exist in the (one-based) inheritance list. 
+    * parent class of our custom vf is default_value_factory.
+    * inheritance list is used by validators and object assignment logic.
+    */
+    inheritlist = get_vtab_inheritance_list((etch_object*)vf, 2, 1, CLASSID_MY_VF_VTAB);
+    inheritlist[1].o.obj_type = ETCHTYPEB_VALUEFACTORY;  
+    inheritlist[1].c.class_id = CLASSID_VALUEFACTORY;  /* parent class */
+    ((etch_object*)vf)->class_id = CLASSID_MY_VF;  /* our class */
+
+    /* instantiate the custom vf's instance data and assign it to the vf. 
+     */  
+    vf->mt_add = new_static_type(L"add");
+    vf->mt_add_result = new_static_type(L"add_result");
+    vf->mf_x = new_static_field(L"x");
+    vf->mf_y = new_static_field(L"y");
+    vf->mf_result = new_static_field(L"xresult");
+
+    /* we replace generated ids with 1-byte IDs to make test data buffers easier to construct */
+    vf->mt_add->id        = FAKEID_TYPE_ADD;
+    vf->mt_add_result->id = FAKEID_TYPE_ADD_RESULT;
+    vf->mf_x->id          = FAKEID_FIELD_X;
+    vf->mf_y->id          = FAKEID_FIELD_Y;
+    vf->mf_result->id     = FAKEID_FIELD_RESULT;
+
+    ((struct i_value_factory*)((etch_object*)vf)->vtab)->add_type(vf, vf->mt_add);
+    ((struct i_value_factory*)((etch_object*)vf)->vtab)->add_type(vf, vf->mt_add_result);
+
+    etchtype_put_validator(vf->mt_add, clone_field(vf->mf_x), 
+        (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(vf->mt_add, clone_field(vf->mf_y), 
+        (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(vf->mt_add, clone_field(builtins._mf__message_id), 
+        (etch_object*) etchvtor_int64_get(0));
+
+    etchtype_put_validator(vf->mt_add_result, clone_field(vf->mf_result), 
+        (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(vf->mt_add_result, clone_field(builtins._mf__message_id), 
+        (etch_object*) etchvtor_int64_get(0));
+    etchtype_put_validator(vf->mt_add_result, clone_field(builtins._mf__in_reply_to), 
+        (etch_object*) etchvtor_int64_get(0));
+
+    g_my_test_vf = vf;
+    return g_my_test_vf;
+}
+
+
+/**
+ * my_valufactory_impl
+ * value factory version 2 instance data object
+ */
+typedef struct my_valufactory_impl
+{
+    etch_object object;
+
+    etch_type*      mt_add;
+    etch_type*      mt_add_result;
+    etch_field*     mf_x;
+    etch_field*     mf_y;
+    etch_field*     mf_result;
+
+} my_valufactory_impl;
+
+
+/**
+ * destroy_my_valufactory_impl()
+ * destructor for inheriting value factory version 2 instance data
+ */
+static int destroy_my_valufactory_impl(void* data)
+{
+    my_valufactory_impl* impl = (my_valufactory_impl*)data;
+    if (NULL == impl) return -1;
+
+    if (!is_etchobj_static_content(impl))
+    {
+ 	    destroy_static_type(impl->mt_add);
+        destroy_static_type(impl->mt_add_result);
+        destroy_static_field(impl->mf_x); 
+        destroy_static_field(impl->mf_y); 
+        destroy_static_field(impl->mf_result);  
+    }
+
+    return destroy_objectex((etch_object*) impl);
+}
+
+
+/**
+ * new_my_valufactory_impl()
+ * constructor for inheriting value factory version 2 instance data
+ */
+static my_valufactory_impl* new_my_valufactory_impl()
+{
+    unsigned short class_id = CLASSID_MY_VF_IMPL? CLASSID_MY_VF_IMPL: 
+        (CLASSID_MY_VF_IMPL = get_dynamic_classid());
+
+    my_valufactory_impl* impl = (my_valufactory_impl*) new_object
+        (sizeof(my_valufactory_impl), ETCHTYPEB_VALUEFACTIMP, class_id);
+
+    ((etch_object*)impl)->destroy = destroy_my_valufactory_impl;
+
+    impl->mt_add = new_static_type(L"add");
+    impl->mt_add_result = new_static_type(L"add_result");
+    impl->mf_x = new_static_field(L"x");
+    impl->mf_y = new_static_field(L"y");
+    impl->mf_result = new_static_field(L"xresult");
+
+    /* we replace generated ids with 1-byte IDs to make test data buffers easier to construct */
+    impl->mt_add->id        = FAKEID_TYPE_ADD;
+    impl->mt_add_result->id = FAKEID_TYPE_ADD_RESULT;
+    impl->mf_x->id          = FAKEID_FIELD_X;
+    impl->mf_y->id          = FAKEID_FIELD_Y;
+    impl->mf_result->id     = FAKEID_FIELD_RESULT;
+
+    etchtype_put_validator(impl->mt_add, clone_field(impl->mf_x), 
+        (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(impl->mt_add, clone_field(impl->mf_y), 
+        (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(impl->mt_add, clone_field(builtins._mf__message_id), 
+        (etch_object*) etchvtor_int64_get(0));
+
+    etchtype_put_validator(impl->mt_add_result, clone_field(impl->mf_result), 
+        (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(impl->mt_add_result, clone_field(builtins._mf__message_id), 
+        (etch_object*) etchvtor_int64_get(0));
+    etchtype_put_validator(impl->mt_add_result, clone_field(builtins._mf__in_reply_to), 
+        (etch_object*) etchvtor_int64_get(0));
+
+    return impl;
+}
+
+
+/**
+ * new_bogus_valuefactory()
+ * constructor for value factory version 2 inheriting from default_value_factory
+ */
+static default_value_factory* new_bogus_valuefactory()
+{
+    etchparentinfo* inheritlist = NULL;
+    my_valufactory_impl* impl = NULL;
+
+
+    g_type_map = new_vf_types_collection(ETCH_DEFSIZE);
+    /* since we explicitly instantiate a type map, and since we explicitly destroy
+     * the test's custom types, we want the type maps destructor to not destroy
+     * the map content. overriding the map's content clear callback is one way 
+     * to do this. */
+    g_type_map->freehook = etch_noop_clear_handler;
+    g_class_to_type_map  = new_class_to_type_map(ETCH_DEFSIZE);
+
+    /* instantiate the new value factory.  
+     * this vf does NOT own its type maps since we supply them here. 
+     * however if we wanted to abandon ownership, we could clear the   
+     * vf.is_own_types and vf.is_own_class_to_type flags here.
+     */    
+    defvf_initialize_static(g_type_map, g_class_to_type_map);
+    g_my_vf = new_default_value_factory(g_type_map, g_class_to_type_map);
+
+   /* ensure parent type keys exist in the (one-based) inheritance list. 
+    * parent class of our custom vf is default_value_factory.
+    * inheritance list is used by validators and object assignment logic.
+    */
+    inheritlist = get_vtab_inheritance_list((etch_object*)g_my_vf, 2, 1, CLASSID_MY_VF_VTAB);
+    inheritlist[1].o.obj_type = ETCHTYPEB_VALUEFACTORY;  
+    inheritlist[1].c.class_id = CLASSID_VALUEFACTORY;  /* parent class */
+    ((etch_object*)g_my_vf)->class_id = CLASSID_MY_VF;  /* our class */
+
+    /* instantiate the custom vf's instance data and assign it to the vf. 
+     * the impl comprises all data specific to the inheriting class, including 
+     * data and methods if any. the default value factory destructor will call 
+     * the destructor on the vf's impl object.
+     */  
+    impl = new_my_valufactory_impl();
+    g_my_vf->impl = (etch_object*) impl;
+
+    ((struct i_value_factory*)((etch_object*)g_my_vf)->vtab)->add_type(g_my_vf, impl->mt_add);
+    ((struct i_value_factory*)((etch_object*)g_my_vf)->vtab)->add_type(g_my_vf, impl->mt_add_result);
+
+    return g_my_vf;
+}
+
+
+/**
+ * get_vftype()
+ * return a type depending on which version of value factory is instantiated
+ */
+static etch_type* get_vftype(const int typeid)
+{
+    etch_type* type = NULL;
+
+    if (g_my_vf)
+    {
+        my_valufactory_impl* impl = (my_valufactory_impl*) g_my_vf->impl;
+
+        if (typeid == impl->mt_add->id)
+            type = impl->mt_add; 
+        else
+        if (typeid == impl->mt_add_result->id)
+            type = impl->mt_add_result; 
+    }
+    else
+    if (g_my_test_vf)
+    {
+        if (typeid == g_my_test_vf->mt_add->id)
+            type = g_my_test_vf->mt_add; 
+        else
+        if (typeid == g_my_test_vf->mt_add_result->id)
+            type = g_my_test_vf->mt_add_result; 
+    }
+
+    return type;
+}
+
+ 
+/* - - - - - - - - - - - - - - - - -
+ * test messagizer
+ * - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * new_bogus_messagizer()
+ */
+static etch_messagizer* new_bogus_messagizer(i_transportpacket* transport)
+{
+    g_my_messagizer = new_messagizer(transport, L"foo:?Messagizer.format=binary", g_my_resources);
+    return g_my_messagizer;
+}
+ 
+
+/* - - - - - - - - - - - - - - - - - - - - -
+ *  individual test data setup and teardown
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * setup_this_test()
+ */
+static int setup_this_test(const int which_valuefactory)
+{
+    my_impl_transportpacket* mytp_impl = NULL;
+    my_impl_sessionmessage*  mysm_impl = NULL;
+    default_value_factory*   thisvf = NULL;
+    g_which_valuefactory = which_valuefactory;
+
+    /* two versions of value factory using different inheritance models */
+    if (which_valuefactory == WHICHVF_TESTVF)  /* vf version 1 inline inheritance */
+    {   thisvf = (default_value_factory*) new_test_valuefactory();     
+        set_etchobj_static_all(g_my_test_vf);  /* so resources will not destroy */
+    }
+    else 
+    {   
+        thisvf = new_bogus_valuefactory();     /* vf version 2 impl object inheritance */
+        set_etchobj_static_all(g_my_vf);       /* so resources will not destroy */
+    }
+
+    g_my_resources = new_etch_resources(ETCH_DEFSIZE);
+    etch_resources_add(g_my_resources, ETCH_RESXKEY_MSGIZER_VALUFACT, (etch_object*) thisvf); 
+
+    /* we instantiate a wrapper x which implements and instantiates i_transportpacket.
+     * the instantiation of i_transportpacket will contain a pointer to x.
+     * our global reference g_my_transportpacket is a pointer to the interface.
+     * the purpose of this excercise is that, in the real binding we can pass
+     * around the interface, whose methods can be then invoked without knowing
+     * anything about the wrapper. when we want to reference the wrapper x, 
+     * it is (my_impl_transportpacket) g_my_transportpacket->thisx. 
+     */
+    mytp_impl = new_my_impl_transportpacket();
+    g_my_transportpacket = mytp_impl->ixp;
+
+    /* we instantiate a wrapper y which implements and instantiates i_sessionmessage.
+     * the instantiation of i_sessionmessage will contain a pointer to y.
+     * our global reference g_my_sessionmessage is a pointer to the interface.
+     * the purpose of this excercise is that, in the real binding we can pass
+     * around the interface, whose methods can be then invoked without knowing
+     * anything about the wrapper. when we want to reference the wrapper x, 
+     * it is (my_impl_sessionmessage*) g_my_sessionmessage->thisx. 
+     */
+    mysm_impl = new_my_impl_sessionmessage();
+    g_my_sessionmessage = mysm_impl->ism;
+    
+    g_who = new_who(new_int32(THISTEST_WHO_VALUE));
+
+    /* finally instantiate the test messagizer */
+    new_bogus_messagizer(g_my_transportpacket);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_messagizer);
+    etch_msgizer_set_session(g_my_messagizer, g_my_sessionmessage);
+  
+    return 0; 
+}
+
+
+/**
+ * teardown_this_test()
+ */
+static int teardown_this_test()
+{
+    etch_object_destroy(g_my_messagizer);
+
+    etch_object_destroy(g_my_transportpacket);
+
+    etch_object_destroy(g_my_sessionmessage);
+
+    etch_object_destroy(g_my_resources);
+
+    if (g_my_vf)
+    {   clear_etchobj_static_all(g_my_vf);
+        etch_object_destroy(g_my_vf);
+    }
+    else  /* can only instantiate one or the other */ 
+    if (g_my_test_vf)
+    {   clear_etchobj_static_all(g_my_test_vf);
+        etch_object_destroy(g_my_test_vf);
+    }
+   
+    etch_object_destroy(g_who);
+
+    etch_object_destroy(g_type_map);    // ************************************************
+    etch_object_destroy(g_class_to_type_map);
+
+    if (g_flexbuffer)
+        etch_object_destroy(g_flexbuffer);
+
+    g_my_transportpacket = NULL;
+    g_my_sessionmessage = NULL; 
+    g_class_to_type_map = NULL;
+    g_my_messagizer = NULL;
+    g_my_resources = NULL;
+    g_flexbuffer = NULL;                  
+    g_my_test_vf = NULL;
+    g_type_map = NULL;
+    g_my_vf = NULL;
+    g_who = NULL;
+
+    etchvf_free_builtins(); 
+
+    return 0; 
+}
+
+
+/* - - - - - - - - - - - - - - 
+ * unit tests 
+ * - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_transportpacket_constructor()
+ */
+static void test_transportpacket_constructor(void)
+{
+    my_impl_transportpacket* mytp_impl = new_my_impl_transportpacket();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mytp_impl);
+
+    /* the custom interface object destructors are coded to destroy their
+     * implementing objects, so we do that here to verify this functionality.
+     */
+    do 
+    {   i_transportpacket* itp = mytp_impl->ixp;
+        etch_object_destroy(itp);
+
+    } while(0);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_sessionmessage_constructor()
+ */
+static void test_sessionmessage_constructor(void)
+{
+    my_impl_sessionmessage* mysm_impl = new_my_impl_sessionmessage();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mysm_impl);
+
+    /* the custom interface object destructors are coded to destroy their
+     * implementing objects, so we do that here to verify this functionality.
+     */
+    do 
+    {   i_sessionmessage* ism = mysm_impl->ism;
+        etch_object_destroy(ism);
+
+    } while(0);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_messagizer_constructor()
+ */
+static void test_messagizer_constructor(void)
+{
+    etch_messagizer* mzr = NULL;
+    i_transportpacket* itp = NULL;
+    etch_resources* resxmap = NULL;
+    default_value_factory*  vf      = NULL;
+    vf_idname_map*          typemap = NULL;
+    class_to_type_map*      c2tmap  = NULL;
+    my_impl_transportpacket* mytp_impl = NULL;
+
+    typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(typemap);
+    c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(c2tmap);
+    defvf_initialize_static(typemap, c2tmap);
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(vf);
+
+    mytp_impl = NULL;
+
+    vf = new_default_value_factory(typemap, c2tmap);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(vf);
+    set_etchobj_static_all(vf); /* so resources will not destroy */
+
+    resxmap = new_etch_resources(ETCH_DEFSIZE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(resxmap);
+    etch_resources_add(resxmap, ETCH_RESXKEY_MSGIZER_VALUFACT, (etch_object*) vf); 
+
+    mytp_impl = new_my_impl_transportpacket();   
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mytp_impl);
+
+    itp = mytp_impl->ixp;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(itp);
+
+    /* messagizer does not own i_transportpacket* itp */
+    mzr = new_messagizer(itp, L"foo:?Messagizer.format=binary", resxmap);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mzr);
+
+    etch_object_destroy(mzr);    
+
+    /* i_transportpacket.destroy() will destroy my_impl_transportpacket */
+    etch_object_destroy(itp);    
+
+    etch_object_destroy(resxmap);
+    clear_etchobj_static_all(vf);  /* so we can destroy it now */
+    
+    etch_object_destroy(vf);
+    etch_object_destroy(c2tmap);
+    etch_object_destroy(typemap);
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_testsetup_teardown_a
+ */
+static void test_testsetup_teardown_a(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_testsetup_teardown_b
+ */
+static void test_testsetup_teardown_b(void)
+{
+    setup_this_test(WHICHVF_MYVF);
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_packet_1
+ * mimics the transport messagizing a packet and delivering the message to the session
+ */
+static void test_packet_1(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+
+    do          
+    {   int result = 0;
+        etch_type* msgtype = NULL;
+        const int THISTEST_BUFSIZE = 4;
+        char* buf = etch_malloc(THISTEST_BUFSIZE, ETCHTYPEB_BYTES);
+
+        /* g_my_sessionmessage is the i_sessionmessage interface    
+         * my_impl_sessionmessage is the implementing test class */
+        my_impl_sessionmessage* my_session = g_my_sessionmessage->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+
+        /* load up the packet buffer with test data */
+        buf[0] = TAGDATA_VERSION; buf[1] = FAKEID_TYPE_ADD; buf[2] = 0; buf[3] = TYPECODE_EOD_MARK;
+        g_flexbuffer = new_flexbuffer_from(buf, THISTEST_BUFSIZE, THISTEST_BUFSIZE, 0);
+
+        my_session->is_msg_handled = TRUE;
+
+        /* messagize the packet and deliver the message to the session */
+        result = g_my_messagizer->session_packet (g_my_messagizer, g_who, g_flexbuffer);
+        CU_ASSERT_EQUAL(result, 0); 
+        if (0 != result) break;
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_MESSAGE); 
+        result = is_equal_who(my_session->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+        CU_ASSERT_EQUAL(message_size(my_session->msg), 0);
+        CU_ASSERT_PTR_NULL(my_session->eventx);
+        /* assert that message type is "add" (since we buffered FAKEID_TYPE_ADD above) */
+        msgtype = message_type(my_session->msg); 
+        CU_ASSERT_PTR_NOT_NULL_FATAL(msgtype);
+        CU_ASSERT_EQUAL(msgtype->id, FAKEID_TYPE_ADD);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_packet_2
+ * mimics the transport messagizing a packet and delivering the message to the session
+ * which rejects the message and forwards the message as rejected.
+ */
+static void test_packet_2(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+
+    do          
+    {   int result = 0;
+        etch_type* msgtype = NULL;
+        const int THISTEST_BUFSIZE = 4;
+        etch_message* thismessage = NULL;
+        etch_unwanted_message* uwmsg = NULL;
+        char* buf = etch_malloc(THISTEST_BUFSIZE, ETCHTYPEB_BYTES);
+
+        /* g_my_sessionmessage is the i_sessionmessage interface    
+         * my_impl_sessionmessage is the implementing test class */
+        my_impl_sessionmessage* my_session = g_my_sessionmessage->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+
+        /* load up the packet buffer with test data */
+        buf[0] = TAGDATA_VERSION; buf[1] = FAKEID_TYPE_ADD; buf[2] = 0; buf[3] = TYPECODE_EOD_MARK;
+        g_flexbuffer = new_flexbuffer_from(buf, THISTEST_BUFSIZE, THISTEST_BUFSIZE, 0);
+
+        /* for the purposes of this test we manually specify that the message was not handled.
+         * when this is the case, the message and who will be wrapped up in an "unwanted message"
+         * which is forwarded to the session as an event. when this is the case, memory for the
+         * message and who is not cleaned up by the session in the normal manner, but is instead
+         * owned by the unwanted message, and destroyed with that object. 
+         */
+        my_session->is_msg_handled = FALSE;
+
+        /* messagize the packet and deliver the message to the session */
+        result = g_my_messagizer->session_packet (g_my_messagizer, g_who, g_flexbuffer);
+        CU_ASSERT_EQUAL(result, -1); 
+        if (-1 != result) break;
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_NOTIFY); 
+        CU_ASSERT_EQUAL(message_size(my_session->msg), 0);      
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->eventx);
+
+        uwmsg = (etch_unwanted_message*) my_session->eventx; 
+        CU_ASSERT_EQUAL_FATAL(((etch_object*)uwmsg)->class_id, CLASSID_EVENT_UNWANTMSG); 
+
+        /* find the message and who in the "unwanted message" wrapper */
+        result = is_equal_who(uwmsg->whofrom, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        thismessage = uwmsg->message;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(thismessage);
+
+        /* assert that message type is "add" (since we buffered FAKEID_TYPE_ADD above) */
+        msgtype = message_type(thismessage); 
+        CU_ASSERT_PTR_NOT_NULL_FATAL(msgtype);
+        CU_ASSERT_EQUAL(msgtype->id, FAKEID_TYPE_ADD);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_packet_3
+ * mimics the transport messagizing a packet and delivering the message to the session
+ */
+static void test_packet_3(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+
+    do          
+    {   int result = 0;
+        etch_type* msgtype = NULL;
+        const int THISTEST_BUFSIZE = 4;
+        char* buf = etch_malloc(THISTEST_BUFSIZE, ETCHTYPEB_BYTES);
+
+        /* g_my_sessionmessage is the i_sessionmessage interface    
+         * my_impl_sessionmessage is the implementing test class */
+        my_impl_sessionmessage* my_session = g_my_sessionmessage->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+
+        /* load up the packet buffer with test data */
+        buf[0] = TAGDATA_VERSION; 
+        buf[1] = FAKEID_TYPE_ADD_RESULT; 
+        buf[2] = 0; 
+        buf[3] = TYPECODE_EOD_MARK;
+
+        g_flexbuffer = new_flexbuffer_from(buf, THISTEST_BUFSIZE, THISTEST_BUFSIZE, 0);
+
+        /* for the purposes of this test we manually specify that the message was handled */
+        my_session->is_msg_handled = TRUE;
+
+        /* messagize the packet and deliver the message to the session */
+        result = g_my_messagizer->session_packet (g_my_messagizer, g_who, g_flexbuffer);
+        CU_ASSERT_EQUAL(result, 0); 
+        if (0 != result) break;
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_MESSAGE); 
+        CU_ASSERT_EQUAL(message_size(my_session->msg), 0);      
+
+        /* assert that message type is "add_result" (since we buffered FAKEID_TYPE_ADD_RESULT above) */
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->msg);
+        msgtype = message_type(my_session->msg); 
+        CU_ASSERT_PTR_NOT_NULL_FATAL(msgtype);
+        CU_ASSERT_EQUAL(msgtype->id, FAKEID_TYPE_ADD_RESULT);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_message_1
+ * mimics the session buffering a message and delivering it to the transport
+ */
+static void test_message_1(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+
+    do          
+    {   int result = 0;
+        etch_type* msgtype = NULL;
+        etch_value_factory* vf = NULL;
+        const int EXPECTED_BUFSIZE = 4;
+        etch_message* thismessage = NULL;
+
+        /* g_my_transportpacket is the i_transportpacket interface    
+         * my_impl_transportpacket is the implementing test class */
+        my_impl_transportpacket* my_transport = g_my_transportpacket->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport);
+
+        vf = (etch_value_factory*) get_current_valuefactory();
+        msgtype = get_vftype(FAKEID_TYPE_ADD);
+
+        g_my_transportpacket->header_size = 0; /* test no header */
+
+        thismessage = new_message(msgtype, ETCH_DEFSIZE, vf);
+
+        /* buffer up the message and deliver to transport */
+        result = g_my_messagizer->transport_message (g_my_messagizer, g_who, thismessage);
+        CU_ASSERT_EQUAL(result, 0); 
+        if (0 != result) break;
+
+        CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_PACKET); 
+        result = is_equal_who(my_transport->recipient, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->buf); 
+        CU_ASSERT_EQUAL(my_transport->bufcount, EXPECTED_BUFSIZE);
+
+        /* check that packet buffer contains expected serialized message */
+        CU_ASSERT_EQUAL(my_transport->buf[0], TAGDATA_VERSION); 
+        CU_ASSERT_EQUAL(my_transport->buf[1], FAKEID_TYPE_ADD); 
+        CU_ASSERT_EQUAL(my_transport->buf[2], 0); 
+        CU_ASSERT_EQUAL(my_transport->buf[3], TYPECODE_EOD_MARK);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_message_2
+ * mimics the session buffering a message and delivering it to the transport
+ */
+static void test_message_2(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+
+    do          
+    {   int result = 0, i = 0, errs = 0;
+        etch_type* msgtype = NULL;
+        etch_value_factory* vf = NULL;
+        etch_message* thismessage = NULL;
+        const int TEST_HEADER_SIZE = 8, EXPECTED_BUFSIZE = 4 + TEST_HEADER_SIZE;
+
+        /* g_my_transportpacket is the i_transportpacket interface    
+         * my_impl_transportpacket is the implementing test class */
+        my_impl_transportpacket* my_transport = g_my_transportpacket->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport);
+
+        vf = (etch_value_factory*) get_current_valuefactory();
+        msgtype = get_vftype(FAKEID_TYPE_ADD_RESULT);
+
+        g_my_transportpacket->header_size = TEST_HEADER_SIZE; /* test with 8-byte header */
+
+        thismessage = new_message(msgtype, ETCH_DEFSIZE, vf);
+
+        /* buffer up the message and deliver to transport */
+        result = g_my_messagizer->transport_message(g_my_messagizer, g_who, thismessage);
+        CU_ASSERT_EQUAL(result, 0); 
+        if (0 != result) break;
+
+        CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_PACKET); 
+        result = is_equal_who(my_transport->recipient, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->buf); 
+        CU_ASSERT_EQUAL(my_transport->bufcount, EXPECTED_BUFSIZE);
+
+        /* check that packet buffer contains expected serialized message */
+        for(; i < TEST_HEADER_SIZE; i++) if (my_transport->buf[i]) errs++;
+        CU_ASSERT_EQUAL(errs, 0); 
+        CU_ASSERT_EQUAL(my_transport->buf[8], TAGDATA_VERSION); 
+        CU_ASSERT_EQUAL(my_transport->buf[9], FAKEID_TYPE_ADD_RESULT); 
+        CU_ASSERT_EQUAL(my_transport->buf[10],0); 
+        CU_ASSERT_EQUAL(my_transport->buf[11],TYPECODE_EOD_MARK);         
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_control
+ * test the session control notification plumbing
+ */
+static void test_session_control(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+
+    do          
+    {
+        const int MY_CONTROL_CLASSID = 0x5200, MY_VALUE_CLASSID = 0x5201;
+        etch_object* mycontrolobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_CONTROL_CLASSID);
+        etch_object* myvalueobj   = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_VALUE_CLASSID);
+
+        /* g_my_sessionmessage is the i_sessionmessage interface    
+         * my_impl_sessionmessage is the implementing test class */
+        my_impl_sessionmessage* my_session = g_my_sessionmessage->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+        CU_ASSERT_EQUAL(my_session->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_session->control);
+        CU_ASSERT_PTR_NULL(my_session->value);
+
+        /* we relinquish memory for mycontrolobj and myvalueobj here. 
+         * the session_control terminal destination must destroy them, which here
+         * is handled by our session object destructor when we teardown_this_test() */
+        g_my_messagizer->session_control(g_my_messagizer, (etch_event*)mycontrolobj, myvalueobj);
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_CONTROL);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->control);
+        CU_ASSERT_EQUAL(((etch_object*)my_session->control)->class_id, MY_CONTROL_CLASSID);
+        CU_ASSERT_EQUAL(((etch_object*)my_session->value)->class_id,   MY_VALUE_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_notify
+ * test the session notify notification plumbing
+ */
+static void test_session_notify(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+
+    do          
+    {
+        const int MY_EVENT_CLASSID = 0x5202;
+        etch_object* myeventobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_EVENT_CLASSID);
+
+        /* g_my_sessionmessage is the i_sessionmessage interface    
+         * my_impl_sessionmessage is the implementing test class */
+        my_impl_sessionmessage* my_session = g_my_sessionmessage->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+        CU_ASSERT_EQUAL(my_session->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_session->eventx);
+
+        /* we relinquish memory for myeventobj here. 
+         * the session_control terminal destination must destroy it, which here
+         * is handled by our session object destructor when we teardown_this_test() */
+        g_my_messagizer->session_notify(g_my_messagizer, (etch_event*)myeventobj);
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_NOTIFY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->eventx);
+        CU_ASSERT_EQUAL(((etch_object*)my_session->eventx)->class_id, MY_EVENT_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_query
+ * test the session query notification plumbing
+ */
+static void test_session_query(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+
+    do          
+    {
+        const int MY_QUERY_CLASSID = 0x5203, MY_RESULT_CLASSID = 0x5204;
+        etch_object* myqueryobj  = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_QUERY_CLASSID);
+        etch_object* myresultobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_RESULT_CLASSID);
+        etch_object* queryresult = NULL;
+
+        /* g_my_sessionmessage is the i_sessionmessage interface    
+         * my_impl_sessionmessage is the implementing test class */
+        my_impl_sessionmessage* my_session = g_my_sessionmessage->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+        CU_ASSERT_EQUAL(my_session->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_session->query);
+
+        /* we relinquish myresultobj here. see comments following */
+        my_session->query_result = myresultobj; 
+
+        /* we relinquish memory for myqueryobj here and assume queryresult. 
+         * the session_control terminal destination must destroy it, which here
+         * is handled by our session object destructor when we teardown_this_test() */
+        queryresult = g_my_messagizer->session_query (g_my_messagizer, (etch_query*)myqueryobj);
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_QUERY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->query);
+        CU_ASSERT_EQUAL(((etch_object*)my_session->query)->class_id, MY_QUERY_CLASSID);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(queryresult);
+        CU_ASSERT_EQUAL(((etch_object*)queryresult)->class_id, MY_RESULT_CLASSID);
+        etch_object_destroy(queryresult);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_control
+ * test the transport control notification plumbing
+ */
+static void test_transport_control(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+
+    do          
+    {
+        my_impl_transportpacket* my_transport = NULL;
+        const int MY_CONTROL_CLASSID = 0x5200, MY_VALUE_CLASSID = 0x5201;
+        etch_object* mycontrolobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_CONTROL_CLASSID);
+        etch_object* myvalueobj   = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_VALUE_CLASSID);
+
+        /* g_my_transportpacket    is the i_transportpacket interface    
+         * my_impl_transportpacket is the implementing test class 
+         */
+        g_my_messagizer->transport = g_my_transportpacket;
+
+        my_transport = g_my_transportpacket->thisx;
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport);
+        CU_ASSERT_EQUAL(my_transport->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport->control);
+        CU_ASSERT_PTR_NULL(my_transport->value);
+
+        /* we relinquish memory for mycontrolobj and myvalueobj here. 
+         * the transport_control terminal destination must destroy them, which here
+         * is handled by our transport object destructor when we teardown_this_test() 
+         */
+        g_my_messagizer->transport_control (g_my_messagizer, (etch_event*)mycontrolobj, myvalueobj);
+
+        CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_CONTROL);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->control);
+        CU_ASSERT_EQUAL(((etch_object*)my_transport->control)->class_id, MY_CONTROL_CLASSID);
+        CU_ASSERT_EQUAL(((etch_object*)my_transport->value)->class_id,   MY_VALUE_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_notify
+ * test the transport notify notification plumbing
+ */
+static void test_transport_notify(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+
+    do          
+    {
+        my_impl_transportpacket* my_transport = NULL;
+        const int MY_EVENT_CLASSID = 0x5202;
+        etch_object* myeventobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_EVENT_CLASSID);
+
+        /* g_my_transportpacket    is the i_transportpacket interface    
+         * my_impl_transportpacket is the implementing test class 
+         */
+        g_my_messagizer->transport = g_my_transportpacket;
+
+        my_transport = g_my_transportpacket->thisx;
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport);
+        CU_ASSERT_EQUAL(my_transport->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport->control);
+        CU_ASSERT_PTR_NULL(my_transport->value);
+
+        /* we relinquish memory for myeventobj here. 
+         * the transport_control terminal destination must destroy it, which here
+         * is handled by our transport object destructor when we teardown_this_test() */
+        g_my_messagizer->transport_notify (g_my_messagizer, (etch_event*)myeventobj);
+
+        CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_NOTIFY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->eventx);
+        CU_ASSERT_EQUAL(((etch_object*)my_transport->eventx)->class_id, MY_EVENT_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_query
+ * test the transport query notification plumbing
+ */
+static void test_transport_query(void)
+{
+    setup_this_test(WHICHVF_TESTVF);
+
+    do          
+    {
+        my_impl_transportpacket* my_transport = NULL;
+        const int MY_QUERY_CLASSID = 0x5203, MY_RESULT_CLASSID = 0x5204;
+        etch_object* myqueryobj  = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_QUERY_CLASSID);
+        etch_object* myresultobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_RESULT_CLASSID);
+        etch_object* queryresult = NULL;
+
+        /* g_my_transportpacket    is the i_transportpacket interface    
+         * my_impl_transportpacket is the implementing test class 
+         */
+        g_my_messagizer->transport = g_my_transportpacket;
+
+        my_transport = g_my_transportpacket->thisx;
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport);
+        CU_ASSERT_EQUAL(my_transport->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport->control);
+        CU_ASSERT_PTR_NULL(my_transport->value);
+
+        /* we relinquish myresultobj here. see comments following */
+        my_transport->query_result = myresultobj; 
+
+        /* we relinquish memory for myqueryobj here and assume queryresult. 
+         * the transport_control terminal destination must destroy it, which here
+         * is handled by our transport object destructor when we teardown_this_test() */
+        queryresult = g_my_messagizer->transport_query (g_my_messagizer, (etch_query*)myqueryobj);
+
+        CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_QUERY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->query);
+        CU_ASSERT_EQUAL(((etch_object*)my_transport->query)->class_id, MY_QUERY_CLASSID);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(queryresult);
+        CU_ASSERT_EQUAL(((etch_object*)queryresult)->class_id, MY_RESULT_CLASSID);
+        etch_object_destroy(queryresult);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_messagizer_suite()
+{    
+    CU_pSuite pSuite = CU_add_suite("suite messagizer", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test transportpacket impl constructor", test_transportpacket_constructor); 
+    CU_add_test(pSuite, "test sessionmessage impl constructor",  test_sessionmessage_constructor); 
+    CU_add_test(pSuite, "test messagizer constructor",  test_messagizer_constructor); 
+    CU_add_test(pSuite, "test test setup and teardown v1",  test_testsetup_teardown_a); 
+    CU_add_test(pSuite, "test test setup and teardown v2",  test_testsetup_teardown_b); 
+
+    CU_add_test(pSuite, "test packet 1",  test_packet_1); 
+    CU_add_test(pSuite, "test packet 2",  test_packet_2); 
+    CU_add_test(pSuite, "test packet 3",  test_packet_3); 
+    CU_add_test(pSuite, "test message 1", test_message_1); 
+    CU_add_test(pSuite, "test message 2", test_message_2); 
+
+    CU_add_test(pSuite, "test session control",test_session_control); 
+    CU_add_test(pSuite, "test session notify", test_session_notify); 
+    CU_add_test(pSuite, "test session query",  test_session_query); 
+    CU_add_test(pSuite, "test transport control",test_transport_control); 
+    CU_add_test(pSuite, "test transport notify", test_transport_notify); 
+    CU_add_test(pSuite, "test transport query",  test_transport_query); 
+
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/transport/test_packetizer.c b/binding-c/runtime/c/src/test/transport/test_packetizer.c
new file mode 100644
index 0000000..2dd0547
--- /dev/null
+++ b/binding-c/runtime/c/src/test/transport/test_packetizer.c
@@ -0,0 +1,2291 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_packetizer.c
+ */
+#include "etch_runtime.h"
+#include "etch_packetizer.h"
+#include "etch_connection.h"
+#include "etch_nativearray.h"
+#include "etch_encoding.h"
+#include "etch_thread.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - 
+ * unit test support
+ * - - - - - - - - - - - - - -
+ */
+
+static etch_packetizer*        g_my_packetizer;
+static i_sessionpacket*        g_my_sessionpacket;
+static i_transportdata*        g_my_transportdata; 
+static etch_flexbuffer*        g_mybuf;
+static etch_who*               g_who;
+
+#define THISTEST_WHO_VALUE 0x5151
+static unsigned short CLASSID_MY_IMPL_SP;
+static unsigned short CLASSID_MY_IMPL_TD;
+
+#define is_my_impl_transportdata(x) \
+ (x && ((etch_object*)x)->obj_type == ETCHTYPEB_TRANSPORTDATA && ((etch_object*)x)->class_id == CLASSID_MY_IMPL_TD)
+
+#define is_my_impl_sessionpkt(x) \
+ (x && ((etch_object*)x)->obj_type == ETCHTYPEB_SESSIONPKT&& ((etch_object*)x)->class_id == CLASSID_MY_IMPL_SP)
+
+static int check_packetizer_results(i_transportdata*, etch_nativearray*);
+static int check_packetizer_resultx(i_sessionpacket*, etch_nativearray*);
+static int check_packetized_results (etch_arraylist*, etch_nativearray*);
+static int check_packetized_result  (byte* v1, size_t c1, byte* v2, size_t c2);
+static etch_arraylist* new_packetizertest_list();
+
+
+typedef enum etch_what
+{ WHAT_NONE, WHAT_DATA, WHAT_PACKET, 
+  TRANSPORT_QUERY, TRANSPORT_CONTROL, TRANSPORT_NOTIFY,
+  SESSION_QUERY,   SESSION_CONTROL,   SESSION_NOTIFY
+} etch_what;
+
+
+static int is_equal_who(etch_who* who1, etch_who* who2)
+{
+    int n1 = 0, n2 = 0;
+    if (!who1 || !who2) return FALSE;
+    if (((etch_object*)who1)->class_id != CLASSID_WHO || ((etch_object*)who2)->class_id != CLASSID_WHO) return FALSE;
+    if (!who1->value  || !who2->value) return FALSE;
+    if (!is_etch_int32(who1->value) || !is_etch_int32(who2->value)) return FALSE;
+    n1 = ((etch_int32*)who1->value)->value;
+    n2 = ((etch_int32*)who2->value)->value;
+    return n1 == n2;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ * my_impl_transportdata (i_transportdata implementation) 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * my_impl_transportdata
+ * test object implementing i_transportdata
+ */
+typedef struct my_impl_transportdata
+{
+    etch_object object;
+
+    /* i_transportdata interface and methods, plus original destructor
+     * which becomes replaced with a custom destructor to destroy this
+     * object. this is the model for destroying an interface wrapper object
+     * when we do not save and pass around a pointer to the wrapper, but rather
+     * a pointer to the interface. the interface in question, i_transportdata
+     * in this case, contains a pointer to the wrapper object, in this case a
+     * my_impl_transportdata*. when the interface is instantiated, its original 
+     * destructor is saved, and is replaced with a destructor which invokes
+     * the wrapper's destructor. the wrapper destructor must then know to 
+     * invoke the interface's original destructor when destroying the interface.
+     */
+    i_transportdata* itd;         /* owned */ 
+    etch_object_destructor destroy_transportdata;     /* i_transportdata original destructor */
+    etch_transport_data transport_data;  /* i_transportdata::transport_data() */
+
+    i_sessiondata*  session;      /* not owned */
+
+    etch_what       what;          
+    etch_who*       recipient;    /* not owned */
+    etch_arraylist* list;         /* owned */    
+    etch_object*    query;        /* owned */
+    etch_object*    query_result; /* owned */
+    etch_object*    control;      /* owned */
+    etch_object*    value;        /* owned */
+    etch_object*    eventx;       /* owned */
+
+} my_impl_transportdata;
+
+
+/**
+ * destroy_my_impl_transportdata()
+ * my_impl_transportdata destructor
+ */
+static int destroy_my_impl_transportdata (void* data)
+{
+
+  my_impl_transportdata* thisx = (my_impl_transportdata*)data;
+    if (!is_etchobj_static_content(thisx))
+    {       /* invoke original i_transportdata destructor */
+        if (thisx->itd && thisx->destroy_transportdata)
+            thisx->destroy_transportdata(thisx->itd);
+
+       etch_object_destroy(thisx->list);
+
+        etch_object_destroy(thisx->query);
+
+        etch_object_destroy(thisx->query_result);
+
+        etch_object_destroy(thisx->control);
+
+        etch_object_destroy(thisx->value);
+
+        etch_object_destroy(thisx->eventx);
+    }
+
+   return destroy_objectex((etch_object*) thisx);
+}
+
+
+
+/**
+ * impl_transport_data()
+ * my_impl_transportdata::transport_data
+ * @param whoto caller retains, can be null
+ * @param fbuf caller retains
+ */
+static int impl_transport_data (void* data, void* who, void* buffer)
+{
+    my_impl_transportdata* mytd = (my_impl_transportdata*)data;
+    etch_who* whoto = (etch_who*)who;
+    etch_flexbuffer* fbuf = (etch_flexbuffer*)buffer;
+
+    etch_nativearray* wrapped_array = NULL;
+    byte* newbuf = NULL;
+    size_t bytecount = 0;
+
+    assert(is_my_impl_transportdata(mytd));   
+    assert(is_etch_transportdata(mytd->itd));     
+
+    mytd->what = WHAT_DATA;
+    mytd->recipient = whoto;   
+   
+    /* get a new byte vector of the entire packet from the buffer */
+    newbuf = etch_flexbuf_get_all (fbuf, &bytecount);
+
+    /* wrap the packet bytes in an etch_nativearray object */
+    wrapped_array = new_etch_nativearray_from (newbuf,
+        CLASSID_ARRAY_BYTE, sizeof(byte), 1, (int) bytecount, 0, 0); 
+
+    /* we want wrapped array to own new packet bytes memory */
+    wrapped_array->is_content_owned = TRUE;
+
+    return etch_arraylist_add (mytd->list, wrapped_array);
+}
+
+
+/**
+ * my_transport_control()
+ * my_impl_transportdata::itransport::transport_control 
+ */
+static int my_transport_control (my_impl_transportdata* mytd, etch_object* control, etch_object* value)
+{
+    /* changed parameter from i_transportdata* to my_impl_transportdata to correspond to change  
+     * in etch_pktizer_transport_control to pass pzr->transport->thisx rather than pzr->transport.
+     * likewise for my_transport_notify() and my_transport_query. */
+    CU_ASSERT_FATAL(is_my_impl_transportdata(mytd));
+    mytd->what    = TRANSPORT_CONTROL;
+    mytd->control = control;
+    mytd->value   = value;
+    return 0;
+}
+
+
+/**
+ * my_transport_notify()
+ * my_impl_transportdata::itransport::transport_notify 
+ */
+static int my_transport_notify (my_impl_transportdata* mytd, etch_object* evt)
+{
+    CU_ASSERT_FATAL(is_my_impl_transportdata(mytd));
+    mytd->what   = TRANSPORT_NOTIFY;
+    mytd->eventx = evt;
+    return 0;
+}
+
+
+/**
+ * my_transport_query()
+ * my_impl_transportdata::itransport::transport_query 
+ */
+static etch_object* my_transport_query (my_impl_transportdata* mytd, etch_object* query) 
+{
+    etch_object* resultobj = NULL;
+    CU_ASSERT_FATAL(is_my_impl_transportdata(mytd));
+    resultobj   = mytd->query_result; /* set artificially in test */
+    mytd->what  = TRANSPORT_QUERY;
+    mytd->query = query;
+    mytd->query_result = NULL;
+    return (etch_object*) resultobj;  /* caller owns */
+}
+
+
+/**
+ * my_transport_get_session()
+ * my_impl_transportdata::itransport::get_session 
+ */
+static i_sessiondata* my_transport_get_session (my_impl_transportdata* mytd)
+{
+    ETCH_ASSERT(is_etch_transportdata(mytd));
+    return mytd->session;
+}
+
+
+/**
+ * my_transport_set_session()
+ * my_impl_transportdata::itransport::set_session
+ */
+static void my_transport_set_session (my_impl_transportdata* mytd, i_sessiondata* newsession)
+{   
+    ETCH_ASSERT(is_etch_transportdata(mytd));
+    ETCH_ASSERT(is_etch_sessiondata(newsession));
+    mytd->session = newsession;
+}
+
+
+/*
+ * destroy_my_transportdata()
+ * i_transportdata destructor
+ * this destructor will destroy its parent (my_impl_transportdata), 
+ * which will in turn destroy this object.
+ */
+static int destroy_my_transportdata(void* data)
+{
+    i_transportdata* itd = (i_transportdata*)data;
+    my_impl_transportdata* mytd = NULL;
+    if (NULL == itd) return -1;
+
+    mytd = itd->thisx;  
+
+    etch_object_destroy(mytd);
+
+    return 0;
+}
+
+
+/**
+ * new_my_impl_transportdata()
+ * my_impl_transportdata constructor
+ */
+static my_impl_transportdata* new_my_impl_transportdata()
+{
+    i_transportdata* itd  = NULL;
+    i_transport* itransport = NULL;
+    /* this is a model for dynamic class ID assigment */
+    unsigned short class_id = CLASSID_MY_IMPL_TD? CLASSID_MY_IMPL_TD: (CLASSID_MY_IMPL_TD = get_dynamic_classid());
+
+    my_impl_transportdata* mytd = (my_impl_transportdata*) new_object
+      (sizeof(my_impl_transportdata), ETCHTYPEB_TRANSPORTDATA, class_id);
+
+    ((etch_object*)mytd)->destroy = destroy_my_impl_transportdata;
+
+    itransport = new_transport_interface_ex (mytd,
+        (etch_transport_control)     my_transport_control, 
+        (etch_transport_notify)      my_transport_notify, 
+        (etch_transport_query)       my_transport_query,
+        (etch_transport_get_session) my_transport_get_session, 
+        (etch_transport_set_session) my_transport_set_session);
+
+    itd = new_transportdata_interface(mytd, impl_transport_data, itransport);
+
+    /* save off i_transportdata destructor */
+    mytd->destroy_transportdata = ((etch_object*)itd)->destroy;   
+
+    /* replace i_transportdata destructor with one which will destroy this object */
+    ((etch_object*)itd)->destroy = destroy_my_transportdata;
+
+    mytd->list = new_packetizertest_list();
+
+    /* g_my_transportdata will get set to this interface */
+    mytd->itd = itd;  
+
+    return mytd;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ * my_impl_sessionpacket (i_sessionpacket implementation) 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+ */
+
+/**
+ * my_impl_sessionpacket
+ * test object implementing i_sessionpacket
+ */
+typedef struct my_impl_sessionpacket
+{
+    etch_object object;
+
+    /* i_sessionpacket interface and methods, plus original destructor
+     * which becomes replaced with a custom destructor to destroy this
+     * object. this is the model for destroying an interface wrapper object
+     * when we do not save and pass around a pointer to the wrapper, but rather
+     * a pointer to the interface. the interface in question, i_sessionpacket
+     * in this case, contains a pointer to the wrapper object, in this case a
+     * my_impl_sessionpacket*. when the interface is instantiated, its original 
+     * destructor is saved, and is replaced with a destructor which invokes
+     * the wrapper's destructor. the wrapper destructor must then know to 
+     * invoke the interface's original destructor when destroying the interface.
+     */
+    i_sessionpacket* isp;          /* owned */
+
+    etch_object_destructor destroy_sessionpacket; /* i_sessionpacket original destructor */
+    etch_session_packet session_packet;  /* session_packet() */
+
+    etch_what       what;          
+    etch_who*       sender;        /* not owned */ 
+    etch_arraylist* list;          /* owned */    
+    etch_object*    query;         /* owned */
+    etch_object*    query_result;  /* owned */
+    etch_object*    control;       /* owned */
+    etch_object*    value;         /* owned */
+    etch_object*    eventx;        /* owned */
+
+} my_impl_sessionpacket;
+
+
+/**
+ * destroy_my_impl_sessionpacket()
+ * my_impl_sessionpacket destructor
+ */
+static int destroy_my_impl_sessionpacket(void* data)
+{
+
+    my_impl_sessionpacket* thisx = (my_impl_sessionpacket*)data;
+    if (!is_etchobj_static_content(thisx))
+    {       /* invoke original i_sessionpacket destructor */
+        if (thisx->isp && thisx->destroy_sessionpacket)   
+            thisx->destroy_sessionpacket(thisx->isp);
+  
+        etch_object_destroy(thisx->list);
+
+        etch_object_destroy(thisx->query);
+
+        etch_object_destroy(thisx->query_result);
+
+        etch_object_destroy(thisx->control);
+
+        etch_object_destroy(thisx->value);
+
+        etch_object_destroy(thisx->eventx);
+    }
+
+   return destroy_objectex((etch_object*) thisx);
+}
+
+
+/**
+ * impl_session_packet()
+ * my_impl_sessionpacket::session_packet
+ * @param whofrom caller retains, can be null
+ * @param fbuf caller retains
+ */
+static int impl_session_packet (void* data, void* who, void* buffer)
+{
+    my_impl_sessionpacket* mysp = (my_impl_sessionpacket*)data;
+    etch_who* whofrom = (etch_who*)who;
+    etch_flexbuffer* fbuf = (etch_flexbuffer*)buffer;
+
+    etch_nativearray* wrapped_array = NULL;
+    byte* newbuf = NULL;
+    size_t bytecount = 0;
+    CU_ASSERT_FATAL(is_my_impl_sessionpkt(mysp));
+    mysp->what   = WHAT_PACKET;
+    mysp->sender = whofrom;   
+   
+    /* get a new byte vector of the entire packet from the buffer */
+    newbuf = etch_flexbuf_get_all(fbuf, &bytecount);
+
+    /* wrap the packet bytes in an etch_nativearray object */
+    wrapped_array = new_etch_nativearray_from(newbuf,
+        CLASSID_ARRAY_BYTE, sizeof(byte), 1, (int) bytecount, 0, 0); 
+
+    /* we want wrapped array to own new packet bytes memory */
+    wrapped_array->is_content_owned = TRUE;
+
+    return etch_arraylist_add(mysp->list, wrapped_array);
+}
+
+
+/**
+ * my_session_control()
+ * my_impl_sessionpacket::isession::session_control 
+ */
+static int my_session_control (my_impl_sessionpacket* mysp, etch_object* control, etch_object* value)
+{
+    CU_ASSERT_FATAL(is_my_impl_sessionpkt(mysp));
+    mysp->what    = SESSION_CONTROL;
+    mysp->control = control;
+    mysp->value   = value;
+    return 0;
+}
+
+
+/**
+ * my_session_notify()
+ * my_impl_sessionpacket::isession::session_notify 
+ */
+static int my_session_notify (my_impl_sessionpacket* mysp, etch_object* evt)
+{
+    CU_ASSERT_FATAL(is_my_impl_sessionpkt(mysp));
+    mysp->what   = SESSION_NOTIFY;
+    mysp->eventx = evt;
+    return 0;
+}
+
+
+/**
+ * my_session_query()
+ * my_impl_sessionpacket::isession::session_query 
+ */
+static etch_object* my_session_query (my_impl_sessionpacket* mysp, etch_object* query) 
+{
+    etch_object* resultobj = NULL;
+    CU_ASSERT_FATAL(is_my_impl_sessionpkt(mysp));
+    resultobj = mysp->query_result; /* set artificially in test */
+    mysp->what  = SESSION_QUERY;
+    mysp->query = query;
+    mysp->query_result = NULL;
+    return (etch_object*) resultobj;  /* caller owns */
+}
+
+
+/**
+ * new_packetizertest_list()
+ * constructor for a list which owns content memory and where content is etch_object derived.
+ * content will be etch_nativearray objects
+ */
+static etch_arraylist* new_packetizertest_list()
+{
+    etch_arraylist* list = new_etch_arraylist(32,0);
+    list->content_type = ETCHARRAYLIST_CONTENT_OBJECT; /* list can call destroy() on list item */
+    list->is_readonly  = FALSE;
+    return list;
+}
+
+
+/*
+ * destroy_my_sessionpacket()
+ * i_sessionpacket destructor
+ * this destructor will destroy its parent (my_impl_sessionpacket), 
+ * which will in turn destroy this object.
+ */
+static int destroy_my_sessionpacket(void* data)
+{
+    i_sessionpacket* itp = (i_sessionpacket*)data;
+    my_impl_sessionpacket* mytp = NULL;
+    if (NULL == itp) return -1;
+
+    mytp = itp->thisx;  
+
+    etch_object_destroy(mytp);
+
+    return 0;
+}
+
+
+/**
+ * new_my_impl_sessionpacket()
+ * my_impl_sessionpacket constructor
+ */
+static my_impl_sessionpacket* new_my_impl_sessionpacket()
+{
+    i_sessionpacket* isessionpkt  = NULL;
+    i_session* isession = NULL;
+    /* this is a model for dynamic class ID assigment */
+    unsigned short class_id = CLASSID_MY_IMPL_SP? CLASSID_MY_IMPL_SP: 
+        (CLASSID_MY_IMPL_SP = get_dynamic_classid());
+
+    my_impl_sessionpacket* mysessionpkt = (my_impl_sessionpacket*) new_object
+      (sizeof(my_impl_sessionpacket), ETCHTYPEB_SESSIONPKT, class_id);
+
+    ((etch_object*)mysessionpkt)->destroy = destroy_my_impl_sessionpacket;
+
+    mysessionpkt->list = new_packetizertest_list();
+
+    isession = new_session_interface(mysessionpkt,
+        (etch_session_control) my_session_control, 
+        (etch_session_notify)  my_session_notify, 
+        (etch_session_query)   my_session_query);
+
+    isessionpkt = new_sessionpkt_interface(mysessionpkt, impl_session_packet, isession);
+
+    /* save off i_sessionpacket destructor */
+    mysessionpkt->destroy_sessionpacket = ((etch_object*)isessionpkt)->destroy;
+
+    /* replace i_sessionpacket destructor with one which will destroy this object */
+    ((etch_object*)isessionpkt)->destroy = destroy_my_sessionpacket;
+
+    /* g_my_sessionpacket will get set to this interface */
+    mysessionpkt->isp = isessionpkt;  
+
+    return mysessionpkt;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * support functions
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * check_packetizer_results()
+ * check array of packetizer result byte arrays against a control byte array. 
+ * arrays may be packet payloads, or packets with headers, depending on test. 
+ * result arrays are found in the packet handler arraylist, each such list item
+ * being an etch_nativearray object of one dimension, wrapping that result array. 
+ * control arrays are passed as an etch_nativearray of two dimensions, created 
+ * from a static 2-dimensional array.
+ */
+static int check_packetizer_results(i_transportdata* itd, etch_nativearray* expected_array)
+{   
+    my_impl_transportdata*  mytd = (my_impl_transportdata*) itd->thisx;
+    const int packetcount = mytd->list->count; /* # of result arrays in list */
+    int errors = 0;
+
+    if (NULL == expected_array) /* todo: also check for zero populated count */
+        return packetcount == 0? 0: -1;
+
+    if (packetcount != expected_array->dimension[1]) 
+        return -1; /* check against count of expected results */
+
+    errors = check_packetized_results(mytd->list, expected_array);
+     
+    return errors? -1: 0;
+}
+
+
+/**
+ * check_packetizer_resultx()
+ * check array of packetizer result byte arrays against a control byte array. 
+ * arrays may be packet payloads, or packets with headers, depending on test. 
+ * result arrays are found in the packet handler arraylist, each such list item
+ * being an etch_nativearray object of one dimension, wrapping that result array. 
+ * control arrays are passed as an etch_nativearray of two dimensions, created 
+ * from a static 2-dimensional array.
+ */
+static int check_packetizer_resultx(i_sessionpacket* isp, etch_nativearray* expected_array)
+{   
+    my_impl_sessionpacket*  mysp = (my_impl_sessionpacket*) isp->thisx;
+    const int packetcount = mysp->list->count; /* # of result arrays in list */
+    int errors = 0;
+
+    if (NULL == expected_array) /* todo: also check for zero populated count */
+        return packetcount == 0? 0: -1;
+
+    if (packetcount != expected_array->dimension[1]) 
+        return -1; /* check against count of expected results */
+
+    errors = check_packetized_results(mysp->list, expected_array);
+     
+    return errors? -1: 0;
+}
+
+
+/**
+ * check_packetized_results()
+ */
+static int check_packetized_results(etch_arraylist* list, etch_nativearray* expected_array)
+{
+    etch_iterator iterator;
+    int result = 0, errors = 0, i = 0;
+    set_iterator(&iterator, list, &list->iterable);
+
+    while(iterator.has_next(&iterator))
+    {   
+        /* get result (one-dimension byte array) out of list */
+        etch_nativearray* resultobj = etch_arraylist_get(list, i);
+        byte*  packetizedbytes = resultobj->values;   
+        size_t packetizedbytecount = resultobj->dimension[0];
+
+        /* get (offset to) this result out of expected results */
+        size_t dim2offset = etch_nativearray_off2(expected_array, i, 0);
+        byte*  expected_bytes = (byte*) expected_array->values + dim2offset;  
+        size_t expected_bytecount = expected_array->dimension[0];
+
+        result = check_packetized_result(packetizedbytes, packetizedbytecount, 
+            expected_bytes, expected_bytecount);
+
+        if (result == -1)
+            errors++;
+
+        i++;
+        iterator.next(&iterator);
+    }
+     
+    return errors;
+}
+
+
+/**
+ * check_packetized_result()
+ * check a single packetizer result array against a control array, 
+ * each represented as a byte vector. the array can be a packet, or a packet payload,
+ * depending on tested direction of the packetizer call.
+ */
+static int check_packetized_result (byte* v1, size_t c1, byte* v2, size_t c2)
+{   
+    byte  *p = 0, *q = 0;
+    size_t i = 0, errors = 0;
+
+    if (c1 != c2)   return FALSE;
+    if (!v1 && !v2) return TRUE;
+    if (!v1 || !v2) return FALSE;
+
+    for(p = v1, q = v2; i < c1; i++, p++, q++)
+        if (*p != *q) 
+            errors++;
+
+    return errors? -1: 0;
+}
+  
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * individual setup and teardown
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * setup_this_test()
+ */
+static int setup_this_test()
+{
+    my_impl_transportdata* mytd_impl = NULL;
+    my_impl_sessionpacket* mysp_impl = NULL;
+
+    /* we instantiate a wrapper x which implements and instantiates i_transportpacket.
+     * the instantiation of i_transportpacket will contain a pointer to x.
+     * our global reference g_my_transportpacket is a pointer to the interface.
+     * the purpose of this excercise is that, in the real binding we can pass
+     * around the interface, whose methods can be then invoked without knowing
+     * anything about the wrapper. when we want to reference the wrapper x, 
+     * it is (my_impl_transportpacket) g_my_transportpacket->thisx. 
+     */
+    mytd_impl = new_my_impl_transportdata();
+    g_my_transportdata = mytd_impl->itd;
+    CU_ASSERT_FATAL(is_my_impl_transportdata(g_my_transportdata->thisx));
+
+    /* we instantiate a wrapper y which implements and instantiates i_sessionpacket.
+     * the instantiation of i_sessionpacket will contain a pointer to y.
+     * our global reference g_my_sessionpacket is a pointer to the interface.
+     * the purpose of this excercise is that, in the real binding we can pass
+     * around the interface, whose methods can be then invoked without knowing
+     * anything about the wrapper. when we want to reference the wrapper x, 
+     * it is (my_impl_sessionpacket*) g_my_sessionpacket->thisx. 
+     */
+    mysp_impl = new_my_impl_sessionpacket();
+    g_my_sessionpacket = mysp_impl->isp;
+    
+    g_who = new_who(new_int32(THISTEST_WHO_VALUE));
+
+    /* finally instantiate the test packetizer */
+    g_my_packetizer = new_packetizer(g_my_transportdata, L"tcp", NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_packetizer);
+    g_my_packetizer->set_session(g_my_packetizer, g_my_sessionpacket);
+  
+    return 0; 
+}
+
+
+/**
+ * teardown_this_test()
+ */
+static int teardown_this_test()
+{
+    etch_object_destroy(g_my_packetizer);
+
+    etch_object_destroy(g_my_sessionpacket);  // destroy() is now 0xfeeefeee
+
+    etch_object_destroy(g_my_transportdata);
+
+    etch_object_destroy(g_who);
+
+    etch_object_destroy(g_mybuf);
+
+    g_my_packetizer = NULL;
+    g_my_sessionpacket = NULL; 
+    g_my_transportdata = NULL;
+    g_mybuf = NULL;
+    g_who = NULL;
+
+    return 0; 
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - - - 
+ * tests
+ * - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_sessionpacket_constructor()
+ */
+static void test_sessionpacket_constructor(void)
+{
+    my_impl_sessionpacket* mysp_impl = new_my_impl_sessionpacket();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mysp_impl);
+
+    /* the custom interface object destructors are coded to destroy their
+     * implementing objects, so we do that here to verify this functionality.
+     */
+    do 
+    {   i_sessionpacket* isp = mysp_impl->isp;
+        etch_object_destroy(isp);
+
+    } while(0);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transportdata_constructor()
+ */
+static void test_transportdata_constructor(void)
+{
+    my_impl_transportdata* mytd_impl = new_my_impl_transportdata();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mytd_impl);
+
+    /* the custom interface object destructors are coded to destroy their
+     * implementing objects, so we do that here to verify this functionality.
+     */
+    do 
+    {   i_transportdata* itd = mytd_impl->itd;
+        etch_object_destroy(itd);
+
+    } while(0);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_packetizer_constructor()
+ */
+static void test_packetizer_constructor(void)
+{
+    etch_packetizer* pzr = NULL;
+    i_transportdata* itd = NULL;
+    my_impl_transportdata* mytd_impl = NULL;
+
+    mytd_impl = new_my_impl_transportdata();   
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mytd_impl);
+
+    itd = mytd_impl->itd;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(itd);
+
+    /* packetizer does not own i_transportdata* itd */
+	pzr = new_packetizer(itd, L"tcp://127.0.0.1:4001?Packetizer.maxPktSize=110480", NULL);
+	CU_ASSERT_TRUE(pzr->maxpacketsize == 110480);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(pzr);
+
+    etch_object_destroy(pzr);
+
+    /* i_transportdata.destroy() will destroy my_impl_transportdata */
+    etch_object_destroy(itd);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_test_setup()
+ * test that the test setup works with all memory accounted for.
+ * if this test fails, all subsequent tests would also fail.
+ * all subsequent tests should include this skeleton code.
+ */
+static void test_test_setup(void)
+{
+    int result = setup_this_test();
+
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_who);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_packetizer);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_sessionpacket);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_transportdata);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_to_source_packet1()
+ * test 1 for packets delivered to packet source
+ */
+static void test_to_source_packet1(void)
+{
+    setup_this_test();
+
+    do          
+    {
+        int result = 0;
+        byte* disposable_packet = NULL;
+        #define EXPECTED_HEADERSIZE 8
+        etch_nativearray* expected_result_array = NULL;
+        my_impl_transportdata* mytransport = g_my_transportdata->thisx; 
+
+        byte empty_packet[EXPECTED_HEADERSIZE] = { 0,0,0,0, 0,0,0,0, };
+
+        byte expected_result[][EXPECTED_HEADERSIZE] = 
+        {
+            {
+                -34,-83,-66,-17,  0,0,0,0,
+            },
+        };
+
+        CU_ASSERT_EQUAL_FATAL(g_my_packetizer->headersize, EXPECTED_HEADERSIZE);
+
+        expected_result_array = new_etch_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, sizeof(byte), 2, EXPECTED_HEADERSIZE, 1, 0);
+      
+        disposable_packet = etch_malloc(sizeof(empty_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, empty_packet, sizeof(empty_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(empty_packet), 8, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+
+        result = g_my_packetizer->transport_packet(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, 0);
+         
+        result = check_packetizer_results(g_my_packetizer->transport, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mytransport->what, WHAT_DATA);
+        result = is_equal_who(mytransport->recipient, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        etch_object_destroy(expected_result_array);
+
+     } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_to_source_packet2()
+ * test 2 for packets delivered to packet source
+ */
+static void test_to_source_packet2(void)
+{
+   setup_this_test();
+
+    do          
+    {   int result = 0;
+        #define TTSP2BYTECOUNT 9
+        byte* disposable_packet = NULL;
+        etch_nativearray* expected_result_array = NULL;
+        my_impl_transportdata* mytransport = g_my_transportdata->thisx; 
+
+        byte test_packet[TTSP2BYTECOUNT] = { 0,0,0,0, 0,0,0,0, 1 };
+
+        byte expected_result[][TTSP2BYTECOUNT] = 
+        {     /* --signature---  data-length  data  */
+            { /* de  ad  be  ef  00 00 00 01  01    */
+                -34,-83,-66,-17,  0, 0, 0, 1,  1
+            },
+        };
+
+        CU_ASSERT_EQUAL_FATAL(g_my_packetizer->headersize, EXPECTED_HEADERSIZE);
+
+        expected_result_array = new_etch_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, sizeof(byte), 2, TTSP2BYTECOUNT, 1, 0);
+      
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 9, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+
+        result = g_my_packetizer->transport_packet(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, 0);
+         
+        result = check_packetizer_results(g_my_packetizer->transport, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mytransport->what, WHAT_DATA);
+        result = is_equal_who(mytransport->recipient, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        etch_object_destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_to_source_packet3()
+ * test 3 for packets delivered to packet source
+ */
+static void test_to_source_packet3(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;
+        #define TTSP3BYTECOUNT 10
+        byte* disposable_packet = NULL;
+        etch_nativearray* expected_result_array = NULL;
+        my_impl_transportdata* mytransport = g_my_transportdata->thisx; 
+
+        byte test_packet[TTSP3BYTECOUNT] = { 0,0,0,0, 0,0,0,0, 2, 3 };
+
+        byte expected_result[][TTSP3BYTECOUNT] = 
+        {     /* --signature---  data-length  data  */
+            { /* de  ad  be  ef  00 00 00 02  02 03 */
+                -34,-83,-66,-17,  0, 0, 0, 2,  2, 3
+            },
+        };
+
+        CU_ASSERT_EQUAL_FATAL(g_my_packetizer->headersize, EXPECTED_HEADERSIZE);
+
+        expected_result_array = new_etch_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, sizeof(byte), 2, TTSP3BYTECOUNT, 1, 0);
+      
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 10, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+
+        result = g_my_packetizer->transport_packet(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, 0);
+         
+        result = check_packetizer_results(g_my_packetizer->transport, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mytransport->what, WHAT_DATA);
+        result = is_equal_who(mytransport->recipient, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        etch_object_destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_to_source_badpacket1()
+ * test 4 for packets delivered to packet source
+ */
+static void test_to_source_badpacket1(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;
+        #define TTSP4BYTECOUNT 7
+        byte* disposable_packet = NULL;
+
+        byte test_packet[TTSP4BYTECOUNT] = { 0,0,0,0, 0,0,0 }; /* too short */
+      
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 256, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+
+        result = g_my_packetizer->transport_packet(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, -1);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_badpacket1()
+ * test 1 for bad packet data
+ */
+static void test_badpacket1(void)
+{
+   setup_this_test();
+
+    do          
+    {   int result = 0;     
+        #define TBP1COUNT 8
+        byte* disposable_packet = NULL;        
+        byte  test_packet_1[TBP1COUNT] = { 0,0,0,0,          0,0,0,0 };  /* bad sig */
+        byte  test_packet_2[TBP1COUNT] = { 1,2,3,4,          0,0,0,0 };  /* bad sig */
+        byte  test_packet_3[TBP1COUNT] = { -34,-83,-66,-17,  0,1,0,0 };  /* bad len */
+      
+        /* bad signature 1 */
+        disposable_packet = etch_malloc(sizeof(test_packet_1), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_1, sizeof(test_packet_1));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_1), 256, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, -1);
+
+        etch_object_destroy(g_mybuf); g_mybuf = NULL;
+
+        /* bad signature 2 */
+        disposable_packet = etch_malloc(sizeof(test_packet_2), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_2, sizeof(test_packet_2));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_2), 256, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);  
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, -1);
+
+        etch_object_destroy(g_mybuf); g_mybuf = NULL; 
+
+        /* bad data length (65536) */
+        disposable_packet = etch_malloc(sizeof(test_packet_3), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_3, sizeof(test_packet_3));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_3), 256, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);  
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result, -1);
+
+        etch_object_destroy(g_mybuf); g_mybuf = NULL; 
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_single_single_data()
+ * 3 tests for single packet in a single buffer
+ */
+static void test_single_single_data(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;     
+        #define TSPSB1BYTECOUNT 8
+        #define TSPSB2BYTECOUNT 9
+        #define TSPSB2RESULTBYTECOUNT 1
+        #define TSPSB3BYTECOUNT 10
+        #define TSPSB3RESULTBYTECOUNT 2
+        byte* disposable_packet = NULL;        
+        etch_nativearray* expected_result_2_array = NULL;
+        etch_nativearray* expected_result_3_array = NULL;
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        byte test_packet_1[TSPSB1BYTECOUNT] = { -34,-83,-66,-17,  0,0,0,0,      }; 
+        byte test_packet_2[TSPSB2BYTECOUNT] = { -34,-83,-66,-17,  0,0,0,1,  1,  }; 
+        byte test_packet_3[TSPSB3BYTECOUNT] = { -34,-83,-66,-17,  0,0,0,2,  3,4 }; 
+
+        byte expected_result_2[][TSPSB2RESULTBYTECOUNT] = 
+        {      
+            {  
+               1
+            },
+        };
+
+        byte expected_result_3[][TSPSB3RESULTBYTECOUNT] = 
+        {      
+            {  
+               3, 4
+            },
+        };
+
+        /* test 1 */
+        disposable_packet = etch_malloc(sizeof(test_packet_1), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_1, sizeof(test_packet_1));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_1), 64, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet_1));
+
+        result = g_my_packetizer->session_data (g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, NULL);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        etch_object_destroy(g_mybuf); g_mybuf = NULL;
+
+        /* test 2 */ 
+        disposable_packet = etch_malloc(sizeof(test_packet_2), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_2, sizeof(test_packet_2));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_2), 9, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet_2));
+
+        result = g_my_packetizer->session_data (g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        expected_result_2_array = new_etch_nativearray_from
+         (&expected_result_2, CLASSID_ARRAY_BYTE, sizeof(byte), 2, TSPSB2RESULTBYTECOUNT, 1, 0);
+
+        result = check_packetizer_resultx (g_my_sessionpacket, expected_result_2_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        etch_object_destroy(expected_result_2_array);
+        etch_object_destroy(g_mybuf); g_mybuf = NULL; 
+        etch_arraylist_clear (mysessionpkt->list, TRUE);
+
+        /* test 3 */
+        disposable_packet = etch_malloc(sizeof(test_packet_3), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet_3, sizeof(test_packet_3));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet_3), 10, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet_3));
+
+        result = g_my_packetizer->session_data (g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        expected_result_3_array = new_etch_nativearray_from
+          (&expected_result_3, CLASSID_ARRAY_BYTE, sizeof(byte), 2, TSPSB3RESULTBYTECOUNT, 1, 0);
+        
+        result = check_packetizer_resultx (g_my_sessionpacket, expected_result_3_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        etch_object_destroy(expected_result_3_array);
+        etch_object_destroy(g_mybuf); g_mybuf = NULL; 
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_two_in_one_buffer_data_1()
+ * test two packets in a single buffer
+ */
+static void test_two_in_one_buffer_data_1(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;     
+        #define TWOIN1_1_BYTECOUNT (8 + 8)
+        signed char* disposable_packet;
+     
+        signed char test_packet[TWOIN1_1_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,0,0,   
+                -34,-83,-66,-17,  0,0,0,0,  
+              }; 
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 64, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, NULL);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        etch_object_destroy(g_mybuf); g_mybuf = NULL;
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_two_in_one_buffer_data_2()
+ * test two packets in a single buffer - 2
+ */
+static void test_two_in_one_buffer_data_2(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;    
+        #define TWOIN1_2_BYTECOUNT (8 + 1 + 8)
+        #define TWOIN1_2_RESULT_BYTECOUNT 1
+        byte* disposable_packet;
+     
+        byte test_packet[TWOIN1_2_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,0,1, 1,  
+                -34,-83,-66,-17,  0,0,0,0,  
+              }; 
+
+        byte expected_result[][TWOIN1_2_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               1
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_etch_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, sizeof(byte), 2, 
+            TWOIN1_2_RESULT_BYTECOUNT, 1, 0);
+
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 17, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+       
+        etch_object_destroy(g_mybuf); g_mybuf = NULL;
+        etch_object_destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_two_in_one_buffer_data_3()
+ * test two packets in a single buffer - 3
+ */
+static void test_two_in_one_buffer_data_3(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;    
+        #define TWOIN1_3_BYTECOUNT (8 + 8 + 1)
+        #define TWOIN1_3_RESULT_BYTECOUNT 1
+        byte* disposable_packet;
+     
+        byte test_packet[TWOIN1_3_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,0,0,   
+                -34,-83,-66,-17,  0,0,0,1, 2  
+              }; 
+
+        byte expected_result[][TWOIN1_3_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               2
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_etch_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, sizeof(byte), 2, 
+            TWOIN1_3_RESULT_BYTECOUNT, 1, 0);
+
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 17, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        etch_object_destroy(g_mybuf); g_mybuf = NULL;
+        etch_object_destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_two_in_one_buffer_data_4()
+ * test two packets in a single buffer - 4
+ */
+static void test_two_in_one_buffer_data_4(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;        
+        signed char* disposable_packet;
+
+        /* byte count for all packets */
+        #define TWOIN1_4_BYTECOUNT (8 + 1 + 8 + 1)
+
+        /* byte count for low order dimension of expected result array ( [2][1] ) */
+        #define TWOIN1_4_RESULT_BYTECOUNT 1 
+     
+        signed char test_packet[TWOIN1_4_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,0,1,  1,  
+                -34,-83,-66,-17,  0,0,0,1,  2,  
+              }; 
+
+        signed char expected_result[][TWOIN1_4_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               1,    /* packet 1 data */
+            },
+            {  
+               2,    /* packet 2 data */
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_etch_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, 
+                sizeof(byte), /* size of an array item is 1 */
+                2,            /* count of dimensions [2][1] */
+                1,            /* count of items in low order dimension */
+                2,            /* count of items in secondary dimension */          
+                0);           /* 3rd dimension (not applicable) */
+
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        etch_object_destroy(g_mybuf); g_mybuf = NULL;
+        etch_object_destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_two_in_one_buffer_data_5()
+ * test two packets in a single buffer - 5
+ */
+static void test_two_in_one_buffer_data_5(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;        
+        signed char* disposable_packet;
+
+        /* byte count for all packets */
+        #define TWOIN1_5_BYTECOUNT (8 + 2 + 8 + 2)
+
+        /* byte count for low order dimension of expected result array ( [2][2] ) */
+        #define TWOIN1_5_RESULT_BYTECOUNT 2 
+     
+        signed char test_packet[TWOIN1_5_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,0,2,  3, 4,   
+                -34,-83,-66,-17,  0,0,0,2,  5, 6,  
+              }; 
+
+        signed char expected_result[][TWOIN1_5_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               3, 4,    /* packet 1 data */
+            },
+            {  
+               5, 6,    /* packet 2 data */
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_etch_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, 
+                sizeof(byte), /* size of an array item is 1 */
+                2,            /* count of dimensions [2][2] */
+                2,            /* count of items in low order dimension */
+                2,            /* count of items in secondary dimension */          
+                0);           /* 3rd dimension (not applicable) */
+
+        disposable_packet = etch_malloc(sizeof(test_packet), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, test_packet, sizeof(test_packet));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(test_packet), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(test_packet));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        etch_object_destroy(g_mybuf); g_mybuf = NULL;
+        etch_object_destroy(expected_result_array);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_two_in_two_buffers_data_1()
+ * test two packets in two buffers with header split across buffers
+ * packets are empty in this test
+ */
+static void test_two_in_two_buffers_data_1(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0;    
+        #define TWOIN2_1_BUF1_BYTECOUNT 6
+        #define TWOIN2_1_BUF2_BYTECOUNT 10
+        etch_flexbuffer* mybuf2=0;
+        byte* disposable_packet=0;
+     
+        byte buf1_data[TWOIN2_1_BUF1_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,      /* packet 1 header (partial) */  
+              }; 
+
+        byte buf2_data[TWOIN2_1_BUF2_BYTECOUNT] 
+            = {  0, 0,                      /* packet 1 header (balance) */ 
+                -34,-83,-66,-17,  0,0,0,0,  /* packet 2 header */   
+              }; 
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        /* buffer 1 */
+        disposable_packet = etch_malloc(sizeof(buf1_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf1_data, sizeof(buf1_data));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(buf1_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(buf1_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        /* buffer 2 */
+        disposable_packet = etch_malloc(sizeof(buf2_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf2_data, sizeof(buf2_data));
+       
+        mybuf2 = new_flexbuffer_from(disposable_packet, sizeof(buf2_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mybuf2);
+        CU_ASSERT_EQUAL(mybuf2->datalen, sizeof(buf2_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        /* done - free memory */
+        etch_object_destroy(g_mybuf); g_mybuf = NULL;
+        etch_object_destroy(mybuf2);    
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_two_in_two_buffers_data_2()
+ * test two packets in two buffers with header split across buffers
+ * packets include bodies in this test
+ */
+static void test_two_in_two_buffers_data_2(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0; 
+        #define TWOIN2_2_BUF1_BYTECOUNT 6
+        #define TWOIN2_2_BUF2_BYTECOUNT (2 + 2 + 8 + 2)
+        /* byte count for low order dimension of expected result array ( [2][2] ) */
+        #define TWOIN2_2_RESULT_BYTECOUNT 2 
+        etch_flexbuffer* mybuf2=0;
+        byte* disposable_packet=0;
+     
+        byte buf1_data[TWOIN2_2_BUF1_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0,0,      /* packet 1 header (partial) */  
+              }; 
+
+        byte buf2_data[TWOIN2_2_BUF2_BYTECOUNT] 
+            = {  0, 2,                      /* packet 1 header (balance) */ 
+                 3, 4,                      /* packet 1 body */ 
+                -34,-83,-66,-17,  0,0,0,2,  /* packet 2 header */  
+                 5, 6,                      /* packet 2 body */ 
+              }; 
+
+        byte expected_result[][TWOIN2_2_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               3, 4,    /* packet 1 body */
+            },
+            {  
+               5, 6,    /* packet 2 body */
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_etch_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, 
+                sizeof(byte), /* size of an array item is 1 */
+                2,            /* count of dimensions [2][2] */
+                2,            /* count of items in low order dimension */
+                2,            /* count of items in secondary dimension */          
+                0             /* 3rd dimension (not applicable) */
+          );           
+
+        /* buffer 1 */
+        disposable_packet = etch_malloc(sizeof(buf1_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf1_data, sizeof(buf1_data));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(buf1_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(buf1_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        /* buffer 2 */
+        disposable_packet = etch_malloc(sizeof(buf2_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf2_data, sizeof(buf2_data));
+       
+        mybuf2 = new_flexbuffer_from(disposable_packet, sizeof(buf2_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mybuf2);
+        CU_ASSERT_EQUAL(mybuf2->datalen, sizeof(buf2_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, mybuf2);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+      
+        /* done - free memory */
+        etch_object_destroy(expected_result_array);
+        etch_object_destroy(g_mybuf); g_mybuf = NULL;
+        etch_object_destroy(mybuf2);    
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_two_in_two_buffers_data_3()
+ * test two packets in two buffers with body split across buffers
+ */
+static void test_two_in_two_buffers_data_3(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0; 
+        #define TWOIN2_3_BUF1_BYTECOUNT (8 + 1)     /* header1 + body1 1 of 2 */
+        #define TWOIN2_3_BUF2_BYTECOUNT (1 + 8 + 2) /* body1 2 of 2 + header2 + body2 */
+        /* byte count for low order dimension of expected result array ( [2][2] ) */
+        #define TWOIN2_3_RESULT_BYTECOUNT 2 
+        etch_flexbuffer* mybuf2 = NULL;
+        signed char* disposable_packet = NULL;
+     
+        signed char buf1_data[TWOIN2_3_BUF1_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0, 0, 0, 2,   /* packet 1 header (length 2) */
+                 1,                             /* packet 1 partial body */  
+              }; 
+
+        signed char buf2_data[TWOIN2_3_BUF2_BYTECOUNT] 
+            = {  2,                             /* packet 1 body balance */       
+                -34,-83,-66,-17,  0, 0, 0, 2,   /* packet 2 header */  
+                 3, 4,                          /* packet 2 body */ 
+              }; 
+
+        signed char expected_result[][TWOIN2_3_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               1, 2,    /* packet 1 body */
+            },
+            {  
+               3, 4,    /* packet 2 body */
+            },
+        };
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx; 
+
+        etch_nativearray* expected_result_array = new_etch_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, 
+                sizeof(byte), /* size of an array item is 1 */
+                2,            /* count of dimensions [2][2] */
+                2,            /* count of items in low order dimension */
+                2,            /* count of items in secondary dimension */          
+                0             /* 3rd dimension (not applicable) */
+          );           
+
+        /* buffer 1 */
+        disposable_packet = etch_malloc(sizeof(buf1_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf1_data, sizeof(buf1_data));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(buf1_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(buf1_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        /* buffer 2 */
+        disposable_packet = etch_malloc(sizeof(buf2_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf2_data, sizeof(buf2_data));
+       
+        mybuf2 = new_flexbuffer_from(disposable_packet, sizeof(buf2_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mybuf2);
+        CU_ASSERT_EQUAL(mybuf2->datalen, sizeof(buf2_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, mybuf2);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+
+        /* done - free memory */
+        etch_object_destroy(expected_result_array);
+        etch_object_destroy(g_mybuf); g_mybuf = NULL;
+        etch_object_destroy(mybuf2);    
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_two_in_two_buffers_data_4()
+ * test two packets in two buffers with body split across buffers
+ */
+static void test_two_in_two_buffers_data_4(void)
+{
+    setup_this_test();
+
+    do          
+    {   int result = 0; 
+        #define TWOIN2_4_BUF1_BYTECOUNT (8 + 2)     /* header1 + body1 2 of 3 */
+        #define TWOIN2_4_BUF2_BYTECOUNT (1 + 8 + 3) /* body1 3 of 3 + header2 + body2 */
+        /* byte count for low order dimension of expected result array ( [2][2] ) */
+        #define TWOIN2_4_RESULT_BYTECOUNT 3 
+        etch_flexbuffer* mybuf2=0;
+        byte* disposable_packet=0;
+     
+        byte buf1_data[TWOIN2_4_BUF1_BYTECOUNT] 
+            = { -34,-83,-66,-17,  0, 0, 0, 3,   /* packet 1 header (length 2) */
+                 5, 6,                          /* packet 1 partial body */  
+              }; 
+
+        byte buf2_data[TWOIN2_4_BUF2_BYTECOUNT] 
+            = {  7,                             /* packet 1 body balance */       
+                -34,-83,-66,-17,  0, 0, 0, 3,   /* packet 2 header */  
+                 8, 9, 10                       /* packet 2 body */ 
+              }; 
+
+        byte expected_result[][TWOIN2_4_RESULT_BYTECOUNT] = 
+        {      
+            {  
+               5, 6, 7,    /* packet 1 body */
+            },
+            {  
+               8, 9, 10,   /* packet 2 body */
+            },
+        };
+
+        etch_nativearray* expected_result_array = new_etch_nativearray_from
+          (&expected_result, CLASSID_ARRAY_BYTE, 
+                sizeof(byte), /* size of an array item is 1 */
+                2,            /* count of dimensions [2][2] */
+                3,            /* count of items in low order dimension */
+                2,            /* count of items in secondary dimension */          
+                0             /* 3rd dimension (not applicable) */
+          );  
+
+        my_impl_sessionpacket* mysessionpkt = g_my_sessionpacket->thisx;          
+
+        /* buffer 1 */
+        disposable_packet = etch_malloc(sizeof(buf1_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf1_data, sizeof(buf1_data));
+       
+        g_mybuf = new_flexbuffer_from(disposable_packet, sizeof(buf1_data), 10, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(g_mybuf);
+        CU_ASSERT_EQUAL(g_mybuf->datalen, sizeof(buf1_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, g_mybuf);
+        CU_ASSERT_EQUAL(result,0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(mysessionpkt->sender);
+
+        /* buffer 2 */
+        disposable_packet = etch_malloc(sizeof(buf2_data), ETCHTYPEB_BYTES);
+        memcpy(disposable_packet, buf2_data, sizeof(buf2_data));
+       
+        mybuf2 = new_flexbuffer_from(disposable_packet, sizeof(buf2_data), 0, 0);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mybuf2);
+        CU_ASSERT_EQUAL(mybuf2->datalen, sizeof(buf2_data));
+
+        result = g_my_packetizer->session_data(g_my_packetizer, g_who, mybuf2);
+        CU_ASSERT_EQUAL(result,0);
+
+        result = check_packetizer_resultx(g_my_sessionpacket, expected_result_array);
+        CU_ASSERT_EQUAL(result, 0);
+
+        CU_ASSERT_EQUAL(mysessionpkt->what, WHAT_PACKET);
+        result = is_equal_who(mysessionpkt->sender, g_who);
+        CU_ASSERT_EQUAL(result, TRUE);
+        /* done - free memory */
+        etch_object_destroy(expected_result_array);
+        etch_object_destroy(g_mybuf); g_mybuf = NULL;
+        etch_object_destroy(mybuf2);    
+
+   } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_control
+ * test the session control notification plumbing
+ */
+static void test_session_control(void)
+{
+    setup_this_test();
+
+    do          
+    {   
+        const int MY_CONTROL_CLASSID = 0x5200, MY_VALUE_CLASSID = 0x5201;
+        etch_object* mycontrolobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_CONTROL_CLASSID);
+        etch_object* myvalueobj   = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_VALUE_CLASSID);
+
+        /* g_my_sessionpacket is the i_sessionpacket interface    
+         * my_impl_sessionpacket is the implementing test class */
+        my_impl_sessionpacket* my_session = g_my_sessionpacket->thisx;          
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+        CU_ASSERT_EQUAL(my_session->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_session->control);
+        CU_ASSERT_PTR_NULL(my_session->value);
+
+        /* we relinquish memory for mycontrolobj and myvalueobj here. 
+         * the session_control terminal destination must destroy them, which here
+         * is handled by our session object destructor when we teardown_this_test() */
+        g_my_packetizer->session_control (g_my_packetizer, (void*)mycontrolobj, myvalueobj);
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_CONTROL);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->control);
+        CU_ASSERT_EQUAL(((etch_object*)my_session->control)->class_id, MY_CONTROL_CLASSID);
+        CU_ASSERT_EQUAL(((etch_object*)my_session->value)->class_id,   MY_VALUE_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_notify
+ * test the session notify notification plumbing
+ */
+static void test_session_notify(void)
+{
+    setup_this_test();
+
+    do          
+    {   
+        const int MY_EVENT_CLASSID = 0x5202;
+        etch_object* myeventobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_EVENT_CLASSID);
+
+        /* g_my_sessionpacket is the i_sessionpacket interface    
+         * my_impl_sessionpacket is the implementing test class */
+        my_impl_sessionpacket* my_session = g_my_sessionpacket->thisx;   
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+        CU_ASSERT_EQUAL(my_session->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_session->eventx);
+
+        /* we relinquish memory for myeventobj here. 
+         * the session_control terminal destination must destroy it, which here
+         * is handled by our session object destructor when we teardown_this_test() */
+        g_my_packetizer->session_notify(g_my_packetizer, (void*)myeventobj);
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_NOTIFY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->eventx);
+        CU_ASSERT_EQUAL(((etch_object*)my_session->eventx)->class_id, MY_EVENT_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_session_query
+ * test the session query notification plumbing
+ */
+static void test_session_query(void)
+{
+    setup_this_test();
+
+    do          
+    {   
+        const int MY_QUERY_CLASSID = 0x5203, MY_RESULT_CLASSID = 0x5204;
+        etch_object* myqueryobj  = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_QUERY_CLASSID);
+        etch_object* myresultobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_RESULT_CLASSID);
+        etch_object* queryresult = NULL;
+
+        /* g_my_sessionpacket is the i_sessionpacket interface    
+         * my_impl_sessionpacket is the implementing test class */
+        my_impl_sessionpacket* my_session = g_my_sessionpacket->thisx;          
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session);
+        CU_ASSERT_EQUAL(my_session->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_session->query);
+
+        /* we relinquish myresultobj here. see comments following */
+        my_session->query_result = myresultobj; 
+
+        /* we relinquish memory for myqueryobj here and assume queryresult. 
+         * the session_control terminal destination must destroy it, which here
+         * is handled by our session object destructor when we teardown_this_test() */
+        queryresult = g_my_packetizer->session_query(g_my_packetizer, (etch_query*)myqueryobj);
+
+        CU_ASSERT_EQUAL(my_session->what, SESSION_QUERY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_session->query);
+        CU_ASSERT_EQUAL(((etch_object*)my_session->query)->class_id, MY_QUERY_CLASSID);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(queryresult);
+        CU_ASSERT_EQUAL(((etch_object*)queryresult)->class_id, MY_RESULT_CLASSID);
+        etch_object_destroy(queryresult);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_control
+ * test the transport control notification plumbing
+ */
+static void test_transport_control(void)
+{
+    setup_this_test();
+
+    do          
+    {   
+        const int MY_CONTROL_CLASSID = 0x5200, MY_VALUE_CLASSID = 0x5201;
+        etch_object* mycontrolobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_CONTROL_CLASSID);
+        etch_object* myvalueobj   = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_VALUE_CLASSID);
+
+        /* g_my_transportdata is the i_transportdata interface    
+         * my_impl_transportdata is the implementing test class */
+        my_impl_transportdata* my_transport = g_my_transportdata->thisx; 
+        CU_ASSERT_FATAL(is_my_impl_transportdata(my_transport));
+        CU_ASSERT_EQUAL(my_transport->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport->control);
+        CU_ASSERT_PTR_NULL(my_transport->value);
+
+        /* we relinquish memory for mycontrolobj and myvalueobj here. 
+         * the transport_control terminal destination must destroy them, which here
+         * is handled by our transport object destructor when we teardown_this_test() */
+        g_my_packetizer->transport_control(g_my_packetizer, (etch_event*)mycontrolobj, myvalueobj);
+
+        CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_CONTROL);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->control);
+        CU_ASSERT_EQUAL(((etch_object*)my_transport->control)->class_id, MY_CONTROL_CLASSID);
+        CU_ASSERT_EQUAL(((etch_object*)my_transport->value)->class_id,   MY_VALUE_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_notify
+ * test the transport notify notification plumbing
+ */
+static void test_transport_notify(void)
+{
+    setup_this_test();
+
+    do          
+    {   
+        const int MY_EVENT_CLASSID = 0x5202;
+        etch_object* myeventobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_EVENT_CLASSID);
+
+        /* g_my_transportdata is the i_transportdata interface    
+         * my_impl_transportdata is the implementing test class */
+        my_impl_transportdata* my_transport = g_my_transportdata->thisx; 
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport);
+        CU_ASSERT_EQUAL(my_transport->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport->control);
+        CU_ASSERT_PTR_NULL(my_transport->value);
+
+        /* we relinquish memory for myeventobj here. 
+         * the transport_control terminal destination must destroy it, which here
+         * is handled by our transport object destructor when we teardown_this_test() */
+        g_my_packetizer->transport_notify(g_my_packetizer, (etch_event*)myeventobj);
+
+        CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_NOTIFY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->eventx);
+        CU_ASSERT_EQUAL(((etch_object*)my_transport->eventx)->class_id, MY_EVENT_CLASSID);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_transport_query
+ * test the transport query notification plumbing
+ */
+static void test_transport_query(void)
+{
+    setup_this_test();
+
+    do          
+    {   
+        const int MY_QUERY_CLASSID = 0x5203, MY_RESULT_CLASSID = 0x5204;
+        etch_object* myqueryobj  = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_QUERY_CLASSID);
+        etch_object* myresultobj = new_object(sizeof(etch_object),ETCHTYPEB_ETCHOBJECT, MY_RESULT_CLASSID);
+        etch_object* queryresult = NULL;
+
+        /* g_my_transportdata is the i_transportdata interface    
+         * my_impl_transportdata is the implementing test class */
+        my_impl_transportdata* my_transport = g_my_transportdata->thisx; 
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport);
+        CU_ASSERT_EQUAL(my_transport->what, WHAT_NONE);
+        CU_ASSERT_PTR_NULL(my_transport->query);
+
+        /* we relinquish myresultobj here. see comments following */
+        my_transport->query_result = myresultobj; 
+
+        /* we relinquish memory for myqueryobj here and assume queryresult. 
+         * the transport_control terminal destination must destroy it, which here
+         * is handled by our transport object destructor when we teardown_this_test() */
+        queryresult = g_my_packetizer->transport_query(g_my_packetizer, (etch_query*)myqueryobj);
+
+        CU_ASSERT_EQUAL(my_transport->what, TRANSPORT_QUERY);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(my_transport->query);
+        CU_ASSERT_EQUAL(((etch_object*)my_transport->query)->class_id, MY_QUERY_CLASSID);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(queryresult);
+        CU_ASSERT_EQUAL(((etch_object*)queryresult)->class_id, MY_RESULT_CLASSID);
+        etch_object_destroy(queryresult);
+
+    } while(0);
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_packetizer_suite()
+{
+    CU_pSuite ps = CU_add_suite("suite_packetizer", init_suite, clean_suite);
+
+    CU_add_test(ps, "test sessionpacket ctor/dtor", test_sessionpacket_constructor);
+    CU_add_test(ps, "test transportdata ctor/dtor", test_transportdata_constructor);
+    CU_add_test(ps, "test packetizer ctor/dtor", test_packetizer_constructor);
+    CU_add_test(ps, "test unit test setup/teardown", test_test_setup);
+    CU_add_test(ps, "test packet1 to source", test_to_source_packet1);
+    CU_add_test(ps, "test packet2 to source", test_to_source_packet2);
+    CU_add_test(ps, "test packet3 to source", test_to_source_packet3);
+    CU_add_test(ps, "test bad packet 0", test_to_source_badpacket1);
+    CU_add_test(ps, "test bad packet 1", test_badpacket1);
+
+    CU_add_test(ps, "test 1 packet 1 buffer", test_single_single_data);
+    CU_add_test(ps, "test 2 in 1 buffer 1",  test_two_in_one_buffer_data_1);
+    CU_add_test(ps, "test 2 in 1 buffer 2",  test_two_in_one_buffer_data_2);
+    CU_add_test(ps, "test 2 in 1 buffer 3",  test_two_in_one_buffer_data_3);
+    CU_add_test(ps, "test 2 in 1 buffer 4",  test_two_in_one_buffer_data_4);
+    CU_add_test(ps, "test 2 in 1 buffer 5",  test_two_in_one_buffer_data_5);
+    CU_add_test(ps, "test 2 in 2 buffers 1", test_two_in_two_buffers_data_1);
+    CU_add_test(ps, "test 2 in 2 buffers 2", test_two_in_two_buffers_data_2);
+    CU_add_test(ps, "test 2 in 2 buffers 3", test_two_in_two_buffers_data_3);
+    CU_add_test(ps, "test 2 in 2 buffers 4", test_two_in_two_buffers_data_4);
+
+    CU_add_test(ps, "test session control",  test_session_control); 
+    CU_add_test(ps, "test session notify",  test_session_notify); 
+    CU_add_test(ps, "test session query",  test_session_query); 
+    CU_add_test(ps, "test transport control",  test_transport_control); 
+    CU_add_test(ps, "test transport notify",  test_transport_notify); 
+    CU_add_test(ps, "test transport query",  test_transport_query); 
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/transport/test_plainmailbox.c b/binding-c/runtime/c/src/test/transport/test_plainmailbox.c
new file mode 100644
index 0000000..47a20d4
--- /dev/null
+++ b/binding-c/runtime/c/src/test/transport/test_plainmailbox.c
@@ -0,0 +1,1338 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_plainmailbox.c 
+ */
+#include "etch_runtime.h"
+#include "etch_plain_mailbox.h"
+#include "etch_plain_mailbox_manager.h"
+#include "etch_default_value_factory.h"
+#include "etch_map.h"
+#include "etch_log.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+#include "etch_simpletimer.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - 
+ * unit test support
+ * - - - - - - - - - - - - - -
+ */
+
+static etch_plainmailboxmgr*  g_manager;
+static etch_arraylist*        g_list;
+static etch_who*              g_who1;
+static etch_who*              g_who2;
+static etch_type*             g_type1;
+static etch_type*             g_type2;
+static etch_mutex*            g_rwlock;
+static default_value_factory* g_vf;
+static vf_idname_map*         g_typemap;
+static class_to_type_map*     g_c2tmap;
+
+
+static int g_is_unregistered;  
+static int g_mailbox_status;
+static int g_mailbox_isclosed;
+static int g_wakeupreason;
+static i_mailbox*   g_mailbox;
+static void*        g_wakeupdata;
+static etch_object* g_mailbox_state;
+static etch_object_destructor g_list_stockdtor;
+#define CLASSID_MYSTATE 0xf0
+#define MYSTATE_VALUE 12345
+
+
+/**
+ * my_redelivery_list_destructor()
+ * custom dtor for message redelivery sink.
+ * logs and destroys redelivered messages.
+ */
+static int my_redelivery_list_destructor(void* data)
+{
+    etch_arraylist* list = (etch_arraylist*)data;
+    etch_iterator iterator;
+    set_iterator(&iterator, list, &list->iterable);
+
+    while(iterator.has_next(&iterator))
+    {
+        etch_mailbox_element* listitem = iterator.current_value;
+        #if IS_DEBUG_CONSOLE
+        ETCH_LOG("TEST", ETCH_LOG_INFO, "destroying message %d from redelivery sink\n", msgid);
+        #endif
+
+        etch_object_destroy(listitem);  /* destroy message and element wrapper */
+        
+        iterator.next(&iterator);
+    }
+
+    return g_list_stockdtor(list);    /* invoke original list destructor */
+}
+
+/**
+ * mymboxmgr_unregister()
+ * override for mailbox manager unregister
+ */
+static int mymboxmgr_unregister (void* mgr, i_mailbox* mbox)
+{
+    g_is_unregistered = TRUE;
+    return 0;
+}
+
+
+/**
+ * mymboxmgr_redeliver()
+ * override for mailbox manager redeliver
+ */
+static int mymboxmgr_redeliver (void* mgr, etch_who* whofrom, etch_message* msg)
+{
+    etch_arraylist_add(g_list, new_mailbox_element(msg, whofrom));
+    return 0;
+} 
+
+/**
+ * mymboxmgr_redeliver()
+ * override for mailbox notify
+ */
+static int my_mailbox_notify (void* data, i_mailbox* mb, void* stateData, const int is_closed) 
+{
+    etch_object* state = (etch_object*)stateData;
+    g_mailbox = mb;
+    g_mailbox_state = state;
+    g_mailbox_status = TRUE;
+    g_mailbox_isclosed = is_closed;
+    return 0;
+}
+
+
+/**
+ * setup_this_test()
+ * set up an individual unit test
+ */
+static int setup_this_test()
+{
+    // TODO: pool
+    etch_mutex_create(&g_rwlock, ETCH_MUTEX_NESTED, NULL);
+
+    g_manager = new_plain_mailbox_manager (NULL, NULL, NULL, g_rwlock); 
+    if (NULL == g_manager) return -1;
+    g_manager->unregister = g_manager->imanager->unregister = mymboxmgr_unregister;
+    g_manager->redeliver  = g_manager->imanager->redeliver  = mymboxmgr_redeliver;
+
+    /* message redelivery sink */
+    g_list = new_etch_arraylist(0, 0);
+    g_list->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
+    g_list->is_readonly  = TRUE;  
+    g_list_stockdtor = ((etch_object*)g_list)->destroy; /* custom destructor will destroy list content */
+    ((etch_object*)g_list)->destroy  = my_redelivery_list_destructor;
+
+    g_who1  = new_who(new_int32(1));
+    g_who2  = new_who(new_int32(2));
+    g_type1 = new_type(L"type1");
+    g_type2 = new_type(L"type2");
+
+    g_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(g_typemap);
+    g_c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(g_c2tmap);  
+    defvf_initialize_static(g_typemap, g_c2tmap);
+    g_vf = new_default_value_factory(g_typemap, g_c2tmap);
+    CU_ASSERT_PTR_NOT_NULL(g_vf);
+
+    etchtype_put_validator(g_type1, clone_field(builtins._mf__message_id), (etch_object*) etchvtor_int64_get(0));
+    etchtype_put_validator(g_type2, clone_field(builtins._mf__message_id), (etch_object*) etchvtor_int64_get(0));
+
+    return g_manager? 0: -1;
+}
+
+
+/**
+ * teardown_this_test()
+ * tear down an individual unit test
+ */
+static void teardown_this_test()
+{
+    etch_object_destroy(g_manager);
+    g_manager = NULL;
+
+    etch_mutex_destroy(g_rwlock);
+    g_rwlock = NULL;
+
+    etch_object_destroy(g_list);
+    g_list = NULL;
+
+    etch_object_destroy(g_who1);
+    g_who1 = NULL;
+
+    etch_object_destroy(g_who2);
+    g_who2 = NULL;
+
+    etch_object_destroy(g_type1);
+    g_type1 = NULL;
+
+    etch_object_destroy(g_type2);
+    g_type2 = NULL;
+
+    etch_object_destroy(g_vf);
+    g_vf = NULL;
+
+    etch_object_destroy(g_c2tmap);
+    g_c2tmap = NULL;
+
+    etch_object_destroy(g_typemap);
+    g_typemap = NULL;
+
+    // TODO: cleanup statics
+    //etchvf_free_builtins()
+
+    g_is_unregistered = g_mailbox_status = g_mailbox_isclosed = g_wakeupreason = 0;
+    g_mailbox = NULL;
+    g_mailbox_state = NULL;
+    g_wakeupdata = NULL;
+    etchvf_free_builtins(); 
+}
+
+
+
+
+
+
+static void check_mailbox_status(const int expected_status,  i_mailbox* expected_mbox, 
+    etch_object* expected_state, const int expected_isclosed)
+{
+    CU_ASSERT_EQUAL(g_mailbox_status,   expected_status);
+    CU_ASSERT_EQUAL(g_mailbox_state,    expected_state);
+    CU_ASSERT_EQUAL(g_mailbox_isclosed, expected_isclosed);
+    CU_ASSERT_PTR_EQUAL(g_mailbox,      expected_mbox);
+}
+
+
+static void check_mailbox(etch_plainmailbox* mbox, const int is_expected_empty, 
+    const int is_expected_full, const int is_expected_closed, 
+    const int is_expected_unregistered, const int expected_size) 
+{
+    i_mailbox* ibox = mbox->imailbox;
+    int result = mbox->is_empty(ibox);
+    CU_ASSERT_EQUAL(result, is_expected_empty);
+    result = mbox->is_full(ibox); 
+    CU_ASSERT_EQUAL(result, is_expected_full); 
+    result = mbox->is_closed(ibox);
+    CU_ASSERT_EQUAL(result, is_expected_closed);
+    CU_ASSERT_EQUAL(g_is_unregistered, is_expected_unregistered);
+    CU_ASSERT_EQUAL(g_list->count, expected_size);
+}
+
+
+static void check_deliver(etch_plainmailbox* mbox, const int expected_ishandled, 
+    etch_who* who, etch_message* msg)
+{
+    int actual_result;
+
+    const int delivery_result = mbox->message(mbox->imailbox, who, msg);
+
+    if (delivery_result == 0 && expected_ishandled)
+        actual_result = 0;
+    else
+    if (delivery_result != 0 && !expected_ishandled)
+        actual_result = 0;
+    else
+        actual_result = -1;
+
+    CU_ASSERT_EQUAL(actual_result, 0);
+
+    if (0 != delivery_result) /* caller retains message memory on failure */
+        if  (delivery_result != ETCH_MAILBOX_DUPLICATE)
+             etch_object_destroy(msg);
+}
+
+
+static void check_redelivered(etch_plainmailbox* mbox, const int index, etch_message* msg) 
+{
+    etch_mailbox_element* entry = etch_arraylist_get(g_list, index);
+    CU_ASSERT_PTR_NOT_NULL(entry);
+    if (NULL == entry) return;
+    CU_ASSERT_PTR_EQUAL(entry->msg, msg);
+}
+
+
+static void check_close_delivery(etch_plainmailbox* mbox, const int expected_is_closed) 
+{
+    const int did_close = 0 == mbox->close_delivery(mbox->imailbox);
+    CU_ASSERT_EQUAL(did_close, expected_is_closed);
+}
+
+
+static void check_close_read(etch_plainmailbox* mbox, const int expected_is_closed) 
+{
+    const int did_close = 0 == mbox->close_read(mbox->imailbox);
+    CU_ASSERT_EQUAL(did_close, expected_is_closed);
+}
+
+
+static void check_element(etch_mailbox_element* elt, etch_who* who, etch_message* msg)
+{
+    CU_ASSERT_PTR_NOT_NULL(elt);
+    if (NULL == elt) return;
+    CU_ASSERT_PTR_EQUAL(who, elt->whofrom);
+    CU_ASSERT_PTR_EQUAL(msg, elt->msg);
+}
+
+
+static void check_read(etch_plainmailbox* mbox, const int expected_to_be_present, 
+    etch_who* who, etch_message* msg) 
+{
+    etch_mailbox_element* thiselt = NULL;
+
+    mbox->read(mbox->imailbox, &thiselt); 
+
+    if (expected_to_be_present)
+        check_element(thiselt, who, msg);
+    else { CU_ASSERT(is_etch_exception(thiselt)); }
+
+    /* message is "processed", end of the line for the message */ 
+    etch_object_destroy(thiselt);
+}
+
+
+static void check_read_withwait(etch_plainmailbox* mbox, const int maxdelay, 
+    const int expected_to_be_present, etch_who* who, etch_message* msg) 
+{
+    etch_mailbox_element* thiselt = NULL;
+
+    mbox->read_withwait(mbox->imailbox, maxdelay, &thiselt); 
+
+    if (expected_to_be_present)
+        check_element(thiselt, who, msg);
+     else { CU_ASSERT(is_etch_exception(thiselt)); }
+
+    /* message is "processed", end of the line for the message */ 
+    etch_object_destroy(thiselt);
+}
+
+
+/**
+ * my_alarm_wakeup()
+ */
+static void my_alarm_wakeup (void* passthrudata, const int wakeupreason) 
+{
+    etch_plainmailbox* thisx = (etch_plainmailbox*) passthrudata;
+    g_wakeupdata = thisx;
+    g_wakeupreason = wakeupreason; 
+}
+
+
+/* - - - - - - - - - - - - - - 
+ * unit tests 
+ * - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_mailboxes_map()
+ * test hashtable configured as for mapping id object to mailbox object,
+ * insert, locate, remove, destroy, verify all memory accounted for.
+ */
+static void test_mailboxes_map(void)
+{
+    int result = 0;
+    const int64 val1 = 1234567890LL;
+    const int64 val2 = 9876543210LL;
+    etch_hashtable* map = new_pmboxmgr_mailboxmap();
+    etch_hashitem hi, *thisitem = &hi; 
+    i_mailbox*  mbox1  = new_default_mailbox_interface(NULL); 
+    i_mailbox*  mbox2  = new_default_mailbox_interface(NULL); 
+    etch_int64* msgid1 = new_int64(val1);
+    etch_int64* msgid2 = new_int64(val2);
+    etch_int64* foundkey = NULL;
+    const unsigned expecthash1 = etchhash(&val1, 8, 0);
+    const unsigned expecthash2 = etchhash(&val2, 8, 0);
+    CU_ASSERT_EQUAL(((etch_object*)msgid1)->get_hashkey(msgid1), expecthash1);
+    CU_ASSERT_EQUAL(((etch_object*)msgid2)->get_hashkey(msgid2), expecthash2);
+
+    result = ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth(map->realtable, msgid1, mbox1, map, 0); 
+    CU_ASSERT_EQUAL(result,0); 
+    result = ((struct i_hashtable*)((etch_object*)map)->vtab)->inserth(map->realtable, msgid2, mbox2, map, 0); 
+    CU_ASSERT_EQUAL(result,0);
+
+    result = ((struct i_hashtable*)((etch_object*)map)->vtab)->findh(map->realtable, ((etch_object*)msgid1)->hashkey, map, (void*)&thisitem);
+    CU_ASSERT_EQUAL(result,0);
+    result = ((struct i_hashtable*)((etch_object*)map)->vtab)->findh(map->realtable, ((etch_object*)msgid2)->hashkey, map, (void*)&thisitem);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = ((struct i_hashtable*)((etch_object*)map)->vtab)->removeh(map->realtable, ((etch_object*)msgid1)->hashkey, map, (void*)&thisitem);
+    CU_ASSERT_EQUAL_FATAL(result,0);
+    foundkey = (etch_int64*) thisitem->key;
+    CU_ASSERT_EQUAL_FATAL(is_etch_int64(foundkey), TRUE);
+    CU_ASSERT_EQUAL(foundkey->value, msgid1->value);
+    etch_free(foundkey);   
+
+    etch_object_destroy(map);
+
+    /* map owns its keys and does not own its values */
+    etch_free(mbox1);
+    etch_free(mbox2);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_setup_teardown()
+ * test the test setup/teardown and verify all memory accounted for.
+ * passing this test ensures that any leaks that might show up in subsequeuent 
+ * tests are specific to the test, not the common test data.
+ */
+static void test_setup_teardown(void)
+{
+    etch_message* test_message;
+
+    int result = setup_this_test();
+    CU_ASSERT_EQUAL_FATAL(result, 0); 
+
+    /* test that messages added to the global list are destroyed at teardown */
+    test_message = new_message(g_type1, 0, (etch_value_factory*) g_vf);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(test_message); 
+    etch_arraylist_add(g_list, new_mailbox_element(test_message, g_who1));
+
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_constructor()
+ * test the plain mailbox constructor
+ */
+static void test_constructor(void)
+{
+    setup_this_test();
+
+    do
+    {   etch_plainmailbox* mbox = NULL;
+        const int64 THISMSGID = 9876543210LL;
+        const int   QUEUEDELAY_1SEC = 1000, LIFETIME_TWO_MINUTES = 120000;
+        const int   MAXMSGS_ONE = 1, QUEUEEWAITFOREVER = 0, QUEUENODELAY = -1;
+        printf("\n");
+
+        mbox = new_mailbox (g_manager->imanager, THISMSGID, 
+            QUEUEDELAY_1SEC, MBOX_LIFETIME_UNTIL_CLOSE, MAXMSGS_ONE);
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mbox);
+        CU_ASSERT_EQUAL(THISMSGID, mbox->get_message_id(mbox->imailbox));  
+        CU_ASSERT_EQUAL(QUEUEDELAY_1SEC, mbox->max_message_delay);  
+        CU_ASSERT_EQUAL(MBOX_LIFETIME_UNTIL_CLOSE, mbox->lifetime);  
+        CU_ASSERT_EQUAL(MAXMSGS_ONE,  mbox->max_messages);  
+        etch_object_destroy(mbox);
+
+        mbox = new_mailbox (g_manager->imanager, THISMSGID, 
+            QUEUENODELAY, MBOX_LIFETIME_UNTIL_CLOSE, MAXMSGS_ONE);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mbox);
+        etch_object_destroy(mbox);
+
+        mbox = new_mailbox (g_manager->imanager, THISMSGID, 
+            QUEUEDELAY_1SEC, MBOX_LIFETIME_UNTIL_CLOSE, MAXMSGS_ONE);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mbox);
+        etch_object_destroy(mbox);
+
+        /* testing with a nonzero lifetime here, this is atypical */
+        mbox = new_mailbox (g_manager->imanager, THISMSGID, 
+            QUEUEEWAITFOREVER, LIFETIME_TWO_MINUTES, MAXMSGS_ONE);
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(mbox);
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_deliver()
+ * test message deliver
+ */
+static void test_deliver(void)
+{
+    setup_this_test();
+
+    do
+    {   etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        check_mailbox(mbox, TRUE, FALSE, FALSE, FALSE, 0);
+
+        check_close_delivery(mbox, TRUE);
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);
+
+        check_deliver(mbox, FALSE, g_who1, new_message(g_type1, 0, (etch_value_factory*) g_vf));
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_close_delivery1()
+ * open box and close it for delivery while empty
+ */
+static void test_closedelivery1(void)
+{
+    setup_this_test();
+
+    do
+    {   etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        check_close_delivery(mbox, TRUE);   
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);  
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_close_delivery2()
+ * open box and close it for delivery while non-empty
+ */
+static void test_closedelivery2(void)
+{
+    setup_this_test();
+
+    do
+    {   etch_plainmailbox* mbox  = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        etch_message *mymessage1 = new_message(g_type1, 0, (etch_value_factory*) g_vf);
+        message_set_id(mymessage1, new_int64(1)); 
+       
+        check_deliver(mbox, TRUE, g_who1, mymessage1);
+        check_mailbox(mbox, FALSE, FALSE, FALSE, FALSE, 0);  
+
+        check_close_delivery(mbox, TRUE);
+        check_mailbox(mbox, FALSE, FALSE, TRUE, TRUE, 0);  
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_close_delivery3()
+ * open box and close it for delivery twice
+ */
+static void test_closedelivery3(void)
+{
+    setup_this_test();
+
+    do
+    {   etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+
+        check_close_delivery(mbox, TRUE);
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);  
+
+        check_close_delivery(mbox, FALSE);
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);  
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_notify1()
+ * test message notify
+ */
+static void test_notify1(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0;
+        etch_object* mystateobj = NULL;
+        etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        i_mailbox* ibox = mbox->imailbox;
+        check_mailbox_status(FALSE, NULL, NULL, FALSE);
+
+        mystateobj = (etch_object*)new_int32(MYSTATE_VALUE);
+
+        result = mbox->register_notify(ibox, my_mailbox_notify, mystateobj, ETCH_INFWAIT);
+
+        CU_ASSERT_EQUAL(result, 0);
+        check_mailbox_status(FALSE, NULL, NULL, FALSE); 
+
+        check_close_delivery(mbox, TRUE);
+        check_mailbox_status(TRUE, ibox, mystateobj, TRUE); 
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_timer()
+ * test current implementation of timer
+ */
+static void test_timer(void)
+{
+    setup_this_test();
+
+     /* this test breaks if breakpoints are set in the underlying wait objects
+      * and thread procedures. this will of course be due to wait expiration 
+      * and subsequent object destruction, however we should have better state
+      * maintenance in the thread, mutex, wait, and timer objects in order to 
+      * be able to detect and avoid such problems.
+      */
+    do
+    {   const int ONE_SECOND = 1000, TWO_SECONDS = 2000, TEN_SECONDS = 10000;
+        etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        etch_timer* timer;
+        int result = 0;
+
+        timer  = new_timer(ONE_SECOND, mbox, my_alarm_wakeup);
+        result = etch_timer_start(timer);
+        etch_sleep(TWO_SECONDS);
+        CU_ASSERT_PTR_EQUAL(g_wakeupdata, mbox);
+        CU_ASSERT_EQUAL(g_wakeupreason, ETCH_TIMER_REASON_TIMEOUT);
+        etch_object_destroy(timer);
+
+        g_wakeupdata = NULL;
+        timer  = new_timer(TEN_SECONDS, mbox, my_alarm_wakeup);  
+        result = etch_timer_start(timer);
+        etch_sleep(TWO_SECONDS);
+        etch_timer_stop(timer);
+        CU_ASSERT_PTR_EQUAL(g_wakeupdata, mbox);
+        CU_ASSERT_EQUAL(g_wakeupreason, ETCH_TIMER_REASON_INTERRUPTED);
+        etch_object_destroy(timer);
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_notify2()
+ * test message notify with mailbox expiration
+ */
+static void test_notify2(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0;
+        etch_object* mystateobj = NULL;
+        const int LIFETIME_ONE_SECOND = 1000, TWO_SECONDS = 2000;
+        etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        i_mailbox* ibox  = mbox->imailbox;
+        check_mailbox_status(FALSE, NULL, NULL, FALSE);
+        mystateobj = (etch_object*)new_int32(MYSTATE_VALUE);
+
+        result = mbox->register_notify(ibox, my_mailbox_notify, mystateobj, LIFETIME_ONE_SECOND);
+
+        CU_ASSERT_EQUAL(result, 0);
+        check_mailbox_status(FALSE, NULL, NULL, FALSE); 
+
+        etch_sleep(TWO_SECONDS);
+        check_mailbox_status(TRUE, ibox, mystateobj, TRUE); 
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_notify3()
+ * test message notify 
+ */
+static void test_notify3(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0;
+        etch_object* mystateobj = NULL;
+        const int LIFETIME_FOREVER = 0, TWO_SECONDS = 2000;
+        etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        check_mailbox_status(FALSE, NULL, NULL, FALSE);
+        mystateobj = (etch_object*)new_int32(MYSTATE_VALUE);
+
+        result = mbox->register_notify(mbox->imailbox, my_mailbox_notify, mystateobj, LIFETIME_FOREVER);
+
+        CU_ASSERT_EQUAL(result, 0);
+        check_mailbox_status(FALSE, NULL, NULL, FALSE); 
+
+        etch_sleep(TWO_SECONDS);
+        check_mailbox_status(FALSE, NULL, NULL, FALSE); 
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_notify4()
+ * test message notify.
+ * test that notify callback receives expected results on a successful queue of
+ * a message to a mailbox. 
+ */
+static void test_notify4(void)
+{
+    setup_this_test();
+
+    do
+    {   int result = 0;
+        etch_object* mystateobj = NULL;
+        etch_message* mymessage = NULL;
+        const int LIFETIME_FOREVER = 0, MYMSGID = 1337;
+        etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        i_mailbox* ibox = mbox->imailbox;
+        check_mailbox_status(FALSE, NULL, NULL, FALSE);
+        mystateobj = (etch_object*)new_int32(MYSTATE_VALUE);
+
+        result = mbox->register_notify(ibox, my_mailbox_notify, mystateobj, LIFETIME_FOREVER);
+
+        CU_ASSERT_EQUAL(result, 0);
+        check_mailbox_status(FALSE, NULL, NULL, FALSE); 
+
+        mymessage = new_message(g_type1, 0, (etch_value_factory*) g_vf);
+        message_set_id(mymessage, new_int64(MYMSGID));
+        printf("\n");
+
+        /* relinquish message on successful queue of message to mailbox, retain message
+         * on other than success. possible results: 0, -1, ETCH_MAILBOX_TIMEOUT.
+         */
+        result = mbox->message(ibox, g_who2, mymessage);
+
+        CU_ASSERT_EQUAL(result, 0);
+        if (0 != result)
+            etch_object_destroy(mymessage);
+
+        check_mailbox_status(TRUE, ibox, mystateobj, FALSE); 
+
+        /* destroying mailbox causes close which causes our message to be redelivered.
+         * our redelivery override causes that message to arrive in our redelivery list.
+         * that list and its message content is destroyed at teardown_this_test(). 
+         */
+        etch_object_destroy(mbox); 
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_read1()
+ * test read message from mailbox and close box
+ */
+static void test_read1(void)
+{
+    setup_this_test();
+
+    do
+    {   int MYMSGID = 1337;
+        etch_message* mymessage = NULL;
+        etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        check_mailbox(mbox, TRUE, FALSE, FALSE, FALSE, 0);
+        mymessage = new_message(g_type1, 0, (etch_value_factory*) g_vf);
+        message_set_id(mymessage, new_int64(MYMSGID));
+
+        check_deliver(mbox, TRUE, g_who2, mymessage);
+        check_mailbox(mbox, FALSE, FALSE, FALSE, FALSE, 0);
+
+        check_read(mbox, TRUE, g_who2, mymessage);
+        check_mailbox(mbox, TRUE, FALSE, FALSE, FALSE, 0);
+
+        check_close_delivery(mbox, TRUE);
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_read2()
+ * test close delivery before read message from mailbox 
+ */
+static void test_read2(void)
+{
+    setup_this_test();
+
+    do
+    {   int MYMSGID = 1337;
+        etch_message* mymessage = NULL;
+        etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        check_mailbox(mbox, TRUE, FALSE, FALSE, FALSE, 0);
+        mymessage = new_message(g_type1, 0, (etch_value_factory*) g_vf);
+        message_set_id(mymessage, new_int64(MYMSGID));
+
+        check_deliver(mbox, TRUE, g_who2, mymessage);
+        check_mailbox(mbox, FALSE, FALSE, FALSE, FALSE, 0);
+
+        check_close_delivery(mbox, TRUE);
+        check_mailbox(mbox, FALSE, FALSE, TRUE, TRUE, 0);
+
+        /* these checks were different in the java test, assuming it was wrong.
+         * java had us expecting to read something, however the queue was closed above 
+         */
+        check_read(mbox, FALSE, g_who2, mymessage);
+        check_mailbox(mbox, FALSE, FALSE, TRUE, TRUE, 0);
+
+        /* mymessage remains queued in the mailbox. destroying the mailbox destroys the message  */
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_read4()
+ */
+static void test_read4(void)
+{
+    setup_this_test();
+
+    do
+    {   
+        etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+
+        check_close_delivery(mbox, TRUE);
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);
+
+        check_read(mbox, FALSE, NULL, NULL);
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_read6()
+ */
+static void test_read6(void)
+{
+    setup_this_test();
+
+    do
+    {   const int LIFETIME_100 = 100;
+        etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, LIFETIME_100, 2);
+
+        check_close_delivery(mbox, TRUE);
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);
+
+        etch_sleep(2 * LIFETIME_100);
+
+        check_read(mbox, FALSE, NULL, NULL);
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_read7()
+ */
+static void test_read7(void)
+{
+    setup_this_test();
+
+    do
+    {   etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+
+        check_read_withwait(mbox, ETCH_NOWAIT, FALSE, NULL, NULL);
+        check_mailbox(mbox, TRUE, FALSE, FALSE, FALSE, 0);
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_read8()
+ */
+static void test_read8(void)
+{
+    setup_this_test();
+
+    do
+    {   const int MAXDELAY_1MS = 1;
+        etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+
+        check_read_withwait(mbox, MAXDELAY_1MS, FALSE, NULL, NULL);
+        check_mailbox(mbox, TRUE, FALSE, FALSE, FALSE, 0);
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_closeread1()
+ * open box and close it for read while empty
+ */
+static void test_closeread1(void)
+{
+    setup_this_test();
+
+    do
+    {   etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        check_close_read(mbox, TRUE);   
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);  
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_closeread2()
+ * open box and close it for delivery while non-empty
+ */
+static void test_closeread2(void)
+{
+    setup_this_test();
+
+    do
+    {   etch_plainmailbox* mbox  = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        etch_message *mymessage1 = new_message(g_type1, 0, (etch_value_factory*) g_vf);
+        message_set_id(mymessage1, new_int64(1)); 
+        #if IS_DEBUG_CONSOLE
+        printf("\n");
+        #endif
+       
+        check_deliver(mbox, TRUE, g_who1, mymessage1);
+        check_mailbox(mbox, FALSE, FALSE, FALSE, FALSE, 0);  
+
+        check_close_read(mbox, TRUE);
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 1);  
+        check_redelivered(mbox, 0, mymessage1);
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_closeread3()
+ * open box and close it for read twice while empty
+ */
+static void test_closeread3(void)
+{
+    setup_this_test();
+
+    do
+    {   etch_plainmailbox* mbox = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        check_close_read(mbox, TRUE);   
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);  
+        // currently we don't get an already closed return when the underlying queue has not
+        // yet been closed. this is benign, but we should really ensure that the queue is closed 
+        // before mailbox state is set to either closed for read or shutdown.
+        // check_close_read(mbox, FALSE); // test disabled due to situation commented above 
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 0);  
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_closeread4()
+ * open box and close it for delivery twice while non-empty
+ */
+static void test_closeread4(void)
+{
+    setup_this_test();
+
+    do
+    {   etch_plainmailbox* mbox  = new_mailbox (g_manager->imanager, 1, -1, 0, 2);
+        etch_message *mymessage1 = new_message(g_type1, 0, (etch_value_factory*) g_vf);
+        message_set_id(mymessage1, new_int64(1)); 
+        #if IS_DEBUG_CONSOLE
+        printf("\n");
+        #endif
+       
+        check_deliver(mbox, TRUE, g_who1, mymessage1);
+        check_mailbox(mbox, FALSE, FALSE, FALSE, FALSE, 0);  
+
+        check_close_read(mbox, TRUE);
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 1);  
+        check_redelivered(mbox, 0, mymessage1);
+
+        // check_close_read(mbox, FALSE);  // test disabled - see test_closeread3 for comment
+        check_mailbox(mbox, TRUE, FALSE, TRUE, TRUE, 1);  
+        check_redelivered(mbox, 0, mymessage1);
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_full1()
+ */
+static void test_full1(void)
+{
+    setup_this_test();
+
+    do
+    {   const int CAPACITY_2 = 2;
+        etch_plainmailbox* mbox  = new_mailbox (g_manager->imanager, 1, -1, 0, CAPACITY_2);
+        etch_message *mymessage1 = new_message(g_type1, 0, (etch_value_factory*) g_vf);
+        etch_message *mymessage2 = new_message(g_type2, 0, (etch_value_factory*) g_vf);
+        message_set_id(mymessage1, new_int64(1)); 
+        message_set_id(mymessage2, new_int64(2));
+        #if IS_DEBUG_CONSOLE
+        printf("\n");
+        #endif
+
+        check_mailbox(mbox, TRUE, FALSE, FALSE, FALSE, 0);  /* should be empty */
+
+        check_deliver(mbox, TRUE, g_who1, mymessage1);
+        check_mailbox(mbox, FALSE, FALSE, FALSE, FALSE, 0); /* should be non-empty */
+
+        check_deliver(mbox, TRUE, g_who2, mymessage2);
+        check_mailbox(mbox, FALSE, TRUE, FALSE, FALSE, 0);  /* should be full */
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_full2()
+ */
+static void test_full2(void)
+{
+    setup_this_test();
+
+    do
+    {   const int CAPACITY_2 = 2;
+        etch_plainmailbox* mbox  = new_mailbox (g_manager->imanager, 1, -1, 0, CAPACITY_2);
+        etch_message *mymessage1 = new_message(g_type1, 0, (etch_value_factory*) g_vf);
+        etch_message *mymessage2 = new_message(g_type2, 0, (etch_value_factory*) g_vf);
+        message_set_id(mymessage1, new_int64(1)); 
+        message_set_id(mymessage2, new_int64(2));
+        #if IS_DEBUG_CONSOLE
+        printf("\n");
+        #endif
+
+        check_deliver(mbox, TRUE, g_who1, mymessage1);      /* deliver message 1 */
+        check_mailbox(mbox, FALSE, FALSE, FALSE, FALSE, 0); /* should be non-empty */
+
+        check_deliver(mbox, TRUE, g_who2, mymessage2);      /* deliver message 2 */
+        check_mailbox(mbox, FALSE, TRUE, FALSE, FALSE, 0);  /* box should be full */
+
+        check_deliver(mbox, FALSE, g_who1, mymessage2);     /* deliver should fail */
+        check_mailbox(mbox, FALSE, TRUE, FALSE, FALSE, 0);  /* box should still be full */
+
+        etch_object_destroy(mbox);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_plainmailbox_suite()
+{    
+    CU_pSuite pSuite = CU_add_suite("plain mailbox test suite", init_suite, clean_suite);
+    
+    CU_add_test(pSuite, "test mailbox map", test_mailboxes_map); 
+    CU_add_test(pSuite, "test setup teardown", test_setup_teardown); 
+    CU_add_test(pSuite, "test constructor", test_constructor); 
+
+    CU_add_test(pSuite, "test delivery", test_deliver); 
+
+    CU_add_test(pSuite, "test close delivery 1", test_closedelivery1);
+    CU_add_test(pSuite, "test close delivery 2", test_closedelivery2);
+    CU_add_test(pSuite, "test close delivery 3", test_closedelivery3);
+
+    CU_add_test(pSuite, "test timer", test_timer); 
+
+    CU_add_test(pSuite, "test notify a", test_notify1); 
+    CU_add_test(pSuite, "test notify b", test_notify2); 
+    CU_add_test(pSuite, "test notify c", test_notify3);
+    CU_add_test(pSuite, "test notify d", test_notify4); 
+
+    CU_add_test(pSuite, "test read a", test_read1); 
+    CU_add_test(pSuite, "test read b", test_read2);
+    CU_add_test(pSuite, "test read c", test_read4);
+    CU_add_test(pSuite, "test read d", test_read6);
+    CU_add_test(pSuite, "test read e", test_read7);
+    CU_add_test(pSuite, "test read f", test_read8);
+
+    CU_add_test(pSuite, "test close read 1", test_closeread1);
+    CU_add_test(pSuite, "test close read 2", test_closeread2);
+    CU_add_test(pSuite, "test close read 3", test_closeread3);
+    CU_add_test(pSuite, "test close read 4", test_closeread4);
+
+    CU_add_test(pSuite, "test full 1", test_full1);
+    CU_add_test(pSuite, "test full 2", test_full2);
+
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/transport/test_queue.c b/binding-c/runtime/c/src/test/transport/test_queue.c
new file mode 100644
index 0000000..3f998e3
--- /dev/null
+++ b/binding-c/runtime/c/src/test/transport/test_queue.c
@@ -0,0 +1,739 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_queue.c 
+ */
+#include "etch_runtime.h"
+#include "etch_queue.h"
+#include "etch_thread.h"
+#include "etch_objecttypes.h"
+#include "etch_threadpool_apr.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - 
+ * unit test support
+ * - - - - - - - - - - - - - -
+ */
+
+#define NUMBER_CONSUMERS     2  
+#define CONSUMER_ACTIVITY    4
+#define NUMBER_PRODUCERS     3  
+#define PRODUCER_ACTIVITY    5
+#define ERROR_BAD_THREADDATA 1
+static int g_error, g_producercount, g_consumercount, g_unique_id, g_pro, g_con;
+
+
+static unsigned next_test_id()
+{
+    apr_atomic_inc32 ((volatile apr_uint32_t*) &g_unique_id);
+    return g_unique_id;
+}
+
+static unsigned next_producer()
+{
+    apr_atomic_inc32 ((volatile apr_uint32_t*) &g_pro);
+    return g_pro;
+}
+
+static unsigned next_consumer()
+{
+    apr_atomic_inc32 ((volatile apr_uint32_t*) &g_con);
+    return g_con;
+}
+
+ 
+/**
+ * push_some_objects()
+ * push specified number of new objects onto the queue
+ */
+static int push_some_objects(etch_queue* q, const int howmany)
+{
+    int count = 0, result = 0;
+
+    while(count < howmany && result == 0)   
+          result = etchqueue_put_withwait(q, ETCH_NOWAIT, new_int32(count++));
+
+    return result;
+}
+
+
+/**
+ * pop_some_objects()
+ * pop specified number of objects off the queue and destroy each object retrieved
+ */
+static int pop_some_objects(etch_queue* q, const int howmany)
+{
+    int count = 0, result = 0;
+    etch_object* thisobj = NULL;
+
+    while(count++ < howmany && result == 0)
+    {
+      result = etchqueue_get_withwait(q, ETCH_NOWAIT, (void**)&thisobj);
+        etch_object_destroy(thisobj);
+        thisobj = NULL;
+    }
+
+    return result;
+}
+
+
+#if 0
+/**
+ * pop_all_objects()
+ * pop all objects off the queue and destroy each object retrieved
+ */
+static int pop_all_objects(etch_queue* q)
+{
+    int popcount = 0, result = 0;
+    const int queuecount = etchqueue_size(q);
+    etch_object* thisobj = NULL;
+
+    while(popcount++ < queuecount && result == 0)
+    {
+      result = etchqueue_get_withwait(q, ETCH_NOWAIT, (void**)&thisobj);
+        if (thisobj) 
+            thisobj->destroy(thisobj);
+        thisobj = NULL;
+    }
+
+    return result;
+}
+#endif
+
+/**
+ * mytest_threaddata()
+ * thread data for our test threads. we could pass the queue directly, but then
+ * we'd have to configure the threadpool to not destroy a thread's data.
+ */
+typedef struct mytest_threaddata  { etch_queue* queue; }  mytest_threaddata;
+
+#if 0
+/**
+ * new_testdata()
+ * constructor for test thread data
+ */
+static mytest_threaddata* new_testdata(etch_queue* q)
+{
+    mytest_threaddata* td = etch_malloc(sizeof(mytest_threaddata), 0);
+    td->queue = q;
+    return td;
+}
+#endif
+
+/**
+ * consumer_threadproc()
+ * consumer thread procedure. derived from APR queue test.
+ */
+static void consumer_threadproc(void *data)
+{
+    etch_thread_params* params = (etch_thread_params*) data;
+    etch_queue* queue = (etch_queue*) params->data; 
+
+    int result = 0; 
+    etch_int32* content = NULL;    
+    int64 sleeprate = 1000000/CONSUMER_ACTIVITY;
+    next_consumer();
+
+    if (!is_etch_queue(queue)) /* can't test assert outside main thread */
+    {          
+        printf("consumer_threadproc data is not etch_queue\n");      
+        g_error = ERROR_BAD_THREADDATA;
+        return;
+    }  
+
+    #if IS_DEBUG_CONSOLE
+    printf("start consumer thread %d\n", thisthread); fflush(stdout);
+    #endif
+
+    etch_sleep((rand() % 4) * 1000);  /* sleep random seconds */
+
+    while(-1 != result)  /* until shutdown ... */
+    {
+        g_consumercount++;
+                               
+        switch(result = etchqueue_get(queue, (void**)&content))
+        {
+            case -1:   
+                 break;     /* shutdown or error */
+
+            case ETCH_QUEUE_OPERATION_CANCELED: 
+                 continue;  /* signaled */
+
+            case ETCH_QUEUE_OPERATION_TIMEOUT:
+            default:        /* timed out (try again) or success */
+
+                 if (content)
+                 {   
+                     #if IS_DEBUG_CONSOLE
+                     printf("consumer thread %d popped content %d\n", thisthread, content->value); fflush(stdout);
+                     #endif
+                     etch_object_destroy(content);
+                     content = NULL;
+                 }
+                 apr_sleep(sleeprate); /* sleep this long to achieve our rate */
+        }
+    }
+
+    #if IS_DEBUG_CONSOLE
+    printf("consumer thread %d exit\n", thisthread); fflush(stdout);
+    #endif
+}
+
+
+/**
+ * producer_threadproc()
+ * producer thread procedure. derived from APR queue test.
+ */
+static void producer_threadproc(void *data)
+{
+    etch_thread_params* params = (etch_thread_params*) data;
+    etch_queue* queue = (etch_queue*) params->data; 
+
+    int result = 0, is_timeout = 0;
+    etch_int32* newcontent = NULL;
+    const int thisthread = next_producer();
+    int64 sleeprate = 1000000/PRODUCER_ACTIVITY;
+
+    if (!is_etch_queue(queue)) /* can't test assert outside main thread */
+    {   printf("producer_threadproc data is not etch_queue\n");
+        g_error = ERROR_BAD_THREADDATA;
+        return;
+    } 
+
+    #if IS_DEBUG_CONSOLE
+    printf("start producer thread %d\n", thisthread); fflush(stdout); 
+    #endif
+
+    etch_sleep((rand() % 4) * 1000); /* sleep random seconds */
+
+    while(-1 != result)  /* until shutdown ... */
+    {
+        g_producercount++;   
+
+        if  (is_timeout)
+        {    
+             #ifdef IS_DEBUG_CONSOLE
+             printf("producer thread %d re-pushing content %d\n", thisthread, newcontent->value); fflush(stdout);
+             #endif
+             is_timeout = FALSE;
+        }
+        else 
+        {   newcontent = new_int32(next_test_id());  
+            #if IS_DEBUG_CONSOLE
+            printf("producer thread %d pushing content %d\n", thisthread, newcontent->value); fflush(stdout);
+            #endif
+        }
+
+        switch(result = etchqueue_put(queue, newcontent))
+        {
+            case -1:  /* queue closed or error */ 
+                 etch_object_destroy(newcontent); 
+                 newcontent = NULL;
+                 break;
+
+            case ETCH_QUEUE_OPERATION_CANCELED: 
+                 etch_object_destroy(newcontent); 
+                 newcontent = NULL;
+                 continue; /* signaled */
+
+            case ETCH_QUEUE_OPERATION_TIMEOUT:
+                 is_timeout = TRUE;     /* fall thru ... */
+
+            default:       /* timeout or success */
+                 apr_sleep(sleeprate);   
+        }
+    }
+
+    #if IS_DEBUG_CONSOLE
+    printf("producer thread %d exit\n", thisthread); fflush(stdout);
+    #endif
+}
+
+
+/* - - - - - - - - - - - - - - 
+ * unit tests
+ * - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_constructor
+ */
+static void test_constructor(void)
+{
+    etch_queue* q = new_queue(ETCH_DEFSIZE);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(q); 
+
+    etch_object_destroy(q);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_putget()
+ */
+static void test_putget(void)
+{
+    int result = 0, qdepth = 0;
+    etch_int32* thiscontent = NULL;
+    etch_int32* thiscontent1 = new_int32(1);
+    etch_int32* thiscontent2 = new_int32(2);
+    etch_queue* q = new_queue(ETCH_DEFSIZE);
+     
+    result = etchqueue_put(q, thiscontent1);
+    CU_ASSERT_EQUAL(result,0);
+
+    qdepth = etchqueue_size(q);
+    CU_ASSERT_EQUAL(qdepth,1);
+
+    result = etchqueue_put(q, thiscontent2);
+    CU_ASSERT_EQUAL(result,0);
+
+    qdepth = etchqueue_size(q);
+    CU_ASSERT_EQUAL(qdepth,2);
+
+    result = etchqueue_get(q, (void**)&thiscontent);
+    CU_ASSERT_EQUAL(result,0);
+    result = is_etch_int32(thiscontent);
+    CU_ASSERT_EQUAL(result, TRUE);
+    CU_ASSERT_EQUAL(thiscontent->value, thiscontent1->value);
+
+    qdepth = etchqueue_size(q);
+    CU_ASSERT_EQUAL(qdepth,1);
+
+    result = etchqueue_get(q, (void**)&thiscontent);
+    CU_ASSERT_EQUAL(result,0);
+    result = is_etch_int32(thiscontent);
+    CU_ASSERT_EQUAL(result, TRUE);
+    CU_ASSERT_EQUAL(thiscontent->value, thiscontent2->value);
+
+    qdepth = etchqueue_size(q);
+    CU_ASSERT_EQUAL(qdepth,0);
+
+    etch_object_destroy(q);
+    etch_object_destroy(thiscontent1);
+    etch_object_destroy(thiscontent2);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_bulkputget()
+ */
+static void test_bulkputget(void)
+{
+    int result = 0, qdepth = 0;
+    const int HOWMANY = 3;
+    etch_queue* q = new_queue(HOWMANY);
+     
+    result = push_some_objects(q, HOWMANY);
+    CU_ASSERT_EQUAL(result,0);
+
+    qdepth = etchqueue_size(q);
+    CU_ASSERT_EQUAL(qdepth, HOWMANY);
+
+    result = pop_some_objects(q, HOWMANY);
+    CU_ASSERT_EQUAL(result,0);
+
+    qdepth = etchqueue_size(q);
+    CU_ASSERT_EQUAL(qdepth, 0);
+
+    etch_object_destroy(q);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_destroy_nonempty_queue()
+ * destroy a nonempty queue and ensure content memory is freed as expected
+ */
+static void test_destroy_nonempty_queue(void)
+{
+    int result = 0;
+    const int HOWMANY = 3;
+    etch_queue* q = new_queue(HOWMANY);
+     
+    result = push_some_objects(q, HOWMANY);
+
+    etch_object_destroy(q);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_queue_overflow()
+ */
+static void test_queue_overflow(void)
+{
+    int result = 0, qdepth = 0;
+    const int MAXDEPTH = 2;
+    etch_int32* newcontent = NULL;
+    etch_queue* q = new_queue(MAXDEPTH);
+
+    result = etchqueue_put_withwait(q, ETCH_NOWAIT, newcontent = new_int32(0));
+    CU_ASSERT_EQUAL(result, 0);
+     
+    result = etchqueue_put_withwait(q, ETCH_NOWAIT, newcontent = new_int32(0));
+    CU_ASSERT_EQUAL(result, 0);
+
+    result = etchqueue_try_put(q, newcontent = new_int32(0));
+    CU_ASSERT_EQUAL(result, -1);
+
+    result = etchqueue_put_withwait(q, ETCH_NOWAIT, newcontent);
+    CU_ASSERT_NOT_EQUAL_FATAL(result, 0);
+    etch_object_destroy(newcontent);
+
+    qdepth = etchqueue_size(q);
+    CU_ASSERT_EQUAL(qdepth, MAXDEPTH);
+
+    etch_object_destroy(q);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_queue_underflow()
+ */
+static void test_queue_underflow(void)
+{
+    int result = 0, qdepth = 0;
+    const int MAXDEPTH = 2;
+    etch_int32* content = NULL;
+    etch_queue* q = new_queue(MAXDEPTH);
+
+    result = etchqueue_put_withwait(q, ETCH_NOWAIT, content = new_int32(0));
+    CU_ASSERT_EQUAL(result, 0);
+     
+    result = etchqueue_get_withwait(q, ETCH_NOWAIT, (void**)&content);
+    CU_ASSERT_EQUAL(result, 0);
+    etch_object_destroy(content);
+    content = NULL;
+
+    result = etchqueue_try_get(q, (void**)&content);
+    CU_ASSERT_EQUAL(result, -1);
+
+    result = etchqueue_get_withwait(q, ETCH_NOWAIT, (void**)&content);
+    CU_ASSERT_NOT_EQUAL_FATAL(result, 0);
+
+    qdepth = etchqueue_size(q);
+    CU_ASSERT_EQUAL(qdepth, 0);
+
+    etch_object_destroy(q);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_iterator()
+ */
+static void test_iterator(void)
+{
+    etch_iterator iterator;
+    int  iterated = 0;
+    const int HOWMANY = 3;
+
+    etch_queue* q = new_queue(ETCH_DEFSIZE);
+
+    push_some_objects(q, HOWMANY);
+
+    set_iterator(&iterator, q, &q->iterable);
+
+    while(iterator.has_next(&iterator))
+    {
+        etch_int32* content = (etch_int32*) iterator.current_value;
+        CU_ASSERT_EQUAL_FATAL(is_etch_int32(content), TRUE);
+        CU_ASSERT_EQUAL(content->value, iterated++);
+        
+        iterator.next(&iterator);
+    }  
+
+    CU_ASSERT_EQUAL(iterated, HOWMANY);  
+
+    etch_object_destroy(q);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_blocking()
+ * derived from apr test_queue.
+ * launch some number of threads which blocking write etch objects to a queue, 
+ * and some number of threads which blocking read from the same queue. let the 
+ * threads  do their thing for a while, and close the queue. verify that all 
+ * memory is accounted for.
+ */
+static void test_blocking(void)
+{
+    #define NUMTHREADS NUMBER_CONSUMERS + NUMBER_PRODUCERS
+    int result = 0, i = 0;
+    etch_queue* myqueue = NULL;
+
+    etch_threadpool* threadpool = new_threadpool(ETCH_THREADPOOLTYPE_FREE, ETCH_DEFSIZE);
+    threadpool->is_free_data = FALSE;   /* thread data will be our queue */
+
+    myqueue = new_queue(ETCH_DEFSIZE);  /* create the single queue */
+    srand((unsigned int)apr_time_now());  
+    g_error = g_producercount = g_consumercount = g_unique_id = g_pro = g_con = 0;
+
+    for(i=0; i < NUMBER_CONSUMERS; i++) /* launch all consumer threads */
+    {   void* newthread = threadpool->run(threadpool, consumer_threadproc, myqueue);
+        CU_ASSERT_PTR_NOT_NULL(newthread);
+    }
+
+    for(i=0; i < NUMBER_PRODUCERS; i++) /* launch all producer threads */
+    {   void* newthread = threadpool->run(threadpool, producer_threadproc, myqueue);
+        CU_ASSERT_PTR_NOT_NULL(newthread);
+    }
+
+    etch_sleep(3000);  /* pause long enough to let the threads do some work */ 
+
+    result = etchqueue_close(myqueue, TRUE);  /* mark queue closed and notify all waiters */
+
+    /* pause to observe waiter threads unblocking  
+       etch_sleep(3000);  
+     */
+
+    #ifdef TEST_BLOCKING_PRECLEAR
+    while(1)
+    {   /* when the queue is closed it clears the queue similarly to this. 
+         * this code is here to verify clearing the queue prior to closing it.  
+         */
+        etch_int32* queuecontent = NULL;
+        result = etchqueue_get_withwait(myqueue, ETCHQUEUE_CLEARING_CLOSED_QUEUE, &queuecontent);
+        CU_ASSERT_EQUAL(result, -1);  
+        if (-1 == result) break;
+        etch_object_destroy(queuecontent);
+    } 
+    #endif 
+
+    /* note that we should always destroy (or otherwise join) the queue  
+     * accessor threads, before destroying the queue, as we do here */
+    etch_object_destroy(threadpool);   
+
+    etch_object_destroy(myqueue);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * APR queue test with APR threadpool
+ * - - - - - - - - - - - - - - - - - -
+ */
+
+static etch_apr_queue_t* g_queue; /* global queue for APR queue test */
+
+
+/**
+ * aprqtest_consumer_thread()
+ */
+static void *APR_THREAD_FUNC aprqtest_consumer_thread(apr_thread_t *thd, void *data)
+{
+    long sleeprate;
+    apr_status_t rv;
+    void *v;
+
+    sleeprate = 1000000/CONSUMER_ACTIVITY;
+    apr_sleep((rand() % 4) * 1000000); /* sleep random seconds */
+
+    while (1)
+    {   
+        rv = etch_apr_queue_pop(g_queue, 0, &v);
+
+        if (rv == APR_EINTR)
+            continue;
+        if (rv == APR_EOF)
+            break;
+        apr_sleep(sleeprate); /* sleep this long to acheive our rate */
+    }
+
+    return NULL;
+}
+
+ 
+/**
+ * aprqtest_producer_thread()
+ */
+static void * APR_THREAD_FUNC aprqtest_producer_thread(apr_thread_t *thd, void *data)
+{
+    long sleeprate;
+    apr_status_t rv;
+
+    sleeprate = 1000000/PRODUCER_ACTIVITY;
+    apr_sleep((rand() % 4) * 1000000); /* sleep random seconds */
+
+    while (1)
+    {
+        rv = etch_apr_queue_push(g_queue, 0, NULL);
+
+        if (rv == APR_EINTR)
+            continue;
+        if (rv == APR_EOF)
+            break;
+        apr_sleep(sleeprate); /* sleep this long to acheive our rate */
+    }
+
+    return NULL;
+}
+ 
+
+/**
+ * test_queue_producer_consumer()
+ * this is the APR queue test modified to use etch_apr_queue calls.
+ * it uses the APR threadpool 
+ */
+static void test_queue_producer_consumer(void)
+{   
+    unsigned int i;
+    apr_status_t rv;
+    apr_thread_pool_t *threadpool;
+    const int QUEUE_SIZE = 32, ZEROPRIORITY = 0;
+    void* NULLPARAM = NULL, *NULLOWNER = NULL;
+    srand((unsigned int)apr_time_now());
+    g_error = g_producercount = g_consumercount = g_unique_id = g_pro = g_con = 0;
+
+    rv = etch_apr_queue_create(&g_queue, QUEUE_SIZE, g_etch_main_pool);
+    CU_ASSERT_EQUAL(rv,0);
+
+    rv = etch_apr_thread_pool_create(&threadpool, 0, NUMBER_CONSUMERS + NUMBER_PRODUCERS, g_etch_main_pool);
+    CU_ASSERT_EQUAL(rv,0);
+
+    for (i = 0; i < NUMBER_CONSUMERS; i++) 
+    {
+        rv = etch_apr_thread_pool_push(threadpool, aprqtest_consumer_thread, NULLPARAM, ZEROPRIORITY, NULLOWNER);
+        CU_ASSERT_EQUAL(rv,0);
+    }
+
+    for (i = 0; i < NUMBER_PRODUCERS; i++) 
+    {
+        rv = etch_apr_thread_pool_push(threadpool, aprqtest_producer_thread, NULLPARAM, ZEROPRIORITY, NULLOWNER);
+        CU_ASSERT_EQUAL(rv,0);
+    }
+
+    etch_sleep(5000); /* let threads work for a bit */
+
+    rv = etch_apr_queue_term(g_queue);
+    CU_ASSERT_EQUAL(rv,0);
+
+    /* pause to observe waiter threads unblocking  
+       etch_sleep(3000);  
+     */
+
+    rv = etch_apr_thread_pool_destroy(threadpool);
+    CU_ASSERT_EQUAL(rv,0);;
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_queue()
+{    
+    CU_pSuite pSuite = CU_add_suite("queue test suite", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test constructor", test_constructor); 
+    CU_add_test(pSuite, "test put and get", test_putget);   
+    CU_add_test(pSuite, "test bulk put and get", test_bulkputget);   
+    CU_add_test(pSuite, "test destroy nonempty", test_destroy_nonempty_queue);   
+    CU_add_test(pSuite, "test overflow",  test_queue_overflow);   
+    CU_add_test(pSuite, "test underflow", test_queue_underflow);
+    CU_add_test(pSuite, "test iterator",  test_iterator);
+    CU_add_test(pSuite, "test blocking", test_blocking);
+    CU_add_test(pSuite, "test producer-consumer (APR)", test_queue_producer_consumer);
+
+    return pSuite;
+}
diff --git a/binding-c/runtime/c/src/test/transport/test_tcpconn.c b/binding-c/runtime/c/src/test/transport/test_tcpconn.c
new file mode 100644
index 0000000..d65fb43
--- /dev/null
+++ b/binding-c/runtime/c/src/test/transport/test_tcpconn.c
@@ -0,0 +1,982 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_tcp_connection.c
+ */
+#include "etch_runtime.h"
+#include "etch_connection.h"  /* must be included second */
+#include "etch_tcp_connection.h"  /* must be included second */
+#include "etch_tcp_server.h"
+#include "etch_encoding.h"
+#include "etch_objecttypes.h"
+#include "etch_flexbuffer.h"
+#include "etch_general.h"
+#include "etch_thread.h"
+#include "etch_log.h"
+#include "etch_mem.h"
+#include <wchar.h>
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+static const char* LOG_CATEGORY = "test_etch_tcp_connection";
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+#define RCVBUFLEN 256
+#define TEST_PORT 7302
+#define TEST_IP   L"127.0.0.1"
+static etch_url* g_test_url;
+static char* g_ip8bit;
+
+static char *g_senddata1="By the rude bridge that arched the flood, their flag from April's breeze unfurled";
+static char *g_senddata2="And therefore I have sailed the seas and come, to the holy city of Byzantium.";
+static int   g_buflen1, g_buflen2;
+
+static etch_url* get_test_url() /* build a URL string for the test */
+{   
+    wchar_t buf[256];
+    memset(buf, 0, sizeof(buf));
+    etch_snwprintf(buf, sizeof(buf), L"%ls:%d", TEST_IP, TEST_PORT);
+    return new_url(buf);
+} 
+
+
+/**
+ * setup_a_test()
+ * set up a tcp server test by creating and returning an 
+ * initialized tcp server object.
+ */
+static etch_tcp_server* setup_a_test()
+{
+    etch_tcp_server*        tcp_server  = 0;
+    etch_tcp_connection*    cxl         = 0;
+    etch_threadpool*        pool        = 0;
+    etch_connection*        cx          = 0;
+
+    /* create objects */ 
+    g_test_url = get_test_url();
+    CU_ASSERT_EQUAL_FATAL(wcscmp(g_test_url->host, TEST_IP), 0);
+    CU_ASSERT_EQUAL_FATAL(g_test_url->port, TEST_PORT);
+    // TODO: pool
+    etch_encoding_transcode_wchar(&g_ip8bit, ETCH_ENCODING_UTF8, TEST_IP, NULL);
+
+    pool = new_threadpool (ETCH_THREADPOOLTYPE_FREE, 0); 
+
+    tcp_server = new_tcp_server(g_test_url, pool, pool, NULL, NULL);
+    CU_ASSERT_PTR_NOT_NULL(tcp_server);
+    tcp_server->is_threadpool_owned = TRUE;  /* server now owns pool */
+
+    CU_ASSERT_EQUAL (tcp_server->state, ETCH_TCPSERVER_STATE_CLOSED);
+    CU_ASSERT_NOT_EQUAL (tcp_server->listener_id, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (tcp_server->cxlisten);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (tcp_server->on_event);
+    
+    cxl = tcp_server->cxlisten; /* listen socket connection object */
+    cx  = &cxl->cx; 
+    CU_ASSERT_PTR_NULL_FATAL (cx->socket);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->mutex);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->listener);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->on_event);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->on_data);
+    CU_ASSERT_EQUAL_FATAL (cx->is_ownpool, TRUE);
+    CU_ASSERT_EQUAL_FATAL (cx->is_started, FALSE);
+
+    return tcp_server;
+}
+
+
+/**
+ * teardown_a_test()
+ * tear down a tcp server test by destroying the specified tcp server 
+ * object plus the various objects created to set it up.
+ */
+static void teardown_a_test(etch_tcp_server* listener)
+{
+    etch_free(g_ip8bit);  
+    etch_object_destroy(listener);    
+    etch_object_destroy(g_test_url); g_test_url = NULL;
+}
+
+
+/**
+ * test_server_create_destroy()
+ * test that we can create a tcp server with all expected pieces present,
+ * and subsequently destroy it with all memory accounted for. also tests
+ * creation of a connection object (the server's listener connection).
+ * tests only construction and destruction, no other functionality. 
+ * assuming we run this test early and it passes, we can safely omit 
+ * a lot of asserts in subsequent tests.
+ */
+static void test_server_create_destroy(void)
+{
+    etch_threadpool* thread_manager = 0;
+    etch_tcp_server* tcp_server = 0;
+    etch_tcp_connection* cxl = 0;    
+     
+    etch_connection* cx = 0;
+    etch_url* url = 0;
+    #if IS_DEBUG_CONSOLE 
+    wprintf(L"\n");          
+    #endif   
+
+    /* start - create objects */ 
+    url = get_test_url(); /* we own it */
+    CU_ASSERT_STRING_EQUAL_FATAL(url->host, TEST_IP);
+    CU_ASSERT_EQUAL_FATAL(url->port, TEST_PORT);
+
+    tcp_server = new_tcp_server(url, NULL, NULL, NULL, NULL);
+    CU_ASSERT_PTR_NOT_NULL(tcp_server);
+
+    CU_ASSERT_EQUAL (tcp_server->state, ETCH_TCPSERVER_STATE_CLOSED);
+    CU_ASSERT_EQUAL (tcp_server->listener_id, 2);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (tcp_server->cxlisten);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (tcp_server->on_event);
+    
+    cxl = tcp_server->cxlisten; /* listen socket connection object */
+    cx  = &cxl->cx; 
+    CU_ASSERT_PTR_NULL_FATAL (cx->socket);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->mutex);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->listener);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->on_event);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (cx->on_data);
+    CU_ASSERT_EQUAL_FATAL (cx->is_ownpool, TRUE);
+    CU_ASSERT_EQUAL_FATAL (cx->is_started, FALSE);
+
+    /* done - destroy objects */ 
+    etch_object_destroy(tcp_server);
+    etch_object_destroy(url);
+    etch_object_destroy(thread_manager);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_setup_a_test()
+ * test that we can do the same as test_server_create_destroy(), but using
+ * setup_a_test() and teardown_a_test to create and destroy objects.
+ */
+static void test_setup_a_test(void)
+{
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    teardown_a_test(tcp_server);
+}
+
+
+/**
+ * test_server_open_close()
+ * test that we can create, open, close, and destroy a tcp server 
+ * with all memory accounted for. when server is open, its listen socket is
+ * listening on the designated port. when closed, it is not listening.
+ */
+static void test_server_open_close(void)
+{
+    int result;
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL(result, 0);  /* state stopped means not closed but not started */
+    CU_ASSERT_EQUAL(tcp_server->state, ETCH_TCPSERVER_STATE_STOPPED); 
+
+    if (result == 0)
+    {   result = etch_tcpsvr_close(tcp_server);
+        CU_ASSERT_EQUAL(result, 0);
+        CU_ASSERT_EQUAL(tcp_server->state, ETCH_TCPSERVER_STATE_CLOSED); 
+    }
+
+    teardown_a_test(tcp_server);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_server_start_stop()
+ * test that we can create, open, start, stop, close, and destroy a tcp server 
+ * with all memory accounted for. when server is started, it is accepting
+ * connections from clients.
+ */
+static void test_server_start_stop(void)
+{
+    int result;
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL (tcp_server->threadpool); 
+    CU_ASSERT_EQUAL_FATAL (tcp_server->is_started, TRUE); 
+    CU_ASSERT_EQUAL_FATAL (tcp_server->state, ETCH_TCPSERVER_STATE_STARTED); 
+
+    //getchar();
+    //etch_sleep(1000);
+
+    result = etch_tcpsvr_stop(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_EQUAL_FATAL(tcp_server->is_started, FALSE); 
+    CU_ASSERT_EQUAL_FATAL(tcp_server->state, ETCH_TCPSERVER_STATE_STOPPED); 
+
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0);    
+
+    teardown_a_test(tcp_server);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_server_control_start_stop()
+ */
+static void test_server_control_start_stop(void)
+{
+    int result = 0;
+    etch_event *startevent = NULL, *stopevent = NULL;
+
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    startevent = new_etch_event(CLASSID_CONTROL_START, 0); /* we relinquish this */
+    result = tcp_server->transport_control(tcp_server, startevent, NULL);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_EQUAL(tcp_server->is_started, TRUE); 
+
+    stopevent = new_etch_event(CLASSID_CONTROL_STOP, 0);  /* we relinquish this */
+    result = tcp_server->transport_control(tcp_server, stopevent, NULL);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_EQUAL(tcp_server->is_started, FALSE); 
+  
+    teardown_a_test(tcp_server);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_server_control_waitup_waitdown()
+ */
+static void test_server_control_waitup_waitdown(void)    
+{
+    int result = 0;
+    etch_event *waitupevent = NULL, *waitdownevent = NULL;
+    etch_int32 *waituptime  = NULL, *waitdowntime  = NULL;
+
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    waitupevent = new_etch_event(CLASSID_CONTROL_START_WAITUP, 0); /* we relinquish this */
+    waituptime  = new_int32(5000);  /* we relinquish this */
+    result = tcp_server->transport_control(tcp_server, waitupevent, (etch_object*)waituptime);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_EQUAL(tcp_server->is_started, TRUE); 
+
+    waitdownevent = new_etch_event(CLASSID_CONTROL_STOP_WAITDOWN, 0);  /* we relinquish this */
+    waitdowntime  = new_int32(5000);  /* we relinquish this */
+    result = tcp_server->transport_control(tcp_server, waitdownevent, (etch_object*)waitdowntime);
+    CU_ASSERT_EQUAL(result, 0);
+    CU_ASSERT_EQUAL(tcp_server->is_started, FALSE); 
+
+    teardown_a_test(tcp_server);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_connect_to_server()
+ * test that we can open and close a client connection to a tcp server.
+ */
+static void test_connect_to_server(void)
+{
+    int result;
+    etch_tcp_connection* cxclient = 0;
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    etch_sleep(1000);  
+
+    cxclient = new_tcp_connection(g_test_url, NULL, NULL);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient);
+
+    result = etch_tcpconx_open(cxclient, FALSE);
+
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_STRING_EQUAL_FATAL(cxclient->cx.hostname, g_ip8bit);
+    CU_ASSERT_EQUAL_FATAL(cxclient->cx.port, TEST_PORT);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient->cx.on_event);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient->cx.on_data);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient->cx.aprpool);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient->cx.socket);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient->cx.mutex);
+  
+    etch_sleep(500);
+
+    result = etch_tcpconx_close(cxclient, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_stop(tcp_server);
+
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_EQUAL_FATAL(tcp_server->is_started, FALSE); 
+    CU_ASSERT_EQUAL_FATAL(tcp_server->state, ETCH_TCPSERVER_STATE_STOPPED); 
+
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    /* free items created here */
+    etch_object_destroy(cxclient);
+
+    teardown_a_test(tcp_server);
+ 
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+
+/**
+ * test_multiple_connect_to_server()
+ * test that we can open and close two concurrent connections to a tcp server.
+ */
+static void test_multiple_connect_to_server(void)
+{
+    int result;
+    etch_tcp_connection *cxclient_a = 0, *cxclient_b = 0;
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    etch_sleep(500);  
+
+    cxclient_a = new_tcp_connection(g_test_url, NULL, NULL);
+    cxclient_b = new_tcp_connection(g_test_url, NULL, NULL);
+
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_a);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b);
+
+    result = etch_tcpconx_open(cxclient_a, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpconx_open(cxclient_b, FALSE);
+
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_STRING_EQUAL_FATAL(cxclient_b->cx.hostname, g_ip8bit);
+    CU_ASSERT_EQUAL_FATAL(cxclient_b->cx.port, TEST_PORT);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b->cx.on_event);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b->cx.on_data);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b->cx.aprpool);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b->cx.socket);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b->cx.mutex);
+
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "client a ID is %d\n", cxclient_a->cx.conxid); 
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "client b ID is %d\n", cxclient_b->cx.conxid); 
+    etch_sleep(500);
+
+    result = etch_tcpconx_close(cxclient_a, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpconx_close(cxclient_b, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_stop(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_EQUAL_FATAL(tcp_server->is_started, FALSE); 
+    CU_ASSERT_EQUAL_FATAL(tcp_server->state, ETCH_TCPSERVER_STATE_STOPPED); 
+
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    /* free items created here */
+    etch_object_destroy(cxclient_a);
+    etch_object_destroy(cxclient_b);
+
+    teardown_a_test(tcp_server);
+ 
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_multiple_connect_to_server()
+ * test that we can open and close two concurrent connections to a tcp server.
+ */
+static void test_max_connections(void)
+{
+    int result;
+    int i = 0;
+    etch_tcp_connection **cxclient = malloc(40 * sizeof(etch_tcp_connection*));
+    etch_tcp_connection *cxclient_last = NULL;
+
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    etch_sleep(1000);  
+
+    for(i = 0; i < 40; i++){
+        cxclient[i] = new_tcp_connection(g_test_url, NULL, NULL);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient[i]);
+        result = etch_tcpconx_open(cxclient[i],0);
+        etch_sleep(25);
+        CU_ASSERT(tcp_server->connections == i + 1);
+    }
+    
+    CU_ASSERT(tcp_server->connections == 40);
+
+    cxclient_last = new_tcp_connection(g_test_url, NULL, NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_last);
+    result = etch_tcpconx_open(cxclient_last,0);
+    
+    CU_ASSERT(tcp_server->connections == 40);
+    etch_sleep(200);  
+    
+    etch_tcpconx_close(cxclient_last,0);
+
+    for(i = 0; i < 40; i++){
+        etch_tcpconx_close(cxclient[i],0);
+    }
+
+    result = etch_tcpsvr_stop(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    CU_ASSERT_EQUAL_FATAL(tcp_server->is_started, FALSE); 
+    CU_ASSERT_EQUAL_FATAL(tcp_server->state, ETCH_TCPSERVER_STATE_STOPPED); 
+
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    /* free items created here */
+    etch_object_destroy(cxclient_last);
+
+    teardown_a_test(tcp_server);
+ 
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/*
+ * on_data_server_test_write_to_server()
+ * server on_data overide for the test_write_to_server() test 
+ */
+static int on_data_server_test_write_to_server(void* data, const int unused, int len, void* bufferData)
+{
+  etch_tcp_connection* c = (etch_tcp_connection*)data;
+  etch_flexbuffer* fbuf = (etch_flexbuffer*)bufferData;
+    int result = 0;
+    char* datacopy = 0;
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "conxn %d on_data server test overide got %d bytes ...\n", 
+        c->cx.conxid, len);    
+    datacopy = etch_malloc(len+2,0); 
+    memcpy(datacopy, fbuf->buf, len);
+    datacopy[len] = '\n'; datacopy[len+1] = '\0';
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, datacopy); 
+    etch_free(datacopy);
+    return result;
+}
+
+
+/**
+ * test_write_to_server()
+ * test that we can send a message to a tcp server.
+ */
+static void test_write_to_server(void)
+{
+    int result = 0;
+    int arc = 0;
+    etch_tcp_connection* cxclient = 0;
+
+    etch_tcp_server* tcp_server = setup_a_test();
+    CU_ASSERT_PTR_NOT_NULL_FATAL(tcp_server);
+
+    /* this test overrides server's accepted connection data handler */
+    tcp_server->on_data = on_data_server_test_write_to_server;  
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    etch_sleep(500); /* not needed, used for watching console */ 
+
+    cxclient = new_tcp_connection(g_test_url, NULL, NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient);
+
+    result = etch_tcpconx_open(cxclient, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    /* send data to server */
+    etch_tcpclient_send(cxclient, (unsigned char*)g_senddata1, g_buflen1, &arc);
+
+    /* if omit this sleep, server receives both sends as one,  
+     * either way is is fine */
+    etch_sleep(200); 
+
+    /* send more data to server */
+    etch_tcpclient_send(cxclient, (unsigned char*)g_senddata2, g_buflen2, &arc);  
+
+    etch_sleep(500); /* not needed, used for watching console */
+
+    result = etch_tcpconx_close(cxclient, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    /* test that we can omit an explicit server stop */
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    /* free items created here */
+    etch_object_destroy(cxclient);
+
+    teardown_a_test(tcp_server);
+ 
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+#if 0
+/*
+ * on_data_server_test_write_with_readback()
+ * receive data handler for server side of test_write_with_readback
+ * this is not executed on the main thread, so no CU_ASSERTs can appear here.
+ * logs data received at the tcp server and sends it back to client
+ */
+static int on_data_server_test_write_with_readback(void* data, const int unused, int length, void* bufferData)
+{
+  etch_connection* cx = (etch_connection*)data;
+  etch_flexbuffer* fbuf = (etch_flexbuffer*)bufferData;
+    int result = 0;
+    char* datacopy = 0; int arc = 0;
+    etch_tcp_server* tcps = (etch_tcp_server*) cx->listener;
+    etch_tcp_connection* tcpx = tcps? tcps->cxlisten: NULL;
+    assert(is_etch_tcpserver(tcps));
+    assert(is_etch_tcpconnection(tcpx));
+ 
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, 
+        "connxn %d TEST SERVER ONDATA GOT %d bytes ...\n", cx->conxid, length);
+
+    datacopy = etch_malloc(length+2,0); memcpy(datacopy, fbuf->buf, length);
+    datacopy[length] = '\n'; datacopy[length+1] = '\0';
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, datacopy); 
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, 
+        "conxn %d TEST SERVER ONDATA RESENDING to client \n", tcpx->cx.conxid);
+    etch_tcpclient_send(tcpx, fbuf->buf, length, &arc); /* return to sender */
+    etch_free(datacopy);
+    return result;
+}
+
+
+/*
+ * on_data_client_test_write_with_readback()
+ * receive data handler for client side of test_write_with_readback 
+ * just logs the data received back from tcp server 
+ */
+static int on_data_client_test_write_with_readback (etch_tcp_connection* c, const int unused, int length, char* data)
+{
+    int result = 0;
+    char* datacopy = 0;
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, 
+        "connxn %d TEST CLIENT ONDATA GOT %d bytes ...\n", c->cx.conxid, length);
+    datacopy = etch_malloc(length+2,0); memcpy(datacopy, data, length);
+    datacopy[length] = '\n'; datacopy[length+1] = '\0';
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, datacopy); 
+    etch_free(datacopy);
+    return result;
+}
+
+
+/**
+ * test_write_with_readback()
+ * test that we can send data to server and that server can send it back to us
+ */
+static void test_write_with_readback(void)
+{
+    char rcvbuf[RCVBUFLEN]; 
+    int result = 0, datalen = 0, sndrc = 0, rcvrc = 0;
+    etch_tcp_connection *cxclient = 0;
+    etch_tcp_server *tcp_server = 0;
+    etch_tcp_client *tcp_client = 0;
+
+    /* 
+     * create and start a tcp server  
+     */
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "CREATING SERVER\n");
+    tcp_server = setup_a_test(); 
+    /* override server's accepted socket data handler to be our test handler */
+    tcp_server->on_data = on_data_server_test_write_with_readback;
+
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "STARTING SERVER\n");
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    /* 
+     * open a client connection and listener 
+     */
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "CREATING CLIENT CONNECTION\n");
+    cxclient = new_tcp_connection(g_test_url, NULL, NULL);
+    cxclient->cx.on_data = on_data_client_test_write_with_readback;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient);
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "client connection ID is %d\n", cxclient->cx.conxid); 
+
+   /* opening this client connection results in an accepted connection on our server.
+    * that accepted connection will recognize and use our test data handler, since we
+    * overrode that handler above. */
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "OPENING CLIENT CONNECTION\n");
+    result = etch_tcpconx_open (cxclient, FALSE);
+    etch_sleep(100);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    /* start a client side listener for the client socket - this is normally done
+     * via a start/waitup mechanism, however for the unit test we do so explicitly here.
+     * note that the tcp_client class is normally not visible, we expose it for the test. */
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "STARTING CLIENT LISTENER THREAD\n");
+    result = etch_tcpclient_start_listener (cxclient);
+    etch_sleep(100);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    tcp_client = cxclient->rcvlxr; /* check the mutual tcp connection references */
+    CU_ASSERT_PTR_EQUAL_FATAL(cxclient, tcp_client->cxlisten);
+
+    /* 
+     * send data to server and receive data back from server
+     * note that both server and client data handlers are overridden above
+     */
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "SENDING DATA TO SERVER\n");
+    etch_tcpclient_send(cxclient, g_senddata1, g_buflen1, &sndrc);  
+    datalen = etch_tcpclient_receive(cxclient, rcvbuf, RCVBUFLEN, &rcvrc);     
+
+    CU_ASSERT_EQUAL(datalen, g_buflen1); /* verify sent == received */
+    CU_ASSERT_EQUAL(0, memcmp(rcvbuf, g_senddata1, datalen));
+
+    /* 
+     * send more data to server and receive data back from server
+     */
+    //ETCH_LOG("TEST", ETCH_LOG_DEBUG, "SENDING MORE DATA TO SERVER\n");
+    //etch_tcpclient_send(cxclient, g_senddata2, g_buflen2, &sndrc); 
+    //datalen = etch_tcpclient_receive(cxclient, rcvbuf, RCVBUFLEN, &rcvrc);  
+
+    //CU_ASSERT_EQUAL(datalen, g_buflen2); /* verify sent == received */
+    //CU_ASSERT_EQUAL(0, memcmp(rcvbuf, g_senddata2, datalen));   
+
+    /* stop the client side listener thread - this is normally done via a
+     * stop/waitdown mechanism, however for the unit test we do so explicitly here */
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "STOPPING CLIENT LISTENER THREAD\n");
+    result = etch_tcpclient_stop_listener (cxclient);
+    etch_sleep(100);
+    CU_ASSERT_EQUAL_FATAL(result, 0);      
+   
+    /* 
+     * close client connection
+     */
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "CLOSING CLIENT CONNECTION\n");
+    result = etch_tcpconx_close(cxclient, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    /* 
+     * shut down tcp server  
+     */
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "STOPPING SERVER\n");
+    result = etch_tcpsvr_stop(tcp_server); /* could omit this */
+    CU_ASSERT_EQUAL(result, 0);  
+   
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "CLOSING SERVER\n");
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    /* 
+     * free memory
+     */
+    etch_object_destroy(cxclient);
+
+    teardown_a_test(tcp_server);
+ 
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+#endif
+
+#if 0
+/**
+ * test_multiple_client_write_with_readback()
+ * test that two clients can send data to server and receive it back.
+ */
+static void test_multiple_client_write_with_readback(void)
+{
+    char rcvbuf[RCVBUFLEN]; 
+    int result = 0, datalen = 0, sndrc = 0, rcvrc = 0;
+    etch_tcp_connection *cxclient_a = 0, *cxclient_b = 0;
+    etch_tcp_server* tcp_server = 0;
+
+    /* 
+     * create and start a tcp server  
+     */
+    tcp_server = setup_a_test(); 
+    tcp_server->on_data = on_data_server_test_write_with_readback;
+
+    result = etch_tcpsvr_open(tcp_server, 0);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+
+    result = etch_tcpsvr_start(tcp_server);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    etch_sleep(500);
+
+    /* 
+     * open multiple client connections   
+     */
+    cxclient_a = new_tcp_connection(g_test_url, NULL, NULL);
+    cxclient_a->cx.on_data = on_data_client_test_write_with_readback;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_a);
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "client a id is %d\n", cxclient_a->cx.conxid); 
+
+    cxclient_b = new_tcp_connection(g_test_url, NULL, NULL);
+    cxclient_b->cx.on_data /* override data handler */
+        = on_data_client_test_write_with_readback;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(cxclient_b);
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "client b id is %d\n", cxclient_b->cx.conxid); 
+
+    result = etch_tcpconx_open(cxclient_a, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    result = etch_tcpconx_open(cxclient_b, FALSE);
+    CU_ASSERT_EQUAL_FATAL(result, 0);
+    etch_sleep(500);
+
+    /* 
+     * client a send data to server and receive data back from server
+     */
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "client a sending data\n", cxclient_b->cx.conxid); 
+    etch_tcpclient_send(cxclient_a, g_senddata1, g_buflen1, &sndrc);  
+    datalen = etch_tcpclient_receive(cxclient_a, rcvbuf, RCVBUFLEN, &rcvrc); 
+
+    CU_ASSERT_EQUAL(datalen, g_buflen1); /* verify sent == received */
+    CU_ASSERT_EQUAL(0, memcmp(rcvbuf, g_senddata1, datalen));
+
+    /* 
+     * client b send data to server and receive data back from server
+     */
+    ETCH_LOG("TEST", ETCH_LOG_DEBUG, "client b sending data\n", cxclient_b->cx.conxid); 
+    etch_tcpclient_send(cxclient_b, g_senddata2, g_buflen2, &sndrc); 
+    datalen = etch_tcpclient_receive(cxclient_b, rcvbuf, RCVBUFLEN, &rcvrc);  
+
+    CU_ASSERT_EQUAL(datalen, g_buflen2); /* verify sent == received */
+    CU_ASSERT_EQUAL(0, memcmp(rcvbuf, g_senddata2, datalen)); 
+    etch_sleep(500);    
+   
+    /* 
+     * close client connections
+     */
+    result = etch_tcpconx_close(cxclient_a, FALSE);
+    CU_ASSERT_EQUAL(result, 0);
+    result = etch_tcpconx_close(cxclient_b, FALSE);
+    CU_ASSERT_EQUAL(result, 0);
+
+    /* 
+     * shut down tcp server  
+     */
+    result = etch_tcpsvr_close(tcp_server);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    /* 
+     * free memory
+     */
+    etch_object_destroy(cxclient_a);
+    etch_object_destroy(cxclient_b);
+
+    teardown_a_test(tcp_server);
+ 
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+#endif
+
+
+#if 0
+/**
+ * test_receive_with_timeout()
+ * test that we can time out a receive operation
+ */
+static void test_receive_with_timeout(void)
+{  
+    char rcvbuf[RCVBUFLEN]; 
+    int result = 0, datalen = 0, sndrc = 0, rcvrc = 0;
+    etch_tcp_connection* cxclient = 0;
+    etch_tcp_server* tcp_server = 0;
+
+    tcp_server = setup_a_test(); 
+    tcp_server->on_data = on_data_server_test_write_with_readback;
+    result = etch_tcpsvr_open (tcp_server, 0);
+    result = etch_tcpsvr_start(tcp_server);
+
+    cxclient = new_tcp_connection(g_test_url, NULL, NULL);
+    result = etch_tcpconx_open(cxclient, FALSE);
+
+    /* do one send and two receives, the 2nd with 2-second timeout */
+    etch_tcpclient_send(cxclient, g_senddata1, g_buflen1, &sndrc);  
+    datalen = etch_tcpclient_receive (cxclient, rcvbuf, RCVBUFLEN, &rcvrc);  
+    datalen = etch_tcpclient_receivex(cxclient, rcvbuf, RCVBUFLEN, 2000, &rcvrc);  
+    CU_ASSERT_EQUAL(IS_ETCH_SOCKET_TIMEOUT(rcvrc), TRUE);  
+   
+    result = etch_tcpconx_close(cxclient, FALSE);
+    result = etch_tcpsvr_close(tcp_server);
+    etch_object_destroy(cxclient);
+    teardown_a_test(tcp_server);
+ 
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+#endif
+
+/**
+ * main   
+ */
+//int _tmain(int argc, _TCHAR* argv[])
+CU_pSuite test_etch_tcpconn_suite()
+{
+    CU_pSuite ps = CU_add_suite("suite_tcpconn", init_suite, clean_suite);
+
+    CU_add_test(ps, "test max number of connections", test_max_connections);
+
+    CU_add_test(ps, "test create and destroy tcp server", test_server_create_destroy);
+    CU_add_test(ps, "test test setup and teardown", test_setup_a_test);
+    CU_add_test(ps, "test tcp server open/close", test_server_open_close);
+    CU_add_test(ps, "test tcp server start/stop", test_server_start_stop);
+
+    CU_add_test(ps, "test server control start/stop", test_server_control_start_stop);
+    CU_add_test(ps, "test server control wait up/down", test_server_control_waitup_waitdown);
+
+    CU_add_test(ps, "test connect to server", test_connect_to_server);
+    CU_add_test(ps, "test multiple connect to server", test_multiple_connect_to_server);
+    CU_add_test(ps, "test write to server", test_write_to_server);
+
+    /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     * these last three tests used to work but are now broken.
+     * all tests that return data from server to client no longer work.
+     * the re-send of data back to client finds "socket not connected" .
+     * the production mailbox stuff works, so not sure what the problem is 
+     * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+     */
+    // CU_add_test(ps, "test write with readback", test_write_with_readback);   
+    // CU_add_test(ps, "test multiple client write/read", test_multiple_client_write_with_readback);  
+    // CU_add_test(ps, "test receive with timeout", test_receive_with_timeout);  
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/transport/test_threadpool.c b/binding-c/runtime/c/src/test/transport/test_threadpool.c
new file mode 100644
index 0000000..e039229
--- /dev/null
+++ b/binding-c/runtime/c/src/test/transport/test_threadpool.c
@@ -0,0 +1,1417 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_threadpool.c
+ */
+#include "etch_runtime.h"
+#include "etch_thread.h"
+#include "etch_mutex.h"
+#include "etch_wait.h"
+#include "etch_arraylist.h"
+#include "etch_mem.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE FALSE
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+static etch_mutex* mutex_threadid;
+static int g_next_threadid;
+
+#define IS_DUMP_AFTER_REMOVE FALSE
+#define IS_TESTING_REMOVE    TRUE
+#define THREAD_TESTDATA_SIG 0xfeedface
+struct usertestdata { int x; int y; };
+
+static int next_threadid()
+{
+    etch_mutex_lock(mutex_threadid);
+    ++g_next_threadid;
+    etch_mutex_unlock(mutex_threadid);
+    return g_next_threadid;
+}
+
+/*
+ * get_threaddata()
+ * get a handle to internal thread create parameters
+ */
+static etch_apr_threaddata* get_threaddata()
+{
+    static etch_apr_threaddata tdata;
+    memset(&tdata, 0, sizeof(etch_apr_threaddata));
+    return &tdata;
+}
+
+
+/**
+ * on_threadstart()
+ * thread start callback
+ */
+static int on_threadstart(void* param)
+{
+    #if (IS_DEBUG_CONSOLE)
+    if  (NULL == param) 
+         printf("pool thread start\n");  
+    else printf("pool thread %04x start\n", params->etch_thread_id); 
+    fflush(stdout);
+    #endif
+    return 0;
+}
+
+
+/**
+ * on_threadexit()
+ * thread stop callback
+ */
+static int on_threadexit(void* param)
+{
+    #if (IS_DEBUG_CONSOLE)
+    if  (NULL == param)
+         printf("pool thread exit\n");  
+    else printf("pool thread %04x exit\n", params->etch_thread_id); 
+    fflush(stdout);
+    #endif
+    return 0;
+}
+
+
+/**
+ * createthread_threadproc
+ */
+static void createthread_threadproc(void* data)
+{
+    etch_thread_params* params;
+    struct usertestdata* ud; 
+    #if (IS_DEBUG_CONSOLE)
+    printf("in createthread_threadproc\n"); 
+    #endif
+
+    params = (etch_thread_params*) data;
+    ud = (struct usertestdata*) params->data;
+    CU_ASSERT_PTR_NOT_NULL_FATAL(ud);
+    CU_ASSERT_EQUAL(ud->x, 1);
+    CU_ASSERT_EQUAL(ud->y, 2);
+}
+
+
+/**
+ * test_createthread
+ */
+static void test_createthread(void)
+{
+    int result = 0;
+    etch_thread_params tp;
+    struct usertestdata  ud;
+    etch_apr_threaddata* td = get_threaddata();
+    memset(&tp, 0, sizeof(etch_thread_params));
+    ud.x = 1; ud.y = 2;
+
+    // TODO: pool
+    etch_mutex_create(&mutex_threadid, ETCH_MUTEX_NESTED, NULL);
+
+    etch_init_threadparams(&tp);
+    tp.etch_thread_id = next_threadid();
+    tp.data       = &ud;
+    tp.libdata    = td;
+    tp.on_start   = on_threadstart;
+    tp.on_exit    = on_threadexit;
+    tp.threadproc = createthread_threadproc;
+    #if (IS_DEBUG_CONSOLE)
+    printf("\n");
+    #endif
+    
+    result = etch_createthread(&tp);    
+    CU_ASSERT_EQUAL(result, 0);
+
+    etch_thread_join(&tp);  /* block until thread exit */
+    CU_ASSERT_EQUAL(result, 0);
+
+    etch_mutex_destroy(mutex_threadid);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * mutextestparams
+ * thread data for mutex test
+ */
+struct mutextestparams
+{
+    unsigned signature;
+    etch_mutex* mutex;
+    unsigned flag;
+};
+
+
+/**
+ * mutex_threadproc_a
+ */
+static void mutex_threadproc_a(void* data)
+{
+    etch_status_t status;
+    int result = 0;
+    etch_thread_params* params;
+    struct mutextestparams* p;
+    params = (etch_thread_params*) data;
+    p = (struct mutextestparams*) params->data;
+    #if (IS_DEBUG_CONSOLE)
+    printf("in threadproc_a\n"); fflush(stdout);
+    #endif
+
+    /* can't use a FATAL cunit macro outside the main thread 
+     * since if it fails the exit handling causes an OS fault */
+
+    CU_ASSERT_PTR_NOT_NULL(p); if (!p) return;
+    CU_ASSERT_EQUAL(p->signature, THREAD_TESTDATA_SIG);
+    if (p->signature != THREAD_TESTDATA_SIG) return;
+    CU_ASSERT_PTR_NOT_NULL(p->mutex); if (!p->mutex) return;
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread a waiting ...\n"); fflush(stdout);
+    #endif
+
+    while(p->flag == 0) /* wait until ready to acquire lock */   
+          apr_sleep(1 * 1000 * 1000);
+
+    CU_ASSERT_EQUAL(p->flag, 1); if (p->flag != 1) return;
+
+    etch_mutex_lock(p->mutex);
+    CU_ASSERT_EQUAL(result, 0); if (result != 0) return;
+
+    p->flag = 2; /* signal thread b to attempt acquire */
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread a waiting ...\n"); fflush(stdout);
+    #endif
+
+    while(p->flag == 2) /* wait for thread thread b signal */
+          apr_sleep(1 * 1000 * 1000);
+
+    status = etch_mutex_unlock(p->mutex);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    p->flag = 4; /* signal thread b to proceed */
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread a waiting ...\n"); fflush(stdout);
+    #endif
+
+    while(p->flag == 4) /* wait until thread b signals done */   
+          apr_sleep(1 * 1000 * 1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread s exits\n"); fflush(stdout);
+    #endif
+}
+
+
+/**
+ * mutex_threadproc_b
+ */
+static void mutex_threadproc_b(void* data)
+{
+    etch_status_t status;
+    etch_thread_params* params;
+    struct mutextestparams* p;
+    params = (etch_thread_params*) data;
+    p = (struct mutextestparams*) params->data;
+    #if (IS_DEBUG_CONSOLE)
+    printf("in mutex_threadproc_b\n"); fflush(stdout);
+    #endif
+
+    CU_ASSERT_PTR_NOT_NULL(p);
+    CU_ASSERT_EQUAL(p->signature, THREAD_TESTDATA_SIG);
+    CU_ASSERT_PTR_NOT_NULL(p->mutex);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread b waiting ...\n"); fflush(stdout);
+    #endif
+
+    while(p->flag != 2) /* wait until ready to attempt lock */   
+          apr_sleep(1 * 1000 * 1000);
+    
+    status = etch_mutex_trylock(p->mutex);
+    CU_ASSERT_NOT_EQUAL(status, ETCH_SUCCESS);
+
+    p->flag = 3; /* signal thread a to continue */
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread b waiting ...\n"); fflush(stdout);
+    #endif
+
+    while(p->flag == 3) /* wait for thread a to release lock */   
+          apr_sleep(1 * 1000 * 1000);
+
+    status = etch_mutex_trylock(p->mutex);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    status = etch_mutex_unlock(p->mutex);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    p->flag = 5; /* signal thread a that we are done here */
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread b waiting 2 secs ...\n"); fflush(stdout);
+    #endif
+
+    /* ensure thread b is last to exit for simplicity */
+    apr_sleep(2 * 1000 * 1000); 
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread_b exits\n"); fflush(stdout);
+    #endif
+}
+
+
+/**
+ * test_mutex()
+ * launches two threads which share a mutex and a signal flag with the main thread.
+ * 1. thread a sets the lock, signals thread b, and waits.
+ * 2. thread b tries to set the lock, fails as expected, signals thread a, and waits.
+ * 3. thread a releases the lock, signals thread b, and waits.
+ * 4. thread b tries the lock, succeeds as expected, releases the lock, signals thread a.
+ * 5. thread a exits
+ * 6. thread b exits
+ */
+static void test_mutex(void)
+{
+    etch_status_t status;
+    int result = 0;
+    etch_mutex* mutex = 0;
+    etch_apr_threaddata* td = get_threaddata();
+    etch_thread_params tpa, tpb;
+    struct mutextestparams threadparams;
+    etch_init_threadparams(&tpa);
+    etch_init_threadparams(&tpb);
+
+    // TODO: pool
+    etch_mutex_create(&mutex_threadid, ETCH_MUTEX_NESTED, NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mutex_threadid);
+
+    // TODO: pool
+    etch_mutex_create(&mutex, ETCH_MUTEX_NESTED, NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mutex);
+
+    status = etch_mutex_lock(mutex);
+    CU_ASSERT_EQUAL_FATAL(status, ETCH_SUCCESS);
+
+    // result = mutex->tryacquire(mutex); /* mutexes are nestable */
+    // CU_ASSERT_NOT_EQUAL_FATAL(result, 0);
+    status = etch_mutex_unlock(mutex);
+    CU_ASSERT_EQUAL_FATAL(status, ETCH_SUCCESS);
+
+    threadparams.mutex = mutex;
+    threadparams.flag  = 0;
+    threadparams.signature = THREAD_TESTDATA_SIG;
+
+    tpa.etch_thread_id = next_threadid();
+    tpa.libdata    = td;
+    tpa.on_start   = on_threadstart;
+    tpa.on_exit    = on_threadexit;
+    tpa.threadproc = mutex_threadproc_a;  
+    tpa.data = &threadparams;
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\n");
+    #endif
+
+    result = etch_createthread(&tpa); /* create thread a */
+    CU_ASSERT_EQUAL(result, 0);
+
+    memcpy(&tpb, &tpa, sizeof(etch_thread_params));
+    tpb.etch_thread_id = next_threadid();
+    tpb.threadproc = mutex_threadproc_b;
+
+    result = etch_createthread(&tpb); /* create thread b */   
+    CU_ASSERT_EQUAL(result, 0);
+
+    /* signal the new threads to commence doing something */
+    threadparams.flag = 1;
+
+    etch_thread_join(&tpa);  /* wait for thread a exit */
+    etch_thread_join(&tpb);  /* wait for thread b exit */
+    
+    etch_mutex_destroy(mutex);
+    etch_mutex_destroy(mutex_threadid);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * synchedlist_testparams
+ * thread data for synched list test
+ */
+typedef struct synchedlist_testparams
+{
+    unsigned signature;
+    etch_arraylist* list;
+    etch_mutex* mutex;
+    uint16 flag;
+} synchedlist_testparams;
+
+/*
+static void dumplist(etch_arraylist* list)
+{
+    int i=0;
+    char result;
+    const int n = list->count;
+    result = etch_arraylist_trylock(list);
+    if (result != 0) return;
+    // printf("\ndumping list ...\n"); fflush(stdout);
+    for(; i < n; i++)
+    {   etch_int32* item = list->base[i];
+        printf("\n list[%d] %d\n", i, item->value); fflush(stdout);
+    }
+
+    result = etch_arraylist_rellock(list);
+    // printf("\nany key ..."); while(!c) c = _getch(); printf("\n"); 
+}
+*/
+
+/* 
+ * synched_arraylist_comparator()
+ * comparator to compare an integer constant with an etch_int32.
+ */
+static int synched_arraylist_comparator(void* testvalue, void* listcontent)
+{
+    const int ivalue  = (int) (size_t) testvalue;
+    etch_int32*  listobj = (etch_int32*) listcontent;
+    int jvalue = listobj->value;
+    return ivalue < jvalue? -1: ivalue > jvalue? 1: 0;
+} 
+
+
+/**
+ * synchedlist_threadproc_a
+ */
+static void synchedlist_threadproc_a(void* data)
+{
+    int result = 0, i;
+    uint16 flag = 0;
+    etch_iterator iterator;
+    etch_thread_params* params;
+    synchedlist_testparams* p;
+    params = (etch_thread_params*) data;
+    p = (struct synchedlist_testparams*) params->data;
+    #if (IS_DEBUG_CONSOLE)
+    printf("in threadproc_a\n"); fflush(stdout);
+    #endif
+
+    /* can't use a FATAL cunit macro outside the main thread 
+     * since if it fails the exit handling causes an OS fault */
+
+    CU_ASSERT_PTR_NOT_NULL(p); if (!p) return;
+    CU_ASSERT_EQUAL(p->signature, THREAD_TESTDATA_SIG);
+    if (p->signature != THREAD_TESTDATA_SIG) return;
+    CU_ASSERT_PTR_NOT_NULL(p->list); if (!p->list) return;
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread a waiting ...\n"); fflush(stdout);
+    #endif
+
+    /* wait until main signals start */
+    do {
+        etch_mutex_lock(p->mutex);
+        flag = p->flag;
+        etch_mutex_unlock(p->mutex);
+        apr_sleep(1 * 500 * 1000);
+    } while(flag < 2);
+
+     CU_ASSERT_TRUE(p->flag >= 2);
+    if (p->flag < 2) {
+        #if (IS_DEBUG_CONSOLE)
+            printf("thread a p->flag < 2 is false ...\n"); fflush(stdout);
+        #endif
+        return;
+    }
+
+    /* both threads should be contending for the list now */
+        /* wait until main signals start */
+    for(i = 1; i <= 20; i++)
+    {
+        #if (IS_DEBUG_CONSOLE)
+        printf("thread a arraylist_add ...\n"); fflush(stdout);
+        #endif
+        etch_arraylist_add(p->list, new_int32(i));
+        etch_thread_yield();        
+    }
+
+    etch_mutex_lock(p->mutex);
+    p->flag++;
+    etch_mutex_unlock(p->mutex);
+    do {
+        etch_mutex_lock(p->mutex);
+        flag = p->flag;
+        etch_mutex_unlock(p->mutex);
+        apr_sleep(1 * 500 * 1000);
+    } while(flag < 3);
+
+
+    CU_ASSERT_EQUAL(p->list->count, 40); 
+    
+    etch_mutex_lock(p->mutex);
+    p->flag++;
+    etch_mutex_unlock(p->mutex);
+    do {
+        etch_mutex_lock(p->mutex);
+        flag = p->flag;
+        etch_mutex_unlock(p->mutex);
+        apr_sleep(1 * 500 * 1000);
+    } while(flag < 5);
+
+    #if IS_TESTING_REMOVE
+
+    /* both threads should be contending for the list now */
+    for(i = 4; i <= 20; i += 4)
+    {
+        /* get the list index for value i */
+        const int index = etch_arraylist_indexof(p->list, (void*)(size_t) i, 0, synched_arraylist_comparator);
+        CU_ASSERT_NOT_EQUAL(index, -1);
+
+        if (index >= 0)
+        {
+            result = etch_arraylist_remove(p->list, index, TRUE);
+            CU_ASSERT_EQUAL(result, 0);
+
+            #if (IS_DEBUG_CONSOLE)
+            if  (result == 0)
+                 printf("thread a arraylist_remove index %d value %d\n", index, i);
+            else printf("thread a could not remove index %d value %d\n", index, i);
+            fflush(stdout);
+            #endif 
+        }
+
+        etch_thread_yield();
+    }
+
+    #endif /* IS_TESTING_REMOVE */
+
+    p->flag++;
+    while(p->flag < 7) /* wait until both threads are done removing from list */   
+          apr_sleep(1 * 1000 * 500);
+
+    #if IS_TESTING_REMOVE
+    CU_ASSERT_EQUAL(p->list->count, 30); /* each thread removed 5 items */
+    #endif
+
+    etch_mutex_lock(p->mutex);
+    p->flag++;
+    etch_mutex_unlock(p->mutex);
+    do {
+        etch_mutex_lock(p->mutex);
+        flag = p->flag;
+        etch_mutex_unlock(p->mutex);
+        apr_sleep(1 * 500 * 1000);
+    } while(flag < 9);
+
+    set_iterator(&iterator, p->list, &p->list->iterable);
+
+    result = etch_arraylist_getlock(p->list);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread a iterating list ...\n"); fflush(stdout);
+    #endif  
+
+    while(iterator.has_next(&iterator))
+    {
+        etch_int32* item = (etch_int32*) iterator.current_value;
+        CU_ASSERT_PTR_NOT_NULL(item); 
+
+        if (item)  
+        {   result = item->value;
+            #if (IS_DEBUG_CONSOLE)
+            printf("thread a list value %d\n", result); fflush(stdout);
+            #endif  
+            #if IS_TESTING_REMOVE
+            CU_ASSERT_NOT_EQUAL(result % 4, 0); /* we removed all modulo 4 values */
+            #endif
+        }
+        
+        result = iterator.next(&iterator);
+    }
+
+    etch_sleep(1000);
+    result = etch_arraylist_rellock(p->list);
+
+
+    etch_mutex_lock(p->mutex);
+    p->flag++;
+    etch_mutex_unlock(p->mutex);
+    #if (IS_DEBUG_CONSOLE)
+         printf("thread a waiting to exit ...\n"); fflush(stdout);
+    #endif
+    do {
+        etch_mutex_lock(p->mutex);
+        flag = p->flag;
+        etch_mutex_unlock(p->mutex);
+        apr_sleep(1 * 500 * 1000);
+    } while(flag < 11);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread a exits\n"); fflush(stdout);
+    #endif
+}
+
+
+/**
+ * synchedlist_threadproc_b
+ */
+static void synchedlist_threadproc_b(void* data)
+{
+    int result = 0, i;
+    uint16 flag = 0;
+    etch_iterator iterator;
+    etch_thread_params* params;
+    struct synchedlist_testparams* p; 
+    params = (etch_thread_params*) data;
+    p = (struct synchedlist_testparams*) params->data;
+    #if (IS_DEBUG_CONSOLE)
+    printf("in threadproc_b\n"); fflush(stdout);
+    #endif
+
+    /* can't use a FATAL cunit macro outside the main thread 
+     * since if it fails the exit handling causes an OS fault */
+
+    CU_ASSERT_PTR_NOT_NULL(p); if (!p) return;
+    CU_ASSERT_EQUAL(p->signature, THREAD_TESTDATA_SIG);
+    if (p->signature != THREAD_TESTDATA_SIG) return;
+    CU_ASSERT_PTR_NOT_NULL(p->list); if (!p->list) return;
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread b waiting ...\n"); fflush(stdout);
+    #endif
+
+    /* wait until main signals start */
+    do {
+        etch_mutex_lock(p->mutex);
+        flag = p->flag;
+        etch_mutex_unlock(p->mutex);
+        apr_sleep(1 * 500 * 1000);
+    } while(flag == 0);
+
+    CU_ASSERT_EQUAL(p->flag, 1); if (p->flag != 1) return;
+
+    /* both threads should be contending for the list now */
+    for(i = 21; i <= 40; i++)
+    {
+        #if (IS_DEBUG_CONSOLE)
+        printf("thread b arraylist_add ...\n"); fflush(stdout);
+        #endif
+        etch_arraylist_add(p->list, new_int32(i));
+        etch_thread_yield();
+    }
+
+    p->flag++;
+    while(p->flag < 3) /* wait until both threads are done adding to list */   
+          apr_sleep(1 * 1000 * 500);
+
+    CU_ASSERT_EQUAL(p->list->count, 40); 
+    p->flag++;
+    while(p->flag < 5) /* wait until both threads are done checking list */   
+          apr_sleep(1 * 1000 * 500);
+
+    #if IS_TESTING_REMOVE
+
+    /* both threads should be contending for the list now */
+    for(i = 24; i <= 40; i += 4)
+    {
+        const int index = etch_arraylist_indexof(p->list, (void*)(size_t) i, 0, synched_arraylist_comparator);
+        CU_ASSERT_NOT_EQUAL(index, -1);
+
+        if (index >= 0)
+        {
+            result = etch_arraylist_remove(p->list, index, TRUE);
+            CU_ASSERT_EQUAL(result, 0);
+
+            #if (IS_DEBUG_CONSOLE)
+            if  (result == 0)
+                 printf("thread b arraylist_remove index %d value %d\n", index, i);
+            else printf("thread b could not remove index %d value %d\n", index, i);
+            fflush(stdout);
+            #endif 
+        }
+            
+        etch_thread_yield();        
+    }
+
+    #endif /*  #if IS_TESTING_REMOVE */
+
+    p->flag++;
+    while(p->flag < 7) /* wait until both threads are done removing from list */   
+          apr_sleep(1 * 1000 * 500);
+
+    #if IS_TESTING_REMOVE
+    CU_ASSERT_EQUAL(p->list->count, 30); /* each thread removed 5 items */
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread b list count after remove is %d\n", p->list->count); fflush(stdout);
+    #endif /* IS_DEBUG_CONSOLE */
+    #endif /* IS_TESTING_REMOVE */
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread b waiting for list lock ...\n"); fflush(stdout);
+    #endif /* IS_DEBUG_CONSOLE */
+    p->flag++;
+    while(p->flag < 9) /* wait until both threads are done checking list */   
+          apr_sleep(1 * 1000 * 500);
+
+    set_iterator(&iterator, p->list, &p->list->iterable);  
+
+    result = etch_arraylist_getlock(p->list);
+    CU_ASSERT_EQUAL(result, 0); 
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread b iterating list ...\n"); fflush(stdout);
+    #endif  /* IS_DEBUG_CONSOLE */ 
+
+    while(iterator.has_next(&iterator))
+    {   
+        etch_int32* item = (etch_int32*) iterator.current_value;
+        CU_ASSERT_PTR_NOT_NULL(item); 
+
+        if (item)  
+        {   result = item->value;
+            #if (IS_DEBUG_CONSOLE)
+            printf("thread b list value %d\n", result); fflush(stdout);
+            #endif  
+            #if IS_TESTING_REMOVE
+            CU_ASSERT_NOT_EQUAL(result % 4, 0); /* we removed all modulo 4 values */
+            #endif
+        }
+        
+        iterator.next(&iterator);
+    }
+
+    result = etch_arraylist_rellock(p->list);
+
+    #if (IS_DEBUG_CONSOLE)
+         printf("thread b waiting to exit ...\n"); fflush(stdout);
+    #endif 
+
+    p->flag++;
+    while(p->flag < 11) /* wait until both threads are done iterating list */   
+          apr_sleep(1 * 1000 * 500);
+
+    /* ensure thread b is last to exit for simplicity */
+    apr_sleep(1 * 1000 * 1000); 
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread b exits\n"); fflush(stdout);
+    #endif
+}
+
+
+/**
+ * test_synched_arraylist()
+ * launches two threads which share a synchronized arraylist.
+ */
+static void test_synched_arraylist(void)
+{
+    int result = 0;
+    etch_mutex* mutex = 0;
+    synchedlist_testparams tparams;
+    etch_apr_threaddata* td = get_threaddata();
+    etch_thread_params tpa, tpb;
+    memset(&tpa, 0, sizeof(etch_thread_params));
+    memset(&tpb, 0, sizeof(etch_thread_params));
+
+    // TODO: pool
+    etch_mutex_create(&mutex_threadid, ETCH_MUTEX_NESTED, NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mutex_threadid);
+
+    // TODO: pool
+    etch_mutex_create(&mutex, ETCH_MUTEX_NESTED, NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mutex_threadid);
+
+    tparams.list  = new_etch_arraylist(0,0);
+    ((etch_object*)tparams.list)->synclock = mutex; /* list now owns the mutex */
+    tparams.flag  = 0;
+    tparams.signature = THREAD_TESTDATA_SIG;
+
+    // TODO: pool
+    etch_mutex_create(&tparams.mutex, ETCH_MUTEX_NESTED, NULL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(mutex_threadid);
+
+    tpa.etch_thread_id = ++g_next_threadid;
+    tpa.libdata    = td;
+    tpa.on_start   = on_threadstart;
+    tpa.on_exit    = on_threadexit;
+    tpa.threadproc = synchedlist_threadproc_a;  
+    tpa.data = &tparams;
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\n");
+    #endif
+
+    result = etch_createthread(&tpa); /* create thread a */
+    CU_ASSERT_EQUAL(result, 0);
+
+    memcpy(&tpb, &tpa, sizeof(etch_thread_params));
+    tpb.etch_thread_id = ++g_next_threadid;
+    tpb.threadproc = synchedlist_threadproc_b;
+
+    result = etch_createthread(&tpb); /* create thread b */   
+    CU_ASSERT_EQUAL(result, 0);
+
+    /* signal both threads to start doing something */
+    etch_mutex_lock(tparams.mutex);
+    tparams.flag = 1;
+    etch_mutex_unlock(tparams.mutex);
+
+    etch_thread_join(&tpb);  /* wait for thread b exit */
+    etch_thread_join(&tpa);  /* wait for thread a exit */
+    
+    etch_object_destroy(tparams.list); /* destroy list and mutex */
+
+    etch_mutex_destroy(mutex_threadid);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+typedef struct waittestdata { int flag; int num; int is_disposable; } waittestdata;
+
+
+/**
+ * wait_threadproc_a
+ */
+static void wait_threadproc_a(void* data)
+{
+    etch_thread_params* params;
+    waittestdata* threadtestdata; 
+    params = (etch_thread_params*) data;
+    threadtestdata = (waittestdata*) params->data;
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nin wait thread_a\n"); fflush(stdout);
+    #endif
+
+    threadtestdata->flag = 1; 
+
+    etch_sleep(3000);
+
+    if (threadtestdata->is_disposable)
+        etch_free(threadtestdata);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("exit wait thread_a\n"); fflush(stdout);
+    #endif
+}
+
+
+/**
+ * test_wait()
+ * test separate thread create and start   
+ */
+static void test_wait(void)
+{
+    int  result = 0;
+    etch_thread* thread    = 0;
+    waittestdata* testdata = 0;  
+    etch_thread_params* tp  = 0;
+
+    testdata = etch_malloc(sizeof(waittestdata),0);
+    testdata->flag = testdata->num = 0;
+    testdata->is_disposable = FALSE;
+
+    /* create a thread that waits to be started */
+    thread = new_thread(wait_threadproc_a, testdata);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(thread);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nnew thread waiting for signal coming in ... "); fflush(stdout);
+    #endif
+
+    tp = &thread->params;
+    /* testdata = tp->data; */
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("3 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("2 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("1 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nmain signaling new thread to start ...\n"); fflush(stdout);
+    #endif
+
+    thread->start(thread);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("main issued newthread.start, waiting for exit ...\n"); fflush(stdout);
+    #endif  
+
+    etch_sleep(1000);
+    
+    etch_thread_join(tp);  /* block until thread exit */
+
+    result = testdata->flag;
+    CU_ASSERT_EQUAL(result, 1);
+    etch_free(testdata);
+    etch_object_destroy(thread);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+typedef struct wait_until_testdata 
+{
+  etch_wait_t* waiter;   /* the condition variable waiter */
+  int64 waitingfor;   /* value the waiter is waiting for */
+  int   sleepstartms; 
+  int   sleepexitms; 
+} wait_until_testdata;
+
+
+/**
+ * wait_until_threadproc_a
+ */
+static void wait_until_threadproc_a(void* data)
+{
+    etch_wait_t* waiter;
+    etch_thread_params* params;
+    wait_until_testdata* threadtestdata; 
+    params = (etch_thread_params*) data;
+    threadtestdata = (wait_until_testdata*) params->data;
+    waiter = threadtestdata->waiter;
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nthread: started ...\n", threadtestdata->sleepstartms); fflush(stdout);
+    #endif
+
+    etch_sleep(threadtestdata->sleepstartms);  /* wait a bit before setting condition */
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nthread: setting unblock condition ...\n"); fflush(stdout);
+    #endif
+
+    etch_wait_set(waiter, threadtestdata->waitingfor);
+
+//    waiter->set(waiter, threadtestdata->waitingfor);  /* set wait condition to unblock waiters */
+
+    etch_sleep(threadtestdata->sleepexitms);  /* wait a bit before exiting thread */
+
+    etch_free(threadtestdata);  /* free caller's memory */
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("thread: exiting ...\n"); fflush(stdout);
+    #endif
+}
+
+
+/**
+ * test_wait_until()
+ * test wait on condition variable -- block until the specified condition is met.  
+ */
+static void test_wait_until(void)
+{
+    etch_status_t status;
+    int   result = 0;
+    etch_wait_t* waiter;
+    etch_thread* thread = 0;
+    etch_thread_params* tp = 0;
+    const int64 VALUE_TO_WAIT_FOR = 1;
+    wait_until_testdata* testdata = 0;  
+
+    // TODO: pool
+    etch_wait_create(&waiter, NULL);
+
+    testdata = etch_malloc(sizeof(wait_until_testdata),0);
+    memset(testdata, 0, sizeof(wait_until_testdata));
+    testdata->waiter = waiter;
+    testdata->waitingfor = VALUE_TO_WAIT_FOR;  
+    testdata->sleepstartms = testdata->sleepexitms = 2000;
+   
+    /* create a thread that waits to be started */
+    thread = new_thread(wait_until_threadproc_a, testdata);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(thread);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nmain: countdown to start worker thread ... "); fflush(stdout);
+    #endif
+
+    tp = &thread->params;
+    testdata = tp->data; 
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("3 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("2 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("1 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nmain: signaling worker thread to start ...\n"); fflush(stdout);
+    #endif
+
+    thread->start(thread);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("main: worker thread started\n");  
+    printf("main: start blocking on condition variable ...\n"); fflush(stdout);
+    #endif  
+
+    /* wait for worker thread to set condition variable */
+    //result = waiter->timed_waitequal(waiter, &condvar, VALUE_TO_WAIT_FOR, 5000);  
+    status = etch_wait_timedwait(waiter, VALUE_TO_WAIT_FOR, 5000);
+    switch(status) {
+        case ETCH_SUCCESS:
+            result = 0;
+            break;
+        case ETCH_ETIMEOUT:
+            result = ETCH_TIMEOUT;
+            break;
+        default:
+            result = -1;
+            break;
+    }
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("main: wait unblocked, waiting for worker thread to exit ...\n"); fflush(stdout);
+    #endif  
+    CU_ASSERT_NOT_EQUAL_FATAL(result, -1);
+    CU_ASSERT_NOT_EQUAL(result, ETCH_TIMEOUT);
+
+    etch_thread_join(tp);  /* block until thread exit */
+    
+    etch_wait_destroy(waiter);
+    etch_object_destroy(thread);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+
+/**
+ * test_wait_until_preexisting()
+ * test wait on condition variable when unblock condition exists prior to request.  
+ */
+static void test_wait_until_preexisting(void)
+{
+    etch_status_t status;
+    int   result = 0;
+    etch_wait_t* waiter;
+    etch_thread* thread = 0;
+    etch_thread_params* tp = 0;
+    const int64 VALUE_TO_WAIT_FOR = 1;
+    wait_until_testdata* testdata = 0;  
+    clock_t tickcount1 = 0, tickcount2 = 0, tickdiff = 0;
+
+    // TODO: pool
+    etch_wait_create(&waiter, NULL);
+
+    testdata = etch_malloc(sizeof(wait_until_testdata),0);
+    memset(testdata, 0, sizeof(wait_until_testdata));
+    testdata->waiter = waiter;
+    testdata->waitingfor = VALUE_TO_WAIT_FOR;  
+    testdata->sleepstartms = testdata->sleepexitms = 2000;
+   
+    /* create a thread that waits to be started */
+    thread = new_thread(wait_until_threadproc_a, testdata);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(thread);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nmain: countdown to start worker thread ... "); fflush(stdout);
+    #endif
+
+    tp = &thread->params;
+    testdata = tp->data; 
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("3 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("2 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("1 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nmain: signaling worker thread to start ...\n"); fflush(stdout);
+    #endif
+
+    thread->start(thread);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("main: worker thread started\n");  
+    #endif  
+
+    //condvar = VALUE_TO_WAIT_FOR; /* pre-set unblock condition */
+    // TODO: check if this is correct
+    etch_wait_set(waiter, VALUE_TO_WAIT_FOR);
+    tickcount1 = clock();
+
+    /* wait for worker thread to set condition variable. we expect that the 
+     * thread will not be started since the wait condition pre-exists */
+    status = etch_wait_timedwait(waiter, VALUE_TO_WAIT_FOR, 5000);
+    CU_ASSERT_EQUAL(status, ETCH_SUCCESS);
+
+    /* we expect zero wait time since the wait condition preexisted */
+    tickcount2 = clock();
+    tickdiff = tickcount2 - tickcount1;
+    result = tickdiff < 20; /* resolution of tick timer could be as high as 20ms */ 
+    CU_ASSERT_EQUAL(result, TRUE); /* if debugger stepping this assert will fail */
+
+    /* block until thread exit. however we expect that it has already done so. */
+    etch_thread_join(tp);  
+    
+    etch_wait_destroy(waiter);
+    etch_object_destroy(thread);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_wait_until_negative_test()
+ * test wait on condition variable  
+ */
+static void test_wait_until_negative_test(void)
+{
+    etch_status_t status;
+    etch_wait_t* waiter;
+    etch_thread* thread = 0;
+    etch_thread_params* tp = 0;
+    const int VALUE_TO_WAIT_FOR = 1, VALUE_TO_SET = 2, THREAD_PAUSE_MS = 1000;
+    wait_until_testdata* testdata = 0;  
+
+    // TODO: pool
+    etch_wait_create(&waiter, NULL);
+
+    testdata = etch_malloc(sizeof(wait_until_testdata),0);
+    memset(testdata, 0, sizeof(wait_until_testdata));
+    testdata->waiter = waiter;
+    testdata->waitingfor = VALUE_TO_SET;  /* not the value we're going to wait for */ 
+    testdata->sleepstartms = testdata->sleepexitms = THREAD_PAUSE_MS;
+   
+    /* create a thread that waits to be started */
+    thread = new_thread(wait_until_threadproc_a, testdata);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(thread);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nmain: countdown to start worker thread ... "); fflush(stdout);
+    #endif
+
+    tp = &thread->params;
+    testdata = tp->data; 
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("3 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("2 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("1 ... "); fflush(stdout);
+    #endif   
+    etch_sleep(1000);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nmain: signaling worker thread to start ...\n"); fflush(stdout);
+    #endif
+
+    thread->start(thread);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("main: worker thread started\n");  
+    printf("main: start blocking on condition variable ...\n"); fflush(stdout);
+    #endif  
+
+    /* wait for worker thread to set condition variable. in this test, we have told
+     * the thread to set some other value than what we are waiting for, so we want
+     * to see a wait timeout here. in other words, we are testing that setting the
+     * waiter to some value other than what we are waiting for, does not unblock. 
+     */
+    status = etch_wait_timedwait(waiter, VALUE_TO_WAIT_FOR, THREAD_PAUSE_MS + 1000);
+    CU_ASSERT_EQUAL(status, ETCH_ETIMEOUT);
+    //result = waiter->timed_waitequal(waiter, &condvar, VALUE_TO_WAIT_FOR, THREAD_PAUSE_MS + 1000 );  
+
+    
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("main: wait unblocked, waiting for worker thread to exit ...\n"); fflush(stdout);
+    #endif  
+
+    etch_thread_join(tp);  /* block until thread exit */
+
+    etch_wait_destroy(waiter);
+    etch_object_destroy(thread);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * wait_multiple_threadproc
+ */
+static void wait_multiple_threadproc(void* data)
+{
+    int threadnum, waitms, remainingms;
+    etch_thread_params* params = (etch_thread_params*) data;
+    waittestdata* tdata = (waittestdata*) params->data; 
+    threadnum = tdata->num;
+    waitms = tdata->flag;
+    remainingms = waitms;
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("\nwait thread %d sleeping %d ms ...\n", threadnum, waitms); fflush(stdout);
+    #endif 
+
+    while(remainingms > 0)
+    {
+        if (params->threadstate > ETCH_THREADSTATE_STARTED) break; 
+        etch_sleep(remainingms > 500? 500: remainingms);
+        remainingms -= 500;
+    }
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("exit wait thread %d\n", threadnum); fflush(stdout);
+    #endif
+}
+
+
+/**
+ * test_wait_for_multiple()
+ * launch multiple threads and wait for them all to complete   
+ */
+static void test_wait_for_multiple(void)
+{
+    #define TEST_WAIT_MULT_NUMTHREADS 4
+
+    etch_thread* thread[TEST_WAIT_MULT_NUMTHREADS];
+    int waitms[TEST_WAIT_MULT_NUMTHREADS], i, priori = 1;
+
+    for(i=0; i < TEST_WAIT_MULT_NUMTHREADS; i++)
+    {   /* initialize wait times for each thread */
+        const int newi = i & 1? priori - 1: priori + 2;
+        waitms[i] = ((priori = newi) * 1000);        
+    }
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("main creating all threads ...\n"); fflush(stdout);
+    #endif 
+  
+    for(i=0; i < TEST_WAIT_MULT_NUMTHREADS; i++) /* create all threads */
+    {   
+        etch_thread* newthread;
+        waittestdata* thread_data = etch_malloc(sizeof(waittestdata),0);
+        thread_data->num = i; thread_data->flag = waitms[i];
+
+        newthread = new_thread(wait_multiple_threadproc, thread_data);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(newthread);
+
+        /* configure thread to free memory for the waittestdata we passed it */
+        newthread->params.is_own_data = TRUE;  
+        thread[i] = newthread;
+    }
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("main starting all threads ...\n"); fflush(stdout);
+    #endif 
+
+    for(i=0; i < TEST_WAIT_MULT_NUMTHREADS; i++) /* start all threads */
+        thread[i]->start(thread[i]);
+         
+    #if (IS_DEBUG_CONSOLE)
+    printf("main waiting for all threads to exit ...\n"); fflush(stdout);
+    #endif 
+
+    for(i=0; i < TEST_WAIT_MULT_NUMTHREADS; i++) /* wait for all threads to exit */
+        etch_join(thread[i]); 
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("main all threads accounted for\n"); fflush(stdout);
+    #endif 
+
+    for(i=0; i < TEST_WAIT_MULT_NUMTHREADS; i++) /* free thread objects */
+        etch_object_destroy(thread[i]);
+       
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_free_threadpool()
+ * test thread "pool" (ad hoc threads)   
+ */
+static void test_free_threadpool(void)
+{
+    #define TEST_FREEPOOL_NUMTHREADS 4
+    etch_threadpool* threadpool = NULL;
+    void* runthread = NULL;
+    int waitms[TEST_FREEPOOL_NUMTHREADS], i, priori = 1;
+
+    for(i=0; i < TEST_FREEPOOL_NUMTHREADS; i++)
+    {   /* initialize wait times for each thread */
+        const int newi = i & 1? priori - 1: priori + 2;
+        waitms[i] = ((priori = newi) * 1000);        
+    }
+
+    threadpool = new_threadpool(ETCH_THREADPOOLTYPE_FREE, 0);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(threadpool);
+    threadpool->is_free_threads = TRUE;
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("main creating %d pool threads ...\n", TEST_FREEPOOL_NUMTHREADS); fflush(stdout);
+    #endif 
+  
+    for(i=0; i < TEST_FREEPOOL_NUMTHREADS; i++) /* launch all threads */
+    {   
+        waittestdata* thread_data = etch_malloc(sizeof(waittestdata),0);
+        thread_data->num = i; thread_data->flag = waitms[i];
+
+        runthread = threadpool->run (threadpool, wait_multiple_threadproc, thread_data);
+
+        CU_ASSERT_PTR_NOT_NULL(runthread);
+    }
+         
+    #if (IS_DEBUG_CONSOLE)
+    printf("main all pool threads launched\n"); fflush(stdout);
+    printf("main destroying thread pool ...\n"); fflush(stdout);
+    #endif 
+
+    etch_object_destroy(threadpool);
+
+    #if (IS_DEBUG_CONSOLE)
+    printf("main all threads accounted for\n"); fflush(stdout);
+    #endif 
+       
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int _tmain(int argc, _TCHAR* argv[])
+CU_pSuite test_etch_threadpool_suite()
+{    
+    CU_pSuite ps = CU_add_suite("suite_threadpool", init_suite, clean_suite);
+
+    CU_add_test(ps, "test create thread", test_createthread);
+    CU_add_test(ps, "test etch mutex", test_mutex);
+    CU_add_test(ps, "test arraylist synchronization", test_synched_arraylist);
+    CU_add_test(ps, "test thread wait/start", test_wait);
+
+    CU_add_test(ps, "test wait on condition", test_wait_until); 
+    CU_add_test(ps, "test wait on pre-existing condition", test_wait_until_preexisting);
+    CU_add_test(ps, "test wait on condition - negative", test_wait_until_negative_test); 
+
+    CU_add_test(ps, "test wait all threads exit", test_wait_for_multiple);
+    CU_add_test(ps, "test free threadpool", test_free_threadpool);
+
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/transport/test_transport.c b/binding-c/runtime/c/src/test/transport/test_transport.c
new file mode 100644
index 0000000..3706e13
--- /dev/null
+++ b/binding-c/runtime/c/src/test/transport/test_transport.c
@@ -0,0 +1,401 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_transport.c
+ * test delivery service etc
+ */
+#include "etch_runtime.h"
+#include "etch_transport.h"
+#include "etch_thread.h"
+#include "etch_default_value_factory.h"
+#include "etch_plain_mailbox_manager.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_map.h"
+#include "etch_log.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+
+#define IS_DEBUG_CONSOLE TRUE
+
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+
+static default_value_factory* new_bogus_valuefactory();
+
+/* - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * unit test support
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+
+#define FAKEID_TYPE_ADD         1 
+#define FAKEID_TYPE_ADD_RESULT  2 
+#define FAKEID_FIELD_X          3 
+#define FAKEID_FIELD_Y          4
+#define FAKEID_FIELD_RESULT     5
+#define THISTEST_WHO_VALUE 0x5151
+
+static unsigned short CLASSID_MY_VF;
+static unsigned short CLASSID_MY_VF_VTAB;
+static unsigned short CLASSID_MY_VF_IMPL;
+static unsigned short CLASSID_MY_IMPL_TP;
+static unsigned short CLASSID_MY_IMPL_SM;
+
+static etch_resources*         g_my_resources;
+static default_value_factory*  g_my_vf;
+static vf_idname_map*          g_my_typemap;
+static class_to_type_map*      g_my_c2tmap;
+static etch_who*               g_who;
+
+/**
+ * setup_this_test()
+ * set up an individual unit test
+ */
+static int setup_this_test()
+{
+    CLASSID_MY_VF      = get_dynamic_classid();
+    CLASSID_MY_VF_VTAB = get_dynamic_classid();
+    CLASSID_MY_VF_IMPL = get_dynamic_classid();
+    CLASSID_MY_IMPL_TP = get_dynamic_classid();
+    CLASSID_MY_IMPL_SM = get_dynamic_classid();  
+
+    g_my_vf = new_bogus_valuefactory();
+    set_etchobj_static_all(g_my_vf);   /* so resources map will not destroy */ 
+ 
+    /* get resources map populated with transport resources such as thread pools */
+    g_my_resources = get_etch_transport_resources(NULL);
+    etch_resources_add(g_my_resources, ETCH_RESXKEY_MSGIZER_VALUFACT, (etch_object*) g_my_vf); 
+   
+    g_who = new_who(new_int32(THISTEST_WHO_VALUE));
+
+    #if(IS_DEBUG_CONSOLE)
+    printf("\n");
+    #endif
+    return 0;
+}
+
+
+/**
+ * teardown_this_test()
+ * tear down an individual unit test
+ */
+static void teardown_this_test()
+{ 
+    etch_object_destroy(g_my_resources);
+
+    if (g_my_vf) 
+    {   /* we clear the set_etchobj_static_all() on the g_my_vf value factory  
+         * and as a result we can then destroy it */
+        clear_etchobj_static_all(g_my_vf);
+        etch_object_destroy(g_my_vf);
+    }
+
+    etch_object_destroy(g_my_c2tmap);
+    etch_object_destroy(g_my_typemap);
+    
+ 
+    etch_object_destroy(g_who);
+
+    g_my_resources = NULL;
+    g_my_vf = NULL;
+    g_who = NULL;
+
+    etchvf_free_builtins(); 
+}
+
+
+/* - - - - - - - - - -
+ * value factory
+ * - - - - - - - - - - 
+ */
+
+/**
+ * my_valufactory_impl
+ * value factory instance data object
+ */
+typedef struct my_valufactory_impl
+{
+    etch_object object;
+
+    etch_type*      mt_add;
+    etch_type*      mt_add_result;
+    etch_field*     mf_x;
+    etch_field*     mf_y;
+    etch_field*     mf_result;
+
+} my_valufactory_impl;
+
+
+/**
+ * destroy_my_valufactory_impl()
+ * destructor for inheriting value factory instance data
+ */
+static int destroy_my_valufactory_impl(void* data)
+{
+    my_valufactory_impl* impl = (my_valufactory_impl*)data;
+    if (NULL == impl) return -1;
+
+    if (!is_etchobj_static_content(impl))
+    {
+ 	    destroy_static_type(impl->mt_add);
+        destroy_static_type(impl->mt_add_result);
+        destroy_static_field(impl->mf_x); 
+        destroy_static_field(impl->mf_y); 
+        destroy_static_field(impl->mf_result);  
+    }
+
+    return destroy_objectex((etch_object*) impl);
+}
+
+
+/**
+ * new_my_valufactory_impl()
+ * constructor for inheriting value factory instance data
+ */
+static my_valufactory_impl* new_my_valufactory_impl()
+{
+    unsigned short class_id = CLASSID_MY_VF_IMPL? CLASSID_MY_VF_IMPL: 
+        (CLASSID_MY_VF_IMPL = get_dynamic_classid());
+
+    my_valufactory_impl* impl = (my_valufactory_impl*) new_object
+        (sizeof(my_valufactory_impl), ETCHTYPEB_VALUEFACTIMP, class_id);
+
+    ((etch_object*)impl)->destroy = destroy_my_valufactory_impl;
+
+    impl->mt_add = new_static_type(L"add");
+    impl->mt_add_result = new_static_type(L"add_result");
+    impl->mf_x = new_static_field(L"x");
+    impl->mf_y = new_static_field(L"y");
+    impl->mf_result = new_static_field(L"xresult");
+
+    /* we replace generated ids with 1-byte IDs to make test data buffers easier to construct */
+    impl->mt_add->id        = FAKEID_TYPE_ADD;
+    impl->mt_add_result->id = FAKEID_TYPE_ADD_RESULT;
+    impl->mf_x->id          = FAKEID_FIELD_X;
+    impl->mf_y->id          = FAKEID_FIELD_Y;
+    impl->mf_result->id     = FAKEID_FIELD_RESULT;
+
+    etchtype_put_validator(impl->mt_add, clone_field(impl->mf_x), 
+        (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(impl->mt_add, clone_field(impl->mf_y), 
+        (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(impl->mt_add, clone_field(builtins._mf__message_id), 
+        (etch_object*) etchvtor_int64_get(0));
+
+    etchtype_put_validator(impl->mt_add_result, clone_field(impl->mf_result), 
+        (etch_object*) etchvtor_int32_get(0));
+    etchtype_put_validator(impl->mt_add_result, clone_field(builtins._mf__message_id), 
+        (etch_object*) etchvtor_int64_get(0));
+    etchtype_put_validator(impl->mt_add_result, clone_field(builtins._mf__in_reply_to), 
+        (etch_object*) etchvtor_int64_get(0));
+
+    return impl;
+}
+
+
+/**
+ * new_bogus_valuefactory()
+ * constructor for value factory version 2 inheriting from default_value_factory
+ */
+static default_value_factory* new_bogus_valuefactory()
+{
+    etchparentinfo* inheritlist = NULL;
+    my_valufactory_impl* impl = NULL;
+
+    /* instantiate the new value factory.  
+     * this vf does NOT own its type maps since we supply them here. 
+     * however if we wanted to abandon ownership, we could clear the
+     * vf.is_own_types and vf.is_own_class_to_type flags here.
+     */
+    g_my_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(g_my_typemap);
+    /* since we explicitly instantiate a type map, and since we explicitly destroy
+     * the test's custom types, we want the type maps destructor to not destroy
+     * the map content. overriding the map's content clear callback is one way 
+     * to do this. */
+    g_my_typemap->freehook = etch_noop_clear_handler;
+    g_my_c2tmap  = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+    CU_ASSERT_PTR_NOT_NULL(g_my_c2tmap);
+    defvf_initialize_static(g_my_typemap, g_my_c2tmap);
+    g_my_vf = new_default_value_factory(g_my_typemap, g_my_c2tmap);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(g_my_vf);
+
+   /* ensure parent type keys exist in the (one-based) inheritance list. 
+    * parent class of our custom vf is default_value_factory.
+    * inheritance list is used by validators and object assignment logic.
+    */
+    inheritlist = get_vtab_inheritance_list((etch_object*)g_my_vf, 2, 1, CLASSID_MY_VF_VTAB);
+    inheritlist[1].o.obj_type = ETCHTYPEB_VALUEFACTORY;  
+    inheritlist[1].c.class_id = CLASSID_VALUEFACTORY;  /* parent class */
+    ((etch_object*)g_my_vf)->class_id = CLASSID_MY_VF;  /* our class */
+
+    /* instantiate the custom vf's instance data and assign it to the vf. 
+     * the impl comprises all data specific to the inheriting class, including 
+     * data and methods if any. the default value factory destructor will call 
+     * the destructor on the vf's impl object.
+     */  
+    impl = new_my_valufactory_impl();
+    g_my_vf->impl = (etch_object*) impl;
+
+    ((struct i_value_factory*)((etch_object*)g_my_vf)->vtab)->add_type(g_my_vf, impl->mt_add);
+    ((struct i_value_factory*)((etch_object*)g_my_vf)->vtab)->add_type(g_my_vf, impl->mt_add_result);
+
+    return g_my_vf;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - - -
+ * unit tests
+ * - - - - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * test_setup()
+ */
+static void test_setup(void)
+{
+    setup_this_test();
+
+    do
+    {   
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * test_tcpds_construction()
+ * test tcp delivery service constructor and destructor
+ */
+static void test_tcpds_construction(void)
+{
+    setup_this_test();
+
+    do 
+    {   etch_tcp_delivery_service* tcpds = NULL;
+        etch_tcp_connection* nullconnection = NULL;
+        /* h_url* url = new_url(L"http://www.cisco.com:9999/cuae:?Messagizer.format=binary"); */
+        /* messagizer format is supplied in resource map - see get_etch_transport_resources() */
+        etch_url* url = new_url(L"http://www.cisco.com:9999/cuae"); 
+        etch_server_factory* impl_factory = new_server_factory (NULL, NULL, NULL, NULL);
+        impl_factory->in_resx = g_my_resources;
+
+        tcpds = new_tcp_delivery_service(url, (etch_factory_params*) impl_factory, nullconnection);  
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(tcpds);  
+
+        etch_object_destroy(tcpds);    
+
+        etch_object_destroy(url);
+        etch_object_destroy(impl_factory);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+
+/**
+ * test_transport_construction()
+ * test delivery service constructor and destructor
+ */
+static void test_transport_construction(void)
+{
+    setup_this_test();
+
+    do 
+    {   etch_server_factory* impl_factory = new_server_factory (NULL, NULL, NULL, NULL);
+        etch_tcp_connection* nullconnection = NULL;
+        i_delivery_service* ds = NULL;
+        impl_factory->in_resx = g_my_resources;
+
+        ds = new_etch_transport(L"http://www.cisco.com:9999/cuae", 
+            (etch_factory_params*) impl_factory, nullconnection);  
+
+        CU_ASSERT_PTR_NOT_NULL_FATAL(ds);  
+
+        etch_object_destroy(ds); /* destroys transport implementation via interface */
+        etch_object_destroy(impl_factory);
+
+    } while(0);
+    
+    teardown_this_test();
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int wmain( int argc, wchar_t* argv[], wchar_t* envp[])
+CU_pSuite test_etch_transport_suite()
+{
+    CU_pSuite ps = CU_add_suite("transport test suite", init_suite, clean_suite);
+
+    CU_add_test(ps, "test test setup and teardown", test_setup);
+    CU_add_test(ps, "test tcp delivery service constructor", test_tcpds_construction);
+    CU_add_test(ps, "test transport constructor", test_transport_construction);
+       
+    return ps;
+}
diff --git a/binding-c/runtime/c/src/test/transport/test_url.c b/binding-c/runtime/c/src/test/transport/test_url.c
new file mode 100644
index 0000000..2b4d9ef
--- /dev/null
+++ b/binding-c/runtime/c/src/test/transport/test_url.c
@@ -0,0 +1,495 @@
+/* $Id$ 
+ * 
+ * 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. 
+ */ 
+
+/*
+ * test_url.c -- test etch_url
+ */
+#include "etch_runtime.h"
+#include "etch_url.h"
+#include "etch_map.h"
+#include "etch_thread.h"
+#include "etch_objecttypes.h"
+
+#include <stdio.h>
+#include "CUnit.h"
+#include <wchar.h>
+
+#define IS_DEBUG_CONSOLE FALSE
+
+// extern types
+extern apr_pool_t* g_etch_main_pool;
+
+/* - - - - - - - - - - - - - - 
+ * unit test infrastructure
+ * - - - - - - - - - - - - - -
+ */
+
+static int init_suite(void)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+
+    etch_status = etch_runtime_initialize(NULL);
+    if(etch_status != NULL) {
+        // error
+    }
+    return 0;
+}
+
+static int clean_suite(void)
+{
+    etch_runtime_shutdown();
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - 
+ * tests
+ * - - - - - - - - - - - - - -
+ */
+
+/* 
+ * test_parse_1
+ */
+static void test_parse_1(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"www.cisco.com";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, ETCH_URL_DEFAULT_SCHEME);
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->host, RAWURL);
+    CU_ASSERT_EQUAL(result,0); 
+
+    etch_object_destroy(url);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_parse_2
+ */
+static void test_parse_2(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"http://www.cisco.com/cuae";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"http");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->host, L"www.cisco.com");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->uri, L"cuae");
+    CU_ASSERT_EQUAL(result,0); 
+
+    etch_object_destroy(url);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_parse_3
+ */
+static void test_parse_3(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"http://www.cisco.com:8080/cuae?param";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"http");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->host, L"www.cisco.com");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = url->port == 8080;
+    CU_ASSERT_EQUAL(result,TRUE); 
+
+    result = wcscmp(url->uri, L"cuae");
+    CU_ASSERT_EQUAL(result,0); 
+
+    etch_object_destroy(url);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_parse_4
+ */
+static void test_parse_4(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"http://administrator:metreos@www.cisco.com:8080/cuae?param";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"http");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->user, L"administrator");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->password, L"metreos");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->host, L"www.cisco.com");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = url->port == 8080;
+    CU_ASSERT_EQUAL(result,TRUE); 
+
+    result = wcscmp(url->uri, L"cuae");
+    CU_ASSERT_EQUAL(result,0); 
+
+    etch_object_destroy(url);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_parse_5
+ * since colon is both scheme and username:password delimiter
+ * ensure we can omit scheme and include password
+ */
+static void test_parse_5(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"administrator:metreos@www.cisco.com:8080/cuae?param";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"http");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->user, L"administrator");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->password, L"metreos");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->host, L"www.cisco.com");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = url->port == 8080;
+    CU_ASSERT_EQUAL(result,TRUE); 
+
+    result = wcscmp(url->uri, L"cuae");
+    CU_ASSERT_EQUAL(result,0); 
+
+    etch_object_destroy(url);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_parse_6
+ */
+static void test_parse_6(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"tcp://administrator:metreos@localhost:10000/defUri;param1;param2?term1=true&term2=false#defFragment";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"tcp");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->user, L"administrator");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->password, L"metreos");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->host, L"localhost");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = url->port == 10000;
+    CU_ASSERT_EQUAL(result,TRUE); 
+
+    result = wcscmp(url->uri, L"defUri");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = etchurl_paramcount(url);
+    CU_ASSERT_EQUAL(result,2); 
+
+    result = etchurl_termcount(url);
+    CU_ASSERT_EQUAL(result,2);
+
+    do 
+    {   etch_iterator* iterator = etchurl_get_params(url);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+
+        while(iterator->has_next(iterator))
+        {   int matches = 0;
+            etch_string* val = (etch_string*) iterator->current_value;
+            wchar_t* param = val? val->v.valw: NULL;
+            if (param && 0 == wcscmp(param, L"param1")) matches++;
+            if (param && 0 == wcscmp(param, L"param2")) matches++;
+            CU_ASSERT_EQUAL(matches,1); 
+            iterator->next(iterator);
+        }
+        etch_object_destroy(iterator);
+    } while(0);
+
+    do 
+    {   etch_iterator iterator;
+        set_iterator(&iterator, url->terms, &url->terms->iterable);
+
+        while(iterator.has_next(&iterator))
+        {   int keymatches = 0, valmatches = 0;
+            wchar_t* key = (wchar_t*) iterator.current_key;
+            etch_string* valobj = (etch_string*) iterator.current_value;
+            wchar_t* val = valobj? valobj->v.valw: NULL;
+            if (key && 0 == wcscmp(key, L"term1")) keymatches++;
+            if (key && 0 == wcscmp(key, L"term2")) keymatches++;
+            CU_ASSERT_EQUAL(keymatches,1); 
+            if (val && 0 == wcscmp(val, L"false")) valmatches++;
+            if (val && 0 == wcscmp(val, L"true"))  valmatches++;
+            CU_ASSERT_EQUAL(valmatches,1); 
+            iterator.next(&iterator);
+        }
+    } while(0);
+
+    etch_object_destroy(url);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/* 
+ * test_parse_7
+ * test a url with duplicate term names
+ */
+static void test_parse_7(void)
+{
+    int result = 0;
+    etch_url* url = NULL;
+    wchar_t* RAWURL = L"tcp://administrator:metreos@localhost:10000/defUri;param1;param2?term1=true&term1=false";
+
+    url = new_url(RAWURL);
+    CU_ASSERT_PTR_NOT_NULL_FATAL(url); 
+
+    CU_ASSERT_NOT_EQUAL(url->bytecount,0); 
+    CU_ASSERT_NOT_EQUAL(url->charcount,0); 
+
+    result = wcscmp(url->raw, RAWURL);
+    CU_ASSERT_EQUAL(result,0);
+
+    result = wcscmp(url->scheme, L"tcp");
+    CU_ASSERT_EQUAL(result,0);  
+
+    result = wcscmp(url->user, L"administrator");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->password, L"metreos");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = wcscmp(url->host, L"localhost");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = url->port == 10000;
+    CU_ASSERT_EQUAL(result,TRUE); 
+
+    result = wcscmp(url->uri, L"defUri");
+    CU_ASSERT_EQUAL(result,0); 
+
+    result = etchurl_paramcount(url);
+    CU_ASSERT_EQUAL(result,2); 
+
+    /* since terms had same name, the two terms should now be collected into a set, 
+     * therefore the count (at top level) should be 1. this is of course based
+     * on our omniscient knowledge of the url content */
+    result = etchurl_termcount(url);
+    CU_ASSERT_EQUAL(result,1); 
+
+    do  /* iterate all params */
+    {   etch_iterator* iterator = etchurl_get_params(url);
+        CU_ASSERT_PTR_NOT_NULL_FATAL(iterator);
+
+        while(iterator->has_next(iterator))
+        {   int matches = 0;
+            etch_string* val = (etch_string*) iterator->current_value;
+            wchar_t* param = val? val->v.valw: NULL;
+            if (param && 0 == wcscmp(param, L"param1")) matches++;
+            if (param && 0 == wcscmp(param, L"param2")) matches++;
+            CU_ASSERT_EQUAL(matches,1); 
+
+            iterator->next(iterator);
+        }
+
+        etch_object_destroy(iterator);
+
+    } while(0);
+
+    do  /* iterate all terms */
+    {   etch_iterator iterator1;
+        set_iterator(&iterator1, url->terms, &url->terms->iterable);
+
+        /* this is hard coded base on our knowledge of the url content. 
+         * there should be one term in the term map with the value "term1",
+         * and its value will be a set whose two members are etch_string 
+         * objects having values of "true" and "false"
+         */
+        while(iterator1.has_next(&iterator1))
+        {    
+            etch_iterator iterator2;
+            etch_set* setobj = (etch_set*)iterator1.current_value;
+            CU_ASSERT_EQUAL_FATAL(is_etch_set(setobj), TRUE);
+
+            result = etchmap_count(setobj);
+            CU_ASSERT_EQUAL(result, 2);
+
+            set_iterator(&iterator2, setobj, &setobj->iterable);
+
+            while(iterator2.has_next(&iterator2))
+            {
+                int matches = 0;
+                wchar_t* val = 0;
+                etch_string* setmember = iterator2.current_key;
+                CU_ASSERT_EQUAL_FATAL(is_etch_string(setmember), TRUE);
+                val = setmember->v.valw;
+                if (val && 0 == wcscmp(val, L"true"))  matches++;
+                if (val && 0 == wcscmp(val, L"false")) matches++;
+                CU_ASSERT_EQUAL(matches,1); 
+
+                iterator2.next(&iterator2);
+            }
+            
+            iterator1.next(&iterator1);
+        }
+
+    } while(0);
+
+    etch_object_destroy(url);
+
+#ifdef ETCH_DEBUGALLOC
+   g_bytes_allocated = etch_showmem(0,IS_DEBUG_CONSOLE);  /* verify all memory freed */
+   CU_ASSERT_EQUAL(g_bytes_allocated, 0);
+   // start fresh for next test
+   memtable_clear();
+#endif
+}
+
+
+/**
+ * main   
+ */
+//int _tmain(int argc, _TCHAR* argv[])
+CU_pSuite test_etch_url_suite()
+{
+    CU_pSuite pSuite = CU_add_suite("suite_url", init_suite, clean_suite);
+
+    CU_add_test(pSuite, "test parse 1", test_parse_1); 
+    CU_add_test(pSuite, "test parse 2", test_parse_2); 
+    CU_add_test(pSuite, "test parse 3", test_parse_3); 
+    CU_add_test(pSuite, "test parse 4", test_parse_4); 
+    CU_add_test(pSuite, "test parse 5", test_parse_5);
+    CU_add_test(pSuite, "test parse 6", test_parse_6);
+    CU_add_test(pSuite, "test parse 7", test_parse_7);
+
+    return pSuite;
+}
+
diff --git a/build-support/etch.common.xml b/build-support/etch.common.xml
index fdaffc2..895f974 100644
--- a/build-support/etch.common.xml
+++ b/build-support/etch.common.xml
@@ -104,6 +104,8 @@
     <property name="etch-java-compiler-src.zip"   value="apache-etch-java-compiler-${Etch.longversion}-src.zip" />
     <property name="etch-java-runtime.jar"        value="apache-etch-java-runtime-${Etch.longversion}.jar" />
     <property name="etch-java-runtime-src.zip"    value="apache-etch-java-runtime-${Etch.longversion}-src.zip" />
+    <property name="etch-c-compiler.jar"          value="apache-etch-c-compiler-${Etch.longversion}.jar" />
+    <property name="etch-c-compiler-src.zip"      value="apache-etch-c-compiler-${Etch.longversion}-src.zip" />  	
     <property name="etch-csharp-compiler.jar"     value="apache-etch-csharp-compiler-${Etch.longversion}.jar" />
     <property name="etch-csharp-compiler-src.zip" value="apache-etch-csharp-compiler-${Etch.longversion}-src.zip" />
     <property name="etch-xml-compiler.jar"        value="apache-etch-xml-compiler-${Etch.longversion}.jar" />
diff --git a/build.xml b/build.xml
index c7d6f6c..3189828 100755
--- a/build.xml
+++ b/build.xml
@@ -153,6 +153,7 @@
         <build_component dir="binding-xml" />
         <build_component dir="binding-java" />
         <build_component dir="binding-csharp" />
+        <build_component dir="binding-c" />
         
         <!-- Examples -->
         <build_component dir="examples" />
diff --git a/examples/helloworld/README.txt b/examples/helloworld/README.txt
new file mode 100644
index 0000000..fb094cb
--- /dev/null
+++ b/examples/helloworld/README.txt
@@ -0,0 +1,23 @@
+The Helloworld example is a very very simple example to illustrate the interoperability 
+of the c and the java binding. 
+
+Of course you can also compile every ETCH IDL from the official Etch examples using the 
+ETCH C IDL Compiler.
+
+This example comes already pre-generated for you, so you should have minimal effort getting it 
+running. You can re-generate the code using the generate-c-and-java.bat in \helloworld\etch\
+
+To run the example, run the java server (an eclipse  project is located in \helloworld\etch)
+and run the c client (a VS solution is provided in \helloworld\c). Feel free to play with IDL 
+and sources to try out other Etch features. Currently the Helloworld c example implements
+only the client part. 
+
+****************************************************
+ATTENTION: The C Binding needs libapr-1.dll and libapriconv-1.dll either in your PATH or
+in the working directory of the client executable!
+****************************************************
+
+Please note that the C Compiler does not overwrite impl-files (they might contain your Implementation).
+A side-effect is that you have to delete all impl headers by hand when adding e.g. a new function to the IDL.
+This will be changed in a later release.
+
diff --git a/examples/helloworld/c/helloworld.sln b/examples/helloworld/c/helloworld.sln
new file mode 100644
index 0000000..608e710
--- /dev/null
+++ b/examples/helloworld/c/helloworld.sln
@@ -0,0 +1,20 @@
+

+Microsoft Visual Studio Solution File, Format Version 9.00

+# Visual Studio 2005

+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "helloworld", "helloworld.vcproj", "{D660401E-5348-4F6B-B3A0-60FC2287788B}"

+EndProject

+Global

+	GlobalSection(SolutionConfigurationPlatforms) = preSolution

+		Debug|Win32 = Debug|Win32

+		Release|Win32 = Release|Win32

+	EndGlobalSection

+	GlobalSection(ProjectConfigurationPlatforms) = postSolution

+		{D660401E-5348-4F6B-B3A0-60FC2287788B}.Debug|Win32.ActiveCfg = Debug|Win32

+		{D660401E-5348-4F6B-B3A0-60FC2287788B}.Debug|Win32.Build.0 = Debug|Win32

+		{D660401E-5348-4F6B-B3A0-60FC2287788B}.Release|Win32.ActiveCfg = Release|Win32

+		{D660401E-5348-4F6B-B3A0-60FC2287788B}.Release|Win32.Build.0 = Release|Win32

+	EndGlobalSection

+	GlobalSection(SolutionProperties) = preSolution

+		HideSolutionNode = FALSE

+	EndGlobalSection

+EndGlobal

diff --git a/examples/helloworld/c/helloworld.vcproj b/examples/helloworld/c/helloworld.vcproj
new file mode 100644
index 0000000..95d0294
--- /dev/null
+++ b/examples/helloworld/c/helloworld.vcproj
@@ -0,0 +1,300 @@
+<?xml version="1.0" encoding="Windows-1252"?>

+<VisualStudioProject

+	ProjectType="Visual C++"

+	Version="8,00"

+	Name="helloworld"

+	ProjectGUID="{D660401E-5348-4F6B-B3A0-60FC2287788B}"

+	RootNamespace="helloworld"

+	>

+	<Platforms>

+		<Platform

+			Name="Win32"

+		/>

+	</Platforms>

+	<ToolFiles>

+	</ToolFiles>

+	<Configurations>

+		<Configuration

+			Name="Debug|Win32"

+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			CharacterSet="2"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				Optimization="0"

+				AdditionalIncludeDirectories="&quot;..\..\..\binding-c\runtime\c\src\extern\apr\apr\include&quot;;&quot;..\..\..\binding-c\runtime\c\src\extern\apr\apr\include\arch\win32&quot;;&quot;..\..\..\binding-c\runtime\c\src\extern\jenkhash&quot;;&quot;..\..\..\binding-c\runtime\c\include&quot;"

+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB;APR_DECLARE_STATIC"

+				MinimalRebuild="true"

+				BasicRuntimeChecks="3"

+				RuntimeLibrary="3"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="4"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				AdditionalDependencies="etch-c.lib jenkhash.lib libapr-1.lib libapriconv-1.lib"

+				AdditionalLibraryDirectories="&quot;..\..\..\binding-c\runtime\c\src\extern\apr\apr\Debug&quot;;&quot;..\..\..\binding-c\runtime\c\target\win32\Debug&quot;;&quot;..\..\..\binding-c\runtime\c\src\extern\jenkhash\target\win32\Debug&quot;;&quot;..\..\..\binding-c\runtime\c\src\extern\apr\apr-iconv\Debug&quot;"

+				GenerateDebugInformation="true"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+		<Configuration

+			Name="Release|Win32"

+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"

+			IntermediateDirectory="$(ConfigurationName)"

+			ConfigurationType="1"

+			CharacterSet="2"

+			WholeProgramOptimization="1"

+			>

+			<Tool

+				Name="VCPreBuildEventTool"

+			/>

+			<Tool

+				Name="VCCustomBuildTool"

+			/>

+			<Tool

+				Name="VCXMLDataGeneratorTool"

+			/>

+			<Tool

+				Name="VCWebServiceProxyGeneratorTool"

+			/>

+			<Tool

+				Name="VCMIDLTool"

+			/>

+			<Tool

+				Name="VCCLCompilerTool"

+				RuntimeLibrary="2"

+				WarningLevel="3"

+				Detect64BitPortabilityProblems="true"

+				DebugInformationFormat="3"

+			/>

+			<Tool

+				Name="VCManagedResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCResourceCompilerTool"

+			/>

+			<Tool

+				Name="VCPreLinkEventTool"

+			/>

+			<Tool

+				Name="VCLinkerTool"

+				GenerateDebugInformation="true"

+				OptimizeReferences="2"

+				EnableCOMDATFolding="2"

+				TargetMachine="1"

+			/>

+			<Tool

+				Name="VCALinkTool"

+			/>

+			<Tool

+				Name="VCManifestTool"

+			/>

+			<Tool

+				Name="VCXDCMakeTool"

+			/>

+			<Tool

+				Name="VCBscMakeTool"

+			/>

+			<Tool

+				Name="VCFxCopTool"

+			/>

+			<Tool

+				Name="VCAppVerifierTool"

+			/>

+			<Tool

+				Name="VCWebDeploymentTool"

+			/>

+			<Tool

+				Name="VCPostBuildEventTool"

+			/>

+		</Configuration>

+	</Configurations>

+	<References>

+	</References>

+	<Files>

+		<Filter

+			Name="Source Files"

+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"

+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"

+			>

+			<File

+				RelativePath=".\helloworld_client.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_client_impl.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_client_implx.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_client_main.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_client_stub.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_helper.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_interface.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_remote.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_remote_client.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_remote_server.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_server.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_server_impl.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_server_implx.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_server_stub.c"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_valufact.c"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Header Files"

+			Filter="h;hpp;hxx;hm;inl;inc;xsd"

+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"

+			>

+			<File

+				RelativePath=".\helloworld_client.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_client_impl.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_client_main.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_client_stub.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_helper.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_interface.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_remote.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_remote_client.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_remote_server.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_server.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_server_impl.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_server_stub.h"

+				>

+			</File>

+			<File

+				RelativePath=".\helloworld_valufact.h"

+				>

+			</File>

+		</Filter>

+		<Filter

+			Name="Resource Files"

+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"

+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"

+			>

+		</Filter>

+	</Files>

+	<Globals>

+	</Globals>

+</VisualStudioProject>

diff --git a/examples/helloworld/c/helloworld_client.c b/examples/helloworld/c/helloworld_client.c
new file mode 100644
index 0000000..617d9d5
--- /dev/null
+++ b/examples/helloworld/c/helloworld_client.c
@@ -0,0 +1,103 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#include "helloworld_client.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_url.h"  
+
+unsigned short CLASSID_HELLOWORLD_CLIENT_BASE;
+	
+	
+int destroy_helloworld_client_base(void*);
+
+
+/* - - - - - - - - - - - - - -  
+ * constructors
+ * - - - - - - - - - - - - - -  
+ */
+/**
+ * new_helloworld_client_base()
+ * @param iservice service interface -- caller retains   
+ */
+i_helloworld_client* new_helloworld_client_base(struct helloworld_client_impl* implobj)
+{
+    i_helloworld_client* ipc = (i_helloworld_client*) new_object (sizeof(i_helloworld_client), 
+        ETCHTYPEB_EXECLIENTBASE, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_CLIENT_BASE));
+
+    ipc->thisx   = implobj;  /* helloworld_client_impl on client, null on server */
+    ((etch_object*)ipc)->destroy = destroy_helloworld_client_base;
+
+    ipc->ihelloworld = new_helloworld_service_interface();
+
+    ipc->say_hello = ipc->ihelloworld->say_hello;
+
+    ipc->user = ipc->ihelloworld->user;
+ 
+    return ipc;
+}
+
+/**
+ * destroy_helloworld_client_base()
+ * i_helloworld_client destructor.
+ */
+int destroy_helloworld_client_base (void* data)
+{
+    i_helloworld_client* ipc = (i_helloworld_client*)data;
+    if (NULL == ipc) return -1;  
+
+    if (!is_etchobj_static_content(ipc))
+    {    
+        if (ipc->thisx)  /* thisx is null on server (i.e. this is a remote client) */
+        {   /* destroy the helloworld_client_impl object */
+            ETCH_ASSERT(is_etch_client_impl((etch_object*)ipc->thisx));
+            //ETCHOBJ_DESTROY();
+			if(((etch_object*)ipc->thisx)){
+				etch_object_destroy(((etch_object*)ipc->thisx));
+			}
+			ipc->thisx = NULL;
+        }
+
+        //ETCHOBJ_DESTROY(ipc->ihelloworld);
+		if(ipc->ihelloworld){
+			etch_object_destroy(ipc->ihelloworld);
+		}
+		ipc->ihelloworld = NULL;
+
+        etch_free(ipc->iobjsession);
+    }
+            
+    return destroy_objectex((etch_object*)ipc);
+}
+
+/* - - - - - - - - - - - - - -  
+ * client base methods
+ * - - - - - - - - - - - - - -  
+ */
+
+/* nothing to do - service defines no client-directed items */
+
diff --git a/examples/helloworld/c/helloworld_client.h b/examples/helloworld/c/helloworld_client.h
new file mode 100644
index 0000000..fde42e6
--- /dev/null
+++ b/examples/helloworld/c/helloworld_client.h
@@ -0,0 +1,100 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * helloworld_client.h
+ * helloworld client interface.
+ * combines java bindings's helloworldServer and BasehelloworldServer
+ */
+
+#ifndef HELLOWORLD_CLIENT_H
+#define HELLOWORLD_CLIENT_H
+
+#include "helloworld_interface.h"
+#include "etch_sessionint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_HELLOWORLD_CLIENT_BASE;
+
+//typedef struct helloworld_client_impl helloworld_client_impl;
+
+/**
+ * i_helloworld_client
+ * helloworld client base interface
+ */
+typedef struct i_helloworld_client
+{
+    etch_object object;
+
+	struct helloworld_client_impl* thisx;
+    i_helloworld*  ihelloworld;
+    
+    
+
+    /* - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - -
+     * service virtuals
+     * - - - - - - - - - - -
+     */
+    helloworld_say_hello say_hello;
+
+    /* no client-directed items defined */
+
+    /* - - - - - - - - - - -
+    * service data
+    * - - - - - - - - - - -
+    */
+    helloworld_user* user;
+
+     /* - - - - - - - - - - -
+     * private instance data
+     * - - - - - - - - - - -
+     */
+    int server_id;
+
+} i_helloworld_client;
+
+//i_helloworld_client* new_helloworld_client_base(helloworld_client_impl* implobj);
+i_helloworld_client* new_helloworld_client_base();
+
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* HELLOWORLD_CLIENT_H */
diff --git a/examples/helloworld/c/helloworld_client_impl.c b/examples/helloworld/c/helloworld_client_impl.c
new file mode 100644
index 0000000..aebb53d
--- /dev/null
+++ b/examples/helloworld/c/helloworld_client_impl.c
@@ -0,0 +1,92 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#include "helloworld_client_impl.h"
+#include "etch_url.h"
+#include "etch_arrayval.h"
+#include "etch_binary_tdo.h"
+#include "etch_exception.h"
+#include "etch_general.h"
+#include "etch_log.h"
+
+#include <stdio.h>
+
+unsigned short CLASSID_HELLOWORLD_CLIENT_IMPL;	
+	
+	
+char* HELLOWORLD_ETCHCIMP = "CIMP";
+
+/* generated signatures */
+int destroy_helloworld_client_implx(helloworld_client_impl*);
+helloworld_client_impl* init_helloworld_client_impl(struct helloworld_remote_server*, etch_object_destructor);
+
+
+/* - - - - - - - -    
+ * instantiation
+ * - - - - - - - -   
+ */
+
+/**
+ * new_helloworld_client_impl()
+ * helloworld_client_impl constructor.
+ * add your custom initialization and virtual method overrides here.
+ */
+helloworld_client_impl* new_helloworld_client_impl(struct helloworld_remote_server* server) 
+{
+    helloworld_client_impl* pclient  /* allocate object and assign default virtuals */
+        = init_helloworld_client_impl(server, destroy_helloworld_client_implx);	
+    /* add virtual method overrides, if any, here */
+    //pclient->xxx = implementation
+
+    return pclient;
+}
+
+
+/**
+ * destroy_helloworld_client_implx()
+ * destructor for any user allocated memory.
+ * this code is invoked by the private perf_client_impl destructor,
+ * via perf_client.destroyex(). add code here to destroy any memory you  
+ * may have allocated for your custom perf_client implementation.
+ */
+int destroy_helloworld_client_implx(helloworld_client_impl* thisx)
+{
+    /* * *  add custom destruction here  * * */
+    //etch_free(thisx->exampleobj);
+
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - -
+ * session interface method overrides
+ * - - - - - - - - - - - - - - - - - - -
+ */
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * implementations of helloworld_client messages from server, if any 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+ 
diff --git a/examples/helloworld/c/helloworld_client_impl.h b/examples/helloworld/c/helloworld_client_impl.h
new file mode 100644
index 0000000..7b01472
--- /dev/null
+++ b/examples/helloworld/c/helloworld_client_impl.h
@@ -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.
+ *
+ */
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#ifndef HELLOWORLD_CLIENT_IMPL_H
+#define HELLOWORLD_CLIENT_IMPL_H
+
+#include "helloworld_client.h"
+#include "etch_transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_HELLOWORLD_CLIENT_IMPL;
+
+//typedef struct helloworld_remote_server helloworld_remote_server;
+
+/**
+ * helloworld_client_impl
+ * your custom implementation of helloworld_client. add methods here 
+ * to provide implementations of messages from the client, if any.
+ */
+typedef struct helloworld_client_impl
+{
+    etch_object object;  
+
+    i_helloworld_client* helloworld_client_base; /* owned */
+    i_helloworld* ihelloworld; /* not owned */
+    struct helloworld_remote_server* server; /* not owned */
+
+    int (*destroyex) (void*);  /* user memory destructor */
+
+    /* - - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;  /* owned by base */
+    /* note that iobjsession->thisx is set to this helloworld_client_impl* */
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - - -
+     * base service virtuals
+     * - - - - - - - - - - - -
+     */
+    helloworld_say_hello say_hello;
+
+    void* context;
+
+
+} helloworld_client_impl;
+
+/* constructor */
+helloworld_client_impl* new_helloworld_client_impl (struct helloworld_remote_server*);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* HELLOWORLD_CLIENT_IMPL_H */
diff --git a/examples/helloworld/c/helloworld_client_implx.c b/examples/helloworld/c/helloworld_client_implx.c
new file mode 100644
index 0000000..ce73802
--- /dev/null
+++ b/examples/helloworld/c/helloworld_client_implx.c
@@ -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.
+ *
+ */
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * helloworld_client_implx.c 
+ * $helper.getImplName functions which would ordinarily not be subject to edit.
+ */
+
+#include "helloworld_client_impl.h"
+#include "helloworld_remote_server.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_url.h"
+
+int destroy_helloworld_client_impl(void*);
+
+/* - - - - - - - - - - - - - - - - - - - - - - - -   
+ *helloworld_client_impl private construction / destruction 
+ * - - - - - - - - - - - - - - - - - - - - - - - -    
+ */
+
+/**
+ * init_helloworld_client_impl()
+ * called by helloworld_client_impl constructor to instantiate server implementation 
+ * object and initialize with default virtuals.
+ * @param client the remote client, not owned.
+ * @param usermem_dtor destructor for any custom memory allocations.
+ */
+helloworld_client_impl* init_helloworld_client_impl(helloworld_remote_server* server, 
+    etch_object_destructor usermem_dtor)
+{
+	helloworld_client_impl* pclient = (helloworld_client_impl*) new_object (sizeof(helloworld_client_impl), 
+        ETCHTYPEB_EXECLIENTIMPL, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_CLIENT_IMPL));  
+		
+    pclient->server  = server;  /* not owned */
+    ((etch_object*)pclient)->destroy = destroy_helloworld_client_impl;  /* private destructor */
+    pclient->destroyex = usermem_dtor;  /* user memory destructor */
+
+    /* instantiate base and copy virtuals, if any, to this object */
+    pclient->helloworld_client_base = new_helloworld_client_base(pclient); /* owned */
+
+    pclient->ihelloworld = pclient->helloworld_client_base->ihelloworld;
+
+
+
+
+    pclient->iobjsession = server->server_base->iobjsession;
+    pclient->iobjsession->thisx = pclient;  /* set implementor reference */
+    pclient->_session_control = pclient->helloworld_client_base->_session_control;
+    pclient->_session_notify  = pclient->helloworld_client_base->_session_notify;
+    pclient->_session_query   = pclient->helloworld_client_base->_session_query;
+
+    return pclient;
+}
+
+/**
+ * destroy_perf_server_impl()
+ * perf_server_impl private destructor.
+ * calls back to user destructor to effect cleanup of any perf_server_impl 
+ * memory which may have been allocated in custom code added by user.
+ */
+int destroy_helloworld_client_impl (void* data)
+{
+    helloworld_client_impl* thisx = (helloworld_client_impl*)data;
+    if (NULL == thisx) return -1;  
+
+    if (!is_etchobj_static_content(thisx))
+    {    
+        if(thisx->destroyex)
+        {   /* call back to user memory destructor */
+            thisx->destroyex(thisx);
+        }
+    }
+            
+    return destroy_objectex((etch_object*)thisx);
+}
diff --git a/examples/helloworld/c/helloworld_client_main.c b/examples/helloworld/c/helloworld_client_main.c
new file mode 100644
index 0000000..b943caa
--- /dev/null
+++ b/examples/helloworld/c/helloworld_client_main.c
@@ -0,0 +1,112 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+/*
+ * helloworld_client_main.c
+ */
+ 
+#include "helloworld_client_main.h"
+#include "etch_objecttypes.h"
+#include "etch_runtime.h"
+#include "etch_arrayval.h"
+#include "etch_nativearray.h"
+#include "etch_binary_tdo.h"
+#include "etch_general.h"
+
+
+/**
+ * new_helloworld_client().
+ * callback constructor for client implementation object.
+ * this callback address is passed to start_helloworld_client() in [main].
+ * @param server the remote server. 
+ * @remarks this callback must be supplied, i.e. its functionality cannot be 
+ * defaulted, since the client implementation constructor new_helloworld_client_impl()
+ * is not known to start_helloworld_client().
+ */
+static i_helloworld_client* helloworld_client_create(void* factory_thisx, helloworld_remote_server* server)
+{
+    helloworld_client_impl* client = new_helloworld_client_impl(server);
+    return client? client->helloworld_client_base:NULL;
+}
+
+/**
+ * main()
+ */
+int main(int argc, char* argv[])
+{
+    etch_status_t etch_status    = ETCH_SUCCESS;
+    helloworld_remote_server* remote = NULL;
+    int result = -1, is_waitkey  = TRUE, waitupms = 4000;
+    helloworld_user* user = new_helloworld_user();
+    etch_string* answer = NULL;
+    
+    wchar_t* uri = L"tcp://127.0.0.1:4004";	
+	
+    etch_config_t* config = NULL;
+    etch_config_create(&config);
+    // set properties or read file
+
+    etch_status = etch_runtime_initialize(config);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+        return 1;
+    }
+
+    etch_status = helloworld_helper_remote_server_create(&remote, uri, NULL, helloworld_client_create);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+
+    etch_status = helloworld_helper_remote_server_start_wait(remote, waitupms);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+	
+	//add your implementation here
+    
+    user->name = new_stringw(L"Testuser");
+    answer = remote->say_hello(remote,user);
+    if(answer && ! is_etch_exception(answer)){
+        wprintf(L"Server said: %s\n", answer->v.valw);
+    }else{
+        wprintf(L"Remote call failed, is the server running?\n");
+    }
+
+    // wait until key press
+    waitkey();
+
+    etch_status = helloworld_helper_remote_server_stop_wait(remote, waitupms);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+
+    etch_status = helloworld_helper_remote_server_destroy(remote);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+	etch_config_destroy(config);
+	return 0;
+}
+  
diff --git a/examples/helloworld/c/helloworld_client_main.h b/examples/helloworld/c/helloworld_client_main.h
new file mode 100644
index 0000000..b8b4244
--- /dev/null
+++ b/examples/helloworld/c/helloworld_client_main.h
@@ -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.
+ *
+ */
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+/*
+ * helloworld_client_main.h
+ * client exe main() private header
+ */
+
+#ifndef HELLOWORLD_CLIENT_MAIN_H
+#define HELLOWORLD_CLIENT_MAIN_H
+
+#include "etch_runtime.h"
+#include "helloworld_helper.h"
+#include "helloworld_client_impl.h"
+#include "helloworld_remote_server.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * helloworld_listener_start(pplistener, uri, waitupms)
+ * Start the listener at the given uri, waiting waitupms microseconds for listener startup.
+ * The created listener is saved at address pointed to by pplistener.
+ */
+extern etch_status_t helloworld_listener_start(i_sessionlistener** pplistener, wchar_t* uri, int waitupms);
+
+/*
+ * helloworld_listener_stop(plistener, waitupms)
+ * Stop the listener given by plistener, waiting waitupms microseconds to stop.
+ */
+extern etch_status_t helloworld_listener_stop(i_sessionlistener* plistener, int waitupms);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* HELLOWORLD_CLIENT_MAIN.H */
diff --git a/examples/helloworld/c/helloworld_client_stub.c b/examples/helloworld/c/helloworld_client_stub.c
new file mode 100644
index 0000000..61db16b
--- /dev/null
+++ b/examples/helloworld/c/helloworld_client_stub.c
@@ -0,0 +1,146 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * helloworld_client_stub.c 
+ */
+
+#include "helloworld_client.h"
+#include "helloworld_client_stub.h"
+#include "helloworld_valufact.h"
+
+#include "etch_url.h"
+#include "etch_objecttypes.h"
+#include "etch_svcobj_masks.h"
+#include "etch_general.h"
+
+
+unsigned short CLASSID_HELLOWORLD_CLIENT_STUB;	
+	
+	
+int destroy_helloworld_client_stub(void*);
+
+
+/* - - - - - - - - - - -
+ * stub helper methods 
+ * - - - - - - - - - - -
+ */
+
+/**
+ * helloworld_client_stub_run_nothing_
+ */
+int helloworld_client_stub_run_nothing_ (etch_stub* stub, i_delivery_service* dsvc, 
+    void* obj, etch_who* whofrom, etch_message* msg)
+{
+    i_helloworld_client* client = (i_helloworld_client*)obj;
+    helloworld_valufact_impl* pvfi = NULL;
+    helloworld_valufact* pvf = NULL;
+    struct helloworld_client_impl* impl = NULL;
+
+    /* objects specific to service.nothing_() */
+    etch_field*  key_foo  = NULL;
+    etch_int64*  val_foo  = NULL;
+    etch_field*  key_bar  = NULL;
+    etch_string* val_bar  = NULL;
+    etch_int32* resultobj = NULL;
+
+    etchstub_validate_args (stub, dsvc, msg, client, &pvf, (void**)&pvfi, (void**)&impl);     
+
+    key_foo = NULL;
+    key_bar = NULL;
+    ETCH_ASSERT(key_foo && key_bar);  
+
+    /* nullarg asserts are initial tests only: server impl   
+     * will generate exceptions on nullargs in the real world */
+    val_foo = NULL; /* = (etch_int64*)  message_get (msg, key_foo); */
+    val_bar = NULL; /* = (etch_string*) message_get (msg, key_bar); */
+    ETCH_ASSERT(val_foo && val_bar); 
+
+    /* execute the service method */
+    resultobj = NULL; /* server->nothing_ (impl, val_foo, val_bar); */
+    ETCH_ASSERT(resultobj); 
+
+    /* transmit reply back to sender */
+    return etchstub_send_reply (stub, dsvc, whofrom, msg, (void*) resultobj, TRUE);
+}   
+
+/* - - - - - - - - - 
+ * constructors 
+ * - - - - - - - - - 
+ */
+
+/**
+ * new_helloworld_client_stub.
+ * called from $helper.getRemoteName($intf, $helper.getRemoteDirection($mc))* perfhelper.new_remote_SERVER().
+ * @param p client parameter bundle
+ */
+helloworld_client_stub* new_helloworld_client_stub (etch_client_factory* p)   
+{
+    helloworld_client_stub* mystub = NULL;
+    i_delivery_service* ids = p->dsvc;
+    etch_threadpool *qp = p->qpool, *fp = p->fpool;
+	
+    i_helloworld_client* client = p->iclient;
+    ETCH_ASSERT(is_etch_ideliverysvc(ids)); 
+    ETCH_ASSERT(is_etch_client_base(client)); 
+
+    mystub = new_clientstub_init (client, sizeof(helloworld_client_stub), 
+        destroy_helloworld_client_stub, ids, qp, fp, p);
+
+    ((etch_object*)mystub)->class_id  = get_dynamic_classid_unique(&CLASSID_HELLOWORLD_CLIENT_STUB);
+    mystub->server_id = p->server_id;  
+
+    /* initialize custom methods and data here */
+
+    /* set stub helper methods */
+
+    return mystub;
+}
+
+/**
+ * is_helloworld_client_stub()
+ */
+int is_helloworld_client_stub(void* obj)
+{
+    return obj && ((etch_object*)obj)->class_id == CLASSID_HELLOWORLD_CLIENT_STUB;
+}
+
+/**
+ * destroy_def_helloworld_client_stub()
+ * helloworld_client_stub user-allocated memory destructor.
+ * called back from private object destructor destroy_stub_object().
+ * if you explicitly allocate memory in the client stub object, destroy it here.
+ */
+int destroy_helloworld_client_stub(void* data)
+{
+   /*
+     helloworld_client_stub* mystub = (helloworld_client_stub*)data;
+      free custom memory allocations here */
+    //etch_free(mystub->my_example_obj); /* free example alloc */
+
+    return 0;
+}
diff --git a/examples/helloworld/c/helloworld_client_stub.h b/examples/helloworld/c/helloworld_client_stub.h
new file mode 100644
index 0000000..583dd88
--- /dev/null
+++ b/examples/helloworld/c/helloworld_client_stub.h
@@ -0,0 +1,75 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#ifndef HELLOWORLD_CLIENT_STUB_H
+#define HELLOWORLD_CLIENT_STUB_H
+
+#include "etch_stub.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_HELLOWORLD_CLIENT_STUB;
+
+/**
+ * helloworld_client_stub
+ */
+typedef struct helloworld_client_stub
+{
+    etch_object object;
+
+    etch_stub* stub_base;
+    
+    int  server_id;            
+    int (*destroyex) (void*);  /* user memory destructor */
+
+    /* - - - - - - - - - - - - - - - - -
+     * client_directed service virtuals
+     * - - - - - - - - - - - - - - - - -
+     */
+     
+    /* no client-directed items defined */
+
+    /* - - - - - - - - - - - - - - - - -
+     * service-specific allocations
+     * - - - - - - - - - - - - - - - - -
+     */
+    // add here
+
+} helloworld_client_stub;
+
+helloworld_client_stub* new_helloworld_client_stub (etch_client_factory*);
+int is_helloworld_client_stub(void* obj);
+int destroy_helloworld_client_stub (void*);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* PERF_SERVER_STUB_H */
+
diff --git a/examples/helloworld/c/helloworld_helper.c b/examples/helloworld/c/helloworld_helper.c
new file mode 100644
index 0000000..c488048
--- /dev/null
+++ b/examples/helloworld/c/helloworld_helper.c
@@ -0,0 +1,337 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+
+/*
+ * helloworld_helper.c 
+ * transport helper for helloworld service
+ */
+#include "helloworld_interface.h"
+
+#include "helloworld_server.h"
+#include "helloworld_server_stub.h"
+#include "helloworld_remote_client.h"
+#include "helloworld_client_stub.h"
+#include "helloworld_remote_server.h"
+
+#include "helloworld_helper.h"
+#include "helloworld_valufact.h"
+#include "etch_svcobj_masks.h"
+#include "etch_objecttypes.h"
+#include "etch_url.h" 
+#include "etch_log.h" 
+
+static const char* LOG_CATEGORY     = "helloworld_helper";
+
+static int helloworld_helper_resources_init(void* data)
+{
+    etch_server_factory* factory = (etch_server_factory*)data;
+    int result = 0;
+    ETCH_ASSERT((factory != NULL) && (factory->in_valufact == NULL));
+    ETCH_ASSERT (factory->in_resx && is_etch_hashtable(factory->in_resx));
+
+    // TODO use new semantic helloworld_valuefactory_create
+    factory->in_valufact = (etch_value_factory*)new_helloworld_valufact();
+    ETCH_ASSERT(factory->in_valufact);
+    if(factory->in_valufact == NULL) {
+        return -1;
+    }
+    result = etch_resources_add(factory->in_resx, ETCH_RESXKEY_MSGIZER_VALUFACT, (etch_object*)factory->in_valufact);
+
+    ETCH_ASSERT(0 == result);
+    return result;
+}
+
+etch_status_t helloworld_helper_remote_server_create(helloworld_remote_server** remote_server, wchar_t* uri, void* factory_thisx, main_client_create_func client_create)
+{
+    etch_status_t         rv                 = ETCH_SUCCESS;
+    etch_client_factory*  factory            = NULL;
+    helloworld_remote_server* newremote_server   = NULL;
+    i_helloworld_client*      client             = NULL;
+    helloworld_client_stub*   client_stub        = NULL;
+    helloworld_valufact*      vf                 = NULL;
+
+    if(remote_server == NULL || client_create == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "creating helloworld client ...\n");
+    factory = new_client_factory (NULL, NULL, client_create);
+    ETCH_ASSERT(factory != NULL);
+	
+	factory->thisx = factory_thisx;
+
+    vf = new_helloworld_valufact();
+    ETCH_ASSERT(vf != NULL);
+
+    factory->in_valufact = (etch_value_factory*)vf;
+    factory->in_resx     = etch_transport_resources_init(factory->in_resx);
+    ETCH_ASSERT(factory->in_resx != NULL);
+    etch_resources_add (factory->in_resx, ETCH_RESXKEY_MSGIZER_VALUFACT, (etch_object*)vf);
+
+    // instantiate a delivery service
+    factory->dsvc = new_etch_transport(uri, (etch_factory_params*)factory, NULL);
+    ETCH_ASSERT(is_etch_ideliverysvc(factory->dsvc));
+
+    // instantiate the remote server
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "instantiating remote server ...\n");
+    newremote_server = new_helloworld_remote_server(NULL, factory->dsvc, (etch_value_factory*)vf);
+    ETCH_ASSERT(is_etch_remote_server(newremote_server));
+
+    factory->server_id = newremote_server->server_base->server_id;
+    factory->server = newremote_server;
+    newremote_server->client_factory = factory;
+
+    /* here we call back to the client constructor in [main]. the purpose of the 
+     * callback is to isolate the editable xxxx_client_impl constructor from the 
+     * private constructor pieces. the callback instantiates a client implenentation
+     * and returns an interface to it. 
+     */   
+    if(factory->new_client != NULL) {
+        client = factory->new_client(factory, newremote_server);
+        ETCH_ASSERT(is_etch_client_base(client));
+        factory->iclient = client;
+    }
+
+    // get thread pools
+    factory->fpool = (etch_threadpool*)etch_resources_get(factory->in_resx, ETCH_RESXKEY_POOLTYPE_FREE);
+    ETCH_ASSERT(factory->fpool);
+    factory->qpool = (etch_threadpool*)etch_resources_get(factory->in_resx, ETCH_RESXKEY_POOLTYPE_QUEUED);
+    ETCH_ASSERT(factory->qpool);
+
+    // construct client stub
+    client_stub = new_helloworld_client_stub(factory);
+    ETCH_ASSERT(is_etch_client_stub(client_stub));
+    factory->stub = client_stub;
+
+    *remote_server = newremote_server;
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG,"remote server instantiated\n");
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "helloworld client created\n");
+
+    return rv;
+}
+
+etch_status_t helloworld_helper_remote_server_start_wait(helloworld_remote_server* remote_server, const int waitms)
+{
+    etch_status_t   rv           = ETCH_SUCCESS;
+    helloworld_remote*  remote       = NULL;
+    int             result       = 0;
+
+    if(remote_server == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    remote = remote_server->remote_base;
+    ETCH_ASSERT(remote != NULL);
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "starting helloworld client ...\n");
+    result = remote->start_waitup(remote, waitms);
+    if(result != 0) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not start helloworld client\n");
+        rv = ETCH_ERROR;
+    } else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "helloworld client started\n");
+        rv = ETCH_SUCCESS;
+    }
+
+    return rv;
+}
+
+etch_status_t helloworld_helper_remote_server_stop_wait(helloworld_remote_server* remote_server, const int waitms)
+{
+    etch_status_t   rv         = ETCH_SUCCESS;
+    helloworld_remote*  remote     = NULL;
+    int             result     = 0;
+
+    if(remote_server == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    remote = remote_server->remote_base;
+    ETCH_ASSERT(remote != NULL);
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "stopping helloworld client ...\n");
+    result = remote->stop_waitdown(remote, waitms);
+    if(result != 0) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not stop helloworld client\n");
+        rv = ETCH_ERROR;
+    } else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "helloworld client stopped\n");
+        rv = ETCH_SUCCESS;
+    }
+
+    return rv;
+}
+
+etch_status_t helloworld_helper_remote_server_destroy(helloworld_remote_server* remote_server)
+{
+    etch_status_t rv     = ETCH_SUCCESS;
+
+    if(remote_server == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "destroying remote server ...\n");
+    etch_object_destroy(remote_server);
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "remote server destroyed\n");
+
+    return rv;
+}
+
+static void* helloworld_helper_listener_create_func(void* factoryData, void* sessionData)
+{
+    etch_server_factory* factory = (etch_server_factory*)factoryData;
+    etch_session* session = (etch_session*)sessionData;
+    i_helloworld_server* iserver;
+    helloworld_server_stub* stub;
+    helloworld_remote_client* client;
+    ETCH_ASSERT(factory && factory->helper_new_listener && factory->main_new_server);
+    ETCH_ASSERT(factory->in_resx && factory->in_valufact);   // TODO assert delivery service
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "instantiating accepted client listener ...\n");
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "creating remote client...\n");
+    client = new_helloworld_remote_client(NULL, session, factory->in_valufact);
+    client->session_id = session->session_id;
+    session->client = client;
+
+    /* here we CALL BACK to the constructor in [main], the purpose of the callback
+     * being to isolate the editable constructor from the private constructor. 
+     * the callback instantiates a client's server implementation and returns 
+     * an interface to it. 
+     */ 
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "creating server implementation ...\n");
+    iserver = factory->main_new_server(factory, session);
+    iserver->session_id = session->session_id;
+    session->server = iserver;
+
+    /* note that the main listener will use p->mainpool as a thread manager, not these */
+    factory->qpool = (etch_threadpool*)etch_resources_get(factory->in_resx, ETCH_RESXKEY_POOLTYPE_QUEUED);
+    factory->fpool = (etch_threadpool*)etch_resources_get(factory->in_resx, ETCH_RESXKEY_POOLTYPE_FREE);
+
+    /* eventually new_helloworld_server_stub() gets to stub_base constructor, which sets
+     * the delivery service's session to this, the server stub. so, in the java binding,
+     * the server stub is referenced as delivery service.session. we should perhaps also 
+     * store the stub opaquely in both the client and listener objects.
+     */
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "creating server stub ...\n");
+    stub = new_helloworld_server_stub(factory, session);
+    stub->session_id = session->session_id;
+    session->server_stub = stub;
+
+    if (iserver && stub)
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "accepted client listener instantiated\n");
+    else
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not instantiate accepted client listener\n");
+
+    return stub;
+}
+
+etch_status_t helloworld_helper_listener_create(i_sessionlistener** listener, wchar_t* uri, void* factory_thisx, main_server_create_func server_create)
+{
+    etch_status_t       rv          = ETCH_SUCCESS;
+    i_sessionlistener*  newlistener = NULL;
+
+    if(listener == NULL || server_create == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "instantiating main listener ...\n");
+
+    newlistener = new_etch_listener(uri, NULL, factory_thisx, helloworld_helper_listener_create_func, server_create, helloworld_helper_resources_init);
+    if(newlistener == NULL) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not instantiate main listener\n");
+        rv = ETCH_ERROR;
+    } else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "main listener instantiated\n");
+        *listener = newlistener;
+        rv = ETCH_SUCCESS;
+    }
+
+    return rv;
+}
+
+etch_status_t helloworld_helper_listener_start_wait(i_sessionlistener* listener, const int waitms)
+{
+    etch_status_t rv     = ETCH_SUCCESS;
+    int result           = 0;
+
+    if(listener == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "starting main listener ...\n");
+
+    result = listener->transport_control(listener->thisx, new_etch_event(CLASSID_CONTROL_START_WAITUP, waitms), NULL);
+    if(result != 0) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not start main listener\n");
+        rv = ETCH_ERROR;
+    } else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "main listener started on thread %d\n", transport_thread_id(listener));
+    }
+
+    return rv;
+}
+
+etch_status_t helloworld_helper_listener_stop_wait(i_sessionlistener* listener, const int waitms)
+{
+    etch_status_t rv     = ETCH_SUCCESS;
+    int result           = 0;
+
+    if(listener == NULL) {
+        return ETCH_EINVAL;
+    }
+
+    ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "stopping main listener ...\n");
+
+    result = listener->transport_control(listener->thisx, new_etch_event(CLASSID_CONTROL_STOP_WAITDOWN, waitms), NULL);
+    if(result != 0) {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not stop main listener\n");
+        rv = ETCH_ERROR;
+    } else {
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_INFO, "main listener ended\n");
+
+        if (transport_session_count (listener) > 0) {
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "begin client sessions teardown\n");
+            result = transport_teardown_client_sessions(listener);
+            ETCH_LOG(LOG_CATEGORY, ETCH_LOG_DEBUG, "end client sessions teardown\n");
+        }
+    }
+
+    return rv;
+}
+
+etch_status_t helloworld_helper_listener_destroy(i_sessionlistener* listener)
+{
+    etch_status_t rv     = ETCH_SUCCESS;
+
+    etch_object_destroy(listener);
+
+    return rv;
+}
+
+ //isSERVER
diff --git a/examples/helloworld/c/helloworld_helper.h b/examples/helloworld/c/helloworld_helper.h
new file mode 100644
index 0000000..cb0b604
--- /dev/null
+++ b/examples/helloworld/c/helloworld_helper.h
@@ -0,0 +1,56 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+
+#ifndef HELLOWORLD_HELPER_H
+#define HELLOWORLD_HELPER_H
+
+#include "etch.h"
+#include "etch_errno.h"
+#include "etch_transport.h"
+#include "helloworld_remote_server.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+etch_status_t helloworld_helper_remote_server_create(helloworld_remote_server** remote_server, wchar_t* uri, void* factory_thisx, main_client_create_func client_create);
+etch_status_t helloworld_helper_remote_server_start_wait(helloworld_remote_server* remote_server, const int waitms);
+etch_status_t helloworld_helper_remote_server_stop_wait(helloworld_remote_server* remote_server, const int waitms);
+etch_status_t helloworld_helper_remote_server_destroy(helloworld_remote_server* remote_server);
+
+etch_status_t helloworld_helper_listener_create(i_sessionlistener** listener, wchar_t* uri, void* factory_thisx, main_server_create_func);
+etch_status_t helloworld_helper_listener_start_wait(i_sessionlistener* listener, const int waitms);
+etch_status_t helloworld_helper_listener_stop_wait(i_sessionlistener* listener, const int waitms);
+etch_status_t helloworld_helper_listener_destroy(i_sessionlistener* listener);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* HELLOWORLD_HELPER_H */
+
diff --git a/examples/helloworld/c/helloworld_interface.c b/examples/helloworld/c/helloworld_interface.c
new file mode 100644
index 0000000..a00bb8a
--- /dev/null
+++ b/examples/helloworld/c/helloworld_interface.c
@@ -0,0 +1,220 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#include "helloworld_interface.h"
+#include "etch_url.h"  
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_cache.h"
+
+
+
+unsigned short CLASSID_HELLOWORLD_SERVICE_INTERFACE;
+unsigned short CLASSID_HELLOWORLD_USER;
+unsigned short CLASSID_HELLOWORLD_USERUNKNOWNEXCEPTION;
+	
+	
+etch_string* helloworld_def_say_hello(void* thisx, helloworld_user* to_whom);
+
+int destroy_helloworld_service_interface (void*);
+
+
+/*
+ * destructors
+ */
+/**
+ * destroy_helloworld_user()
+ * user object destructor
+ */
+int destroy_helloworld_user(void* data)
+{
+    helloworld_user* this = (helloworld_user*)data;
+    if(!((etch_object*)this)->is_static && this->name)
+        etch_object_destroy(this->name); 
+    destroy_object(this);
+    return 0;
+}
+/**
+ * destroy_helloworld_UserUnknownException()
+ * userunknownexception object destructor
+ */
+int destroy_helloworld_UserUnknownException(void* data)
+{
+    helloworld_UserUnknownException* this = (helloworld_UserUnknownException*)data;
+	if(!((etch_object*)this)->is_static)
+    	etch_object_destroy(this->message);
+    if(!((etch_object*)this)->is_static && this->mes)
+        etch_object_destroy(this->mes); 
+    destroy_object(this);
+    return 0;
+}
+
+/* - - - - - - - - - - - - - -  
+ * constructors
+ * - - - - - - - - - - - - - -  
+ */
+
+/**
+ * new_helloworld_user()
+ * user object constructor.
+ */
+helloworld_user* new_helloworld_user() 
+{
+    helloworld_user* user = (helloworld_user*) new_object(sizeof(helloworld_user), 
+        ETCHTYPEB_USER, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USER));
+		
+	((etch_object*)user)->destroy = destroy_helloworld_user;
+
+    return user;
+}
+
+
+
+
+
+/**
+ * clone_helloworld_user()
+ * user object copy constructor.
+ */
+helloworld_user* clone_helloworld_user(helloworld_user* other) 
+{
+    helloworld_user* user = (helloworld_user*) new_object(sizeof(helloworld_user), 
+        ETCHTYPEB_USER, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USER));
+		
+    user->id = other->id; 
+    user->name = other->name; 
+
+	((etch_object*)user)->destroy = destroy_helloworld_user;
+
+    return user;
+}
+
+
+/**
+ * is_helloworld_user()
+ */
+int is_helloworld_user(void* x) 
+{
+    return x && ((etch_object*)x)->class_id == CLASSID_HELLOWORLD_USER;
+}
+
+/**
+ * new_helloworld_UserUnknownException()
+ * userunknownexception object constructor.
+ */
+helloworld_UserUnknownException* new_helloworld_UserUnknownException() 
+{
+
+	helloworld_UserUnknownException* userunknownexception  = (helloworld_UserUnknownException*) new_object(sizeof(helloworld_UserUnknownException), 
+        ETCHTYPEB_EXCEPTION, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USERUNKNOWNEXCEPTION));
+    
+    userunknownexception->message = new_stringw(L"user generated exception, no default exception message.");
+    userunknownexception->errorcode = ETCH_ERROR;
+    userunknownexception->excptype = EXCPTYPE_USERDEFINED;
+        
+		
+	((etch_object*)userunknownexception)->destroy = destroy_helloworld_UserUnknownException;
+
+    return userunknownexception;
+}
+
+
+
+
+
+/**
+ * clone_helloworld_UserUnknownException()
+ * userunknownexception object copy constructor.
+ */
+helloworld_UserUnknownException* clone_helloworld_UserUnknownException(helloworld_UserUnknownException* other) 
+{
+	helloworld_UserUnknownException* userunknownexception = (helloworld_UserUnknownException*) new_object(sizeof(helloworld_UserUnknownException), 
+        ETCHTYPEB_EXCEPTION, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USERUNKNOWNEXCEPTION));
+		
+    userunknownexception->mes = other->mes; 
+
+	((etch_object*)userunknownexception)->destroy = destroy_helloworld_UserUnknownException;
+
+    return userunknownexception;
+}
+
+
+/**
+ * is_helloworld_UserUnknownException()
+ */
+int is_helloworld_UserUnknownException(void* x) 
+{
+    return x && ((etch_object*)x)->class_id == CLASSID_HELLOWORLD_USERUNKNOWNEXCEPTION;
+}
+
+
+/**
+ * new_helloworld_service_interface
+ */
+i_helloworld* new_helloworld_service_interface ()
+{
+    i_helloworld* isvc = (i_helloworld*) new_object (sizeof(i_helloworld), ETCHTYPEB_SVCINTERFACE, 
+        get_dynamic_classid_unique(&CLASSID_HELLOWORLD_SERVICE_INTERFACE));
+
+    ((etch_object*)isvc)->destroy = destroy_helloworld_service_interface;
+
+    isvc->say_hello = helloworld_def_say_hello;
+
+    isvc->user = new_helloworld_user();
+
+    return isvc;
+}
+
+/**
+ * destroy_helloworld_service_interface()
+ * i_helloworld destructor.
+ */
+int destroy_helloworld_service_interface (void* data)
+{
+    i_helloworld* isvc = (i_helloworld*)data;
+    if (NULL == isvc) return -1;  
+
+    if (!is_etchobj_static_content(isvc))
+    {    
+        etch_object_destroy(isvc->user);
+    }
+    
+    return destroy_objectex((etch_object*)isvc);
+}
+
+
+/* - - - - - - - - - - - - - -  
+ * service method stubs
+ * - - - - - - - - - - - - - -  
+ */
+
+etch_string* helloworld_def_say_hello(void* thisx, helloworld_user* to_whom)
+{
+    etch_free(to_whom);
+    return NULL;
+}
+
diff --git a/examples/helloworld/c/helloworld_interface.h b/examples/helloworld/c/helloworld_interface.h
new file mode 100644
index 0000000..d4eb54c
--- /dev/null
+++ b/examples/helloworld/c/helloworld_interface.h
@@ -0,0 +1,125 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#ifndef HELLOWORLD_H
+#define HELLOWORLD_H
+
+#include "etch_object.h"
+#include "etch_mailbox.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_HELLOWORLD_SERVICE_INTERFACE;
+extern unsigned short CLASSID_HELLOWORLD_USER;
+extern unsigned short CLASSID_HELLOWORLD_USERUNKNOWNEXCEPTION;
+
+//typedef struct helloworld_user helloworld_user;
+
+
+
+
+
+/**
+ * helloworld_user 
+ * helloworld service value object user 
+ */
+typedef struct helloworld_user
+{
+    etch_object object;
+
+
+    int id;
+    etch_string* name;
+ 
+ } helloworld_user;
+
+helloworld_user* new_helloworld_user();
+helloworld_user* clone_helloworld_user(helloworld_user* other); 
+int is_helloworld_user(void* obj); 
+
+/**
+ * helloworld_UserUnknownException 
+ * helloworld service value object userunknownexception 
+ */
+typedef struct helloworld_UserUnknownException
+{
+    etch_object object;
+
+    etch_string*    message;
+    uint32          errorcode;
+    excptype_t      excptype;
+
+    etch_string* mes;
+ 
+ } helloworld_UserUnknownException;
+
+helloworld_UserUnknownException* new_helloworld_UserUnknownException();
+helloworld_UserUnknownException* clone_helloworld_UserUnknownException(helloworld_UserUnknownException* other); 
+int is_helloworld_UserUnknownException(void* obj); 
+
+
+
+typedef etch_string* (*helloworld_say_hello)(void* thisx, helloworld_user* to_whom);
+
+//typedef struct i_mailbox i_mailbox;
+
+typedef i_mailbox* (*helloworld_async_begin_say_hello)(void* thisx, helloworld_user* to_whom);
+
+typedef etch_string* (*helloworld_async_end_say_hello)(void* thisx, i_mailbox*);
+
+/**
+ * i_helloworld
+ * helloworld service interface
+ */
+typedef struct i_helloworld
+{
+    etch_object object;
+
+    /* - - - - - - - - - - -
+     * service virtuals
+     * - - - - - - - - - - -
+     */
+    helloworld_say_hello say_hello;
+     
+    /* - - - - - - - - - - -
+     * service data
+     * - - - - - - - - - - -
+     */
+    helloworld_user* user;
+    helloworld_UserUnknownException* UserUnknownException;
+
+} i_helloworld;
+
+i_helloworld* new_helloworld_service_interface();
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* HELLOWORLD_H */
diff --git a/examples/helloworld/c/helloworld_keywords_wireshark.txt b/examples/helloworld/c/helloworld_keywords_wireshark.txt
new file mode 100644
index 0000000..92992e5
--- /dev/null
+++ b/examples/helloworld/c/helloworld_keywords_wireshark.txt
@@ -0,0 +1,24 @@
+
+0x0cab1655,etch.cbinding.test.helloworld.say_hello
+0xc44339d2,etch.cbinding.test.helloworld._result_say_hello
+0xa37cfad4,etch.cbinding.test.helloworld.user
+0xbeae3199,etch.cbinding.test.helloworld.UserUnknownException
+0x5a24fcc0,id
+0xe5879d30,name
+0x2dd371f6,mes
+0x54a712ce,to_whom
+0xef092188,_Etch_RuntimeException
+0x97e30f76,_Etch_AuthException
+0xa53d2e35,_exception
+0x3084deef,_Etch_List
+0x7feae04b,_Etch_Map
+0x82e33e51,_Etch_Set
+0x2b396bcc,_Etch_Datetime
+0x2de1755c,msg
+0x6306b468,_messageId
+0xeda8c9a6,_inReplyTo
+0x8104fdc2,result
+0x5bf76bf9,keys
+0x844e4fc7,values
+0x66001a40,dateTime
+0xee9ff760,keysAndValues
diff --git a/examples/helloworld/c/helloworld_listener_main.c b/examples/helloworld/c/helloworld_listener_main.c
new file mode 100644
index 0000000..5780d37
--- /dev/null
+++ b/examples/helloworld/c/helloworld_listener_main.c
@@ -0,0 +1,130 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+/*
+ * helloworld_listener_main.c
+ */
+ 
+#include "helloworld_listener_main.h"
+#include "etch_objecttypes.h"
+#include "etch_runtime.h"
+#include "etch_arrayval.h"
+#include "etch_nativearray.h"
+#include "etch_binary_tdo.h"
+#include "etch_general.h"
+
+
+/**
+ * new_helloworld_server
+ * create an individual client's helloworld_server implementation.
+ * this is java binding's newhelloworldServer().
+ * this is called back from helper.new_helper_accepted_server() (java's newServer).
+ * @param p parameter bundle. caller retains. 
+ * @return the i_helloworld_server, whose thisx is the helloworld_server_impl.
+ */
+static i_helloworld_server* helloworld_server_create(etch_server_factory* p, etch_session* session)
+{
+    helloworld_remote_client* client  = (helloworld_remote_client*) session->client;
+
+    helloworld_server_impl* newserver = new_helloworld_server_impl(client);
+
+    return newserver->helloworld_server_base;
+}
+
+etch_status_t helloworld_listener_start(i_sessionlistener** pplistener, wchar_t* uri, int waitupms)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    
+    etch_status = helloworld_helper_listener_create(pplistener, uri, NULL, helloworld_server_create);
+    if(etch_status == ETCH_SUCCESS) 
+    {
+        etch_status = helloworld_helper_listener_start_wait(*pplistener, waitupms);
+    }
+
+    return etch_status;
+}
+
+etch_status_t helloworld_listener_stop(i_sessionlistener* plistener, int waitupms)
+{
+    etch_status_t etch_status = ETCH_SUCCESS;
+    
+    etch_status = helloworld_helper_listener_stop_wait(plistener, waitupms);
+    if(etch_status == ETCH_SUCCESS) 
+    {
+        helloworld_helper_listener_destroy(plistener);
+    }
+
+    return etch_status;
+}
+
+
+#ifndef NO_ETCH_SERVER_MAIN
+
+/**
+ * main()
+ */
+int main(int argc, char* argv[])
+{
+	etch_status_t etch_status = ETCH_SUCCESS;
+    i_sessionlistener* listener = NULL;
+    int result = -1, is_waitkey = TRUE, waitupms = 4000;
+    
+    wchar_t* uri = L"tcp://0.0.0.0:4001";
+
+    etch_config_t* config = NULL;
+    etch_config_create(&config);
+	
+    etch_status = etch_runtime_initialize(config);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+        return 1;
+    }
+
+    etch_status = helloworld_listener_start(&listener, uri, waitupms);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+
+    // wait for keypress
+    waitkey();
+
+    etch_status = helloworld_listener_stop(listener, waitupms);
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+    }
+
+    etch_status = etch_runtime_shutdown();
+    if(etch_status != ETCH_SUCCESS) {
+        // error
+        return 1;
+    }
+	etch_config_destroy(config);
+    // wait for keypress
+    waitkey();
+	
+    return 0;
+}
+
+#endif /* NO_ETCH_SERVER_MAIN */
diff --git a/examples/helloworld/c/helloworld_listener_main.h b/examples/helloworld/c/helloworld_listener_main.h
new file mode 100644
index 0000000..3cda593
--- /dev/null
+++ b/examples/helloworld/c/helloworld_listener_main.h
@@ -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.
+ *
+ */
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+/*
+ * helloworld_listener_main.h
+ * server exe main() private header
+ */
+
+#ifndef HELLOWORLD_LISTENER_MAIN_H
+#define HELLOWORLD_LISTENER_MAIN_H
+
+#include "etch_runtime.h"
+#include "helloworld_helper.h"
+#include "helloworld_server_impl.h"
+#include "helloworld_remote_client.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * helloworld_listener_start(pplistener, uri, waitupms)
+ * Start the listener at the given uri, waiting waitupms microseconds for listener startup.
+ * The created listener is saved at address pointed to by pplistener.
+ */
+extern etch_status_t helloworld_listener_start(i_sessionlistener** pplistener, wchar_t* uri, int waitupms);
+
+/*
+ * helloworld_listener_stop(plistener, waitupms)
+ * Stop the listener given by plistener, waiting waitupms microseconds to stop.
+ */
+extern etch_status_t helloworld_listener_stop(i_sessionlistener* plistener, int waitupms);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* HELLOWORLD_LISTENER_MAIN.H */
diff --git a/examples/helloworld/c/helloworld_remote.c b/examples/helloworld/c/helloworld_remote.c
new file mode 100644
index 0000000..2dabb6d
--- /dev/null
+++ b/examples/helloworld/c/helloworld_remote.c
@@ -0,0 +1,269 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#include "helloworld_remote.h"
+#include "etch_url.h"  
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+
+unsigned short CLASSID_HELLOWORLD_REMOTE;
+
+int destroy_helloworld_remote (void*);
+#if(0)
+etch_message* etchremote_new_message(helloworld_remote*, etch_type*);
+int etchremote_send(helloworld_remote*, etch_message*);
+int etchremote_begincall(helloworld_remote*, etch_message*, void**);
+int etchremote_endcall  (helloworld_remote*, i_mailbox*, etch_type*, void**);
+int etchremote_transport_control (helloworld_remote*, etch_event*, etch_int32*);
+int etchremote_transport_notify  (helloworld_remote*, etch_event*);
+etch_object* etchremote_transport_query (helloworld_remote*, etch_object*); 
+int etchremote_start_waitup  (helloworld_remote*, const int);
+int etchremote_stop_waitdown (helloworld_remote*, const int);
+#endif
+
+
+/* - - - - - - - - - - - - - -  
+ * constructors
+ * - - - - - - - - - - - - - -  
+ */
+
+/**
+ * new_helloworld_remote
+ * @param ids delivery service -- caller retains
+ * @param vf helloworld value factory - caller retains 
+ * @param ihelloworld optional helloworld service interface -- caller retains
+ */
+helloworld_remote* new_helloworld_remote (void* thisx, 
+    i_delivery_service* ids, etch_value_factory* vf, i_helloworld* iservice)
+{
+    helloworld_remote* remote = (helloworld_remote*) new_object (sizeof(helloworld_remote), 
+        ETCHTYPEB_REMOTE, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_REMOTE));
+
+    ((etch_object*)remote)->destroy = destroy_helloworld_remote;
+
+    /* helloworld_remote instance data and methods */
+    remote->dsvc = ids; 
+    remote->vf   = vf;
+    remote->start_waitup  = etchremote_start_waitup;
+    remote->stop_waitdown = etchremote_stop_waitdown;
+
+    /* transport methods */
+    remote->transport_control = etchremote_transport_control;
+    remote->transport_notify  = etchremote_transport_notify;
+    remote->transport_query   = etchremote_transport_query;
+
+    /* remote base */
+    remote->new_message = etchremote_new_message;
+    remote->send        = etchremote_send;
+    remote->sendex      = etchremote_sendex;
+    remote->begin_call  = etchremote_begincall;
+    remote->end_call    = etchremote_endcall;
+
+    /* helloworld service */
+    if (iservice)
+        remote->ihelloworld = iservice;
+    else
+    {   remote->ihelloworld = new_helloworld_service_interface();
+        remote->is_service_interface_owned = TRUE;
+    }
+    remote->say_hello = remote->ihelloworld->say_hello;
+
+    remote->user = remote->ihelloworld->user;
+
+    return remote;
+}
+
+
+/**
+ * destroy_helloworld_remote()
+ * helloworld_remote destructor.
+ */
+int destroy_helloworld_remote (void* data)
+{
+    helloworld_remote* thisx = (helloworld_remote*)data;
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx))
+    {
+        if (thisx->is_service_interface_owned && thisx->ihelloworld)
+            etch_object_destroy(thisx->ihelloworld);
+    }
+
+    return destroy_objectex((etch_object*)thisx);
+}
+
+
+/* - - - - - - - - - - - - - -  
+ * remote methods
+ * - - - - - - - - - - - - - -  
+ */
+
+/**
+ * etchremote_new_message()
+ * instantiates a message to be sent via this.send() or this.begin_call().
+ * @param thisx this remote object.
+ * @param message_type type of message, caller retains.
+ * @return message object, which could wrap an exception.
+ */
+#if(0)
+etch_message* etchremote_new_message ($helper.getRemoteName($intf, $mc)* thisx, etch_type* message_type)
+{
+    etch_message* msg = new_message(message_type, ETCH_DEFSIZE, thisx->vf);
+    return msg;
+}
+#endif
+
+
+/**
+ * etchremote_send()
+ * sends message to recipient without waiting for a response.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_send ($helper.getRemoteName($intf, $mc)* thisx, etch_message* msg)
+{
+    const int result = thisx->dsvc->itm->transport_message(thisx->dsvc, NULL, msg);
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_begincall()
+ * sends message beginning a call sequence.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return in out parameter, a mailbox which can be used to retrieve the response.
+ * @return 0 success, -1 failure.
+ */
+
+#if(0)
+int etchremote_begincall ($helper.getRemoteName($intf, $mc)* thisx, etch_message* msg, i_mailbox** out)
+{
+    const int result = thisx->dsvc->begin_call(thisx->dsvc, msg, out);
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_endcall()
+ * finishes a call sequence by waiting for a response message.
+ * @param thisx this remote object.
+ * @param mbox a mailbox which will be used to read an expected message response.
+ * @param response_type the message type of the expected response.
+ * @return in out parameter, on success, the response.
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_endcall ($helper.getRemoteName($intf, $mc)* thisx, i_mailbox* mbox, etch_type* response_type, etch_object** out)
+{
+    const int result = thisx->dsvc->end_call(thisx->dsvc, mbox, response_type, out);
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_transport_control()
+ * @param evt caller relinquishes
+ * @param value caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_transport_control ($helper.getRemoteName($intf, $mc)* thisx, etch_event* evt, etch_int32* value)
+{
+    const int result = thisx->dsvc->itm->transport_control(thisx->dsvc, evt, value);
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_transport_notify()
+ * @param evt caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_transport_notify  ($helper.getRemoteName($intf, $mc)* thisx, etch_event* evt)
+{
+    const int result = thisx->dsvc->itm->transport_notify(thisx->dsvc, evt);
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_transport_query()
+ * @param query caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+etch_object* etchremote_transport_query ($helper.getRemoteName($intf, $mc)* thisx, etch_object* query) 
+{
+    etch_object* resultobj = thisx->dsvc->itm->transport_query(thisx->dsvc, query);
+    return resultobj;
+}
+#endif
+
+
+/**
+ * etchremote_start_waitup()
+ * start the transport and wait for it to come up.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_start_waitup ($helper.getRemoteName($intf, $mc)* thisx, const int waitms)
+{
+    const int result = thisx->transport_control(thisx, 
+        new_etch_event(CLASSID_CONTROL_START_WAITUP, waitms), NULL);
+
+    return result;
+}
+#endif
+
+
+/**
+ * etchremote_stop_waitdown()
+ * stop the transport and wait for it to go down.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+#if(0)
+int etchremote_stop_waitdown ($helper.getRemoteName($intf, $mc)* thisx, const int waitms)
+{
+    const int result = thisx->transport_control(thisx, 
+        new_etch_event(CLASSID_CONTROL_STOP_WAITDOWN, waitms), NULL);
+
+    return result;
+}
+#endif
diff --git a/examples/helloworld/c/helloworld_remote.h b/examples/helloworld/c/helloworld_remote.h
new file mode 100644
index 0000000..11dc4c2
--- /dev/null
+++ b/examples/helloworld/c/helloworld_remote.h
@@ -0,0 +1,101 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * $helper.getRemoteFileNameH($intf, $mc)
+ * helloworld remote.
+ * combines java bindings's RemotePerf, Perf, and RemoteBase.
+ */
+
+#ifndef HELLOWORLD_REMOTE_H
+#define HELLOWORLD_REMOTE_H
+
+#include "helloworld_interface.h"
+#include "etch_remote.h"
+#include "etch_transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_HELLOWORLD_REMOTE;
+
+/**
+ * helloworld_remote
+ */
+typedef struct helloworld_remote
+{
+    etch_object object;    
+
+    i_helloworld*  ihelloworld; /* possibly owned */
+    i_delivery_service*  dsvc;  /* not owned */
+    etch_value_factory*  vf;    /* not owned */
+    unsigned char  remote_type; /* client or server */
+    unsigned char  is_service_interface_owned;
+    unsigned short unused;      /* alignment */
+
+    etch_message* (*new_message) (void*, etch_type*);
+    int   (*send)   (void*, etch_message*);
+    void* (*sendex) (void*, etch_message*);
+    etch_delivsvc_begincall begin_call;  /* i_mailbox** out */
+    etch_delvisvc_endcall   end_call;    /* etch_object** out */
+
+    int (*start_waitup)  (void*, const int waitms);
+    int (*stop_waitdown) (void*, const int waitms);
+
+    /* - - - - - - - - - - - - -
+     * transport functionality
+     * - - - - - - - - - - - - -
+     */
+    etch_transport_control transport_control;  
+    etch_transport_notify  transport_notify;   
+    etch_transport_query   transport_query; 
+    etch_transport_get_session get_session;  
+    etch_transport_set_session set_session; 
+
+    /* - - - - - - - - - - -
+     * service virtuals
+     * - - - - - - - - - - -
+     */
+    helloworld_say_hello say_hello;
+
+    helloworld_user* user;
+
+    /* - - - - - - - - - - -
+     * private instance data
+     * - - - - - - - - - - -
+     */    
+
+} helloworld_remote;
+
+
+helloworld_remote* new_helloworld_remote (void*, i_delivery_service*, etch_value_factory*, i_helloworld*);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+#endif /* HELLOWORLD_REMOTE_H */
diff --git a/examples/helloworld/c/helloworld_remote_client.c b/examples/helloworld/c/helloworld_remote_client.c
new file mode 100644
index 0000000..4a78538
--- /dev/null
+++ b/examples/helloworld/c/helloworld_remote_client.c
@@ -0,0 +1,213 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * $helper.getRemoteName($intf, $suffix).c
+ */
+
+#include "helloworld_remote_client.h"
+#include "helloworld_valufact.h"
+#include "etch_url.h"
+#include "etch_log.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+
+static const char* LOG_CATEGORY = "helloworld_remote_client";
+
+unsigned short CLASSID_HELLOWORLD_REMOTE_CLIENT;
+	
+char* HELLOWORLD_ETCHREMC = "REMC";
+
+
+
+/* generated signatures */
+int destroy_helloworld_remote_client (void*);
+
+
+/* - - - - - - - -    
+ * instantiation
+ * - - - - - - - -   
+ */
+
+/**
+ * new_helloworld_remote_client()
+ * helloworld_remote_client constructor.
+ */
+helloworld_remote_client* new_helloworld_remote_client (void* thisx, etch_session* session, etch_value_factory* vf)
+{
+    helloworld_remote* remote = NULL;
+    helloworld_remote_client* rc = NULL;
+
+    rc = (helloworld_remote_client*) new_object (sizeof(helloworld_remote_client), 
+       ETCHTYPEB_REMOTECLIENT, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_REMOTE_CLIENT));
+
+    ((etch_object*)rc)->destroy = destroy_helloworld_remote_client;
+
+    /* we "implement" the service interface here since it may contain client-directed 
+     * items, in which case those methods and data are exposed in this object.  we do  
+     * not expose the service's server-directed methods in the remote client object.
+     */
+    remote = new_helloworld_remote (thisx, session->ds, vf, NULL);
+    remote->remote_type = ETCH_REMOTETYPE_CLIENT;
+
+    rc->remote_base = remote;
+    rc->client_base = new_helloworld_client_base (thisx);
+    rc->session_id = session->session_id;
+
+	rc->vf = (helloworld_valufact*) rc->remote_base->vf;
+	
+    /* override client-directed virtuals with implementations here */
+
+    return rc;
+}
+
+
+/**
+ * destroy_helloworld_remote_client()
+ * helloworld_remote_client destructor.
+ */
+int destroy_helloworld_remote_client (void* thisx)
+{
+    helloworld_remote_client* remote = (helloworld_remote_client*)thisx;
+    if (NULL == remote) return -1;
+
+    if (!is_etchobj_static_content(remote))
+    {
+		etch_object_destroy(remote->remote_base);
+		remote->remote_base = NULL;
+		etch_object_destroy(remote->client_base);
+		remote->client_base = NULL;
+    }
+    return destroy_objectex((etch_object*)remote);
+}
+
+
+
+
+
+/**
+ * perf_remote_dispose_mailbox()
+ * dispose of mailbox after use.
+ * this is the common means of disposing of a mailbox when we're done with it.
+ * this would intuitively be part of base class code but we don't have one.
+ * @param thisx the remote server this.
+ * @param pibox pointer to pointer to the mailbox interface, passed indirectly
+ * such that this method can null out the caller's mailbox reference.
+ * @return 0 if mailbox was successfullly closed, otherwise -1. 
+ * caller's i_mailbox reference is nulled out regardless of result.
+ */
+int helloworld_remote_client_dispose_mailbox (helloworld_remote_client* thisx, i_mailbox** pibox)
+{
+    int result = 0;
+    i_mailbox* ibox = 0;
+    if (!pibox || !*pibox) return -1;
+    ibox = *pibox;
+    *pibox = NULL;  /* null out caller's reference */
+    
+    if (0 != (result = ibox->close_read (ibox)))
+    {  
+        /* we should not need this failsafe unregister if close_read() 
+         * is reliable, since close_read() will do the unregister */
+        i_mailbox_manager* imgr = ibox->manager(ibox);
+        ETCH_LOG(LOG_CATEGORY, ETCH_LOG_ERROR, "could not close mailbox %x\n", ibox);
+        if (imgr) result = imgr->unregister(imgr, ibox);
+    }
+ 
+    /* mailbox manager does not destroy the unregistered mailbox since it is    
+     * owned by whoever registered it, that being us, so we destroy it here. 
+     * debug heap issue note: this is/was the spot.
+     */
+    etch_object_destroy(ibox);   
+    return result;
+}
+
+/**
+ * perf_remote_get_stubbase()
+ * convenience to return stub base object from remote server object.
+ */
+etch_stub* helloworld_remote_client_get_stubbase (helloworld_remote_client* thisx)
+{
+    etch_stub* stub = NULL;
+    xxxx_either_stub* clistub = (xxxx_either_stub*) thisx->client_factory->stub;
+    stub = clistub? clistub->stub_base: NULL;
+    return stub;
+}
+
+
+/**
+ * helloworld_remote_set_session_notify()
+ * convenience to override remote server's session_notify().
+ * @return the session_notify function that was overridden.
+ */
+etch_session_notify helloworld_remote_client_set_session_notify(helloworld_remote_client* thisx, etch_session_notify newfunc)
+{
+    etch_session_notify oldfunc = NULL;
+    etch_stub* stub = helloworld_remote_client_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_notify;
+    stub->impl_callbacks->_session_notify = newfunc;
+    return oldfunc;
+}
+
+
+/**
+ * helloworld_remote_set_session_control()
+ * convenience to override remote server's session_control().
+ * @return the session_control function that was overridden.
+ */
+etch_session_control helloworld_remote_client_set_session_control(helloworld_remote_client* thisx, etch_session_control newfunc)
+{
+    etch_session_control oldfunc = NULL;
+    etch_stub* stub = helloworld_remote_client_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_control;
+    stub->impl_callbacks->_session_control = newfunc;
+    return oldfunc;
+}
+
+
+/**
+ * helloworld_remote_set_session_query()
+ * convenience to override remote server's session_query().
+ * @return the session_query function that was overridden.
+ */
+etch_session_query helloworld_remote_client_set_session_query(helloworld_remote_client* thisx, etch_session_query newfunc)
+{
+    etch_session_query oldfunc = NULL;
+    etch_stub* stub = helloworld_remote_client_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_query;
+    stub->impl_callbacks->_session_query = newfunc;
+    return oldfunc;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -  
+ * remote procedure call implementations
+ * - - - - - - - - - - - - - - - - - - - - 
+ */
+ 
diff --git a/examples/helloworld/c/helloworld_remote_client.h b/examples/helloworld/c/helloworld_remote_client.h
new file mode 100644
index 0000000..5b7d6e5
--- /dev/null
+++ b/examples/helloworld/c/helloworld_remote_client.h
@@ -0,0 +1,81 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * helloworld_remote_client.h 
+ */
+
+#ifndef HELLOWORLD_REMOTE_CLIENT_H
+#define HELLOWORLD_REMOTE_CLIENT_H
+
+#include "helloworld_remote.h"
+#include "helloworld_client.h"
+#include "etch_transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_HELLOWORLD_REMOTE_CLIENT;
+
+/**
+ * helloworld_remote_client
+ */
+typedef struct helloworld_remote_client
+{
+    etch_object object;  
+
+    i_helloworld_client* client_base;     /* owned */
+    helloworld_remote* remote_base;     /* owned */
+    etch_client_factory* client_factory; /* owned */
+    default_value_factory* vf;   /* owned by base */
+    int session_id;
+
+    /* toward-client virtuals go here */
+    
+/*
+    helloworld_user* user;
+*/
+
+
+    /* private, generally. since unit tests invoke async begin and end,
+     * we must expose them either as virtuals or as external references.
+     */
+     
+
+    
+    
+} helloworld_remote_client;
+
+/* constructor */
+helloworld_remote_client* new_helloworld_remote_client (void*, etch_session*, etch_value_factory*);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* HELLOWORLD_REMOTE_CLIENT_H */
diff --git a/examples/helloworld/c/helloworld_remote_server.c b/examples/helloworld/c/helloworld_remote_server.c
new file mode 100644
index 0000000..2ddf094
--- /dev/null
+++ b/examples/helloworld/c/helloworld_remote_server.c
@@ -0,0 +1,309 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * helloworld_remote_server.c
+ * generated remote procedure calls.
+ */
+
+#include "helloworld_remote_server.h"
+#include "etch_plain_mailbox_manager.h"
+#include "etch_svcobj_masks.h"
+#include "etch_objecttypes.h"
+#include "etch_exception.h"
+#include "etch_url.h" 
+#include "etch_log.h" 
+#include "etch_general.h"
+
+unsigned short CLASSID_HELLOWORLD_REMOTE_SERVER;	
+	
+char* HELLOWORLD_ETCHREMS = "REMS";
+
+	
+etch_string* helloworld_remote_server_say_hello (void* thisAsVoid, helloworld_user* to_whom);
+i_mailbox* helloworld_remote_begin_server_say_hello (void* thisAsVoid, helloworld_user* to_whom);
+etch_string* helloworld_remote_end_server_say_hello(void*, i_mailbox*);
+
+
+int destroy_helloworld_remote_server (void*);
+
+/* - - - - - - - - - -   
+ * instantiation etc.
+ * - - - - - - - - - -  
+ */
+
+/**
+ * new_helloworld_remote_server()
+ * helloworld_remote_server constructor.
+ * @param thisx owner, optional, null in practice.
+ * @param ids delivery service interface, caller retains.
+ * @param vf service specific value factory, caller retains.
+ */
+helloworld_remote_server* new_helloworld_remote_server (void* thisx, i_delivery_service* ids, etch_value_factory* vf)
+{
+    helloworld_remote_server* rs = (helloworld_remote_server*) new_object (sizeof(helloworld_remote_server), 
+        ETCHTYPEB_REMOTESERVER, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_REMOTE_SERVER));
+
+    ((etch_object*)rs)->destroy = destroy_helloworld_remote_server;
+
+    rs->remote_base = new_helloworld_remote (thisx, ids, vf, NULL);
+    rs->remote_base->remote_type = ETCH_REMOTETYPE_SERVER;
+
+    /* 2/3/09 now passing perf interface not owned by server_base */
+    rs->server_base = new_helloworld_remote_server_base (thisx, rs->remote_base->ihelloworld);  
+
+    rs->vf = (helloworld_valufact*) rs->remote_base->vf;
+
+    rs->say_hello = helloworld_remote_server_say_hello;
+
+    rs->async_begin_say_hello = helloworld_remote_begin_server_say_hello;
+    rs->async_end_say_hello = helloworld_remote_end_server_say_hello;
+
+    return rs;
+}
+
+/**
+ * destroy_helloworld_server_base()
+ * i_helloworld_server destructor.
+ */
+int destroy_helloworld_remote_server (void* thisAsVoid)
+{
+    helloworld_remote_server* thisx = (helloworld_remote_server*)thisAsVoid;
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx))
+    {
+        etch_object_destroy(thisx->remote_base);
+		thisx->remote_base = NULL;
+		etch_object_destroy(thisx->server_base);
+		thisx->server_base = NULL;
+		etch_object_destroy(thisx->client_factory);
+		thisx->client_factory = NULL;
+    }
+
+    return destroy_objectex((etch_object*)thisx);
+}
+
+
+/**
+ * perf_remote_dispose_mailbox()
+ * dispose of mailbox after use.
+ * this is the common means of disposing of a mailbox when we're done with it.
+ * this would intuitively be part of base class code but we don't have one.
+ * @param thisx the remote server this.
+ * @param pibox pointer to pointer to the mailbox interface, passed indirectly
+ * such that this method can null out the caller's mailbox reference.
+ * @return 0 if mailbox was successfullly closed, otherwise -1. 
+ * caller's i_mailbox reference is nulled out regardless of result.
+ */
+int helloworld_remote_server_dispose_mailbox (helloworld_remote_server* thisx, i_mailbox** pibox)
+{
+    int result = 0;
+    i_mailbox* ibox = 0;
+    if (!pibox || !*pibox) return -1;
+    ibox = *pibox;
+    *pibox = NULL;  /* null out caller's reference */
+    
+    if (0 != (result = ibox->close_read (ibox)))
+    {  
+        /* we should not need this failsafe unregister if close_read() 
+         * is reliable, since close_read() will do the unregister */
+        i_mailbox_manager* imgr = ibox->manager(ibox);
+        ETCH_LOG(HELLOWORLD_ETCHREMS, ETCH_LOG_ERROR, "could not close mailbox %x\n", ibox);
+        if (imgr) result = imgr->unregister(imgr, ibox);
+    }
+ 
+    /* mailbox manager does not destroy the unregistered mailbox since it is    
+     * owned by whoever registered it, that being us, so we destroy it here. 
+     * debug heap issue note: this is/was the spot.
+     */
+    etch_object_destroy(ibox);   
+    return result;
+}
+
+etch_stub* helloworld_remote_server_get_stubbase (helloworld_remote_server* thisx)
+{
+    etch_stub* stub = NULL;
+    xxxx_either_stub* clistub = (xxxx_either_stub*) thisx->client_factory->stub;
+    stub = clistub? clistub->stub_base: NULL;
+    return stub;
+}
+
+
+/**
+ * helloworld_remote_set_session_notify()
+ * convenience to override remote server's session_notify().
+ * @return the session_notify function that was overridden.
+ */
+etch_session_notify helloworld_remote_server_set_session_notify(helloworld_remote_server* thisx, etch_session_notify newfunc)
+{
+    etch_session_notify oldfunc = NULL;
+    etch_stub* stub = helloworld_remote_server_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_notify;
+    stub->impl_callbacks->_session_notify = newfunc;
+    return oldfunc;
+}
+
+
+/**
+ * helloworld_remote_set_session_control()
+ * convenience to override remote server's session_control().
+ * @return the session_control function that was overridden.
+ */
+etch_session_control helloworld_remote_server_set_session_control(helloworld_remote_server* thisx, etch_session_control newfunc)
+{
+    etch_session_control oldfunc = NULL;
+    etch_stub* stub = helloworld_remote_server_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_control;
+    stub->impl_callbacks->_session_control = newfunc;
+    return oldfunc;
+}
+
+
+/**
+ * helloworld_remote_set_session_query()
+ * convenience to override remote server's session_query().
+ * @return the session_query function that was overridden.
+ */
+etch_session_query helloworld_remote_server_set_session_query(helloworld_remote_server* thisx, etch_session_query newfunc)
+{
+    etch_session_query oldfunc = NULL;
+    etch_stub* stub = helloworld_remote_server_get_stubbase(thisx);
+    if (NULL == stub || NULL == stub->impl_callbacks) return NULL;
+    oldfunc = stub->impl_callbacks->_session_query;
+    stub->impl_callbacks->_session_query = newfunc;
+    return oldfunc;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -  
+ * remote procedure call implementations
+ * - - - - - - - - - - - - - - - - - - - - 
+ */
+ 
+	
+/* - - - - - - - - - - -  
+ * helloworld.say_hello()
+ * - - - - - - - - - - -  
+ */
+ 
+/**
+ * helloworld_remote_begin_say_hello()
+ * helloworld.say_hello async start 
+ * TODO: doc generation
+ */
+i_mailbox* helloworld_remote_begin_server_say_hello(void* thisAsVoid, helloworld_user* to_whom)
+{
+    helloworld_remote_server* thisx = (helloworld_remote_server*)thisAsVoid;
+    int _result = 0;
+    i_mailbox* _mbox = NULL;
+    etch_message* _msg = NULL;
+    etch_type* _msgtype = helloworld_valufact_get_static()->_mt_helloworld_say_hello;
+
+    do
+    {   
+        _msg = thisx->remote_base->new_message (thisx->remote_base, _msgtype);
+        if (!_msg) break;
+
+        _result = message_putc (_msg, helloworld_valufact_get_static()->_mf_helloworld_to_whom, (void**)&to_whom);
+		if (to_whom != NULL && 0 != _result) break; 
+
+        /* fyi msg memory is relinquished here regardless of result */ 
+        _result = thisx->remote_base->begin_call(thisx->remote_base, _msg, (void**)&_mbox);
+        _msg = NULL;
+
+    } while(0);
+
+    /* destroy any unrelinquished objects */
+    etch_object_destroy(to_whom);
+	to_whom = NULL;
+    etch_object_destroy(_msg);
+	_msg = NULL;
+	
+    return _mbox;
+}
+
+/**
+ * helloworld_remote_end__say_hello()
+ * _say_hello async end (read result from mailbox and return result)
+ * @param thisx this.
+ * @param mbox caller relinquishes
+ * @return etch_int32* result of add, caller owns.
+ */
+etch_string* helloworld_remote_end_server_say_hello (void* thisAsVoid, i_mailbox* ibox)
+{
+    helloworld_remote_server* thisx = (helloworld_remote_server*)thisAsVoid;
+    etch_string* _resobj = NULL;
+    int _result = -1;
+    etch_type* _restype = helloworld_valufact_get_static()->_mt_helloworld__result_say_hello;
+    
+    if(ibox == NULL) {
+        return NULL;
+    }
+
+    thisx->remote_base->end_call(thisx->remote_base, ibox, _restype, (void**)&_resobj);
+    
+    _result = helloworld_remote_server_dispose_mailbox (thisx, &ibox);
+    if(_result) {
+     	etch_exception* excp = new_etch_exception_from_errorcode(ETCH_ERROR);
+        etch_exception_set_message(excp,new_stringw(L"can not dispose mailbox."));
+        return (etch_string*)excp;
+    }
+    
+    return _resobj;
+}
+
+/**
+ * helloworld_remote_say_hello
+ * helloworld.say_hello remote method call.
+ * instantiates a mailbox, sends perf.add message, waits for result to arrive
+ * in mailbox, disposes mailbox, and returns object containing add() result.
+ * @param thisx this.
+ * @param x etch_int32* caller relinquishes.
+ * @param y etch_int32* caller relinquishes.
+ * @return etch_int32* result of add, caller owns.
+ */
+etch_string* helloworld_remote_server_say_hello(void* thisAsVoid, helloworld_user* to_whom)
+{
+    helloworld_remote_server* thisx = (helloworld_remote_server*)thisAsVoid;
+    etch_string* _resultobj = NULL;
+
+    i_mailbox* _mbox = helloworld_remote_begin_server_say_hello(thisx, to_whom);
+
+	if(_mbox == NULL){
+		etch_exception* excp = new_etch_exception_from_errorcode(ETCH_EIO);
+        etch_exception_set_message(excp,new_stringw(L"can not create mailbox, connection could be down."));
+        return (etch_string*)excp;
+	}
+
+    _resultobj = helloworld_remote_end_server_say_hello (thisx, _mbox);
+
+    return _resultobj;
+}
+
diff --git a/examples/helloworld/c/helloworld_remote_server.h b/examples/helloworld/c/helloworld_remote_server.h
new file mode 100644
index 0000000..6f8ea28
--- /dev/null
+++ b/examples/helloworld/c/helloworld_remote_server.h
@@ -0,0 +1,92 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * helloworld_remote_server.h 
+ * generated remote procedure calls.
+ */
+
+#ifndef HELLOWORLD_REMOTE_SERVER_H
+#define HELLOWORLD_REMOTE_SERVER_H
+
+#include "helloworld_remote.h"
+#include "helloworld_server.h"
+#include "helloworld_valufact.h"
+#include "etch_transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_HELLOWORLD_REMOTE_SERVER;
+
+
+/**
+ * helloworld_remote_server
+ */
+typedef struct helloworld_remote_server
+{
+    etch_object object;
+    
+    i_helloworld_server* server_base;  /* owned */
+    helloworld_remote*   remote_base;  /* owned */
+    etch_client_factory* client_factory; /* owned */
+    helloworld_valufact*  vf;     /* owned by base */
+    int server_id;
+
+    helloworld_say_hello say_hello;
+
+/*
+    helloworld_user* user;
+*/
+
+    /* private, generally. since unit tests invoke async begin and end,
+     * we must expose them either as virtuals or as external references.
+     */
+    helloworld_async_begin_say_hello async_begin_say_hello;
+
+    helloworld_async_end_say_hello async_end_say_hello;
+
+} helloworld_remote_server;
+
+
+/* constructor */
+helloworld_remote_server* new_helloworld_remote_server(void*, i_delivery_service*, etch_value_factory*);
+
+int helloworld_remote_dispose_mailbox(helloworld_remote_server*, i_mailbox**);
+
+/* convenience methods to override client's session interface methods */
+etch_stub* helloworld_remote_get_stubbase (helloworld_remote_server*);
+etch_session_notify helloworld_remote_set_session_notify(helloworld_remote_server*, etch_session_notify);
+etch_session_control helloworld_remote_set_session_control(helloworld_remote_server*, etch_session_control);
+etch_session_query helloworld_remote_set_session_query(helloworld_remote_server*, etch_session_query);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* HELLOWORLD_REMOTE_SERVER_H */
diff --git a/examples/helloworld/c/helloworld_server.c b/examples/helloworld/c/helloworld_server.c
new file mode 100644
index 0000000..10a7ff1
--- /dev/null
+++ b/examples/helloworld/c/helloworld_server.c
@@ -0,0 +1,150 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#include "helloworld_server.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_url.h"  
+
+unsigned short CLASSID_HELLOWORLD_SERVER_BASE;
+	
+	
+int destroy_helloworld_server_via_base(void*);
+
+static int helloworld_server_id_farm;
+
+/* - - - - - - - - - - - - - -  
+ * constructors
+ * - - - - - - - - - - - - - -  
+ */
+/**
+ * new_helloworld_server_base()
+ * @param implobj not interpreted
+ * @param psi a helloworld service interface. if supplied, caller retains,
+ * otherwise a service interface is instantiated and owned here. 
+ */
+i_helloworld_server* new_helloworld_server_base(void* implobj, i_helloworld* psi)
+{
+    i_helloworld_server* ips = (i_helloworld_server*) new_object (sizeof(i_helloworld_server), 
+        ETCHTYPEB_EXESERVERBASE, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_SERVER_BASE));
+
+    /* the server impl is destroyed via this base object. the virtual destructor we assign
+     * here will call the impl object's virtual destructor, which will directly call a 
+     * non-virtual destructor for the base object. 
+     */
+
+    ((etch_object*)ips)->destroy = destroy_helloworld_server_via_base;
+    
+    ips->thisx   = implobj; /* null passed thru from client main */
+    
+    if (psi)
+        ips->ihelloworld = psi;
+    else
+    {   ips->ihelloworld = new_helloworld_service_interface();
+        ips->is_service_interface_owned = TRUE;
+    }
+
+    ips->say_hello = ips->ihelloworld->say_hello;
+
+    ips->user = ips->ihelloworld->user;
+
+    ips->iobjsession = new_default_objsession_interface (ips);
+    ips->_session_control = ips->iobjsession->_session_control; 
+    ips->_session_notify  = ips->iobjsession->_session_notify; 
+    ips->_session_query   = ips->iobjsession->_session_query; 
+
+    ips->server_id = ++helloworld_server_id_farm;
+
+    return ips;
+}
+
+/**
+ * new_helloworld_remote_server_base()  
+ * constructor for server base when host is a remote server.
+ * the server base destructor in this case destroys only itself.   
+ * @param psi a helloworld service interface, if supplied, caller retains.
+ * may be null.
+ */
+i_helloworld_server* new_helloworld_remote_server_base (void* implobj, i_helloworld* psi)
+{
+    i_helloworld_server* ips = new_helloworld_server_base (implobj, psi);
+    ((etch_object*)ips)->destroy = destroy_helloworld_server_base;
+    return ips;
+}
+
+/**
+ * destroy_helloworld_server_base()
+ * i_helloworld_server destructor.
+ */
+int destroy_helloworld_server_base (void* data)
+{
+
+    i_helloworld_server* ips = (i_helloworld_server*)data;
+    if (NULL == ips) return -1;
+
+    if (!is_etchobj_static_content(ips))
+    {    
+        if (ips->is_service_interface_owned){
+            //ETCHOBJ_DESTROY(ips->ihelloworld);
+			if(ips->ihelloworld){
+				etch_object_destroy(ips->ihelloworld);
+			}
+			ips->ihelloworld = NULL;
+			
+		}
+
+        etch_free(ips->iobjsession);
+    }
+            
+    return destroy_objectex((etch_object*)ips);
+}
+
+
+/**
+ * destroy_helloworld_server_via_base()
+ * destructor for helloworld_server_impl via i_helloworld_server.
+ */
+int destroy_helloworld_server_via_base (void* data)
+{
+    i_helloworld_server* ips = (i_helloworld_server*)data;
+    if (NULL == ips) return -1;  
+
+    if (!is_etchobj_static_content(ips))
+    {    
+        /* serverimpl dtor will call base dtor (destroy_helloworld_server_base) */
+        etch_object* serverimpl = (etch_object*) ips->thisx;
+        ETCH_ASSERT(is_etch_serverimpl(serverimpl));
+        //ETCHOBJ_DESTROY(serverimpl);
+		if(serverimpl){
+			etch_object_destroy(serverimpl);
+		}
+		serverimpl = NULL;
+    }
+
+    return 0;
+}
+
diff --git a/examples/helloworld/c/helloworld_server.h b/examples/helloworld/c/helloworld_server.h
new file mode 100644
index 0000000..5114e6a
--- /dev/null
+++ b/examples/helloworld/c/helloworld_server.h
@@ -0,0 +1,104 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * helloworld_server.h
+ * helloworld client interface.
+ * combines java bindings's helloworldServer and BasehelloworldServer
+ */
+
+#ifndef HELLOWORLD_SERVER_H
+#define HELLOWORLD_SERVER_H
+
+#include "helloworld_interface.h"
+#include "etch_sessionint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_HELLOWORLD_SERVER_BASE;
+
+//typedef struct helloworld_server_impl helloworld_server_impl;
+
+/**
+ * i_helloworld_server
+ * helloworld server base interface
+ */
+typedef struct i_helloworld_server
+{
+    etch_object object;
+
+	struct helloworld_server_impl* thisx;
+    i_helloworld*  ihelloworld;
+    
+    
+    int session_id;
+    unsigned char is_service_interface_owned;
+    unsigned char unused[3];
+
+    /* - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - -
+     * service virtuals
+     * - - - - - - - - - - -
+     */
+    helloworld_say_hello say_hello;
+
+    helloworld_say_hello async_say_hello;
+
+    /* - - - - - - - - - - -
+    * service data
+    * - - - - - - - - - - -
+    */
+    helloworld_user* user;
+
+     /* - - - - - - - - - - -
+     * private instance data
+     * - - - - - - - - - - -
+     */
+    int server_id;
+
+} i_helloworld_server;
+
+i_helloworld_server* new_helloworld_server_base (void* implobj, i_helloworld*);
+i_helloworld_server* new_helloworld_remote_server_base (void* implobj, i_helloworld*);
+int destroy_helloworld_server_base (void*);
+
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* HELLOWORLD_SERVER_H */
diff --git a/examples/helloworld/c/helloworld_server_impl.c b/examples/helloworld/c/helloworld_server_impl.c
new file mode 100644
index 0000000..8c5f46c
--- /dev/null
+++ b/examples/helloworld/c/helloworld_server_impl.c
@@ -0,0 +1,95 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#include "helloworld_server_impl.h"
+#include "etch_url.h"
+#include "etch_arrayval.h"
+#include "etch_binary_tdo.h"
+#include "etch_exception.h"
+#include "etch_general.h"
+#include "etch_log.h"
+
+#include <stdio.h>
+
+unsigned short CLASSID_HELLOWORLD_SERVER_IMPL;	
+	
+	
+char* HELLOWORLD_ETCHSIMP = "SIMP";
+
+/* generated signatures */
+int destroy_helloworld_server_implx(helloworld_server_impl*);
+helloworld_server_impl* init_helloworld_server_impl(struct helloworld_remote_client*, etch_object_destructor);
+
+
+/* - - - - - - - -    
+ * instantiation
+ * - - - - - - - -   
+ */
+
+/**
+ * new_helloworld_server_impl()
+ * helloworld_server_impl constructor.
+ * add your custom initialization and virtual method overrides here.
+ */
+helloworld_server_impl* new_helloworld_server_impl(struct helloworld_remote_client* client) 
+{
+    helloworld_server_impl* pserver  /* allocate object and assign default virtuals */
+        = init_helloworld_server_impl(client, destroy_helloworld_server_implx);	
+    i_helloworld_server* pserver_base = pserver->helloworld_server_base;
+    
+    pserver_base->object.class_id = get_dynamic_classid_unique(&CLASSID_HELLOWORLD_SERVER_IMPL);
+    /* add virtual method overrides, if any, here */
+    //pserver->xxx = implementation
+
+    return pserver;
+}
+
+
+/**
+ * destroy_helloworld_server_implx()
+ * destructor for any user allocated memory.
+ * this code is invoked by the private perf_client_impl destructor,
+ * via perf_client.destroyex(). add code here to destroy any memory you  
+ * may have allocated for your custom perf_client implementation.
+ */
+int destroy_helloworld_server_implx(helloworld_server_impl* thisx)
+{
+    /* * *  add custom destruction here  * * */
+    //etch_free(thisx->exampleobj);
+
+    return 0;
+}
+
+/* - - - - - - - - - - - - - - - - - - -
+ * session interface method overrides
+ * - - - - - - - - - - - - - - - - - - -
+ */
+
+ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ * implementations of helloworld_server messages from server, if any 
+ * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ */
+ 
diff --git a/examples/helloworld/c/helloworld_server_impl.h b/examples/helloworld/c/helloworld_server_impl.h
new file mode 100644
index 0000000..52bb064
--- /dev/null
+++ b/examples/helloworld/c/helloworld_server_impl.h
@@ -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.
+ *
+ */
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#ifndef HELLOWORLD_SERVER_IMPL_H
+#define HELLOWORLD_SERVER_IMPL_H
+
+#include "helloworld_server.h"
+#include "etch_transport.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_HELLOWORLD_SERVER_IMPL;
+
+//typedef struct helloworld_remote_client helloworld_remote_client;
+
+/**
+ * helloworld_server_impl
+ * your custom implementation of helloworld_server. add methods here 
+ * to provide implementations of messages from the client, if any.
+ */
+typedef struct helloworld_server_impl
+{
+    etch_object object;  
+
+    i_helloworld_server* helloworld_server_base; /* owned */
+    i_helloworld* ihelloworld; /* not owned */
+    struct helloworld_remote_client* client; /* not owned */
+
+    int (*destroyex) (void*);  /* user memory destructor */
+
+    /* - - - - - - - - - - - -
+     * objsession
+     * - - - - - - - - - - - -
+     */
+    i_objsession* iobjsession;  /* owned by base */
+    /* note that iobjsession->thisx is set to this helloworld_server_impl* */
+    etch_session_control _session_control;
+    etch_session_notify  _session_notify;
+    etch_session_query   _session_query;
+
+    /* - - - - - - - - - - - -
+     * base service virtuals
+     * - - - - - - - - - - - -
+     */
+    helloworld_say_hello say_hello;
+
+    void* context;
+
+
+} helloworld_server_impl;
+
+/* constructor */
+helloworld_server_impl* new_helloworld_server_impl (struct helloworld_remote_client*);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* HELLOWORLD_SERVER_IMPL_H */
diff --git a/examples/helloworld/c/helloworld_server_implx.c b/examples/helloworld/c/helloworld_server_implx.c
new file mode 100644
index 0000000..c6ae57f
--- /dev/null
+++ b/examples/helloworld/c/helloworld_server_implx.c
@@ -0,0 +1,103 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * helloworld_server_implx.c 
+ * $helper.getImplName functions which would ordinarily not be subject to edit.
+ */
+
+#include "helloworld_server_impl.h"
+#include "helloworld_remote_client.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_url.h"
+
+int destroy_helloworld_server_impl(helloworld_server_impl*);
+
+/* - - - - - - - - - - - - - - - - - - - - - - - -   
+ *helloworld_server_impl private construction / destruction 
+ * - - - - - - - - - - - - - - - - - - - - - - - -    
+ */
+
+/**
+ * init_helloworld_server_impl()
+ * called by helloworld_server_impl constructor to instantiate server implementation 
+ * object and initialize with default virtuals.
+ * @param client the remote client, not owned.
+ * @param usermem_dtor destructor for any custom memory allocations.
+ */
+helloworld_server_impl* init_helloworld_server_impl(helloworld_remote_client* client, 
+    etch_object_destructor usermem_dtor)
+{
+    helloworld_server_impl* pserver = (helloworld_server_impl*) new_object (sizeof(helloworld_server_impl), 
+        ETCHTYPEB_EXESERVERIMPL, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_SERVER_IMPL));  
+		
+    pserver->client  = client;  /* not owned */
+    pserver->object.destroy = destroy_helloworld_server_impl;  /* private destructor */
+    pserver->destroyex = usermem_dtor;  /* user memory destructor */
+
+    /* instantiate base and copy virtuals, if any, to this object */
+    pserver->helloworld_server_base = new_helloworld_server_base(pserver, NULL); /* owned */
+
+    pserver->ihelloworld = pserver->helloworld_server_base->ihelloworld;
+
+
+    pserver->say_hello = pserver->helloworld_server_base->say_hello;
+
+
+    pserver->iobjsession = pserver->helloworld_server_base->iobjsession;
+    pserver->iobjsession->thisx = pserver;  /* set implementor reference */
+    pserver->_session_control = pserver->helloworld_server_base->_session_control;
+    pserver->_session_notify  = pserver->helloworld_server_base->_session_notify;
+    pserver->_session_query   = pserver->helloworld_server_base->_session_query;
+
+    return pserver;
+}
+
+/**
+ * destroy_perf_server_impl()
+ * perf_server_impl private destructor.
+ * calls back to user destructor to effect cleanup of any perf_server_impl 
+ * memory which may have been allocated in custom code added by user.
+ */
+int destroy_helloworld_server_impl (helloworld_server_impl* thisx)
+{
+    if (NULL == thisx) return -1;
+
+    if (!is_etchobj_static_content(thisx))
+    {    
+        if(thisx->destroyex)
+        {   /* call back to user memory destructor */
+            thisx->destroyex(thisx);
+        }
+        if(thisx->helloworld_server_base)
+        {
+            destroy_helloworld_server_base(thisx->helloworld_server_base);
+        }
+    }
+            
+    return destroy_objectex(thisx);
+}
diff --git a/examples/helloworld/c/helloworld_server_stub.c b/examples/helloworld/c/helloworld_server_stub.c
new file mode 100644
index 0000000..c69771e
--- /dev/null
+++ b/examples/helloworld/c/helloworld_server_stub.c
@@ -0,0 +1,148 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * helloworld_server_stub.c 
+ */
+
+#include "helloworld_server.h"
+#include "helloworld_server_stub.h"
+#include "helloworld_valufact.h"
+
+#include "etch_url.h"
+#include "etch_objecttypes.h"
+#include "etch_svcobj_masks.h"
+#include "etch_general.h"
+
+#include "etch_exception.h"
+#include "etch_log.h"
+
+unsigned short CLASSID_HELLOWORLD_SERVER_STUB;	
+	
+char* HELLOWORLD_HELLOWORLD_ETCHSTBI = "STBI";
+	
+int destroy_helloworld_server_stub(void*);
+
+
+/* - - - - - - - - - - -
+ * stub helper methods 
+ * - - - - - - - - - - -
+ */
+
+/**
+ * helloworld_stub_run_say_hello
+ */
+int helloworld_stub_run_server_say_hello(etch_stub* stub, i_delivery_service* dsvc, void* obj, etch_who* whofrom, etch_message* msg)
+{
+    i_helloworld_server* server = (i_helloworld_server*)obj;
+	int returnCode = 0;
+    helloworld_valufact_impl* pvfi = NULL;
+    helloworld_valufact* pvf = NULL;
+    struct helloworld_server_impl* impl = NULL;
+
+    /* objects specific to helloworld_server.$name.name()() */
+    etch_field* key_to_whom = NULL;
+    helloworld_user* val_to_whom = NULL;
+    etch_string* resultobj = NULL;
+    etchstub_validate_args (stub, dsvc, msg, server, &pvf, (void**)&pvfi, (void**)&impl);
+
+    key_to_whom = helloworld_valufact_get_static()->_mf_helloworld_to_whom;
+    ETCH_ASSERT(key_to_whom);
+
+    val_to_whom = (helloworld_user*) message_remove(msg, key_to_whom);
+    
+    /* execute the service method */
+    resultobj =  server->say_hello (impl, val_to_whom);
+
+    returnCode = etchstub_send_reply (stub, dsvc, whofrom, msg, (void*) resultobj, resultobj != NULL);
+	if(!returnCode){
+		etch_object_destroy(msg);
+	}
+    return returnCode;
+}
+
+/* - - - - - - - - - 
+ * constructors 
+ * - - - - - - - - - 
+ */
+
+/**
+ * new_helloworld_server_stub()
+ * @param p serv factory parameter bundle, caller retains. 
+ *
+ * this constructor is called on the server via callback from the listener 
+ * socket accept handler <transportfactory>_session_accepted, via the new_server 
+ * function pointer to perf_helper.new_helper_accepted_server().
+ * java binding passes this constructor the delivery service, however we pass the
+ * etch_server_factory parameter bundle, (i_sessionlistener.server_params),
+ * i_sessionlistener being the set session interface of etch_tcp_server. 
+ */
+helloworld_server_stub* new_helloworld_server_stub(etch_server_factory* p, etch_session* session)
+{
+    i_delivery_service* ids = session->ds;
+    etch_threadpool *qp = p->qpool, *fp = p->fpool;
+
+    helloworld_server_stub* mystub = new_serverstub_init (session->server,  
+        sizeof(helloworld_server_stub), destroy_helloworld_server_stub, ids, qp, fp, p);
+
+    ((etch_object*)mystub)->class_id   = get_dynamic_classid_unique(&CLASSID_HELLOWORLD_SERVER_STUB);
+    mystub->session_id = session->session_id;  
+
+    /* initialize service-specific methods and data here. this facility may
+     * likely prove unecessary, as this is generated code, in which case we 
+     * can remove any associated comments from code and headers. */
+    //mystub->my_example_obj = etch_malloc(128, 0); /* example custom alloc */
+
+    /* set stub "helper" methods (run() procedures for each message type) */
+    etchtype_set_type_stubhelper(helloworld_valufact_get_static()->_mt_helloworld_say_hello, helloworld_stub_run_server_say_hello);
+
+    return mystub;
+}
+
+/**
+ * is_helloworld_server_stub()
+ */
+int is_helloworld_server_stub(void* obj)
+{
+    return obj && ((etch_object*)obj)->class_id == CLASSID_HELLOWORLD_SERVER_STUB;
+}
+
+/**
+ * destroy_def_helloworld_server_stub()
+ * helloworld_server_stub user-allocated memory destructor.
+ * called back from private object destructor destroy_stub_object().
+ * if you explicitly allocate memory in the client stub object, destroy it here.
+ */
+int destroy_helloworld_server_stub(void* data)
+{
+   /*
+     helloworld_server_stub* mystub = (helloworld_server_stub*)data;
+      free custom memory allocations here */
+    //etch_free(mystub->my_example_obj); /* free example alloc */
+
+    return 0;
+}
diff --git a/examples/helloworld/c/helloworld_server_stub.h b/examples/helloworld/c/helloworld_server_stub.h
new file mode 100644
index 0000000..6b430b6
--- /dev/null
+++ b/examples/helloworld/c/helloworld_server_stub.h
@@ -0,0 +1,74 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+#ifndef HELLOWORLD_SERVER_STUB_H
+#define HELLOWORLD_SERVER_STUB_H
+
+#include "etch_stub.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern unsigned short CLASSID_HELLOWORLD_SERVER_STUB;
+
+/**
+ * helloworld_server_stub
+ */
+typedef struct helloworld_server_stub
+{
+    etch_object object;
+
+    etch_stub* stub_base;
+    
+    int  session_id;           /* client session to which stub belongs */
+    int (*destroyex) (void*);  /* user memory destructor */
+
+    /* - - - - - - - - - - - - - - - - -
+     * server_directed service virtuals
+     * - - - - - - - - - - - - - - - - -
+     */
+     
+
+    /* - - - - - - - - - - - - - - - - -
+     * service-specific allocations
+     * - - - - - - - - - - - - - - - - -
+     */
+    // add here
+
+} helloworld_server_stub;
+
+helloworld_server_stub* new_helloworld_server_stub (etch_server_factory*, etch_session*);
+int is_helloworld_server_stub(void* obj);
+int destroy_helloworld_server_stub (void*);
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif /* PERF_SERVER_STUB_H */
+
diff --git a/examples/helloworld/c/helloworld_valufact.c b/examples/helloworld/c/helloworld_valufact.c
new file mode 100644
index 0000000..fbad16d
--- /dev/null
+++ b/examples/helloworld/c/helloworld_valufact.c
@@ -0,0 +1,518 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+/*
+ * helloworld_valufact.c 
+ * helloworld service value factory
+ */
+ 
+#include "helloworld_valufact.h"
+#include "helloworld_interface.h"
+#include "etch_serializer.h"
+#include "etch_exception.h"
+#include "etch_objecttypes.h"
+#include "etch_general.h"
+#include "etch_map.h"
+#include "etch_runtime.h"
+
+unsigned short CLASSID_HELLOWORLD_VALUFACT_IMPL;
+
+static helloworld_valufact_statics* _g_helloworld_valufact_statics = NULL;
+
+/* constructors */
+etch_arraylist* helloworld_valufact_get_types(helloworld_valufact*);
+
+void helloworld_valufact_free_statics();
+
+/* initializers */
+static int helloworld_valufact_init_static_fields();
+static int helloworld_valufact_init_static_types();
+static int helloworld_valufact_init_static_parameters();
+static int  helloworld_valufact_init_static_serializers();
+
+/* user serializer */
+etch_serializer* new_helloworld_user_serializer(etch_type*, etch_field*); 
+etch_object* etchserializer_helloworld_user_export_value(etch_serializer*, etch_object*);
+etch_object* etchserializer_helloworld_user_import_value(etch_serializer*, etch_object*);
+/* UserUnknownException serializer */
+etch_serializer* new_helloworld_UserUnknownException_serializer(etch_type*, etch_field*); 
+etch_object* etchserializer_helloworld_UserUnknownException_export_value(etch_serializer*, etch_object*);
+etch_object* etchserializer_helloworld_UserUnknownException_import_value(etch_serializer*, etch_object*);
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * static constructors/destructors
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+
+etch_status_t helloworld_etch_runtime_shutdown_hook_func()
+{
+    if(_g_helloworld_valufact_statics) {
+        helloworld_valufact_free_statics();
+    }
+	return ETCH_SUCCESS;
+}
+ 
+helloworld_valufact_statics* helloworld_valufact_get_static(){
+    if(_g_helloworld_valufact_statics == NULL){
+        _g_helloworld_valufact_statics  = malloc(sizeof(helloworld_valufact_statics));
+        memset(_g_helloworld_valufact_statics ,0 ,sizeof(helloworld_valufact_statics)); 
+
+        _g_helloworld_valufact_statics->_etch_helloworld_valufact_typemap = new_vf_types_collection(ETCH_DEFVF_IDNMAP_DEFINITSIZE);
+        _g_helloworld_valufact_statics->_etch_helloworld_valufact_c2tmap = new_class_to_type_map(ETCH_DEVVF_C2TMAP_DEFINITSIZE);
+
+        defvf_initialize_static(_g_helloworld_valufact_statics->_etch_helloworld_valufact_typemap, _g_helloworld_valufact_statics->_etch_helloworld_valufact_c2tmap);
+        helloworld_valufact_init_static_types();
+        helloworld_valufact_init_static_fields();
+        helloworld_valufact_init_static_parameters();
+        helloworld_valufact_init_static_serializers();
+		etch_runtime_shutdown_hook_add(helloworld_etch_runtime_shutdown_hook_func);
+    }
+
+    return _g_helloworld_valufact_statics;
+}
+
+
+/**
+ * helloworld_valufact_init_types()
+ * instantiate type objects
+ */
+static int helloworld_valufact_init_static_types ()
+{
+    int restype = NULL;
+    struct i_hashtable* vtab = NULL; 
+	helloworld_valufact_statics* p =  helloworld_valufact_get_static();
+
+    /* instantiate type name strings */
+    
+	p->str_helloworld_say_hello = new_wchar(L"etch.cbinding.test.helloworld.say_hello");
+	p->str_helloworld__result_say_hello = new_wchar(L"etch.cbinding.test.helloworld._result_say_hello");
+
+    p->str_helloworld_user = new_wchar(L"etch.cbinding.test.helloworld.user");
+    p->str_helloworld_UserUnknownException = new_wchar(L"etch.cbinding.test.helloworld.UserUnknownException");
+
+    /* instantiate type objects */
+    p->_mt_helloworld_say_hello = new_static_type(p->str_helloworld_say_hello);
+    ETCH_ASSERT(p->_mt_helloworld_say_hello);
+    p->_mt_helloworld__result_say_hello = new_static_type(p->str_helloworld__result_say_hello);
+    ETCH_ASSERT(p->_mt_helloworld__result_say_hello);
+
+    p->_mt_helloworld_user = new_static_type(p->str_helloworld_user);
+    ETCH_ASSERT(p->_mt_helloworld_user);
+    p->_mt_helloworld_UserUnknownException = new_static_type(p->str_helloworld_UserUnknownException);
+    ETCH_ASSERT(p->_mt_helloworld_UserUnknownException);
+	vtab = (struct i_hashtable*)((etch_object*)p->_etch_helloworld_valufact_typemap)->vtab;
+    /* add types to vf */
+   restype =  vtab->inserth(p->_etch_helloworld_valufact_typemap->realtable, p->_mt_helloworld_say_hello, NULL, p->_etch_helloworld_valufact_typemap, 0); 
+   ETCH_ASSERT(! restype);
+   restype =  vtab->inserth(p->_etch_helloworld_valufact_typemap->realtable, p->_mt_helloworld__result_say_hello, NULL, p->_etch_helloworld_valufact_typemap, 0); 
+   ETCH_ASSERT(! restype);
+
+	restype =  vtab->inserth(p->_etch_helloworld_valufact_typemap->realtable, p->_mt_helloworld_user, NULL, p->_etch_helloworld_valufact_typemap, 0); 
+    ETCH_ASSERT(! restype);
+	restype =  vtab->inserth(p->_etch_helloworld_valufact_typemap->realtable, p->_mt_helloworld_UserUnknownException, NULL, p->_etch_helloworld_valufact_typemap, 0); 
+    ETCH_ASSERT(! restype);
+
+    /* set type response fields */
+    etchtype_set_response_field(p->_mt_helloworld__result_say_hello,  builtins._mf_result);
+
+    /* set message result types */
+    etchtype_set_result_type (p->_mt_helloworld_say_hello,  p->_mt_helloworld__result_say_hello);
+
+    /* set timeouts */
+    etchtype_set_timeout (p->_mt_helloworld__result_say_hello,  0);
+
+	/* set async modes */
+    etchtype_set_async_mode(p->_mt_helloworld_say_hello, ETCH_ASYNCMODE_NONE);
+
+	return 0;
+}
+
+
+/**
+ * helloworld_valufact_init_fields()
+ * instantiate field objects
+ */
+static int helloworld_valufact_init_static_fields ()
+{
+    helloworld_valufact_get_static()->str_helloworld_id = new_wchar(L"id");
+    helloworld_valufact_get_static()->str_helloworld_name = new_wchar(L"name");
+    helloworld_valufact_get_static()->str_helloworld_mes = new_wchar(L"mes");
+    helloworld_valufact_get_static()->str_helloworld_to_whom = new_wchar(L"to_whom");
+
+    helloworld_valufact_get_static()->_mf_helloworld_id = new_static_field(helloworld_valufact_get_static()->str_helloworld_id);
+    helloworld_valufact_get_static()->_mf_helloworld_name = new_static_field(helloworld_valufact_get_static()->str_helloworld_name);
+    helloworld_valufact_get_static()->_mf_helloworld_mes = new_static_field(helloworld_valufact_get_static()->str_helloworld_mes);
+    helloworld_valufact_get_static()->_mf_helloworld_to_whom = new_static_field(helloworld_valufact_get_static()->str_helloworld_to_whom);
+	return 0;
+
+}
+
+/**
+ * helloworld_valufact_init_parameters()
+ * initialize service method parameters
+ */
+static int helloworld_valufact_init_static_parameters ()
+{
+	helloworld_valufact_statics* p = helloworld_valufact_get_static();
+	
+	
+//params for built-in List( etch_arraylist )
+//params for built-in Map( etch_hashtable )
+//params for built-in Set( etch_set )
+//params for built-in Datetime( etch_date )
+//params for struct user ([int id, string name])
+	etchtype_put_validator(p->_mt_helloworld_user,
+	                       clone_field(p->_mf_helloworld_id), 
+		                   (etch_object*)etchvtor_int32_get( 0 ));
+	etchtype_put_validator(p->_mt_helloworld_user,
+	                       clone_field(p->_mf_helloworld_name), 
+		                   (etch_object*)etchvtor_string_get( 0 ));
+//params for except UserUnknownException ([string mes])
+	etchtype_put_validator(p->_mt_helloworld_UserUnknownException,
+	                       clone_field(p->_mf_helloworld_mes), 
+		                   (etch_object*)etchvtor_string_get( 0 ));
+//params for message SERVER string say_hello ([user to_whom]) throws [UserUnknownException]
+	etchtype_put_validator(p->_mt_helloworld_say_hello,
+	                       clone_field(p->_mf_helloworld_to_whom), 
+						   (etch_object*)etchvtor_custom_get(ETCHTYPEB_USER, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USER), helloworld_valufact_get_static()->_mt_helloworld_user, 0));
+    etchtype_put_validator(p->_mt_helloworld_say_hello, 
+        clone_field(builtins._mf__message_id), (etch_object*) etchvtor_int64_get(0));
+//params for message CLIENT void _result_say_hello ([string result]) throws []
+	etchtype_put_validator(p->_mt_helloworld__result_say_hello,
+	                       builtins._mf_result, 
+						   (etch_object*)etchvtor_string_get( 0 ));
+    etchtype_put_validator(p->_mt_helloworld__result_say_hello, 
+        clone_field(builtins._mf__message_id), (etch_object*) etchvtor_int64_get(0));
+	etchtype_put_validator(p->_mt_helloworld__result_say_hello, 
+        clone_field(builtins._mf_result), (etch_object*) etchvtor_exception_get(0));
+	etchtype_put_validator(p->_mt_helloworld__result_say_hello, 
+        clone_field(builtins._mf__in_reply_to), (etch_object*) etchvtor_int64_get(0));
+	etchtype_put_validator(p->_mt_helloworld__result_say_hello,
+	                       builtins._mf_result, 
+		                   (etch_object*)etchvtor_custom_get( ETCHTYPEB_USER,get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USERUNKNOWNEXCEPTION), helloworld_valufact_get_static()->_mt_helloworld_UserUnknownException,0));
+	etchtype_put_validator(p->_mt_helloworld__result_say_hello,
+	                       builtins._mf_result, 
+		                   (etch_object*)etchvtor_string_get( 0 ));
+	
+
+//OLD
+//structs	
+	return 0;
+}
+
+/**
+ * helloworld_valufact_init_serializers()
+ */
+static int helloworld_valufact_init_static_serializers ()
+{
+    int  result = 0;
+    helloworld_valufact_statics* p = helloworld_valufact_get_static();
+    class_to_type_map* c2tmap = p->_etch_helloworld_valufact_c2tmap;
+
+    const unsigned short classid_helloworld_user = get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USER);
+    const unsigned short classid_helloworld_UserUnknownException = get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USERUNKNOWNEXCEPTION);
+
+    /* note that etch_serializer_init takes care of the class to type, setting
+     * of component type, instantiation of import export helper and installing
+     * it to the type. 
+     */
+
+    /* serializer for helloworld_user */
+    result = etch_serializer_init (p->_mt_helloworld_user, p->str_helloworld_user, 
+        ETCHMAKECLASS(ETCHTYPEB_USER, classid_helloworld_user), 
+            c2tmap, NULL, new_helloworld_user_serializer);
+
+	  /* serializer for helloworld_UserUnknownException */
+    result = etch_serializer_init (p->_mt_helloworld_UserUnknownException, p->str_helloworld_UserUnknownException, 
+        ETCHMAKECLASS(ETCHTYPEB_EXCEPTION, classid_helloworld_UserUnknownException), 
+            c2tmap, NULL, new_helloworld_UserUnknownException_serializer);
+
+    return result;
+}
+
+
+
+/**
+ * destroy_helloworld_valufact_impl()
+ * destructor for the helloworld value factory extension
+ */
+int destroy_helloworld_valufact_impl(void* data)
+{
+    helloworld_valufact_impl* impl = (helloworld_valufact_impl*)data;
+    if (NULL == impl) return -1;
+
+    if (!is_etchobj_static_content(impl))
+    {
+        // add if neccessary
+    }
+
+   return destroy_objectex((etch_object*) impl);
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * constructors/destructors
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+ 
+helloworld_valufact* new_helloworld_valufact()
+{
+    helloworld_valufact_impl* impl = NULL;
+	default_value_factory* pvf = new_default_value_factory (
+		helloworld_valufact_get_static()->_etch_helloworld_valufact_typemap, 
+		helloworld_valufact_get_static()->_etch_helloworld_valufact_c2tmap);
+    ETCH_ASSERT(pvf);
+
+    /* note that the vf destructor is the default value factory destructor,
+     * which in turn invokes the destructor on its impl object 
+     */
+    impl = (helloworld_valufact_impl*) new_object (sizeof(helloworld_valufact_impl), 
+       ETCHTYPEB_VALUEFACTIMP, get_dynamic_classid_unique(&CLASSID_HELLOWORLD_VALUFACT_IMPL));
+
+    ((etch_object*)impl)->destroy = destroy_helloworld_valufact_impl; 
+    pvf->impl = (etch_object*) impl;	
+    return pvf; 
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * vf class methods
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+ 
+void helloworld_valufact_free_statics ()
+{
+    
+	helloworld_valufact_statics* data = helloworld_valufact_get_static();
+    ETCH_ASSERT(data); 
+
+    destroy_static_type (data->_mt_helloworld_say_hello);
+    destroy_static_type (data->_mt_helloworld__result_say_hello);
+	
+    destroy_static_type (data->_mt_helloworld_user);
+    destroy_static_type (data->_mt_helloworld_UserUnknownException);
+
+    destroy_static_field(data->_mf_helloworld_id);
+    destroy_static_field(data->_mf_helloworld_name);
+    destroy_static_field(data->_mf_helloworld_mes);
+    destroy_static_field(data->_mf_helloworld_to_whom);
+
+    etch_free (data->str_helloworld_id);
+    etch_free (data->str_helloworld_name);
+    etch_free (data->str_helloworld_mes);
+    etch_free (data->str_helloworld_to_whom);
+
+    etch_free (data->str_helloworld_say_hello);
+    etch_free (data->str_helloworld__result_say_hello);
+
+    etch_free (data->str_helloworld_user);
+    etch_free (data->str_helloworld_UserUnknownException);
+
+
+    //set_etchobj_static_content(data->_etch_helloworld_valufact_typemap);
+    //set_etchobj_static_content(data->_etch_helloworld_valufact_c2tmap);
+	
+	data->_etch_helloworld_valufact_typemap->is_readonly_keys = 0;
+    data->_etch_helloworld_valufact_c2tmap->is_readonly_keys = 0;
+    etch_object_destroy(data->_etch_helloworld_valufact_typemap);
+    etch_object_destroy(data->_etch_helloworld_valufact_c2tmap);
+
+	etch_free(data);
+	_g_helloworld_valufact_statics = NULL;
+}
+
+
+/* - - - - - - - - - - - - - - - - - - - -
+ * serializers
+ * - - - - - - - - - - - - - - - - - - - -
+ */
+ 
+/**
+ * etchserializer_helloworld_user_export_value() 
+ * export valueof a helloworld_user
+ * @param objval a helloworld_user, caller owns it and presumably will
+ * destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+etch_object* etchserializer_helloworld_user_export_value(etch_serializer* thisx, etch_object* objval)
+{
+    const int THISINITSIZE = 2;
+    etch_structvalue* expstruct = NULL;
+    const unsigned short classid_helloworld_user = get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USER);
+	if (!is_etch_objparams(objval, ETCHTYPEB_USER, classid_helloworld_user)) return NULL;
+
+    expstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+
+
+    structvalue_put(expstruct, _g_helloworld_valufact_statics->_mf_helloworld_id,
+	   (etch_object*) new_int32(((helloworld_user*)objval)->id));
+	if(((helloworld_user*)objval)->name) {
+		structvalue_put(expstruct, _g_helloworld_valufact_statics->_mf_helloworld_name, 
+			etch_object_clone_func((void*)((helloworld_user*)objval)->name));
+	}
+    return (etch_object*) expstruct; /* caller owns this structvalue */
+}
+
+/**
+ * etchserializer_helloworld_user_import_value() 
+ * import value for a helloworld_user.
+ * @param objval an etch_structvalue of appropriate type for the helloworld_user.
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported helloworld_user. 
+ * caller owns and must destroy the returned object.  
+ */
+etch_object* etchserializer_helloworld_user_import_value (etch_serializer* thisx, etch_object* objval) 
+{
+    helloworld_user* outobj = NULL;
+	
+    etch_int32* valobj_id = NULL;
+    etch_string* valobj_name = NULL;
+
+
+    etch_structvalue* instruct = NULL;
+    if (!is_etch_struct(objval)) return NULL;
+
+    instruct = (etch_structvalue*) objval;
+    if (!structvalue_is_type(instruct, thisx->type)) return NULL;
+
+
+    /* fetch the id value wrapper out of the struct. struct owns it */
+    valobj_id = (etch_int32*) structvalue_get(instruct, _g_helloworld_valufact_statics->_mf_helloworld_id);
+    if (valobj_id && !is_etch_int32(valobj_id)) return NULL;
+    /* fetch the name value wrapper out of the struct. struct owns it */
+    valobj_name = (etch_string*) structvalue_get(instruct, _g_helloworld_valufact_statics->_mf_helloworld_name);
+    if (valobj_name && !is_etch_string(valobj_name)) return NULL;
+
+    outobj = new_helloworld_user();
+	
+	
+    if(valobj_id)
+        outobj->id = valobj_id->value;
+    if(valobj_name)
+        outobj->name = (etch_string*) etch_object_clone_func((void*)valobj_name);
+    return (etch_object*) outobj;  /* caller owns this object */
+}
+
+/**
+ * new_helloworld_user_serializer() 
+ * etch_serializer_excp constructor - conforms to typedef etch_serializer_ctor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_helloworld_user_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    ((etch_object*)newobj)->class_id = get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USER_SERIALIZER);
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_helloworld_user_export_value;
+    newobj->import_value = etchserializer_helloworld_user_import_value;
+
+    return newobj;
+}
+
+/**
+ * etchserializer_helloworld_UserUnknownException_export_value() 
+ * export valueof a helloworld_UserUnknownException
+ * @param objval a helloworld_UserUnknownException, caller owns it and presumably will
+ * destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+etch_object* etchserializer_helloworld_UserUnknownException_export_value(etch_serializer* thisx, etch_object* objval)
+{
+    const int THISINITSIZE = 2;
+    etch_structvalue* expstruct = NULL;
+    const unsigned short classid_helloworld_UserUnknownException = get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USERUNKNOWNEXCEPTION);
+	if (!is_etch_objparams(objval, ETCHTYPEB_EXCEPTION, classid_helloworld_UserUnknownException)) return NULL;
+
+    expstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+
+
+	if(((helloworld_UserUnknownException*)objval)->mes) {
+		structvalue_put(expstruct, _g_helloworld_valufact_statics->_mf_helloworld_mes, 
+			etch_object_clone_func((void*)((helloworld_UserUnknownException*)objval)->mes));
+	}
+    return (etch_object*) expstruct; /* caller owns this structvalue */
+}
+
+/**
+ * etchserializer_helloworld_UserUnknownException_import_value() 
+ * import value for a helloworld_UserUnknownException.
+ * @param objval an etch_structvalue of appropriate type for the helloworld_UserUnknownException.
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported helloworld_UserUnknownException. 
+ * caller owns and must destroy the returned object.  
+ */
+etch_object* etchserializer_helloworld_UserUnknownException_import_value (etch_serializer* thisx, etch_object* objval) 
+{
+    helloworld_UserUnknownException* outobj = NULL;
+	
+    etch_string* valobj_mes = NULL;
+
+
+    etch_structvalue* instruct = NULL;
+    if (!is_etch_struct(objval)) return NULL;
+
+    instruct = (etch_structvalue*) objval;
+    if (!structvalue_is_type(instruct, thisx->type)) return NULL;
+
+
+    /* fetch the mes value wrapper out of the struct. struct owns it */
+    valobj_mes = (etch_string*) structvalue_get(instruct, _g_helloworld_valufact_statics->_mf_helloworld_mes);
+    if (valobj_mes && !is_etch_string(valobj_mes)) return NULL;
+
+    outobj = new_helloworld_UserUnknownException();
+	
+	
+    if(valobj_mes)
+        outobj->mes = (etch_string*) etch_object_clone_func((void*)valobj_mes);
+    return (etch_object*) outobj;  /* caller owns this object */
+}
+
+/**
+ * new_helloworld_UserUnknownException_serializer() 
+ * etch_serializer_excp constructor - conforms to typedef etch_serializer_ctor
+ * @param type  - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_helloworld_UserUnknownException_serializer(etch_type* type, etch_field* field) 
+{
+    etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+    ((etch_object*)newobj)->class_id = get_dynamic_classid_unique(&CLASSID_HELLOWORLD_USERUNKNOWNEXCEPTION_SERIALIZER);
+    newobj->type  = type;  /* not owned */
+    newobj->field = field; /* not owned */
+
+    newobj->export_value = etchserializer_helloworld_UserUnknownException_export_value;
+    newobj->import_value = etchserializer_helloworld_UserUnknownException_import_value;
+
+    return newobj;
+}
+
diff --git a/examples/helloworld/c/helloworld_valufact.h b/examples/helloworld/c/helloworld_valufact.h
new file mode 100644
index 0000000..feb9424
--- /dev/null
+++ b/examples/helloworld/c/helloworld_valufact.h
@@ -0,0 +1,104 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+ 
+/*
+ * helloworld_valufact.h
+ * helloworld implementation of value factory
+ */
+
+#ifndef HELLOWORLD_VALUFACT_H
+#define HELLOWORLD_VALUFACT_H
+
+#include "etch_default_value_factory.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef default_value_factory helloworld_valufact;
+
+extern unsigned short CLASSID_HELLOWORLD_VALUFACT_IMPL;
+
+unsigned short CLASSID_HELLOWORLD_USER_SERIALIZER;
+unsigned short CLASSID_HELLOWORLD_USERUNKNOWNEXCEPTION_SERIALIZER;
+
+
+/**
+ * helloworld_valufact_statics
+ */
+typedef struct helloworld_valufact_statics
+{
+    class_to_type_map*  _etch_helloworld_valufact_c2tmap;
+    vf_idname_map*      _etch_helloworld_valufact_typemap;
+
+    etch_type* _mt_helloworld_say_hello;
+    etch_type* _mt_helloworld__result_say_hello;
+
+    etch_type* _mt_helloworld_user;
+    etch_type* _mt_helloworld_UserUnknownException;
+
+	
+    etch_field* _mf_helloworld_id;
+    etch_field* _mf_helloworld_name;
+    etch_field* _mf_helloworld_mes;
+    etch_field* _mf_helloworld_to_whom;
+
+    struct etch_serializer* serializer_user;
+    struct etch_serializer* serializer_UserUnknownException;
+
+    wchar_t* str_helloworld_id;
+    wchar_t* str_helloworld_name;
+    wchar_t* str_helloworld_mes;
+    wchar_t* str_helloworld_to_whom;
+
+    wchar_t* str_helloworld_say_hello;
+    wchar_t* str_helloworld__result_say_hello;
+    wchar_t* str_helloworld_user;
+    wchar_t* str_helloworld_UserUnknownException;
+
+} helloworld_valufact_statics;
+
+/**
+ * helloworld_valufact_impl
+ * helloworld extension of default value factory
+ */
+typedef struct helloworld_valufact_impl
+{
+    etch_object object;    
+    	
+} helloworld_valufact_impl;
+
+helloworld_valufact* new_helloworld_valufact();
+helloworld_valufact_statics* helloworld_valufact_get_static();
+
+#ifdef __cplusplus
+} //extern "C"
+#endif
+
+#endif 
+
diff --git a/examples/helloworld/c/readme-etch-c-files.txt b/examples/helloworld/c/readme-etch-c-files.txt
new file mode 100644
index 0000000..00ec1ed
--- /dev/null
+++ b/examples/helloworld/c/readme-etch-c-files.txt
@@ -0,0 +1,10 @@
+
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / c 1.1.0-incubating (LOCAL-0)
+//   Fri Aug 28 15:58:20 CEST 2009
+// This file is automatically created and should not be edited!
+
+Generated C Binding files of Apache Etch.
+
+Add your specific implementations to xxx_client_impl.c/xxx_server_impl.c
+Startup is done via xxx_listener_main.c/xxx_client_main.c
diff --git a/examples/helloworld/etch/generate-c-and-java.bat b/examples/helloworld/etch/generate-c-and-java.bat
new file mode 100644
index 0000000..7dabc9b
--- /dev/null
+++ b/examples/helloworld/etch/generate-c-and-java.bat
@@ -0,0 +1,23 @@
+rem
+rem
+rem Licensed to the Apache Software Foundation (ASF) under one
+rem or more contributor license agreements.  See the NOTICE file
+rem distributed with this work for additional information
+rem regarding copyright ownership.  The ASF licenses this file
+rem to you under the Apache License, Version 2.0 (the
+rem "License"); you may not use this file except in compliance
+rem with the License.  You may obtain a copy of the License at
+rem
+rem   http://www.apache.org/licenses/LICENSE-2.0
+rem
+rem Unless required by applicable law or agreed to in writing,
+rem software distributed under the License is distributed on an
+rem "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+rem KIND, either express or implied.  See the License for the
+rem specific language governing permissions and limitations
+rem under the License.
+rem
+rem
+call ..\..\..\target\Installers\dist\bin\etch.bat -b java -w BOTH,IMPL,INTF,MAIN -d ..\java helloworld.etch
+call ..\..\..\target\Installers\dist\bin\etch.bat -b c -w BOTH,IMPL,INTF,MAIN -d ..\c helloworld.etch
+
diff --git a/examples/helloworld/etch/helloworld.etch b/examples/helloworld/etch/helloworld.etch
new file mode 100644
index 0000000..66253e1
--- /dev/null
+++ b/examples/helloworld/etch/helloworld.etch
@@ -0,0 +1,16 @@
+module etch.cbinding.test
+
+service helloworld {
+	struct user (
+		int id,
+		string name
+	)
+
+	exception UserUnknownException (
+		string mes
+	)
+
+	@Direction(Server)
+	string say_hello(user to_whom) throws UserUnknownException
+
+}
\ No newline at end of file
diff --git a/examples/helloworld/java/.classpath b/examples/helloworld/java/.classpath
new file mode 100644
index 0000000..43330c1
--- /dev/null
+++ b/examples/helloworld/java/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<classpath>

+	<classpathentry kind="src" path=""/>

+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>

+	<classpathentry kind="lib" path="apache-etch-java-runtime-1.1.0-incubating.jar"/>

+	<classpathentry kind="output" path=""/>

+</classpath>

diff --git a/examples/helloworld/java/.project b/examples/helloworld/java/.project
new file mode 100644
index 0000000..020a918
--- /dev/null
+++ b/examples/helloworld/java/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<projectDescription>

+	<name>helloworld</name>

+	<comment></comment>

+	<projects>

+	</projects>

+	<buildSpec>

+		<buildCommand>

+			<name>org.eclipse.jdt.core.javabuilder</name>

+			<arguments>

+			</arguments>

+		</buildCommand>

+	</buildSpec>

+	<natures>

+		<nature>org.eclipse.jdt.core.javanature</nature>

+	</natures>

+</projectDescription>

diff --git a/examples/helloworld/java/apache-etch-java-runtime-1.1.0-incubating.jar b/examples/helloworld/java/apache-etch-java-runtime-1.1.0-incubating.jar
new file mode 100644
index 0000000..3c39188
--- /dev/null
+++ b/examples/helloworld/java/apache-etch-java-runtime-1.1.0-incubating.jar
Binary files differ
diff --git a/examples/helloworld/java/etch/cbinding/test/BasehelloworldClient.java b/examples/helloworld/java/etch/cbinding/test/BasehelloworldClient.java
new file mode 100644
index 0000000..ca4d5e1
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/BasehelloworldClient.java
@@ -0,0 +1,57 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+// Re-implement these methods by overriding them in ImplhelloworldClient.
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.etch.bindings.java.support.ObjSession;
+
+
+/**
+ * Base implementation of helloworldClient, with default method implementations
+ * which throw UnsupportedOperationException. Extend this class to provide
+ * implementations of messages from the server.
+ *
+ * @see ImplhelloworldClient
+ */
+public class BasehelloworldClient implements helloworldClient, ObjSession
+{
+	public Object _sessionQuery( Object query ) throws Exception
+	{
+		throw new UnsupportedOperationException( "unknown query: "+query );
+	}
+
+	public void _sessionControl( Object control, Object value ) throws Exception
+	{
+		throw new UnsupportedOperationException( "unknown control: "+control );
+	}
+
+	public void _sessionNotify( Object event ) throws Exception
+	{
+		if (event instanceof Throwable)
+			((Throwable) event).printStackTrace();
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/BasehelloworldServer.java b/examples/helloworld/java/etch/cbinding/test/BasehelloworldServer.java
new file mode 100644
index 0000000..3e4522e
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/BasehelloworldServer.java
@@ -0,0 +1,67 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+// Re-implement these methods by overriding them in ImplhelloworldServer.
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.etch.bindings.java.support.ObjSession;
+
+
+/**
+ * Base implementation of helloworldServer, with default method implementations
+ * which throw UnsupportedOperationException. Extend this class to provide
+ * implementations of messages from the client.
+ *
+ * @see ImplhelloworldServer
+ */
+public class BasehelloworldServer implements helloworldServer, ObjSession
+{
+	public Object _sessionQuery( Object query ) throws Exception
+	{
+		throw new UnsupportedOperationException( "unknown query: "+query );
+	}
+
+	public void _sessionControl( Object control, Object value ) throws Exception
+	{
+		throw new UnsupportedOperationException( "unknown control: "+control );
+	}
+
+	public void _sessionNotify( Object event ) throws Exception
+	{
+		if (event instanceof Throwable)
+			((Throwable) event).printStackTrace();
+	}
+
+	public String say_hello
+	(
+		etch.cbinding.test.helloworld.user to_whom
+	)
+	throws
+		etch.cbinding.test.helloworld.UserUnknownException
+	{
+		throw new UnsupportedOperationException( "say_hello" );
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/ImplhelloworldClient.java b/examples/helloworld/java/etch/cbinding/test/ImplhelloworldClient.java
new file mode 100644
index 0000000..b80533f
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/ImplhelloworldClient.java
@@ -0,0 +1,57 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Feb 05 15:40:43 CET 2010
+// This file is automatically created for your convenience and will not be
+// overwritten once it exists! Please edit this file as necessary to implement
+// your service logic.
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+/**
+ * Your custom implementation of BasehelloworldClient. Add methods here to provide
+ * implementations of messages from the server.
+ */
+public class ImplhelloworldClient extends BasehelloworldClient
+{
+	/**
+	 * Constructs the ImplhelloworldClient.
+	 *
+	 * @param server a connection to the server session. Use this to send a
+	 * message to the server.
+	 */
+	public ImplhelloworldClient( RemotehelloworldServer server )
+	{
+		this.server = server;
+	}
+	
+	/**
+	 * A connection to the server session. Use this to send a
+	 * message to the server.
+	 */
+	@SuppressWarnings( "unused" )
+	private final RemotehelloworldServer server;
+
+	// TODO insert methods here to provide implementations of helloworldClient
+	// messages from the server.
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/ImplhelloworldServer.java b/examples/helloworld/java/etch/cbinding/test/ImplhelloworldServer.java
new file mode 100644
index 0000000..7ac5bfa
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/ImplhelloworldServer.java
@@ -0,0 +1,62 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Feb 05 15:40:43 CET 2010
+// This file is automatically created for your convenience and will not be
+// overwritten once it exists! Please edit this file as necessary to implement
+// your service logic.
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+/**
+ * Your custom implementation of BasehelloworldServer. Add methods here to provide
+ * implementations of messages from the client.
+ */
+public class ImplhelloworldServer extends BasehelloworldServer
+{
+	/**
+	 * Constructs the ImplhelloworldServer.
+	 *
+	 * @param client a connection to the client session. Use this to send a
+	 * message to the client.
+	 */
+	public ImplhelloworldServer( RemotehelloworldClient client )
+	{
+		this.client = client;
+	}
+	
+	/**
+	 * A connection to the client session. Use this to send a
+	 * message to the client.
+	 */
+	@SuppressWarnings( "unused" )
+	private final RemotehelloworldClient client;
+
+	// TODO insert methods here to provide implementations of helloworldServer
+	// messages from the client.
+	
+	@Override
+	public String say_hello(user toWhom) throws UserUnknownException {
+		return "Hello " + toWhom.name + ", nice to meet you!";
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/MainhelloworldClient.java b/examples/helloworld/java/etch/cbinding/test/MainhelloworldClient.java
new file mode 100644
index 0000000..c8eecce
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/MainhelloworldClient.java
@@ -0,0 +1,65 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Feb 05 15:40:43 CET 2010
+// This file is automatically created for your convenience and will not be
+// overwritten once it exists! Please edit this file as necessary to implement
+// your service logic.
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+/**
+ * Main program for helloworldClient. This program makes a connection to the
+ * listener created by MainhelloworldListener.
+ */
+public class MainhelloworldClient implements helloworldHelper.helloworldClientFactory
+{
+	/**
+	 * Main program for helloworldClient.
+	 * 
+	 * @param args command line arguments.
+	 * @throws Exception
+	 */
+	public static void main( String[] args ) throws Exception
+	{
+		// TODO Change to correct URI
+		String uri = "tcp://localhost:4001";
+		
+		RemotehelloworldServer server = helloworldHelper.newServer( uri, null,
+			new MainhelloworldClient() );
+
+		// Connect to the service
+		server._startAndWaitUp( 4000 );
+
+		// TODO Insert Your Code Here
+
+		// Disconnect from the service
+		server._stopAndWaitDown( 4000 );
+	}
+
+	public helloworldClient newhelloworldClient( RemotehelloworldServer server )
+		throws Exception
+	{
+		return new ImplhelloworldClient( server );
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/MainhelloworldListener.java b/examples/helloworld/java/etch/cbinding/test/MainhelloworldListener.java
new file mode 100644
index 0000000..30d1d8c
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/MainhelloworldListener.java
@@ -0,0 +1,63 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Feb 05 15:40:43 CET 2010
+// This file is automatically created for your convenience and will not be
+// overwritten once it exists! Please edit this file as necessary to implement
+// your service logic.
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.etch.bindings.java.support.ServerFactory;
+import org.apache.etch.util.core.io.Transport;
+
+/**
+ * Main program for helloworldServer. This program makes a listener to accept
+ * connections from MainhelloworldClient.
+ */
+public class MainhelloworldListener implements helloworldHelper.helloworldServerFactory
+{
+	/**
+	 * Main program for helloworldServer.
+	 * 
+	 * @param args command line arguments.
+	 * @throws Exception
+	 */
+	public static void main( String[] args ) throws Exception
+	{
+		// TODO Change to correct URI
+		String uri = "tcp://0.0.0.0:4004";
+		
+		ServerFactory listener = helloworldHelper.newListener( uri, null,
+			new MainhelloworldListener() );
+		System.out.println("This is the hello server...");
+		// Start the Listener
+		listener.transportControl( Transport.START_AND_WAIT_UP, 9999999 );
+		
+	}
+
+	public helloworldServer newhelloworldServer( RemotehelloworldClient client )
+	{
+		return new ImplhelloworldServer( client );
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/Remotehelloworld.java b/examples/helloworld/java/etch/cbinding/test/Remotehelloworld.java
new file mode 100644
index 0000000..eb3c1dd
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/Remotehelloworld.java
@@ -0,0 +1,71 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+
+/**
+ * Call to message translator for helloworld.
+ */
+@SuppressWarnings("unused")
+public class Remotehelloworld extends org.apache.etch.bindings.java.support.RemoteBase implements helloworld
+{
+	/**
+	 * Constructs the Remotehelloworld.
+	 *
+	 * @param svc
+	 * @param vf
+	 */
+	public Remotehelloworld( org.apache.etch.bindings.java.support.DeliveryService svc, org.apache.etch.bindings.java.msg.ValueFactory vf )
+	{
+		super( svc, vf );
+	}
+
+	/**
+	 * {@link _Async} class instance used to hide asynchronous message
+	 * implementation. Use this to invoke the asynchronous message
+	 * implementations.
+	 */
+	public final _Async _async = new _Async();
+
+	/**
+	 * {@link _Async} class instance used to hide asynchronous message
+	 * implementation. This is here for backwards compatibility only, use
+	 * {@link #_async} instead.
+	 * @deprecated
+	 */
+	@Deprecated
+	public final _Async _inner = _async;
+
+	/**
+	 * Asynchronous implementation of service methods.
+	 */
+	public class _Async
+	{
+
+		// Mixin Methods
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/RemotehelloworldClient.java b/examples/helloworld/java/etch/cbinding/test/RemotehelloworldClient.java
new file mode 100644
index 0000000..6959eba
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/RemotehelloworldClient.java
@@ -0,0 +1,71 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+
+/**
+ * Call to message translator for helloworldClient.
+ */
+@SuppressWarnings("unused")
+public final class RemotehelloworldClient extends Remotehelloworld implements helloworldClient
+{
+	/**
+	 * Constructs the RemotehelloworldClient.
+	 *
+	 * @param svc
+	 * @param vf
+	 */
+	public RemotehelloworldClient( org.apache.etch.bindings.java.support.DeliveryService svc, org.apache.etch.bindings.java.msg.ValueFactory vf )
+	{
+		super( svc, vf );
+	}
+
+	/**
+	 * {@link _Async} class instance used to hide asynchronous message
+	 * implementation. Use this to invoke the asynchronous message
+	 * implementations.
+	 */
+	public final _Async _async = new _Async();
+
+	/**
+	 * {@link _Async} class instance used to hide asynchronous message
+	 * implementation. This is here for backwards compatibility only, use
+	 * {@link #_async} instead.
+	 * @deprecated
+	 */
+	@Deprecated
+	public final _Async _inner = _async;
+
+	/**
+	 * Asynchronous implementation of service methods.
+	 */
+	public final class _Async extends Remotehelloworld._Async
+	{
+
+		// Mixin Methods
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/RemotehelloworldServer.java b/examples/helloworld/java/etch/cbinding/test/RemotehelloworldServer.java
new file mode 100644
index 0000000..d91a504
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/RemotehelloworldServer.java
@@ -0,0 +1,127 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+
+/**
+ * Call to message translator for helloworldServer.
+ */
+@SuppressWarnings("unused")
+public final class RemotehelloworldServer extends Remotehelloworld implements helloworldServer
+{
+	/**
+	 * Constructs the RemotehelloworldServer.
+	 *
+	 * @param svc
+	 * @param vf
+	 */
+	public RemotehelloworldServer( org.apache.etch.bindings.java.support.DeliveryService svc, org.apache.etch.bindings.java.msg.ValueFactory vf )
+	{
+		super( svc, vf );
+	}
+
+	/**
+	 * {@link _Async} class instance used to hide asynchronous message
+	 * implementation. Use this to invoke the asynchronous message
+	 * implementations.
+	 */
+	public final _Async _async = new _Async();
+
+	/**
+	 * {@link _Async} class instance used to hide asynchronous message
+	 * implementation. This is here for backwards compatibility only, use
+	 * {@link #_async} instead.
+	 * @deprecated
+	 */
+	@Deprecated
+	public final _Async _inner = _async;
+
+	public final String say_hello(
+		etch.cbinding.test.helloworld.user to_whom
+	)
+	throws
+		etch.cbinding.test.helloworld.UserUnknownException
+	{
+		return
+		_async._end_say_hello( _async._begin_say_hello(
+			to_whom
+		) );
+	}
+
+	/**
+	 * Asynchronous implementation of service methods.
+	 */
+	public final class _Async extends Remotehelloworld._Async
+	{
+
+		/**
+		 * Begins a call to say_hello.
+		 *
+		 * @return mailbox used to retrieve the result using _end_say_hello.
+		 * @see RemotehelloworldServer#say_hello
+		 * @see #_end_say_hello
+		 */
+		public final org.apache.etch.bindings.java.support.Mailbox _begin_say_hello(
+			etch.cbinding.test.helloworld.user to_whom
+		)
+		{
+			org.apache.etch.bindings.java.msg.Message _msg = _newMessage( ValueFactoryhelloworld._mt_etch_cbinding_test_helloworld_say_hello );
+			_msg.put( ValueFactoryhelloworld._mf_to_whom, to_whom );
+			return _begincall( _msg );
+		}
+		
+		/**
+		 * Ends a call to say_hello.
+		 *
+		 * @param mb mailbox returned by _begin_say_hello.
+		 *
+		 * @see RemotehelloworldServer#say_hello
+		 * @see #_begin_say_hello
+		 */
+		public final String _end_say_hello( org.apache.etch.bindings.java.support.Mailbox mb )
+			throws
+				etch.cbinding.test.helloworld.UserUnknownException
+		{
+			try
+			{
+				return
+					(String)
+						_endcall( mb,
+							ValueFactoryhelloworld._mt_etch_cbinding_test_helloworld__result_say_hello );
+			}
+			catch ( Exception e )
+			{
+				if (e instanceof etch.cbinding.test.helloworld.UserUnknownException)
+					throw (etch.cbinding.test.helloworld.UserUnknownException) e;
+				if (e instanceof RuntimeException) throw (RuntimeException) e;
+				throw new RuntimeException( "unexpected exception from peer: "+e, e );
+			}
+		}
+
+		// Mixin Methods
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/Stubhelloworld.java b/examples/helloworld/java/etch/cbinding/test/Stubhelloworld.java
new file mode 100644
index 0000000..28c6ac0
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/Stubhelloworld.java
@@ -0,0 +1,72 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.etch.util.core.Who;
+import org.apache.etch.bindings.java.msg.Message;
+import org.apache.etch.bindings.java.support.DeliveryService;
+import org.apache.etch.bindings.java.support.Pool;
+import org.apache.etch.bindings.java.support.StubHelper;
+import org.apache.etch.bindings.java.support._Etch_AuthException;
+import org.apache.etch.bindings.java.support.StubBase;
+import org.apache.etch.bindings.java.support.Pool.PoolRunnable;
+
+/**
+ * Message to call translator for helloworld.
+ * @param <T> helloworld or a subclass thereof.
+ */
+@SuppressWarnings("unused")
+public class Stubhelloworld<T extends helloworld> extends StubBase<T>
+{
+	/**
+	 * Stub for helloworld.
+	 * @param svc the delivery service.
+	 * @param obj the implementation of helloworld responsive to requests.
+	 * @param queued thread pool used to run AsyncMode.QUEUED methods.
+	 * @param free thread pool used to run AsyncMode.FREE methods.
+	 */
+	public Stubhelloworld( DeliveryService svc, T obj, Pool queued, Pool free )
+	{
+		super( svc, obj, queued, free );
+	}
+	
+	static
+	{
+	}
+
+	/**
+	 * Method used to force static initialization.
+	 */
+	public static void init()
+	{
+		// nothing to do.
+	}
+	
+	static
+	{
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/StubhelloworldClient.java b/examples/helloworld/java/etch/cbinding/test/StubhelloworldClient.java
new file mode 100644
index 0000000..99b401f
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/StubhelloworldClient.java
@@ -0,0 +1,70 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.etch.util.core.Who;
+import org.apache.etch.bindings.java.msg.Message;
+import org.apache.etch.bindings.java.support.DeliveryService;
+import org.apache.etch.bindings.java.support.Pool;
+import org.apache.etch.bindings.java.support.StubHelper;
+import org.apache.etch.bindings.java.support._Etch_AuthException;
+import org.apache.etch.bindings.java.support.Pool.PoolRunnable;
+
+/**
+ * Message to call translator for helloworldClient.
+ */
+@SuppressWarnings("unused")
+public class StubhelloworldClient extends Stubhelloworld<helloworldClient>
+{
+	/**
+	 * Stub for helloworldClient.
+	 * @param svc the delivery service.
+	 * @param obj the implementation of helloworldClient responsive to requests.
+	 * @param queued thread pool used to run AsyncMode.QUEUED methods.
+	 * @param free thread pool used to run AsyncMode.FREE methods.
+	 */
+	public StubhelloworldClient( DeliveryService svc, helloworldClient obj, Pool queued, Pool free )
+	{
+		super( svc, obj, queued, free );
+	}
+	
+	static
+	{
+	}
+
+	/**
+	 * Method used to force static initialization.
+	 */
+	public static void init()
+	{
+		// nothing to do.
+	}
+	
+	static
+	{
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/StubhelloworldServer.java b/examples/helloworld/java/etch/cbinding/test/StubhelloworldServer.java
new file mode 100644
index 0000000..f3ee95f
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/StubhelloworldServer.java
@@ -0,0 +1,91 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.etch.util.core.Who;
+import org.apache.etch.bindings.java.msg.Message;
+import org.apache.etch.bindings.java.support.DeliveryService;
+import org.apache.etch.bindings.java.support.Pool;
+import org.apache.etch.bindings.java.support.StubHelper;
+import org.apache.etch.bindings.java.support._Etch_AuthException;
+import org.apache.etch.bindings.java.support.Pool.PoolRunnable;
+
+/**
+ * Message to call translator for helloworldServer.
+ */
+@SuppressWarnings("unused")
+public class StubhelloworldServer extends Stubhelloworld<helloworldServer>
+{
+	/**
+	 * Stub for helloworldServer.
+	 * @param svc the delivery service.
+	 * @param obj the implementation of helloworldServer responsive to requests.
+	 * @param queued thread pool used to run AsyncMode.QUEUED methods.
+	 * @param free thread pool used to run AsyncMode.FREE methods.
+	 */
+	public StubhelloworldServer( DeliveryService svc, helloworldServer obj, Pool queued, Pool free )
+	{
+		super( svc, obj, queued, free );
+	}
+	
+	static
+	{
+	}
+
+	/**
+	 * Method used to force static initialization.
+	 */
+	public static void init()
+	{
+		// nothing to do.
+	}
+	
+	static
+	{
+		ValueFactoryhelloworld._mt_etch_cbinding_test_helloworld_say_hello.setStubHelper( new StubHelper<helloworldServer>()
+		{
+			public final void run( DeliveryService _svc, helloworldServer _obj, Who _sender, Message _msg ) throws Exception
+			{
+				final Message _rmsg = _msg.reply();
+				try
+				{
+					_rmsg.put( ValueFactoryhelloworld._mf_result,
+					_obj.say_hello(
+						(etch.cbinding.test.helloworld.user) _msg.get( ValueFactoryhelloworld._mf_to_whom )
+					)
+					);
+				}
+				catch ( Exception e )
+				{
+					sessionNotify( _obj, e );
+					_rmsg.put( ValueFactoryhelloworld._mf_result, e );
+				}
+				_svc.transportMessage( _sender, _rmsg );
+			}
+		} );
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/ValueFactoryhelloworld.java b/examples/helloworld/java/etch/cbinding/test/ValueFactoryhelloworld.java
new file mode 100644
index 0000000..282fa9c
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/ValueFactoryhelloworld.java
@@ -0,0 +1,203 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.etch.bindings.java.msg.AsyncMode;
+import org.apache.etch.bindings.java.msg.Direction;
+import org.apache.etch.bindings.java.msg.Field;
+import org.apache.etch.bindings.java.msg.ImportExportHelper;
+import org.apache.etch.bindings.java.msg.StructValue;
+import org.apache.etch.bindings.java.msg.Type;
+import org.apache.etch.bindings.java.msg.TypeMap;
+import org.apache.etch.bindings.java.msg.ValueFactory;
+import org.apache.etch.bindings.java.support.Class2TypeMap;
+import org.apache.etch.bindings.java.support.DefaultValueFactory;
+
+
+/**
+ * ValueFactory for helloworld.
+ */
+@SuppressWarnings("unused")
+public final class ValueFactoryhelloworld extends DefaultValueFactory
+{
+	/**
+	 * Constructs ValueFactoryhelloworld.
+	 * @param uri the uri used to configure the session.
+	 */
+	public ValueFactoryhelloworld( String uri )
+	{
+		super( uri, types, class2type );
+	}
+	
+	private final static TypeMap types = new TypeMap();
+	
+	private final static Class2TypeMap class2type = new Class2TypeMap();
+
+	static
+	{
+		DefaultValueFactory.init( types, class2type );
+		initTypes();
+		initResults();
+		initFields();
+		initParams();
+	}
+
+	/** Type for etch.cbinding.test.helloworld.user */
+	public static Type _mt_etch_cbinding_test_helloworld_user;
+
+	/** Type for etch.cbinding.test.helloworld.UserUnknownException */
+	public static Type _mt_etch_cbinding_test_helloworld_UserUnknownException;
+
+	/** Type for etch.cbinding.test.helloworld.say_hello */
+	public static Type _mt_etch_cbinding_test_helloworld_say_hello;
+
+	/** Type for etch.cbinding.test.helloworld._result_say_hello */
+	public static Type _mt_etch_cbinding_test_helloworld__result_say_hello;
+
+	private static void initTypes()
+	{
+		_mt_etch_cbinding_test_helloworld_user = types.get( "etch.cbinding.test.helloworld.user" );
+		_mt_etch_cbinding_test_helloworld_UserUnknownException = types.get( "etch.cbinding.test.helloworld.UserUnknownException" );
+		_mt_etch_cbinding_test_helloworld_say_hello = types.get( "etch.cbinding.test.helloworld.say_hello" );
+		_mt_etch_cbinding_test_helloworld__result_say_hello = types.get( "etch.cbinding.test.helloworld._result_say_hello" );
+	}
+
+	private static void initResults()
+	{
+		_mt_etch_cbinding_test_helloworld_say_hello.setDirection( Direction.SERVER );
+		_mt_etch_cbinding_test_helloworld_say_hello.setAsyncMode( AsyncMode.NONE );
+		_mt_etch_cbinding_test_helloworld_say_hello.setResult( _mt_etch_cbinding_test_helloworld__result_say_hello );
+		_mt_etch_cbinding_test_helloworld__result_say_hello.setTimeout( 0 );
+		_mt_etch_cbinding_test_helloworld__result_say_hello.setDirection( Direction.CLIENT );
+	}
+
+	static
+	{
+		class2type.put( etch.cbinding.test.helloworld.user.class, _mt_etch_cbinding_test_helloworld_user );
+		_mt_etch_cbinding_test_helloworld_user.setComponentType( etch.cbinding.test.helloworld.user.class );
+		_mt_etch_cbinding_test_helloworld_user.setImportExportHelper( new ImportExportHelper()
+		{
+			public final StructValue exportValue( ValueFactory vf, Object value )
+			{
+				StructValue struct = new StructValue( _mt_etch_cbinding_test_helloworld_user, vf );
+				etch.cbinding.test.helloworld.user v = (etch.cbinding.test.helloworld.user) value;
+				struct.put( _mf_id, v.id );
+				struct.put( _mf_name, v.name );
+				return struct;
+			}
+
+			public final Object importValue( StructValue struct )
+			{
+				etch.cbinding.test.helloworld.user v = new etch.cbinding.test.helloworld.user();
+				v.id = (Integer) struct.get( _mf_id );
+				v.name = (String) struct.get( _mf_name );
+				return v;
+			}
+		} );
+	}
+
+	static
+	{
+		class2type.put( etch.cbinding.test.helloworld.UserUnknownException.class, _mt_etch_cbinding_test_helloworld_UserUnknownException );
+		_mt_etch_cbinding_test_helloworld_UserUnknownException.setComponentType( etch.cbinding.test.helloworld.UserUnknownException.class );
+		_mt_etch_cbinding_test_helloworld_UserUnknownException.setImportExportHelper( new ImportExportHelper()
+		{
+			public final StructValue exportValue( ValueFactory vf, Object value )
+			{
+				StructValue struct = new StructValue( _mt_etch_cbinding_test_helloworld_UserUnknownException, vf );
+				etch.cbinding.test.helloworld.UserUnknownException v = (etch.cbinding.test.helloworld.UserUnknownException) value;
+				struct.put( _mf_mes, v.mes );
+				return struct;
+			}
+
+			public final Object importValue( StructValue struct )
+			{
+				etch.cbinding.test.helloworld.UserUnknownException v = new etch.cbinding.test.helloworld.UserUnknownException();
+				v.mes = (String) struct.get( _mf_mes );
+				return v;
+			}
+		} );
+	}
+
+	/** Field for id */
+	public static Field _mf_id;
+
+	/** Field for name */
+	public static Field _mf_name;
+
+	/** Field for mes */
+	public static Field _mf_mes;
+
+	/** Field for to_whom */
+	public static Field _mf_to_whom;
+
+	private static void initFields()
+	{
+		_mf_id = new Field( "id" );
+		_mf_name = new Field( "name" );
+		_mf_mes = new Field( "mes" );
+		_mf_to_whom = new Field( "to_whom" );
+
+		_mt_etch_cbinding_test_helloworld__result_say_hello.setResponseField( _mf_result );
+	}
+	
+	static
+	{
+		// initialize the extern serializers:
+	}
+
+	private static void initParams()
+	{
+
+		// params for user
+		_mt_etch_cbinding_test_helloworld_user.putValidator( _mf_id, org.apache.etch.bindings.java.support.Validator_int.get( 0 ) );
+		_mt_etch_cbinding_test_helloworld_user.putValidator( _mf_name, org.apache.etch.bindings.java.support.Validator_string.get( 0 ) );
+
+		// params for UserUnknownException
+		_mt_etch_cbinding_test_helloworld_UserUnknownException.putValidator( _mf_mes, org.apache.etch.bindings.java.support.Validator_string.get( 0 ) );
+
+		// params for say_hello
+		_mt_etch_cbinding_test_helloworld_say_hello.putValidator( _mf_to_whom, org.apache.etch.bindings.java.support.Validator_custom.get( etch.cbinding.test.helloworld.user.class, 0, true ) );
+		_mt_etch_cbinding_test_helloworld_say_hello.putValidator( _mf__messageId, org.apache.etch.bindings.java.support.Validator_long.get( 0 ) );
+
+		// params for _result_say_hello
+		_mt_etch_cbinding_test_helloworld__result_say_hello.putValidator( _mf_result, org.apache.etch.bindings.java.support.Validator_string.get( 0 ) );
+		_mt_etch_cbinding_test_helloworld__result_say_hello.putValidator( _mf__messageId, org.apache.etch.bindings.java.support.Validator_long.get( 0 ) );
+		_mt_etch_cbinding_test_helloworld__result_say_hello.putValidator( _mf_result, org.apache.etch.bindings.java.support.Validator_custom.get( etch.cbinding.test.helloworld.UserUnknownException.class, 0, true ) ); // thrown UserUnknownException
+		_mt_etch_cbinding_test_helloworld__result_say_hello.putValidator( _mf_result, org.apache.etch.bindings.java.support.Validator_RuntimeException.get() ); // thrown RuntimeException
+		_mt_etch_cbinding_test_helloworld__result_say_hello.putValidator( _mf__inReplyTo, org.apache.etch.bindings.java.support.Validator_long.get( 0 ) );
+	}
+	
+	static
+	{
+		// done updating types, and class2type: lock them.
+		types.lock();
+		for (Type t: types.values())
+			t.lock();
+		class2type.lock();
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/helloworld.java b/examples/helloworld/java/etch/cbinding/test/helloworld.java
new file mode 100644
index 0000000..c4cc057
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/helloworld.java
@@ -0,0 +1,169 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import java.io.Serializable;
+
+
+@SuppressWarnings("unused")
+public interface helloworld
+{
+	@SuppressWarnings("serial")
+	public class user
+		implements Serializable
+	{
+		/**
+		 * Constructs the user. Don't init any fields.
+		 */
+		public user()
+		{
+			// don't init any fields.
+		}
+
+		/**
+		 * Constructs the user.
+		 */
+		public user
+		(
+			Integer id
+			, String name
+		)
+		{
+			this.id = id;
+			this.name = name;
+		}
+
+		@Override
+		public String toString()
+		{
+			return String.format( "user(id=%s; name=%s)", id, name );
+		}
+
+		public Integer id;
+
+		/**
+		 * Gets the value.
+		 *
+		 *
+		 * @return the value.
+		 */
+		public Integer getId()
+		{
+			return id;
+		}
+
+		/**
+		 * Sets the value.
+		 *
+		 *
+		 * @param value the value.
+		 */
+		public void setId( Integer value )
+		{
+			this.id = value;
+		}
+
+		public String name;
+
+		/**
+		 * Gets the value.
+		 *
+		 *
+		 * @return the value.
+		 */
+		public String getName()
+		{
+			return name;
+		}
+
+		/**
+		 * Sets the value.
+		 *
+		 *
+		 * @param value the value.
+		 */
+		public void setName( String value )
+		{
+			this.name = value;
+		}
+	}
+
+	@SuppressWarnings("serial")
+	public class UserUnknownException
+		extends Exception
+	{
+		/**
+		 * Constructs the UserUnknownException. Don't init any fields.
+		 */
+		public UserUnknownException()
+		{
+			// don't init any fields.
+		}
+
+		/**
+		 * Constructs the UserUnknownException.
+		 */
+		public UserUnknownException
+		(
+			String mes
+		)
+		{
+			this.mes = mes;
+		}
+
+		@Override
+		public String getMessage()
+		{
+			return String.format( "mes=%s", mes );
+		}
+
+		public String mes;
+
+		/**
+		 * Gets the value.
+		 *
+		 *
+		 * @return the value.
+		 */
+		public String getMes()
+		{
+			return mes;
+		}
+
+		/**
+		 * Sets the value.
+		 *
+		 *
+		 * @param value the value.
+		 */
+		public void setMes( String value )
+		{
+			this.mes = value;
+		}
+	}
+
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/helloworldClient.java b/examples/helloworld/java/etch/cbinding/test/helloworldClient.java
new file mode 100644
index 0000000..4fc7066
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/helloworldClient.java
@@ -0,0 +1,35 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+
+
+@SuppressWarnings("unused")
+public interface helloworldClient extends helloworld
+{
+	// no CLIENT direction items defined.
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/helloworldHelper.java b/examples/helloworld/java/etch/cbinding/test/helloworldHelper.java
new file mode 100644
index 0000000..7dd8b0a
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/helloworldHelper.java
@@ -0,0 +1,190 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+import org.apache.etch.bindings.java.support.DeliveryService;
+import org.apache.etch.bindings.java.support.Pool;
+import org.apache.etch.bindings.java.support.ServerFactory;
+import org.apache.etch.bindings.java.msg.ValueFactory;
+import org.apache.etch.bindings.java.support.DefaultServerFactory;
+import org.apache.etch.util.core.io.Transport;
+import org.apache.etch.bindings.java.support.TransportFactory;
+import org.apache.etch.bindings.java.support.TransportHelper;
+import org.apache.etch.bindings.java.transport.DefaultDeliveryService;
+import org.apache.etch.bindings.java.transport.MailboxManager;
+import org.apache.etch.bindings.java.transport.PlainMailboxManager;
+import org.apache.etch.bindings.java.transport.TransportMessage;
+import org.apache.etch.util.Resources;
+import org.apache.etch.util.URL;
+
+/**
+ * Transport helper for helloworld. All methods are static.
+ */
+abstract public class helloworldHelper extends TransportHelper
+{
+
+	/**
+	 * Constructs a new server session listener per specifications in uri and
+	 * resources. This listener will accept requests from clients for new server
+	 * sessions.
+	 *
+	 * @param uri contains specifications for the server session listener and
+	 * for the server session transport stack.
+	 *
+	 * @param resources additional resources to aid in constructing new server
+	 * sessions.
+	 *
+	 * @param implFactory factory used to construct a new instance implementing
+	 * helloworldServer. The new instance will receive and process messages from
+	 * the client session.
+	 *
+	 * @return a server session listener.
+	 *
+	 * @throws Exception
+	 */
+	public static ServerFactory newListener( final String uri,
+		final Resources resources, final helloworldServerFactory implFactory )
+		throws Exception
+	{
+		final Resources res = initResources( resources );
+		
+		final Transport<ServerFactory> listener = TransportFactory.getListener( uri, res );
+		
+		return new DefaultServerFactory( listener, implFactory )
+		{
+			public void newServer( TransportMessage t, String uri, Resources r )
+				throws Exception
+			{
+				ValueFactory vf = (ValueFactory) r.get( Transport.VALUE_FACTORY );
+				MailboxManager x = new PlainMailboxManager( t, uri, r );
+				DeliveryService d = new DefaultDeliveryService( x, uri, r );
+				RemotehelloworldClient client = new RemotehelloworldClient( d, vf );
+				helloworldServer server = implFactory.newhelloworldServer( client );
+				Pool qp = (Pool) r.get( QUEUED_POOL );
+				Pool fp = (Pool) r.get( FREE_POOL );
+				new StubhelloworldServer( d, server, qp, fp );
+				client._start();
+			}
+
+			public ValueFactory newValueFactory( String uri )
+			{
+				return new ValueFactoryhelloworld( uri );
+			}
+			
+			@Override
+			public String toString()
+			{
+				return "helloworldHelper.ServerFactory/" + listener;
+			}
+		};
+	}
+
+	/**
+	 * Factory used by
+	 * {@link helloworldHelper#newListener(String, Resources, helloworldServerFactory)}
+	 * to construct a new instance implementing {@link helloworldServer}. The new
+	 * instance will receive and process messages from the client session.
+	 */
+	public interface helloworldServerFactory
+	{
+		/**
+		 * Constructs a new instance implementing helloworldServer. The new
+		 * instance will receive and process messages from the client session.
+		 *
+		 * @param client an instance of RemotehelloworldClient which may be used to
+		 * send messages to the client session.
+		 * @return a new instance implementing helloworldServer (typically
+		 * ImplhelloworldServer).
+		 * @throws Exception
+		 */
+		public helloworldServer newhelloworldServer( RemotehelloworldClient client )
+			throws Exception;
+	}
+
+	/**
+	 * Constructs a new client session per specifications in uri and resources.
+	 * 
+	 * @param uri contains specifications for the client session transport
+	 * stack.
+	 * 
+	 * @param resources additional resources to aid in constructing new client
+	 * sessions.
+	 * 
+	 * @param implFactory factory used to construct a new instance implementing
+	 * helloworldClient. The new instance will receive and process messages from
+	 * the server session.
+	 * 
+	 * @return an instance of RemotehelloworldServer initialized by uri and
+	 * resources which may be used to send messages to the server session.
+	 * 
+	 * @throws Exception
+	 */
+	public static RemotehelloworldServer newServer( String uri,
+		Resources resources, helloworldClientFactory implFactory )
+		throws Exception
+	{
+		final Resources res = initResources( resources );
+		
+		final ValueFactoryhelloworld vf = new ValueFactoryhelloworld( uri );
+		res.put( Transport.VALUE_FACTORY, vf );
+		
+		URL u = new URL( uri );
+		
+		TransportMessage m = TransportFactory.getTransport( uri, res );
+		MailboxManager r = new PlainMailboxManager( m, u, resources );
+		DeliveryService d = new DefaultDeliveryService( r, u, resources );
+		RemotehelloworldServer server = new RemotehelloworldServer( d, vf );
+		helloworldClient client = implFactory.newhelloworldClient( server );
+		Pool qp = (Pool) res.get( QUEUED_POOL );
+		Pool fp = (Pool) res.get( FREE_POOL );
+		new StubhelloworldClient( d, client, qp, fp );
+
+		return server;
+	}
+
+	/**
+	 * Factory used by
+	 * {@link helloworldHelper#newServer(String, Resources, helloworldClientFactory)}
+	 * to construct a new instance implementing {@link helloworldClient}. The new
+	 * instance will receive and process messages from the server session.
+	 */
+	public interface helloworldClientFactory
+	{
+		/**
+		 * Constructs a new instance implementing helloworldClient. The new
+		 * instance will receive and process messages from the server session.
+		 * 
+		 * @param server an instance of RemotehelloworldServer which may be used to
+		 * send messages to the server session.
+		 * @return a new instance implementing helloworldClient (typically
+		 * ImplhelloworldClient).
+		 * @throws Exception
+		 */
+		public helloworldClient newhelloworldClient( RemotehelloworldServer server )
+			throws Exception;
+	}
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/helloworldServer.java b/examples/helloworld/java/etch/cbinding/test/helloworldServer.java
new file mode 100644
index 0000000..31e4a1c
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/helloworldServer.java
@@ -0,0 +1,42 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+package etch.cbinding.test;
+/*
+ *
+ * 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.
+ *
+ */
+
+
+
+
+@SuppressWarnings("unused")
+public interface helloworldServer extends helloworld
+{
+	/**
+	 */
+	public String say_hello(
+		etch.cbinding.test.helloworld.user to_whom
+	)
+	throws
+		etch.cbinding.test.helloworld.UserUnknownException
+	;
+}
diff --git a/examples/helloworld/java/etch/cbinding/test/readme-etch-java-files.txt b/examples/helloworld/java/etch/cbinding/test/readme-etch-java-files.txt
new file mode 100644
index 0000000..2d02223
--- /dev/null
+++ b/examples/helloworld/java/etch/cbinding/test/readme-etch-java-files.txt
@@ -0,0 +1,122 @@
+// This file automatically generated by:
+//   Apache Etch 1.1.0-incubating (LOCAL-0) / java 1.1.0-incubating (LOCAL-0)
+//   Fri Jul 16 12:01:27 CEST 2010
+// This file is automatically created and should not be edited!
+
+This is a description of the etch-generated files for your service.
+
+----------------
+- How To Build -
+----------------
+
+In the directory where the etch file is located, execute the following command:
+
+etch -q -d . -I . -b java -w all Blah.etch
+
+This would compile the service description Blah.etch, generating all java files,
+into java packages rooted in the current directory (-d .), resolving includes
+and mixins from the current directory (-I .) and being quiet about it (-q).
+
+Assuming the Blah.etch specified a module of "demo" and a service of Blah,
+the java files would be generated into a sub-directory demo of the current
+directory. you may now change to that directory and compile the resulting files:
+
+cd demo
+javac -cp %ETCH_HOME%\lib\etch-java-runtime.jar *.java
+
+(Assuming windows; for unix, you only need to change the slash direction and
+change %ETCH_HOME% into \$ETCH_HOME.)
+
+To run the service (which initially won't do anything but make a connection and
+then close it, use the following two commands in separate shells (again, from
+the demo directory):
+
+java -cp %ETCH_HOME%\lib\etch-java-runtime.jar;.. demo.MainBlahListener
+
+java -cp %ETCH_HOME%\lib\etch-java-runtime.jar;.. demo.MainBlahClient
+
+(Again, assuming windows; for unix, make the changes detailed above and also
+change the semi-colon in the -cp spec to a colon.)
+
+The first command (java ... demo.MainBlahListener) starts the service listener
+which accepts connections. The second command runs a sample client, which makes
+a connection to the running listener and then closes it again.
+
+Once you've compiled the service and tested the result, you may implement your
+service by adding content to the etch file, adding implementation details to the
+Impl*.java and Main*.java files, and recompiling using the above steps. You may
+also load these files into an IDE such as eclipse or intellij, or use a build
+management system such as maven or ant. Remember, whenever you change the etch
+file, you must re-etch the service description and then re-javac all the java
+files.
+
+-------------------
+- Generated Files -
+-------------------
+
+Here is a description of the generated files for a service named Blah.
+
+Blah.java
+BlahClient.java
+BlahServer.java
+
+These three files are the generated interface classes. Service defined constants
+and types are in Blah.java, as well as direction "both" messages, which are
+messages which are shared between client and server. BlahClient.java and
+BlahServer.java are respectively the messages for just the direction client or
+server. You should not edit these files.
+
+RemoteBlah.java
+RemoteBlahClient.java
+RemoteBlahServer.java
+
+RemoteBlah*.java are the generated classes which implement the interfaces,
+with message implementations which encode the message type and arguments for
+transport to the connection peer and then receive and decode any response. You
+should not edit these files.
+
+StubBlah.java
+StubBlahClient.java
+StubBlahServer.java
+
+StubBlah*.java are the generated classes which receive messages encoded by
+RemoteBlah*.java and decode them, calling the appropriate message implementation
+and then encoding and sending any result. You should not edit these files.
+
+ValueFactoryBlah.java
+
+ValueFactoryBlah.java is a generated class which contains helper code to
+serialize service defined types and also the meta data which describes the
+messages and fields, field types, timeouts, etc. You should not edit this file.
+
+BaseBlah.java
+BaseBlahClient.java
+BaseBlahServer.java
+
+BaseBlah*.java are generated classes which implement the interfaces, with
+message implementations which do nothing but throw UnsupportedOperationException.
+They can be used to supply an implementation when you don't want to immediately
+implement all the messages. You should not edit these files.
+
+ImplBlahClient.java
+ImplBlahServer.java
+
+ImplBlah*.java are the generated sample client and server implementation
+classes. They extend the generated base classes. These are used by the sample
+main programs to provide implementations of the client or server messages. Edit
+these files as you wish to implement your service (overriding the default
+implementations from the generated base classes).
+
+BlahHelper.java
+
+BlahHelper.java is a generated class which includes static methods to help
+construct transports for client and listener. You should not edit this file.
+
+MainBlahClient.java
+MainBlahListener.java
+
+MainBlah*.java are the generated sample client and server main programs.
+They show how to setup a transport and start it and how to create a session.
+Edit these files as you wish to implement your service, or just copy the code
+into your own application.
+