Print

Print


Author: [log in to unmask]
Date: Wed Aug 26 19:32:50 2015
New Revision: 3412

Log:
Current working version of new datacat API.

Added:
    java/trunk/record-util/src/main/java/org/hps/datacat/DatacatFactory.java
    java/trunk/record-util/src/main/java/org/hps/datacat/Dataset.java
    java/trunk/record-util/src/main/java/org/hps/datacat/DatasetDataType.java
    java/trunk/record-util/src/main/java/org/hps/datacat/DatasetFileFormat.java
    java/trunk/record-util/src/main/java/org/hps/datacat/DatasetImpl.java
    java/trunk/record-util/src/main/java/org/hps/datacat/DatasetLocation.java
    java/trunk/record-util/src/main/java/org/hps/datacat/DatasetLocationImpl.java
    java/trunk/record-util/src/main/java/org/hps/datacat/DatasetMetadata.java
    java/trunk/record-util/src/main/java/org/hps/datacat/DatasetSite.java
    java/trunk/record-util/src/main/java/org/hps/datacat/DatasetUtilities.java
    java/trunk/record-util/src/main/java/org/hps/datacat/HttpUtilities.java
    java/trunk/record-util/src/main/java/org/hps/datacat/JSONUtilities.java
    java/trunk/record-util/src/main/java/org/hps/datacat/ScanStatus.java
Removed:
    java/trunk/record-util/src/main/java/org/hps/datacat/DatacatUtilities.java
Modified:
    java/trunk/record-util/pom.xml
    java/trunk/record-util/src/main/java/org/hps/datacat/DatacatClient.java
    java/trunk/record-util/src/main/java/org/hps/datacat/DatacatClientImpl.java
    java/trunk/record-util/src/main/java/org/hps/datacat/DatacatConstants.java

Modified: java/trunk/record-util/pom.xml
 =============================================================================
--- java/trunk/record-util/pom.xml	(original)
+++ java/trunk/record-util/pom.xml	Wed Aug 26 19:32:50 2015
@@ -45,5 +45,15 @@
 	    <artifactId>json</artifactId>
 	    <version>20140107</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.4.1</version>
+        </dependency>
+        <dependency>
+	    <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.4</version>
+        </dependency>
     </dependencies>
 </project>

Modified: java/trunk/record-util/src/main/java/org/hps/datacat/DatacatClient.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatacatClient.java	(original)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatacatClient.java	Wed Aug 26 19:32:50 2015
@@ -1,6 +1,6 @@
 package org.hps.datacat;
 
-import java.net.URL;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -9,24 +9,78 @@
  * @author Jeremy McCormick, SLAC
  */
 public interface DatacatClient {
-    
-    int addDataset(String folder, Map<String, Object> parameters);
-    
+
+    /**
+     * Add a dataset to the data catalog.
+     * 
+     * @param folder the folder which must already exist
+     * @param dataType the data type
+     * @param resource the resource (path)
+     * @param site the site of the file 
+     * @param fileFormat the file format
+     * @param name the name of the dataset
+     * @return the HTTP status code from the request
+     */
+    int addDataset(String folder, DatasetDataType dataType, String resource, DatasetSite site, DatasetFileFormat fileFormat, String name);
+            
+    /**
+     * Create a folder in the data catalog.
+     * 
+     * @param folder the folder's path
+     * @return the HTTP status code from the request
+     */
     int makeFolder(String folder);
     
-    int patchDataset(String folder, String datasetName, Map<String, Object> metaData);
+    /**
+     * Add metadata to an existing dataset.
+     * 
+     * @param folder the folder
+     * @param datasetName the name of the dataset
+     * @param metaData the map of metadata where values can be <code>String</code>, <code>Integer</code> or <code>Float</code>
+     * @return the HTTP status code from the request
+     */
+    int addMetadata(String folder, String datasetName, Map<String, Object> metaData);
     
+    /**
+     * Remove a folder from the catalog.
+     * <p>
+     * It must be empty or an error will occur. 
+     * 
+     * @param folder the folder path
+     * @return the HHTP status code from the request
+     */
     int removeFolder(String folder);
     
+    /**
+     * Delete a dataset from the catalog.
+     * <p>
+     * This has no affect on the underlying resource (file).
+     * 
+     * @param path the path of the dataset
+     * @return the HTTP status code from the reqest
+     */
     int deleteDataset(String path);
+            
+    /**
+     * Find datasets in the catalog.
+     * <p>
+     * See <a href="http://docs.datacatalog.apiary.io/#search">Search Doc</a> for more details.
+     * 
+     * @param folder the folder path
+     * @param query the query to execute
+     * @return the HTTP status code from the request
+     */
+    List<Dataset> findDatasets(String folder, String query);
     
-    // TODO: get full info on dataset
+    // TODO: method to get dataset from path
+    // to get all metadata need site
+    // http://localhost:8080/datacat-v0.4-SNAPSHOT/r/path.json/HPS/derp/herp01;s=SLAC 
+    // use HTTP GET 
+    // Dataset getDataSet(String path);
     
-    // TODO: query for datasets on meta data or other info
-    
-    String getRootDir();
-    
-    URL getBaseUrl();
-    
-    String getSite();
+    // TODO: method to determine if folder or dataset exists
+    // http://localhost:8080/datacat-v0.4-SNAPSHOT/r/path.json/HPS/derp/derp
+    // will return 
+    // {"message":"File doesn't exist","type":"NoSuchFileException","cause":"Unable to resolve /HPS/derp/derp in parent Name: derp\tPath: /HPS/derp\t"}
+    // boolean exists(String path);
 }

Modified: java/trunk/record-util/src/main/java/org/hps/datacat/DatacatClientImpl.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatacatClientImpl.java	(original)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatacatClientImpl.java	Wed Aug 26 19:32:50 2015
@@ -1,36 +1,43 @@
 package org.hps.datacat;
 
 import java.io.File;
+import java.io.UnsupportedEncodingException;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLEncoder;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import org.json.JSONObject;
 
-
-public class DatacatClientImpl implements DatacatClient {
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ */
+final class DatacatClientImpl implements DatacatClient {
 
     private URL url;
-    private String site;
+    private DatasetSite site;
     private String rootDir;
     
     /**
      * Create client with default parameters.
      */
     DatacatClientImpl() {        
-        this(DatacatConstants.BASE_URL, DatacatConstants.SLAC_SITE, DatacatConstants.ROOT_DIR);
+        this(DatacatConstants.BASE_URL, DatasetSite.SLAC, DatacatConstants.ROOT_DIR);
     }
     
     /**
      * Create client.
+     * 
      * @param baseUrl
      * @param site
      * @param rootDir
      */
-    DatacatClientImpl(String baseUrl, String site, String rootDir) {
+    DatacatClientImpl(String url, DatasetSite site, String rootDir) {
         try {
-            url = new URL(baseUrl);
+            this.url = new URL(url);
         } catch (MalformedURLException e) {
             throw new IllegalArgumentException("The URL is bad.", e);
         }
@@ -42,7 +49,7 @@
             throw new IllegalArgumentException("The root dir argument is null.");
         }
         this.rootDir = rootDir;
-        System.out.println("rootUrl: " + baseUrl);
+        System.out.println("url: " + url);
         System.out.println("site: " + site);
         System.out.println("rootDir: " + rootDir);
     }
@@ -50,19 +57,13 @@
     @Override
     public int removeFolder(String folder) {
         String fullUrl = url.toString() + "/r/folders.json/" + this.rootDir + folder;
-        return DatacatUtilities.doDelete(fullUrl);
+        return HttpUtilities.doDelete(fullUrl);
     }
 
     @Override
     public int deleteDataset(String path) {
         String fullUrl = url.toString() + "/r/datasets.json/" + this.rootDir + path;
-        return DatacatUtilities.doDelete(fullUrl);
-    }
-
-    @Override
-    public int addDataset(String folder, Map<String, Object> parameters) {
-        JSONObject dataset = DatacatUtilities.createJSONDataset(parameters);
-        return DatacatUtilities.doPost(url + "/r/datasets.json/" + this.rootDir + "/" + folder, dataset.toString());
+        return HttpUtilities.doDelete(fullUrl);
     }
         
     @Override
@@ -72,26 +73,57 @@
         String name = new File(path).getName();       
         parameters.put("name", name);
         parameters.put("_type", "folder");
-        JSONObject object = DatacatUtilities.createJSONFromMap(parameters);
-        return DatacatUtilities.doPost(url + "/r/folders.json/" + this.rootDir, object.toString());
-    }
-
-    @Override
-    public int patchDataset(String folder, String name, Map<String, Object> metaData) {
-        JSONObject object = DatacatUtilities.createJSONMetaData(metaData);
-        String patchUrl = this.url.toString() + "/r/datasets.json/" + this.rootDir + "/" + folder + "/" + name + ";v=current;s=" + this.site;
-        return DatacatUtilities.doPost(patchUrl, object.toString());
-    }      
-    
-    public String getRootDir() {
-        return this.rootDir;
+        JSONObject object = JSONUtilities.createJSONFromMap(parameters);
+        return HttpUtilities.doPost(url + "/r/folders.json/" + this.rootDir, object.toString());
     }
     
-    public URL getBaseUrl() {
-        return this.url;
-    }
+    @Override
+    public int addMetadata(String folder, String name, Map<String, Object> metaData) {
+        JSONObject object = JSONUtilities.createJSONMetaData(metaData);
+        String patchUrl = this.url.toString() + "/r/datasets.json/" + this.rootDir + "/" + folder + "/" + name + ";v=current;s=" + this.site;
+                
+        return HttpUtilities.doPatch(patchUrl, object.toString());
+    }      
+
+    // example
+    // http://localhost:8080/datacat-v0.4-SNAPSHOT/r/search.json/HPS/derp?filter=run+%3E+1000
+    @Override
+    public List<Dataset> findDatasets(String directory, String query) {
+        
+        String fullUrl = this.url.toString() + "/r/search.json/" + this.rootDir + "/";
+        if (directory != null) {
+            fullUrl += directory;
+        }
+        fullUrl += ";s=" + this.site.name();
+        if (query != null) {
+            String encoded = null;        
+            try {
+                encoded = URLEncoder.encode(query, "UTF-8");
+            } catch (UnsupportedEncodingException e) {
+                throw new RuntimeException(e);
+            }
+            fullUrl += "?filter=" + encoded;
+        }
+        System.out.println("query: " + fullUrl);
+        StringBuffer outputBuffer = new StringBuffer();
+        int response = HttpUtilities.doGet(fullUrl, outputBuffer);
+        System.out.println("response: " + response);
+        System.out.println("output: " + outputBuffer.toString());
+        
+        // Build and return dataset list
+        JSONObject searchResults = new JSONObject(outputBuffer.toString());
+        return DatasetUtilities.getDatasetsFromSearch(searchResults);
+    }    
     
-    public String getSite() {
-        return this.site;
+    @Override
+    public int addDataset(String folder, DatasetDataType dataType, String resource, DatasetSite site, DatasetFileFormat fileFormat, String name) {
+        Map<String, Object> parameters = new HashMap<String, Object>();
+        parameters.put("dataType", dataType.toString());
+        parameters.put("resource", resource);
+        parameters.put("site", DatasetSite.SLAC.name());
+        parameters.put("fileFormat", fileFormat.toString());        
+        parameters.put("name", name);           
+        JSONObject dataset = JSONUtilities.createJSONDataset(parameters);
+        return HttpUtilities.doPost(url + "/r/datasets.json/" + this.rootDir + "/" + folder, dataset.toString());
     }
 }

Modified: java/trunk/record-util/src/main/java/org/hps/datacat/DatacatConstants.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatacatConstants.java	(original)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatacatConstants.java	Wed Aug 26 19:32:50 2015
@@ -1,29 +1,20 @@
 package org.hps.datacat;
 
+/**
+ * Constants for the HPS datacat.
+ * 
+ * @author Jeremy McCormick, SLAC
+ */
+final class DatacatConstants {
 
-public class DatacatConstants {
-
+    /**
+     * The root directory in the catalog for HPS folders.
+     */
     public static final String ROOT_DIR = "HPS";
         
-    public static final String BASE_URL = "http://localhost:8080/datacat-v0.4-SNAPSHOT";
-    
-    public static final String SLAC_SITE = "SLAC";
-    
-    public static final String JLAB_SITE = "JLAB";
-    
-    public static final String EVIO_FORMAT = "EVIO";
-    
-    public static final String LCIO_FORMAT = "LCIO";
-    
-    public static final String ROOT_FORMAT = "ROOT";
-    
-    public static final String AIDA_FORMAT = "AIDA";
-    
-    public static final String DQM_TYPE = "DQM";
-    
-    public static final String RAW_TYPE = "RAW";
-    
-    public static final String RECON_TYPE = "RECON";
-    
-    public static final String DST_TYPE = "DST";        
+    /**
+     * The base URL of the datacat server.
+     */
+    // FIXME: This needs to be more easily configurable and not hard-coded.
+    public static final String BASE_URL = "http://localhost:8080/datacat-v0.4-SNAPSHOT";            
 }

Added: java/trunk/record-util/src/main/java/org/hps/datacat/DatacatFactory.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatacatFactory.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatacatFactory.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,18 @@
+package org.hps.datacat;
+
+/**
+ * Factory class for providing user access to interfaces with protected implementation classes.
+ * 
+ * @author Jeremy McCormick, SLAC
+ */
+public class DatacatFactory {
+        
+    /**
+     * Create a datacat client.
+     * 
+     * @return the datacat client
+     */
+    public DatacatClient createClient() {
+        return new DatacatClientImpl();
+    }
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/Dataset.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/Dataset.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/Dataset.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,26 @@
+package org.hps.datacat;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ *
+ */
+public interface Dataset {
+    
+    String getName();
+    
+    String getPath();
+    
+    List<DatasetLocation> getLocations();
+        
+    DatasetFileFormat getFileFormat();
+    
+    DatasetDataType getDataType();
+    
+    Date getCreated();
+    
+    //DatasetMetadata getMetadata();
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/DatasetDataType.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatasetDataType.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatasetDataType.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,14 @@
+package org.hps.datacat;
+
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ *
+ */
+public enum DatasetDataType {
+    DQM,
+    RAW,
+    RECON,
+    DST,
+    TEST;
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/DatasetFileFormat.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatasetFileFormat.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatasetFileFormat.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,14 @@
+package org.hps.datacat;
+
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ *
+ */
+public enum DatasetFileFormat {
+    EVIO,
+    LCIO,
+    ROOT,
+    AIDA,
+    TEST;
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/DatasetImpl.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatasetImpl.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatasetImpl.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,81 @@
+package org.hps.datacat;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ *
+ */
+final class DatasetImpl implements Dataset {
+    
+    private String name;
+    private String path;
+    private DatasetDataType dataType;
+    private DatasetFileFormat fileFormat;
+    private List<DatasetLocation> locations = new ArrayList<DatasetLocation>();
+    private Date created;
+    
+    private static final SimpleDateFormat DATE_PARSER = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
+    
+    DatasetImpl(JSONObject jsonObject) {
+        parse(jsonObject);
+    }
+        
+    private void parse(JSONObject jsonObject) {
+        if (!jsonObject.getString("_type").equals("dataset#full")) {
+            throw new IllegalArgumentException("Wrong _type in JSON data: " + jsonObject.getString("_type"));
+        }
+        name = jsonObject.getString("name");
+        path = jsonObject.getString("path");
+        dataType = DatasetDataType.valueOf(jsonObject.getString("dataType"));
+        fileFormat = DatasetFileFormat.valueOf(jsonObject.getString("fileFormat"));
+        try {
+            created = DATE_PARSER.parse(jsonObject.getString("created"));
+        } catch (ParseException e) {
+            throw new IllegalArgumentException("Bad created value: " + jsonObject.getString("created"), e);
+        }        
+        JSONArray locationsArray = jsonObject.getJSONArray("locations");
+        for (int i = 0; i < locationsArray.length(); i++) {
+            this.locations.add(new DatasetLocationImpl(locationsArray.getJSONObject(i)));
+        }        
+    }
+    
+    @Override
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public String getPath() {
+        return this.path;
+    }
+
+    @Override
+    public List<DatasetLocation> getLocations() {
+        return Collections.unmodifiableList(this.locations);
+    }
+
+    @Override
+    public DatasetFileFormat getFileFormat() {
+        return this.fileFormat;
+    }
+
+    @Override
+    public DatasetDataType getDataType() {
+        return this.dataType;
+    }
+
+    @Override
+    public Date getCreated() {
+        return this.created;
+    }
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/DatasetLocation.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatasetLocation.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatasetLocation.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,23 @@
+package org.hps.datacat;
+
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ *
+ */
+public interface DatasetLocation {
+    
+    DatasetSite getSite();
+    
+    String getResource();
+    
+    ScanStatus getScanStatus();
+    
+    long getSize();
+    
+    int getRunMin();
+    
+    int getRunMax();
+    
+    int getEventCount();
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/DatasetLocationImpl.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatasetLocationImpl.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatasetLocationImpl.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,73 @@
+package org.hps.datacat;
+
+import org.json.JSONObject;
+
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ */
+final class DatasetLocationImpl implements DatasetLocation {
+
+    private DatasetSite site;
+    private String resource;
+    private ScanStatus scanStatus = ScanStatus.UNKNOWN;
+    private long size;
+    private int runMin;
+    private int runMax;
+    private int eventCount;
+    
+    DatasetLocationImpl(JSONObject jsonObject) {
+        parse(jsonObject);
+    }
+    
+    private void parse(JSONObject jsonObject) {
+        if (!jsonObject.getString("_type").equals("location")) {
+            throw new IllegalArgumentException("Wrong _type in JSON data: " + jsonObject.getString("_type"));
+        }
+        this.site = DatasetSite.valueOf(jsonObject.getString("name"));
+        this.resource = jsonObject.getString("resource");
+        this.size = jsonObject.getLong("size");        
+        if (!jsonObject.get("scanStatus").equals(JSONObject.NULL)) {            
+            this.scanStatus = ScanStatus.valueOf(jsonObject.getString("scanStatus"));
+        }
+        this.runMin = jsonObject.getInt("runMin");
+        this.runMax = jsonObject.getInt("runMax");
+        this.eventCount = jsonObject.getInt("eventCount");
+    }
+    
+    @Override
+    public DatasetSite getSite() {
+        return this.site;
+    }
+
+    @Override
+    public String getResource() {
+        return resource;
+    }
+
+    @Override
+    public ScanStatus getScanStatus() {
+        return scanStatus;
+    }
+
+    @Override
+    public long getSize() {
+        return this.size;
+    }
+
+    @Override
+    public int getRunMin() {
+        return this.runMin;
+    }
+
+    @Override
+    public int getRunMax() {
+        return this.runMax;
+    }
+
+    @Override
+    public int getEventCount() {
+        return this.eventCount;
+    }
+
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/DatasetMetadata.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatasetMetadata.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatasetMetadata.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,17 @@
+package org.hps.datacat;
+
+
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ */
+public interface DatasetMetadata {
+        
+    float getFloat(String key);
+    
+    int getInt(String key);
+    
+    String getString(String key);
+    
+    boolean hasKey(String key);
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/DatasetSite.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatasetSite.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatasetSite.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,11 @@
+package org.hps.datacat;
+
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ *
+ */
+public enum DatasetSite {
+    SLAC,
+    JLAB;
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/DatasetUtilities.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/DatasetUtilities.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/DatasetUtilities.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,23 @@
+package org.hps.datacat;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ */
+final class DatasetUtilities {
+    
+    static List<Dataset> getDatasetsFromSearch(JSONObject searchResults) {
+        List<Dataset> datasets = new ArrayList<Dataset>();
+        JSONArray resultsArray = searchResults.getJSONArray("results");
+        for (int i = 0; i < resultsArray.length(); i++) {
+            datasets.add(new DatasetImpl(resultsArray.getJSONObject(i)));
+        }
+        return datasets;
+    }
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/HttpUtilities.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/HttpUtilities.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/HttpUtilities.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,141 @@
+package org.hps.datacat;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPatch;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.InputStreamEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ */
+final class HttpUtilities {
+
+    static int doPost(String urlLocation, String data) {
+        int responseCode = 0;
+        try {
+            URL url = new URL(urlLocation);
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+            connection.setRequestMethod("POST");
+            connection.setRequestProperty("Content-Type", "application/json");
+            connection.setDoOutput(true);
+            if (data != null) {
+                OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream());
+                out.write(data);
+                out.close();
+            }
+            System.out.println("url: " + urlLocation);
+            System.out.println("data: " + data);
+            System.out.println("response: " + connection.getResponseCode());
+            System.out.println("message: " + connection.getResponseMessage());
+            responseCode = connection.getResponseCode();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return responseCode;
+    }
+    
+    static int doGet(String urlLocation, StringBuffer stringBuffer) {
+        HttpURLConnection connection = null;
+        int response = 0;
+        try {
+            //System.out.println("doGet: " + urlLocation);
+            connection = (HttpURLConnection) new URL(urlLocation).openConnection();
+            connection.setRequestMethod("GET");
+            connection.setRequestProperty("Content-Type", "application/json");
+            connection.setRequestProperty("Accept", "application/json");
+            connection.setDoInput(true);
+            connection.connect();
+            if (stringBuffer != null) {
+                String output = IOUtils.toString(connection.getInputStream(), "UTF-8");            
+                stringBuffer.append(output);
+            }
+            response = connection.getResponseCode();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            connection.disconnect();
+        }
+        return response;
+    }    
+    
+    
+    static int doPatch(String urlLocation, String data) {
+        int responseCode = 0;        
+        CloseableHttpClient httpClient = HttpClients.createDefault();
+        HttpPatch httpPatch = null;
+        try {
+            httpPatch = new HttpPatch(new URI(urlLocation));            
+            InputStreamEntity entity = 
+                    new InputStreamEntity(
+                            new ByteArrayInputStream(
+                                    data.getBytes("UTF-8")), 
+                                    -1, 
+                                    ContentType.APPLICATION_JSON);
+            httpPatch.setEntity(entity);            
+            CloseableHttpResponse response = httpClient.execute(httpPatch);
+            System.out.println("status: " + response.getStatusLine());
+            try {
+                EntityUtils.consume(response.getEntity());
+            } finally {
+                response.close();
+            }            
+        } catch (URISyntaxException e) {
+            throw new IllegalArgumentException(e);
+        } catch(IOException e) {
+            throw new RuntimeException(e);
+        } finally {
+            try {
+                httpClient.close();
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }                   
+        return responseCode;
+    }    
+    
+    
+    static int doDelete(String fullUrl) {
+        int responseCode = 0;
+        try {
+            URL url = new URL(fullUrl);
+            System.out.println("deleting url: " + fullUrl);
+            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+            connection.setDoOutput(true);
+            connection.setRequestMethod("DELETE");
+            connection.connect();
+            responseCode = connection.getResponseCode();
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+        return responseCode;
+    }
+    
+    static URL createURL(String... chunks) {
+        if (chunks.length == 0) {
+            throw new IllegalArgumentException("No arguments provided.");
+        }
+        String urlString = "";
+        for (String chunk : chunks) {
+            urlString += chunk;
+        }
+        try {
+            return new URL(urlString);
+        } catch (MalformedURLException e) {
+            throw new IllegalArgumentException("Bad URL string: " + urlString);
+        }
+    }
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/JSONUtilities.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/JSONUtilities.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/JSONUtilities.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,48 @@
+package org.hps.datacat;
+
+import java.util.Map;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+/**
+ * 
+ * @author Jeremy McCormick, SLAC
+ */
+final class JSONUtilities {
+    
+    static JSONObject createJSONDataset(Map<String, Object> parameters) {
+        JSONObject dataset = new JSONObject();
+        dataset.put("dataType", parameters.get("dataType"));
+        dataset.put("versionId", "new");
+        JSONObject location = new JSONObject();
+        location.put("resource", parameters.get("resource"));
+        location.put("site", parameters.get("site"));
+        JSONArray array = new JSONArray();
+        array.put(location);
+        dataset.put("locations", array);                
+        dataset.put("fileFormat", parameters.get("fileFormat"));
+        dataset.put("name", parameters.get("name"));
+        return dataset;
+    }
+    
+    static JSONObject createJSONFromMap(Map<String, Object> parameters) {
+        JSONObject object = new JSONObject();
+        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
+            object.put(entry.getKey(), entry.getValue());
+        }
+        return object;
+    }
+    
+    static JSONObject createJSONMetaData(Map<String, Object> metaData) {
+        JSONObject object = new JSONObject();
+        JSONArray array = new JSONArray();
+        for (Map.Entry<String, Object> entry : metaData.entrySet()) {
+            JSONObject value = new JSONObject();
+            value.put(entry.getKey(), entry.getValue());
+            array.put(value);
+        }                
+        object.put("versionMetadata", array);
+        return object;
+    }
+}

Added: java/trunk/record-util/src/main/java/org/hps/datacat/ScanStatus.java
 =============================================================================
--- java/trunk/record-util/src/main/java/org/hps/datacat/ScanStatus.java	(added)
+++ java/trunk/record-util/src/main/java/org/hps/datacat/ScanStatus.java	Wed Aug 26 19:32:50 2015
@@ -0,0 +1,8 @@
+package org.hps.datacat;
+
+
+public enum ScanStatus {
+    UNKNOWN,
+    UNSCANNED,
+    OK
+}