com.lrodriguez.SVNBrowser.java Source code

Java tutorial

Introduction

Here is the source code for com.lrodriguez.SVNBrowser.java

Source

/*
 Copyright (c) <2009> <Leonardo Rodriguez-Velez draco_rosa@hotmail.com>
    
 Permission is hereby granted, free of charge, to any person
 obtaining a copy of this software and associated documentation
 files (the "Software"), to deal in the Software without
 restriction, including without limitation the rights to use,
 copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the
 Software is furnished to do so, subject to the following
 conditions:
    
 The above copyright notice and this permission notice shall be
 included in all copies or substantial portions of the Software.
    
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 OTHER DEALINGS IN THE SOFTWARE.
    
*/

package com.lrodriguez;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

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

import org.apache.commons.jxpath.JXPathContext;
import org.tigris.subversion.javahl.ClientException;
import org.tigris.subversion.javahl.DirEntry;
import org.tigris.subversion.javahl.Revision;
import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.SVNLogEntryPath;
import org.tmatesoft.svn.core.SVNURL;
import org.tmatesoft.svn.core.auth.ISVNAuthenticationManager;
import org.tmatesoft.svn.core.internal.io.dav.DAVRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.fs.FSRepositoryFactory;
import org.tmatesoft.svn.core.internal.io.svn.SVNRepositoryFactoryImpl;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.io.SVNRepositoryFactory;
import org.tmatesoft.svn.core.wc.SVNWCUtil;

import com.lrodriguez.model.SVNHttpSession;

public class SVNBrowser extends HttpServlet {

    private static final long serialVersionUID = 3L;

    private static final String INDEX_JSP = "index.jsp";//most GET requests are forwarded to this JSP after processing

    public static final int _2359HOURS = 86399999;//this is added to endDate in short Date style

    private static String webappRoot = null;

    //initialization parameters (in web.xml)
    public static final String REPOSITORY_DIR = "repositoryDir";
    public static final String USER_NAME = "userName";
    public static final String REPOSITORY_URL = "repositoryURL";
    public static final String WEBAPP_ROOT = "webappRoot";

    //session only attributes
    public static final String SVNSESSION = "svnsession";//holds the SVNHttpSession object
    public static final String UNIQUE_ENTRIES = "uniqueEntries";//holds a List of entries for this session
    public static final String BRANCHES = "branches";//holds a List<String> of all branches

    //session and/or request attributes/parameters (for session persistence)
    public static final String SORT_BY = "sortBy";//query parameter
    public static final String START_DATE = "startDate";//query parameter
    public static final String END_DATE = "endDate";//query parameter
    public static final String P_FILE_TYPE = "pFileType";//query parameter
    public static final String CURRENT_BRANCH = "currentBranch";//query parameter (the branch we are working with in the UI)
    public static final String IS_SHORT_END_DATE = "isShortEndDate";//interpreted from END_DATE parameter, indicates the user wants dates in "yyyy-MM-dd" format instead of "yyyy-MM-dd-HH:mm:ss"
    public static final String IS_SHORT_START_DATE = "isShortStartDate";//interpreted from START_DATE parameter, indicates the user wants dates in "yyyy-MM-dd" format instead of "yyyy-MM-dd-HH:mm:ss"

    //request only parameters/attributes
    public static final String SVN_QUERY = "svnQuery";//indicates a new query (returns plain list of files)
    public static final String QUERY = "query";//query parameter - indicates a new query (UI interface)
    public static final String XPATH_QUERY = "xpathQuery";//indicates a new xpath query
    public static final String FILE_QUERY = "fileQuery";
    public static final String CHANGE_URL = "changeUrl";
    public static final String ERROR = "error";//indicates an error
    public static final String FILE_TYPE = "fileType";//query parameter
    public static final String FILE_PATH = "filePath";//query parameter
    public static final String END_REVISION = "endRevision";
    public static final String START_REVISION = "startRevision";
    public static final String GET_FILE = "getFile";
    public static final String REVISION = "revision";

    //Utility properties
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");//short Date style
    private static final String sdfRegex = "[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}";//short Date style
    private static final SimpleDateFormat sdfFull = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");//Full Date style
    private static final String sdfFullRegex = "[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}-[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}";//Full Date style

    private void initSession(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        if (session.getAttribute(SVNSESSION) == null) {
            try {
                SVNHttpSession svnsession = new SVNHttpSession(getInitParameter(REPOSITORY_URL),
                        getInitParameter(USER_NAME), getInitParameter("password"), webappRoot,
                        getInitParameter(REPOSITORY_DIR));
                logDebug("initializing SVNRepository.\nrepositoryURL=" + svnsession.getRepositoryURL() + "\nuser="
                        + svnsession.getUserName());
                svnsession.init();
                session.setAttribute(SVNSESSION, svnsession);
            } catch (SVNException e) {
                e.printStackTrace();
                request.setAttribute(ERROR, e.getErrorMessage());
            }
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        request.setAttribute(ERROR, "this functionality is disabled");
        request.getRequestDispatcher(INDEX_JSP).forward(request, response);
        return;
        //request.getRequestDispatcher("SVNClient").forward(request, response);
    }

    /**
     * this method acts as the controller/dispatcher
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        logDebug("SVNBrowser: doGet() invoked");
        initSession(request, response);
        initBranches(request);
        HttpSession session = request.getSession();
        Date startDate = persistStartDate(request);
        Date endDate = persistEndDate(request);
        String pFileType = persistFileType(request);
        String currentBranch = persistCurrentBranch(request);
        Comparator comparator = persistSortBy(request);

        //get file for listings
        if (request.getParameter("serveFile") != null) {
            doGetGetFile2(request, response);
            return;
        }

        //get file
        if (request.getParameter(GET_FILE) != null) {
            doGetFile(request, response);
            return;
        }

        //Change URL
        if (request.getParameter(CHANGE_URL) != null) {
            doChangeUrl(request, response);
            return;
        }

        //SVN Date query
        if (request.getParameter(SVN_QUERY) != null && request.getParameter(START_DATE) != null
                && request.getParameter(END_DATE) != null) {//new query
            doSvnDateQuery(request, response, startDate, endDate);
            return;
        }

        //SVN Revision query
        if (request.getParameter(SVN_QUERY) != null && request.getParameter(START_REVISION) != null
                && request.getParameter(END_REVISION) != null) {
            doSvnRevisionQuery(request, response);
            return;
        }

        //Xpath query
        if (request.getParameter(XPATH_QUERY) != null) {
            doXpathQuery(request, response, session);
            return;
        }

        //Browser Date query
        if (request.getParameter(QUERY) != null && request.getParameter(START_DATE) != null
                && request.getParameter(END_DATE) != null) {//new query
            doBrowserDateQuery(request, response, session, startDate, endDate, pFileType, currentBranch,
                    comparator);
            return;
        }

        //Browser Revision query
        if (request.getParameter(QUERY) != null && request.getParameter(START_REVISION) != null
                && request.getParameter(END_REVISION) != null) {//new query
            doBrowserRevisionQuery(request, response, session, pFileType, currentBranch, comparator);
            return;
        }

        //Browser file query
        if (request.getParameter(FILE_QUERY) != null) {
            doBrowserFileQuery(request, response, session, comparator);
            return;
        }

        //Sort query
        if (request.getParameter(SORT_BY) != null && request.getParameter(QUERY) == null
                && session.getAttribute(UNIQUE_ENTRIES) != null) {//request to sort
            doSort(request, response, session, comparator);
            return;
        }

        //Sort query null entries
        if (request.getParameter(SORT_BY) != null && request.getParameter(QUERY) == null
                && session.getAttribute(UNIQUE_ENTRIES) == null) {//request to sort, no entries
            doSortNoEntries(request, response, session, startDate, endDate, comparator);
            return;
        }

        //Ant build
        if (request.getParameter("doAntBuild") != null) {
            request.setAttribute(ERROR, "this functionality is disabled");
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
            //logDebug("dispatching doAntBuild request");
            //AntRunner antRunner = new AntRunner();
            //antRunner.run(request, response);
        }

        //switch branch
        if (request.getParameter(QUERY) != null && request.getParameter(CURRENT_BRANCH) != null) {
            doSwitchBranch(request, response, session);
            return;
        }

        //DEFAULT request
        if (request.getParameter(SORT_BY) == null && request.getParameter(QUERY) == null
                && request.getParameter("doUpdate") == null && request.getParameter("doUpdate") == null
                && request.getParameter("doCleanup") == null && request.getParameter("doCheckout") == null
                && request.getParameter("doAntBuild") == null) {//on initial page
            doDefaultRequest(request, response, session, startDate, endDate, comparator);
            return;
        }

        //request.getRequestDispatcher("index.jsp").forward(request, response);
    }

    /////////////////////////////////////Dispatch methods
    private void doDefaultRequest(HttpServletRequest request, HttpServletResponse response, HttpSession session,
            Date startDate, Date endDate, Comparator comparator) throws ServletException, IOException {
        logDebug("dispatching default request");

        List branches = getAllBranches(request);
        if (request.getAttribute(ERROR) != null) {
            return;
        }
        session.setAttribute(BRANCHES, branches);

        List uniqueEntries = getUniqueEntries(request, startDate, endDate);
        if (request.getAttribute(ERROR) != null) {
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
        }

        //uniqueEntries = filterListByCurrentBranch(uniqueEntries, currentBranch);

        Collections.sort(uniqueEntries, comparator);

        session.setAttribute(UNIQUE_ENTRIES, uniqueEntries);
        request.getRequestDispatcher(INDEX_JSP).forward(request, response);
        return;
    }

    private void doGetGetFile2(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        logDebug("dispatching serveFile request");
        if (request.getParameter("serveFile") != null) {
            if (request.getParameter("serveFile").indexOf("..") >= 0) {
                response.sendError(404);
                System.err.println("******** Invalid serveFile attempt from " + request.getRemoteAddr());
                return;
            }
            String workingCopyDir = webappRoot
                    + getInitParameter(REPOSITORY_DIR).replaceAll("[/\\\\]+", "\\" + File.separator);
            String fileName = workingCopyDir
                    + request.getParameter("serveFile").replaceAll("[/\\\\]+", "\\" + File.separator);

            File f = new File(fileName);

            try {
                if (f.getCanonicalPath().indexOf(workingCopyDir) != 0 || !f.exists() || !f.isFile()
                        || f.isHidden()) {
                    response.sendError(404);
                    System.err.println(
                            "******** Invalid serveFile attempt " + fileName + " from " + request.getRemoteAddr());
                    return;
                }
            } catch (IOException e) {
                e.printStackTrace();
                response.sendError(404);
                System.err.println(
                        "******** Invalid serveFile attempt " + fileName + " from " + request.getRemoteAddr());
                return;
            }
            int length = 0;
            byte[] bbuf = new byte[1024];
            DataInputStream in = new DataInputStream(new FileInputStream(f));
            response.setHeader("Content-disposition", "attachment; filename=\"" + request.getParameter("serveFile")
                    .substring(request.getParameter("serveFile").lastIndexOf("/") + 1));
            while ((in != null) && ((length = in.read(bbuf)) != -1)) {
                response.getOutputStream().write(bbuf, 0, length);
            }
            in.close();
            response.getOutputStream().flush();
            response.getOutputStream().close();
            return;
        }
    }

    private void doGetFile(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
        logDebug("dispatching getFile");
        HttpSession session = request.getSession();

        if (session != null && (request.getParameter(GET_FILE) == null || "".equals(request.getParameter(GET_FILE)))
                && request.getParameter(REVISION) != null) {
            response.getWriter().println("an error ocurred, check the query parameters");
        }

        if (session.getAttribute(SVNBrowser.SVNSESSION) != null) {
            SVNHttpSession svnsession = (SVNHttpSession) session.getAttribute(SVNBrowser.SVNSESSION);
            if (svnsession != null) {
                SVNRepository repo = svnsession.getRepository();
                logDebug("im here!");
                response.setHeader("Content-disposition", "attachment; filename=\"" + request.getParameter(GET_FILE)
                        .substring(request.getParameter(GET_FILE).lastIndexOf("/") + 1));
                try {
                    repo.getFile(request.getParameter(GET_FILE), Long.parseLong(request.getParameter("revision")),
                            null, response.getOutputStream());
                } catch (NumberFormatException e) {
                    request.setAttribute(ERROR, e.getMessage());
                    request.getRequestDispatcher(INDEX_JSP).forward(request, response);
                } catch (SVNException e) {
                    request.setAttribute(ERROR, e.getMessage());
                    request.getRequestDispatcher(INDEX_JSP).forward(request, response);
                }
            } else {
                request.setAttribute(ERROR,
                        "svnsession is null, try refreshing the session by setting the Repository URL");
                request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            }
        }
    }

    private void doSwitchBranch(HttpServletRequest request, HttpServletResponse response, HttpSession session)
            throws ServletException, IOException {
        logDebug("dispatching Browser switch branch query");

        //List uniqueEntries = getUniqueEntries(request, startDate, endDate);
        //if(request.getAttribute(ERROR)!= null){
        //   request.getRequestDispatcher("index.jsp").forward(request, response);
        //   return;
        //}
        //uniqueEntries = filterListByCurrentBranch(uniqueEntries, currentBranch);
        //Collections.sort(uniqueEntries, comparator);

        session.setAttribute(UNIQUE_ENTRIES, null);
        request.getRequestDispatcher(INDEX_JSP).forward(request, response);
        return;
    }

    private void doSvnRevisionQuery(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        logDebug("dispatching Revision SVN query request");
        List entriesList = getUniqueEntries(request, Long.parseLong(request.getParameter(START_REVISION)),
                Long.parseLong(request.getParameter(END_REVISION)));//get all files in date range
        if (request.getAttribute(ERROR) != null) {
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
        }
        sortAndFilterSvnQuery(request, response, entriesList);
        return;
    }

    private void doSvnDateQuery(HttpServletRequest request, HttpServletResponse response, Date startDate,
            Date endDate) throws ServletException, IOException {
        logDebug("dispatching Date SVN query request");
        List entriesList = getUniqueEntries(request, startDate, endDate);//get all files in date range
        if (request.getAttribute(ERROR) != null) {
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
        }
        sortAndFilterSvnQuery(request, response, entriesList);
        return;
    }

    private void doSort(HttpServletRequest request, HttpServletResponse response, HttpSession session,
            Comparator comparator) throws ServletException, IOException {
        logDebug("dispatching Sort request");
        Collections.sort(((List) session.getAttribute(UNIQUE_ENTRIES)), comparator);
        request.getRequestDispatcher(INDEX_JSP).forward(request, response);
        return;
    }

    private void doSortNoEntries(HttpServletRequest request, HttpServletResponse response, HttpSession session,
            Date startDate, Date endDate, Comparator comparator) throws ServletException, IOException {
        logDebug("dispatching Default request");
        List uniqueEntries = getUniqueEntries(request, startDate, endDate);
        if (request.getAttribute(ERROR) != null) {
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
        }
        Collections.sort(uniqueEntries, comparator);

        session.setAttribute(UNIQUE_ENTRIES, uniqueEntries);
        request.getRequestDispatcher(INDEX_JSP).forward(request, response);
        return;
    }

    private void doXpathQuery(HttpServletRequest request, HttpServletResponse response, HttpSession session)
            throws ServletException, IOException {
        //example
        //?xpathQuery=.[revision < 9315 and revision>9000 and author='echow' or author ='lrodrigu' and type='A']
        logDebug("dispatching xpath query: " + request.getParameter(XPATH_QUERY));

        SVNRepository repository = ((SVNHttpSession) request.getSession().getAttribute(SVNSESSION)).getRepository();
        Collection svnLogEntries = null;
        try {
            svnLogEntries = getSVNLogEntries(request, 0, repository.getDatedRevision(new Date()));
        } catch (SVNException e) {
            e.printStackTrace();
            request.setAttribute(ERROR, e.getErrorMessage());
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
        }
        List entriesList = new ArrayList();
        if (svnLogEntries != null && svnLogEntries.size() > 0) {
            List entryFacadeList = getAllEntries(svnLogEntries);

            JXPathContext context = JXPathContext.newContext(entryFacadeList);
            context.setLenient(true);
            for (Iterator iter = context.iterate(request.getParameter(XPATH_QUERY)); iter.hasNext();) {
                Object currEntryFacade = iter.next();
                entriesList.add(currEntryFacade);
            }
        }
        session.setAttribute(UNIQUE_ENTRIES, entriesList);
        request.getRequestDispatcher(INDEX_JSP).forward(request, response);
        return;
    }

    private void doBrowserDateQuery(HttpServletRequest request, HttpServletResponse response, HttpSession session,
            Date startDate, Date endDate, String pFileType, String currentBranch, Comparator comparator)
            throws ServletException, IOException {
        logDebug("dispatching Browser Date query");

        List uniqueEntries = getUniqueEntries(request, startDate, endDate);
        if (request.getAttribute(ERROR) != null) {
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
        }

        uniqueEntries = filterListByDateRange(uniqueEntries, startDate, endDate);
        uniqueEntries = filterListByFileType(uniqueEntries, pFileType);
        uniqueEntries = filterListByCurrentBranch(uniqueEntries, currentBranch);

        Collections.sort(uniqueEntries, comparator);

        session.setAttribute(UNIQUE_ENTRIES, uniqueEntries);
        request.getRequestDispatcher(INDEX_JSP).forward(request, response);
        return;
    }

    private void doBrowserFileQuery(HttpServletRequest request, HttpServletResponse response, HttpSession session,
            Comparator comparator) throws ServletException, IOException {
        logDebug("Dispatching Browser File query");
        SVNRepository repository = ((SVNHttpSession) request.getSession().getAttribute(SVNSESSION)).getRepository();
        try {
            long endRevision = repository.getDatedRevision(new Date());
            Collection logEntries = repository.log(new String[] { request.getParameter(FILE_QUERY) }, null, 1,
                    endRevision, true, true);
            List outputList = getAllEntries(logEntries);
            outputList = filterListByFilePath(outputList, request.getParameter(FILE_QUERY));
            Collections.sort(outputList, comparator);
            session.setAttribute(UNIQUE_ENTRIES, outputList);
        } catch (SVNException e) {
            e.printStackTrace();
            request.setAttribute(ERROR, e.getErrorMessage());
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
        }
        request.getRequestDispatcher(INDEX_JSP).forward(request, response);
        return;
    }

    private void doBrowserRevisionQuery(HttpServletRequest request, HttpServletResponse response,
            HttpSession session, String pFileType, String currentBranch, Comparator comparator)
            throws ServletException, IOException {
        logDebug("Dispatching Browser Revision query");

        logDebug("dispatching Revision query request");
        List uniqueEntries = getUniqueEntries(request, Long.parseLong(request.getParameter(START_REVISION)),
                Long.parseLong(request.getParameter(END_REVISION)));
        if (request.getAttribute(ERROR) != null) {
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
        }

        uniqueEntries = filterListByFileType(uniqueEntries, pFileType);
        uniqueEntries = filterListByCurrentBranch(uniqueEntries, currentBranch);

        Collections.sort(uniqueEntries, comparator);

        session.setAttribute(UNIQUE_ENTRIES, uniqueEntries);
        request.getRequestDispatcher(INDEX_JSP).forward(request, response);
    }

    private void doChangeUrl(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        HttpSession session = request.getSession();

        logDebug("dispatching changeUrl");
        SVNHttpSession svnsession = (SVNHttpSession) session.getAttribute(SVNSESSION);
        if (svnsession == null) {
            request.setAttribute(ERROR,
                    "svnsession is null, try deleting your cookies and accessing SVNBrowser with no parameters");
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
        }

        String webappRoot = this.getServletContext().getRealPath("/") == null ? getInitParameter(WEBAPP_ROOT)
                : this.getServletContext().getRealPath("/");
        SVNHttpSession newSvnsession = new SVNHttpSession(request.getParameter(CHANGE_URL),
                getInitParameter(USER_NAME), getInitParameter("password"), webappRoot,
                getInitParameter(REPOSITORY_DIR));
        logDebug("initializing SVNRepository.\nrepositoryURL=" + newSvnsession.getRepositoryURL() + "\nuser="
                + newSvnsession.getUserName());
        try {
            newSvnsession.init();
        } catch (SVNException e) {
            e.printStackTrace();
            request.setAttribute(ERROR, e.getErrorMessage());
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
        }

        session.setAttribute(SVNSESSION, newSvnsession);
        List branches = getAllBranches(request);
        if (request.getAttribute(ERROR) != null) {
            session.setAttribute(SVNSESSION, newSvnsession);//revert to original session
            request.getRequestDispatcher(INDEX_JSP).forward(request, response);
            return;
        }
        session.setAttribute(BRANCHES, branches);

        logDebug("closing existing svnsession ");
        svnsession.getRepository().closeSession();

        session.setAttribute(REPOSITORY_URL, request.getParameter(CHANGE_URL));//set the new URL in the session (used by JSP)
        session.removeAttribute(CURRENT_BRANCH);
        //currentBranch = persistCurrentBranch(request);//set the current branch

        //List uniqueEntries = getUniqueEntries(request, startDate, endDate);
        //if(request.getAttribute(ERROR)!= null){
        //   request.getRequestDispatcher("index.jsp").forward(request, response);
        //   return;
        //}

        //uniqueEntries = filterListByCurrentBranch(uniqueEntries, currentBranch);

        //Collections.sort(uniqueEntries, comparator);

        session.setAttribute(UNIQUE_ENTRIES, null);

        request.getRequestDispatcher(INDEX_JSP).forward(request, response);
        return;
    }

    /////////////////////////////////////Utility methods
    private List getAllBranches(HttpServletRequest request) {//TODO this logic needs to be fixed, too many assumptions
        HttpSession session = request.getSession();
        SVNHttpSession svnsession = (SVNHttpSession) session.getAttribute(SVNSESSION);
        org.tigris.subversion.javahl.SVNClient client = new org.tigris.subversion.javahl.SVNClient();
        client.username(svnsession.getUserName());
        client.password(svnsession.getPassword());
        List branchesList = new ArrayList();
        try {
            DirEntry[] branches = client.list(svnsession.getRepositoryURL(), Revision.HEAD, false);
            for (int i = 0; i < branches.length; i++) {
                if (branches[i].getPath().equals("trunk")) {//in VitaminShoppe's case, the trunk has no sub-branch
                    branchesList.add(branches[i].getPath());
                    continue;
                }
                DirEntry[] subBranches = client.list(svnsession.getRepositoryURL() + "/" + branches[i].getPath(),
                        Revision.HEAD, false);
                for (int j = 0; j < subBranches.length; j++) {
                    branchesList.add(branches[i].getPath() + "/" + subBranches[j].getPath());
                }
            }
            //branchesList.add("trunk");
        } catch (ClientException e) {
            request.setAttribute(ERROR, e.getMessage());
            e.printStackTrace();
        }
        return branchesList;
    }

    private void sortAndFilterSvnQuery(HttpServletRequest request, HttpServletResponse response, List entriesList)
            throws IOException {
        Collections.sort(entriesList, Sorter.PATH_INSENSITIVE_COMPARATOR);

        if (request.getParameter(FILE_TYPE) != null && request.getParameter(FILE_PATH) == null) {//filter by fileType
            String fileType = request.getParameter(FILE_TYPE);
            entriesList = filterListByFileType(entriesList, fileType);
        } else if (request.getParameter(FILE_TYPE) == null && request.getParameter(FILE_PATH) != null) {//filter by filePath
            String filePath = request.getParameter(FILE_PATH);
            entriesList = filterListByFilePath(entriesList, filePath);
        } else if (request.getParameter(FILE_TYPE) != null && request.getParameter(FILE_PATH) != null) {//filter by both
            String fileType = request.getParameter(FILE_TYPE);
            String filePath = request.getParameter(FILE_PATH);
            entriesList = filterListByFilePath(entriesList, filePath);//the path is a larger restriction, do first
            entriesList = filterListByFileType(entriesList, fileType);
        }

        for (Iterator iter = entriesList.iterator(); iter.hasNext();) {
            response.getWriter().println(((SVNEntryFacade) iter.next()).getPath());
        }

        logDebug("svnQuery: returning " + entriesList.size() + " entries");
    }

    private List filterListByDateRange(List input, Date startDate, Date endDate) {
        List filteredList = new ArrayList();
        for (int i = 0; i < input.size(); i++) {
            SVNEntryFacade entry = (SVNEntryFacade) input.get(i);
            if ((entry.getTimestamp().after(startDate) || entry.getTimestamp().equals(startDate))
                    && entry.getTimestamp().before(endDate) || entry.getTimestamp().equals(endDate)) {
                filteredList.add(entry);
            }
        }
        return filteredList;
    }

    private List filterListByCurrentBranch(List input, String currentBranch) {
        List filteredList = new ArrayList();
        for (int i = 0; i < input.size(); i++) {
            SVNEntryFacade entry = (SVNEntryFacade) input.get(i);
            if (entry.getPath().indexOf("/" + currentBranch + "/") >= 0) {//TODO this is causing issues with repositories whose Bran
                filteredList.add(entry);
            }
        }
        return filteredList;
    }

    private List filterListByFilePath(List input, String filePath) {
        List filteredList = new ArrayList();
        if (filePath == null || filePath.length() == 0) {
            return input;
        } else {
            for (int i = 0; i < input.size(); i++) {
                SVNEntryFacade entry = (SVNEntryFacade) input.get(i);
                if (entry.getPath().startsWith(filePath)) {
                    filteredList.add(entry);
                    //logDebug(i+" "+entry.getPath());
                }
            }
        }
        return filteredList;
    }

    private List filterListByFileType(List input, String fileType) {
        List filteredList = new ArrayList();
        if (fileType == null || fileType.length() == 0) {
            return input;
        } else if (("jsp".equals(fileType) || ".jsp".equals(fileType) || "*.jsp".equals(fileType))) {
            //logDebug("uniqueEntries.size()="+input.size());
            for (int i = 0; i < input.size(); i++) {
                SVNEntryFacade entry = (SVNEntryFacade) input.get(i);
                if (entry.getPath().matches(".*\\.jsp") || entry.getPath().matches(".*\\.jspf")) {
                    filteredList.add(entry);
                    //logDebug(i+" "+entry.getPath());
                }
            }
        } else {
            logDebug("uniqueEntries.size()=" + input.size());
            for (int i = 0; i < input.size(); i++) {
                SVNEntryFacade entry = (SVNEntryFacade) input.get(i);
                //String ft = fileType.matches("\\..*") ? fileType.substring(1) : fileType;
                if (fileType.startsWith("*") || fileType.startsWith(".")) {
                    String ft = fileType.replaceAll("\\*", "");
                    //logDebug("ft="+ft);
                    if (entry.getPath().matches(".*" + ft) || entry.getPath().matches(".*\\." + ft)) {
                        filteredList.add(entry);
                        //logDebug(i+" "+entry.getPath());
                    }
                } else if (fileType.indexOf("/") > -1) {//searching for a path+filename
                    if (entry.getPath().indexOf(fileType) > -1) {
                        filteredList.add(entry);
                    }
                } else {//searching for just the filename
                    String comparePath = entry.getPath().substring(entry.getPath().lastIndexOf("/") + 1);
                    if (comparePath.equals(fileType)) {
                        filteredList.add(entry);
                    }
                }
            }
        }

        return filteredList;
    }

    public List getUniqueEntries(HttpServletRequest request, Date startDate, Date endDate) {
        List outputList = new ArrayList();

        try {
            Collection latestEntries = getSVNLogEntries(request, startDate, endDate);
            if (latestEntries == null || latestEntries.size() == 0) {
                if (request.getAttribute(ERROR) != null) {
                    return null;
                }
            } else {
                HashMap uniqueEntries = getLatestEntries(latestEntries);
                Iterator iter = uniqueEntries.keySet().iterator();
                while (iter.hasNext()) {
                    SVNEntryFacade entry = (SVNEntryFacade) uniqueEntries.get(iter.next());
                    outputList.add(entry);
                }
            }
        } catch (SVNException e) {
            request.setAttribute(ERROR, e.getErrorMessage());
            e.printStackTrace();
        }
        return outputList;
    }

    public List getUniqueEntries(HttpServletRequest request, long startRevision, long endRevision) {
        List outputList = new ArrayList();

        try {
            Collection latestEntries = getSVNLogEntries(request, startRevision, endRevision);
            if (latestEntries.size() == 0) {
                if (request.getAttribute(ERROR) != null) {
                    return null;
                }
            } else {
                HashMap uniqueEntries = getLatestEntries(latestEntries);
                Iterator iter = uniqueEntries.keySet().iterator();
                while (iter.hasNext()) {
                    SVNEntryFacade entry = (SVNEntryFacade) uniqueEntries.get(iter.next());
                    outputList.add(entry);
                }
            }
        } catch (SVNException e) {
            request.setAttribute(ERROR, e.getErrorMessage());
            e.printStackTrace();
        }
        return outputList;
    }

    private HashMap getLatestEntries(Collection logEntries) {
        HashMap uniqueEntries = new HashMap();
        for (Iterator entries = logEntries.iterator(); entries.hasNext();) {
            SVNLogEntry logEntry = (SVNLogEntry) entries.next();
            if (logEntry.getChangedPaths().size() > 0) {
                Set changedPathsSet = logEntry.getChangedPaths().keySet();
                for (Iterator changedPaths = changedPathsSet.iterator(); changedPaths.hasNext();) {
                    SVNLogEntryPath entryPath = (SVNLogEntryPath) logEntry.getChangedPaths()
                            .get(changedPaths.next());
                    SVNEntryFacade fileEntry = new SVNEntryFacade(new File(entryPath.getPath()), entryPath,
                            logEntry, true);
                    if (uniqueEntries.containsKey(fileEntry.file.getAbsolutePath())) {
                        SVNEntryFacade existingEntry = (SVNEntryFacade) uniqueEntries
                                .get(fileEntry.file.getAbsolutePath());
                        if (existingEntry.getRevision() <= logEntry.getRevision()) {
                            uniqueEntries.put(fileEntry.file.getAbsolutePath(), fileEntry);
                        }
                    } else {
                        uniqueEntries.put(fileEntry.file.getAbsolutePath(), fileEntry);
                    }
                }
            }
        }
        return uniqueEntries;
    }

    private List getAllEntries(Collection logEntries) {
        List uniqueEntries = new ArrayList();
        for (Iterator entries = logEntries.iterator(); entries.hasNext();) {
            SVNLogEntry logEntry = (SVNLogEntry) entries.next();
            if (logEntry.getChangedPaths().size() > 0) {
                Set changedPathsSet = logEntry.getChangedPaths().keySet();
                for (Iterator changedPaths = changedPathsSet.iterator(); changedPaths.hasNext();) {
                    SVNLogEntryPath entryPath = (SVNLogEntryPath) logEntry.getChangedPaths()
                            .get(changedPaths.next());
                    SVNEntryFacade fileEntry = new SVNEntryFacade(new File(entryPath.getPath()), entryPath,
                            logEntry, true);
                    uniqueEntries.add(fileEntry);

                }
            }
        }
        return uniqueEntries;
    }

    public Collection getSVNLogEntries(HttpServletRequest request, Date startDate, Date endDate)
            throws SVNException {
        SVNRepository repository = ((SVNHttpSession) request.getSession().getAttribute(SVNSESSION)).getRepository();
        long startRevision = repository.getDatedRevision(startDate);
        //long endRevision = repository.getDatedRevision(new Date(endDate.getTime()+_2359HOURS));
        long endRevision = repository.getDatedRevision(endDate);
        logDebug("startDate=" + startDate);

        Collection logEntries = null;
        if (request.getSession().getAttribute(CURRENT_BRANCH) != null) {
            logEntries = repository.log(new String[] { (String) request.getSession().getAttribute(CURRENT_BRANCH) },
                    null, startRevision, endRevision, true, true);
        } else {
            repository.log(new String[] { "" }, null, startRevision, endRevision, true, true);
        }
        return logEntries;
    }

    public Collection getSVNLogEntries(HttpServletRequest request, long startRevision, long endRevision)
            throws SVNException {
        SVNRepository repository = ((SVNHttpSession) request.getSession().getAttribute(SVNSESSION)).getRepository();
        Collection logEntries = repository.log(new String[] { "" }, null, startRevision, endRevision, true, true);
        return logEntries;
    }

    /////////////////////////////////////Session Persistence methods
    //these are called at the beginning of every request
    private void initBranches(HttpServletRequest request) {
        if (request.getSession().getAttribute(BRANCHES) == null) {
            List branches = getAllBranches(request);
            //branches.add("trunk");
            request.getSession().setAttribute(BRANCHES, branches);
        }
    }

    private String persistCurrentBranch(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String currentBranch = "";
        if (request.getParameter(CURRENT_BRANCH) == null) {
            if (session.getAttribute(CURRENT_BRANCH) != null) {
                currentBranch = (String) session.getAttribute(CURRENT_BRANCH);
            } else {
                List branches = getAllBranches(request);
                for (int i = 0; i < branches.size(); i++) {
                    if ("trunk".equals((String) branches.get(i))) {
                        currentBranch = (String) branches.get(i);//if we find "trunk" in List, use that as default
                        break;
                    }
                }
                if ("".equals(currentBranch) && branches.size() > 0) {
                    currentBranch = (String) branches.get(0);//we didn't find "trunk", so use whatever
                }
                session.setAttribute(CURRENT_BRANCH, currentBranch);
            }
        } else {
            currentBranch = request.getParameter(CURRENT_BRANCH);
            session.setAttribute(CURRENT_BRANCH, currentBranch);
        }
        return currentBranch;
    }

    private String persistFileType(HttpServletRequest request) {
        HttpSession session = request.getSession();
        String fileType = "";
        if (request.getParameter(P_FILE_TYPE) == null) {
            if (session.getAttribute(FILE_TYPE) != null) {
                fileType = (String) session.getAttribute(FILE_TYPE);
            } else {
                fileType = "*";
                session.setAttribute(FILE_TYPE, "*");
            }
        } else {
            fileType = request.getParameter(P_FILE_TYPE);
            session.setAttribute(FILE_TYPE, fileType);
        }
        return fileType;
    }

    private Date persistEndDate(HttpServletRequest request) {
        HttpSession session = request.getSession();
        Date endDate = null;
        if (request.getParameter(END_DATE) == null) {
            if (session.getAttribute(END_DATE) == null) {//the first request(default)
                endDate = new Date((new Date()).getTime());
                session.setAttribute(END_DATE, endDate);
                session.setAttribute(IS_SHORT_END_DATE, Boolean.TRUE);//default to short style
            } else {
                endDate = (Date) session.getAttribute(END_DATE);
            }
        } else {
            try {
                if (request.getParameter(END_DATE).matches(sdfRegex)) {
                    endDate = new Date(sdf.parse(request.getParameter(END_DATE)).getTime() + _2359HOURS);//add 23:59
                    session.setAttribute(IS_SHORT_END_DATE, Boolean.TRUE);
                } else if (request.getParameter(END_DATE).matches(sdfFullRegex)) {
                    endDate = new Date(sdfFull.parse(request.getParameter(END_DATE)).getTime());//add one second
                    session.setAttribute(IS_SHORT_END_DATE, Boolean.FALSE);
                }
                session.setAttribute(END_DATE, endDate);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return endDate;
    }

    private Date persistStartDate(HttpServletRequest request) {
        HttpSession session = request.getSession();
        Date startDate = null;
        if (request.getParameter(START_DATE) == null) {
            if (session.getAttribute(START_DATE) == null) {//the first request(default)
                startDate = new Date(837039900000L);
                session.setAttribute(IS_SHORT_START_DATE, Boolean.TRUE);//default to short style
                session.setAttribute(START_DATE, startDate);
            } else {
                startDate = (Date) session.getAttribute(START_DATE);
            }
        } else {
            try {
                if (request.getParameter(START_DATE).matches(sdfRegex)) {
                    startDate = sdf.parse(request.getParameter(START_DATE));
                    session.setAttribute(IS_SHORT_START_DATE, Boolean.TRUE);
                } else if (request.getParameter(START_DATE).matches(sdfFullRegex)) {
                    startDate = sdfFull.parse(request.getParameter(START_DATE));
                    session.setAttribute(IS_SHORT_START_DATE, Boolean.FALSE);
                }
                session.setAttribute(START_DATE, startDate);
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        return startDate;
    }

    private Comparator persistSortBy(HttpServletRequest request) {
        HttpSession session = request.getSession();
        Comparator comparator = (Comparator) session.getAttribute(SORT_BY);
        if (request.getParameter(SORT_BY) == null) {
            if (session.getAttribute(SORT_BY) == null) {
                comparator = Sorter.DATE_REVERSE_COMPARATOR;//default
            }
        } else {
            if (session.getAttribute(SORT_BY) == null) {
                if ("togglePath".equals(request.getParameter(SORT_BY))) {
                    comparator = Sorter.PATH_INSENSITIVE_REVERSE_COMPARATOR;
                } else if ("toggleAuthor".equals(request.getParameter(SORT_BY))) {
                    comparator = String.CASE_INSENSITIVE_ORDER;
                } else {
                    comparator = Sorter.DATE_REVERSE_COMPARATOR;//default
                }
            } else {
                if ("togglePath".equals(request.getParameter(SORT_BY))) {
                    if (Sorter.PATH_INSENSITIVE_COMPARATOR.equals(comparator)) {
                        comparator = Sorter.PATH_INSENSITIVE_REVERSE_COMPARATOR;
                    } else {
                        comparator = Sorter.PATH_INSENSITIVE_COMPARATOR;
                    }
                } else if ("toggleAuthor".equals(request.getParameter(SORT_BY))) {
                    if (Sorter.AUTHOR_COMPARATOR.equals(comparator)) {
                        comparator = Sorter.AUTHOR_REVERSE_COMPARATOR;
                    } else {
                        comparator = Sorter.AUTHOR_COMPARATOR;
                    }
                } else if ("toggleDate".equals(request.getParameter(SORT_BY))) {
                    if (Sorter.DATE_COMPARATOR.equals(comparator)) {
                        comparator = Sorter.DATE_REVERSE_COMPARATOR;
                    } else {
                        comparator = Sorter.DATE_COMPARATOR;
                    }
                } else if ("toggleRevision".equals(request.getParameter(SORT_BY))) {
                    if (Sorter.REV_COMPARATOR.equals(comparator)) {
                        comparator = Sorter.REV__REVERSE_COMPARATOR;
                    } else {
                        comparator = Sorter.REV_COMPARATOR;
                    }
                }
            }

        }
        session.setAttribute(SORT_BY, comparator);
        return comparator;
    }

    //////////////////////////////////////initialization Methods
    private static void initSVNRepositoryFactories() {
        DAVRepositoryFactory.setup();
        SVNRepositoryFactoryImpl.setup();
        FSRepositoryFactory.setup();
    }

    public void init() throws ServletException {
        try {
            super.init();
        } catch (ServletException e) {
            e.printStackTrace();
        }
        webappRoot = (this.getServletContext().getRealPath("/") == null ? getInitParameter(WEBAPP_ROOT)
                : this.getServletContext().getRealPath("/")).replaceAll("[/\\\\]+", "\\" + File.separator);
        ;
        System.out.println("init() setting webappRoot to " + webappRoot);
        if (getServletContext().getAttribute("com.lrodriguez.model.SVNLogEntryDB") == null) {
            try {
                initSVNRepositoryFactories();
                //SVNLogEntryDB db = SVNLogEntryDB.getInstance();
                SVNRepository repository = SVNRepositoryFactory
                        .create(SVNURL.parseURIEncoded(getInitParameter(REPOSITORY_URL)));
                ISVNAuthenticationManager manager = SVNWCUtil.createDefaultAuthenticationManager(
                        getInitParameter(USER_NAME), getInitParameter("password"));
                repository.setAuthenticationManager(manager);

            } catch (SVNException e) {
                e.printStackTrace();
            }
        }
    }

    public void logDebug(String arg) {
        System.out.println(arg);
    }

}