template of an adaptor
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..9f309ff
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "lib/plexi"]
+	path = lib/plexi
+	url = https://code.google.com/p/plexi/
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..9599317
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,283 @@
+<project name="plexi.database" default="build" basedir=".">
+  <description>Database Adaptor</description>
+  <tstamp/>
+  <property name="src.dir" location="src"/>
+  <property name="test.dir" location="test"/>
+  <property name="test.class" value="*Test"/>
+  <property name="build.dir" location="build"/>
+  <property name="build-src.dir" location="${build.dir}/src"/>
+  <property name="build-test.dir" location="${build.dir}/test"/>
+  <property name="build-instrument.dir" location="${build.dir}/instrument"/>
+  <property name="adaptor.clone.dir" location="lib/plexi"/>
+  <!-- Used for checking if adaptor.jar has been changed. -->
+  <property name="adaptor.jar.default"
+    value="${adaptor.clone.dir}/build/dist/adaptor/adaptor-withlib.jar"/>
+  <property name="adaptor.jar" value="${adaptor.jar.default}"/>
+  <property name="dist.dir" location="dist"/>
+  <property name="javadoc.dir" location="${build.dir}/javadoc"/>
+  <property name="resource.dir" location="resources"/>
+  <property name="lib.dir" location="lib"/>
+  <property name="junit.jar" location="${lib.dir}/junit-4.8.2.jar"/>
+  <property name="adaptor.class"
+    value="com.google.enterprise.adaptor.database.DatabaseAdaptor"/>
+  <property name="adaptor.args" value=""/>
+  <property name="cobertura.dir" value="${basedir}/../cobertura/"/>
+  <!-- Adaptor suffix for distribution files. Useful for placing version numbers
+       on our jars. -->
+  <condition property="adaptor.suffix" value="-${adaptor.version}">
+    <isset property="adaptor.version"/>
+  </condition>
+  <!-- If adaptor.version isn't set, simply use the current date. -->
+  <property name="adaptor.suffix" value="-${DSTAMP}"/>
+
+  <path id="adaptor.build.classpath">
+<!--
+    <fileset dir="${lib.dir}">
+    </fileset>
+-->
+    <pathelement location="${adaptor.jar}"/>
+  </path>
+
+  <path id="adaptor.run.classpath">
+    <path refid="adaptor.build.classpath"/>
+  </path>
+
+  <path id="cobertura.classpath">
+    <fileset dir="${cobertura.dir}" erroronmissingdir="false">
+      <include name="cobertura.jar"/>
+      <include name="lib/**/*.jar"/>
+    </fileset>
+  </path>
+
+  <target name="-check-instrument-uptodate">
+    <uptodate property="instrument.uptodate"
+      targetfile="${build-instrument.dir}/cobertura.ser">
+      <srcfiles dir="${build-src.dir}"/>
+    </uptodate>
+  </target>
+
+  <target name="build"
+    depends="-real-build,-check-instrument-uptodate,clean-instrument"
+    description="Build source"/>
+
+  <target name="-plexi-check-submodule">
+    <condition property="plexi.is-not-submodule">
+      <not>
+        <equals arg1="${adaptor.jar.default}" arg2="${adaptor.jar}"/>
+      </not>
+    </condition>
+    <condition property="tmp.plexi.valid-setup">
+      <or>
+        <isset property="plexi.is-not-submodule"/>
+        <available file="${adaptor.clone.dir}/.git"/>
+      </or>
+    </condition>
+    <fail unless="tmp.plexi.valid-setup">Invalid setup:
+No lib/plexi submodule and using default adaptor.jar property.
+
+You need to run "git submodule init; git submodule update" to initialize the
+lib/plexi submodule or add the the command line argument
+-Dadaptor.jar=path/to/adaptor-withlib.jar to point to the adaptor library.
+    </fail>
+  </target>
+
+  <target name="-plexi-test-uptodate" depends="-plexi-check-submodule">
+    <condition property="plexi.uptodate">
+      <or>
+        <isset property="plexi.is-not-submodule"/>
+        <uptodate targetfile="${adaptor.jar}">
+          <srcfiles dir="${adaptor.clone.dir}"
+            excludes=".git/** build/** dist/** **.swp"/>
+        </uptodate>
+      </or>
+    </condition>
+  </target>
+
+  <target name="-plexi-build" depends="-plexi-test-uptodate"
+    unless="plexi.uptodate">
+    <echo message="Detected Plexi changes. Re-packaging Plexi..."/>
+    <ant antfile="${adaptor.clone.dir}/build.xml" dir="${adaptor.clone.dir}"
+      target="package" inheritAll="false">
+      <property name="adaptorlib.suffix" value=""/>
+    </ant>
+  </target>
+
+  <target name="-real-build" depends="-plexi-build">
+    <mkdir dir="${build-src.dir}"/>
+
+    <javac srcdir="${src.dir}" destdir="${build-src.dir}" debug="true"
+      includeantruntime="false" encoding="utf-8">
+      <compilerarg value="-Xlint:unchecked"/>
+      <classpath refid="adaptor.build.classpath"/>
+    </javac>
+
+    <mkdir dir="${build-test.dir}"/>
+    <!-- Compile JUnit helper -->
+    <javac srcdir="${lib.dir}" destdir="${build-test.dir}" debug="true"
+      includeantruntime="true" encoding="utf-8">
+      <compilerarg value="-Xlint:unchecked"/>
+      <classpath location="${junit.jar}"/>
+      <include name="JUnitLogFixFormatter.java"/>
+    </javac>
+
+    <!-- Compile tests, excluding example tests. -->
+    <javac srcdir="${test.dir}" destdir="${build-test.dir}" debug="true"
+      includeantruntime="false" encoding="utf-8">
+      <compilerarg value="-Xlint:unchecked"/>
+      <classpath refid="adaptor.build.classpath"/>
+      <classpath location="${build-src.dir}"/>
+      <classpath location="${junit.jar}"/>
+    </javac>
+  </target>
+
+  <target name="-discover-version" unless="adaptor.version">
+    <exec executable="git" outputproperty="adaptor.version"
+      logError="true" failifexecutionfails="false">
+      <arg value="describe"/>
+      <arg value="--always"/>
+    </exec>
+    <!-- Set version if git describe failed. -->
+    <property name="adaptor.version" value="unknown"/>
+  </target>
+
+  <target name="dist" description="Generate distribution binaries"
+    depends="clean,test,package"/>
+
+  <target name="package" description="Generate binaries"
+    depends="build,javadoc,-discover-version">
+    <property name="dist.staging.dir" value="${build.dir}/dist/staging"/>
+
+    <delete dir="${build.dir}/dist"/>
+    <delete dir="${dist.dir}"/>
+
+    <mkdir dir="${build.dir}/dist"/>
+    <mkdir dir="${build.dir}/dist/staging"/>
+    <mkdir dir="${dist.dir}"/>
+
+    <!-- Concatenate dependent JARs together into a comma-delimited list. -->
+    <pathconvert pathsep=" " refid="adaptor.run.classpath"
+      property="tmp.adaptor.classpath">
+      <mapper type="flatten"/>
+      <map from="" to="lib/"/>
+    </pathconvert>
+    <jar destfile="${dist.staging.dir}/adaptor-database${adaptor.suffix}.jar"
+      basedir="${build-src.dir}">
+      <manifest>
+        <attribute name="Main-Class" value="${adaptor.class}"/>
+        <attribute name="Class-Path" value="${tmp.adaptor.classpath}"/>
+        <section name="com/google/enterprise/adaptor/database/">
+          <attribute name="Implementation-Title"
+            value="Google Database Adaptor"/>
+          <attribute name="Implementation-Vendor" value="Google Inc."/>
+          <attribute name="Implementation-Version"
+            value="${adaptor.version}"/>
+        </section>
+      </manifest>
+    </jar>
+
+    <!-- lib/ -->
+    <!-- Concatenate dependent JARs together into a comma-delimited list. -->
+    <pathconvert pathsep="," refid="adaptor.run.classpath"
+      property="tmp.adaptor.fileset">
+      <!-- We remove the lib.dir from the paths to prevent trouble with comma
+           and space in lib.dir. It also makes it nicer <echo>ing
+           tmp.adaptorlib.fileset. -->
+      <map from="${lib.dir}/" to=""/>
+    </pathconvert>
+    <copy todir="${dist.staging.dir}/lib" flatten="true">
+      <fileset dir="${lib.dir}" includes="${tmp.adaptor.fileset}"/>
+    </copy>
+
+    <!-- adaptor-database-withlib.jar -->
+    <jar filesetmanifest="mergewithoutmain"
+      destfile="${dist.staging.dir}/adaptor-database${adaptor.suffix}-withlib.jar">
+      <zipfileset
+        src="${dist.staging.dir}/adaptor-database${adaptor.suffix}.jar"/>
+      <zipgroupfileset dir="${dist.staging.dir}/lib"/>
+      <manifest>
+        <attribute name="Main-Class" value="${adaptor.class}"/>
+      </manifest>
+    </jar>
+
+    <!-- adaptor-bin.zip -->
+    <move file="${dist.staging.dir}"
+      tofile="${build.dir}/dist/adaptor-database${adaptor.suffix}"/>
+    <zip destfile="${dist.dir}/adaptor-database${adaptor.suffix}-bin.zip"
+      basedir="${build.dir}/dist/adaptor-database${adaptor.suffix}"/>
+  </target>
+
+  <target name="clean" description="Remove build output">
+    <delete dir="${build.dir}"/>
+    <delete dir="${dist.dir}"/>
+  </target>
+
+  <target name="javadoc" description="Build JavaDocs">
+    <javadoc sourcepath="${src.dir}" destdir="${javadoc.dir}"
+        overview="${src.dir}/overview.html">
+      <classpath refid="adaptor.build.classpath"/>
+      <arg value="-quiet"/>
+      <arg value="-notimestamp"/>
+    </javadoc>
+  </target>
+
+  <target name="run" depends="build" description="Run adaptor">
+    <java classpath="${build-src.dir}" fork="true" classname="${adaptor.class}">
+      <classpath refid="adaptor.run.classpath"/>
+      <sysproperty key="java.util.logging.config.file"
+        value="logging.properties"/>
+      <sysproperty key="javax.net.ssl.keyStore" file="keys.jks"/>
+      <sysproperty key="javax.net.ssl.keyStoreType" value="jks"/>
+      <sysproperty key="javax.net.ssl.keyStorePassword" value="changeit"/>
+      <sysproperty key="javax.net.ssl.trustStore" file="cacerts.jks"/>
+      <sysproperty key="javax.net.ssl.trustStoreType" value="jks"/>
+      <sysproperty key="javax.net.ssl.trustStorePassword" value="changeit"/>
+      <arg line="${adaptor.args}"/>
+    </java>
+  </target>
+
+  <target name="coverage" depends="instrument,test,coverage-report"
+    description="Run instrumented tests and generate coverage report"/>
+
+  <target name="test" depends="build" description="Run JUnit tests">
+    <junit printsummary="yes" haltonfailure="yes" forkmode="once" fork="true"
+      dir="${basedir}" maxmemory="512m">
+      <sysproperty key="net.sourceforge.cobertura.datafile"
+        file="${build-instrument.dir}/cobertura.ser"/>
+      <classpath refid="adaptor.run.classpath"/>
+      <classpath refid="cobertura.classpath"/>
+      <classpath location="${junit.jar}"/>
+      <classpath location="${build-instrument.dir}"/>
+      <classpath location="${build-src.dir}"/>
+      <classpath location="${build-test.dir}"/>
+      <formatter type="plain" usefile="false"/>
+      <formatter classname="JUnitLogFixFormatter" usefile="false"/>
+      <batchtest>
+        <fileset dir="${test.dir}">
+          <include name="**/${test.class}.java"/>
+        </fileset>
+      </batchtest>
+    </junit>
+  </target>
+
+  <target name="instrument" depends="build" description="Instrument classes">
+    <taskdef classpathref="cobertura.classpath" resource="tasks.properties"/>
+    <cobertura-instrument datafile="${build-instrument.dir}/cobertura.ser"
+      todir="${build-instrument.dir}">
+      <auxClassPath>
+        <path refid="adaptor.build.classpath" />
+      </auxClassPath>
+      <fileset dir="${build-src.dir}"/>
+    </cobertura-instrument>
+  </target>
+
+  <target name="clean-instrument" unless="instrument.uptodate"
+    description="Delete instrumented classes">
+    <delete dir="${build-instrument.dir}"/>
+  </target>
+
+  <target name="coverage-report" description="Generates code coverage report">
+    <taskdef classpathref="cobertura.classpath" resource="tasks.properties"/>
+    <cobertura-report datafile="${build-instrument.dir}/cobertura.ser"
+      srcdir="${src.dir}" destdir="${build.dir}/coverage"/>
+  </target>
+</project>
diff --git a/lib/JUnitLogFixFormatter.java b/lib/JUnitLogFixFormatter.java
new file mode 100644
index 0000000..9920f3b
--- /dev/null
+++ b/lib/JUnitLogFixFormatter.java
@@ -0,0 +1,109 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.optional.junit.JUnitResultFormatter;
+import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
+
+import java.io.*;
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * Ant formatter for fixing logging output when runing multiple JUnit tests in
+ * the same JVM.
+ *
+ * <p>The default {@link ConsoleHandler} caches the value of {@code System.err}.
+ * The Ant task changes {@code System.err} after every test. Thus, only the
+ * first test gets logging logged when running JUnit tests from Ant. This
+ * formatter changes swaps out any ConsoleHandlers with new console handlers
+ * that have the correct {@code System.err} reference, and the swaps them back
+ * after the test is over.
+ */
+public class JUnitLogFixFormatter implements JUnitResultFormatter {
+  private List<ConsoleHandler> removedHandlers
+      = new ArrayList<ConsoleHandler>();
+  private List<ConsoleHandler> addedHandlers = new ArrayList<ConsoleHandler>();
+
+  @Override
+  public void startTestSuite(JUnitTest suite) throws BuildException {
+    if (removedHandlers.size() != 0) {
+      throw new IllegalStateException("removedHandlers must be empty");
+    }
+    if (addedHandlers.size() != 0) {
+      throw new IllegalStateException("addedHandlers must be empty");
+    }
+
+    Logger root = Logger.getLogger("");
+    for (Handler handler : root.getHandlers()) {
+      if (handler instanceof ConsoleHandler) {
+        removedHandlers.add((ConsoleHandler) handler);
+      }
+    }
+
+    for (ConsoleHandler oldHandler : removedHandlers) {
+      ConsoleHandler newHandler = new ConsoleHandler();
+      newHandler.setLevel(oldHandler.getLevel());
+      newHandler.setFilter(oldHandler.getFilter());
+      newHandler.setFormatter(oldHandler.getFormatter());
+      try {
+        newHandler.setEncoding(oldHandler.getEncoding());
+      } catch (UnsupportedEncodingException ex) {
+        throw new IllegalStateException(ex);
+      }
+      newHandler.setErrorManager(oldHandler.getErrorManager());
+      root.addHandler(newHandler);
+      addedHandlers.add(newHandler);
+      root.removeHandler(oldHandler);
+    }
+  }
+
+  @Override
+  public void endTestSuite(JUnitTest suite) throws BuildException {
+    Logger root = Logger.getLogger("");
+    for (ConsoleHandler handler : removedHandlers) {
+      root.addHandler(handler);
+    }
+    removedHandlers.clear();
+
+    for (ConsoleHandler handler : addedHandlers) {
+      root.removeHandler(handler);
+    }
+    addedHandlers.clear();
+  }
+
+  @Override
+  public void setOutput(OutputStream out) {}
+
+  @Override
+  public void setSystemError(String err) {}
+
+  @Override
+  public void setSystemOutput(String out) {}
+
+  @Override
+  public void addError(Test test, Throwable t) {}
+
+  @Override
+  public void addFailure(Test test, AssertionFailedError t) {}
+
+  @Override
+  public void endTest(Test test) {}
+
+  @Override
+  public void startTest(Test test) {}
+}
diff --git a/lib/junit-4.8.2.jar b/lib/junit-4.8.2.jar
new file mode 100644
index 0000000..5b4bb84
--- /dev/null
+++ b/lib/junit-4.8.2.jar
Binary files differ
diff --git a/lib/plexi b/lib/plexi
new file mode 160000
index 0000000..a0ceeba
--- /dev/null
+++ b/lib/plexi
@@ -0,0 +1 @@
+Subproject commit a0ceeba4a0c9eba529446a8b8995488a8c441dc9
diff --git a/logging.properties b/logging.properties
new file mode 100644
index 0000000..5633323
--- /dev/null
+++ b/logging.properties
@@ -0,0 +1,9 @@
+handlers = java.util.logging.ConsoleHandler
+.level = INFO
+com.google.enterprise.adaptor.database.level = FINER
+com.google.enterprise.adaptor.level = FINER
+java.util.logging.ConsoleHandler.level = FINEST
+java.util.logging.ConsoleHandler.formatter = com.google.enterprise.adaptor.CustomFormatter
+# Uncomment if your terminal can't handle colors and the auto-detection
+# is incorrect.
+# com.google.enterprise.adaptor.CustomFormatter.useColor = false
diff --git a/src/com/google/enterprise/adaptor/database/DatabaseAdaptor.java b/src/com/google/enterprise/adaptor/database/DatabaseAdaptor.java
new file mode 100644
index 0000000..d78db1e
--- /dev/null
+++ b/src/com/google/enterprise/adaptor/database/DatabaseAdaptor.java
@@ -0,0 +1,49 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.enterprise.adaptor.database;
+
+import com.google.enterprise.adaptor.AbstractAdaptor;
+import com.google.enterprise.adaptor.AdaptorContext;
+import com.google.enterprise.adaptor.Config;
+import com.google.enterprise.adaptor.DocId;
+import com.google.enterprise.adaptor.DocIdPusher;
+import com.google.enterprise.adaptor.Request;
+import com.google.enterprise.adaptor.Response;
+
+/** For getting DB content into a Google Search Appliance. */
+public class DatabaseAdaptor extends AbstractAdaptor {
+
+  public static void main(String[] args) {
+    AbstractAdaptor.main(new DatabaseAdaptor(), args);
+  }
+ 
+  @Override
+  public void initConfig(Config config) {
+  }
+
+  @Override
+  public void init(AdaptorContext context) throws Exception {
+  }
+
+  /** Get all doc ids from database. */
+  @Override
+  public void getDocIds(DocIdPusher pusher) {
+  }
+
+  /** Gives the bytes of a document referenced with id. */
+  @Override
+  public void getDocContent(Request req, Response resp) {
+  }
+}
diff --git a/test/com/google/enterprise/adaptor/database/DatabaseAdaptorTest.java b/test/com/google/enterprise/adaptor/database/DatabaseAdaptorTest.java
new file mode 100644
index 0000000..0928524
--- /dev/null
+++ b/test/com/google/enterprise/adaptor/database/DatabaseAdaptorTest.java
@@ -0,0 +1,34 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.enterprise.adaptor.database;
+
+import static org.junit.Assert.*;
+
+import org.junit.*;
+import org.junit.rules.ExpectedException;
+
+import org.junit.Test;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DatabaseAdaptorTest {
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Test
+  public void testAbsolutelyNothing() {
+    // throw new RuntimeException("add test here");
+  }
+}