read RecordTypes from JSON specifications
diff --git a/asterix-maven-plugins/record-manager-generator-maven-plugin/pom.xml b/asterix-maven-plugins/record-manager-generator-maven-plugin/pom.xml
index 9ffc8d2..a4470d6 100644
--- a/asterix-maven-plugins/record-manager-generator-maven-plugin/pom.xml
+++ b/asterix-maven-plugins/record-manager-generator-maven-plugin/pom.xml
@@ -52,5 +52,21 @@
       <artifactId>maven-plugin-api</artifactId>
       <version>2.0.2</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-artifact</artifactId>
+      <version>2.0.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-project</artifactId>
+      <version>2.0.2</version>
+    </dependency>
+	<dependency>
+      <groupId>org.json</groupId>
+      <artifactId>json</artifactId>
+      <version>20090211</version>
+      <type>jar</type>
+    </dependency>
   </dependencies>    
 </project>
diff --git a/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordManagerGeneratorMojo.java b/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordManagerGeneratorMojo.java
index 8b6b581..dc7fe19 100644
--- a/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordManagerGeneratorMojo.java
+++ b/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordManagerGeneratorMojo.java
@@ -16,14 +16,20 @@
 package edu.uci.ics.asterix.recordmanagergenerator;
 
 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.InputStream;
+import java.io.Reader;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.project.MavenProject;
+import org.json.JSONException;
 
 /**
  * @goal generate-record-manager
@@ -56,88 +62,78 @@
      * @parameter
      * @required
      */
-    private String[] recordTypes;
+    private File[] inputFiles;
     /**
      * parameter injected from pom.xml
      * 
      * @parameter
      * @required
      */
-    private File outputDir;
-
+    private String outputDir;
+    /**
+     * @parameter default-value="${project}"
+     * @required
+     * @readonly
+     */
+    MavenProject project;
+    
     private Map<String, RecordType> typeMap;
 
     public RecordManagerGeneratorMojo() {        
     }
 
-    private void defineRecordTypes() {
+    private void readRecordTypes() throws MojoExecutionException {
         if (debug) {
             getLog().info("generating debug code");
         }
 
         typeMap = new HashMap<String, RecordType>();
 
-        RecordType resource = new RecordType("Resource");
-        resource.addField("last holder", RecordType.Type.GLOBAL, "-1");
-        resource.addField("first waiter", RecordType.Type.GLOBAL, "-1");
-        resource.addField("first upgrader", RecordType.Type.GLOBAL, "-1");
-        resource.addField("next", RecordType.Type.GLOBAL, null);
-        resource.addField("max mode", RecordType.Type.INT, "LockMode.NL");
-        resource.addField("dataset id", RecordType.Type.INT, null);
-        resource.addField("pk hash val", RecordType.Type.INT, null);
-        resource.addField("alloc id", RecordType.Type.SHORT, null);
-
-        resource.addToMap(typeMap);
-
-        RecordType request = new RecordType("Request");
-        request.addField("resource id", RecordType.Type.GLOBAL, null);
-        request.addField("job slot", RecordType.Type.GLOBAL, null);
-        request.addField("prev job request", RecordType.Type.GLOBAL, null);
-        request.addField("next job request", RecordType.Type.GLOBAL, null);
-        request.addField("next request", RecordType.Type.GLOBAL, null);
-        request.addField("lock mode", RecordType.Type.INT, null);
-        request.addField("alloc id", RecordType.Type.SHORT, null);
-
-        request.addToMap(typeMap);
-
-        RecordType job = new RecordType("Job");
-        job.addField("last holder", RecordType.Type.GLOBAL, "-1");
-        job.addField("last waiter", RecordType.Type.GLOBAL, "-1");
-        job.addField("last upgrader", RecordType.Type.GLOBAL, "-1");
-        job.addField("job id", RecordType.Type.INT, null);
-        job.addField("alloc id", RecordType.Type.SHORT, null);
-
-        job.addToMap(typeMap);
+        for (int i = 0; i < inputFiles.length; ++i) {
+            try {
+                getLog().info("reading " + inputFiles[i].toString());
+                Reader read = new FileReader(inputFiles[i]);
+                RecordType type = RecordType.read(read);
+                // always add allocId to enable tracking of allocations 
+                type.addField("alloc id", RecordType.Type.SHORT, null);
+                type.addToMap(typeMap);
+            } catch (FileNotFoundException fnfe) {
+                throw new MojoExecutionException("cound not find type description file " + inputFiles[i], fnfe);
+            } catch (JSONException jse) {
+                throw new MojoExecutionException("cound not parse type description file " + inputFiles[i], jse);
+            }
+        }
     }
 
     public void execute() throws MojoExecutionException, MojoFailureException {
-        if (!outputDir.exists()) {
-            outputDir.mkdirs();
+        String buildDir = project.getBuild().getDirectory();
+        String outputPath = buildDir + File.separator + outputDir;
+        File dir = new File(outputPath);
+        if (!dir.exists()) {
+            dir.mkdirs();
         }
 
-        defineRecordTypes();
-
-        for (int i = 0; i < recordTypes.length; ++i) {
-            final String recordType = recordTypes[i];
-
+        readRecordTypes();
+        
+        for (String recordType : typeMap.keySet()) {
             if (recordManagerTemplate != null) {
-                generateSource(Generator.Manager.RECORD, recordManagerTemplate, recordType);
+                generateSource(Generator.Manager.RECORD, recordManagerTemplate, recordType, outputPath);
             }
 
             if (arenaManagerTemplate != null) {
-                generateSource(Generator.Manager.ARENA, arenaManagerTemplate, recordType);
-            }
+                generateSource(Generator.Manager.ARENA, arenaManagerTemplate, recordType, outputPath);
+            } 
         }
     }
 
-    private void generateSource(Generator.Manager mgrType, String template, String recordType) throws MojoFailureException {
+    private void generateSource(Generator.Manager mgrType, String template, String recordType, String outputPath) throws MojoFailureException {
         InputStream is = getClass().getClassLoader().getResourceAsStream(template);
         if (is == null) {
             throw new MojoFailureException("template '" + template + "' not found in classpath");
         }
 
         StringBuilder sb = new StringBuilder();
-        File outputFile = new File(outputDir, recordType + template);
+        File outputFile = new File(outputPath + File.separator + recordType + template);
 
         try {
             getLog().info("generating " + outputFile.toString());
diff --git a/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordType.java b/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordType.java
index d794c50..3cab3bd 100644
--- a/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordType.java
+++ b/asterix-maven-plugins/record-manager-generator-maven-plugin/src/main/java/edu/uci/ics/asterix/recordmanagergenerator/RecordType.java
@@ -15,11 +15,17 @@
 
 package edu.uci.ics.asterix.recordmanagergenerator;
 
+import java.io.Reader;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Map;
 
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONTokener;
+
 public class RecordType {
     
     enum Type {
@@ -61,6 +67,27 @@
             this.accessible = accessible;
         }
         
+        public static Field fromJSON(JSONObject obj) throws JSONException {
+            String name = obj.getString("name");
+            Type type = parseType(obj.getString("type"));
+            String initial = obj.optString("initial", null);
+            return new Field(name, type, initial, -1, true);
+        }
+        
+        private static Type parseType(String string) {
+            string = string.toUpperCase();
+            if (string.equals("GLOBAL")) {
+                return Type.GLOBAL;
+            } else if (string.equals("INT")) {
+                return Type.INT;
+            } else if (string.equals("SHORT")) {
+                return Type.SHORT;
+            } else if (string.equals("BYTE")) {
+                return Type.BYTE;
+            }
+            throw new IllegalArgumentException("Unknown type \"" + string + "\"");
+        }
+
         String methodName(String prefix) {
             String words[] = name.split(" ");
             assert(words.length > 0);
@@ -238,6 +265,22 @@
         addField("next free slot", Type.INT, "-1", false);
     }
     
+    public static RecordType read(Reader reader) throws JSONException {
+        JSONTokener tok = new JSONTokener(reader);
+        JSONObject obj = new JSONObject(tok);
+        return fromJSON(obj);
+    }
+    
+    public static RecordType fromJSON(JSONObject obj) throws JSONException {
+        RecordType result = new RecordType(obj.getString("name"));
+        JSONArray fields = obj.getJSONArray("fields");
+        for (int i = 0; i < fields.length(); ++i) {
+            JSONObject field = fields.getJSONObject(i);
+            result.fields.add(Field.fromJSON(field));
+        }
+        return result;        
+    }
+    
     public void addToMap(Map<String, RecordType> map) {
         modifiable = false;
         calcOffsetsAndSize();
diff --git a/asterix-transactions/pom.xml b/asterix-transactions/pom.xml
index 13a01a6..bb3647e 100644
--- a/asterix-transactions/pom.xml
+++ b/asterix-transactions/pom.xml
@@ -41,12 +41,12 @@
                     <debug>false</debug>
                     <arenaManagerTemplate>ArenaManager.java</arenaManagerTemplate>
                     <recordManagerTemplate>RecordManager.java</recordManagerTemplate>
-                    <recordTypes>
-                        <param>Job</param>
-                        <param>Request</param>
-                        <param>Resource</param>
-                    </recordTypes>
-                    <outputDir>${project.build.directory}/generated-sources/java/edu/uci/ics/asterix/transaction/management/service/locking</outputDir>
+                    <inputFiles>
+                        <param>src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Job.json</param>
+                        <param>src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Resource.json</param>
+                        <param>src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Request.json</param>
+                    </inputFiles>
+                    <outputDir>generated-sources/java/edu/uci/ics/asterix/transaction/management/service/locking</outputDir>
                 </configuration>
                 <executions>
                     <execution>
diff --git a/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Job.json b/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Job.json
new file mode 100644
index 0000000..a649b7c
--- /dev/null
+++ b/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Job.json
@@ -0,0 +1,24 @@
+{ 
+    "name" : "Job",
+    "fields" : [
+        {
+            "name" : "last holder",
+            "type" : "GLOBAL",
+            "initial" : "-1"
+        },
+        {
+            "name" : "last waiter",
+            "type" : "GLOBAL",
+            "initial" : "-1"
+        },
+        {
+            "name" : "last upgrader",
+            "type" : "GLOBAL",
+            "initial" : "-1"
+        },
+        {
+            "name" : "job id",
+            "type" : "INT"
+        }
+    ]
+}
diff --git a/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Request.json b/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Request.json
new file mode 100644
index 0000000..0c4fa71
--- /dev/null
+++ b/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Request.json
@@ -0,0 +1,29 @@
+{
+    "name" : "Request",
+    "fields" : [
+        {
+            "name" : "resource id",
+            "type" : "GLOBAL"
+        },
+        {
+            "name" : "job slot",
+            "type" : "GLOBAL"
+        },
+        {
+            "name" : "prev job request",
+            "type" : "GLOBAL"
+        },
+        {
+            "name" : "next job request",
+            "type" : "GLOBAL"
+        },
+        {
+            "name" : "next request",
+            "type" : "GLOBAL"
+        },
+        {
+            "name" : "lock mode",
+            "type" : "INT"
+        }
+    ]
+}
diff --git a/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Resource.json b/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Resource.json
new file mode 100644
index 0000000..cceca3c
--- /dev/null
+++ b/asterix-transactions/src/main/java/edu/uci/ics/asterix/transaction/management/service/locking/Resource.json
@@ -0,0 +1,37 @@
+{
+    "name" : "Resource",
+    "fields" : [
+        {
+            "name" : "last holder",
+            "type" : "GLOBAL",
+            "initial" : "-1"
+        },
+        {
+            "name" : "first waiter",
+            "type" : "GLOBAL",
+            "initial" : "-1"
+        },
+        {
+            "name" : "first upgrader",
+            "type" : "GLOBAL",
+            "initial" : "-1"
+        },
+        {
+            "name" : "next",
+            "type" : "GLOBAL"
+        },
+        {
+            "name" : "max mode",
+            "type" : "INT",
+            "initial" : "LockMode.NL"
+        },
+        {
+            "name" : "dataset id",
+            "type" : "INT"
+        },
+        {
+            "name" : "pk hash val",
+            "type" : "INT"
+        }
+    ]
+}