org.archive.wayback.accesscontrol.ui.AdministrativeExclusionServlet.java Source code

Java tutorial

Introduction

Here is the source code for org.archive.wayback.accesscontrol.ui.AdministrativeExclusionServlet.java

Source

/* AdministrativeExclusionServlet
 *
 * $Id: AdministrativeExclusionServlet.java 1893 2007-07-26 21:42:35Z bradtofel $
 *
 * Created on 4:31:48 PM May 12, 2006.
 *
 * Copyright (C) 2006 Internet Archive.
 *
 * This file is part of wayback.
 *
 * wayback is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * any later version.
 *
 * wayback 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 Lesser Public License for more details.
 *
 * You should have received a copy of the GNU Lesser Public License
 * along with wayback; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package org.archive.wayback.accesscontrol.ui;

import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

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

import org.apache.commons.httpclient.URIException;
import org.archive.wayback.core.Timestamp;
import org.archive.wayback.surt.SURTTokenizer;
import org.archive.wayback.webapp.ServletRequestContext;

import com.sleepycat.je.DatabaseException;

/**
 * Servlet responsible for UI generation of the Administrative Exclustion 
 * system.
 * 
 * Primarily this includes:
 *    1) generating query form
 *    2) displaying current exclusion rules based on queries
 *  3) recieving POST requests from clients to add rules
 *  
 * @author brad
 * @version $Date: 2007-07-26 22:42:35 +0100 (Thu, 26 Jul 2007) $, $Revision: 1893 $
 */
public class AdministrativeExclusionServlet extends ServletRequestContext {

    private static final String DEFAULT_USER_AGENT = "ia_archiver";
    private static final String HTML_BR = "<br></br>";
    private static final long serialVersionUID = 1L;

    private static String FORM_OPERATION = "operation";

    private static String MODIFY_FORM_START = "start";
    private static String MODIFY_FORM_END = "end";
    private static String MODIFY_FORM_URL = "modify_url";
    private static String MODIFY_FORM_SURT = "modify_surt";
    private static String MODIFY_FORM_TYPE = "type";
    private static String MODIFY_FORM_MOD = "mod";
    private static String MODIFY_FORM_WHO = "who";
    private static String MODIFY_FORM_WHY = "why";
    private static String MODIFY_FORM_PREFIX = "prefix";

    private static String DELETE_FORM_OPERATION = "delete";
    private static String MODIFY_FORM_OPERATION = "modify";

    private static String MODIFY_FORM_MOD_ADD_VALUE = "add";
    private static String MODIFY_FORM_MOD_DELETE_VALUE = "delete";

    private static String MODIFY_FORM_TYPE_EXCLUDE_VALUE = "exclude";
    private static String MODIFY_FORM_TYPE_INCLUDE_VALUE = "include";
    private static String MODIFY_FORM_TYPE_NOROBOTS_VALUE = "norobots";
    private static String MODIFY_FORM_TYPE_ROBOTS_VALUE = "robots";

    private static String MODIFY_FORM_PREFIX_YES_VALUE = "yes";

    private static String QUERY_FORM_URL = "query_url";
    private static String QUERY_FORM_ALL = "query_all";
    private static String QUERY_FORM_ALL_VALUE = "yes";
    private static String QUERY_FORM_OPERATION = "query";

    private static String CHECK_FORM_URL = "check_url";
    private static String CHECK_FORM_TIMESTAMP = "timestamp";
    private static String CHECK_FORM_OPERATION = "check";

    private static final int RULE_STATUS_HEADER = -1;
    private static final int RULE_STATUS_ACTIVE = 0;
    private static final int RULE_STATUS_INACTIVE = 1;
    private static final int RULE_STATUS_DELETE = 2;

    private AdministrativeExclusionAuthority exclusionAuthority = null;

    private void showPage(HttpServletResponse response, StringBuilder page) throws IOException {
        response.setContentType("text/html");
        response.getOutputStream().print(page.toString());
    }

    private String formatException(Exception e) {
        return e.getMessage();
    }

    public boolean handleRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse)
            throws ServletException, IOException {
        AdministrativeExclusionAuthority exclAuth = exclusionAuthority;

        StringBuilder page = new StringBuilder(1024);
        page.append("<html><head><title>Wayback: Administrative Exclusions</title></head><body>");
        @SuppressWarnings("unchecked")
        Map<String, String[]> queryArgs = httpRequest.getParameterMap();
        String operation = getMapParam(queryArgs, FORM_OPERATION);
        if (operation == null) {
            page.append(makeCheckForm(queryArgs));
            page.append(makeQueryForm(queryArgs));
            page.append(makeCreateForm(queryArgs));
        } else if (operation.equals(QUERY_FORM_OPERATION)) {
            page.append(makeCheckForm(queryArgs));
            page.append(makeQueryForm(queryArgs));
            try {
                page.append(handleRuleQuery(exclAuth, queryArgs));
            } catch (URIException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                page.append(formatException(e));
            } catch (ParseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                page.append(formatException(e));
            } catch (DatabaseException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                page.append(formatException(e));
            }
            page.append(makeCreateForm(queryArgs));
        } else if (operation.equals(CHECK_FORM_OPERATION)) {
            page.append(makeCheckForm(queryArgs));
            try {
                page.append(handleRuleCheck(exclAuth, queryArgs));
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                page.append(formatException(e));
            }
            page.append(makeQueryForm(queryArgs));
            page.append(makeCreateForm(queryArgs));

        } else if ((operation.equals(MODIFY_FORM_OPERATION) || operation.equals(DELETE_FORM_OPERATION))) {

            try {
                handleRuleCreate(exclAuth, queryArgs);
                page.append("OK - added rule");
            } catch (URIException e) {
                e.printStackTrace();
                page.append(formatException(e));
            } catch (ParseException e) {
                e.printStackTrace();
                page.append(formatException(e));
            } catch (DatabaseException e) {
                e.printStackTrace();
                page.append(formatException(e));
            }

        } else {
            page.append("Unknown operation");
        }
        page.append("</body></html>");
        showPage(httpResponse, page);
        return true;
    }

    // HTML GENERATION METHODS: 

    private String htmlEncode(String orig) {
        return orig;
    }

    private String propertyHTMLEncode(String orig) {
        return orig;
    }

    private String makeFormTextInput(String label, String name, Map<String, String[]> queryArgs, String suffix) {
        String value = "";
        if (queryArgs != null) {
            value = propertyHTMLEncode(getMapParamOrEmpty(queryArgs, name));
        }
        return label + ":<input type=\"text\" name=\"" + name + "\" VALUE=\"" + value + "\"></input>" + suffix;
    }

    private String makeFormTextAreaInput(String label, String name, Map<String, String[]> queryArgs,
            String suffix) {
        String value = "";
        if (queryArgs != null) {
            value = htmlEncode(getMapParamOrEmpty(queryArgs, name));
        }
        return label + ":<textarea cols=80 rows=4 name=\"" + name + "\">" + value + "</textarea>" + suffix;
    }

    private String makeFormCheckInput(String label, String name, String value, Map<String, String[]> queryArgs,
            String suffix) {
        String curValue = getMapParam(queryArgs, name);
        String checked = "";
        if (curValue != null && curValue.equals(value)) {
            checked = "checked";
        }
        return label + ":<input type=\"checkbox\" name=\"" + name + "\" VALUE=\"" + value + "\" " + checked
                + "></input>" + suffix;
    }

    private String makeHiddenInput(String name, String value) {
        return "<input type=\"hidden\" name=\"" + name + "\" value=\"" + propertyHTMLEncode(value) + "\"></input>";
    }

    private String makeForm(String method, String submitValue, String content) {
        StringBuilder sb = new StringBuilder(1024);
        sb.append("<form method=\"").append(method);
        sb.append("\" action=\"admin-exclusion\">\n");
        sb.append(content);
        sb.append("<input type=\"SUBMIT\" name=\"").append(FORM_OPERATION);
        sb.append("\" value=\"").append(submitValue).append("\"></input>\n");
        sb.append("</form>");
        return sb.toString();
    }

    private String makeHeaderForm(String title, String method, String submitValue, String content) {
        return "<hr></hr><p><h2>" + title + "</h2>" + makeForm(method, submitValue, content) + "</p>";
    }

    // CHECK FORM AND HANDLING

    private String makeCheckForm(Map<String, String[]> queryArgs) {
        String content = makeFormTextInput("Url", CHECK_FORM_URL, queryArgs, " ")
                + makeFormTextInput("Timestamp", CHECK_FORM_TIMESTAMP, queryArgs, " ");
        return makeHeaderForm("Test Exclusion", "GET", CHECK_FORM_OPERATION, content);
    }

    private String handleRuleCheck(AdministrativeExclusionAuthority excl, Map<String, String[]> queryArgs)
            throws Exception {
        String url = getRequiredMapParam(queryArgs, CHECK_FORM_URL);
        String timestamp = getRequiredMapParam(queryArgs, CHECK_FORM_TIMESTAMP);
        String userAgent = DEFAULT_USER_AGENT;

        ExclusionResponse response = excl.checkExclusion(userAgent, url, timestamp);
        return response.getContentText();
    }

    // RULE QUERY FORM AND HANDLING

    private String makeQueryForm(Map<String, String[]> queryArgs) {
        StringBuilder content = new StringBuilder(1024);
        content.append(makeFormTextInput("Url", QUERY_FORM_URL, queryArgs, ""));
        content.append(makeFormCheckInput("all", QUERY_FORM_ALL, QUERY_FORM_ALL_VALUE, queryArgs, ""));
        return makeHeaderForm("Rule Query", "GET", QUERY_FORM_OPERATION, content.toString());
    }

    private String handleRuleQuery(AdministrativeExclusionAuthority excl, Map<String, String[]> queryArgs)
            throws ParseException, URIException, DatabaseException {
        String url = getRequiredMapParam(queryArgs, QUERY_FORM_URL);
        String all = getMapParam(queryArgs, QUERY_FORM_ALL);
        boolean showAll = (all != null && all.equals(QUERY_FORM_ALL_VALUE));
        String surt = SURTTokenizer.prefixKey(url);
        ArrayList<AdministrativeExclusionRules> matching = excl.matchRules(surt);
        StringBuilder matchHTML = new StringBuilder();
        rulesToTable(matchHTML, matching, url, showAll);
        return matchHTML.toString();
    }

    private String ruleToType(AdministrativeExclusionRule rule) {
        String type = MODIFY_FORM_TYPE_EXCLUDE_VALUE;
        if (rule.isExclude()) {
            type = MODIFY_FORM_TYPE_EXCLUDE_VALUE;
        } else if (rule.isInclude()) {
            type = MODIFY_FORM_TYPE_INCLUDE_VALUE;
        } else if (rule.isNoRobots()) {
            type = MODIFY_FORM_TYPE_NOROBOTS_VALUE;
        } else if (rule.isRobots()) {
            type = MODIFY_FORM_TYPE_ROBOTS_VALUE;
        }
        return type;
    }

    // RULE DELETION/CREATION FORM AND HANDLING 

    private String makeDeleteForm(String surt, AdministrativeExclusionRule rule) {
        StringBuilder sb = new StringBuilder(1024);
        sb.append(makeHiddenInput(MODIFY_FORM_SURT, surt));
        sb.append(makeHiddenInput(MODIFY_FORM_START, rule.getStartDateStr()));
        sb.append(makeHiddenInput(MODIFY_FORM_END, rule.getEndDateStr()));
        sb.append(makeHiddenInput(MODIFY_FORM_TYPE, ruleToType(rule)));
        sb.append(makeHiddenInput(MODIFY_FORM_MOD, MODIFY_FORM_MOD_DELETE_VALUE));
        sb.append(makeFormTextInput("Who", MODIFY_FORM_WHO, null, " "));
        sb.append(makeFormTextInput("Why", MODIFY_FORM_WHY, null, " "));
        return makeForm("POST", DELETE_FORM_OPERATION, sb.toString());
    }

    private String makeCreateForm(Map<String, String[]> queryArgs) {
        StringBuilder sb = new StringBuilder(1024);
        sb.append(makeFormTextInput("Url", MODIFY_FORM_URL, queryArgs, ""));
        sb.append(makeFormCheckInput("(prefix)", MODIFY_FORM_PREFIX, MODIFY_FORM_PREFIX_YES_VALUE, queryArgs,
                HTML_BR));

        sb.append(makeFormTextInput("Start", MODIFY_FORM_START, queryArgs, ""));
        sb.append(makeFormTextInput("End", MODIFY_FORM_END, queryArgs, HTML_BR));

        sb.append("Type: <select name=\"" + MODIFY_FORM_TYPE + "\">" + "<option>" + MODIFY_FORM_TYPE_EXCLUDE_VALUE
                + "</option>" + "<option>" + MODIFY_FORM_TYPE_INCLUDE_VALUE + "</option>" + "<option>"
                + MODIFY_FORM_TYPE_ROBOTS_VALUE + "</option>" +
                //            "<option>"+MODIFY_FORM_TYPE_NOROBOTS_VALUE+"</option>" +
                "</select>").append(HTML_BR).append("\n");

        //      sb.append("Add/Remove: <select NAME=\""+MODIFY_FORM_MOD+"\">" +
        //            "<option>"+MODIFY_FORM_MOD_ADD_VALUE+"</option>" +
        //            "<option>"+MODIFY_FORM_MOD_DELETE_VALUE+"</option>" +
        //         "</select><br></br>\n");
        sb.append(makeHiddenInput(MODIFY_FORM_MOD, MODIFY_FORM_MOD_ADD_VALUE));

        sb.append(makeFormTextInput("Who", MODIFY_FORM_WHO, queryArgs, HTML_BR));
        sb.append(makeFormTextAreaInput("Why", MODIFY_FORM_WHY, queryArgs, HTML_BR));

        return makeHeaderForm("Compose Rule", "POST", MODIFY_FORM_OPERATION, sb.toString());
    }

    private void handleRuleCreate(AdministrativeExclusionAuthority auth, Map<String, String[]> queryMap)
            throws ParseException, URIException, DatabaseException {

        AdministrativeExclusionRule rule = new AdministrativeExclusionRule();

        String start = getRequiredMapParam(queryMap, MODIFY_FORM_START);
        String startDateStr = Timestamp.padStartDateStr(start);
        if (!startDateStr.equals(start)) {
            throw new ParseException("invalid value: " + MODIFY_FORM_START, 0);
        }

        String end = getRequiredMapParam(queryMap, MODIFY_FORM_END);
        String endDateStr = Timestamp.padEndDateStr(end);
        if (!endDateStr.equals(end)) {
            throw new ParseException("invalid value: " + MODIFY_FORM_END, 0);
        }

        String type = getRequiredMapParam(queryMap, MODIFY_FORM_TYPE);
        if (type.equals(MODIFY_FORM_TYPE_EXCLUDE_VALUE)) {
            rule.setExclude();
        } else if (type.equals(MODIFY_FORM_TYPE_INCLUDE_VALUE)) {
            rule.setInclude();
        } else if (type.equals(MODIFY_FORM_TYPE_ROBOTS_VALUE)) {
            rule.setRobots();
        } else if (type.equals(MODIFY_FORM_TYPE_NOROBOTS_VALUE)) {
            rule.setNoRobots();
        } else {
            throw new ParseException("invalid value: " + MODIFY_FORM_TYPE, 0);
        }

        String mod = getRequiredMapParam(queryMap, MODIFY_FORM_MOD);
        if (mod.equals(MODIFY_FORM_MOD_ADD_VALUE)) {
            rule.setAdd();
        } else if (mod.equals(MODIFY_FORM_MOD_DELETE_VALUE)) {
            rule.setDelete();
        } else {
            throw new ParseException("invalid value: " + MODIFY_FORM_MOD, 0);
        }

        String who = getRequiredMapParam(queryMap, MODIFY_FORM_WHO);
        String why = getRequiredMapParam(queryMap, MODIFY_FORM_WHY);

        String url = getMapParam(queryMap, MODIFY_FORM_URL);
        String surt = getMapParam(queryMap, MODIFY_FORM_SURT);
        if (surt == null) {
            if (url == null) {
                throw new ParseException("Missing argument " + MODIFY_FORM_URL, 0);
            }
            String prefix = getMapParam(queryMap, MODIFY_FORM_PREFIX);
            if (prefix == null || !prefix.equals(MODIFY_FORM_PREFIX_YES_VALUE)) {
                surt = SURTTokenizer.exactKey(url);
            } else {
                surt = SURTTokenizer.prefixKey(url);
            }
        }
        rule.setWho(who);
        rule.setWhy(why);
        rule.setWhen(new Date().getTime());
        rule.setStartDateStr(startDateStr);
        rule.setEndDateStr(endDateStr);

        auth.addRuleFor(surt, rule);
    }

    private int statusForRule(AdministrativeExclusionRule rule, AdministrativeExclusionRules rules) {
        int status = RULE_STATUS_ACTIVE;
        if (rule.isDelete()) {
            status = RULE_STATUS_DELETE;
        } else {
            // has rule been deleted?
            String key = rule.key();
            boolean deleted = false;

            Iterator<AdministrativeExclusionRule> itr = rules.getRules().iterator();
            while (itr.hasNext()) {
                AdministrativeExclusionRule daRule = (AdministrativeExclusionRule) itr.next();
                if (daRule.isDelete() && key.equals(daRule.key()) && daRule.getWhen() > rule.getWhen()) {
                    deleted = true;
                    break;
                }
            }

            if (deleted) {
                status = RULE_STATUS_INACTIVE;
            }
        }
        return status;
    }

    private void tableCell(StringBuilder page, String content, int status) {
        content = htmlEncode(content);
        String style = "";
        if (status == RULE_STATUS_DELETE) {
            style = "style=\"color:red;\"";
        } else if (status == RULE_STATUS_INACTIVE) {
            style = "style=\"text-decoration:line-through;\"";
        } else if (status == RULE_STATUS_HEADER) {
            style = "style=\"bold:yes;\"";
        }
        page.append("<td ").append(style).append(">");
        page.append(htmlEncode(content));
        page.append("</td>");
    }

    private void ruleHeaderRow(StringBuilder page) {
        int status = RULE_STATUS_HEADER;
        page.append("<tr>");
        tableCell(page, "Url Prefix", status);
        tableCell(page, "Starts", status);
        tableCell(page, "Ends", status);
        tableCell(page, "Rule Type", status);
        tableCell(page, "Add/Delete", status);
        tableCell(page, "When", status);
        tableCell(page, "Admin", status);
        tableCell(page, "Comment", status);
        page.append("</tr>\n");
    }

    private void ruleToRow(StringBuilder page, String surt, AdministrativeExclusionRule rule, int status) {
        String surtPrefix = surt;
        if (surtPrefix.endsWith("\t")) {
            surtPrefix = surtPrefix.substring(0, surtPrefix.length() - 1);
        } else {
            surtPrefix = surtPrefix + "*";
        }

        page.append("<tr>");
        tableCell(page, surtPrefix, status);
        tableCell(page, rule.getPrettyStartDateStr(), status);
        tableCell(page, rule.getPrettyEndDateStr(), status);
        tableCell(page, rule.getPrettyType(), status);
        tableCell(page, rule.getPrettyMod(), status);
        int sse = (int) (rule.getWhen() / 1000);
        // TODO: Localization
        tableCell(page, Timestamp.fromSse(sse).prettyDateTime(), status);
        tableCell(page, rule.getWho(), status);
        // TODO: shrink
        if (status == RULE_STATUS_ACTIVE) {
            page.append("<td>").append(rule.getWhy()).append(" ").append(makeDeleteForm(surt, rule))
                    .append("</td>");
        } else {
            tableCell(page, rule.getWhy(), status);
        }
        page.append("</tr>\n");
    }

    private void rulesToTable(StringBuilder page, ArrayList<AdministrativeExclusionRules> matching, String url,
            boolean showAll) {

        if (matching.size() > 0) {
            page.append("<table border=1>");
            ruleHeaderRow(page);
            Iterator<AdministrativeExclusionRules> itr = matching.iterator();
            while (itr.hasNext()) {
                AdministrativeExclusionRules rules = itr.next();

                String surtPrefix = rules.getSurtPrefix();
                Iterator<AdministrativeExclusionRule> ruleItr = null;
                if (showAll) {
                    ruleItr = rules.getRules().iterator();
                } else {
                    ruleItr = rules.filterRules("").iterator();
                }
                while (ruleItr.hasNext()) {
                    AdministrativeExclusionRule rule = (AdministrativeExclusionRule) ruleItr.next();
                    int status = statusForRule(rule, rules);
                    ruleToRow(page, surtPrefix, rule, status);
                }
            }
            page.append("</table>\n");
        } else {
            page.append("<p>No records match(" + url + ")</p>\n");
        }
    }
}