formatter.handler.get.FormatterGetHandler.java Source code

Java tutorial

Introduction

Here is the source code for formatter.handler.get.FormatterGetHandler.java

Source

/*
 * This file is part of Formatter.
 *
 *  Formatter is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  Formatter is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Formatter.  If not, see <http://www.gnu.org/licenses/>.
 *  (c) copyright Desmond Schmidt 2015
 */

package formatter.handler.get;

import calliope.AeseFormatter;
import formatter.exception.*;
import formatter.handler.FormatterHandler;
import formatter.path.Path;
import formatter.constants.Params;
import formatter.constants.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import calliope.core.Utils;
import calliope.core.database.Connector;
import calliope.core.handler.EcdosisVersion;
import calliope.core.constants.Database;
import calliope.core.constants.Formats;
import calliope.core.constants.JSONKeys;
import calliope.core.handler.EcdosisMVD;
import calliope.exception.AeseException;
import calliope.json.JSONResponse;
import calliope.json.corcode.Range;
import calliope.json.corcode.STILDocument;
import edu.luc.nmerge.mvd.MVD;
import edu.luc.nmerge.mvd.MVDFile;
import java.util.ArrayList;
import java.util.Map;
import java.util.Arrays;
import html.Comment;
import java.util.BitSet;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import java.io.File;
import java.io.FileWriter;

/**
 * Get a project document from the database
 * @author desmond
 */
public class FormatterGetHandler extends FormatterHandler {
    /** optional section ranges */
    String selections;

    public void handle(HttpServletRequest request, HttpServletResponse response, String urn)
            throws FormatterException {
        try {
            String prefix = Utils.first(urn);
            urn = Utils.pop(urn);
            if (prefix != null) {
                if (prefix.equals(Service.LIST)) {
                    new ListHandler().handle(request, response, Path.pop(urn));
                } else if (prefix.equals(Service.TABLE)) {
                    new TableHandler().handle(request, response, Path.pop(urn));
                } else if (prefix.equals(Service.VERSION1))
                    new Version1Handler().handle(request, response, Utils.pop(urn));
                else if (prefix.equals(Service.METADATA)) {
                    new MetadataHandler().handle(request, response, Path.pop(urn));
                } else
                    handleGetVersion(request, response, urn);
            } else
                throw new FormatterException("Invalid urn (prefix was null) " + urn);
        } catch (Exception e) {
            try {
                response.setCharacterEncoding("UTF-8");
                response.getWriter().println(e.getMessage());
            } catch (Exception ex) {
                throw new FormatterException(ex);
            }
        }
    }

    /**
     * Fetch and load an MVD
     * @param db the database 
     * @param docID
     * @return the loaded MVD
     * @throws an FormatterException if not found
     */
    protected EcdosisMVD loadMVD(String db, String docID) throws FormatterException {
        try {
            String data = Connector.getConnection().getFromDb(db, docID);
            if (data.length() > 0) {
                JSONObject doc = (JSONObject) JSONValue.parse(data);
                if (doc != null)
                    return new EcdosisMVD(doc);
            }
            throw new FormatterException("MVD not found " + docID);
        } catch (Exception e) {
            throw new FormatterException(e);
        }
    }

    protected String getVersionTableForUrn(String urn) throws FormatterException {
        try {
            JSONObject doc = loadJSONDocument(Database.CORTEX, urn);
            String fmt = (String) doc.get(JSONKeys.FORMAT);
            if (fmt != null && fmt.startsWith(Formats.MVD)) {
                EcdosisMVD mvd = loadMVD(Database.CORTEX, urn);
                return mvd.mvd.getVersionTable();
            } else if (fmt != null && fmt.equals(Formats.TEXT)) {
                // concoct a version list of length 1
                StringBuilder sb = new StringBuilder();
                String version1 = (String) doc.get(JSONKeys.VERSION1);
                if (version1 == null)
                    throw new FormatterException("Lacks version1 default");
                sb.append("Single version\n");
                String[] parts = version1.split("/");
                for (int i = 0; i < parts.length; i++) {
                    sb.append(parts[i]);
                    sb.append("\t");
                }
                sb.append(parts[parts.length - 1] + " version");
                sb.append("\n");
                return sb.toString();
            } else
                throw new FormatterException("Unknown of null Format");
        } catch (Exception e) {
            throw new FormatterException(e);
        }
    }

    /**
     * Use this method to retrieve the doc just to see its format
     * @param db the database to fetch from
     * @param docID the doc's ID
     * @return a JSON doc as returned by Mongo
     * @throws FormatterException 
     */
    JSONObject loadJSONDocument(String db, String docID) throws FormatterException {
        try {
            String data = Connector.getConnection().getFromDb(db, docID);
            if (data.length() > 0) {
                JSONObject doc = (JSONObject) JSONValue.parse(data);
                if (doc != null)
                    return doc;
            }
            throw new FormatterException("Doc not found " + docID);
        } catch (Exception e) {
            throw new FormatterException(e);
        }
    }

    /**
     * Try to retrieve the CorTex/CorCode version specified by the path
     * @param db the database to fetch from
     * @param docID the document ID
     * @param vPath the groups/version path to get
     * @return the CorTex/CorCode version contents or null if not found
     * @throws AeseException if the resource couldn't be found for some reason
     */
    protected EcdosisVersion doGetResourceVersion(String db, String docID, String vPath) throws FormatterException {
        EcdosisVersion version = new EcdosisVersion();
        JSONObject doc = null;
        char[] data = null;
        String res = null;
        //System.out.println("fetching version "+vPath );
        try {
            res = Connector.getConnection().getFromDb(db, docID);
        } catch (Exception e) {
            throw new FormatterException(e);
        }
        if (res != null)
            doc = (JSONObject) JSONValue.parse(res);
        if (doc != null) {
            String format = (String) doc.get(JSONKeys.FORMAT);
            if (format == null)
                throw new FormatterException("doc missing format");
            version.setFormat(format);
            if (version.getFormat().equals(Formats.MVD)) {
                MVD mvd = MVDFile.internalise((String) doc.get(JSONKeys.BODY));
                if (vPath == null)
                    vPath = (String) doc.get(JSONKeys.VERSION1);
                version.setStyle((String) doc.get(JSONKeys.STYLE));
                String sName = Utils.getShortName(vPath);
                String gName = Utils.getGroupName(vPath);
                int vId = mvd.getVersionByNameAndGroup(sName, gName);
                //System.out.println("vId="+vId+" sName="+sName);
                version.setMVD(mvd);
                if (vId != 0) {
                    data = mvd.getVersion(vId);
                    String desc = mvd.getDescription();
                    //System.out.println("description="+desc);
                    //int nversions = mvd.numVersions();
                    //System.out.println("nversions="+nversions);
                    //System.out.println("length of version "+vId+"="+data.length);
                    if (data != null)
                        version.setVersion(data);
                    else
                        throw new FormatterException("Version " + vPath + " not found");
                } else
                    throw new FormatterException("Version " + vPath + " not found");
            } else {
                String body = (String) doc.get(JSONKeys.BODY);
                version.setStyle((String) doc.get(JSONKeys.STYLE));
                if (body == null)
                    throw new FormatterException("empty body");
                try {
                    data = body.toCharArray();
                } catch (Exception e) {
                    throw new FormatterException(e);
                }
                version.setVersion(data);
            }
        }
        return version;
    }

    /**
     * Does one set of versions entirely contain another
     * @param container the putative container
     * @param contained the containee
     * @return true if all the bits of contained are in container
     */
    boolean containsVersions(BitSet container, BitSet contained) {
        for (int i = contained.nextSetBit(0); i >= 0; i = contained.nextSetBit(i + 1)) {
            if (container.nextSetBit(i) != i)
                return false;
        }
        return true;
    }

/**
 * Return the length of the word starting at offset
 * @param offset the index of the first letter
 * @param text the whole text of this version
 * @return the length of the word there
 */
int wordLen( int offset, String text )
{
    int state = 0;
    int lastLetterPos=offset;
    for ( int i=offset;i<text.length();i++ )
    {
        char token = text.charAt(i);
        switch ( state )
        {
            case 0: // seen one letter
                if ( Character.isWhitespace(token) )
                    return i-offset;
                else if ( token== '\'' || token == '')
                    state = 1;
                else if ( token=='-' )
                {
                    lastLetterPos = i;
                    state = 4;
                }
                else if ( token=='s' )
                    state = 2;
                else if ( !Character.isLetter(token) )
                    return i-offset;
                break;
            case 1: // seen apostrophe or hyphen
                if ( Character.isWhitespace(token) )
                    return (i-1)-offset;
                if ( Character.isLetter(token) )
                    state = 0;
                break;
            case 2: // seen 's'
                if ( token=='\''||token == '' )
                    state = 3;
                else if ( Character.isLetter(token)||token=='-' )
                    state = 0;
                else 
                    return i-offset;
                break;
            case 3:
                if ( Character.isWhitespace(token) )
                    return i-offset;
                else if ( Character.isLetter(token) )
                    state = 0;
                else
                    return (i-1)-offset;
                break;
            case 4: // seen hyphen
                if ( Character.isWhitespace(token) )
                    state = 5;
                else if ( Character.isLetter(token) )
                    state = 0;
                else
                    return lastLetterPos-offset;
                break;
            case 5: // seen hyphen and white space
                if ( Character.isLetter(token) )
                    state = 0;
                else if ( !Character.isWhitespace(token) )
                    return lastLetterPos-i;
                /// else stay in this state
                break;
        }
    }
    return text.length()-offset;
}

    /**
     * Convert the selections parameter to a real corcode
     * @param text the whole text of this version
     * @return a corcode as a string containing the selection ranges
     */
    String selectionsToCorcode(String text) {
        String[] parts = selections.split(",");
        STILDocument cc = new STILDocument();
        int[] values = new int[parts.length];
        for (int i = 0; i < parts.length; i++)
            values[i] = Integer.parseInt(parts[i]);
        Arrays.sort(values);
        for (int i = 0; i < values.length; i++) {
            int len = wordLen(values[i], text);
            System.out.println("len=" + len);
            Range r = new Range("selected", values[i], len);
            cc.add(r);
        }
        cc.put(JSONKeys.STYLE, "TEI/default");
        return cc.toJSONString();
    }

    /**
     * Turn a list of corcode names into an actual list of corcodes
     * @param names the docids of the corcodes
     * @param styleNames an array of style names to augment
     * @param text the text of the version
     * @return an array of actual corcodes
     * @throws FormatterException 
     */
    String[] fetchCorcodes(ArrayList names, ArrayList styleNames, String text) throws FormatterException {
        ArrayList<String> list = new ArrayList<String>();
        for (int i = 0; i < names.size(); i++) {
            EcdosisVersion hv = doGetResourceVersion(Database.CORCODE, (String) names.get(i), version1);
            if (!styleNames.contains(hv.getStyle()))
                styleNames.add(hv.getStyle());
            list.add(new String(hv.getVersion()));
        }
        // add selections
        if (selections != null && selections.length() > 0)
            list.add(selectionsToCorcode(text));
        String[] corcodes = new String[list.size()];
        list.toArray(corcodes);
        return corcodes;
    }

    private void dumpText(String fileName, String text) {
        try {
            File textFile = new File(fileName);
            if (textFile.exists())
                textFile.delete();
            textFile.createNewFile();
            FileWriter fw = new FileWriter(textFile);
            fw.write(text);
            fw.close();
        } catch (Exception e) {
            // ignore
        }
    }

    /**
     * Format the requested URN version as HTML
     * @param request the original http request
     * @param urn the original request urn
     * @return the converted HTML
     * @throws AeseException 
     */
    protected void handleGetVersion(HttpServletRequest request, HttpServletResponse response, String urn)
            throws FormatterException {
        version1 = request.getParameter(Params.VERSION1);
        if (version1 == null)
            throw new FormatterException("version1 parameter required");
        docid = request.getParameter(Params.DOCID);
        selections = request.getParameter(Params.SELECTIONS);
        EcdosisVersion corTex = doGetResourceVersion(Database.CORTEX, docid, version1);
        ArrayList<String> ccNames = new ArrayList<String>();
        Map map = request.getParameterMap();
        if (map.containsKey(Params.CORCODE)) {
            String[] values = (String[]) map.get(Params.CORCODE);
            for (int i = 0; i < values.length; i++)
                ccNames.add(values[i]);
        } else
            ccNames.add(docid + "/default");
        ArrayList<String> styleNames = new ArrayList<String>();
        if (map.containsKey(Params.STYLE)) {
            String[] values = (String[]) map.get(Params.STYLE);
            for (int i = 0; i < values.length; i++)
                styleNames.add(values[i]);
        } else
            styleNames.add(corTex.getStyle());
        String text = corTex.getVersionString();
        String[] corcodes = fetchCorcodes(ccNames, styleNames, text);
        //System.out.println("Fetching corcodes");
        String[] styles = fetchStyles(styleNames);
        // call the native library to format it
        JSONResponse html = new JSONResponse(JSONResponse.HTML);
        // String text, String[] markup, String[] css, JSONResponse output 
        boolean ok = true;
        if (corcodes == null || corcodes.length == 0) {
            System.out.println("corcodes is null or empty");
            ok = false;
        }
        if (text == null || text.length() == 0) {
            System.out.println("text is null or empty");
            ok = false;
        }
        if (styles == null || styles.length == 0) {
            System.out.println("styles is null or empty");
            ok = false;
        }
        int res = 0;
        if (ok) {
            if (docid.equals("english/harpur/h694")) {
                dumpText("/tmp/h694.txt", text);
                dumpText("/tmp/h694-default.json", corcodes[0]);
            }
            res = new AeseFormatter().format(text, corcodes, styles, html);
        }
        //        for ( int k=0;k<corcodes.length;k++ )
        //            System.out.println(corcodes[k]);
        //        System.out.println("res="+res+" corcodes.length="+corcodes.length);
        if (res == 0)
            throw new NativeException("formatting failed");
        else {
            response.setContentType("text/html;charset=UTF-8");
            try {
                Comment comment = new Comment();
                comment.addText("styles: ");
                for (int i = 0; i < styles.length; i++)
                    comment.addText(styles[i]);
                response.getWriter().println(comment.toString());
                response.getWriter().println(html.getBody());
            } catch (Exception e) {
                throw new FormatterException(e);
            }
        }
    }
}