Package org.molgenis.framework.server

Source Code of org.molgenis.framework.server.RestInterface

package org.molgenis.framework.server;

import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.molgenis.framework.db.Database;
import org.molgenis.framework.db.QueryRule;
import org.molgenis.framework.ui.html.SelectInput;
import org.molgenis.framework.ui.html.StringInput;
import org.molgenis.io.TupleWriter;
import org.molgenis.io.csv.CsvWriter;
import org.molgenis.util.Entity;
import org.molgenis.util.tuple.HttpServletRequestTuple;
import org.molgenis.util.tuple.Tuple;

/**
* Implementation of the REST interface
*
* @author Morris Swertz
*/
public class RestInterface
{
  private static final Logger logger = Logger.getLogger(RestInterface.class);

  /**
   * Handle use of the REST api URL pattern /rest/find/[select]?[filter] and
   * /rest/count/[select]?[filter]<br>
   *
   * [select] should be either an entity name like '/rest/find/sample?...' or
   * an enumeration of field names like 'sample.id,sample.name' (not yet
   * implemented!)<br>
   *
   * [filter] should be of form field1>=value1&field2=4&LIMIT=1&SORTASC=field1<br>
   *
   * field names are need to be fully unique within the selection or fully
   * qualified<br>
   *
   * if fields are selected from multiple entities then a join path is
   * automatically calculated unless suitable join rules are defined like
   * 'entity1.field1JOINentity2.field2'
   *
   * Do we need enhancements: Aggregate functions and group by?
   */
  public static void handleRequest(HttpServletRequest request, HttpServletResponse response, Database db)
  {
    // setup the output-stream
    response.setBufferSize(10000);
    response.setContentType("text/html; charset=UTF-8");

    logger.info("starting REST request " + request.getPathInfo());
    long start_time = System.currentTimeMillis();

    if (request.getPathInfo().startsWith("/find") || request.getPathInfo().startsWith("/count")) handleRetrievalRequest(
        request, response, db);

    logger.info("servlet took: " + (System.currentTimeMillis() - start_time));
    logger.info("------------");
  }

  private static void handleRetrievalRequest(HttpServletRequest request, HttpServletResponse response, Database db)
  {
    try
    {
      PrintWriter out = response.getWriter();

      try
      {
        // check whether the url already includes the entity parameter
        // /rest/find/<selectparameters>
        if (request.getPathInfo().equals("/find") || request.getPathInfo().equals("/count"))
        {
          showSelectEntityDialog(out, db);
          return;
        }

        // retrieve entity name from request (if any)
        String entityName = request.getPathInfo().substring("/find/".length());
        if (request.getPathInfo().startsWith("/count/")) entityName = request.getPathInfo().substring(
            "/count/".length());
        Entity entity = (Entity) Class.forName(entityName).newInstance();
        // TODO this may be an enumeration of fields...

        // check whether a dialog for the filters has to be shown
        if (request.getQueryString() != null && request.getQueryString().equals("__showQueryDialogue=true"))
        {
          showSelectFilterDialogForEntity(entity, out, db);
          return;
        }

        // create query rules
        List<QueryRule> rulesList = createQueryRulesFromRequest(request);

        // execute query
        if (request.getPathInfo().startsWith("/count/"))
        {
          if (rulesList != null) db.count(getClassForName(entityName),
              rulesList.toArray(new QueryRule[rulesList.size()]));
          else
          {
            out.println(db.count(getClassForName(entityName)));
          }
        }
        else
        {
          TupleWriter csvWriter = new CsvWriter(out);
          try
          {
            if (rulesList != null) db.find(getClassForName(entityName), csvWriter,
                rulesList.toArray(new QueryRule[rulesList.size()]));
            else
            {
              db.find(getClassForName(entityName), csvWriter);
            }
          }
          finally
          {
            csvWriter.close();
          }
        }
      }
      catch (Exception e)
      {
        out.println(e + "<br>");
        e.printStackTrace();
        throw e;
      }
      finally
      {
        db.close();
      }

      out.close();
    }
    catch (Exception e)
    {
      logger.error(e);
    }
  }

  @SuppressWarnings("unchecked")
  /*
   * No way to do this without warnings.
   */
  private static Class<? extends Entity> getClassForName(String entityName) throws ClassNotFoundException
  {
    return (Class<? extends Entity>) Class.forName(entityName);
  }

  private static List<QueryRule> createQueryRulesFromRequest(HttpServletRequest request) throws Exception
  {
    List<QueryRule> rulesList;
    // use 'get' protocol
    if (request.getQueryString() != null)
    {
      logger.debug("handle find query via http-get: " + request.getQueryString());
      rulesList = QueryRuleUtil.fromRESTstring(URLDecoder.decode(request.getQueryString(), "UTF-8"));
    }
    // use 'post'
    else
    {
      Tuple requestTuple = new HttpServletRequestTuple(request);
      StringBuilder queryStringBuilder = new StringBuilder();
      for (String name : requestTuple.getColNames())
      {
        queryStringBuilder.append(URLDecoder.decode(name, "UTF-8")).append('=');
        queryStringBuilder.append(URLDecoder.decode(requestTuple.getString(name), "UTF-8"));
      }
      String queryString = queryStringBuilder.toString();
      logger.debug("handle find query via http-post with parameters: " + queryString);
      rulesList = QueryRuleUtil.fromRESTstring(queryString);
    }

    return rulesList;
  }

  private static void showSelectFilterDialogForEntity(Entity entity, PrintWriter out, Database db)
  {
    logger.debug("show 'set filters' dialogue");
    out.println("<html><body>");
    out.println("<head><script src=\"../../../res/scripts/rest.js\" language=\"javascript\"></script></head>");
    out.println("<h1>REST url wizard:</h1>");
    out.println("Step 2: choose filters<br>");
    out.println("<form>");
    out.println("You choose to use the REST interface for retrieval of '" + entity.getClass().getName()
        + "' data. (<a href=\"../find\">back</a>)<br><br> Here you can add filters:<br>");

    SelectInput fieldInput = new SelectInput("field", null);
    fieldInput.setOptions(entity.getFields().toArray(new String[entity.getFields().size()]));

    SelectInput operatorInput = new SelectInput("operator", null);
    List<String> operators = new ArrayList<String>();
    operators.add(QueryRule.Operator.EQUALS.toString());
    operators.add(QueryRule.Operator.GREATER_EQUAL.toString());
    operators.add(QueryRule.Operator.NOT.toString());
    operators.add(QueryRule.Operator.LESS.toString());
    operators.add(QueryRule.Operator.LESS_EQUAL.toString());
    operators.add(QueryRule.Operator.LIKE.toString());
    operatorInput.setOptions(operators.toArray(new String[operators.size()]));

    StringInput valueInput = new StringInput("value", null);

    out.println(fieldInput.getHtml() + operatorInput.getHtml() + valueInput.getHtml());
    out.println("<br>");

    out.println(fieldInput.getHtml() + operatorInput.getHtml() + valueInput.getHtml());
    out.println("<br>");

    out.println("<input type=\"submit\" value=\"generate url\" onclick=\"generateRestUrl(this.form.elements); return false\">");

    out.println("TIP: notice how the url is bookmarkeable for future downloads!");
    out.println("TIP: click 'save as...' and name it as '.txt' file.");
    out.println("</form></body></html>");
  }

  private static void showSelectEntityDialog(PrintWriter out, Database db)
  {
    logger.debug("show 'choose entity' dialogue");
    out.println("<html><body>");
    out.println("<h1>REST url wizard:</h1>");
    out.println("Step 1: choose entity<br>");

    for (String className : db.getEntityNames())
    {

      out.println(className + ": <a href=\"find/" + className
          + "?__showQueryDialogue=true\">find</a> or <a href=\"count/" + className
          + "?__showQueryDialogue=true\">count</a><br>");
    }

    // TODO enable a dialog for the selection of fields too

    out.println("</body></html>");

    logger.debug("done");

  }
}
TOP

Related Classes of org.molgenis.framework.server.RestInterface

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.