You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@oodt.apache.org by ma...@apache.org on 2017/02/18 23:39:51 UTC

[5/6] oodt git commit: update files for new curator

http://git-wip-us.apache.org/repos/asf/oodt/blob/a47b088a/curator2/src/main/java/org/apache/oodt/cas/curation/service/CurationServiceConfig.java
----------------------------------------------------------------------
diff --git a/curator2/src/main/java/org/apache/oodt/cas/curation/service/CurationServiceConfig.java b/curator2/src/main/java/org/apache/oodt/cas/curation/service/CurationServiceConfig.java
new file mode 100644
index 0000000..dc497ed
--- /dev/null
+++ b/curator2/src/main/java/org/apache/oodt/cas/curation/service/CurationServiceConfig.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.oodt.cas.curation.service;
+
+//OODT imports
+import org.apache.oodt.cas.curation.servlet.CuratorConfMetKeys;
+import org.apache.oodt.cas.filemgr.datatransfer.DataTransferFactory;
+import org.apache.oodt.cas.filemgr.system.XmlRpcFileManagerClient;
+import org.apache.oodt.cas.metadata.util.PathUtils;
+
+//JDK imports
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+
+/**
+ * 
+ * 
+ * Configures the {@link CurationService} by reading the parameters out of the
+ * <code>context.xml</code> file, doing a
+ * {@link PathUtils#replaceEnvVariables(String)} on each property in the
+ * context.xml. This allows you to specify environment variables using the
+ * traditional CAS syntax of:
+ * 
+ * <pre>
+ *   [VAR_NAME], e.g., [CAS_CURATOR_HOME]/some/other/path
+ * </pre>
+ * 
+ * The configuration parameters are read once upon loading the instance of this
+ * object.
+ * 
+ * @author pramirez
+ * @author mattmann
+ * @version $Revision$
+ * 
+ */
+public class CurationServiceConfig implements CuratorConfMetKeys {
+  private static CurationServiceConfig instance;
+
+  private final Map<String, String> parameters = new HashMap<String, String>();
+
+  private XmlRpcFileManagerClient fmClient = null;
+
+  private static final Logger LOG = Logger
+      .getLogger(CurationServiceConfig.class.getName());
+
+  /**
+   * Gets a singleton static instance of the global
+   * {@link CurationServiceConfig} for the CAS Curator Webapp.
+   * 
+   * @param conf
+   *          The {@link ServletConfig} read on startup of the webapp. This is
+   *          typically specified in a <code>context.xml</code> file, but can
+   *          also be specified in <code>web.xml</code>.
+   * @return A singleton instance of the global {@link link
+   *         CurationServiceConfig}.
+   * @throws InstantiationException
+   *           If there is any error constructing the config.
+   */
+  public static CurationServiceConfig getInstance(ServletConfig conf) {
+    if (instance == null) {
+      instance = new CurationServiceConfig(conf);
+    }
+    return instance;
+  }
+
+  /**
+   * 
+   * @return The metadata output file path.
+   */
+  public String getMetAreaPath() {
+    return this.evaluateParameter(MET_AREA_PATH);
+  }
+  
+  /**
+   * 
+   * @return The extension of metadata files that will be generated and consumed
+   *         by CAS curator.
+   */
+  public String getMetExtension() {
+    return this.evaluateParameter(MET_EXTENSION);
+  }
+
+  /**
+   * 
+   * @return The path to the staging area where the CAS curator is ingesting
+   *         files from.
+   */
+  public String getStagingAreaPath() {
+    return this.evaluateParameter(STAGING_AREA_PATH);
+  }
+
+  /**
+   * 
+   * @return A {@link String} representation of the CAS File Manager {@link URL}
+   *         .
+   */
+  public String getFileMgrURL() {
+    return this.evaluateParameter(FM_URL);
+  }
+
+  /**
+   * 
+   * @return The full {@link XmlRpcFileManagerClient} built from the CAS curator
+   *         property <code>filemgr.url</code>.
+   */
+  public XmlRpcFileManagerClient getFileManagerClient() {
+    try {
+      return new XmlRpcFileManagerClient(new URL(this.getFileMgrURL()));
+    } catch (Exception e) {
+      e.printStackTrace();
+      return null;
+    }
+  }
+
+  /**
+   * 
+   * @return The java class name (fully-qualified) of the CAS SSO security
+   *         implementation.
+   */
+  public String getSSOImplClass() {
+    return this.evaluateParameter(SSO_IMPL_CLASS);
+  }
+
+  /**
+   * 
+   * @return The display name of the project.
+   */
+  public String getProjectDisplayName() {
+    return this.evaluateParameter(PROJECT_DISPLAY_NAME);
+  }
+
+  /**
+   * 
+   * @return The upload path for metadata extractor config files.
+   */
+  public String getMetExtrConfUploadPath() {
+    return this.evaluateParameter(MET_EXTRACTOR_CONF_UPLOAD_PATH);
+  }
+
+  /**
+   * 
+   * @return The path to the crawler config file.
+   */
+  public String getCrawlerConfFile() {
+    return this.evaluateParameter(CRAWLER_CONF_FILE);
+  }
+
+  /**
+   * 
+   * @return The path to the location where policy directories should be
+   *         uploaded to.
+   */
+  public String getPolicyUploadPath() {
+    return this.evaluateParameter(POLICY_UPLOAD_PATH);
+  }
+
+  /**
+   * 
+   * @return The default CAS File Manager {@link DataTransferFactory} classname.
+   */
+  public String getDefaultTransferFactory() {
+    return this.evaluateParameter(DEFAULT_TRANSFER_FACTORY);
+  }
+
+  /**
+   * Gets a property from the CAS Curator config without calling
+   * {@link PathUtils#replaceEnvVariables(String)}.
+   * 
+   * @param name
+   *          The name of the parameter to return.
+   * @return The un-evaluated property value from the config.
+   */
+  public String getParameter(String name) {
+    return this.parameters.get(name);
+  }
+  
+  public String getFileMgrProps() {
+    return this.evaluateParameter(FM_PROPS);
+  }
+
+  private String evaluateParameter(String name) {
+    return PathUtils.replaceEnvVariables(this.parameters.get(name));
+  }
+
+  // Note that the constructor is private
+  private CurationServiceConfig(ServletConfig conf) {
+    readContextParams(conf.getServletContext());
+    try {
+      fmClient = new XmlRpcFileManagerClient(new URL(this.getFileMgrURL()));
+    } catch (Exception e) {
+      e.printStackTrace();
+      LOG.log(Level.WARNING, "Unable to build CurationServiceConfig: Message: " + e.getMessage());
+    }
+  }
+
+  @SuppressWarnings("unchecked")
+  private void readContextParams(ServletContext context) {
+    for (Enumeration<String> names = context.getInitParameterNames(); names
+        .hasMoreElements();) {
+      String name = names.nextElement();
+      parameters.put(name, context.getInitParameter(name));
+    }
+    LOG.log(Level.INFO, "Init Parameters: " + parameters);
+  }
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/a47b088a/curator2/src/main/java/org/apache/oodt/cas/curation/service/DirectoryResource.java
----------------------------------------------------------------------
diff --git a/curator2/src/main/java/org/apache/oodt/cas/curation/service/DirectoryResource.java b/curator2/src/main/java/org/apache/oodt/cas/curation/service/DirectoryResource.java
new file mode 100644
index 0000000..2700a69
--- /dev/null
+++ b/curator2/src/main/java/org/apache/oodt/cas/curation/service/DirectoryResource.java
@@ -0,0 +1,138 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.oodt.cas.curation.service;
+
+//JDK imports
+import java.io.File;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//JAX-RS imports
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+
+
+
+@Path("directory")
+/**
+ * 
+ * A web service endpoint to a service providing views of the staging area, the
+ * archive area, and the met output area.
+ * 
+ * @author pramirez
+ * @version $Id$
+ */
+public class DirectoryResource extends CurationService {
+  private static final Logger LOG = Logger.getLogger(DirectoryResource.class
+      .getName());
+
+  @Context
+  UriInfo uriInfo;
+  
+  private static final long serialVersionUID = 715126227357637464L;
+
+  @GET
+  @Path("staging")
+  @Produces("text/plain")
+  public String showStagingArea(
+      @DefaultValue("/") @QueryParam("path") String path,
+      @DefaultValue("true") @QueryParam("showFiles") boolean showFiles,
+      @DefaultValue(FORMAT_HTML) @QueryParam("format") String format) {
+    if (FORMAT_HTML.equals(format)) {
+      String response = this.getDirectoryAreaAsHTML(CurationService.config
+          .getStagingAreaPath(), path, showFiles);
+      return response;
+    }
+    return this.getDirectoryAreaAsJSON(CurationService.config
+        .getStagingAreaPath(), path, showFiles);
+  }
+
+  @GET
+  @Path("metadata")
+  @Produces("text/plain")
+  public String showMetArea(@DefaultValue("/") @QueryParam("path") String path,
+      @DefaultValue("true") @QueryParam("showFiles") boolean showFiles) {
+    return this.getDirectoryAreaAsJSON(CurationService.config.getMetAreaPath(),
+        path, showFiles);
+  }
+
+  @GET
+  @Path("catalog")
+  @Produces("text/plain")
+  public String showArchiveArea(@QueryParam("policy") String policy,
+      @QueryParam("productType") String productType,
+      @DefaultValue("20") @QueryParam("num") int numberOfResults,
+      @DefaultValue("0") @QueryParam("start") int start) {
+
+    // Figure out where the product type root path is and display contents
+    return productType;
+  }
+
+
+  public String getDirectoryAreaAsHTML(String base, String path,
+      boolean showFiles) {
+    StringBuffer html = new StringBuffer();
+    String relativePath = null;
+    try {
+      relativePath = this.cleansePath(path);
+    } catch (Exception e) {
+      e.printStackTrace();
+      LOG.log(Level.WARNING, "Error decoding path: [" + path + "]: Message: "
+          + e.getMessage());
+      return html.toString();
+    }
+
+    String startingPath = (base + "/" + relativePath);
+    String f[] = this.getFilesInDirectory(startingPath, showFiles);
+
+    html.append("<ul class=\"fileTree\">\r\n");
+    // Loop through and list directories first. Nicer for UI to get these first
+    for (int i = 0; i < f.length; i++) {
+      if (new File(startingPath + "/" + f[i]).isDirectory()) {
+        html.append(" <li class=\"directory collapsed\">");
+        html.append("<a href=\"#\" rel=\"").append(relativePath).append("/")
+            .append(f[i]).append("\">").append(f[i]).append("</a>");
+        html.append("</li>\r\n");
+      }
+    }
+    // If we are showing files now loop through and show files
+    if (showFiles) {
+      for (int i = 0; i < f.length; i++) {
+        if (new File(startingPath + "/" + f[i]).isFile()) {
+          String filename = new File(startingPath + "/" + f[i]).getName();
+          String ext = filename.substring(filename.lastIndexOf('.') + 1);
+          html.append(" <li class=\"file draggy ext_").append(ext)
+              .append("\">");
+          html.append("<a href=\"#\" rel=\"").append(relativePath).append("/")
+              .append(f[i]).append("\">").append(f[i]).append("</a>");
+          html.append("</li>\r\n");
+        }
+      }
+    }
+    html.append("</ul>");
+
+    return html.toString();
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/a47b088a/curator2/src/main/java/org/apache/oodt/cas/curation/service/IngestionResource.java
----------------------------------------------------------------------
diff --git a/curator2/src/main/java/org/apache/oodt/cas/curation/service/IngestionResource.java b/curator2/src/main/java/org/apache/oodt/cas/curation/service/IngestionResource.java
new file mode 100644
index 0000000..2ea61bb
--- /dev/null
+++ b/curator2/src/main/java/org/apache/oodt/cas/curation/service/IngestionResource.java
@@ -0,0 +1,352 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.oodt.cas.curation.service;
+
+//OODT imports
+import org.apache.oodt.cas.curation.structs.IngestionTask;
+import org.apache.oodt.cas.curation.util.DateUtils;
+import org.apache.oodt.cas.curation.util.ExtractorConfigReader;
+import org.apache.oodt.cas.filemgr.ingest.Ingester;
+import org.apache.oodt.cas.filemgr.ingest.StdIngester;
+import org.apache.oodt.cas.filemgr.structs.exceptions.IngestException;
+import org.apache.oodt.cas.metadata.Metadata;
+
+//JDK imports
+import java.io.File;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//JAX-RS imports
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+
+//JSON imports
+import net.sf.json.JSONObject;
+
+/**
+ * 
+ * Leverages CAS {@link Ingester} interface to ingest Products into the CAS File
+ * Manager via CAS Curator and a REST-ful interface.
+ * 
+ * @author mattmann
+ * @version $Revision$
+ * 
+ */
+@Path("ingest")
+public class IngestionResource extends CurationService {
+
+  private static final long serialVersionUID = -7514150767897700936L;
+
+  private static final Logger LOG = Logger.getLogger(IngestionResource.class
+      .getName());
+
+  private static final String DATA_TRANSFER_SERVICE = "org.apache.oodt.cas.filemgr.datatransfer.LocalDataTransferFactory";
+
+  private static final String RESP_SUCCESS = "success";
+
+  private IngestionTaskList taskList;
+
+  public IngestionResource() {
+    super();
+    this.taskList = new IngestionTaskList();
+    IngestionTask task = new IngestionTask();
+    task.setCreateDate(new Date());
+
+  }
+
+  @Context
+  UriInfo uriInfo;
+
+  @GET
+  @Path("create")
+  @Produces("text/plain")
+  public String createTask(@QueryParam("files") String fileList,
+      @QueryParam("numfiles") Integer numFiles,
+      @QueryParam("metExtCfgId") String metExtractorConfigId,
+      @QueryParam("policy") String policy,
+      @QueryParam("ptype") String productType) {
+
+    IngestionTask newTask = new IngestionTask();
+    newTask.setCreateDate(new Date());
+    try {
+      newTask.setExtConf(ExtractorConfigReader.readFromDirectory(new File(
+          CurationService.config.getMetExtrConfUploadPath()),
+          metExtractorConfigId));
+    } catch (Exception e) {
+      e.printStackTrace();
+      String errorMsg = "Unable to load extractor config from metExtCfgId: ["
+          + metExtractorConfigId + "]";
+      LOG.log(Level.WARNING, errorMsg);
+      return errorMsg;
+    }
+    newTask.setFileList(deducePaths(Arrays.asList(fileList.split(","))));
+    newTask.setPolicy(policy);
+    newTask.setProductType(productType);
+    newTask.setStatus(IngestionTask.NOT_STARTED);
+    return this.taskList.addIngestionTask(newTask);
+  }
+
+  @GET
+  @Path("remove")
+  @Produces("text/plain")
+  public void removeTask(@QueryParam("taskId") String ingestTaskId) {
+	  this.taskList.removeIngestionTask(ingestTaskId);
+  }
+
+  @GET
+  @Path("list")
+  @Produces("text/plain")
+  public String getIngestTaskList(
+      @QueryParam("format") @DefaultValue(FORMAT_HTML) String format) {
+    if (format.equals(FORMAT_HTML)) {
+      return this.encodeTaskListAsHTML(this.taskList.getTaskList());
+    } else if (format.equals(FORMAT_JSON)) {
+      return this.encodeTaskListAsJSON(this.taskList.getTaskList());
+    } else {
+      return "Unsupported Format!";
+    }
+  }
+
+  @GET
+  @Path("start")
+  @Produces("text/plain")
+  public String doIngest(@QueryParam("taskId") String ingestTaskId) {
+    IngestionTask task = this.taskList.getIngestionTaskById(ingestTaskId);
+    if (task == null) {
+      String errorMsg = "Task with ID [" + ingestTaskId
+          + "] is not being managed by this Ingestion Resource!";
+      LOG.log(Level.WARNING, errorMsg);
+      return this.encodeIngestResponseAsJSON(false, errorMsg);
+    }
+
+    Ingester ingest = this.configureIngester();
+    MetadataResource metService = new MetadataResource();
+    for (String file : task.getFileList()) {
+      Metadata fileMet = null;
+      try {
+        String vFilePath = this.getVirtualPath(CurationService.config
+            .getStagingAreaPath(), file);
+        LOG.log(Level.FINE,
+            "IngestionResource: getting staging metadata for virtual path: ["
+                + vFilePath + "]");
+        fileMet = metService.getStagingMetadata(vFilePath, task.getExtConf()
+            .getIdentifier(), false);
+      } catch (Exception e) {
+        e.printStackTrace();
+        return this.encodeIngestResponseAsHTML(false, e.getMessage());
+      }
+
+      try {
+        ingest.ingest(safeGetUrl(CurationService.config.getFileMgrURL()),
+            new File(file), fileMet);
+      } catch (IngestException e) {
+        e.printStackTrace();
+        return this.encodeIngestResponseAsHTML(false, e.getMessage());
+      }
+
+      // set task status to success
+      task.setStatus(IngestionTask.FINISHED);
+    }
+
+    return this.encodeIngestResponseAsHTML(true, null);
+  }
+
+  private String encodeTaskListAsHTML(List<IngestionTask> taskList) {
+    StringBuffer out = new StringBuffer();
+
+    for (IngestionTask task : taskList) {
+      out.append("<tr>");
+      out.append("<td>");
+      out.append(task.getId());
+      out.append("</td><td>");
+      out.append(DateUtils.getDateAsISO8601String(task.getCreateDate()));
+      out.append("</td><td>");
+      out.append(task.getFileList().size());
+      out.append("</td><td>");
+      out.append(task.getPolicy());
+      out.append("</td><td>");
+      out.append(task.getProductType());
+      out.append("</td><td>");
+      out.append(task.getExtConf().getIdentifier());
+      out.append("</td><td>");
+      out.append(task.getExtConf().getConfigFiles().size());
+      out.append("</td><td id='");
+      out.append(task.getId());
+      out.append("_Status'>");
+      out.append(task.getStatus());
+      out.append("</td>");
+      if (!task.getStatus().equals(IngestionTask.FINISHED)) {
+        out.append("<td><input type=\"button\" rel=\"_taskid_\" value=\"Start\" onclick=\"startIngestionTask('");
+        out.append(task.getId());
+        out.append("')\"/></td>");
+      } else {
+		out.append("<td><input type=\"button\" rel=\"_taskid_\" value=\"Remove\" onclick=\"removeIngestionTask('");
+		out.append(task.getId());
+		out.append("')\"></td>");
+      }
+
+      out.append("</tr>");
+    }
+    return out.toString();
+  }
+
+  private String encodeTaskListAsJSON(List<IngestionTask> taskList) {
+    List<Map<String, String>> jsonFriendlyTaskList = new Vector<Map<String, String>>();
+    for (IngestionTask task : taskList) {
+      Map<String, String> taskPropMap = new HashMap<String, String>();
+      taskPropMap.put("id", task.getId());
+      taskPropMap.put("createDate", DateUtils.getDateAsISO8601String(task
+          .getCreateDate()));
+      taskPropMap.put("policy", task.getPolicy());
+      taskPropMap.put("productType", task.getProductType());
+      taskPropMap.put("status", task.getStatus());
+      taskPropMap.put("fileList", task.getFileList().toString());
+      taskPropMap.put("extractorClass", task.getExtConf().getClassName());
+      taskPropMap.put("extractorConfFiles", task.getExtConf().getConfigFiles()
+          .toString());
+      jsonFriendlyTaskList.add(taskPropMap);
+    }
+
+    JSONObject resObj = new JSONObject();
+    resObj.put("taskList", jsonFriendlyTaskList);
+    return resObj.toString();
+
+  }
+
+  private String encodeIngestResponseAsHTML(boolean success, String msg) {
+    StringBuffer out = new StringBuffer();
+    if (success) {
+      out.append("Success");
+    } else {
+      out.append(msg);
+    }
+    return out.toString();
+  }
+
+  private String encodeIngestResponseAsJSON(boolean success, String msg) {
+    Map<String, Object> resMap = new HashMap<String, Object>();
+    resMap.put("success", success);
+    resMap.put("msg", msg);
+    JSONObject resObj = new JSONObject();
+    resObj.putAll(resMap);
+    return resObj.toString();
+
+  }
+
+  private Ingester configureIngester() {
+    StdIngester ingest = new StdIngester(DATA_TRANSFER_SERVICE);
+    return ingest;
+  }
+
+  private URL safeGetUrl(String urlStr) {
+    try {
+      return new URL(urlStr);
+    } catch (Exception e) {
+      e.printStackTrace();
+      return null;
+    }
+  }
+
+  private List<String> deducePaths(List<String> vPaths) {
+    List<String> absolutePaths = new Vector<String>();
+    String stagingIngestPath = CurationService.config.getStagingAreaPath();
+    if (!stagingIngestPath.endsWith("/")) {
+      stagingIngestPath += "/";
+    }
+
+    for (String vPath : vPaths) {
+      String realPath = stagingIngestPath + vPath;
+      absolutePaths.add(realPath);
+    }
+
+    return absolutePaths;
+  }
+
+  private String getVirtualPath(String stagingAreaPath, String fullFilePath) {
+    int startIdx = stagingAreaPath.length();
+    try {
+      return fullFilePath.substring(startIdx);
+    } catch (Exception e) {
+      e.printStackTrace();
+      return null;
+    }
+  }
+
+  class IngestionTaskList {
+
+    private HashMap<String, IngestionTask> taskMap;
+
+    public IngestionTaskList() {
+      this.taskMap = new HashMap<String, IngestionTask>();
+    }
+
+    public synchronized String addIngestionTask(IngestionTask task) {
+      this.provideTaskId(task);
+      taskMap.put(task.getId(), task);
+      return task.getId();
+    }
+
+    public synchronized void removeIngestionTask(String taskId) {
+      taskMap.remove(taskId);
+    }
+
+    public IngestionTask getIngestionTaskById(String taskId) {
+      return taskMap.get(taskId);
+    }
+
+    public List<IngestionTask> getTaskList() {
+      List<IngestionTask> taskList = Arrays.asList(taskMap.values().toArray(
+          new IngestionTask[taskMap.values().size()]));
+      Collections.sort(taskList, new Comparator<IngestionTask>() {
+
+        public int compare(IngestionTask o1, IngestionTask o2) {
+          if (o1.getCreateDate().before(o2.getCreateDate())) {
+            return -1;
+          } else if (o1.getCreateDate().equals(o2.getCreateDate())) {
+            return 0;
+          } else
+            return 1;
+        }
+      });
+      return taskList;
+    }
+
+    private void provideTaskId(IngestionTask task) {
+      UUID id = UUID.randomUUID();
+      task.setId(id.toString());
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/a47b088a/curator2/src/main/java/org/apache/oodt/cas/curation/service/MetadataResource.java
----------------------------------------------------------------------
diff --git a/curator2/src/main/java/org/apache/oodt/cas/curation/service/MetadataResource.java b/curator2/src/main/java/org/apache/oodt/cas/curation/service/MetadataResource.java
new file mode 100644
index 0000000..77eba3f
--- /dev/null
+++ b/curator2/src/main/java/org/apache/oodt/cas/curation/service/MetadataResource.java
@@ -0,0 +1,970 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.oodt.cas.curation.service;
+
+//JDK imports
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+//JAX-RS imports
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+
+
+//JSON imports
+import net.sf.json.JSONArray;
+import net.sf.json.JSONObject;
+import net.sf.json.JSONSerializer;
+
+
+
+//OODT imports
+import org.apache.oodt.cas.curation.service.CurationService;
+import org.apache.oodt.cas.curation.structs.ExtractorConfig;
+import org.apache.oodt.cas.curation.util.CurationXmlStructFactory;
+import org.apache.oodt.cas.curation.util.ExtractorConfigReader;
+import org.apache.oodt.cas.filemgr.catalog.Catalog;
+import org.apache.oodt.cas.filemgr.repository.XMLRepositoryManager;
+import org.apache.oodt.cas.filemgr.structs.Element;
+import org.apache.oodt.cas.filemgr.structs.Product;
+import org.apache.oodt.cas.filemgr.structs.ProductType;
+import org.apache.oodt.cas.filemgr.structs.Reference;
+import org.apache.oodt.cas.filemgr.structs.exceptions.CatalogException;
+import org.apache.oodt.cas.filemgr.structs.exceptions.RepositoryManagerException;
+import org.apache.oodt.cas.filemgr.structs.exceptions.ValidationLayerException;
+import org.apache.oodt.cas.filemgr.system.XmlRpcFileManagerClient;
+import org.apache.oodt.cas.filemgr.util.GenericFileManagerObjectFactory;
+import org.apache.oodt.cas.filemgr.validation.XMLValidationLayer;
+import org.apache.oodt.cas.metadata.MetExtractor;
+import org.apache.oodt.cas.metadata.Metadata;
+import org.apache.oodt.cas.metadata.SerializableMetadata;
+import org.apache.oodt.cas.metadata.exceptions.MetExtractionException;
+import org.apache.oodt.cas.metadata.util.GenericMetadataObjectFactory;
+
+//SPRING imports
+import org.springframework.util.StringUtils;
+
+@Path("metadata")
+/**
+ * 
+ * A web-service endpoint for dealing with CAS {@link Metadata} object.
+ * 
+ * @author pramirez
+ * @version $Id$
+ */
+public class MetadataResource extends CurationService {
+  
+  @Context
+  UriInfo uriInfo;
+  
+  @Context 
+  private ServletContext context;
+
+  private static final long serialVersionUID = 1930946924218765724L;
+
+  public static final String STAGING = "staging";
+
+  public static final String CATALOG = "catalog";
+
+  public static final String PRODUCT_TYPE = "productType";
+  
+  public static final String UPDATE = "update";
+  
+  public static final String DELETE = "delete";
+  
+  // single instance of CAS catalog shared among all requests
+  private Catalog catalog = null;
+    
+  public MetadataResource(){
+    
+  }
+
+  public MetadataResource(@Context ServletContext context) {
+  	
+  }
+
+  @GET
+  @Path(STAGING)
+  @Produces("text/plain")
+  public String getStagingMetadata(@QueryParam("id") String id,
+      @DefaultValue(FORMAT_HTML) @QueryParam("format") String format,
+      @QueryParam("configId") String configId,
+      @DefaultValue("false") @QueryParam("overwrite") Boolean overwrite,
+      @Context HttpServletRequest req, @Context HttpServletResponse res) {
+    
+      // this.sendRedirect("login.jsp", uriInfo, res);
+
+      Metadata metadata = null;
+      
+      try {
+        metadata = this.getStagingMetadata(id, configId, overwrite);
+      } catch (Exception e) {
+        return "<div class=\"error\">" + e.getMessage() + "</div>";
+      }
+      
+      if (FORMAT_HTML.equals(format)) {
+        return this.getMetadataAsHTML(metadata);
+      }
+      return this.getMetadataAsJSON(metadata).toString();
+  }
+  
+  @GET
+  @Path("extractor/config")
+  @Produces("text/plain")
+  public String getMetExtractorConfigList(
+      @DefaultValue("") @QueryParam("current") String current,
+      @DefaultValue(FORMAT_HTML) @QueryParam("format") String format) {
+    String[] configIds = this.getFilesInDirectory(this.config
+        .getMetExtrConfUploadPath(), false);
+
+    if (FORMAT_HTML.equals(format)) {
+      return this.getExtractorConfigIdsAsHTML(configIds, current);
+    }
+    return this.getExtractorConfigIdsAsJSON(configIds);
+  }
+
+  protected String getExtractorConfigIdsAsHTML(String[] configIds,
+      String current) {
+    StringBuffer html = new StringBuffer();
+    for (int i = 0; i < configIds.length; i++) {
+      html.append("<option ");
+      if (configIds[i].equals(current)) {
+        html.append("selected ");
+      }
+      html.append("value=\"");
+      html.append(configIds[i]);
+      html.append("\">");
+      html.append(configIds[i]);
+      html.append("</option>\r\n");
+    }
+    return html.toString();
+  }
+  
+  protected String getExtractorConfigIdsAsJSON(String[] configIds) {
+    // TODO: Support JSON WHY, OH WHY!!!
+    return "Not Implemented...";
+  }
+
+  /**
+   * 
+   * @param id
+   *          Relative path from staging root to product. The met extension will
+   *          be added to this id to look up and see if a met file exists with
+   *          in the met area.
+   * @param configId
+   *          Reference to the extractor config. {@link ExtractorConfigReader}
+   *          will load the configuration
+   * @param overwrite
+   *          Flag to indicate whether or not to overwrite a met file if present
+   *          in the staging area.
+   * @return The {@link Metadata} retrieved from the met area path if present or
+   *         extracted using the met extractor config.
+   * @throws FileNotFoundException
+   * @throws InstantiationException
+   * @throws IOException
+   * @throws MetExtractionException
+   */
+  protected Metadata getStagingMetadata(String id, String configId,
+      Boolean overwrite) throws FileNotFoundException, InstantiationException,
+      IOException, MetExtractionException {
+    if (configId == null || configId.trim().length() == 0) {
+      return this.readMetFile(id + CurationService.config.getMetExtension());
+    } else {
+      String relMetPath = id.startsWith("/") ? id : "/" + id;
+      String pathToMetFile = CurationService.config.getMetAreaPath()
+          + relMetPath + CurationService.config.getMetExtension();
+      if (!overwrite && new File(pathToMetFile).exists()) {
+        return this.readMetFile(id + CurationService.config.getMetExtension());
+      } else {
+        // Make sure the parent directory exists
+        new File(pathToMetFile).getParentFile().mkdirs();
+        Metadata metadata = this.runMetExtractor(id, ExtractorConfigReader
+            .readFromDirectory(
+                new File(CurationService.config
+                .getMetExtrConfUploadPath()), configId));
+        this.writeMetFile(id, metadata);
+        return metadata;
+      }
+    }
+  }
+
+  /**
+   * 
+   * @param id
+   *          Relative path from staging root to the product
+   * @param config
+   *          Configuration to run this met extractor
+   * @return
+   * @throws MetExtractionException
+   */
+  protected Metadata runMetExtractor(String id, ExtractorConfig config)
+      throws MetExtractionException {
+    MetExtractor metExtractor = GenericMetadataObjectFactory
+        .getMetExtractorFromClassName(config.getClassName());
+    metExtractor.setConfigFile(config.getConfigFiles().get(0));
+    return metExtractor.extractMetadata(CurationService.config
+        .getStagingAreaPath()
+        + "/" + id);
+  }
+  
+  @GET
+  @Path(CATALOG)
+  @Produces("text/plain")
+  public String getCatalogMetadata(@QueryParam("id") String id,
+      @DefaultValue(FORMAT_HTML) @QueryParam("format") String format,
+      @Context HttpServletRequest req, @Context HttpServletResponse res) {
+
+      // this.sendRedirect("login.jsp", uriInfo, res);
+      // Call file manager to get metadata
+      Product prod;
+      Metadata metadata;
+      String productId = id.substring(id.lastIndexOf("/") + 1);
+
+      try {
+        prod = CurationService.config.getFileManagerClient().getProductById(
+          productId);
+        metadata = this.getCatalogMetadata(prod);
+      } catch (Exception e) {
+        return "<div class=\"error\">" + e.getMessage() + "</div>";
+      }
+
+      if (FORMAT_HTML.equals(format)) {
+        return this.getMetadataAsHTML(metadata);
+      }
+      return this.getMetadataAsJSON(metadata).toString();
+  }
+
+  @POST
+  @Path(CATALOG)
+  @Consumes("application/x-www-form-urlencoded")
+  @Produces("text/plain")
+  public String setCatalogMetadata(MultivaluedMap<String, String> formParams,
+      @FormParam("id") String id) {
+  	
+    Product prod;
+    Metadata metadata = this.getMetadataFromMap(formParams);
+    
+    String productId = id.substring(id.lastIndexOf("/") + 1);
+
+    try {
+      prod = CurationService.config.getFileManagerClient().getProductById(
+          productId);
+      this.updateCatalogMetadata(prod, metadata);
+    } catch (Exception e) {
+      e.printStackTrace();
+      return "<div class=\"error\">" + e.getMessage() + "</div>";
+    }
+
+    return this.getMetadataAsHTML(metadata);
+  }
+  
+  @GET
+  @Path(PRODUCT_TYPE)
+  @Produces("text/plain")
+  public String getProductTypeMetadata(@QueryParam("id") String id,
+      @DefaultValue(FORMAT_HTML) @QueryParam("format") String format,
+      @Context HttpServletRequest req, @Context HttpServletResponse res) {
+
+    // this.sendRedirect("login.jsp", uriInfo, res);
+
+    Metadata metadata;
+    String[] idParts = id.split("/", 3);
+    String policy = idParts[1];
+    String productType = idParts[2];
+    productType = productType.substring(0, productType.lastIndexOf("/"));
+    try {
+      metadata = getProductTypeMetadataForPolicy(policy, productType);
+    } catch (Exception e) {
+      return "<div class=\"error\">" + e.getMessage() + "</div>";
+    }
+
+    if (FORMAT_HTML.equals(format)) {
+      return this.getMetadataAsHTML(metadata);
+    }
+    return this.getMetadataAsJSON(metadata).toString();
+  }
+  
+
+  @POST
+  @Path(PRODUCT_TYPE)
+  @Consumes("application/x-www-form-urlencoded")
+  @Produces("text/plain")
+  public String setProductTypeMetadata(MultivaluedMap<String, String> formParams) {
+    String[] idParts = formParams.getFirst("id").split("/");
+    String policy = idParts[1];
+    String productType = idParts[2];
+    try {
+    this.writeProductTypeMetadata(policy, productType, this
+        .getMetadataFromMap(formParams));
+    } catch (Exception e) {
+      return "<div class=\"error\">" + e.getMessage() + "</div>";
+    }
+    return "";
+  }
+
+  @POST
+  @Path(STAGING)
+  @Consumes("application/x-www-form-urlencoded")
+  @Produces("text/plain")
+  public String setStagingMetadata(MultivaluedMap<String, String> formParams) {
+    try {
+      this.writeMetFile(formParams.getFirst("id"), this
+          .getMetadataFromMap(formParams));
+    } catch (Exception e) {
+      return "<div class=\"error\">" + e.getMessage() + "</div>";
+    }
+    return "";
+  }
+
+  @GET
+  @Path("staging/info")
+  @Produces("text/plain")
+  public String getMetadataInfo(@QueryParam("id") String id) {
+
+      return "Staging met info";
+  }
+  
+
+  private JSONObject getMetadataAsJSON(Metadata metadata) {
+    return JSONObject.fromObject(metadata.getHashTable());
+  }
+
+  private Metadata getMetadataFromJSON(String metadataJSON) {
+    JSONObject json = (JSONObject) JSONSerializer.toJSON(metadataJSON);
+    Metadata metadata = new Metadata();
+
+    Set<String> keys = json.keySet();
+    for (String key : keys) {
+      List values = (List) JSONSerializer.toJava((JSONArray) json.get(key));
+      metadata.addMetadata(key, values);
+    }
+
+    return metadata;
+  }
+  
+  private Metadata getMetadataFromMap(MultivaluedMap<String, String> formParams) {
+    Metadata metadata = new Metadata();
+    
+    for (String key : formParams.keySet()) {
+      if (key.startsWith("metadata.")) {
+        String newKey = key.substring(key.indexOf('.') + 1);
+        for (String value : formParams.get(key)) {
+          metadata.addMetadata(newKey, value);
+        }
+      }
+    }
+    
+    return metadata;
+  }
+  
+  protected String getMetadataAsHTML(Metadata metadata) {
+    if (metadata == null) {
+      return "<table></table>";
+    }
+
+    StringBuffer html = new StringBuffer();
+
+    html.append("<table>\r\n");
+    for (String key : (Set<String>) metadata.getHashTable().keySet()) {
+      html.append(" <tr>\r\n");
+      html.append("  <th>").append(key).append("</th>\r\n");
+      html.append("  <td class=\"").append(key).append("\">");
+      List<String> values = metadata.getAllMetadata(key);
+      for (Iterator<String> i = values.iterator(); i.hasNext();) {
+        html.append("<span>").append(i.next()).append("</span>");
+        if (i.hasNext()) {
+          html.append(", ");
+        }
+      }
+      for (String value : (List<String>) metadata.getAllMetadata(key)) {
+      }
+      html.append("</td>\r\n");
+      html.append(" </tr>\r\n");
+    }
+    html.append("</table>\r\n");
+
+    return html.toString();
+  }
+  
+
+  /**
+   * Reads a {@link Metadata} object from a String representation of a .met
+   * {@link File}.
+   * 
+   * @param file
+   *          The full path to the .met {@link File}.
+   * @return The read-in CAS {@link Metadata} object.
+   * @throws InstantiationException
+   * @throws InstantiationException
+   *           If there is an error instantiating the {@link Metadata} class.
+   * @throws IOException
+   * @throws FileNotFoundException
+   * @throws FileNotFoundException
+   *           If the .met {@link File} is not found.
+   * @throws IOException
+   *           If there is an IO problem opening the met file.
+   */
+  public Metadata readMetFile(String file) throws InstantiationException,
+      FileNotFoundException, IOException {
+    SerializableMetadata metadata = new SerializableMetadata("UTF-8", false);
+    metadata.loadMetadataFromXmlStream(new FileInputStream(config
+        .getMetAreaPath()
+        + "/" + file));
+
+    return metadata;
+  }
+
+  /**
+   * Retrieves the cataloged {@link Metadata} associated with a {@link Product}.
+   * 
+   * @param product
+   *          The {@link Product} to obtain cataloged {@link Metadata} for.
+   * @return The cataloged {@link Metadata} for {@link Product}.
+   * @throws CatalogException
+   *           If there is an error talking to the CAS File Manager
+   *           {@link Catalog}.
+   */
+  public Metadata getCatalogMetadata(Product product) throws CatalogException {
+    return CurationService.config.getFileManagerClient().getMetadata(
+        CurationService.config.getFileManagerClient().getProductById(
+            product.getProductId()));
+  }
+
+  /**
+   * Writes a CAS {@link Metadata} {@link File} using the given identifier.
+   * 
+   * @param id
+   *          The identifier of the .met file to write.
+   * @param metadata
+   *          The {@link Metadata} object to persist and write to a {@link File}
+   *          .
+   * @throws FileNotFoundException
+   *           If the .met {@link File} cannot be written.
+   * @throws IOException
+   *           If there is an IO exception writing the {@link File}.
+   */
+  public void writeMetFile(String id, Metadata metadata)
+      throws FileNotFoundException, IOException {
+    SerializableMetadata serMet = new SerializableMetadata(metadata, "UTF-8",
+        false);
+    serMet.writeMetadataToXmlStream(new FileOutputStream(new File(config
+        .getMetAreaPath(), id + config.getMetExtension())));
+  }
+  
+  /**
+   * Method to update the catalog metadata for a given product. 
+   * All current metadata fields will be preserved, 
+   * except those specified in the HTTP POST request as 'metadata.<field_name>=<field_value>'.
+   * 
+   * @param id
+   * 	identifier of CAS product - either 'id' or 'name' must be specified
+   * @param name
+   * 	name of CAS product - either 'id' or 'name' must be specified
+   * @param formParams
+   * 	HTTP (name, value) form parameters. The parameter names MUST start with "metadata."
+   * @param replace
+   * 	optional flag set to false to add the new metadata values to the existing values, for the given flags
+   */
+  @POST
+  @Path(UPDATE)
+  @Consumes("application/x-www-form-urlencoded")
+  @Produces("text/plain")
+  public String updateMetadata(MultivaluedMap<String, String> formParams, 
+		  @FormParam("id") String id, 
+		  @FormParam("name") String name, 
+		  @DefaultValue("true") @FormParam("replace") boolean replace,
+		  @DefaultValue("false") @FormParam("remove") boolean remove) {
+  		      
+  	// new metadata from HTTP POST request
+    Metadata newMetadata = this.getMetadataFromMap(formParams);
+    
+    // client for interacting with remote File Manager
+    XmlRpcFileManagerClient fmClient = CurationService.config.getFileManagerClient();
+ 
+    // empty metadata
+    Metadata metadata = new Metadata();
+    
+    try {
+    
+      // retrieve product from catalog
+      Product product = null;
+      if (StringUtils.hasText(id)) {
+    	  id = id.substring(id.lastIndexOf("/") + 1);
+    	  product = fmClient.getProductById(id);
+      } else if (StringUtils.hasText(name)) {
+    	  product = fmClient.getProductByName(name);
+      } else {
+    	  throw new Exception("Either the HTTP parameter 'id' or the HTTP parameter 'name' must be specified");
+      }
+            
+      // retrieve existing metadata
+      metadata = fmClient.getMetadata(product);
+
+      // remove product references (as they will be added later)
+      metadata.removeMetadata("reference_orig");
+      metadata.removeMetadata("reference_data_store");
+      metadata.removeMetadata("reference_fileSize");
+      metadata.removeMetadata("reference_mimeType");
+      
+      // merge new and existing metadata
+      metadata.addMetadata(newMetadata);
+      
+      // replace metadata values for keys specified in HTTP request (not others)
+      if (replace) {
+    	  for (String key : newMetadata.getAllKeys()) {
+    		  metadata.replaceMetadata(key, newMetadata.getAllMetadata(key));
+    	  }
+      }
+      
+      // remove metadata tags
+      if (remove) {
+	      for (String key : newMetadata.getAllKeys()) {
+	      	metadata.removeMetadata(key);
+	      }
+      }
+      
+      // insert old and new metadata
+      fmClient.updateMetadata(product, metadata);
+      
+      // return product id to downstream processors
+      return "id="+product.getProductId();
+          
+    } catch (Exception e) {
+    	
+      e.printStackTrace();
+      // return error message
+      throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);
+
+    }
+
+  }
+
+  /**
+   * Updates the cataloged {@link Metadata} for a {@link Product} in the CAS
+   * File Manager.
+   * 
+   * @param product
+   *          The {@link Product} to update {@link Metadata} for.
+   * @param newMetadata
+   *          The new {@link Metadata} to persist into the {@link Catalog}.
+   * @throws CatalogException
+   *           If any error occurs during the update.
+   * @throws IOException
+   * @throws FileNotFoundException
+   */
+  public void updateCatalogMetadata(Product product, Metadata newMetadata)
+      throws CatalogException, FileNotFoundException, IOException {
+    System.getProperties().load(
+        new FileInputStream(CurationService.config.getFileMgrProps()));
+    Catalog catalog = this.getCatalog();
+    
+    Metadata oldMetadata = catalog.getMetadata(product);
+    List<Reference> references = catalog.getProductReferences(product);
+    Product newProduct = new Product(product.getProductName(), product
+        .getProductType(), product.getProductStructure(), product
+        .getTransferStatus(), product.getProductReferences());
+    // Constructor is bugged and doesn't set transfer status
+    newProduct.setTransferStatus(product.getTransferStatus());
+    catalog.removeMetadata(oldMetadata, product);
+    catalog.removeProduct(product);
+    newProduct.setProductId(product.getProductId());
+    catalog.addProduct(newProduct);
+    newProduct.setProductReferences(references);
+    catalog.addProductReferences(newProduct);
+    catalog.addMetadata(newMetadata, newProduct);
+  }
+
+  /**
+   * Method to delete a specific product from the catalog
+   * 
+   * @param id
+   * 	identifier of CAS product - either 'id' or 'name' must be specified
+   * @param name
+   * 	name of CAS product - either 'id' or 'name' must be specified
+   * @return the product ID of the deleted product if deletion successful
+   */
+  @POST
+  @Path(DELETE)
+  @Consumes("application/x-www-form-urlencoded")
+  @Produces("text/plain")
+  public String deleteCatalogMetadata(
+		  @FormParam("id") String id, 
+		  @FormParam("name") String name) {
+
+	  try {
+		  // retrieve product from catalog
+		  Product product = null;
+		  if (StringUtils.hasText(id)) {
+			  id = id.substring(id.lastIndexOf("/") + 1);
+			  product = CurationService.config.getFileManagerClient().getProductById(id);
+		  } else if (StringUtils.hasText(name)) {
+			  product = CurationService.config.getFileManagerClient().getProductByName(name);
+		  } else {
+			  throw new Exception("Either the HTTP parameter 'id' or the HTTP parameter 'name' must be specified");
+		  }
+
+		  // remove product from catalog
+		  this.deleteCatalogProduct(product);
+
+		  // return product id to downstream processors
+		  return "id="+product.getProductId();
+
+	  } catch (Exception e) {
+
+		  e.printStackTrace();
+		  // return error message
+		  throw new WebApplicationException(e, Response.Status.INTERNAL_SERVER_ERROR);
+
+	  }
+  }  
+
+  /**
+   * Deletes a given product from the catalog
+   * 
+   * @param product
+   *          The {@link Product} to delete
+   * @throws FileNotFoundException
+   * @throws IOException
+   * @throws CatalogException
+   *           If any error occurs during this delete operation.
+   */
+  public void deleteCatalogProduct(Product product) 
+  throws FileNotFoundException, IOException, CatalogException {
+	  CurationService.config.getFileManagerClient().removeProduct(product);
+  }  
+
+  private Metadata getProductTypeMetadataForPolicy(String policy,
+      String productTypeName) throws MalformedURLException,
+      InstantiationException, RepositoryManagerException {
+    String rootPolicyPath = this.cleanse(CurationService.config
+        .getPolicyUploadPath());
+    String policyPath = new File(rootPolicyPath + policy).toURL()
+        .toExternalForm();
+    String[] policies = { policyPath };
+    XMLRepositoryManager repMgr = new XMLRepositoryManager(Arrays
+        .asList(policies));
+    ProductType productType = repMgr.getProductTypeByName(productTypeName);
+    
+    return productType.getTypeMetadata();
+  }
+  
+  private Metadata writeProductTypeMetadata(String policy,
+      String productTypeName, Metadata metadata) throws Exception {
+    String rootPolicyPath = this.cleanse(CurationService.config
+        .getPolicyUploadPath());
+    String policyPath = new File(rootPolicyPath + policy).toURL()
+        .toExternalForm();
+    String[] policies = { policyPath };
+    XMLRepositoryManager repMgr = new XMLRepositoryManager(Arrays
+        .asList(policies));
+
+    ProductType productType = repMgr.getProductTypeByName(productTypeName);
+    productType.setTypeMetadata(metadata);
+    
+    CurationXmlStructFactory.writeProductTypeXmlDocument(repMgr
+        .getProductTypes(), rootPolicyPath + policy + "/product-types.xml");
+
+    // refresh the config on the fm end
+    CurationService.config.getFileManagerClient().refreshConfigAndPolicy();
+    
+    return productType.getTypeMetadata();
+  }
+  
+  private String cleanse(String origPath) {
+    String retStr = origPath;
+    if (!retStr.endsWith("/")) {
+      retStr += "/";
+    }
+    return retStr;
+  }
+  
+  // Method to instantiate the CAS catalog, if not done already.
+  private synchronized Catalog getCatalog() {
+  	
+  	if (catalog==null) {
+  		String catalogFactoryClass = this.context.getInitParameter(CATALOG_FACTORY_CLASS);
+  		// preserve backward compatibility
+  		if (!StringUtils.hasText(catalogFactoryClass))
+  			catalogFactoryClass = "org.apache.oodt.cas.filemgr.catalog.LuceneCatalogFactory";
+  		catalog = GenericFileManagerObjectFactory.getCatalogServiceFromFactory(catalogFactoryClass);
+  	}
+  	
+  	return catalog;
+  }
+  
+  @DELETE
+  @Path(PRODUCT_TYPE+"/remove")
+  @Produces("text/plain")
+  public boolean removeProductType(
+		  @FormParam("policy") String policy, 
+		  @FormParam("id") String id) {
+    XMLRepositoryManager xmlRepo = getRepo(policy);
+    try {
+      ProductType type = xmlRepo.getProductTypeById(id);
+      xmlRepo.removeProductType(type);
+      return true;
+    } catch (RepositoryManagerException e) {
+      e.printStackTrace();
+      return false;
+    }
+  }
+  
+  @GET
+  @Path(PRODUCT_TYPE+"/parentmap")
+  @Produces("text/plain")
+  public String getParentTypeMap(
+      @FormParam("policy") String policy) {
+    XMLValidationLayer vLayer = getValidationLayer(policy);
+    return JSONSerializer.toJSON(vLayer.getSubToSuperMap()).toString();
+  }
+	 
+  @POST
+  @Path(PRODUCT_TYPE+"/parent/add")
+  @Produces("text/plain")
+  public boolean addParentForProductType(
+      @FormParam("policy") String policy, 
+      @FormParam("id") String id, 
+      @FormParam("parentId") String parentId) {
+    XMLValidationLayer vLayer = getValidationLayer(policy);
+    XMLRepositoryManager xmlRepo = getRepo(policy);
+    try {
+      ProductType type = xmlRepo.getProductTypeById(id);
+      vLayer.addParentForProductType(type, parentId);
+      return true;
+    } catch (RepositoryManagerException e) {
+      e.printStackTrace();
+    }
+    return false;
+  }
+  
+  @DELETE
+  @Path(PRODUCT_TYPE+"/parent/remove")
+  @Produces("text/plain")
+  public boolean removeParentForProductType(
+      @FormParam("policy") String policy, 
+      @FormParam("id") String id) 
+          throws ValidationLayerException {
+    XMLValidationLayer vLayer = getValidationLayer(policy);
+    XMLRepositoryManager xmlRepo = getRepo(policy);
+    try {
+      ProductType type = xmlRepo.getProductTypeById(id);
+      vLayer.removeParentForProductType(type);
+      return true;
+    } catch (RepositoryManagerException e) {
+      e.printStackTrace();
+    }
+    return false;
+  }
+  
+  @POST
+  @Path(PRODUCT_TYPE+"/elements/add")
+  @Produces("text/plain")
+  public boolean addElementsForProductType(
+		  @FormParam("policy") String policy, 
+		  @FormParam("id") String id,  
+		  @FormParam("elementIds") String elementIds) {
+    XMLValidationLayer vLayer = getValidationLayer(policy);
+    XMLRepositoryManager xmlRepo = getRepo(policy);
+    try {
+      ProductType type = xmlRepo.getProductTypeById(id);
+      for(String elementid: elementIds.split(",")) {
+        Element element = vLayer.getElementById(elementid);
+        if(element == null) {
+          element = new Element(elementid, elementid, "", "", "Automatically added", "");
+          vLayer.addElement(element);
+        }
+        vLayer.addElementToProductType(type, element);
+      }
+      return true;
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return false;
+  }
+  
+  @GET
+  @Path(PRODUCT_TYPE+"/elements")
+  @Produces("text/plain")
+  public String getElementsForProductType(
+		  @FormParam("policy") String policy, 
+		  @FormParam("id") String id, 
+		  @FormParam("direct") boolean direct) {
+    XMLValidationLayer vLayer = getValidationLayer(policy);
+    XMLRepositoryManager xmlRepo = getRepo(policy);
+    try {
+      ProductType type = xmlRepo.getProductTypeById(id);
+      ArrayList<String> elementIds = new ArrayList<String>();
+      for(Element el : vLayer.getElements(type, direct)) {
+        elementIds.add(el.getElementId());
+      }
+      return JSONSerializer.toJSON(elementIds).toString();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return null;
+  }
+  
+  @DELETE
+  @Path(PRODUCT_TYPE+"/elements/remove/all")
+  @Produces("text/plain")
+  public boolean removeAllElementsForProductType(
+		  @FormParam("policy") String policy, 
+		  @FormParam("id") String id) {
+    XMLValidationLayer vLayer = getValidationLayer(policy);
+    XMLRepositoryManager xmlRepo = getRepo(policy);
+    try {
+      ProductType type = xmlRepo.getProductTypeById(id);
+      List<Element> elementList = vLayer.getElements(type);
+      for(Element element: elementList) {
+        vLayer.removeElementFromProductType(type, element);
+      }
+      this.removeUnusedElements(elementList, xmlRepo, vLayer);
+      return true;
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return false;
+  }
+
+  @DELETE
+  @Path(PRODUCT_TYPE+"/elements/remove")
+  @Produces("text/plain")
+  public boolean removeElementsForProductType(
+		  @FormParam("policy") String policy, 
+		  @FormParam("id") String id, 
+		  @FormParam("elementIds") String elementIds) {
+    XMLValidationLayer vLayer = getValidationLayer(policy);
+    XMLRepositoryManager xmlRepo = getRepo(policy);
+    try {
+      ProductType type = xmlRepo.getProductTypeById(id);
+      ArrayList<Element> elements = new ArrayList<Element>();
+      for(String elementId: elementIds.split(",")) {
+        Element element = vLayer.getElementById(elementId);
+        if(element != null) {
+          vLayer.removeElementFromProductType(type, element);
+          elements.add(element);
+        }
+      }
+      this.removeUnusedElements(elements, xmlRepo, vLayer);
+      return true;
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+    return false;
+  }
+  
+  @GET
+  @Path(PRODUCT_TYPE+"/typeswithelement/{elementId}")
+  @Produces("text/plain")
+  public String getProductTypeIdsHavingElement(
+		  @FormParam("policy") String policy, 
+		  @PathParam("elementId") String elementId) {
+	  XMLValidationLayer vLayer = getValidationLayer(policy);
+	  XMLRepositoryManager xmlRepo = getRepo(policy);
+	  ArrayList<String> typeids = new ArrayList<String>();
+      try {
+    	  for(ProductType type : xmlRepo.getProductTypes()) {
+    		  for(Element el : vLayer.getElements(type)) {
+    			  if(el.getElementId().equals(elementId))
+    				  typeids.add(type.getProductTypeId());
+    		  }
+    	  }
+      } catch (Exception e) {
+          e.printStackTrace();
+      }
+      return JSONSerializer.toJSON(typeids).toString();
+  }
+  
+  
+  /*
+   * Private helper functions
+   */
+  private void removeUnusedElements(List<Element> elements, 
+		  XMLRepositoryManager xmlRepo, XMLValidationLayer vLayer) 
+				  throws ValidationLayerException, RepositoryManagerException {
+      // Remove Elements that aren't used in any product type
+      List<ProductType> ptypelist = xmlRepo.getProductTypes();
+      HashMap<String, Boolean> usedElementIds = new HashMap<String, Boolean>();
+      for(ProductType ptype: ptypelist) {
+          List<Element> ptypeElements = 
+              vLayer.getElements(ptype);
+          for(Element el: ptypeElements) {
+              usedElementIds.put(el.getElementId(), true);
+          }
+      }
+      for(Element el: elements) {
+          if(!usedElementIds.containsKey(el.getElementId()))
+             vLayer.removeElement(el);
+      }
+  }  
+
+	private XMLRepositoryManager getRepo(String policy) {
+		XMLRepositoryManager xmlRepo = null;
+		String url = "file://" + CurationService.config.getPolicyUploadPath() + "/" + policy;
+
+		try {
+			xmlRepo = new XMLRepositoryManager(Collections.singletonList(url));
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+
+		return xmlRepo;
+	}
+
+	private XMLValidationLayer getValidationLayer(String policy) {
+		XMLValidationLayer vLayer = null;
+		String url = "file://" + CurationService.config.getPolicyUploadPath() + "/" + policy;
+
+		try {
+			vLayer = new XMLValidationLayer(Collections.singletonList(url));
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return vLayer;
+	}
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/a47b088a/curator2/src/main/java/org/apache/oodt/cas/curation/service/PolicyResource.java
----------------------------------------------------------------------
diff --git a/curator2/src/main/java/org/apache/oodt/cas/curation/service/PolicyResource.java b/curator2/src/main/java/org/apache/oodt/cas/curation/service/PolicyResource.java
new file mode 100644
index 0000000..ff98753
--- /dev/null
+++ b/curator2/src/main/java/org/apache/oodt/cas/curation/service/PolicyResource.java
@@ -0,0 +1,310 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.oodt.cas.curation.service;
+
+//OODT imports
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.oodt.cas.filemgr.repository.XMLRepositoryManager;
+import org.apache.oodt.cas.filemgr.structs.Product;
+import org.apache.oodt.cas.filemgr.structs.ProductPage;
+import org.apache.oodt.cas.filemgr.structs.ProductType;
+import org.apache.oodt.cas.filemgr.structs.Query;
+import org.apache.oodt.cas.filemgr.structs.exceptions.RepositoryManagerException;
+
+//JDK imports
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+//JAX-RS imports
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.DefaultValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+
+//JSON imports
+import net.sf.json.JSONObject;
+
+@Path("policy")
+public class PolicyResource extends CurationService {
+
+  @Context
+  UriInfo uriInfo;
+
+  private static final long serialVersionUID = -3757481221589264709L;
+
+  private static final Logger LOG = Logger.getLogger(PolicyResource.class
+      .getName());
+
+  private static final FilenameFilter DIR_FILTER = new FilenameFilter() {
+
+    public boolean accept(File dir, String name) {
+      return new File(dir, name).isDirectory()
+          && !new File(dir, name).getName().startsWith(".");
+    }
+  };
+  
+  public PolicyResource(@Context ServletContext context){
+    
+  }
+
+  @GET
+  @Path("browse")
+  @Produces("text/plain")
+  public String browseCatalog(
+      @QueryParam("path") @DefaultValue("/") String path,
+      @DefaultValue(FORMAT_HTML) @QueryParam("format") String format,
+      @DefaultValue("1") @QueryParam("pageNum") Integer pageNum,
+      @Context HttpServletRequest req, @Context HttpServletResponse res)
+      throws IOException {
+    
+    // TODO: Send a not authorized response if not logged in. This should be a
+    // utility method as a part of CurationService that every service interface
+    // calls.
+
+    String[] pathToks = tokenizeVirtualPath(path);
+    String policy = null;
+    String productType = null;
+
+    if (pathToks == null) {
+      LOG.log(Level.WARNING, "malformed path token string: "
+          + Arrays.asList(pathToks));
+      return "";
+    }
+
+    policy = pathToks.length > 0 ? pathToks[0]:null;
+    productType = pathToks.length > 1 ? pathToks[1] : null;
+
+    if (policy != null) {
+      if (productType != null) {
+        return getProductsForProductType(policy, productType, format, pageNum);
+      } else {
+        return getProductTypesForPolicy(policy, format);
+      }
+    } else {
+      return getPolicies(format);
+    }
+
+  }
+  
+  private String getProductsForProductType(String policy,
+      String productTypeName,
+      String format, int pageNum) {
+    
+    ProductType productType;
+    ProductPage page;
+    try {
+      productType = this.config.getFileManagerClient().getProductTypeByName(
+          productTypeName);
+      page = this.config.getFileManagerClient().pagedQuery(new Query(),
+          productType, pageNum);
+    } catch (Exception e) {
+      e.printStackTrace();
+      LOG.log(Level.WARNING, "Unable to obtain products for product type: ["
+          + productTypeName + "]: Message: " + e.getMessage());
+      return "";
+    }
+
+    if (format.equals(FORMAT_HTML)) {
+      return encodeProductsAsHTML(page, policy, productTypeName);
+    } else if (format.equals(FORMAT_JSON)) {
+      return encodeProductsAsJSON(page, policy, productTypeName);
+    } else {
+      return UNKNOWN_OUT_FORMAT;
+    }
+  }
+  
+  private String encodeProductsAsHTML(ProductPage page, String policy,
+      String productTypeName) {
+    StringBuffer html = new StringBuffer();
+    html.append("<ul class=\"fileTree\" >\r\n");
+    
+    for (Product product : page.getPageProducts()) {
+      html.append(" <li class=\"file\">");
+      html.append("<a href=\"#\" rel=\"/");
+      html.append(policy);
+      html.append("/");
+      html.append(productTypeName);
+      html.append("/");
+      html.append(product.getProductId());
+      html.append("\">");
+      html.append(product.getProductName());
+      html.append("</a>");
+      html.append("</li>\r\n");
+    }
+
+    html.append("</ul>");
+    return html.toString();
+  }
+  
+  private String encodeProductsAsJSON(ProductPage page, String policy,
+      String productTypeName) {
+    return "NOT IMPLENTED YET";
+  }
+
+  private String getPolicies(String format) {
+    String policyPath = this.cleanse(CurationService.config
+        .getPolicyUploadPath());
+    String[] policyDirs = new File(policyPath).list(DIR_FILTER);
+
+    if (format.equals(FORMAT_HTML)) {
+      return encodePoliciesAsHTML(policyDirs);
+    } else if (format.equals(FORMAT_JSON)) {
+      return encodePoliciesAsJSON(policyDirs);
+    } else {
+      return UNKNOWN_OUT_FORMAT;
+    }
+
+  }
+
+  private String getProductTypesForPolicy(String policy, String format) {
+    String[] typeNames = null;
+    try {
+      typeNames = this.getProductTypeNamesForPolicy(policy);
+    } catch (Exception e) {
+      e.printStackTrace();
+      LOG.log(Level.WARNING,
+          "Unable to obtain product type names for policy: [" + policy
+              + "]: Message: " + e.getMessage());
+      return "";
+    }
+
+    if (format.equals(FORMAT_HTML)) {
+      return encodeProductTypesAsHTML(policy, typeNames);
+    } else if (format.equals(FORMAT_JSON)) {
+      return encodeProductTypesAsJSON(policy, typeNames);
+    } else {
+      return UNKNOWN_OUT_FORMAT;
+    }
+
+  }
+
+  private String encodePoliciesAsHTML(String[] policyDirs) {
+    StringBuffer out = new StringBuffer();
+    out.append("<ul class=\"fileTree\" >");
+    for (String policy : policyDirs) {
+      out.append("<li class=\"directory collapsed\"><a href=\"#\" rel=\"/");
+      out.append(StringEscapeUtils.escapeHtml(policy));
+      out.append("/\">");
+      out.append(StringEscapeUtils.escapeHtml(policy));
+      out.append("</a></li>");
+    }
+    out.append("</ul>");
+    return out.toString();
+  }
+
+  private String encodePoliciesAsJSON(String[] policyDirs) {
+    Map<String, String> retMap = new HashMap<String, String>();
+    for (String policyDir : policyDirs) {
+      retMap.put("policy", policyDir);
+    }
+    JSONObject resObj = new JSONObject();
+    resObj.put("policies", retMap);
+    resObj.put("succeed", true);
+    return resObj.toString();
+  }
+
+  private String encodeProductTypesAsHTML(String policy, String[] typeNames) {
+    StringBuffer out = new StringBuffer();
+    out.append("<ul class=\"fileTree\" >");
+    for (String type : typeNames) {
+      out
+          .append("<li class=\"directory collapsed productType\"><a href=\"#\" rel=\"/");
+      out.append(StringEscapeUtils.escapeHtml(policy));
+      out.append("/");
+      out.append(StringEscapeUtils.escapeHtml(type));
+      out.append("/\">");
+      out.append(StringEscapeUtils.escapeHtml(type));
+      out.append("</a></li>");
+    }
+
+    out.append("</ul>");
+    return out.toString();
+  }
+
+  private String encodeProductTypesAsJSON(String policy, String[] typeNames) {
+    Map<String, Object> retMap = new HashMap<String, Object>();
+    retMap.put("policy", policy);
+    List<Map<String, String>> typeList = new Vector<Map<String, String>>();
+    for (String typeName : typeNames) {
+      Map<String, String> typeMap = new HashMap<String, String>();
+      typeMap.put("name", typeName);
+      typeList.add(typeMap);
+    }
+    retMap.put("productTypes", typeList);
+    JSONObject resObj = new JSONObject();
+    resObj.putAll(retMap);
+    return resObj.toString();
+  }
+
+  private String[] getProductTypeNamesForPolicy(String policy)
+      throws MalformedURLException, InstantiationException,
+      RepositoryManagerException {
+    String rootPolicyPath = this.cleanse(CurationService.config
+        .getPolicyUploadPath());
+    String policyPath = new File(rootPolicyPath + policy).toURL()
+        .toExternalForm();
+    String[] policies = { policyPath };
+    XMLRepositoryManager repMgr = new XMLRepositoryManager(Arrays
+        .asList(policies));
+    List<ProductType> types = repMgr.getProductTypes();
+    String[] typeNames = new String[types.size()];
+    int i = 0;
+    for (ProductType type : types) {
+      typeNames[i] = type.getName();
+      i++;
+    }
+
+    return typeNames;
+  }
+
+  private String cleanse(String origPath) {
+    String retStr = origPath;
+    if (!retStr.endsWith("/")) {
+      retStr += "/";
+    }
+    return retStr;
+  }
+
+  private String[] tokenizeVirtualPath(String path) {
+    String vPath = path;
+    if (vPath.startsWith("/") && vPath.length() != 1) {
+      vPath = vPath.substring(1);
+    }
+    String[] pathToks = vPath.split("/");
+    LOG.log(Level.INFO, "origPath: ["+path+"]");
+    LOG.log(Level.INFO, "pathToks: "+Arrays.asList(pathToks));
+    return pathToks;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/a47b088a/curator2/src/main/java/org/apache/oodt/cas/curation/service/SystemResource.java
----------------------------------------------------------------------
diff --git a/curator2/src/main/java/org/apache/oodt/cas/curation/service/SystemResource.java b/curator2/src/main/java/org/apache/oodt/cas/curation/service/SystemResource.java
new file mode 100644
index 0000000..784d383
--- /dev/null
+++ b/curator2/src/main/java/org/apache/oodt/cas/curation/service/SystemResource.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.oodt.cas.curation.service;
+
+//JAX-RS imports
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.UriInfo;
+
+@Path("system")
+public class SystemResource extends CurationService {
+
+  @Context
+  UriInfo uriInfo;
+  
+  private static final long serialVersionUID = -2318607955517605998L;
+
+  /**
+   * This is what will go in the upper left box on landing page. To gather
+   * information such as is the file manager up If this needs to be something
+   * that gets updated periodically then it would change into a JSON feed
+   */
+  @GET
+  @Path("stats")
+  @Produces("text/html")
+  public String getStatistics() {
+    return "<div>Server Stats</div>";
+  }
+
+  /**
+   * This returns the configuration information that is set in the context.xml
+   * file.
+   */
+  @GET
+  @Path("config")
+  @Produces("text/html")
+  public String getConfig() {
+    return "";
+  }
+
+  /**
+   * This will return the information that appears in the upper right box on
+   * landing page.
+   */
+  @GET
+  @Path("feed")
+  @Produces("text/html")
+  public String getFeed() {
+    return "<div>Latest Products?</div>";
+  }
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/a47b088a/curator2/src/main/java/org/apache/oodt/cas/curation/servlet/CuratorConfMetKeys.java
----------------------------------------------------------------------
diff --git a/curator2/src/main/java/org/apache/oodt/cas/curation/servlet/CuratorConfMetKeys.java b/curator2/src/main/java/org/apache/oodt/cas/curation/servlet/CuratorConfMetKeys.java
new file mode 100644
index 0000000..6233775
--- /dev/null
+++ b/curator2/src/main/java/org/apache/oodt/cas/curation/servlet/CuratorConfMetKeys.java
@@ -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.
+ */
+
+
+package org.apache.oodt.cas.curation.servlet;
+
+/**
+ * 
+ * Met keys used in the <code>context.xml</code> file to configure the CAS
+ * curator webapp.
+ * 
+ * @author mattmann
+ * @version $Revision$
+ * 
+ */
+public interface CuratorConfMetKeys {
+
+  final String MET_EXTRACTOR_CONF_UPLOAD_PATH = "org.apache.oodt.cas.curator.metExtractorConf.uploadPath";
+
+  final String POLICY_UPLOAD_PATH = "org.apache.oodt.cas.curator.dataDefinition.uploadPath";
+
+  final String FM_URL = "org.apache.oodt.cas.fm.url";
+
+  final String SSO_IMPL_CLASS = "org.apache.oodt.security.sso.implClass";
+
+  final String DEFAULT_TRANSFER_FACTORY = "org.apache.oodt.cas.filemgr.datatransfer.LocalDataTransferFactory";
+
+  final String CRAWLER_CONF_FILE = "classpath:/org.apache/oodt/cas/crawl/crawler-config.xml";
+
+  final String PROJECT_DISPLAY_NAME = "org.apache.oodt.cas.curator.projectName";
+
+  final String STAGING_AREA_PATH = "org.apache.oodt.cas.curator.stagingAreaPath";
+
+  final String MET_AREA_PATH = "org.apache.oodt.cas.curator.metAreaPath";
+  
+  final String MET_EXTENSION = "org.apache.oodt.cas.curator.metExtension";
+  
+  final String FM_PROPS = "org.apache.oodt.cas.curator.fmProps";
+  
+  final String CATALOG_FACTORY_CLASS = "org.apache.oodt.cas.curator.catalogFactoryClass";
+  
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/a47b088a/curator2/src/main/java/org/apache/oodt/cas/curation/servlet/CuratorServlet.java
----------------------------------------------------------------------
diff --git a/curator2/src/main/java/org/apache/oodt/cas/curation/servlet/CuratorServlet.java b/curator2/src/main/java/org/apache/oodt/cas/curation/servlet/CuratorServlet.java
new file mode 100644
index 0000000..aed7f14
--- /dev/null
+++ b/curator2/src/main/java/org/apache/oodt/cas/curation/servlet/CuratorServlet.java
@@ -0,0 +1,28 @@
+/**
+ * 
+ */
+package org.apache.oodt.cas.curation.servlet;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+
+import org.apache.oodt.cas.curation.configuration.Configuration;
+
+
+/**
+ * Handles basic servlet features like config
+ * 
+ * @author starchmd
+ */
+public class CuratorServlet extends HttpServlet {
+    
+    private static final long serialVersionUID = 1498427942585673418L;
+
+    @Override
+    public void init(ServletConfig conf) throws ServletException {
+        super.init(conf);
+        //Load configuration from context
+        Configuration.loadConfiguration(conf.getServletContext());
+    }
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/a47b088a/curator2/src/main/java/org/apache/oodt/cas/curation/structs/ExtractorConfig.java
----------------------------------------------------------------------
diff --git a/curator2/src/main/java/org/apache/oodt/cas/curation/structs/ExtractorConfig.java b/curator2/src/main/java/org/apache/oodt/cas/curation/structs/ExtractorConfig.java
new file mode 100644
index 0000000..79beb30
--- /dev/null
+++ b/curator2/src/main/java/org/apache/oodt/cas/curation/structs/ExtractorConfig.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.oodt.cas.curation.structs;
+
+import java.io.File;
+import java.util.List;
+/**
+ * A class holding the configuration for metadata extractors
+ * 
+ * @author starchmd - cleanup only, original author unspecified
+ */
+public class ExtractorConfig {
+
+    public final static String PROP_CLASS_NAME = "extractor.classname";
+    public final static String PROP_CONFIG_FILES = "extractor.config.files";
+    public final static String PROP_FILLER = "extractor.filler";
+
+    private final List<File> configFiles;
+    private final String className;
+    private final String identifier;
+    private final String filler;
+    /**
+     * Creates a new extractor configuration object
+     * @param identifier - name of this extractor
+     * @param className - class name of extractor
+     * @param configFiles - list of config file for this extractor (Note: only the first is used)
+     * @param filler - fill string for unextracted fields
+     */
+    public ExtractorConfig(String identifier, String className, List<File> configFiles, String filler) {
+      this.configFiles = configFiles;
+      this.className = className;
+      this.identifier = identifier;
+      this.filler = filler;
+    }
+    /**
+     * Gets the list of configuration files (Note: only the first, index 0, is used)
+     * @return config files
+     */
+    public List<File> getConfigFiles() {
+      return this.configFiles;
+    }
+    /**
+     * Accessor - get class name of this extractor
+     * @return class name
+     */
+    public String getClassName() {
+      return this.className;
+    }
+    /**
+     * Accessor - get identifier (i.e. name) of this extractor
+     * @return identifier
+     */
+    public String getIdentifier() {
+      return this.identifier;
+    }
+    /**
+     * Accessor - get the filler string
+     * @return filler
+     */
+    public String getFiller() {
+        return this.filler;
+    }
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/a47b088a/curator2/src/main/java/org/apache/oodt/cas/curation/structs/IngestionTask.java
----------------------------------------------------------------------
diff --git a/curator2/src/main/java/org/apache/oodt/cas/curation/structs/IngestionTask.java b/curator2/src/main/java/org/apache/oodt/cas/curation/structs/IngestionTask.java
new file mode 100644
index 0000000..d1a4327
--- /dev/null
+++ b/curator2/src/main/java/org/apache/oodt/cas/curation/structs/IngestionTask.java
@@ -0,0 +1,168 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.oodt.cas.curation.structs;
+
+//OODT imports
+import org.apache.oodt.cas.filemgr.ingest.Ingester;
+
+//JDK imports
+import java.util.Date;
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * 
+ * A specification for ingestion using the {@link Ingester} interface in the
+ * CAS.
+ * 
+ * @author mattmann
+ * @version $Revision$
+ * 
+ */
+public class IngestionTask implements IngestionTaskStatus {
+
+  private String id;
+
+  private Date createDate;
+
+  private List<String> fileList;
+
+  private String policy;
+
+  private String productType;
+
+  private String status;
+
+  private ExtractorConfig extConf;
+
+  public IngestionTask() {
+    this.id = null;
+    this.createDate = null;
+    this.fileList = new Vector<String>();
+    this.policy = null;
+    this.productType = null;
+    this.extConf = new ExtractorConfig(null, null, null,null);
+  }
+
+  /**
+   * @return the id
+   */
+  public String getId() {
+    return id;
+  }
+
+  /**
+   * @param id
+   *          the id to set
+   */
+  public void setId(String id) {
+    this.id = id;
+  }
+
+  /**
+   * @return the createDate
+   */
+  public Date getCreateDate() {
+    return createDate;
+  }
+
+  /**
+   * @param createDate
+   *          the createDate to set
+   */
+  public void setCreateDate(Date createDate) {
+    this.createDate = createDate;
+  }
+
+  /**
+   * @return the fileList
+   */
+  public List<String> getFileList() {
+    return fileList;
+  }
+
+  /**
+   * @param fileList
+   *          the fileList to set
+   */
+  public void setFileList(List<String> fileList) {
+    this.fileList = fileList;
+  }
+
+  /**
+   * @return the policy
+   */
+  public String getPolicy() {
+    return policy;
+  }
+
+  /**
+   * @param policy
+   *          the policy to set
+   */
+  public void setPolicy(String policy) {
+    this.policy = policy;
+  }
+
+  /**
+   * @return the productType
+   */
+  public String getProductType() {
+    return productType;
+  }
+
+  /**
+   * @param productType
+   *          the productType to set
+   */
+  public void setProductType(String productType) {
+    this.productType = productType;
+  }
+
+  /**
+   * @return the status
+   */
+  public String getStatus() {
+    return status;
+  }
+
+  /**
+   * @param status
+   *          the status to set
+   */
+  public void setStatus(String status) {
+    this.status = status;
+  }
+
+  /**
+   * @return the extConf
+   */
+  public ExtractorConfig getExtConf() {
+    return extConf;
+  }
+
+  /**
+   * @param extConf
+   *          the extConf to set
+   */
+  public void setExtConf(ExtractorConfig extConf) {
+    this.extConf = extConf;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/oodt/blob/a47b088a/curator2/src/main/java/org/apache/oodt/cas/curation/structs/IngestionTaskStatus.java
----------------------------------------------------------------------
diff --git a/curator2/src/main/java/org/apache/oodt/cas/curation/structs/IngestionTaskStatus.java b/curator2/src/main/java/org/apache/oodt/cas/curation/structs/IngestionTaskStatus.java
new file mode 100644
index 0000000..7527060
--- /dev/null
+++ b/curator2/src/main/java/org/apache/oodt/cas/curation/structs/IngestionTaskStatus.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.oodt.cas.curation.structs;
+
+/**
+ *
+ * Met keys for the {@link IngestionTask#getStatus()} field.
+ *
+ * @author mattmann
+ * @version $Revision$
+ *
+ */
+public interface IngestionTaskStatus {
+
+  public static final String FINISHED = "Finished";
+  
+  public static final String STARTED = "Started";
+  
+  public static final String NOT_STARTED = "Not Started";
+}