Package org.haystack.server

Source Code of org.haystack.server.HOp

//
// Copyright (c) 2012, Brian Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   25 Sep 2012  Brian Frank  Creation
//
package org.haystack.server;


import java.io.IOException;
import java.util.Iterator;
import java.util.Map.Entry;

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

import org.haystack.HDict;
import org.haystack.HDictBuilder;
import org.haystack.HGrid;
import org.haystack.HGridBuilder;
import org.haystack.io.HGridFormat;
import org.haystack.io.HGridWriter;
import org.haystack.io.HZincReader;
import org.haystack.tagval.HRef;
import org.haystack.tagval.HStr;
import org.haystack.tagval.HUri;
import org.haystack.tagval.HVal;

/**
* HOp is the base class for server side operations exposed by the REST API.
* All methods on HOp must be thread safe.
*
* @see <a href='http://project-haystack.org/doc/Ops'>Project Haystack</a>
*/
public abstract class HOp {
    /** Programatic name of the operation. */
    public abstract String name();

    /** Short one line summary of what the operation does. */
    public abstract String summary();

    /**
     * Service the request and return response.
     * This method routes to "onService(HServer,HGrid)".
     */
    public void onService(HServer db, HttpServletRequest req, HttpServletResponse res) throws Exception {
        // parse GET query parameters or POST body into grid
        HGrid reqGrid = HGrid.EMPTY;
        String method = req.getMethod();
        if (method.equals("GET"))
            reqGrid = getToGrid(req);
        if (method.equals("POST"))
            reqGrid = postToGrid(req, res);
        if (reqGrid == null)
            return;

        // figure out best format to use for response
        HGridFormat format = toFormat(req);

        // send response
        res.setStatus(HttpServletResponse.SC_OK);
        if (format.mime.startsWith("text/")) {
            res.setCharacterEncoding("UTF-8");
            res.setContentType(format.mime + "; charset=utf-8");
        }
        else
            res.setContentType(format.mime);

        HGridWriter writer = format.makeWriter(res.getOutputStream());
        try {
            onService(db, reqGrid, writer);
        }
        catch (Throwable e) {
            writeGrid(writer, HGridBuilder.errToGrid(e));
        }

        writer.flush();
    }

    /**
     * Service the request and return response.
     *
     * @param db
     * @param req
     * @param writer
     *            grid writer to which to write
     * @return
     * @throws Exception
     */
    public void onService(HServer db, HGrid req, HGridWriter writer) throws Exception {
        throw new UnsupportedOperationException(getClass().getName() + ".onService(HServer,HGrid)");
    }

    protected void writeGrid(HGridWriter writer, HGrid grid) {
        HGridWriter.writeGrid(writer, grid);
    }

    /**
     * Map the GET query parameters to grid with one row
     */
    private HGrid getToGrid(HttpServletRequest req) {
        if (req.getParameterMap() == null)
            return HGrid.EMPTY;

        HDictBuilder b = new HDictBuilder();
        @SuppressWarnings("unchecked")
        Iterator<Entry<String, String[]>> it = req.getParameterMap().entrySet().iterator();
        while (it.hasNext()) {
            Entry<String, String[]> entry = it.next();
            String name = entry.getKey();
            String valStr = entry.getValue()[0];

            HVal val;
            try {
                val = new HZincReader(valStr).readScalar();
            }
            catch (Exception e) {
                val = HStr.make(valStr);
            }
            b.add(name, val);
        }
        return HGridBuilder.dictToGrid(b.toDict());
    }

    /**
     * Map the POST body to grid
     */
    private HGrid postToGrid(HttpServletRequest req, HttpServletResponse res) throws IOException {
        // get content type
        String mime = req.getHeader("Content-Type");
        if (mime == null) {
            res.sendError(HttpServletResponse.SC_BAD_REQUEST, "Missing 'Content-Type' header");
            return null;
        }

        // check if we have a format that supports reading the content type
        HGridFormat format = HGridFormat.find(mime, false);
        if (format == null || format.reader == null) {
            res.sendError(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, "No format reader available for MIME type: "
                    + mime);
            return null;
        }

        // read the grid
        return format.makeReader(req.getInputStream()).readGrid();
    }

    /**
     * Find the best format to use for encoding response using
     * HTTP content negotiation.
     */
    private HGridFormat toFormat(HttpServletRequest req) {
        HGridFormat format = null;
        String accept = req.getHeader("Accept");
        if (accept != null) {
            String[] mimes = accept.split(",");
            for (int i = 0; i < mimes.length; ++i) {
                format = HGridFormat.find(mimes[i], false);
                if (format != null && format.writer != null)
                    break;
            }
        }
        if (format == null)
            format = HGridFormat.find("text/plain", true);
        return format;
    }

    HRef[] gridToIds(HServer db, HGrid grid) {
        HRef[] ids = new HRef[grid.numRows()];
        for (int i = 0; i < ids.length; ++i) {
            HVal val = grid.row(i).get("id");
            ids[i] = valToId(db, val);
        }
        return ids;
    }

    HRef valToId(HServer db, HVal val) {
        if (val instanceof HUri) {
            HDict rec = db.navReadByUri((HUri) val, false);
            return rec == null ? HRef.nullRef : rec.id();
        }
        return (HRef) val;
    }

}
TOP

Related Classes of org.haystack.server.HOp

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.