Package org.watermint.sourcecolon.org.opensolaris.opengrok.web

Source Code of org.watermint.sourcecolon.org.opensolaris.opengrok.web.PageConfig

/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* See LICENSE.txt included in this distribution for the specific
* language governing permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at LICENSE.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/

/*
* Copyright (c) 2011 Jens Elkner.
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Portions Copyright (c) 2013 Takayuki Okazaki.
*/
package org.watermint.sourcecolon.org.opensolaris.opengrok.web;

import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.Query;
import org.watermint.sourcecolon.org.opensolaris.opengrok.analysis.AnalyzerGuru;
import org.watermint.sourcecolon.org.opensolaris.opengrok.analysis.Definitions;
import org.watermint.sourcecolon.org.opensolaris.opengrok.analysis.FileAnalyzer;
import org.watermint.sourcecolon.org.opensolaris.opengrok.analysis.FileAnalyzerFactory;
import org.watermint.sourcecolon.org.opensolaris.opengrok.configuration.Project;
import org.watermint.sourcecolon.org.opensolaris.opengrok.configuration.RuntimeEnvironment;
import org.watermint.sourcecolon.org.opensolaris.opengrok.index.IgnoredNames;
import org.watermint.sourcecolon.org.opensolaris.opengrok.index.IndexDatabase;
import org.watermint.sourcecolon.org.opensolaris.opengrok.search.QueryBuilder;
import org.watermint.sourcecolon.org.opensolaris.opengrok.search.context.Context;
import org.watermint.sourcecolon.org.opensolaris.opengrok.util.IOUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.security.InvalidParameterException;
import java.text.Format;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;

/**
* A simple container to lazy initialize common vars wrt. a single request.
* It MUST NOT be shared between several requests and {@link #cleanup()} should
* be called before the page context gets destroyed (e.g. by overwriting
* {@code jspDestroy()} or when leaving the {@code service} method.
* <p/>
* Purpose is to decouple implementation details from web design, so that the
* JSP developer does not need to know every implementation detail and normally
* has to deal with this class/wrapper, only (so some people may like to call
* this class a bean with request scope ;-)). Furthermore it helps to keep the
* pages (how content gets generated) consistent and to document the request
* parameters used.
* <p/>
* General contract for this class (i.e. if not explicitly documented):
* no method of this class changes neither the request nor the response.
*
* @author Jens Elkner
* @version $Revision$
*/
public final class PageConfig {
    // TODO if still used, get it from the app context

    private RuntimeEnvironment env;
    private IgnoredNames ignoredNames;
    private String path;
    private File resourceFile;
    private String resourcePath;
    private String sourceRootPath;
    private Boolean isDir;
    private String uriEncodedPath;
    private Prefix prefix;
    private String pageTitle;
    private String rev;
    private SortedSet<String> requestedProjects;
    private String requestedProjectsString;
    private List<String> dirFileList;
    private QueryBuilder queryBuilder;
    private File dataRoot;
    private static final Logger log = Logger.getLogger(PageConfig.class.getName());

    /**
     * Get a list of filenames in the requested path.
     *
     * @return an empty list, if the resource does not exist, is not a
     *         directory or an error occurred when reading it, otherwise a list of
     *         filenames in that directory, sorted alphabetically
     * @see #getResourceFile()
     * @see #isDir()
     */
    public List<String> getResourceFileList() {
        if (dirFileList == null) {
            String[] files = null;
            if (isDir() && getResourcePath().length() > 1) {
                files = getResourceFile().list();
            }
            if (files == null) {
                dirFileList = Collections.emptyList();
            } else {
                Arrays.sort(files, String.CASE_INSENSITIVE_ORDER);
                dirFileList = Collections.unmodifiableList(Arrays.asList(files));
            }
        }
        return dirFileList;
    }

    /**
     * Get the time of last modification of the related file or directory.
     *
     * @return the last modification time of the related file or directory.
     * @see File#lastModified()
     */
    public long getLastModified() {
        return getResourceFile().lastModified();
    }

    /**
     * Get the int value of the given request parameter.
     *
     * @param name         name of the parameter to lookup.
     * @param defaultValue value to return, if the parameter is not set, is not
     *                     a number, or is &lt; 0.
     * @return the parsed int value on success, the given default value otherwise.
     */
    public int getIntParam(String name, int defaultValue) {
        int ret = defaultValue;
        String s = req.getParameter(name);
        if (s != null && s.length() != 0) {
            try {
                int x = Integer.parseInt(s, 10);
                if (x >= 0) {
                    ret = x;
                }
            } catch (Exception e) {
                log.log(Level.INFO, "Failed to parse integer " + s, e);
            }
        }
        return ret;
    }

    /**
     * Get the <b>start</b> index for a search result to return by looking up
     * the {@code start} request parameter.
     *
     * @return 0 if the corresponding start parameter is not set or not a number,
     *         the number found otherwise.
     */
    public int getSearchStart() {
        return getIntParam("start", 0);
    }

    /**
     * Get the number of search results to max. return by looking up the
     * {@code n} request parameter.
     *
     * @return the default number of hits if the corresponding start parameter
     *         is not set or not a number, the number found otherwise.
     */
    public int getSearchMaxItems() {
        return getIntParam("n", getEnv().getHitsPerPage());
    }

    /**
     * Get sort orders from the request parameter {@code sort} and if this list
     * would be empty from the cookie {@code OpenGrokorting}.
     *
     * @return a possible empty list which contains the sort order values in
     *         the same order supplied by the request parameter or cookie(s).
     */
    public List<SortOrder> getSortOrder() {
        List<SortOrder> sort = new ArrayList<>();
        List<String> vals = getParamVals("sort");
        for (String s : vals) {
            SortOrder so = SortOrder.get(s);
            if (so != null) {
                sort.add(so);
            }
        }
        if (sort.isEmpty()) {
            vals = getCookieVals("OpenGrokSorting");
            for (String s : vals) {
                SortOrder so = SortOrder.get(s);
                if (so != null) {
                    sort.add(so);
                }
            }
        }
        return sort;
    }

    /**
     * Get a reference to the {@code QueryBuilder} wrt. to the current request
     * parameters:
     * <dl>
     * <dt>q</dt>
     * <dd>freetext lookup rules</dd>
     * <dt>defs</dt>
     * <dd>definitions lookup rules</dd>
     * <dt>path</dt>
     * <dd>path related rules</dd>
     * </dl>
     *
     * @return a query builder with all relevant fields populated.
     */
    public QueryBuilder getQueryBuilder() {
        if (queryBuilder == null) {
            queryBuilder = new QueryBuilder().setFreetext(req.getParameter("q")).setDefs(req.getParameter("defs")).setRefs(req.getParameter("refs")).setPath(req.getParameter("path"));

            // This is for backward compatibility with links created by OpenGrok
            // 0.8.x and earlier. We used to concatenate the entire query into a
            // single string and send it in the t parameter. If we get such a
            // link, just add it to the freetext field, and we'll get the old
            // behaviour. We can probably remove this code in the first feature
            // release after 0.9.
            String t = req.getParameter("t");
            if (t != null) {
                queryBuilder.setFreetext(t);
            }
        }
        return queryBuilder;
    }

    /**
     * Get the revision parameter {@code r} from the request.
     *
     * @return {@code "r=<i>revision</i>"} if found, an empty string otherwise.
     */
    public String getRequestedRevision() {
        if (rev == null) {
            String tmp = req.getParameter("r");
            rev = (tmp != null && tmp.length() > 0) ? "r=" + tmp : "";
        }
        return rev;
    }

    /**
     * Get the name which should be show as "Crossfile"
     *
     * @return the name of the related file or directory.
     */
    public String getCrossFilename() {
        return getResourceFile().getName();
    }

    /**
     * Get the {@code path} parameter and display value for "Search only in"
     * option.
     *
     * @return always an array of 3 fields, whereby field[0] contains the
     *         path value to use (starts and ends always with a '/'). Field[1] the
     *         contains string to show in the UI. field[2] is set to
     *         {@code disabled=""} if the current path is the "/" directory,
     *         otherwise set to an empty string.
     */
    public String[] getSearchOnlyIn() {
        if (isDir()) {
            return path.length() == 0 ? new String[]{"/", "/", "disabled=\"\""} : new String[]{path, path, ""};
        }
        String[] res = new String[3];
        res[0] = path.substring(0, path.lastIndexOf('/') + 1);
        res[1] = path.substring(res[0].length());
        res[2] = "";
        return res;
    }

    /**
     * Same as {@link #getRequestedProjects()} but returns the project names as
     * a coma separated String.
     *
     * @return a possible empty String but never {@code null}.
     */
    public String getRequestedProjectsAsString() {
        if (requestedProjectsString == null) {
            Set<String> projects = getRequestedProjects();
            if (projects.isEmpty()) {
                requestedProjectsString = "";
            } else {
                StringBuilder buf = new StringBuilder();
                for (String name : projects) {
                    buf.append(name).append(',');
                }
                buf.setLength(buf.length() - 1);
                requestedProjectsString = buf.toString();
            }
        }
        return requestedProjectsString;
    }

    /**
     * Get the document hash provided by the request parameter {@code h}.
     *
     * @return {@code null} if the request does not contain such a parameter,
     *         its value otherwise.
     */
    public String getDocumentHash() {
        return req.getParameter("h");
    }

    /**
     * Get a reference to a set of requested projects via request parameter
     * {@code project} or cookies or defaults.
     * <p/>
     * NOTE: This method assumes, that project names do <b>not</b> contain
     * a comma (','), since this character is used as name separator!
     *
     * @return a possible empty set of project names aka descriptions but never
     *         {@code null}. It is determined as
     *         follows:
     *         <ol>
     *         <li>If there is no project in the runtime environment (RTE) an empty
     *         set is returned. Otherwise:</li>
     *         <li>If there is only one project in the RTE, this one gets returned (no
     *         matter, what the request actually says). Otherwise</li>
     *         <li>If the request parameter {@code project} contains any available
     *         project, the set with invalid projects removed gets returned.
     *         Otherwise:</li>
     *         <li>If the request has a cookie with the name {@code OpenGrokProject}
     *         and it contains any available project, the set with invalid
     *         projects removed gets returned. Otherwise:</li>
     *         <li>If a default project is set in the RTE, this project gets returned.
     *         Otherwise:</li>
     *         <li>an empty set</li>
     *         </ol>
     */
    public SortedSet<String> getRequestedProjects() {
        if (requestedProjects == null) {
            requestedProjects = getRequestedProjects("project", "OpenGrokProject");
        }
        return requestedProjects;
    }

    private static Pattern COMMA_PATTERN = Pattern.compile(",");

    private static void splitByComma(String value, List<String> result) {
        if (value == null || value.length() == 0) {
            return;
        }
        String p[] = COMMA_PATTERN.split(value);
        for (String aP : p) {
            if (aP.length() != 0) {
                result.add(aP);
            }
        }
    }

    /**
     * Get the cookie values for the given name. Splits comma separated values
     * automatically into a list of Strings.
     *
     * @param cookieName name of the cookie.
     * @return a possible empty list.
     */
    public List<String> getCookieVals(String cookieName) {
        Cookie[] cookies = req.getCookies();
        ArrayList<String> res = new ArrayList<>();
        if (cookies != null) {
            for (int i = cookies.length - 1; i >= 0; i--) {
                if (cookies[i].getName().equals(cookieName)) {
                    splitByComma(cookies[i].getValue(), res);
                }
            }
        }
        return res;
    }

    /**
     * Get the parameter values for the given name. Splits comma separated
     * values automatically into a list of Strings.
     *
     * @param paramName name of the parameter.
     * @return a possible empty list.
     */
    private List<String> getParamVals(String paramName) {
        String vals[] = req.getParameterValues(paramName);
        List<String> res = new ArrayList<>();
        if (vals != null) {
            for (int i = vals.length - 1; i >= 0; i--) {
                splitByComma(vals[i], res);
            }
        }
        return res;
    }

    /**
     * Same as {@link #getRequestedProjects()}, but with a variable cookieName
     * and parameter name. This way it is trivial to implement a project filter
     * ...
     *
     * @param paramName  the name of the request parameter, which possibly
     *                   contains the project list in question.
     * @param cookieName name of the cookie which possible contains project
     *                   lists used as fallback
     * @return a possible empty set but never {@code null}.
     */
    protected SortedSet<String> getRequestedProjects(String paramName, String cookieName) {
        TreeSet<String> set = new TreeSet<>();
        List<Project> projects = getEnv().getProjects();
        if (projects == null) {
            return set;
        }
        if (projects.size() == 1) {
            set.add(projects.get(0).getProjectId());
            return set;
        }
        List<String> vals = getParamVals(paramName);
        for (String s : vals) {
            if (Project.getByProjectId(s) != null) {
                set.add(s);
            }
        }
        if (set.isEmpty()) {
            List<String> cookies = getCookieVals(cookieName);
            for (String s : cookies) {
                if (Project.getByProjectId(s) != null) {
                    set.add(s);
                }
            }
        }
        if (set.isEmpty()) {
            Project defaultProject = env.getDefaultProject();
            if (defaultProject != null) {
                set.add(defaultProject.getProjectId());
            }
        }
        return set;
    }

    /**
     * Set the page title to use.
     *
     * @param title title to set (might be {@code null}).
     */
    public void setTitle(String title) {
        pageTitle = title;
    }

    /**
     * Get the page title to use.
     *
     * @return {@code null} if not set, the page title otherwise.
     */
    public String getTitle() {
        return pageTitle;
    }

    /**
     * Get the current runtime environment.
     *
     * @return the runtime env.
     * @see RuntimeEnvironment#getInstance()
     * @see RuntimeEnvironment#register()
     */
    public RuntimeEnvironment getEnv() {
        if (env == null) {
            env = RuntimeEnvironment.getInstance().register();
        }
        return env;
    }

    /**
     * Get the name patterns used to determine, whether a file should be
     * ignored.
     *
     * @return the corresponding value from the current runtime config..
     */
    public IgnoredNames getIgnoredNames() {
        if (ignoredNames == null) {
            ignoredNames = getEnv().getIgnoredNames();
        }
        return ignoredNames;
    }

    /**
     * Get the canonical path to root of the source tree. File separators are
     * replaced with a '/'.
     *
     * @return The on disk source root directory.
     * @see RuntimeEnvironment#getSourceRootPath()
     */
    public String getSourceRootPath() {
        if (sourceRootPath == null) {
            sourceRootPath = getEnv().getSourceRootPath().replace(File.separatorChar, '/');
        }
        return sourceRootPath;
    }

    /**
     * Get the prefix for the related request.
     *
     * @return {@link Prefix#UNKNOWN} if the servlet path matches any known
     *         prefix, the prefix otherwise.
     */
    public Prefix getPrefix() {
        if (prefix == null) {
            prefix = Prefix.get(req.getServletPath());
        }
        return prefix;
    }

    /**
     * Get the canonical path of the related resource relative to the
     * source root directory (used file separators are all '/'). No check is
     * made, whether the obtained path is really an accessible resource on disk.
     *
     * @return a possible empty String (denotes the source root directory) but
     *         not {@code null}.
     * @see HttpServletRequest#getPathInfo()
     */
    public String getPath() {
        if (path == null) {
            path = Util.getCanonicalPath(req.getPathInfo(), '/');
            if ("/".equals(path)) {
                path = "";
            }
        }
        return path;
    }

    /**
     * If a requested resource is not available, append "/on/" to
     * the source root directory and try again to resolve it.
     *
     * @return on success a none-{@code null} gets returned, which should be
     *         used to redirect the client to the propper path.
     */
    public String getOnRedirect() {
        File newFile = new File(getSourceRootPath() + "/on/" + getPath());
        if (newFile.canRead()) {
            return req.getContextPath() + req.getServletPath() + "/on" + getUriEncodedPath() + (newFile.isDirectory() ? trailingSlash(path) : "");
        }
        return null;
    }

    /**
     * Get the on disk file to the request related file or directory.
     * <p/>
     * NOTE: If a repository contains hard or symbolic links, the returned
     * file may finally point to a file outside of the source root directory.
     *
     * @return {@code new File("/")} if the related file or directory is not
     *         available (can not be find below the source root directory),
     *         the readable file or directory otherwise.
     * @see #getSourceRootPath()
     * @see #getPath()
     */
    public File getResourceFile() {
        if (resourceFile == null) {
            resourceFile = new File(getSourceRootPath(), getPath());
            if (!resourceFile.canRead()) {
                resourceFile = new File("/");
            }
        }
        return resourceFile;
    }

    /**
     * Get the canonical on disk path to the request related file or directory
     * with all file separators replaced by a '/'.
     *
     * @return "/" if the evaluated path is invalid or outside the source root
     *         directory), otherwise the path to the readable file or directory.
     * @see #getResourceFile()
     */
    public String getResourcePath() {
        if (resourcePath == null) {
            resourcePath = getResourceFile().getPath().replace(File.separatorChar, '/');
        }
        return resourcePath;
    }

    /**
     * Check, whether the related request resource matches a valid file or
     * directory below the source root directory and wether it matches an
     * ignored pattern.
     *
     * @return {@code true} if the related resource does not exists or should be
     *         ignored.
     * @see #getIgnoredNames()
     * @see #getResourcePath()
     */
    public boolean resourceNotAvailable() {
        getIgnoredNames();
        return getResourcePath().equals("/") || ignoredNames.ignore(getPath()) || ignoredNames.ignore(resourceFile.getParentFile().getName());
    }

    /**
     * Check, whether the request related path represents a directory.
     *
     * @return {@code true} if directory related request
     */
    public boolean isDir() {
        if (isDir == null) {
            isDir = getResourceFile().isDirectory();
        }
        return isDir;
    }

    private static String trailingSlash(String path) {
        return path.length() == 0 || path.charAt(path.length() - 1) != '/' ? "/" : "";
    }

    private File checkFile(File dir, String name, boolean compressed) {
        File f = null;
        if (compressed) {
            f = new File(dir, name + ".gz");
            if (f.exists() && f.isFile() && f.lastModified() >= resourceFile.lastModified()) {
                return f;
            }
        }
        f = new File(dir, name);
        if (f.exists() && f.isFile() && f.lastModified() >= resourceFile.lastModified()) {
            return f;
        }
        return null;
    }

    private File checkFileResolve(File dir, String name, boolean compressed) {
        File lresourceFile = new File(getSourceRootPath() + getPath(), name);
        if (!lresourceFile.canRead()) {
            lresourceFile = new File("/");
        }
        File f = null;
        if (compressed) {
            f = new File(dir, name + ".gz");
            if (f.exists() && f.isFile() && f.lastModified() >= lresourceFile.lastModified()) {
                return f;
            }
        }
        f = new File(dir, name);
        if (f.exists() && f.isFile() && f.lastModified() >= lresourceFile.lastModified()) {
            return f;
        }
        return null;
    }

    /**
     * Find the files with the given names in the {@link #getPath()} directory
     * relative to the crossfile directory of the opengrok data directory. It
     * is tried to find the compressed file first by appending the file extension
     * ".gz" to the filename. If that fails or an uncompressed version of the
     * file is younger than its compressed version, the uncompressed file gets
     * used.
     *
     * @param filenames filenames to lookup.
     * @return an empty array if the related directory does not exist or the
     *         given list is {@code null} or empty, otherwise an array, which may
     *         contain {@code null} entries (when the related file could not be found)
     *         having the same order as the given list.
     */
    public File[] findDataFiles(List<String> filenames) {
        if (filenames == null || filenames.isEmpty()) {
            return new File[0];
        }
        File[] res = new File[filenames.size()];
        for (int i = 0; i < res.length; i++) {
            res[i] = findDataFile(filenames.get(i));
        }
        return res;
    }

    public File findDataFile(String filename) {
        File dir = new File(getEnv().getDataRootPath() + Prefix.XREF_P + path);
        if (dir.exists() && dir.isDirectory()) {
            getResourceFile();
            boolean compressed = getEnv().isCompressXref();
            return checkFileResolve(dir, filename, compressed);
        }
        return null;
    }

    /**
     * Lookup the file {@link #getPath()} relative to the crossfile directory
     * of the opengrok data directory. It is tried to find the compressed file
     * first by appending the file extension ".gz" to the filename. If that
     * fails or an uncompressed version of the file is younger than its
     * compressed version, the uncompressed file gets used.
     *
     * @return {@code null} if not found, the file otherwise.
     */
    public File findDataFile() {
        return checkFile(new File(getEnv().getDataRootPath() + Prefix.XREF_P), path, env.isCompressXref());
    }

    public File getCurrentDataFile() {
        return findDataFile();
    }

    public String getFileTimestamp(File file) {
        long now = System.currentTimeMillis();
        Format dateFormatter = new SimpleDateFormat("dd-MMM-yyyy", Locale.getDefault());

        if (now - file.lastModified() < 86400000) {
            return "Today";
        } else {
            return dateFormatter.format(file.lastModified());
        }
    }

    public List<Map<String, String>> getDirectoryFiles() {
        List<Map<String, String>> files = new ArrayList<>();
        IgnoredNames ignoredNames = getEnv().getIgnoredNames();

        for (String filename : getResourceFileList()) {
            if (ignoredNames.ignore(filename)) {
                continue;
            }

            File file = new File(getResourceFile(), filename);
            Map<String, String> f = new HashMap<>();

            if (file.isDirectory()) {
                f.put("link", Util.URIEncodePath(filename) + "/");
                f.put("name", "<strong>" + filename + "</strong>/");
            } else {
                f.put("link", Util.URIEncodePath(filename));
                f.put("name", filename);
            }
            f.put("date", getFileTimestamp(file));
            f.put("size", Util.readableSize(file.length()));

            files.add(f);
        }

        return files;
    }

    public FileAnalyzer.Genre getGenre() {
        FileAnalyzerFactory a = AnalyzerGuru.find(getResourceFile().getName());
        return AnalyzerGuru.getGenre(a);
    }

    public boolean isImage() {
        return getGenre() == FileAnalyzer.Genre.IMAGE;
    }

    public boolean isHTML() {
        return getGenre() == FileAnalyzer.Genre.HTML;
    }

    public boolean isPlain() {
        return getGenre() == FileAnalyzer.Genre.PLAIN;
    }

    public boolean isBinary() {
        return getGenre() == FileAnalyzer.Genre.DATA;
    }

    public boolean isXrefable() {
        return getGenre() == FileAnalyzer.Genre.XREFABLE;
    }

    /**
     * Get the path the request should be redirected (if any).
     *
     * @return {@code null} if there is no reason to redirect, the URI encoded
     *         redirect path to use otherwise.
     */
    public String getDirectoryRedirect() {
        if (isDir()) {
            if (path.length() == 0) {
                // => /
                return null;
            }
            getPrefix();
            if (prefix != Prefix.XREF_P) {
                //if it is an existing dir perhaps people wanted dir xref
                return req.getContextPath() + Prefix.XREF_P + getUriEncodedPath() + trailingSlash(path);
            }
            String ts = trailingSlash(path);
            if (ts.length() != 0) {
                return req.getContextPath() + prefix + getUriEncodedPath() + ts;
            }
        }
        return null;
    }

    /**
     * Get the URI encoded canonical path to the related file or directory
     * (the URI part between the servlet path and the start of the query string).
     *
     * @return an URI encoded path which might be an empty string but not
     *         {@code null}.
     * @see #getPath()
     */
    public String getUriEncodedPath() {
        if (uriEncodedPath == null) {
            uriEncodedPath = Util.URIEncodePath(getPath());
        }
        return uriEncodedPath;
    }

    /**
     * Get opengrok's configured dataroot directory.
     * It is veriefied, that the used environment has a valid opengrok data root
     * set and that it is an accessable directory.
     *
     * @return the opengrok data directory.
     * @throws InvalidParameterException if inaccessable or not set.
     */
    public File getDataRoot() {
        if (dataRoot == null) {
            String tmp = getEnv().getDataRootPath();
            if (tmp == null || tmp.length() == 0) {
                throw new InvalidParameterException("dataRoot parameter is not " + "set in configuration.xml!");
            }
            dataRoot = new File(tmp);
            if (!(dataRoot.isDirectory() && dataRoot.canRead())) {
                throw new InvalidParameterException("The configured dataRoot '" + tmp + "' refers to a none-exsting or unreadable directory!");
            }
        }
        return dataRoot;
    }

    private SearchHelper currentSearchHelper = null;

    public SearchHelper getCurrentSearchHelper() {
        if (currentSearchHelper == null) {
            currentSearchHelper = prepareSearch().prepareExec(getRequestedProjects()).executeQuery().prepareSummary();
        }
        return currentSearchHelper;
    }

    /**
     * Prepare a search helper with all required information, ready to execute
     * the query implied by the related request parameters and cookies.
     * <p/>
     * NOTE: One should check the {@link SearchHelper#errorMsg} as well as
     * {@link SearchHelper#redirect} and take the appropriate action before
     * executing the prepared query or continue processing.
     * <p/>
     * This method stops populating fields as soon as an error occurs.
     *
     * @return a search helper.
     */
    public SearchHelper prepareSearch() {
        SearchHelper sh = new SearchHelper();
        sh.dataRoot = getDataRoot(); // throws Exception if none-existent
        List<SortOrder> sortOrders = getSortOrder();
        sh.order = sortOrders.isEmpty() ? SortOrder.RELEVANCY : sortOrders.get(0);
        if (getRequestedProjects().isEmpty() && getEnv().hasProjects()) {
            sh.errorMsg = "You must select a project!";
            return sh;
        }
        sh.builder = getQueryBuilder();
        if (sh.builder.getSize() == 0) {
            // Entry page show the map
            sh.redirect = req.getContextPath() + '/';
            return sh;
        }
        sh.start = getSearchStart();
        sh.maxItems = getSearchMaxItems();
        sh.contextPath = req.getContextPath();
        sh.isCrossRefSearch = getPrefix() == Prefix.SEARCH_R;
        sh.compressed = env.isCompressXref();
        sh.sourceRoot = new File(getSourceRootPath());
        return sh;
    }

    public String getBreadcrumbPath() {
        return Util.breadcrumbPath(req.getContextPath() + Prefix.XREF_P, getPath(), '/', "", true, isDir(), true);
    }

    public Map<String, File> getReadmeFiles() {
        Map<String, File> files = new HashMap<>();
        for (String file : getResourceFileList()) {
            if (file.startsWith("README") || file.endsWith("README") || file.startsWith("readme")) {
                File data = findDataFile(file);
                if (data != null) {
                    files.put(file, data);
                }
            }
        }
        return files;
    }

    public String getHtmlContents() {
        ByteArrayOutputStream content = new ByteArrayOutputStream();
        OutputStreamWriter writer = new OutputStreamWriter(content);
        try {
            try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(getResourceFile()))) {
                Util.dump(writer, new InputStreamReader(bin));
                writer.flush();
                return content.toString();
            }
        } catch (IOException e) {
            e.printStackTrace()//To change body of catch statement use File | Settings | File Templates.
            return "";
        }
    }

    public String getPlainContents() {
        ByteArrayOutputStream content = new ByteArrayOutputStream();
        OutputStreamWriter writer = new OutputStreamWriter(content);
        try {
            try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(getResourceFile()))) {
                Definitions defs = null;

                defs = IndexDatabase.getDefinitions(resourceFile);
                FileAnalyzerFactory a = AnalyzerGuru.find(resourceFile.getName());
                AnalyzerGuru.writeXref(a, new InputStreamReader(bin), writer, defs, Project.getProject(resourceFile));

                writer.flush();
                return content.toString();
            }
        } catch (IOException | ParseException | ClassNotFoundException e) {
            e.printStackTrace()//To change body of catch statement use File | Settings | File Templates.
            return "";
        }
    }

    public String fileContents(File dataFile) {
        ByteArrayOutputStream content = new ByteArrayOutputStream();
        OutputStreamWriter writer = new OutputStreamWriter(content);

        Util.dump(writer, dataFile, dataFile.getName().endsWith(".gz"));
        try {
            writer.flush();
            return content.toString();
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

    public String getCurrentQueryString() {
        QueryBuilder queryBuilder = getQueryBuilder();

        try {
            return queryBuilder.build().toString();
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }

    public String getCurrentMatch() {
        ByteArrayOutputStream content = new ByteArrayOutputStream();
        OutputStreamWriter writer = new OutputStreamWriter(content);
        QueryBuilder queryBuilder = getQueryBuilder();

        try {
            Context sourceContext = new Context(queryBuilder.build(), queryBuilder.getQueries());
            sourceContext.getContext(IOUtils.readerWithCharsetDetect(getResourceFile()), writer, req.getContextPath() + Prefix.XREF_P, null, getPath(), null, false, null);
            writer.flush();
            return content.toString();
        } catch (IOException | ParseException e) {
            e.printStackTrace();
            return "";
        }
    }

    private StringBuilder createUrl(SearchHelper sh, boolean menu) {
        StringBuilder url = new StringBuilder(64);
        QueryBuilder qb = sh.builder;
        if (menu) {
            url.append("search?");
        } else {
            Util.appendQuery(url, "sort", sh.order.toString());
        }
        if (qb != null) {
            Util.appendQuery(url, "q", qb.getFreetext());
            Util.appendQuery(url, "defs", qb.getDefs());
            Util.appendQuery(url, "refs", qb.getRefs());
            Util.appendQuery(url, "path", qb.getPath());
        }
        return url;
    }

    public List<Map<String, Object>> getSortOrderList() {
        List<Map<String, Object>> list = new ArrayList<>();

        StringBuilder url = createUrl(getCurrentSearchHelper(), true).append("&amp;sort=");
        for (SortOrder o : SortOrder.values()) {
            Map<String, Object> order = new HashMap<>();
            if (getCurrentSearchHelper().order == o) {
                order.put("active", true);
                order.put("link", "#");
            } else {
                order.put("active", false);
                order.put("link", url + o.toString());
            }
            order.put("name", o.getDesc());
            list.add(order);
        }

        return list;
    }

    public String getCurrentSearchQueryErrorMessage() {
        return Util.htmlize(getCurrentSearchHelper().getErrorMsg());
    }

    /**
     * Get the config wrt. the given request. If there is none yet, a new config
     * gets created, attached to the request and returned.
     * <p/>
     *
     * @param request the request to use to initialize the config parameters.
     * @return always the same none-{@code null} config for a given request.
     * @throws NullPointerException if the given parameter is {@code null}.
     */
    public static PageConfig get(HttpServletRequest request) {
        Object cfg = request.getAttribute(ATTR_NAME);
        if (cfg != null) {
            return (PageConfig) cfg;
        }
        PageConfig pcfg = new PageConfig(request);
        request.setAttribute(ATTR_NAME, pcfg);
        return pcfg;
    }

    private static final String ATTR_NAME = "pageconfig"; //PageConfig.class.getCanonicalName();
    private HttpServletRequest req;

    private PageConfig(HttpServletRequest req) {
        this.req = req;
    }

    /**
     * Cleanup all allocated resources. Should always be called right before
     * leaving the _jspService / service.
     */
    public void cleanup() {
        if (req != null) {
            req.removeAttribute(ATTR_NAME);
            req = null;
        }
        env = null;
    }
}
TOP

Related Classes of org.watermint.sourcecolon.org.opensolaris.opengrok.web.PageConfig

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.